From 0b0b38ba288188a4c2f2e94c595c5ac9517d5562 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Thu, 29 Feb 2024 18:20:03 +0100 Subject: [PATCH 01/40] Add base endpoints for Stripe integration --- README.md | 7 + docker/Dockerfile | 8 + package-lock.json | 18 +- package.json | 3 +- src/app.ts | 19 ++ src/controllers/portal-customer.ts.ts | 31 +++ src/controllers/prices.ts | 54 +++++ src/controllers/product.ts | 120 +++++++++++ src/controllers/subscriptions.ts | 298 ++++++++++++++++++++++++++ src/types/environment.d.ts | 4 + src/types/portal.ts | 100 +++++++++ 11 files changed, 659 insertions(+), 3 deletions(-) create mode 100644 src/controllers/portal-customer.ts.ts create mode 100644 src/controllers/prices.ts create mode 100644 src/controllers/product.ts create mode 100644 src/controllers/subscriptions.ts create mode 100644 src/types/portal.ts diff --git a/README.md b/README.md index cb8842b2..adeff22f 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,13 @@ some tokens on the testnet for making the process simpler. 2. `FAUCET_URI`: Faucet service API endpoint (Default: `https://faucet-api.cheqd.network/credit`) 3. `TESTNET_MINIMUM_BALANCE`: Minimum balance on account before it is automatically topped up from the faucet. This value should be expressed as an integer in `CHEQ` tokens, which will then be converted in the background to `ncheq` denomination. Account balance check is carried out on every account creation/login. (Default: 10,000 CHEQ testnet tokens) +#### Stripe integration + +The application supports Stripe integration for payment processing. + +1. `STRIPE_SECRET_KEY`: Secret key for Stripe API. Please, keep it secret on deploying +2. `STRIPE_PUBLISHABLE_KEY` - Publishable key for Stripe API. + ### 3rd Party Connectors The app supports 3rd party connectors for credential storage and delivery. diff --git a/docker/Dockerfile b/docker/Dockerfile index e992bd46..9f7f3c8a 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -81,6 +81,10 @@ ARG ENABLE_ACCOUNT_TOPUP=false ARG FAUCET_URI=https://faucet-api.cheqd.network/credit ARG TESTNET_MINIMUM_BALANCE=1000 +# Stripe +ARG STRIPE_SECRET_KEY +ARG STRIPE_PUBLISHABLE_KEY + # Environment variables: base configuration ENV NPM_CONFIG_LOGLEVEL ${NPM_CONFIG_LOGLEVEL} ENV PORT ${PORT} @@ -125,6 +129,10 @@ ENV POLYGON_RPC_URL ${POLYGON_RPC_URL} ENV VERIDA_PRIVATE_KEY ${VERIDA_PRIVATE_KEY} ENV POLYGON_PRIVATE_KEY ${POLYGON_PRIVATE_KEY} +# Environment variables: Stripe +ENV STRIPE_SECRET_KEY ${STRIPE_SECRET_KEY} +ENV STRIPE_PUBLISHABLE_KEY ${STRIPE_PUBLISHABLE_KEY} + # Set ownership permissions RUN chown -R node:node /home/node/app diff --git a/package-lock.json b/package-lock.json index b5a1f66a..ea2cc887 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cheqd/credential-service", - "version": "2.18.0-develop.1", + "version": "2.18.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@cheqd/credential-service", - "version": "2.18.0-develop.1", + "version": "2.18.0", "license": "Apache-2.0", "dependencies": { "@cheqd/did-provider-cheqd": "^3.7.0", @@ -53,9 +53,11 @@ "pg-connection-string": "^2.6.2", "secp256k1": "^5.0.0", "sqlite3": "^5.1.7", + "stripe": "^14.18.0", "swagger-ui-dist": "5.10.5", "swagger-ui-express": "^5.0.0", "typeorm": "^0.3.20", + "uint8arrays": "^5.0.2", "uri-js": "^4.4.1" }, "devDependencies": { @@ -30235,6 +30237,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/stripe": { + "version": "14.18.0", + "resolved": "https://registry.npmjs.org/stripe/-/stripe-14.18.0.tgz", + "integrity": "sha512-yLqKPqYgGJbMxrQiE4+i2i00ZVA2NRIZbZ1rejzj5XR3F3Uc+1iy9QE133knZudhVGMw367b8vTpB8D9pYMETw==", + "dependencies": { + "@types/node": ">=8.1.0", + "qs": "^6.11.0" + }, + "engines": { + "node": ">=12.*" + } + }, "node_modules/strnum": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", diff --git a/package.json b/package.json index 5dde656f..44082157 100644 --- a/package.json +++ b/package.json @@ -94,8 +94,9 @@ "pg-connection-string": "^2.6.2", "secp256k1": "^5.0.0", "sqlite3": "^5.1.7", - "swagger-ui-express": "^5.0.0", + "stripe": "^14.18.0", "swagger-ui-dist": "5.10.5", + "swagger-ui-express": "^5.0.0", "typeorm": "^0.3.20", "uint8arrays": "^5.0.2", "uri-js": "^4.4.1" diff --git a/src/app.ts b/src/app.ts index f5580293..675742b9 100644 --- a/src/app.ts +++ b/src/app.ts @@ -26,6 +26,9 @@ import { KeyController } from './controllers/key.js'; import { DIDController } from './controllers/did.js'; import { ResourceController } from './controllers/resource.js'; import { FailedResponseTracker } from './middleware/event-tracker.js'; +import { ProductController } from './controllers/product.js'; +import { SubscriptionController } from './controllers/subscriptions.js'; +import { PriceController } from './controllers/prices.js'; let swaggerOptions = {}; if (process.env.ENABLE_AUTHENTICATION === 'true') { @@ -206,6 +209,22 @@ class App { express.static(path.join(process.cwd(), '/dist'), { extensions: ['js'], index: false }) ); + // Portal + // Product + app.get('/portal/product/list', ProductController.productListValidator, new ProductController().getListProducts); + app.get('/portal/product/:productId', ProductController.productGetValidator, new ProductController().getProduct); + + // Prices + app.get('/portal/price/list', PriceController.priceListValidator, new PriceController().getListPrices); + + // Subscription + app.post('/portal/subscription/create', SubscriptionController.subscriptionCreateValidator, new SubscriptionController().create); + app.post('/portal/subscription/update', SubscriptionController.subscriptionUpdateValidator, new SubscriptionController().update); + app.get('/portal/subscription/get/:subscriptionId', SubscriptionController.subscriptionGetValidator, new SubscriptionController().get); + app.get('/portal/subscription/list', SubscriptionController.subscriptionListValidator, new SubscriptionController().list); + app.delete('/portal/subscription/cancel', SubscriptionController.subscriptionCancelValidator, new SubscriptionController().cancel); + app.post('/portal/subscription/resume', SubscriptionController.subscriptionResumeValidator, new SubscriptionController().resume); + // 404 for all other requests app.all('*', (_req, res) => res.status(StatusCodes.BAD_REQUEST).send('Bad request')); } diff --git a/src/controllers/portal-customer.ts.ts b/src/controllers/portal-customer.ts.ts new file mode 100644 index 00000000..aa63e846 --- /dev/null +++ b/src/controllers/portal-customer.ts.ts @@ -0,0 +1,31 @@ +import * as dotenv from 'dotenv'; +import type { Request, Response } from 'express'; +import { check } from 'express-validator'; +import { validationResult } from './validator'; +import type { PortalCustomerGetUnsuccessfulResponseBody } from '../types/portal'; + +dotenv.config(); + +export class PortalCustomerController { + static portalCustomerGetValidator = [ + check('logToUserId') + .optional() + .isString() + .withMessage('logToUserId should be a string') + .bail(), + ]; + + async get(request: Request, response: Response) { + const result = validationResult(request); + // handle error + if (!result.isEmpty()) { + return response.status(400).json({ + error: result.array().pop()?.msg + } satisfies PortalCustomerGetUnsuccessfulResponseBody); + } + + return response.status(500).json({ + error: "Not implemented yet" + }) + } +} \ No newline at end of file diff --git a/src/controllers/prices.ts b/src/controllers/prices.ts new file mode 100644 index 00000000..6ab5a199 --- /dev/null +++ b/src/controllers/prices.ts @@ -0,0 +1,54 @@ +import { Stripe } from 'stripe'; +import type { Request, Response } from 'express'; +import * as dotenv from 'dotenv'; +import type { PriceListResponseBody, PriceListUnsuccessfulResponseBody } from '../types/portal.js'; +import { StatusCodes } from 'http-status-codes'; +import { validationResult } from './validator/index.js'; +import { check } from 'express-validator'; + +dotenv.config(); + +const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); + +export class PriceController { + + static priceListValidator = [ + check('productId') + .optional() + .isString() + .withMessage('productId should be a string') + .bail(), + ]; + + async getListPrices(request: Request, response: Response) { + const result = validationResult(request); + // handle error + if (!result.isEmpty()) { + return response.status(StatusCodes.BAD_REQUEST).json({ + error: result.array().pop()?.msg + } satisfies PriceListUnsuccessfulResponseBody); + } + // Get query parameters + const productId = request.query.productId; + + try { + // Fetch the list of prices + const prices = productId + ? await stripe.prices.list({ + product: productId as string, + active: true, + }) + : await stripe.prices.list({ + active: true, + }) + + return response.status(StatusCodes.OK).json({ + prices: prices + } satisfies PriceListResponseBody); + } catch (error) { + return response.status(500).json({ + error: `Internal error: ${(error as Error)?.message || error}` + } satisfies PriceListUnsuccessfulResponseBody); + } + } +} \ No newline at end of file diff --git a/src/controllers/product.ts b/src/controllers/product.ts new file mode 100644 index 00000000..5ada6dde --- /dev/null +++ b/src/controllers/product.ts @@ -0,0 +1,120 @@ +import { Stripe } from 'stripe'; +import type { Request, Response } from 'express'; +import * as dotenv from 'dotenv'; +import type { ProductGetResponseBody, ProductGetUnsuccessfulResponseBody, ProductListResponseBody, ProductListUnsuccessfulResponseBody, ProductWithPrices } from '../types/portal.js'; +import { StatusCodes } from 'http-status-codes'; +import { validationResult } from './validator/index.js'; +import { check } from 'express-validator'; + +dotenv.config(); + +const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); + +export class ProductController { + + static productListValidator = [ + check('prices') + .optional() + .isBoolean() + .withMessage('prices should be a boolean') + .bail(), + ]; + + static productGetValidator = [ + check('productId') + .exists() + .withMessage('productId was not provided') + .bail(), + check('prices') + .optional() + .isBoolean() + .withMessage('prices should be a boolean') + .bail(), + ]; + + async getListProducts(request: Request, response: Response) { + const result = validationResult(request); + // handle error + if (!result.isEmpty()) { + return response.status(StatusCodes.BAD_REQUEST).json({ + error: result.array().pop()?.msg + } satisfies ProductListUnsuccessfulResponseBody); + } + // Get query parameters + const prices = request.query.prices === 'false' ? false : true; + + try { + const products = await stripe.products.list({ + active: true, + }) as Stripe.ApiList; + + // If no products found return 404 + if (!products.data) { + return response.status(StatusCodes.NOT_FOUND).json({ + error: 'Seems like there no any active products on Stripe side. Please add some.' + } satisfies ProductListUnsuccessfulResponseBody); + } + + if (prices) { + for (const product of products.data) { + const prices = await stripe.prices.list({ + product: product.id, + active: true, + }); + product.prices = prices.data; + } + } + + return response.status(StatusCodes.OK).json({ + products: products + } satisfies ProductListResponseBody); + } catch (error) { + return response.status(500).json({ + error: `Internal error: ${(error as Error)?.message || error}` + } satisfies ProductListUnsuccessfulResponseBody); + } + } + + async getProduct(request: Request, response: Response) { + const result = validationResult(request); + // handle error + if (!result.isEmpty()) { + return response.status(StatusCodes.BAD_REQUEST).json({ + error: result.array().pop()?.msg + } satisfies ProductGetUnsuccessfulResponseBody); + } + // Get query parameters + const prices = request.query.prices === 'false' ? false : true; + const productId = request.params.productId as string; + + try { + // Get the product + const product = await stripe.products.retrieve(productId) as ProductWithPrices; + + // If no product found return 404 + if (!product) { + return response.status(StatusCodes.NOT_FOUND).json({ + error: 'No product found with id: ' + productId + } satisfies ProductGetUnsuccessfulResponseBody); + } + + if (prices) { + const prices = await stripe.prices.list({ + product: product.id, + active: true, + }); + if (prices.data) { + product.prices = prices.data; + } + } + + return response.status(StatusCodes.OK).json({ + product: product + } satisfies ProductGetResponseBody); + } catch (error) { + return response.status(500).json({ + error: `Internal error: ${(error as Error)?.message || error}` + } satisfies ProductGetUnsuccessfulResponseBody); + } + } +} \ No newline at end of file diff --git a/src/controllers/subscriptions.ts b/src/controllers/subscriptions.ts new file mode 100644 index 00000000..7fe948bf --- /dev/null +++ b/src/controllers/subscriptions.ts @@ -0,0 +1,298 @@ +import { Stripe } from 'stripe'; +import type { Request, Response } from 'express'; +import * as dotenv from 'dotenv'; +import type { SubscriptionCreateRequestBody, SubscriptionCreateResponseBody, SubscriptionCreateUnsuccessfulResponseBody, SubscriptionCancelResponseBody, SubscriptionCancelUnsuccessfulResponseBody, SubscriptionGetResponseBody, SubscriptionGetUnsuccessfulResponseBody, SubscriptionListResponseBody, SubscriptionListUnsuccessfulResponseBody, SubscriptionUpdateRequestBody, SubscriptionUpdateResponseBody, SubscriptionUpdateUnsuccessfulResponseBody, SubscriptionResumeUnsuccessfulResponseBody, SubscriptionResumeResponseBody, SubscriptionResumeRequestBody, SubscriptionCancelRequestBody } from '../types/portal.js'; +import { StatusCodes } from 'http-status-codes'; +import { validationResult } from './validator/index.js'; +import { check } from 'express-validator'; + +dotenv.config(); + +const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); + +export class SubscriptionController { + + static subscriptionCreateValidator = [ + check('customerId') + .exists() + .withMessage('customerId was not provided') + .bail(), + check('items') + .exists() + .withMessage('items was not provided') + .bail() + .isArray() + .withMessage('items should be an array') + .bail(), + check('items.*.price') + .exists() + .withMessage('price was not provided') + .bail() + .isString() + .withMessage('price should be a string') + .bail(), + check('idempotencyKey') + .optional() + .isString() + .withMessage('idempotencyKey should be a string') + .bail(), + ]; + + static subscriptionUpdateValidator = [ + check('subscriptionId') + .exists() + .withMessage('subscriptionId was not provided') + .bail(), + check('updateParams') + .exists() + .withMessage('updateParams was not provided') + .bail(), + check('idempotencyKey') + .optional() + .isString() + .withMessage('idempotencyKey should be a string') + .bail(), + ]; + + static subscriptionGetValidator = [ + check('subscriptionId') + .exists() + .withMessage('subscriptionId was not provided') + .bail() + .isString() + .withMessage('subscriptionId should be a string') + .bail(), + ]; + + static subscriptionListValidator = [ + check('customerId') + .optional() + .isString() + .withMessage('customerId should be a string') + .bail(), + ]; + + static subscriptionCancelValidator = [ + check('subscriptionId') + .exists() + .withMessage('subscriptionId was not provided') + .bail() + .isString() + .withMessage('subscriptionId should be a string') + .bail(), + check('idempotencyKey') + .optional() + .isString() + .withMessage('idempotencyKey should be a string') + .bail(), + ]; + + static subscriptionResumeValidator = [ + check('subscriptionId') + .exists() + .withMessage('subscriptionId was not provided') + .bail() + .isString() + .withMessage('subscriptionId should be a string') + .bail(), + check('idempotencyKey') + .optional() + .isString() + .withMessage('idempotencyKey should be a string') + .bail(), + ]; + + async create(request: Request, response: Response) { + // Validate request + const result = validationResult(request); + if (!result.isEmpty()) { + return response.status(StatusCodes.BAD_REQUEST).json({ + error: result.array().pop()?.msg + } satisfies SubscriptionCreateUnsuccessfulResponseBody); + } + + const { customerId, items, idempotencyKey } = request.body satisfies SubscriptionCreateRequestBody; + try { + // Create the subscription + const subscription = await stripe.subscriptions.create({ + customer: customerId, + items: items, + }, + { + idempotencyKey: idempotencyKey, + }); + if (subscription.lastResponse?.statusCode !== StatusCodes.OK) { + return response.status(StatusCodes.NOT_FOUND).json({ + error: `Subscription was not created`, + } satisfies SubscriptionCreateUnsuccessfulResponseBody); + } + return response.status(StatusCodes.OK).json({ + subscription: subscription + } satisfies SubscriptionCreateResponseBody ); + } catch (error) { + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: `Internal error: ${(error as Error)?.message || error}` + } satisfies SubscriptionCreateUnsuccessfulResponseBody); + } + } + + async update(request: Request, response: Response) { + // Validate request + const result = validationResult(request); + if (!result.isEmpty()) { + return response.status(StatusCodes.BAD_REQUEST).json({ + error: result.array().pop()?.msg + } satisfies SubscriptionUpdateUnsuccessfulResponseBody); + } + + const { subscriptionId, updateParams, idempotencyKey} = request.body satisfies SubscriptionUpdateRequestBody; + try { + // Update the subscription + const subscription = await stripe.subscriptions.update( + subscriptionId, + updateParams, + { + idempotencyKey: idempotencyKey, + }); + if (subscription.lastResponse?.statusCode !== StatusCodes.OK) { + return response.status(StatusCodes.NOT_FOUND).json({ + error: `Subscription was not updated`, + } satisfies SubscriptionUpdateUnsuccessfulResponseBody); + } + return response.status(StatusCodes.OK).json({ + subscription: subscription + } satisfies SubscriptionUpdateResponseBody); + + } catch (error) { + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: `Internal error: ${(error as Error)?.message || error}` + } satisfies SubscriptionUpdateUnsuccessfulResponseBody); + } + } + + public async list(request: Request, response: Response) { + // Validate request + const result = validationResult(request); + if (!result.isEmpty()) { + return response.status(StatusCodes.BAD_REQUEST).json({ + error: result.array().pop()?.msg + } satisfies SubscriptionListUnsuccessfulResponseBody); + } + const customerId = request.query.customerId; + try { + // Get the subscriptions + const subscriptions = customerId + ? await stripe.subscriptions.list({ + customer: customerId as string, + }) + : await stripe.subscriptions.list(); + + if (subscriptions.lastResponse?.statusCode !== StatusCodes.OK) { + return response.status(StatusCodes.NOT_FOUND).json({ + error: `Subscriptions were not found`, + } satisfies SubscriptionListUnsuccessfulResponseBody); + } + return response.status(StatusCodes.OK).json({ + subscriptions: subscriptions + } satisfies SubscriptionListResponseBody); + } catch (error) { + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: `Internal error: ${(error as Error)?.message || error}` + } satisfies SubscriptionListUnsuccessfulResponseBody); + } + } + + async get(request: Request, response: Response) { + // Validate request + const result = validationResult(request); + if (!result.isEmpty()) { + return response.status(StatusCodes.BAD_REQUEST).json({ + error: result.array().pop()?.msg + } satisfies SubscriptionGetUnsuccessfulResponseBody); + } + const subscriptionId = request.query.subscriptionId; + try { + // Get the subscription + const subscription = await stripe.subscriptions.retrieve(subscriptionId as string); + if (subscription.lastResponse?.statusCode !== StatusCodes.OK) { + return response.status(StatusCodes.NOT_FOUND).json({ + error: `Subscription was not found`, + } satisfies SubscriptionGetUnsuccessfulResponseBody); + } + return response.status(StatusCodes.OK).json({ + subscription: subscription + } satisfies SubscriptionGetResponseBody); + } catch (error) { + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: `Internal error: ${(error as Error)?.message || error}` + } satisfies SubscriptionGetUnsuccessfulResponseBody); + } + } + + async cancel(request: Request, response: Response) { + // Validate request + const result = validationResult(request); + if (!result.isEmpty()) { + return response.status(StatusCodes.BAD_REQUEST).json({ + error: result.array().pop()?.msg + } satisfies SubscriptionCancelUnsuccessfulResponseBody); + } + const {subscriptionId, idempotencyKey } = request.body satisfies SubscriptionCancelRequestBody; + + try { + // Cancel the subscription + const subscription = await stripe.subscriptions.cancel( + subscriptionId as string, + { + idempotencyKey: idempotencyKey + }); + + // Check if the subscription was cancelled + if (subscription.lastResponse?.statusCode !== StatusCodes.OK) { + return response.status(StatusCodes.NOT_FOUND).json({ + error: `Subscription was not deleted`, + } satisfies SubscriptionCancelUnsuccessfulResponseBody); + } + return response.status(StatusCodes.OK).json({ + subscription: subscription + } satisfies SubscriptionCancelResponseBody); + } catch (error) { + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: `Internal error: ${(error as Error)?.message || error}` + } satisfies SubscriptionCancelUnsuccessfulResponseBody); + } + } + + async resume(request: Request, response: Response) { + // Validate request + const result = validationResult(request); + if (!result.isEmpty()) { + return response.status(StatusCodes.BAD_REQUEST).json({ + error: result.array().pop()?.msg + } satisfies SubscriptionResumeUnsuccessfulResponseBody); + } + const { subscriptionId, idempotencyKey } = request.body satisfies SubscriptionResumeRequestBody; + try { + // Resume the subscription + const subscription = await stripe.subscriptions.resume( + subscriptionId as string, + { + idempotencyKey: idempotencyKey + }); + + // Check if the subscription was resumed + if (subscription.lastResponse?.statusCode !== StatusCodes.OK) { + return response.status(StatusCodes.NOT_FOUND).json({ + error: `Subscription was not resumed`, + } satisfies SubscriptionResumeUnsuccessfulResponseBody); + } + return response.status(StatusCodes.OK).json({ + subscription: subscription + } satisfies SubscriptionResumeResponseBody); + } catch (error) { + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: `Internal error: ${(error as Error)?.message || error}` + } satisfies SubscriptionResumeUnsuccessfulResponseBody); + } + } +} \ No newline at end of file diff --git a/src/types/environment.d.ts b/src/types/environment.d.ts index 49bd71c6..f29c106e 100644 --- a/src/types/environment.d.ts +++ b/src/types/environment.d.ts @@ -56,6 +56,10 @@ declare global { // Creds CREDS_DECRYPTION_SECRET: string; + + // Stripe + STRIPE_SECRET_KEY: string; + STRIPE_PUBLISHABLE_KEY: string; } } diff --git a/src/types/portal.ts b/src/types/portal.ts new file mode 100644 index 00000000..e4de0863 --- /dev/null +++ b/src/types/portal.ts @@ -0,0 +1,100 @@ +import type Stripe from "stripe"; +import type { UnsuccessfulResponseBody } from "./shared.js"; + +export type ProductWithPrices = Stripe.Product & { + prices?: Stripe.Price[]; +}; + +export type ProductListUnsuccessfulResponseBody = UnsuccessfulResponseBody; +export type ProductGetUnsuccessfulResponseBody = UnsuccessfulResponseBody; + + +export type ProductListResponseBody = { + products: Stripe.ApiList; +} + +export type ProductGetResponseBody = { + product: ProductWithPrices; +} + +// Prices +// List +export type PriceListResponseBody = { + prices: Stripe.ApiList; +} +export type PriceListUnsuccessfulResponseBody = UnsuccessfulResponseBody; + +// Subscription +// Create +export type SubscriptionCreateRequestBody = { + customerId: string; + items: [{ price: string }]; + idempotencyKey?: string; +} + +export type SubscriptionCreateResponseBody = { + subscription: Stripe.Response; +} + +// Update +export type SubscriptionUpdateRequestBody = { + subscriptionId: string; + updateParams: Stripe.SubscriptionUpdateParams; + idempotencyKey?: string; + +} + +export type SubscriptionUpdateResponseBody = { + subscription: Stripe.Response; +} + +// Get +export type SubscriptionGetRequestBody = { + subscriptionId: string; +} + +export type SubscriptionGetResponseBody = { + subscription: Stripe.Response; +} + +// List +export type SubscriptionListRequestBody = { + customerId: string; +} + +export type SubscriptionListResponseBody = { + subscriptions: Stripe.Response>; +} + +// Delete +export type SubscriptionCancelRequestBody = { + subscriptionId: string; +} + +export type SubscriptionCancelResponseBody = { + subscription: Stripe.Subscription; + idempotencyKey?: string; +} + +//Resume + +export type SubscriptionResumeRequestBody = { + subscriptionId: string; + idempotencyKey?: string; +} + +export type SubscriptionResumeResponseBody = { + subscription: Stripe.Response; +} + +export type SubscriptionCreateUnsuccessfulResponseBody = UnsuccessfulResponseBody; +export type SubscriptionListUnsuccessfulResponseBody = UnsuccessfulResponseBody; +export type SubscriptionGetUnsuccessfulResponseBody = UnsuccessfulResponseBody; +export type SubscriptionUpdateUnsuccessfulResponseBody = UnsuccessfulResponseBody; +export type SubscriptionCancelUnsuccessfulResponseBody = UnsuccessfulResponseBody; +export type SubscriptionResumeUnsuccessfulResponseBody = UnsuccessfulResponseBody; + +// Customer +// Get + +export type PortalCustomerGetUnsuccessfulResponseBody = UnsuccessfulResponseBody; \ No newline at end of file From e50cece593dfc0c3e54ae928a66563e5b625be54 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Fri, 1 Mar 2024 18:27:54 +0100 Subject: [PATCH 02/40] Add swagger docs and make it as separate swagger for admin and api --- package.json | 4 +- src/app.ts | 44 +- .../portal-customer.ts} | 4 +- src/controllers/{ => admin}/prices.ts | 35 +- src/controllers/{ => admin}/product.ts | 90 ++- src/controllers/{ => admin}/subscriptions.ts | 185 ++++- src/controllers/{ => api}/account.ts | 28 +- .../{ => api}/credential-status.ts | 24 +- src/controllers/{ => api}/credential.ts | 22 +- src/controllers/{ => api}/did.ts | 20 +- src/controllers/{ => api}/key.ts | 14 +- src/controllers/{ => api}/presentation.ts | 18 +- src/controllers/{ => api}/resource.ts | 18 +- src/static/swagger-admin-options.json | 31 + src/static/swagger-admin.json | 662 ++++++++++++++++++ ...-options.json => swagger-api-options.json} | 0 src/static/{swagger.json => swagger-api.json} | 0 src/types/swagger-admin-types.ts | 175 +++++ ...{swagger-types.ts => swagger-api-types.ts} | 0 19 files changed, 1263 insertions(+), 111 deletions(-) rename src/controllers/{portal-customer.ts.ts => admin/portal-customer.ts} (92%) rename src/controllers/{ => admin}/prices.ts (61%) rename src/controllers/{ => admin}/product.ts (62%) rename src/controllers/{ => admin}/subscriptions.ts (67%) rename src/controllers/{ => api}/account.ts (94%) rename src/controllers/{ => api}/credential-status.ts (98%) rename src/controllers/{ => api}/credential.ts (97%) rename src/controllers/{ => api}/did.ts (98%) rename src/controllers/{ => api}/key.ts (96%) rename src/controllers/{ => api}/presentation.ts (95%) rename src/controllers/{ => api}/resource.ts (95%) create mode 100644 src/static/swagger-admin-options.json create mode 100644 src/static/swagger-admin.json rename src/static/{swagger-options.json => swagger-api-options.json} (100%) rename src/static/{swagger.json => swagger-api.json} (100%) create mode 100644 src/types/swagger-admin-types.ts rename src/types/{swagger-types.ts => swagger-api-types.ts} (100%) diff --git a/package.json b/package.json index 44082157..e929ca56 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,9 @@ "scripts": { "build": "npm run build:swagger && npm run build:app", "build:app": "tsc", - "build:swagger": "swagger-jsdoc --definition src/static/swagger-options.json -o src/static/swagger.json ./src/controllers/*.ts ./src/types/swagger-types.ts", + "build:swagger-api": "swagger-jsdoc --definition src/static/swagger-api-options.json -o src/static/swagger-api.json ./src/controllers/api/*.ts ./src/types/swagger-api-types.ts", + "build:swagger-admin": "swagger-jsdoc --definition src/static/swagger-admin-options.json -o src/static/swagger-admin.json ./src/controllers/admin/*.ts ./src/types/swagger-admin-types.ts", + "build:swagger": "npm run build:swagger-api && npm run build:swagger-admin", "start": "node dist/index.js", "start:local": "npm run build:app && npm run start", "format": "prettier --write '**/*.{js,ts,cjs,mjs,json}'", diff --git a/src/app.ts b/src/app.ts index 675742b9..4d4ce21f 100644 --- a/src/app.ts +++ b/src/app.ts @@ -7,11 +7,11 @@ import path from 'path'; import swaggerUi from 'swagger-ui-express'; import { StatusCodes } from 'http-status-codes'; -import { CredentialController } from './controllers/credential.js'; -import { AccountController } from './controllers/account.js'; +import { CredentialController } from './controllers/api/credential.js'; +import { AccountController } from './controllers/api/account.js'; import { Authentication } from './middleware/authentication.js'; import { Connection } from './database/connection/connection.js'; -import { CredentialStatusController } from './controllers/credential-status.js'; +import { CredentialStatusController } from './controllers/api/credential-status.js'; import { CORS_ALLOWED_ORIGINS, CORS_ERROR_MSG } from './types/constants.js'; import { LogToWebHook } from './middleware/hook.js'; import { Middleware } from './middleware/middleware.js'; @@ -20,15 +20,16 @@ import * as dotenv from 'dotenv'; dotenv.config(); // Define Swagger file -import swaggerDocument from './static/swagger.json' assert { type: 'json' }; -import { PresentationController } from './controllers/presentation.js'; -import { KeyController } from './controllers/key.js'; -import { DIDController } from './controllers/did.js'; -import { ResourceController } from './controllers/resource.js'; +import swaggerAPIDocument from './static/swagger-api.json' assert { type: 'json' }; +import swaggerAdminDocument from './static/swagger-admin.json' assert { type: 'json' }; +import { PresentationController } from './controllers/api/presentation.js'; +import { KeyController } from './controllers/api/key.js'; +import { DIDController } from './controllers/api/did.js'; +import { ResourceController } from './controllers/api/resource.js'; import { FailedResponseTracker } from './middleware/event-tracker.js'; -import { ProductController } from './controllers/product.js'; -import { SubscriptionController } from './controllers/subscriptions.js'; -import { PriceController } from './controllers/prices.js'; +import { ProductController } from './controllers/admin/product.js'; +import { SubscriptionController } from './controllers/admin/subscriptions.js'; +import { PriceController } from './controllers/admin/prices.js'; let swaggerOptions = {}; if (process.env.ENABLE_AUTHENTICATION === 'true') { @@ -99,7 +100,8 @@ class App { } this.express.use(express.text()); - this.express.use('/swagger', swaggerUi.serve, swaggerUi.setup(swaggerDocument, swaggerOptions)); + this.express.use('/swagger', swaggerUi.serve, swaggerUi.setup(swaggerAPIDocument, swaggerOptions)); + this.express.use('/admin/swagger', swaggerUi.serve, swaggerUi.setup(swaggerAdminDocument)) this.express.use(auth.handleError); this.express.use(async (req, res, next) => await auth.accessControl(req, res, next)); } @@ -211,19 +213,19 @@ class App { // Portal // Product - app.get('/portal/product/list', ProductController.productListValidator, new ProductController().getListProducts); - app.get('/portal/product/:productId', ProductController.productGetValidator, new ProductController().getProduct); + app.get('/admin/product/list', ProductController.productListValidator, new ProductController().getListProducts); + app.get('/admin/product/:productId', ProductController.productGetValidator, new ProductController().getProduct); // Prices - app.get('/portal/price/list', PriceController.priceListValidator, new PriceController().getListPrices); + app.get('/admin/price/list', PriceController.priceListValidator, new PriceController().getListPrices); // Subscription - app.post('/portal/subscription/create', SubscriptionController.subscriptionCreateValidator, new SubscriptionController().create); - app.post('/portal/subscription/update', SubscriptionController.subscriptionUpdateValidator, new SubscriptionController().update); - app.get('/portal/subscription/get/:subscriptionId', SubscriptionController.subscriptionGetValidator, new SubscriptionController().get); - app.get('/portal/subscription/list', SubscriptionController.subscriptionListValidator, new SubscriptionController().list); - app.delete('/portal/subscription/cancel', SubscriptionController.subscriptionCancelValidator, new SubscriptionController().cancel); - app.post('/portal/subscription/resume', SubscriptionController.subscriptionResumeValidator, new SubscriptionController().resume); + app.post('/admin/subscription/create', SubscriptionController.subscriptionCreateValidator, new SubscriptionController().create); + app.post('/admin/subscription/update', SubscriptionController.subscriptionUpdateValidator, new SubscriptionController().update); + app.get('/admin/subscription/get/:subscriptionId', SubscriptionController.subscriptionGetValidator, new SubscriptionController().get); + app.get('/admin/subscription/list', SubscriptionController.subscriptionListValidator, new SubscriptionController().list); + app.delete('/admin/subscription/cancel', SubscriptionController.subscriptionCancelValidator, new SubscriptionController().cancel); + app.post('/admin/subscription/resume', SubscriptionController.subscriptionResumeValidator, new SubscriptionController().resume); // 404 for all other requests app.all('*', (_req, res) => res.status(StatusCodes.BAD_REQUEST).send('Bad request')); diff --git a/src/controllers/portal-customer.ts.ts b/src/controllers/admin/portal-customer.ts similarity index 92% rename from src/controllers/portal-customer.ts.ts rename to src/controllers/admin/portal-customer.ts index aa63e846..67a262e9 100644 --- a/src/controllers/portal-customer.ts.ts +++ b/src/controllers/admin/portal-customer.ts @@ -1,8 +1,8 @@ import * as dotenv from 'dotenv'; import type { Request, Response } from 'express'; import { check } from 'express-validator'; -import { validationResult } from './validator'; -import type { PortalCustomerGetUnsuccessfulResponseBody } from '../types/portal'; +import { validationResult } from '../validator'; +import type { PortalCustomerGetUnsuccessfulResponseBody } from '../../types/portal.js'; dotenv.config(); diff --git a/src/controllers/prices.ts b/src/controllers/admin/prices.ts similarity index 61% rename from src/controllers/prices.ts rename to src/controllers/admin/prices.ts index 6ab5a199..cb9e3178 100644 --- a/src/controllers/prices.ts +++ b/src/controllers/admin/prices.ts @@ -1,9 +1,9 @@ import { Stripe } from 'stripe'; import type { Request, Response } from 'express'; import * as dotenv from 'dotenv'; -import type { PriceListResponseBody, PriceListUnsuccessfulResponseBody } from '../types/portal.js'; +import type { PriceListResponseBody, PriceListUnsuccessfulResponseBody } from '../../types/portal.js'; import { StatusCodes } from 'http-status-codes'; -import { validationResult } from './validator/index.js'; +import { validationResult } from '../validator/index.js'; import { check } from 'express-validator'; dotenv.config(); @@ -20,6 +20,37 @@ export class PriceController { .bail(), ]; + /** + * @openapi + * + * /admin/price/list: + * get: + * summary: Get a list of prices + * description: Get a list of prices + * tags: [Price] + * parameters: + * - in: query + * name: productId + * schema: + * type: string + * description: The product id. If passed - returns filtered by this product list of prices. + * required: false + * responses: + * 200: + * description: A list of prices + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/PriceListResponseBody' + * 400: + * $ref: '#/components/schemas/InvalidRequest' + * 401: + * $ref: '#/components/schemas/UnauthorizedError' + * 500: + * $ref: '#/components/schemas/InternalError' + * 404: + * $ref: '#/components/schemas/NotFoundError' + */ async getListPrices(request: Request, response: Response) { const result = validationResult(request); // handle error diff --git a/src/controllers/product.ts b/src/controllers/admin/product.ts similarity index 62% rename from src/controllers/product.ts rename to src/controllers/admin/product.ts index 5ada6dde..d1d23786 100644 --- a/src/controllers/product.ts +++ b/src/controllers/admin/product.ts @@ -1,9 +1,9 @@ import { Stripe } from 'stripe'; import type { Request, Response } from 'express'; import * as dotenv from 'dotenv'; -import type { ProductGetResponseBody, ProductGetUnsuccessfulResponseBody, ProductListResponseBody, ProductListUnsuccessfulResponseBody, ProductWithPrices } from '../types/portal.js'; +import type { ProductGetResponseBody, ProductGetUnsuccessfulResponseBody, ProductListResponseBody, ProductListUnsuccessfulResponseBody, ProductWithPrices } from '../../types/portal.js'; import { StatusCodes } from 'http-status-codes'; -import { validationResult } from './validator/index.js'; +import { validationResult } from '../validator/index.js'; import { check } from 'express-validator'; dotenv.config(); @@ -32,6 +32,37 @@ export class ProductController { .bail(), ]; + /** + * @openapi + * + * /admin/product/list: + * get: + * summary: Get a list of products + * description: Get a list of products which are on a Stripe side + * tags: [Product] + * parameters: + * - in: query + * name: prices + * schema: + * type: boolean + * description: If setup to true - returns the list of products with prices inside. Default - true + * required: false + * responses: + * 200: + * description: A list of products + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/ProductListResponseBody' + * 400: + * $ref: '#/components/schemas/InvalidRequest' + * 401: + * $ref: '#/components/schemas/UnauthorizedError' + * 500: + * $ref: '#/components/schemas/InternalError' + * 404: + * $ref: '#/components/schemas/NotFoundError' + */ async getListProducts(request: Request, response: Response) { const result = validationResult(request); // handle error @@ -75,6 +106,44 @@ export class ProductController { } } + + /** + * @openapi + * + * /admin/product/{productId}: + * get: + * summary: Get a product + * description: Get a product by id + * tags: [Product] + * parameters: + * - in: path + * name: productId + * schema: + * type: string + * description: The product id which identifies the product in Stripe + * required: true + * - in: query + * name: prices + * schema: + * type: boolean + * description: If setup to true - returns the product with prices inside. Default - true + * required: false + * responses: + * 200: + * description: A product + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/ProductGetResponseBody' + * 400: + * $ref: '#/components/schemas/InvalidRequest' + * 401: + * $ref: '#/components/schemas/UnauthorizedError' + * 500: + * $ref: '#/components/schemas/InternalError' + * 404: + * $ref: '#/components/schemas/NotFoundError' + */ async getProduct(request: Request, response: Response) { const result = validationResult(request); // handle error @@ -91,13 +160,6 @@ export class ProductController { // Get the product const product = await stripe.products.retrieve(productId) as ProductWithPrices; - // If no product found return 404 - if (!product) { - return response.status(StatusCodes.NOT_FOUND).json({ - error: 'No product found with id: ' + productId - } satisfies ProductGetUnsuccessfulResponseBody); - } - if (prices) { const prices = await stripe.prices.list({ product: product.id, @@ -112,6 +174,16 @@ export class ProductController { product: product } satisfies ProductGetResponseBody); } catch (error) { + + // define error + const errorRef = error as Record; + + if (errorRef?.statusCode === 404) { + return response.status(StatusCodes.NOT_FOUND).json({ + error: `Product with id ${productId} not found` + } satisfies ProductGetUnsuccessfulResponseBody); + } + return response.status(500).json({ error: `Internal error: ${(error as Error)?.message || error}` } satisfies ProductGetUnsuccessfulResponseBody); diff --git a/src/controllers/subscriptions.ts b/src/controllers/admin/subscriptions.ts similarity index 67% rename from src/controllers/subscriptions.ts rename to src/controllers/admin/subscriptions.ts index 7fe948bf..3b149a9a 100644 --- a/src/controllers/subscriptions.ts +++ b/src/controllers/admin/subscriptions.ts @@ -1,9 +1,9 @@ import { Stripe } from 'stripe'; import type { Request, Response } from 'express'; import * as dotenv from 'dotenv'; -import type { SubscriptionCreateRequestBody, SubscriptionCreateResponseBody, SubscriptionCreateUnsuccessfulResponseBody, SubscriptionCancelResponseBody, SubscriptionCancelUnsuccessfulResponseBody, SubscriptionGetResponseBody, SubscriptionGetUnsuccessfulResponseBody, SubscriptionListResponseBody, SubscriptionListUnsuccessfulResponseBody, SubscriptionUpdateRequestBody, SubscriptionUpdateResponseBody, SubscriptionUpdateUnsuccessfulResponseBody, SubscriptionResumeUnsuccessfulResponseBody, SubscriptionResumeResponseBody, SubscriptionResumeRequestBody, SubscriptionCancelRequestBody } from '../types/portal.js'; +import type { SubscriptionCreateRequestBody, SubscriptionCreateResponseBody, SubscriptionCreateUnsuccessfulResponseBody, SubscriptionCancelResponseBody, SubscriptionCancelUnsuccessfulResponseBody, SubscriptionGetResponseBody, SubscriptionGetUnsuccessfulResponseBody, SubscriptionListResponseBody, SubscriptionListUnsuccessfulResponseBody, SubscriptionUpdateRequestBody, SubscriptionUpdateResponseBody, SubscriptionUpdateUnsuccessfulResponseBody, SubscriptionResumeUnsuccessfulResponseBody, SubscriptionResumeResponseBody, SubscriptionResumeRequestBody, SubscriptionCancelRequestBody } from '../../types/portal.js'; import { StatusCodes } from 'http-status-codes'; -import { validationResult } from './validator/index.js'; +import { validationResult } from '../validator/index.js'; import { check } from 'express-validator'; dotenv.config(); @@ -102,6 +102,34 @@ export class SubscriptionController { .bail(), ]; + + /** + * @openapi + * + * /admin/subscription/create: + * post: + * summary: Create a subscription + * description: Creates a new subscription for an existing customer + * tags: [Subscription] + * requestBody: + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/SubscriptionCreateRequestBody' + * responses: + * 201: + * description: The request was successful. + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/SubscriptionCreateResponseBody' + * 400: + * $ref: '#/components/schemas/InvalidRequest' + * 401: + * $ref: '#/components/schemas/UnauthorizedError' + * 500: + * $ref: '#/components/schemas/InternalError' + */ async create(request: Request, response: Response) { // Validate request const result = validationResult(request); @@ -126,7 +154,7 @@ export class SubscriptionController { error: `Subscription was not created`, } satisfies SubscriptionCreateUnsuccessfulResponseBody); } - return response.status(StatusCodes.OK).json({ + return response.status(StatusCodes.CREATED).json({ subscription: subscription } satisfies SubscriptionCreateResponseBody ); } catch (error) { @@ -136,6 +164,33 @@ export class SubscriptionController { } } + /** + * @openapi + * + * /admin/subscription/update: + * post: + * summary: Update a subscription + * description: Updates an existing subscription + * tags: [Subscription] + * requestBody: + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/SubscriptionUpdateRequestBody' + * responses: + * 200: + * description: The request was successful. + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/SubscriptionUpdateResponseBody' + * 400: + * $ref: '#/components/schemas/InvalidRequest' + * 401: + * $ref: '#/components/schemas/UnauthorizedError' + * 500: + * $ref: '#/components/schemas/InternalError' + */ async update(request: Request, response: Response) { // Validate request const result = validationResult(request); @@ -170,6 +225,38 @@ export class SubscriptionController { } } + /** + * @openapi + * + * /admin/subscription/list: + * get: + * summary: Get a list of subscriptions + * description: Get a list of subscriptions + * tags: [Subscription] + * parameters: + * - in: query + * name: customerId + * schema: + * type: string + * description: The customer id. If passed - returns filtered by this customer list of subscriptions. + * required: false + * responses: + * 200: + * description: A list of subscriptions + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/SubscriptionListResponseBody' + * 400: + * $ref: '#/components/schemas/InvalidRequest' + * 401: + * $ref: '#/components/schemas/UnauthorizedError' + * 500: + * $ref: '#/components/schemas/InternalError' + * 404: + * $ref: '#/components/schemas/NotFoundError' + */ + public async list(request: Request, response: Response) { // Validate request const result = validationResult(request); @@ -202,6 +289,38 @@ export class SubscriptionController { } } + + /** + * @openapi + * + * /admin/subscription/get/{subscriptionId}: + * get: + * summary: Get a subscription + * description: Get a subscription + * tags: [Subscription] + * parameters: + * - in: path + * name: subscriptionId + * schema: + * type: string + * description: The subscription id + * required: true + * responses: + * 200: + * description: The request was successful. + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/SubscriptionGetResponseBody' + * 400: + * $ref: '#/components/schemas/InvalidRequest' + * 401: + * $ref: '#/components/schemas/UnauthorizedError' + * 500: + * $ref: '#/components/schemas/InternalError' + * 404: + * $ref: '#/components/schemas/NotFoundError' + */ async get(request: Request, response: Response) { // Validate request const result = validationResult(request); @@ -210,7 +329,7 @@ export class SubscriptionController { error: result.array().pop()?.msg } satisfies SubscriptionGetUnsuccessfulResponseBody); } - const subscriptionId = request.query.subscriptionId; + const subscriptionId = request.params.subscriptionId; try { // Get the subscription const subscription = await stripe.subscriptions.retrieve(subscriptionId as string); @@ -229,6 +348,35 @@ export class SubscriptionController { } } + /** + * @openapi + * + * /admin/subscription/cancel: + * post: + * summary: Cancel a subscription + * description: Cancels an existing subscription + * tags: [Subscription] + * requestBody: + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/SubscriptionCancelRequestBody' + * responses: + * 200: + * description: The request was successful. + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/SubscriptionCancelResponseBody' + * 400: + * $ref: '#/components/schemas/InvalidRequest' + * 401: + * $ref: '#/components/schemas/UnauthorizedError' + * 500: + * $ref: '#/components/schemas/InternalError' + * 404: + * $ref: '#/components/schemas/NotFoundError' + */ async cancel(request: Request, response: Response) { // Validate request const result = validationResult(request); @@ -263,6 +411,35 @@ export class SubscriptionController { } } + /** + * @openapi + * + * /admin/subscription/resume: + * post: + * summary: Resume a subscription + * description: Resumes an existing subscription + * tags: [Subscription] + * requestBody: + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/SubscriptionResumeRequestBody' + * responses: + * 200: + * description: The request was successful. + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/SubscriptionResumeResponseBody' + * 400: + * $ref: '#/components/schemas/InvalidRequest' + * 401: + * $ref: '#/components/schemas/UnauthorizedError' + * 500: + * $ref: '#/components/schemas/InternalError' + * 404: + * $ref: '#/components/schemas/NotFoundError' + */ async resume(request: Request, response: Response) { // Validate request const result = validationResult(request); diff --git a/src/controllers/account.ts b/src/controllers/api/account.ts similarity index 94% rename from src/controllers/account.ts rename to src/controllers/api/account.ts index 739e4943..0e32cac1 100644 --- a/src/controllers/account.ts +++ b/src/controllers/api/account.ts @@ -1,25 +1,25 @@ import type { Request, Response } from 'express'; import { CheqdNetwork, checkBalance } from '@cheqd/sdk'; -import { TESTNET_MINIMUM_BALANCE, DEFAULT_DENOM_EXPONENT } from '../types/constants.js'; -import { CustomerService } from '../services/customer.js'; -import { LogToHelper } from '../middleware/auth/logto-helper.js'; -import { FaucetHelper } from '../helpers/faucet.js'; +import { TESTNET_MINIMUM_BALANCE, DEFAULT_DENOM_EXPONENT } from '../../types/constants.js'; +import { CustomerService } from '../../services/customer.js'; +import { LogToHelper } from '../../middleware/auth/logto-helper.js'; +import { FaucetHelper } from '../../helpers/faucet.js'; import { StatusCodes } from 'http-status-codes'; -import { LogToWebHook } from '../middleware/hook.js'; -import { UserService } from '../services/user.js'; -import { RoleService } from '../services/role.js'; -import { PaymentAccountService } from '../services/payment-account.js'; -import type { CustomerEntity } from '../database/entities/customer.entity.js'; -import type { UserEntity } from '../database/entities/user.entity.js'; -import type { PaymentAccountEntity } from '../database/entities/payment.account.entity.js'; -import { IdentityServiceStrategySetup } from '../services/identity/index.js'; +import { LogToWebHook } from '../../middleware/hook.js'; +import { UserService } from '../../services/user.js'; +import { RoleService } from '../../services/role.js'; +import { PaymentAccountService } from '../../services/payment-account.js'; +import type { CustomerEntity } from '../../database/entities/customer.entity.js'; +import type { UserEntity } from '../../database/entities/user.entity.js'; +import type { PaymentAccountEntity } from '../../database/entities/payment.account.entity.js'; +import { IdentityServiceStrategySetup } from '../../services/identity/index.js'; import type { QueryCustomerResponseBody, QueryIdTokenResponseBody, UnsuccessfulQueryCustomerResponseBody, UnsuccessfulQueryIdTokenResponseBody, -} from '../types/customer.js'; -import type { UnsuccessfulResponseBody } from '../types/shared.js'; +} from '../../types/customer.js'; +import type { UnsuccessfulResponseBody } from '../../types/shared.js'; import { check, validationResult } from 'express-validator'; export class AccountController { diff --git a/src/controllers/credential-status.ts b/src/controllers/api/credential-status.ts similarity index 98% rename from src/controllers/credential-status.ts rename to src/controllers/api/credential-status.ts index b4677767..480c2493 100644 --- a/src/controllers/credential-status.ts +++ b/src/controllers/api/credential-status.ts @@ -1,21 +1,21 @@ import type { Request, Response } from 'express'; -import { check, validationResult, query } from './validator/index.js'; +import { check, validationResult, query } from '../validator/index.js'; import { fromString } from 'uint8arrays'; import { StatusCodes } from 'http-status-codes'; -import { IdentityServiceStrategySetup } from '../services/identity/index.js'; -import type { ValidationErrorResponseBody } from '../types/shared.js'; -import type { CheckStatusListSuccessfulResponseBody, FeePaymentOptions } from '../types/credential-status.js'; +import { IdentityServiceStrategySetup } from '../../services/identity/index.js'; +import type { ValidationErrorResponseBody } from '../../types/shared.js'; +import type { CheckStatusListSuccessfulResponseBody, FeePaymentOptions } from '../../types/credential-status.js'; import { DefaultStatusAction, DefaultStatusActionPurposeMap, DefaultStatusActions, MinimalPaymentCondition, -} from '../types/credential-status.js'; +} from '../../types/credential-status.js'; import type { SearchStatusListQuery, SearchStatusListSuccessfulResponseBody, SearchStatusListUnsuccessfulResponseBody, -} from '../types/credential-status.js'; +} from '../../types/credential-status.js'; import type { CheckStatusListRequestBody, CheckStatusListRequestQuery, @@ -35,7 +35,7 @@ import type { UpdateUnencryptedStatusListRequestQuery, UpdateUnencryptedStatusListSuccessfulResponseBody, UpdateUnencryptedStatusListUnsuccessfulResponseBody, -} from '../types/credential-status.js'; +} from '../../types/credential-status.js'; import { BulkRevocationResult, BulkSuspensionResult, @@ -44,11 +44,11 @@ import { DefaultStatusList2021StatusPurposeTypes, } from '@cheqd/did-provider-cheqd'; import type { AlternativeUri } from '@cheqd/ts-proto/cheqd/resource/v2/resource.js'; -import { toNetwork } from '../helpers/helpers.js'; -import { eventTracker } from '../services/track/tracker.js'; -import type { ICredentialStatusTrack, ITrackOperation, IFeePaymentOptions } from '../types/track.js'; -import { OperationCategoryNameEnum, OperationNameEnum } from '../types/constants.js'; -import { FeeAnalyzer } from '../helpers/fee-analyzer.js'; +import { toNetwork } from '../../helpers/helpers.js'; +import { eventTracker } from '../../services/track/tracker.js'; +import type { ICredentialStatusTrack, ITrackOperation, IFeePaymentOptions } from '../../types/track.js'; +import { OperationCategoryNameEnum, OperationNameEnum } from '../../types/constants.js'; +import { FeeAnalyzer } from '../../helpers/fee-analyzer.js'; export class CredentialStatusController { static createUnencryptedValidator = [ diff --git a/src/controllers/credential.ts b/src/controllers/api/credential.ts similarity index 97% rename from src/controllers/credential.ts rename to src/controllers/api/credential.ts index 99eda5b0..8737de86 100644 --- a/src/controllers/credential.ts +++ b/src/controllers/api/credential.ts @@ -2,13 +2,13 @@ import type { Request, Response } from 'express'; import type { VerifiableCredential } from '@veramo/core'; import { StatusCodes } from 'http-status-codes'; -import { check, validationResult, query } from './validator/index.js'; +import { check, validationResult, query } from '../validator/index.js'; -import { Credentials } from '../services/credentials.js'; -import { IdentityServiceStrategySetup } from '../services/identity/index.js'; -import type { ValidationErrorResponseBody } from '../types/shared.js'; -import { CheqdW3CVerifiableCredential } from '../services/w3c-credential.js'; -import { isCredentialIssuerDidDeactivated } from '../services/helpers.js'; +import { Credentials } from '../../services/credentials.js'; +import { IdentityServiceStrategySetup } from '../../services/identity/index.js'; +import type { ValidationErrorResponseBody } from '../../types/shared.js'; +import { CheqdW3CVerifiableCredential } from '../../services/w3c-credential.js'; +import { isCredentialIssuerDidDeactivated } from '../../services/helpers.js'; import type { IssueCredentialRequestBody, IssueCredentialResponseBody, @@ -29,12 +29,12 @@ import type { VerifyCredentialRequestBody, VerifyCredentialRequestQuery, VerifyCredentialResponseBody, -} from '../types/credential.js'; -import { VeridaDIDValidator } from './validator/did.js'; +} from '../../types/credential.js'; +import { VeridaDIDValidator } from '../validator/did.js'; import { Cheqd } from '@cheqd/did-provider-cheqd'; -import { OperationCategoryNameEnum, OperationNameEnum } from '../types/constants.js'; -import { eventTracker } from '../services/track/tracker.js'; -import type { ICredentialStatusTrack, ICredentialTrack, ITrackOperation } from '../types/track.js'; +import { OperationCategoryNameEnum, OperationNameEnum } from '../../types/constants.js'; +import { eventTracker } from '../../services/track/tracker.js'; +import type { ICredentialStatusTrack, ICredentialTrack, ITrackOperation } from '../../types/track.js'; export class CredentialController { public static issueValidator = [ diff --git a/src/controllers/did.ts b/src/controllers/api/did.ts similarity index 98% rename from src/controllers/did.ts rename to src/controllers/api/did.ts index a4f064b0..1b062492 100644 --- a/src/controllers/did.ts +++ b/src/controllers/api/did.ts @@ -9,8 +9,8 @@ import { createDidVerificationMethod, } from '@cheqd/sdk'; import { StatusCodes } from 'http-status-codes'; -import { IdentityServiceStrategySetup } from '../services/identity/index.js'; -import { decryptPrivateKey, generateDidDoc, getQueryParams } from '../helpers/helpers.js'; +import { IdentityServiceStrategySetup } from '../../services/identity/index.js'; +import { decryptPrivateKey, generateDidDoc, getQueryParams } from '../../helpers/helpers.js'; import { bases } from 'multiformats/basics'; import { base64ToBytes } from 'did-jwt'; import type { @@ -32,16 +32,16 @@ import type { GetDIDRequestParams, ResolveDIDRequestParams, DeactivateDIDRequestBody, -} from '../types/did.js'; -import { check, validationResult, param } from './validator/index.js'; +} from '../../types/did.js'; +import { check, validationResult, param } from '../validator/index.js'; import type { IKey, RequireOnly } from '@veramo/core'; import { extractPublicKeyHex } from '@veramo/utils'; -import type { ValidationErrorResponseBody } from '../types/shared.js'; -import type { KeyImport } from '../types/key.js'; -import { eventTracker } from '../services/track/tracker.js'; -import { OperationCategoryNameEnum, OperationNameEnum } from '../types/constants.js'; -import type { IDIDTrack, ITrackOperation } from '../types/track.js'; -import { arePublicKeyHexsInWallet } from '../services/helpers.js'; +import type { ValidationErrorResponseBody } from '../../types/shared.js'; +import type { KeyImport } from '../../types/key.js'; +import { eventTracker } from '../../services/track/tracker.js'; +import { OperationCategoryNameEnum, OperationNameEnum } from '../../types/constants.js'; +import type { IDIDTrack, ITrackOperation } from '../../types/track.js'; +import { arePublicKeyHexsInWallet } from '../../services/helpers.js'; import { CheqdProviderErrorCodes } from '@cheqd/did-provider-cheqd'; import type { CheqdProviderError } from '@cheqd/did-provider-cheqd'; diff --git a/src/controllers/key.ts b/src/controllers/api/key.ts similarity index 96% rename from src/controllers/key.ts rename to src/controllers/api/key.ts index eec745a6..d480178d 100644 --- a/src/controllers/key.ts +++ b/src/controllers/api/key.ts @@ -1,7 +1,7 @@ import type { Request, Response } from 'express'; import { StatusCodes } from 'http-status-codes'; -import { IdentityServiceStrategySetup } from '../services/identity/index.js'; -import { decryptPrivateKey } from '../helpers/helpers.js'; +import { IdentityServiceStrategySetup } from '../../services/identity/index.js'; +import { decryptPrivateKey } from '../../helpers/helpers.js'; import { toString } from 'uint8arrays'; import type { CreateKeyResponseBody, @@ -12,11 +12,11 @@ import type { UnsuccessfulCreateKeyResponseBody, UnsuccessfulImportKeyResponseBody, UnsuccessfulQueryKeyResponseBody, -} from '../types/key.js'; -import { check } from './validator/index.js'; -import { eventTracker } from '../services/track/tracker.js'; -import type { IKeyTrack, ITrackOperation } from '../types/track.js'; -import { OperationCategoryNameEnum, OperationNameEnum } from '../types/constants.js'; +} from '../../types/key.js'; +import { check } from '../validator/index.js'; +import { eventTracker } from '../../services/track/tracker.js'; +import type { IKeyTrack, ITrackOperation } from '../../types/track.js'; +import { OperationCategoryNameEnum, OperationNameEnum } from '../../types/constants.js'; // ToDo: Make the format of /key/create and /key/read the same // ToDo: Add valdiation for /key/import diff --git a/src/controllers/presentation.ts b/src/controllers/api/presentation.ts similarity index 95% rename from src/controllers/presentation.ts rename to src/controllers/api/presentation.ts index 4446b652..d3ec020e 100644 --- a/src/controllers/presentation.ts +++ b/src/controllers/api/presentation.ts @@ -1,9 +1,9 @@ import type { Request, Response } from 'express'; import { StatusCodes } from 'http-status-codes'; -import { check, validationResult, query } from './validator/index.js'; -import { IdentityServiceStrategySetup } from '../services/identity/index.js'; -import { CheqdW3CVerifiablePresentation } from '../services/w3c-presentation.js'; +import { check, validationResult, query } from '../validator/index.js'; +import { IdentityServiceStrategySetup } from '../../services/identity/index.js'; +import { CheqdW3CVerifiablePresentation } from '../../services/w3c-presentation.js'; import type { CreatePresentationRequestBody, CreatePresentationResponseBody, @@ -12,12 +12,12 @@ import type { VerifyPresentationRequestBody, VerifyPresentationResponseBody, VerifyPresentationResponseQuery, -} from '../types/presentation.js'; -import { isIssuerDidDeactivated } from '../services/helpers.js'; -import type { ValidationErrorResponseBody } from '../types/shared.js'; -import { OperationCategoryNameEnum, OperationNameEnum } from '../types/constants.js'; -import { eventTracker } from '../services/track/tracker.js'; -import type { IFeePaymentOptions, IPresentationTrack, ITrackOperation } from '../types/track.js'; +} from '../../types/presentation.js'; +import { isIssuerDidDeactivated } from '../../services/helpers.js'; +import type { ValidationErrorResponseBody } from '../../types/shared.js'; +import { OperationCategoryNameEnum, OperationNameEnum } from '../../types/constants.js'; +import { eventTracker } from '../../services/track/tracker.js'; +import type { IFeePaymentOptions, IPresentationTrack, ITrackOperation } from '../../types/track.js'; export class PresentationController { public static presentationCreateValidator = [ diff --git a/src/controllers/resource.ts b/src/controllers/api/resource.ts similarity index 95% rename from src/controllers/resource.ts rename to src/controllers/api/resource.ts index a4aaf599..5251fd5b 100644 --- a/src/controllers/resource.ts +++ b/src/controllers/api/resource.ts @@ -3,13 +3,13 @@ import { fromString } from 'uint8arrays'; import { v4 } from 'uuid'; import type { MsgCreateResourcePayload } from '@cheqd/ts-proto/cheqd/resource/v2/index.js'; import { StatusCodes } from 'http-status-codes'; -import { IdentityServiceStrategySetup } from '../services/identity/index.js'; -import { getQueryParams } from '../helpers/helpers.js'; +import { IdentityServiceStrategySetup } from '../../services/identity/index.js'; +import { getQueryParams } from '../../helpers/helpers.js'; import { DIDMetadataDereferencingResult, DefaultResolverUrl } from '@cheqd/did-provider-cheqd'; -import type { ValidationErrorResponseBody } from '../types/shared.js'; -import type { IResourceTrack, ITrackOperation } from '../types/track.js'; -import { OperationCategoryNameEnum, OperationNameEnum } from '../types/constants.js'; -import { check, validationResult, param, query } from './validator/index.js'; +import type { ValidationErrorResponseBody } from '../../types/shared.js'; +import type { IResourceTrack, ITrackOperation } from '../../types/track.js'; +import { OperationCategoryNameEnum, OperationNameEnum } from '../../types/constants.js'; +import { check, validationResult, param, query } from '../validator/index.js'; import type { CreateResourceRequestBody, CreateResourceResponseBody, @@ -17,9 +17,9 @@ import type { SearchResourceRequestParams, UnsuccessfulCreateResourceResponseBody, UnsuccessfulQueryResourceResponseBody, -} from '../types/resource.js'; -import { eventTracker } from '../services/track/tracker.js'; -import { arePublicKeyHexsInWallet } from '../services/helpers.js'; +} from '../../types/resource.js'; +import { eventTracker } from '../../services/track/tracker.js'; +import { arePublicKeyHexsInWallet } from '../../services/helpers.js'; export class ResourceController { public static createResourceValidator = [ diff --git a/src/static/swagger-admin-options.json b/src/static/swagger-admin-options.json new file mode 100644 index 00000000..4e4498c5 --- /dev/null +++ b/src/static/swagger-admin-options.json @@ -0,0 +1,31 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "Credential Service admin API for cheqd network", + "version": "2.0.0", + "description": "Admin API which handles users subscriptions and payments", + "contact": { + "name": "Cheqd Foundation Limited", + "url": "https://github.com/cheqd/credential-service", + "email": "support-github@cheqd.io" + }, + "license": { + "name": "Apache 2.0", + "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" + } + }, + "tags": [ + { + "name": "Product" + }, + { + "name": "Price" + }, + { + "name": "Customer" + }, + { + "name": "Subscription" + } + ] +} diff --git a/src/static/swagger-admin.json b/src/static/swagger-admin.json new file mode 100644 index 00000000..022bcf36 --- /dev/null +++ b/src/static/swagger-admin.json @@ -0,0 +1,662 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "Credential Service admin API for cheqd network", + "version": "2.0.0", + "description": "Admin API which handles users subscriptions and payments", + "contact": { + "name": "Cheqd Foundation Limited", + "url": "https://github.com/cheqd/credential-service", + "email": "support-github@cheqd.io" + }, + "license": { + "name": "Apache 2.0", + "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" + } + }, + "tags": [ + { + "name": "Product" + }, + { + "name": "Price" + }, + { + "name": "Customer" + }, + { + "name": "Subscription" + } + ], + "paths": { + "/admin/price/list": { + "get": { + "summary": "Get a list of prices", + "description": "Get a list of prices", + "tags": [ + "Price" + ], + "parameters": [ + { + "in": "query", + "name": "productId", + "schema": { + "type": "string", + "description": "The product id. If passed - returns filtered by this product list of prices.", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A list of prices", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PriceListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/product/list": { + "get": { + "summary": "Get a list of products", + "description": "Get a list of products which are on a Stripe side", + "tags": [ + "Product" + ], + "parameters": [ + { + "in": "query", + "name": "prices", + "schema": { + "type": "boolean", + "description": "If setup to true - returns the list of products with prices inside. Default - true", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A list of products", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProductListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/product/{productId}": { + "get": { + "summary": "Get a product", + "description": "Get a product by id", + "tags": [ + "Product" + ], + "parameters": [ + { + "in": "path", + "name": "productId", + "schema": { + "type": "string", + "description": "The product id which identifies the product in Stripe", + "required": true + } + }, + { + "in": "query", + "name": "prices", + "schema": { + "type": "boolean", + "description": "If setup to true - returns the product with prices inside. Default - true", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A product", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProductGetResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/create": { + "post": { + "summary": "Create a subscription", + "description": "Creates a new subscription for an existing customer", + "tags": [ + "Subscription" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCreateRequestBody" + } + } + } + }, + "responses": { + "201": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCreateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/update": { + "post": { + "summary": "Update a subscription", + "description": "Updates an existing subscription", + "tags": [ + "Subscription" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionUpdateRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionUpdateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/list": { + "get": { + "summary": "Get a list of subscriptions", + "description": "Get a list of subscriptions", + "tags": [ + "Subscription" + ], + "parameters": [ + { + "in": "query", + "name": "customerId", + "schema": { + "type": "string", + "description": "The customer id. If passed - returns filtered by this customer list of subscriptions.", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A list of subscriptions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/get/{subscriptionId}": { + "get": { + "summary": "Get a subscription", + "description": "Get a subscription", + "tags": [ + "Subscription" + ], + "parameters": [ + { + "in": "path", + "name": "subscriptionId", + "schema": { + "type": "string", + "description": "The subscription id", + "required": true + } + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionGetResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/cancel": { + "post": { + "summary": "Cancel a subscription", + "description": "Cancels an existing subscription", + "tags": [ + "Subscription" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCancelRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCancelResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/resume": {}, + "post": { + "summary": "Resume a subscription", + "description": "Resumes an existing subscription", + "tags": [ + "Subscription" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionResumeRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionResumeResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "components": { + "schemas": { + "PriceListResponseBody": { + "description": "A list of active prcies from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/list)", + "type": "object", + "properties": { + "prices": { + "type": "array", + "items": { + "type": "object", + "description": "A price object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/object)" + } + } + } + }, + "ProductListResponseBody": { + "type": "object", + "properties": { + "products": { + "type": "array", + "items": { + "type": "object", + "description": "A product object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/object)" + } + } + } + }, + "ProductGetResponseBody": { + "description": "A product with or without prices inside. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/retrieve)", + "type": "object" + }, + "InvalidRequest": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "InvalidRequest" + } + } + }, + "InternalError": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Internal Error" + } + } + }, + "UnauthorizedError": { + "description": "Access token is missing or invalid", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Unauthorized Error" + } + } + }, + "SubscriptionCreateRequestBody": { + "description": "The request body for creating a subscription", + "type": "object", + "properties": { + "customerId": { + "type": "string", + "description": "The Stripe customer id", + "example": "cus_1234567890" + }, + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "price": { + "type": "string", + "description": "The price id", + "example": "price_1234567890" + } + } + } + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": 1234567890 + } + } + }, + "SubscriptionCreateResponseBody": { + "description": "The response body for creating a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" + } + } + }, + "SubscriptionUpdateRequestBody": { + "description": "The request body for updating a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + }, + "updateParams": { + "type": "object", + "description": "The subscription update parameters. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/update)" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": 1234567890 + } + } + }, + "SubscriptionUpdateResponseBody": { + "description": "The response body for updating a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" + } + } + }, + "SubscriptionGetRequestBody": { + "description": "The request body for getting a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + } + } + }, + "SubscriptionGetResponseBody": { + "description": "The response body for getting a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" + } + } + }, + "SubscriptionListRequestBody": { + "description": "The request body for listing subscriptions", + "type": "object", + "properties": { + "customerId": { + "type": "string", + "description": "The Stripe customer id", + "example": "cus_1234567890" + } + } + }, + "SubscriptionListResponseBody": { + "description": "The response body for listing subscriptions", + "type": "object", + "properties": { + "subscriptions": { + "type": "array", + "items": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + } + } + } + }, + "SubscriptionCancelRequestBody": { + "description": "The request body for canceling a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + } + } + }, + "SubscriptionCancelResponseBody": { + "description": "The response body for canceling a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": 1234567890 + } + } + }, + "SubscriptionResumeRequestBody": { + "description": "The request body for resuming a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": 1234567890 + } + } + }, + "SubscriptionResumeResponseBody": { + "description": "The response body for resuming a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + } + } + }, + "NotFoundError": { + "description": "The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Not Found Error" + } + } + } + } + } +} \ No newline at end of file diff --git a/src/static/swagger-options.json b/src/static/swagger-api-options.json similarity index 100% rename from src/static/swagger-options.json rename to src/static/swagger-api-options.json diff --git a/src/static/swagger.json b/src/static/swagger-api.json similarity index 100% rename from src/static/swagger.json rename to src/static/swagger-api.json diff --git a/src/types/swagger-admin-types.ts b/src/types/swagger-admin-types.ts new file mode 100644 index 00000000..e7ac6ea1 --- /dev/null +++ b/src/types/swagger-admin-types.ts @@ -0,0 +1,175 @@ +/** + * @openapi + * + * components: + * schemas: + * PriceListResponseBody: + * description: A list of active prcies from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/list) + * type: object + * properties: + * prices: + * type: array + * items: + * type: object + * description: A price object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/object) + * ProductListResponseBody: + * type: object + * properties: + * products: + * type: array + * items: + * type: object + * description: A product object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/object) + * ProductGetResponseBody: + * description: A product with or without prices inside. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/retrieve) + * type: object + * InvalidRequest: + * description: A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body. + * type: object + * properties: + * error: + * type: string + * example: InvalidRequest + * InternalError: + * description: An internal error has occurred. Additional state information plus metadata may be available in the response body. + * type: object + * properties: + * error: + * type: string + * example: Internal Error + * UnauthorizedError: + * description: Access token is missing or invalid + * type: object + * properties: + * error: + * type: string + * example: Unauthorized Error + * SubscriptionCreateRequestBody: + * description: The request body for creating a subscription + * type: object + * properties: + * customerId: + * type: string + * description: The Stripe customer id + * example: cus_1234567890 + * items: + * type: array + * items: + * type: object + * properties: + * price: + * type: string + * description: The price id + * example: price_1234567890 + * idempotencyKey: + * type: string + * description: The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request. + * example: 1234567890 + * + * SubscriptionCreateResponseBody: + * description: The response body for creating a subscription + * type: object + * properties: + * subscription: + * type: object + * description: A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object) + * SubscriptionUpdateRequestBody: + * description: The request body for updating a subscription + * type: object + * properties: + * subscriptionId: + * type: string + * description: The subscription id + * example: sub_1234567890 + * updateParams: + * type: object + * description: The subscription update parameters. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/update) + * idempotencyKey: + * type: string + * description: The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request. + * example: 1234567890 + * SubscriptionUpdateResponseBody: + * description: The response body for updating a subscription + * type: object + * properties: + * subscription: + * type: object + * description: A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object) + * SubscriptionGetRequestBody: + * description: The request body for getting a subscription + * type: object + * properties: + * subscriptionId: + * type: string + * description: The subscription id + * example: sub_1234567890 + * SubscriptionGetResponseBody: + * description: The response body for getting a subscription + * type: object + * properties: + * subscription: + * type: object + * description: A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object) + * SubscriptionListRequestBody: + * description: The request body for listing subscriptions + * type: object + * properties: + * customerId: + * type: string + * description: The Stripe customer id + * example: cus_1234567890 + * SubscriptionListResponseBody: + * description: The response body for listing subscriptions + * type: object + * properties: + * subscriptions: + * type: array + * items: + * type: object + * description: A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object] + * SubscriptionCancelRequestBody: + * description: The request body for canceling a subscription + * type: object + * properties: + * subscriptionId: + * type: string + * description: The subscription id + * example: sub_1234567890 + * SubscriptionCancelResponseBody: + * description: The response body for canceling a subscription + * type: object + * properties: + * subscription: + * type: object + * description: A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object] + * idempotencyKey: + * type: string + * description: The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request. + * example: 1234567890 + * SubscriptionResumeRequestBody: + * description: The request body for resuming a subscription + * type: object + * properties: + * subscriptionId: + * type: string + * description: The subscription id + * example: sub_1234567890 + * idempotencyKey: + * type: string + * description: The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request. + * example: 1234567890 + * SubscriptionResumeResponseBody: + * description: The response body for resuming a subscription + * type: object + * properties: + * subscription: + * type: object + * description: A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object] + * NotFoundError: + * description: The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible. + * type: object + * properties: + * error: + * type: string + * example: Not Found Error + */ diff --git a/src/types/swagger-types.ts b/src/types/swagger-api-types.ts similarity index 100% rename from src/types/swagger-types.ts rename to src/types/swagger-api-types.ts From 77bb82227548cb177c6d1f7076956142d30bf0c1 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Sun, 10 Mar 2024 00:05:16 +0100 Subject: [PATCH 03/40] - Add Stripe webhook handling - Add subscription entity - Add chekout API guarding --- README.md | 1 + docker/Dockerfile | 2 + src/app.ts | 14 +- src/controllers/admin/checkout-session.ts | 117 +++++ src/controllers/admin/portal-customer.ts | 2 + src/controllers/admin/product.ts | 4 +- src/controllers/admin/subscriptions.ts | 15 +- src/controllers/admin/webhook.ts | 121 +++++ src/controllers/api/account.ts | 23 +- src/controllers/api/credential.ts | 2 +- src/controllers/api/did.ts | 6 +- src/database/entities/customer.entity.ts | 6 + src/database/entities/subscription.entity.ts | 89 ++++ src/database/migrations/AlterCustomerTable.ts | 20 + .../AlterOperationTableNewCategory.ts | 22 + .../migrations/CreateSubscriptionTable.ts | 38 ++ src/database/types/enum.ts | 3 +- src/database/types/types.ts | 11 + src/middleware/auth/base-auth-handler.ts | 22 +- .../auth/routes/admin/admin-auth.ts | 18 + src/middleware/auth/user-info-fetcher/base.ts | 7 +- .../auth/user-info-fetcher/m2m-token.ts | 5 +- .../auth/user-info-fetcher/portal-token.ts | 86 ++++ src/middleware/authentication.ts | 11 +- src/services/admin/subscription.ts | 74 +++ src/services/{ => api}/api-key.ts | 8 +- src/services/{ => api}/coin.ts | 6 +- src/services/{ => api}/credentials.ts | 10 +- src/services/{ => api}/customer.ts | 27 +- src/services/{ => api}/identifier.ts | 6 +- src/services/{ => api}/key.ts | 6 +- src/services/{ => api}/operation.ts | 6 +- src/services/{ => api}/payment-account.ts | 8 +- src/services/{ => api}/payment.ts | 12 +- src/services/{ => api}/resource.ts | 10 +- src/services/{ => api}/role.ts | 4 +- src/services/{ => api}/store.ts | 0 src/services/{ => api}/user.ts | 8 +- src/services/helpers.ts | 2 +- src/services/identity/postgres.ts | 8 +- src/services/track/admin/account-submitter.ts | 60 +++ .../track/admin/subscription-submitter.ts | 161 ++++++ .../track/api/credential-status-subscriber.ts | 44 ++ .../track/api/credential-subscriber.ts | 44 ++ src/services/track/api/did-subscriber.ts | 43 ++ src/services/track/api/key-subscriber.ts | 45 ++ .../track/api/presentation-subscriber.ts | 44 ++ src/services/track/api/resource-subscriber.ts | 134 +++++ src/services/track/base.ts | 2 +- src/services/track/observer.ts | 30 +- src/services/track/operation-subscriber.ts | 157 ++++++ src/services/track/submitter.ts | 24 + src/services/track/subscribers.ts | 463 ------------------ src/services/track/tracker.ts | 52 +- src/services/track/types.ts | 3 +- src/static/swagger-admin-options.json | 3 + src/static/swagger-admin.json | 67 +++ src/types/constants.ts | 9 + src/types/environment.d.ts | 1 + src/types/portal.ts | 20 +- src/types/swagger-admin-types.ts | 20 + src/types/track.ts | 2 +- 62 files changed, 1699 insertions(+), 569 deletions(-) create mode 100644 src/controllers/admin/checkout-session.ts create mode 100644 src/controllers/admin/webhook.ts create mode 100644 src/database/entities/subscription.entity.ts create mode 100644 src/database/migrations/AlterCustomerTable.ts create mode 100644 src/database/migrations/AlterOperationTableNewCategory.ts create mode 100644 src/database/migrations/CreateSubscriptionTable.ts create mode 100644 src/middleware/auth/routes/admin/admin-auth.ts create mode 100644 src/middleware/auth/user-info-fetcher/portal-token.ts create mode 100644 src/services/admin/subscription.ts rename src/services/{ => api}/api-key.ts (88%) rename src/services/{ => api}/coin.ts (87%) rename src/services/{ => api}/credentials.ts (82%) rename src/services/{ => api}/customer.ts (76%) rename src/services/{ => api}/identifier.ts (81%) rename src/services/{ => api}/key.ts (86%) rename src/services/{ => api}/operation.ts (90%) rename src/services/{ => api}/payment-account.ts (88%) rename src/services/{ => api}/payment.ts (84%) rename src/services/{ => api}/resource.ts (89%) rename src/services/{ => api}/role.ts (92%) rename src/services/{ => api}/store.ts (100%) rename src/services/{ => api}/user.ts (85%) create mode 100644 src/services/track/admin/account-submitter.ts create mode 100644 src/services/track/admin/subscription-submitter.ts create mode 100644 src/services/track/api/credential-status-subscriber.ts create mode 100644 src/services/track/api/credential-subscriber.ts create mode 100644 src/services/track/api/did-subscriber.ts create mode 100644 src/services/track/api/key-subscriber.ts create mode 100644 src/services/track/api/presentation-subscriber.ts create mode 100644 src/services/track/api/resource-subscriber.ts create mode 100644 src/services/track/operation-subscriber.ts create mode 100644 src/services/track/submitter.ts delete mode 100644 src/services/track/subscribers.ts diff --git a/README.md b/README.md index adeff22f..916a6c33 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,7 @@ The application supports Stripe integration for payment processing. 1. `STRIPE_SECRET_KEY`: Secret key for Stripe API. Please, keep it secret on deploying 2. `STRIPE_PUBLISHABLE_KEY` - Publishable key for Stripe API. +3. `STRIPE_WEBHOOK_SECRET` - Secret for Stripe Webhook. ### 3rd Party Connectors diff --git a/docker/Dockerfile b/docker/Dockerfile index 9f7f3c8a..c3da44e0 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -84,6 +84,7 @@ ARG TESTNET_MINIMUM_BALANCE=1000 # Stripe ARG STRIPE_SECRET_KEY ARG STRIPE_PUBLISHABLE_KEY +ARG STRIPE_WEBHOOK_SECRET # Environment variables: base configuration ENV NPM_CONFIG_LOGLEVEL ${NPM_CONFIG_LOGLEVEL} @@ -132,6 +133,7 @@ ENV POLYGON_PRIVATE_KEY ${POLYGON_PRIVATE_KEY} # Environment variables: Stripe ENV STRIPE_SECRET_KEY ${STRIPE_SECRET_KEY} ENV STRIPE_PUBLISHABLE_KEY ${STRIPE_PUBLISHABLE_KEY} +ENV STRIPE_WEBHOOK_SECRET ${STRIPE_WEBHOOK_SECRET} # Set ownership permissions RUN chown -R node:node /home/node/app diff --git a/src/app.ts b/src/app.ts index 4d4ce21f..06771e39 100644 --- a/src/app.ts +++ b/src/app.ts @@ -21,7 +21,7 @@ dotenv.config(); // Define Swagger file import swaggerAPIDocument from './static/swagger-api.json' assert { type: 'json' }; -import swaggerAdminDocument from './static/swagger-admin.json' assert { type: 'json' }; +// import swaggerAdminDocument from './static/swagger-admin.json' assert { type: 'json' }; import { PresentationController } from './controllers/api/presentation.js'; import { KeyController } from './controllers/api/key.js'; import { DIDController } from './controllers/api/did.js'; @@ -30,6 +30,8 @@ import { FailedResponseTracker } from './middleware/event-tracker.js'; import { ProductController } from './controllers/admin/product.js'; import { SubscriptionController } from './controllers/admin/subscriptions.js'; import { PriceController } from './controllers/admin/prices.js'; +import { WebhookController } from './controllers/admin/webhook.js'; +import { CheckoutSessionController } from './controllers/admin/checkout-session.js'; let swaggerOptions = {}; if (process.env.ENABLE_AUTHENTICATION === 'true') { @@ -100,8 +102,8 @@ class App { } this.express.use(express.text()); - this.express.use('/swagger', swaggerUi.serve, swaggerUi.setup(swaggerAPIDocument, swaggerOptions)); - this.express.use('/admin/swagger', swaggerUi.serve, swaggerUi.setup(swaggerAdminDocument)) + this.express.use('/swagger', swaggerUi.serveFiles(swaggerAPIDocument, swaggerOptions), swaggerUi.setup(swaggerAPIDocument, swaggerOptions)); + // this.express.use('/admin/swagger', swaggerUi.serveFiles(swaggerAdminDocument), swaggerUi.setup(swaggerAdminDocument)) this.express.use(auth.handleError); this.express.use(async (req, res, next) => await auth.accessControl(req, res, next)); } @@ -227,6 +229,12 @@ class App { app.delete('/admin/subscription/cancel', SubscriptionController.subscriptionCancelValidator, new SubscriptionController().cancel); app.post('/admin/subscription/resume', SubscriptionController.subscriptionResumeValidator, new SubscriptionController().resume); + // Checkout session + app.post('/admin/checkout/session/create', CheckoutSessionController.checkoutSessionCreateValidator, new CheckoutSessionController().create); + + // Webhook + app.post('/admin/webhook', new WebhookController().handleWebhook); + // 404 for all other requests app.all('*', (_req, res) => res.status(StatusCodes.BAD_REQUEST).send('Bad request')); } diff --git a/src/controllers/admin/checkout-session.ts b/src/controllers/admin/checkout-session.ts new file mode 100644 index 00000000..4477e0e6 --- /dev/null +++ b/src/controllers/admin/checkout-session.ts @@ -0,0 +1,117 @@ + +import Stripe from 'stripe'; +import type { Request, Response } from 'express'; +import * as dotenv from 'dotenv'; +import type { CheckoutSessionCreateRequestBody, CheckoutSessionCreateUnsuccessfulResponseBody } from '../../types/portal.js'; +import { check, validationResult } from '../validator/index.js'; +import { StatusCodes } from 'http-status-codes'; + +dotenv.config(); + +const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); + + +export class CheckoutSessionController { + static checkoutSessionCreateValidator = [ + check('price') + .exists() + .withMessage('price is required') + .bail() + .isString() + .withMessage('price should be a string') + .bail(), + check('successURL') + .exists() + .withMessage('successURL is required') + .bail() + .isString() + .withMessage('successURL should be a string') + .bail(), + check('cancelURL') + .exists() + .withMessage('cancelURL is required') + .bail() + .isString() + .withMessage('cancelURL should be a string') + .bail(), + check('idempotencyKey') + .optional() + .isString() + .withMessage('idempotencyKey should be a string') + .bail(), + ]; + + /** + * @openapi + * + * /admin/checkout/session/create: + * post: + * summary: Create a checkout session + * description: Create a checkout session + * tags: [Checkout] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/CheckoutSessionCreateRequestBody' + * responses: + * 303: + * description: A redirect to Stripe prebuilt checkout page + * 400: + * $ref: '#/components/schemas/InvalidRequest' + * 401: + * $ref: '#/components/schemas/UnauthorizedError' + * 500: + * $ref: '#/components/schemas/InternalError' + */ + + public async create(request: Request, response: Response) { + const result = validationResult(request); + // handle error + if (!result.isEmpty()) { + return response.status(StatusCodes.BAD_REQUEST).json({ + error: result.array().pop()?.msg + } satisfies CheckoutSessionCreateUnsuccessfulResponseBody); + } + + const { price, successURL, cancelURL, quantity, idempotencyKey } = request.body satisfies CheckoutSessionCreateRequestBody; + try { + const session = await stripe.checkout.sessions.create({ + mode: 'subscription', + customer: response.locals.customer.stripeCustomerId, + line_items: [ + { + price: price, + quantity: quantity || 1, + }, + ], + success_url: successURL, + cancel_url: cancelURL, + }, { + idempotencyKey + }); + + if (session.lastResponse?.statusCode !== StatusCodes.OK) { + return response.status(StatusCodes.BAD_GATEWAY).json({ + error: 'Checkout session was not created' + } satisfies CheckoutSessionCreateUnsuccessfulResponseBody); + } + + if (!session.url) { + return response.status(StatusCodes.BAD_GATEWAY).json({ + error: 'Checkout session URL was not provided' + } satisfies CheckoutSessionCreateUnsuccessfulResponseBody); + } + + return response.json({ + url: session.url as string + }) + + } catch (error) { + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: `Internal error: ${(error as Error)?.message || error}` + } satisfies CheckoutSessionCreateUnsuccessfulResponseBody); + } + } +} \ No newline at end of file diff --git a/src/controllers/admin/portal-customer.ts b/src/controllers/admin/portal-customer.ts index 67a262e9..c092d4e9 100644 --- a/src/controllers/admin/portal-customer.ts +++ b/src/controllers/admin/portal-customer.ts @@ -24,6 +24,8 @@ export class PortalCustomerController { } satisfies PortalCustomerGetUnsuccessfulResponseBody); } + + return response.status(500).json({ error: "Not implemented yet" }) diff --git a/src/controllers/admin/product.ts b/src/controllers/admin/product.ts index d1d23786..23f81c35 100644 --- a/src/controllers/admin/product.ts +++ b/src/controllers/admin/product.ts @@ -178,13 +178,13 @@ export class ProductController { // define error const errorRef = error as Record; - if (errorRef?.statusCode === 404) { + if (errorRef?.statusCode === StatusCodes.NOT_FOUND) { return response.status(StatusCodes.NOT_FOUND).json({ error: `Product with id ${productId} not found` } satisfies ProductGetUnsuccessfulResponseBody); } - return response.status(500).json({ + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ error: `Internal error: ${(error as Error)?.message || error}` } satisfies ProductGetUnsuccessfulResponseBody); } diff --git a/src/controllers/admin/subscriptions.ts b/src/controllers/admin/subscriptions.ts index 3b149a9a..41180ebc 100644 --- a/src/controllers/admin/subscriptions.ts +++ b/src/controllers/admin/subscriptions.ts @@ -1,13 +1,14 @@ -import { Stripe } from 'stripe'; +import Stripe from 'stripe'; import type { Request, Response } from 'express'; import * as dotenv from 'dotenv'; -import type { SubscriptionCreateRequestBody, SubscriptionCreateResponseBody, SubscriptionCreateUnsuccessfulResponseBody, SubscriptionCancelResponseBody, SubscriptionCancelUnsuccessfulResponseBody, SubscriptionGetResponseBody, SubscriptionGetUnsuccessfulResponseBody, SubscriptionListResponseBody, SubscriptionListUnsuccessfulResponseBody, SubscriptionUpdateRequestBody, SubscriptionUpdateResponseBody, SubscriptionUpdateUnsuccessfulResponseBody, SubscriptionResumeUnsuccessfulResponseBody, SubscriptionResumeResponseBody, SubscriptionResumeRequestBody, SubscriptionCancelRequestBody } from '../../types/portal.js'; +import type { SubscriptionCreateRequestBody, SubscriptionCreateResponseBody, SubscriptionCreateUnsuccessfulResponseBody, SubscriptionCancelResponseBody, SubscriptionCancelUnsuccessfulResponseBody, SubscriptionGetResponseBody, SubscriptionGetUnsuccessfulResponseBody, SubscriptionListResponseBody, SubscriptionListUnsuccessfulResponseBody, SubscriptionUpdateRequestBody, SubscriptionUpdateResponseBody, SubscriptionUpdateUnsuccessfulResponseBody, SubscriptionResumeUnsuccessfulResponseBody, SubscriptionResumeResponseBody, SubscriptionResumeRequestBody, SubscriptionCancelRequestBody, PaymentBehavior } from '../../types/portal.js'; import { StatusCodes } from 'http-status-codes'; import { validationResult } from '../validator/index.js'; import { check } from 'express-validator'; dotenv.config(); + const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); export class SubscriptionController { @@ -145,15 +146,17 @@ export class SubscriptionController { const subscription = await stripe.subscriptions.create({ customer: customerId, items: items, + payment_behavior: "default_incomplete" as PaymentBehavior, }, { idempotencyKey: idempotencyKey, }); if (subscription.lastResponse?.statusCode !== StatusCodes.OK) { - return response.status(StatusCodes.NOT_FOUND).json({ + return response.status(StatusCodes.BAD_GATEWAY).json({ error: `Subscription was not created`, } satisfies SubscriptionCreateUnsuccessfulResponseBody); } + return response.status(StatusCodes.CREATED).json({ subscription: subscription } satisfies SubscriptionCreateResponseBody ); @@ -210,7 +213,7 @@ export class SubscriptionController { idempotencyKey: idempotencyKey, }); if (subscription.lastResponse?.statusCode !== StatusCodes.OK) { - return response.status(StatusCodes.NOT_FOUND).json({ + return response.status(StatusCodes.BAD_GATEWAY).json({ error: `Subscription was not updated`, } satisfies SubscriptionUpdateUnsuccessfulResponseBody); } @@ -397,7 +400,7 @@ export class SubscriptionController { // Check if the subscription was cancelled if (subscription.lastResponse?.statusCode !== StatusCodes.OK) { - return response.status(StatusCodes.NOT_FOUND).json({ + return response.status(StatusCodes.BAD_GATEWAY).json({ error: `Subscription was not deleted`, } satisfies SubscriptionCancelUnsuccessfulResponseBody); } @@ -459,7 +462,7 @@ export class SubscriptionController { // Check if the subscription was resumed if (subscription.lastResponse?.statusCode !== StatusCodes.OK) { - return response.status(StatusCodes.NOT_FOUND).json({ + return response.status(StatusCodes.BAD_GATEWAY).json({ error: `Subscription was not resumed`, } satisfies SubscriptionResumeUnsuccessfulResponseBody); } diff --git a/src/controllers/admin/webhook.ts b/src/controllers/admin/webhook.ts new file mode 100644 index 00000000..14debffb --- /dev/null +++ b/src/controllers/admin/webhook.ts @@ -0,0 +1,121 @@ +import Stripe from 'stripe'; +import type { Request, Response } from 'express'; +import * as dotenv from 'dotenv'; +import { StatusCodes } from 'http-status-codes'; +import { EventTracker, eventTracker } from '../../services/track/tracker.js'; +import type { INotifyMessage } from '../../types/track.js'; +import { OperationNameEnum } from '../../types/constants.js'; +import type { ISubmitOperation, ISubmitData } from '../../services/track/submitter.js'; + +dotenv.config(); + +const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); +export class WebhookController { + public async handleWebhook(request: Request, response: Response) { + let event = request.body; + let subscription; + let status; + const builSubmitOperation = ( function(subscription: Stripe.Subscription, name: string) { + return { + operation: name, + data: { + subscriptionId: subscription.id, + stripeCustomerId: subscription.customer as string, + status: subscription.status, + currentPeriodStart: new Date(subscription.current_period_start * 1000), + currentPeriodEnd: new Date(subscription.current_period_end * 1000), + trialStart: subscription.trial_start ? new Date(subscription.trial_start * 1000) : undefined, + trialEnd: subscription.trial_end ? new Date(subscription.trial_end * 1000) : undefined, + } satisfies ISubmitData, + } satisfies ISubmitOperation; + }) + // Only verify the event if you have an endpoint secret defined. + // Otherwise use the basic event deserialized with JSON.parse + // Get the signature sent by Stripe + + if (!process.env.STRIPE_WEBHOOK_SECRET) { + await eventTracker.notify({ + message: 'Stripe webhook secret not found. Webhook ID: ${request.body.id}.', + severity: 'error', + } satisfies INotifyMessage) + return response.sendStatus(StatusCodes.BAD_REQUEST); + } + + const signature = request.headers['stripe-signature']; + if (!signature) { + await eventTracker.notify({ + message: 'Webhook signature not found. Webhook ID: ${request.body.id}.', + severity: 'error', + } satisfies INotifyMessage) + return response.sendStatus(StatusCodes.BAD_REQUEST); + } + + try { + event = stripe.webhooks.constructEvent( + request.rawBody, + signature, + process.env.STRIPE_WEBHOOK_SECRET + ); + } catch (err) { + + await eventTracker.notify({ + message: `Webhook signature verification failed. Webhook ID: ${request.body.id}. Error: ${(err as Record)?.message || err}`, + severity: 'error', + } satisfies INotifyMessage) + return response.sendStatus(StatusCodes.BAD_REQUEST); + } + // Handle the event + switch (event.type) { + case 'customer.subscription.trial_will_end': + subscription = event.data.object; + status = subscription.status; + await eventTracker.notify({ + message: EventTracker.compileBasicNotification(`Subscription status is ${status} for subscription with id: ${subscription.id}`, 'Stripe Webhook: customer.subscription.trial_will_end'), + severity: 'info', + } satisfies INotifyMessage) + await eventTracker.submit(builSubmitOperation(subscription, OperationNameEnum.SUBSCRIPTION_TRIAL_WILL_END)); + break; + case 'customer.subscription.deleted': + subscription = event.data.object; + status = subscription.status; + await eventTracker.notify({ + message: EventTracker.compileBasicNotification(`Subscription status is ${status} for subscription with id: ${subscription.id}`, 'Stripe Webhook: customer.subscription.deleted'), + severity: 'info', + } satisfies INotifyMessage) + await eventTracker.submit(builSubmitOperation(subscription, OperationNameEnum.SUBSCRIPTION_CANCEL)); + // Then define and call a method to handle the subscription deleted. + // handleSubscriptionDeleted(subscriptionDeleted); + break; + case 'customer.subscription.created': + subscription = event.data.object; + status = subscription.status; + await eventTracker.notify({ + message: EventTracker.compileBasicNotification(`Subscription status is ${status} for subscription with id: ${subscription.id}`, 'Stripe Webhook: customer.subscription.created'), + severity: 'info', + } satisfies INotifyMessage) + await eventTracker.submit(builSubmitOperation(subscription, OperationNameEnum.SUBSCRIPTION_CREATE)); + // Then define and call a method to handle the subscription created. + // handleSubscriptionCreated(subscription); + break; + case 'customer.subscription.updated': + subscription = event.data.object; + status = subscription.status; + await eventTracker.notify({ + message: EventTracker.compileBasicNotification(`Subscription status is ${status} for subscription with id: ${subscription.id}`, 'Stripe Webhook: customer.subscription.updated'), + severity: 'info', + } satisfies INotifyMessage) + await eventTracker.submit(builSubmitOperation(subscription, OperationNameEnum.SUBSCRIPTION_UPDATE)); + // Then define and call a method to handle the subscription update. + // handleSubscriptionUpdated(subscription); + break; + default: + // Unexpected event type + eventTracker.notify({ + message: EventTracker.compileBasicNotification(`Unexpected event type: ${event.type}`, 'Stripe Webhook: unexpected'), + severity: 'error', + } satisfies INotifyMessage) + } + // Return a 200 response to acknowledge receipt of the event + return response.status(StatusCodes.OK).send(); + } +} \ No newline at end of file diff --git a/src/controllers/api/account.ts b/src/controllers/api/account.ts index 0e32cac1..a9312916 100644 --- a/src/controllers/api/account.ts +++ b/src/controllers/api/account.ts @@ -1,14 +1,14 @@ import type { Request, Response } from 'express'; import { CheqdNetwork, checkBalance } from '@cheqd/sdk'; -import { TESTNET_MINIMUM_BALANCE, DEFAULT_DENOM_EXPONENT } from '../../types/constants.js'; -import { CustomerService } from '../../services/customer.js'; +import { TESTNET_MINIMUM_BALANCE, DEFAULT_DENOM_EXPONENT, OperationNameEnum } from '../../types/constants.js'; +import { CustomerService } from '../../services/api/customer.js'; import { LogToHelper } from '../../middleware/auth/logto-helper.js'; import { FaucetHelper } from '../../helpers/faucet.js'; import { StatusCodes } from 'http-status-codes'; import { LogToWebHook } from '../../middleware/hook.js'; -import { UserService } from '../../services/user.js'; -import { RoleService } from '../../services/role.js'; -import { PaymentAccountService } from '../../services/payment-account.js'; +import { UserService } from '../../services/api/user.js'; +import { RoleService } from '../../services/api/role.js'; +import { PaymentAccountService } from '../../services/api/payment-account.js'; import type { CustomerEntity } from '../../database/entities/customer.entity.js'; import type { UserEntity } from '../../database/entities/user.entity.js'; import type { PaymentAccountEntity } from '../../database/entities/payment.account.entity.js'; @@ -21,6 +21,8 @@ import type { } from '../../types/customer.js'; import type { UnsuccessfulResponseBody } from '../../types/shared.js'; import { check, validationResult } from 'express-validator'; +import { eventTracker } from '../../services/track/tracker.js'; +import type { ISubmitOperation, ISubmitStripeCustomerCreateData } from '../../services/track/submitter.js'; export class AccountController { public static createValidator = [ @@ -302,6 +304,17 @@ export class AccountController { } } } + // 8. Add the Stripe account to the Customer + if (customer.stripeCustomerId === null) { + eventTracker.submit({ + operation: OperationNameEnum.STRIPE_ACCOUNT_CREATE, + data: { + name: customer.name, + customerId: customer.customerId, + } satisfies ISubmitStripeCustomerCreateData, + } satisfies ISubmitOperation) + } + return response.status(StatusCodes.OK).json({}); } diff --git a/src/controllers/api/credential.ts b/src/controllers/api/credential.ts index 8737de86..7cbea5f1 100644 --- a/src/controllers/api/credential.ts +++ b/src/controllers/api/credential.ts @@ -4,7 +4,7 @@ import { StatusCodes } from 'http-status-codes'; import { check, validationResult, query } from '../validator/index.js'; -import { Credentials } from '../../services/credentials.js'; +import { Credentials } from '../../services/api/credentials.js'; import { IdentityServiceStrategySetup } from '../../services/identity/index.js'; import type { ValidationErrorResponseBody } from '../../types/shared.js'; import { CheqdW3CVerifiableCredential } from '../../services/w3c-credential.js'; diff --git a/src/controllers/api/did.ts b/src/controllers/api/did.ts index 1b062492..d41e06f9 100644 --- a/src/controllers/api/did.ts +++ b/src/controllers/api/did.ts @@ -665,11 +665,13 @@ export class DIDController { // Extract did from params const { did } = request.params as GetDIDRequestParams; // Get strategy e.g. postgres or local - const identityServiceStrategySetup = new IdentityServiceStrategySetup(response.locals.customer.customerId); + const identityServiceStrategySetup = response.locals.customer + ? new IdentityServiceStrategySetup(response.locals.customer.customerId) + : new IdentityServiceStrategySetup(); try { const didDocument = did - ? await identityServiceStrategySetup.agent.resolveDid(request.params.did) + ? await identityServiceStrategySetup.agent.resolveDid(did) : await identityServiceStrategySetup.agent.listDids(response.locals.customer); return response diff --git a/src/database/entities/customer.entity.ts b/src/database/entities/customer.entity.ts index 6426c24d..6d5f8a52 100644 --- a/src/database/entities/customer.entity.ts +++ b/src/database/entities/customer.entity.ts @@ -26,6 +26,12 @@ export class CustomerEntity { }) updatedAt!: Date; + @Column({ + type: 'text', + nullable: true, + }) + stripeCustomerId!: string; + @BeforeInsert() setCreatedAt() { this.createdAt = new Date(); diff --git a/src/database/entities/subscription.entity.ts b/src/database/entities/subscription.entity.ts new file mode 100644 index 00000000..125d89de --- /dev/null +++ b/src/database/entities/subscription.entity.ts @@ -0,0 +1,89 @@ +import { BeforeInsert, BeforeUpdate, Column, Entity, JoinColumn, ManyToOne } from 'typeorm'; + +import * as dotenv from 'dotenv'; +import { CustomerEntity } from './customer.entity.js'; +dotenv.config(); + +@Entity('subscription') +export class SubscriptionEntity { + @Column({ + type: 'text', + nullable: false, + primary: true, + }) + subscriptionId!: string; + + @Column({ + type: 'text', + nullable: false, + }) + status!: string; + + @Column({ + type: 'timestamptz', + nullable: false, + }) + currentPeriodStart!: Date; + + @Column({ + type: 'timestamptz', + nullable: false, + }) + currentPeriodEnd!: Date; + + @Column({ + type: 'timestamptz', + nullable: true, + }) + trialStart!: Date; + + @Column({ + type: 'timestamptz', + nullable: true, + }) + trialEnd!: Date; + + @Column({ + type: 'timestamptz', + nullable: false, + }) + createdAt!: Date; + + @Column({ + type: 'timestamptz', + nullable: true, + }) + updatedAt!: Date; + + @BeforeInsert() + setCreatedAt() { + this.createdAt = new Date(); + } + + @BeforeUpdate() + setUpdateAt() { + this.updatedAt = new Date(); + } + + @ManyToOne(() => CustomerEntity, (customer) => customer.customerId) + @JoinColumn({ name: 'customerId' }) + customer!: CustomerEntity; + + constructor( + subscriptionId: string, + customer: CustomerEntity, + status: string, + currentPeriodStart: Date, + currentPeriodEnd: Date, + trialStart: Date, + trialEnd: Date, + ){ + this.subscriptionId = subscriptionId; + this.customer = customer; + this.status = status; + this.currentPeriodStart = currentPeriodStart; + this.currentPeriodEnd = currentPeriodEnd; + this.trialStart = trialStart; + this.trialEnd = trialEnd; + } +} diff --git a/src/database/migrations/AlterCustomerTable.ts b/src/database/migrations/AlterCustomerTable.ts new file mode 100644 index 00000000..7792647d --- /dev/null +++ b/src/database/migrations/AlterCustomerTable.ts @@ -0,0 +1,20 @@ +import { TableColumn, type MigrationInterface, type QueryRunner } from 'typeorm'; + +export class AlterCustomerTable1695740346000 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + const table_name = 'customer'; + + await queryRunner.addColumn( + table_name, + new TableColumn({ + name: 'stripeAccountId', + type: 'text', + isNullable: true, + }) + ); + } + + public async down(queryRunner: QueryRunner): Promise { + throw new Error('illegal_operation: cannot roll back initial migration'); + } +} diff --git a/src/database/migrations/AlterOperationTableNewCategory.ts b/src/database/migrations/AlterOperationTableNewCategory.ts new file mode 100644 index 00000000..fd33b50e --- /dev/null +++ b/src/database/migrations/AlterOperationTableNewCategory.ts @@ -0,0 +1,22 @@ +import { TableColumn, type MigrationInterface, type QueryRunner } from 'typeorm'; +import { categoryEnum } from '../types/enum.js'; + +export class AlterOperationTable1695740346001 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + const table_name = 'operation'; + await queryRunner.changeColumn( + table_name, + 'category', + new TableColumn({ + name: 'category', + type: 'enum', + isNullable: false, + enum: categoryEnum.toStringList(), + }) + ); + } + + public async down(queryRunner: QueryRunner): Promise { + throw new Error('illegal_operation: cannot roll back initial migration'); + } +} diff --git a/src/database/migrations/CreateSubscriptionTable.ts b/src/database/migrations/CreateSubscriptionTable.ts new file mode 100644 index 00000000..e117ae37 --- /dev/null +++ b/src/database/migrations/CreateSubscriptionTable.ts @@ -0,0 +1,38 @@ +import { MigrationInterface, QueryRunner, Table, TableForeignKey } from "typeorm"; + + +export class CreateSubscritpionTable1695740346003 implements MigrationInterface { + + public async up(queryRunner: QueryRunner): Promise { + const table = new Table({ + name: 'subscription', + columns: [ + { name: 'subscriptionId', type: 'text', isNullable: false, isPrimary: true }, + { name: 'customerId', type: 'uuid', isNullable: false }, + { name: 'status', type: 'text', isNullable: false }, + { name: 'trialStart', type: 'timestamptz', isNullable: true }, + { name: 'trialEnd', type: 'timestamptz', isNullable: true }, + { name: 'currentPeriodStart', type: 'timestamptz', isNullable: false }, + { name: 'currentPeriodEnd', type: 'timestamptz', isNullable: false }, + { name: 'createdAt', type: 'timestamptz', isNullable: false }, + { name: 'updatedAt', type: 'timestamptz', isNullable: true }, + ], + }); + await queryRunner.createTable(table, true); + + await queryRunner.createForeignKey( + table, + new TableForeignKey({ + columnNames: ['customerId'], + referencedColumnNames: ['customerId'], + referencedTableName: 'customer', + onDelete: 'CASCADE', + }) + ); + + } + + public async down(queryRunner: QueryRunner): Promise { + throw new Error('illegal_operation: cannot roll back initial migration'); + } +} \ No newline at end of file diff --git a/src/database/types/enum.ts b/src/database/types/enum.ts index 72f3bfae..8316c32a 100644 --- a/src/database/types/enum.ts +++ b/src/database/types/enum.ts @@ -5,9 +5,10 @@ export const categoryEnum = { CREDENTIAL_STATUS: 'credential-status', PRESENTATION: 'presentation', KEY: 'key', + SUBSCRIPTION: 'subscription', toStringList: function (): string[] { - return [this.DID, this.RESOURCE, this.CREDENTIAL, this.CREDENTIAL_STATUS, this.PRESENTATION, this.KEY]; + return [this.DID, this.RESOURCE, this.CREDENTIAL, this.CREDENTIAL_STATUS, this.PRESENTATION, this.KEY, this.SUBSCRIPTION]; }, }; diff --git a/src/database/types/types.ts b/src/database/types/types.ts index 2e47cfa9..61e38972 100644 --- a/src/database/types/types.ts +++ b/src/database/types/types.ts @@ -32,6 +32,10 @@ import { AlterOperationTable1695740345978 } from '../migrations/AlterOperationTa import { AlterPaymentTable1695740345979 } from '../migrations/AlterPaymentTable.js'; import { CreateCoinTable1695740345977 } from '../migrations/CreateCoinTable.js'; import { CoinEntity } from '../entities/coin.entity.js'; +import { AlterCustomerTable1695740346000 } from '../migrations/AlterCustomerTable.js'; +import { AlterOperationTable1695740346001 } from '../migrations/AlterOperationTableNewCategory.js'; +import { SubscriptionEntity } from '../entities/subscription.entity.js'; +import { CreateSubscritpionTable1695740346003 } from '../migrations/CreateSubscriptionTable.js'; dotenv.config(); const { EXTERNAL_DB_CONNECTION_URL, EXTERNAL_DB_CERT } = process.env; @@ -96,6 +100,12 @@ export class Postgres implements AbstractDatabase { AlterOperationTable1695740345978, // Change payment table structure AlterPaymentTable1695740345979, + // Add stripeCustomerId to customer table + AlterCustomerTable1695740346000, + // Add new category + AlterOperationTable1695740346001, + // Add subscription table + CreateSubscritpionTable1695740346003, ], entities: [ ...Entities, @@ -110,6 +120,7 @@ export class Postgres implements AbstractDatabase { IdentifierEntity, APIKeyEntity, CoinEntity, + SubscriptionEntity, ], logging: ['error', 'info', 'warn'], }); diff --git a/src/middleware/auth/base-auth-handler.ts b/src/middleware/auth/base-auth-handler.ts index c479bb25..255810fe 100644 --- a/src/middleware/auth/base-auth-handler.ts +++ b/src/middleware/auth/base-auth-handler.ts @@ -10,6 +10,7 @@ import { IAuthHandler, RuleRoutine, IAPIGuard } from './routine.js'; import type { IAuthResponse, MethodToScopeRule } from '../../types/authentication.js'; import { M2MTokenUserInfoFetcher } from './user-info-fetcher/m2m-token.js'; import { decodeJwt } from 'jose'; +import { PortalUserInfoFetcher } from './user-info-fetcher/portal-token.js'; export class BaseAPIGuard extends RuleRoutine implements IAPIGuard { userInfoFetcher: IUserInfoFetcher = {} as IUserInfoFetcher; @@ -111,7 +112,7 @@ export class BaseAuthHandler extends BaseAPIGuard implements IAuthHandler { private nextHandler: IAuthHandler; oauthProvider: IOAuthProvider; private static bearerTokenIdentifier = 'Bearer'; - private pathSkip = ['/swagger', '/static', '/logto', '/account/bootstrap']; + private pathSkip = ['/swagger', '/static', '/logto', '/account/bootstrap', '/admin/webhook', '/admin/swagger']; constructor() { super(); @@ -130,15 +131,20 @@ export class BaseAuthHandler extends BaseAPIGuard implements IAuthHandler { private chooseUserFetcherStrategy(request: Request): void { const token = BaseAuthHandler.extractBearerTokenFromHeaders(request.headers) as string; - if (token) { - const payload = decodeJwt(token); - if (payload.aud === process.env.LOGTO_APP_ID) { - this.setUserInfoStrategy(new APITokenUserInfoFetcher(token)); + const headerIdToken = request.headers['id-token'] as string; + if (headerIdToken && token) { + this.setUserInfoStrategy(new PortalUserInfoFetcher(token, headerIdToken)); + } else { + if (token) { + const payload = decodeJwt(token); + if (payload.aud === process.env.LOGTO_APP_ID) { + this.setUserInfoStrategy(new APITokenUserInfoFetcher(token)); + } else { + this.setUserInfoStrategy(new M2MTokenUserInfoFetcher(token)); + } } else { - this.setUserInfoStrategy(new M2MTokenUserInfoFetcher(token)); + this.setUserInfoStrategy(new SwaggerUserInfoFetcher()); } - } else { - this.setUserInfoStrategy(new SwaggerUserInfoFetcher()); } } diff --git a/src/middleware/auth/routes/admin/admin-auth.ts b/src/middleware/auth/routes/admin/admin-auth.ts new file mode 100644 index 00000000..013ee342 --- /dev/null +++ b/src/middleware/auth/routes/admin/admin-auth.ts @@ -0,0 +1,18 @@ +import type { Request, Response } from 'express'; +import { BaseAuthHandler } from '../../base-auth-handler.js'; +import type { IAuthResponse } from '../../../../types/authentication.js'; + +export class AdminHandler extends BaseAuthHandler { + constructor() { + super(); + // ToDo: define how to get namespace information + this.registerRoute('/admin/checkout/session/create', 'POST', 'admin:checkout:session:create:testnet', { skipNamespace: true}); + this.registerRoute('/admin/checkout/session/create', 'POST', 'admin:checkout:session:create:mainnet', { skipNamespace: true}); + } + public async handle(request: Request, response: Response): Promise { + if (!request.path.includes('/admin/')) { + return super.handle(request, response); + } + return this.guardAPI(request); + } +} diff --git a/src/middleware/auth/user-info-fetcher/base.ts b/src/middleware/auth/user-info-fetcher/base.ts index 9366d30b..9cc7ca03 100644 --- a/src/middleware/auth/user-info-fetcher/base.ts +++ b/src/middleware/auth/user-info-fetcher/base.ts @@ -2,6 +2,11 @@ import type { Request } from 'express'; import type { IAuthResponse } from '../../../types/authentication.js'; import type { IOAuthProvider } from '../oauth/base.js'; + +export interface IUserInfoOptions { + [key: string]: any; +} + export interface IUserInfoFetcher { - fetchUserInfo(request: Request, oauthProvider: IOAuthProvider): Promise; + fetchUserInfo(request: Request, oauthProvider: IOAuthProvider, options?: IUserInfoOptions): Promise; } diff --git a/src/middleware/auth/user-info-fetcher/m2m-token.ts b/src/middleware/auth/user-info-fetcher/m2m-token.ts index 4c6df508..a865decb 100644 --- a/src/middleware/auth/user-info-fetcher/m2m-token.ts +++ b/src/middleware/auth/user-info-fetcher/m2m-token.ts @@ -39,10 +39,7 @@ export class M2MTokenUserInfoFetcher extends AuthReturn implements IUserInfoFetc if (!payload.sub) { return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: No sub found in the token.`); } - const { error, data: scopes } = await oauthProvider.getAppScopes(payload.sub); - if (error) { - return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: No scopes found for the roles.`); - } + const scopes = payload.scope ? (payload.scope as string).split(' ') : []; this.setScopes(scopes); return this.returnOk(); } catch (error) { diff --git a/src/middleware/auth/user-info-fetcher/portal-token.ts b/src/middleware/auth/user-info-fetcher/portal-token.ts new file mode 100644 index 00000000..08efa54c --- /dev/null +++ b/src/middleware/auth/user-info-fetcher/portal-token.ts @@ -0,0 +1,86 @@ +import type { Request } from 'express'; +import { AuthReturn } from '../routine.js'; +import type { IAuthResponse } from '../../../types/authentication.js'; +import { StatusCodes } from 'http-status-codes'; +import type { IUserInfoFetcher } from './base.js'; +import type { IOAuthProvider } from '../oauth/base.js'; +import { createRemoteJWKSet, jwtVerify } from 'jose'; + +import * as dotenv from 'dotenv'; +dotenv.config(); + +export class PortalUserInfoFetcher extends AuthReturn implements IUserInfoFetcher { + private m2mToken: string; + private idToken + + constructor(m2mToken: string, idToken: string) { + super(); + this.m2mToken = m2mToken; + this.idToken = idToken; + } + + async fetchUserInfo(request: Request, oauthProvider: IOAuthProvider): Promise { + // Get customerId from header + if (!this.idToken) { + return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: No idToken found in the header.`); + } + + // Check the idToken, provided in header + const idTokenVerification = await this.verifyIdToken(oauthProvider); + if (idTokenVerification.error) { + return idTokenVerification; + } + // return this.returnOk(); + + return this.verifyM2MToken(oauthProvider); + } + + public async verifyIdToken(oauthProvider: IOAuthProvider): Promise { + try { + const { payload } = await jwtVerify( + this.idToken, // The raw Bearer Token extracted from the request header + createRemoteJWKSet(new URL(oauthProvider.endpoint_jwks)), // generate a jwks using jwks_uri inquired from Logto server + { + // expected issuer of the token, should be issued by the Logto server + issuer: oauthProvider.endpoint_issuer, + } + ); + // Setup the scopes from the token + if (!payload.sub) { + return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: No sub found in the token. Cannot set customerId.`); + } + this.setUserId(payload.sub); + return this.returnOk(); + } + catch (error) { + console.error(error); + return this.returnError(StatusCodes.INTERNAL_SERVER_ERROR, `Unexpected error: ${error}`); + } + } + + public async verifyM2MToken(oauthProvider: IOAuthProvider): Promise { + try { + const { payload } = await jwtVerify( + this.m2mToken, // The raw Bearer Token extracted from the request header + createRemoteJWKSet(new URL(oauthProvider.endpoint_jwks)), // generate a jwks using jwks_uri inquired from Logto server + { + // expected issuer of the token, should be issued by the Logto server + issuer: oauthProvider.endpoint_issuer, + } + ); + // Setup the scopes from the token + if (!payload.sub) { + return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: No sub found in the token.`); + } + const { error, data: scopes } = await oauthProvider.getAppScopes(payload.sub); + if (error) { + return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: No scopes found for the roles.`); + } + this.setScopes(scopes); + return this.returnOk(); + } catch (error) { + console.error(error); + return this.returnError(StatusCodes.INTERNAL_SERVER_ERROR, `Unexpected error: ${error}`); + } + } +} diff --git a/src/middleware/authentication.ts b/src/middleware/authentication.ts index 3322c7fd..2f3e6fa7 100644 --- a/src/middleware/authentication.ts +++ b/src/middleware/authentication.ts @@ -11,12 +11,13 @@ import { ResourceAuthHandler } from './auth/routes/resource-auth.js'; import type { BaseAuthHandler } from './auth/base-auth-handler.js'; import { LogToHelper } from './auth/logto-helper.js'; import { PresentationAuthHandler } from './auth/routes/presentation-auth.js'; -import { UserService } from '../services/user.js'; +import { UserService } from '../services/api/user.js'; import { configLogToExpress } from '../types/constants.js'; import { handleAuthRoutes, withLogto } from '@logto/express'; import { LogToProvider } from './auth/oauth/logto-provider.js'; import { AuthInfoHandler } from './auth/routes/auth-user-info.js'; -import { CustomerService } from '../services/customer.js'; +import { CustomerService } from '../services/api/customer.js'; +import { AdminHandler } from './auth/routes/admin/admin-auth.js'; dotenv.config(); @@ -52,6 +53,8 @@ export class Authentication { const presentationAuthHandler = new PresentationAuthHandler(); const authInfoHandler = new AuthInfoHandler(); + const adminAuthHandler = new AdminHandler(); + // Set logToHelper. We do it for avoiding re-asking LogToHelper.setup() in each auth handler // cause it does a lot of requests to LogTo this.authHandler.setOAuthProvider(oauthProvider); @@ -62,6 +65,7 @@ export class Authentication { resourceAuthHandler.setOAuthProvider(oauthProvider); presentationAuthHandler.setOAuthProvider(oauthProvider); authInfoHandler.setOAuthProvider(oauthProvider); + adminAuthHandler.setOAuthProvider(oauthProvider); // Set chain of responsibility this.authHandler @@ -71,7 +75,8 @@ export class Authentication { .setNext(credentialStatusAuthHandler) .setNext(resourceAuthHandler) .setNext(presentationAuthHandler) - .setNext(authInfoHandler); + .setNext(authInfoHandler) + .setNext(adminAuthHandler); this.isSetup = true; } diff --git a/src/services/admin/subscription.ts b/src/services/admin/subscription.ts new file mode 100644 index 00000000..9006adf9 --- /dev/null +++ b/src/services/admin/subscription.ts @@ -0,0 +1,74 @@ +import type { Repository } from 'typeorm'; + +import { Connection } from '../../database/connection/connection.js'; +import { SubscriptionEntity } from '../../database/entities/subscription.entity.js'; +import type { CustomerEntity } from '../../database/entities/customer.entity.js'; + +export class SubscriptionService { + public subscriptionRepository: Repository; + + // Get rid of such code and move it to the builder + public static instance = new SubscriptionService(); + + constructor() { + this.subscriptionRepository = Connection.instance.dbConnection.getRepository(SubscriptionEntity); + } + + public async create( + subscriptionId: string, + customer: CustomerEntity, + status: string, + currentPeriodStart: Date, + currentPeriodEnd: Date, + trialStart: Date, + trialEnd: Date, + ): Promise { + const subscriptionEntity = new SubscriptionEntity( + subscriptionId, + customer, + status, + currentPeriodStart, + currentPeriodEnd, + trialStart, + trialEnd, + ); + const res = await this.subscriptionRepository.insert(subscriptionEntity); + if (!res) throw new Error(`Cannot create a new subscription`); + + return subscriptionEntity; + } + + public async update( + subscriptionId: string, + status?: string, + currentPeriodStart?: Date, + currentPeriodEnd?: Date, + trialStart?: Date, + trialEnd?: Date, + ) { + const existing = await this.subscriptionRepository.findOneBy({ subscriptionId }); + if (!existing) { + throw new Error(`Subscription with id ${subscriptionId} not found`); + } + if (status) existing.status = status; + if (currentPeriodStart) existing.currentPeriodStart = currentPeriodStart; + if (currentPeriodEnd) existing.currentPeriodEnd = currentPeriodEnd; + if (trialStart) existing.trialStart = trialStart; + if (trialEnd) existing.trialEnd = trialEnd; + return await this.subscriptionRepository.save(existing); + } + + public async get(subscriptionId?: string): Promise { + return await this.subscriptionRepository.findOne({ + where: { subscriptionId }, + relations: ['customer'], + }); + } + + public async findOne(where: Record) { + return await this.subscriptionRepository.findOne({ + where: where, + relations: ['customer'], + }); + } +} diff --git a/src/services/api-key.ts b/src/services/api/api-key.ts similarity index 88% rename from src/services/api-key.ts rename to src/services/api/api-key.ts index a09ac860..63bdedb8 100644 --- a/src/services/api-key.ts +++ b/src/services/api/api-key.ts @@ -1,11 +1,11 @@ import type { Repository } from 'typeorm'; import { decodeJWT } from 'did-jwt'; -import { Connection } from '../database/connection/connection.js'; +import { Connection } from '../../database/connection/connection.js'; import * as dotenv from 'dotenv'; -import type { CustomerEntity } from '../database/entities/customer.entity.js'; -import { APIKeyEntity } from '../database/entities/api.key.entity.js'; -import type { UserEntity } from '../database/entities/user.entity.js'; +import type { CustomerEntity } from '../../database/entities/customer.entity.js'; +import { APIKeyEntity } from '../../database/entities/api.key.entity.js'; +import type { UserEntity } from '../../database/entities/user.entity.js'; import { v4 } from 'uuid'; dotenv.config(); diff --git a/src/services/coin.ts b/src/services/api/coin.ts similarity index 87% rename from src/services/coin.ts rename to src/services/api/coin.ts index 5edc6f81..c0cde9b6 100644 --- a/src/services/coin.ts +++ b/src/services/api/coin.ts @@ -1,8 +1,8 @@ import type { Repository } from 'typeorm'; -import { Connection } from '../database/connection/connection.js'; -import { CoinEntity } from '../database/entities/coin.entity.js'; -import { MINIMAL_DENOM } from '../types/constants.js'; +import { Connection } from '../../database/connection/connection.js'; +import { CoinEntity } from '../../database/entities/coin.entity.js'; +import { MINIMAL_DENOM } from '../../types/constants.js'; import { v4 } from 'uuid'; export class CoinService { diff --git a/src/services/credentials.ts b/src/services/api/credentials.ts similarity index 82% rename from src/services/credentials.ts rename to src/services/api/credentials.ts index 8e6f74f9..70c79653 100644 --- a/src/services/credentials.ts +++ b/src/services/api/credentials.ts @@ -1,11 +1,11 @@ import type { CredentialPayload, VerifiableCredential } from '@veramo/core'; -import { VC_CONTEXT, VC_TYPE } from '../types/constants.js'; -import type { CredentialRequest } from '../types/credential.js'; -import { IdentityServiceStrategySetup } from './identity/index.js'; +import { VC_CONTEXT, VC_TYPE } from '../../types/constants.js'; +import type { CredentialRequest } from '../../types/credential.js'; +import { IdentityServiceStrategySetup } from '../identity/index.js'; import { v4 } from 'uuid'; import * as dotenv from 'dotenv'; -import type { CustomerEntity } from '../database/entities/customer.entity.js'; +import type { CustomerEntity } from '../../database/entities/customer.entity.js'; dotenv.config(); const { ENABLE_VERIDA_CONNECTOR } = process.env; @@ -40,7 +40,7 @@ export class Credentials { if (!request.credentialSchema) throw new Error('Credential schema is required'); // dynamic import to avoid circular dependency - const { VeridaService } = await import('./connectors/verida.js'); + const { VeridaService } = await import('../connectors/verida.js'); await VeridaService.instance.sendCredential( request.subjectDid, diff --git a/src/services/customer.ts b/src/services/api/customer.ts similarity index 76% rename from src/services/customer.ts rename to src/services/api/customer.ts index 4f103dad..9accc137 100644 --- a/src/services/customer.ts +++ b/src/services/api/customer.ts @@ -1,8 +1,8 @@ import type { Repository } from 'typeorm'; -import { Connection } from '../database/connection/connection.js'; -import { CustomerEntity } from '../database/entities/customer.entity.js'; -import { IdentityServiceStrategySetup } from './identity/index.js'; +import { Connection } from '../../database/connection/connection.js'; +import { CustomerEntity } from '../../database/entities/customer.entity.js'; +import { IdentityServiceStrategySetup } from '../identity/index.js'; import * as dotenv from 'dotenv'; import { PaymentAccountService } from './payment-account.js'; @@ -42,13 +42,18 @@ export class CustomerService { }; } - public async update(customerId: string, name: string) { + public async update(customerId: string, name?: string, stripeCustomerId?: string) { const existingCustomer = await this.customerRepository.findOneBy({ customerId }); if (!existingCustomer) { throw new Error(`CustomerId not found`); } + if (name) { + existingCustomer.name = name; + } - existingCustomer.name = name; + if (stripeCustomerId) { + existingCustomer.stripeCustomerId = stripeCustomerId; + } return await this.customerRepository.save(existingCustomer); } @@ -56,12 +61,22 @@ export class CustomerService { return this.customerRepository.findOneBy({ customerId }); } - public async findOne(name: string) { + public async findOne(name?: string) { return await this.customerRepository.findOne({ where: { name }, }); } + public async find(where: Record) { + try { + return await this.customerRepository.find({ + where: where, + }); + } catch { + return []; + } + } + public async isExist(where: Record) { try { return (await this.customerRepository.findOne({ where })) ? true : false; diff --git a/src/services/identifier.ts b/src/services/api/identifier.ts similarity index 81% rename from src/services/identifier.ts rename to src/services/api/identifier.ts index 457c95d6..8226b75a 100644 --- a/src/services/identifier.ts +++ b/src/services/api/identifier.ts @@ -1,9 +1,9 @@ import type { Repository } from 'typeorm'; -import { Connection } from '../database/connection/connection.js'; -import { IdentifierEntity } from '../database/entities/identifier.entity.js'; +import { Connection } from '../../database/connection/connection.js'; +import { IdentifierEntity } from '../../database/entities/identifier.entity.js'; import * as dotenv from 'dotenv'; -import type { CustomerEntity } from '../database/entities/customer.entity.js'; +import type { CustomerEntity } from '../../database/entities/customer.entity.js'; dotenv.config(); export class IdentifierService { diff --git a/src/services/key.ts b/src/services/api/key.ts similarity index 86% rename from src/services/key.ts rename to src/services/api/key.ts index 797425f6..97ec80fe 100644 --- a/src/services/key.ts +++ b/src/services/api/key.ts @@ -1,11 +1,11 @@ import type { Repository } from 'typeorm'; -import { Connection } from '../database/connection/connection.js'; +import { Connection } from '../../database/connection/connection.js'; import * as dotenv from 'dotenv'; -import { KeyEntity } from '../database/entities/key.entity.js'; +import { KeyEntity } from '../../database/entities/key.entity.js'; import type { Key } from '@veramo/data-store'; -import type { CustomerEntity } from '../database/entities/customer.entity.js'; +import type { CustomerEntity } from '../../database/entities/customer.entity.js'; dotenv.config(); export class KeyService { diff --git a/src/services/operation.ts b/src/services/api/operation.ts similarity index 90% rename from src/services/operation.ts rename to src/services/api/operation.ts index 2c078153..82fb97d7 100644 --- a/src/services/operation.ts +++ b/src/services/api/operation.ts @@ -1,11 +1,11 @@ import type { Repository } from 'typeorm'; -import { Connection } from '../database/connection/connection.js'; +import { Connection } from '../../database/connection/connection.js'; import * as dotenv from 'dotenv'; -import { OperationEntity } from '../database/entities/operation.entity.js'; +import { OperationEntity } from '../../database/entities/operation.entity.js'; import { v4 } from 'uuid'; -import type { CoinEntity } from '../database/entities/coin.entity.js'; +import type { CoinEntity } from '../../database/entities/coin.entity.js'; dotenv.config(); export class OperationService { diff --git a/src/services/payment-account.ts b/src/services/api/payment-account.ts similarity index 88% rename from src/services/payment-account.ts rename to src/services/api/payment-account.ts index 0ed4e0b6..b0f66530 100644 --- a/src/services/payment-account.ts +++ b/src/services/api/payment-account.ts @@ -1,11 +1,11 @@ import type { Repository } from 'typeorm'; -import { Connection } from '../database/connection/connection.js'; +import { Connection } from '../../database/connection/connection.js'; import * as dotenv from 'dotenv'; -import { PaymentAccountEntity } from '../database/entities/payment.account.entity.js'; -import type { CustomerEntity } from '../database/entities/customer.entity.js'; -import type { KeyEntity } from '../database/entities/key.entity.js'; +import { PaymentAccountEntity } from '../../database/entities/payment.account.entity.js'; +import type { CustomerEntity } from '../../database/entities/customer.entity.js'; +import type { KeyEntity } from '../../database/entities/key.entity.js'; import { getCosmosAccount } from '@cheqd/sdk'; dotenv.config(); diff --git a/src/services/payment.ts b/src/services/api/payment.ts similarity index 84% rename from src/services/payment.ts rename to src/services/api/payment.ts index ac9f45d0..6a4f2c54 100644 --- a/src/services/payment.ts +++ b/src/services/api/payment.ts @@ -1,14 +1,14 @@ import type { Repository } from 'typeorm'; -import { Connection } from '../database/connection/connection.js'; +import { Connection } from '../../database/connection/connection.js'; import * as dotenv from 'dotenv'; -import type { CustomerEntity } from '../database/entities/customer.entity.js'; -import { PaymentEntity } from '../database/entities/payment.entity.js'; -import type { OperationEntity } from '../database/entities/operation.entity.js'; -import type { ResourceEntity } from '../database/entities/resource.entity.js'; +import type { CustomerEntity } from '../../database/entities/customer.entity.js'; +import { PaymentEntity } from '../../database/entities/payment.entity.js'; +import type { OperationEntity } from '../../database/entities/operation.entity.js'; +import type { ResourceEntity } from '../../database/entities/resource.entity.js'; import type { CheqdNetwork } from '@cheqd/sdk'; -import type { CoinEntity } from '../database/entities/coin.entity.js'; +import type { CoinEntity } from '../../database/entities/coin.entity.js'; dotenv.config(); export class PaymentService { diff --git a/src/services/resource.ts b/src/services/api/resource.ts similarity index 89% rename from src/services/resource.ts rename to src/services/api/resource.ts index 0908801a..47579e63 100644 --- a/src/services/resource.ts +++ b/src/services/api/resource.ts @@ -1,12 +1,12 @@ import type { Repository } from 'typeorm'; -import { Connection } from '../database/connection/connection.js'; +import { Connection } from '../../database/connection/connection.js'; import * as dotenv from 'dotenv'; -import { ResourceEntity } from '../database/entities/resource.entity.js'; -import type { IdentifierEntity } from '../database/entities/identifier.entity.js'; -import type { KeyEntity } from '../database/entities/key.entity.js'; -import type { CustomerEntity } from '../database/entities/customer.entity.js'; +import { ResourceEntity } from '../../database/entities/resource.entity.js'; +import type { IdentifierEntity } from '../../database/entities/identifier.entity.js'; +import type { KeyEntity } from '../../database/entities/key.entity.js'; +import type { CustomerEntity } from '../../database/entities/customer.entity.js'; import type { LinkedResourceMetadataResolutionResult } from '@cheqd/did-provider-cheqd'; dotenv.config(); diff --git a/src/services/role.ts b/src/services/api/role.ts similarity index 92% rename from src/services/role.ts rename to src/services/api/role.ts index 1ac40e6e..46ec24fc 100644 --- a/src/services/role.ts +++ b/src/services/api/role.ts @@ -1,9 +1,9 @@ import type { Repository } from 'typeorm'; -import { Connection } from '../database/connection/connection.js'; +import { Connection } from '../../database/connection/connection.js'; import * as dotenv from 'dotenv'; -import { RoleEntity } from '../database/entities/role.entity.js'; +import { RoleEntity } from '../../database/entities/role.entity.js'; dotenv.config(); export class RoleService { diff --git a/src/services/store.ts b/src/services/api/store.ts similarity index 100% rename from src/services/store.ts rename to src/services/api/store.ts diff --git a/src/services/user.ts b/src/services/api/user.ts similarity index 85% rename from src/services/user.ts rename to src/services/api/user.ts index 57721422..fe068e82 100644 --- a/src/services/user.ts +++ b/src/services/api/user.ts @@ -1,11 +1,11 @@ import type { Repository } from 'typeorm'; -import { Connection } from '../database/connection/connection.js'; -import type { CustomerEntity } from '../database/entities/customer.entity.js'; +import { Connection } from '../../database/connection/connection.js'; +import type { CustomerEntity } from '../../database/entities/customer.entity.js'; import * as dotenv from 'dotenv'; -import { UserEntity } from '../database/entities/user.entity.js'; -import type { RoleEntity } from '../database/entities/role.entity.js'; +import { UserEntity } from '../../database/entities/user.entity.js'; +import type { RoleEntity } from '../../database/entities/role.entity.js'; dotenv.config(); export class UserService { diff --git a/src/services/helpers.ts b/src/services/helpers.ts index 3a7a284a..6a719d9d 100644 --- a/src/services/helpers.ts +++ b/src/services/helpers.ts @@ -2,7 +2,7 @@ import type { TPublicKeyEd25519 } from '@cheqd/did-provider-cheqd'; import type { CustomerEntity } from '../database/entities/customer.entity.js'; import type { IBooleanResponse } from '../types/shared.js'; import { IdentityServiceStrategySetup } from './identity/index.js'; -import { KeyService } from './key.js'; +import { KeyService } from './api/key.js'; import type { CheqdW3CVerifiableCredential } from './w3c-credential.js'; import type { CheqdW3CVerifiablePresentation } from './w3c-presentation.js'; diff --git a/src/services/identity/postgres.ts b/src/services/identity/postgres.ts index eaccb909..cd433ba5 100644 --- a/src/services/identity/postgres.ts +++ b/src/services/identity/postgres.ts @@ -42,13 +42,13 @@ import type { CustomerEntity } from '../../database/entities/customer.entity.js' import { Veramo } from './agent.js'; import { DefaultIdentityService } from './default.js'; import * as dotenv from 'dotenv'; -import { KeyService } from '../key.js'; -import { PaymentAccountService } from '../payment-account.js'; +import { KeyService } from '../api/key.js'; +import { PaymentAccountService } from '../api/payment-account.js'; import { CheqdNetwork } from '@cheqd/sdk'; -import { IdentifierService } from '../identifier.js'; +import { IdentifierService } from '../api/identifier.js'; import type { KeyEntity } from '../../database/entities/key.entity.js'; import type { UserEntity } from '../../database/entities/user.entity.js'; -import { APIKeyService } from '../api-key.js'; +import { APIKeyService } from '../api/api-key.js'; import type { APIKeyEntity } from '../../database/entities/api.key.entity.js'; import { KeyDIDProvider } from '@veramo/did-provider-key'; import type { AbstractIdentifierProvider } from '@veramo/did-manager'; diff --git a/src/services/track/admin/account-submitter.ts b/src/services/track/admin/account-submitter.ts new file mode 100644 index 00000000..b6261ec1 --- /dev/null +++ b/src/services/track/admin/account-submitter.ts @@ -0,0 +1,60 @@ +import Stripe from "stripe"; +import type { IObserver } from "../types.js"; +import { OperationNameEnum } from "../../../types/constants.js"; +import type { INotifyMessage } from "../../../types/track.js"; +import { EventTracker } from "../tracker.js"; +import { StatusCodes } from "http-status-codes"; +import { CustomerService } from "../../api/customer.js"; +import type { ISubmitOperation, ISubmitStripeCustomerCreateData } from "../submitter.js"; + + +export class PortalAccountCreateSubmitter implements IObserver { + private emitter: EventEmitter; + private stripe: Stripe; + + constructor(emitter: EventEmitter) { + this.emitter = emitter; + this.stripe = new Stripe(process.env.STRIPE_SECRET_KEY); + } + + notify(notifyMessage: INotifyMessage): void { + this.emitter.emit('notify', notifyMessage); + } + + async update(operation: ISubmitOperation): Promise { + if (operation.operation === OperationNameEnum.STRIPE_ACCOUNT_CREATE) { + await this.submitStripeAccountCreate(operation); + } + } + + async submitStripeAccountCreate(operation: ISubmitOperation): Promise { + const data = operation.data as ISubmitStripeCustomerCreateData; + + try { + // Create a new Stripe account + const account = await this.stripe.customers.create({ + name: data.name, + email: data.email, + }); + if (account.lastResponse.statusCode !== StatusCodes.OK) { + await this.notify({ + message: EventTracker.compileBasicNotification(`Failed to create Stripe account with name: ${data.name}.`, operation.operation), + severity: 'error', + } as INotifyMessage); + return; + } + + // Update the CaaS customer with the new Stripe account + await CustomerService.instance.update(data.customerId, undefined, account.id); + await this.notify({ + message: EventTracker.compileBasicNotification(`Stripe account created with name: ${data.name}.`, operation.operation), + severity: 'info', + } as INotifyMessage); + } catch (error) { + await this.notify({ + message: EventTracker.compileBasicNotification(`Failed to create Stripe account with name: ${data.name as string}.`, operation.operation), + severity: 'error', + } as INotifyMessage); + } + } +} diff --git a/src/services/track/admin/subscription-submitter.ts b/src/services/track/admin/subscription-submitter.ts new file mode 100644 index 00000000..d6f2144b --- /dev/null +++ b/src/services/track/admin/subscription-submitter.ts @@ -0,0 +1,161 @@ +import { OperationNameEnum } from "../../../types/constants.js"; +import type { INotifyMessage } from "../../../types/track.js"; +import { SubscriptionService } from "../../admin/subscription.js"; +import { CustomerService } from "../../api/customer.js"; +import type { ISubmitOperation, ISubmitSubscriptionData } from "../submitter.js"; +import { EventTracker, eventTracker } from "../tracker.js"; +import type { IObserver } from "../types.js"; + +//eslint-disable-next-line + +function isPromise(object: any): object is Promise { + return object && Promise.resolve(object) === object; + } + +export const eventDecorator = () => { + return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => { + const { value } = descriptor; + //eslint-disable-next-line + descriptor.value = async (...args: any) => { + try { + const response = value.apply(target, args); + return isPromise(response) ? await response : Promise.resolve(response); + } catch (error) { + eventTracker.notify({ + message: EventTracker.compileBasicNotification(`Error while calling function: ${propertyKey}: ${(error as Record)?.message || error}`), + severity: 'error', + } satisfies INotifyMessage); + } + }; + return descriptor; + } +} + +export class SubscriptionSubmitter implements IObserver { + + private emitter: EventEmitter; + + constructor(emitter: EventEmitter) { + this.emitter = emitter; + } + + notify(notifyMessage: INotifyMessage): void { + this.emitter.emit('notify', notifyMessage); + } + + async update(operation: ISubmitOperation): Promise { + switch (operation.operation) { + case OperationNameEnum.SUBSCRIPTION_CREATE: + await this.submitSubscriptionCreate(operation); + break; + + case OperationNameEnum.SUBSCRIPTION_UPDATE: + await this.submitSubscriptionUpdate(operation); + break; + + case OperationNameEnum.SUBSCRIPTION_CANCEL: + await this.submitSubscriptionCancel(operation); + break; + } + } + + // @eventDecorator() + async submitSubscriptionCreate(operation: ISubmitOperation): Promise { + const data = operation.data as ISubmitSubscriptionData; + try{ + const customers = await CustomerService.instance.find({ + stripeCustomerId: data.stripeCustomerId + }) + + if (customers.length !== 1) { + this.notify({ + message: EventTracker.compileBasicNotification(`It should be only 1 Stripe account associated with CaaS customer. Stripe accountId: ${data.stripeCustomerId}.`, operation.operation), + severity: 'error', + }) + } + const subscription = await SubscriptionService.instance.create( + data.subscriptionId, + customers[0], + data.status, + data.currentPeriodStart, + data.currentPeriodEnd, + data.trialStart as Date, + data.trialEnd as Date, + ) + if (!subscription) { + this.notify({ + message: EventTracker.compileBasicNotification(`Failed to create a new subscription with id: ${data.subscriptionId}.`, operation.operation), + severity: 'error', + }) + } + + this.notify({ + message: EventTracker.compileBasicNotification(`Subscription created with id: ${data.subscriptionId}.`, operation.operation), + severity: 'info', + }) + } catch (error) { + this.notify({ + message: EventTracker.compileBasicNotification(`Failed to create a new subscription with id: ${data.subscriptionId} because of error: ${(error as Error)?.message || error}`, operation.operation), + severity: 'error', + }) + } + } + + // @eventDecorator() + async submitSubscriptionUpdate(operation: ISubmitOperation): Promise { + const data = operation.data as ISubmitSubscriptionData; + try { + const subscription = await SubscriptionService.instance.update( + data.subscriptionId, + data.status, + data.currentPeriodStart, + data.currentPeriodEnd, + data.trialStart as Date, + data.trialEnd as Date, + ) + if (!subscription) { + this.notify({ + message: EventTracker.compileBasicNotification(`Failed to update subscription with id: ${data.subscriptionId}.`, operation.operation), + severity: 'error', + }) + } + + this.notify({ + message: EventTracker.compileBasicNotification(`Subscription updated with id: ${data.subscriptionId}.`, operation.operation), + severity: 'info', + }) + } catch (error) { + this.notify({ + message: EventTracker.compileBasicNotification(`Failed to update subscription with id: ${data.subscriptionId} because of error: ${(error as Error)?.message || error}`, operation.operation), + severity: 'error', + }) + } + } + + // @eventDecorator() + async submitSubscriptionCancel(operation: ISubmitOperation): Promise { + const data = operation.data as ISubmitSubscriptionData; + try { + const subscription = await SubscriptionService.instance.update( + data.subscriptionId, + data.status, + ) + if (!subscription) { + this.notify({ + message: EventTracker.compileBasicNotification(`Failed to cancel subscription with id: ${data.subscriptionId}.`, operation.operation), + severity: 'error', + }) + } + + this.notify({ + message: EventTracker.compileBasicNotification(`Subscription canceled with id: ${data.subscriptionId}.`, operation.operation), + severity: 'info', + }) + } catch (error) { + this.notify({ + message: EventTracker.compileBasicNotification(`Failed to cancel subscription with id: ${data.subscriptionId} because of error: ${(error as Error)?.message || error}`, operation.operation), + severity: 'error', + }) + } + } +} \ No newline at end of file diff --git a/src/services/track/api/credential-status-subscriber.ts b/src/services/track/api/credential-status-subscriber.ts new file mode 100644 index 00000000..41c5d6c9 --- /dev/null +++ b/src/services/track/api/credential-status-subscriber.ts @@ -0,0 +1,44 @@ +import { OperationCategoryNameEnum } from '../../../types/constants.js'; +import type { + ICredentialStatusTrack, ITrackOperation, + ITrackResult +} from '../../../types/track.js'; +import type { IObserver } from '../types.js'; +import { BaseOperationObserver } from '../base.js'; + + +export class CredentialStatusSubscriber extends BaseOperationObserver implements IObserver { + isReactionNeeded(trackOperation: ITrackOperation): boolean { + // Credential tracker reacts on CredentialStatusList, Credential operations like revocation + // and Resource operations like create, update, delete + return trackOperation.category === OperationCategoryNameEnum.CREDENTIAL_STATUS; + } + + public compileMessage(trackResult: ITrackResult): string { + const base_message = super.compileMessage(trackResult); + const data = trackResult.operation.data as ICredentialStatusTrack; + return `${base_message} | Target DID: ${data.did} | Encrypted: ${data.encrypted} | StatusListName: ${data.resource?.resourceName}`; + } + + async update(trackOperation: ITrackOperation): Promise { + if (!this.isReactionNeeded(trackOperation)) { + // Just skip this operation + return; + } + // tracking resource creation in DB + const result = await this.trackCredentialStatusOperation(trackOperation); + // notify about the result of tracking, e.g. log or datadog + await this.notify({ + message: this.compileMessage(result), + severity: result.error ? 'error' : 'info', + }); + } + + async trackCredentialStatusOperation(trackOperation: ITrackOperation): Promise { + // We don't have specific credential status writes, so we just track credential creation + return { + operation: trackOperation, + error: '', + } satisfies ITrackResult; + } +} diff --git a/src/services/track/api/credential-subscriber.ts b/src/services/track/api/credential-subscriber.ts new file mode 100644 index 00000000..b1a7af29 --- /dev/null +++ b/src/services/track/api/credential-subscriber.ts @@ -0,0 +1,44 @@ +import { OperationCategoryNameEnum } from '../../../types/constants.js'; +import type { + ICredentialTrack, ITrackOperation, + ITrackResult +} from '../../../types/track.js'; +import type { IObserver } from '../types.js'; +import { BaseOperationObserver } from '../base.js'; + + +export class CredentialSubscriber extends BaseOperationObserver implements IObserver { + isReactionNeeded(trackOperation: ITrackOperation): boolean { + // Credential tracker reacts on CredentialStatusList, Credential operations like revocation + // and Resource operations like create, update, delete + return trackOperation.category === OperationCategoryNameEnum.CREDENTIAL; + } + + public compileMessage(trackResult: ITrackResult): string { + const base_message = super.compileMessage(trackResult); + const data = trackResult.operation.data as ICredentialTrack; + return `${base_message} | Credential holder: ${data.did}`; + } + + async update(trackOperation: ITrackOperation): Promise { + if (!this.isReactionNeeded(trackOperation)) { + // Just skip this operation + return; + } + // tracking resource creation in DB + const result = await this.trackCredentialOperation(trackOperation); + // notify about the result of tracking, e.g. log or datadog + await this.notify({ + message: this.compileMessage(result), + severity: result.error ? 'error' : 'info', + }); + } + + async trackCredentialOperation(trackOperation: ITrackOperation): Promise { + // We don't have specific credential writes, so we just track credential creation + return { + operation: trackOperation, + error: '', + } satisfies ITrackResult; + } +} diff --git a/src/services/track/api/did-subscriber.ts b/src/services/track/api/did-subscriber.ts new file mode 100644 index 00000000..b6be6b07 --- /dev/null +++ b/src/services/track/api/did-subscriber.ts @@ -0,0 +1,43 @@ +import { OperationCategoryNameEnum } from '../../../types/constants.js'; +import type { + ITrackOperation, + ITrackResult, + IDIDTrack +} from '../../../types/track.js'; +import type { IObserver } from '../types.js'; +import { BaseOperationObserver } from '../base.js'; + + +export class DIDSubscriber extends BaseOperationObserver implements IObserver { + isReactionNeeded(trackOperation: ITrackOperation): boolean { + return trackOperation.category === OperationCategoryNameEnum.DID; + } + + public compileMessage(trackResult: ITrackResult): string { + const base_message = super.compileMessage(trackResult); + const data = trackResult.operation.data as IDIDTrack; + return `${base_message} | Target DID: ${data.did}`; + } + + async update(trackOperation: ITrackOperation): Promise { + if (!this.isReactionNeeded(trackOperation)) { + // Just skip this operation + return; + } + // tracking resource creation in DB + const result = await this.trackDIDOperation(trackOperation); + // notify about the result of tracking, e.g. log or datadog + await this.notify({ + message: this.compileMessage(result), + severity: result.error ? 'error' : 'info', + }); + } + + async trackDIDOperation(trackOperation: ITrackOperation): Promise { + // We don't have specific DID related operations to track + return { + operation: trackOperation, + error: '', + } satisfies ITrackResult; + } +} diff --git a/src/services/track/api/key-subscriber.ts b/src/services/track/api/key-subscriber.ts new file mode 100644 index 00000000..c5ff1d0b --- /dev/null +++ b/src/services/track/api/key-subscriber.ts @@ -0,0 +1,45 @@ +import { OperationCategoryNameEnum } from '../../../types/constants.js'; +import type { + IKeyTrack, + ITrackOperation, + ITrackResult +} from '../../../types/track.js'; +import type { IObserver } from '../types.js'; +import { BaseOperationObserver } from '../base.js'; + + +export class KeySubscriber extends BaseOperationObserver implements IObserver { + isReactionNeeded(trackOperation: ITrackOperation): boolean { + // Credential tracker reacts on CredentialStatusList, Credential operations like revocation + // and Resource operations like create, update, delete + return trackOperation.category === OperationCategoryNameEnum.KEY; + } + + public compileMessage(trackResult: ITrackResult): string { + const base_message = super.compileMessage(trackResult); + const data = trackResult.operation.data as IKeyTrack; + return `${base_message} | keyRef: ${data.keyRef} | keyType: ${data.keyType}`; + } + + async update(trackOperation: ITrackOperation): Promise { + if (!this.isReactionNeeded(trackOperation)) { + // Just skip this operation + return; + } + // tracking resource creation in DB + const result = await this.trackKeyOperation(trackOperation); + // notify about the result of tracking, e.g. log or datadog + await this.notify({ + message: this.compileMessage(result), + severity: result.error ? 'error' : 'info', + }); + } + + async trackKeyOperation(trackOperation: ITrackOperation): Promise { + // We don't have specific presentation writes, so we just track presentation creation + return { + operation: trackOperation, + error: '', + } satisfies ITrackResult; + } +} diff --git a/src/services/track/api/presentation-subscriber.ts b/src/services/track/api/presentation-subscriber.ts new file mode 100644 index 00000000..4d66101f --- /dev/null +++ b/src/services/track/api/presentation-subscriber.ts @@ -0,0 +1,44 @@ +import { OperationCategoryNameEnum } from '../../../types/constants.js'; +import type { + IPresentationTrack, ITrackOperation, + ITrackResult +} from '../../../types/track.js'; +import type { IObserver } from '../types.js'; +import { BaseOperationObserver } from '../base.js'; + + +export class PresentationSubscriber extends BaseOperationObserver implements IObserver { + isReactionNeeded(trackOperation: ITrackOperation): boolean { + // Credential tracker reacts on CredentialStatusList, Credential operations like revocation + // and Resource operations like create, update, delete + return trackOperation.category === OperationCategoryNameEnum.PRESENTATION; + } + + public compileMessage(trackResult: ITrackResult): string { + const base_message = super.compileMessage(trackResult); + const data = trackResult.operation.data as IPresentationTrack; + return `${base_message} | Presentation holder: ${data.holder}`; + } + + async update(trackOperation: ITrackOperation): Promise { + if (!this.isReactionNeeded(trackOperation)) { + // Just skip this operation + return; + } + // tracking resource creation in DB + const result = await this.trackPresentationOperation(trackOperation); + // notify about the result of tracking, e.g. log or datadog + await this.notify({ + message: this.compileMessage(result), + severity: result.error ? 'error' : 'info', + }); + } + + async trackPresentationOperation(trackOperation: ITrackOperation): Promise { + // We don't have specific presentation writes, so we just track presentation creation + return { + operation: trackOperation, + error: '', + } satisfies ITrackResult; + } +} diff --git a/src/services/track/api/resource-subscriber.ts b/src/services/track/api/resource-subscriber.ts new file mode 100644 index 00000000..67e5cc5f --- /dev/null +++ b/src/services/track/api/resource-subscriber.ts @@ -0,0 +1,134 @@ +import type { LinkedResourceMetadataResolutionResult } from '@cheqd/did-provider-cheqd'; +import { OperationNameEnum, OperationCategoryNameEnum } from '../../../types/constants.js'; +import type { + ICredentialStatusTrack, + ICredentialTrack, + IResourceTrack, + ITrackOperation, + ITrackResult} from '../../../types/track.js'; +import { isCredentialStatusTrack, isCredentialTrack, isResourceTrack } from '../helpers.js'; +import { IdentifierService } from '../../api/identifier.js'; +import { KeyService } from '../../api/key.js'; +import { ResourceService } from '../../api/resource.js'; +import type { IObserver } from '../types.js'; +import { BaseOperationObserver } from '../base.js'; + + +export class ResourceSubscriber extends BaseOperationObserver implements IObserver { + private static acceptedOperations = [ + OperationNameEnum.RESOURCE_CREATE, + OperationNameEnum.CREDENTIAL_REVOKE, + OperationNameEnum.CREDENTIAL_SUSPEND, + OperationNameEnum.CREDENTIAL_UNSUSPEND, + OperationNameEnum.CREDENTIAL_STATUS_CREATE_UNENCRYPTED, + OperationNameEnum.CREDENTIAL_STATUS_CREATE_ENCRYPTED, + OperationNameEnum.CREDENTIAL_STATUS_UPDATE_UNENCRYPTED, + OperationNameEnum.CREDENTIAL_STATUS_UPDATE_ENCRYPTED, + ]; + + isReactionNeeded(trackOperation: ITrackOperation): boolean { + // Resource tracker reacts on CredentialStatusList, Credential operations like revocation + // and Resource operations like create, update, delete + const isCategoryAccepted = trackOperation.category === OperationCategoryNameEnum.RESOURCE || + trackOperation.category === OperationCategoryNameEnum.CREDENTIAL || + trackOperation.category === OperationCategoryNameEnum.CREDENTIAL_STATUS; + const isOperationAccepted = ResourceSubscriber.acceptedOperations.includes( + trackOperation.name as OperationNameEnum + ); + return isCategoryAccepted && isOperationAccepted; + } + + public compileMessage(trackResult: ITrackResult): string { + const base_message = super.compileMessage(trackResult); + const data = trackResult.operation.data as IResourceTrack; + return `${base_message} | Resource DID: ${data.did} | ResourceName: ${data.resource.resourceName} | ResourceType: ${data.resource.resourceType} | ResourceId: ${data.resource.resourceId}`; + } + + async update(trackOperation: ITrackOperation): Promise { + if (!this.isReactionNeeded(trackOperation)) { + // Just skip this operation + return; + } + trackOperation.category = OperationCategoryNameEnum.RESOURCE; + trackOperation.name = OperationNameEnum.RESOURCE_CREATE; + // tracking resource creation in DB + const result = await this.trackResourceOperation(trackOperation); + // notify about the result of tracking, e.g. log or datadog + await this.notify({ + message: this.compileMessage(result), + severity: result.error ? 'error' : 'info', + }); + } + + async trackResourceOperation(trackOperation: ITrackOperation): Promise { + // Resource operation may be with CredentialStatusList or with Credential operations like revocation + // and others and also with Resource operations like create, update, delete + const customer = trackOperation.customer; + const data = trackOperation.data as IResourceTrack | ICredentialStatusTrack | ICredentialTrack; + const did = data.did; + let encrypted = false; + let symmetricKey = ''; + let resource: LinkedResourceMetadataResolutionResult | undefined = undefined; + + if (!customer) { + return { + operation: trackOperation, + error: `Customer for resource operation was not specified`, + }; + } + + if (isResourceTrack(data)) { + encrypted = false; + symmetricKey = ''; + resource = (data as IResourceTrack).resource; + } + if (isCredentialStatusTrack(data)) { + encrypted = (data as ICredentialStatusTrack).encrypted || false; + symmetricKey = (data as ICredentialStatusTrack).symmetricKey || ''; + resource = (data as ICredentialStatusTrack).resource; + } + if (isCredentialTrack(data)) { + encrypted = (data as ICredentialTrack).encrypted || false; + symmetricKey = (data as ICredentialTrack).symmetricKey || ''; + resource = (data as ICredentialTrack).resource; + } + + if (!resource) { + return { + operation: trackOperation, + error: `Resource for ${did} was not specified`, + }; + } + + const identifier = await IdentifierService.instance.get(did); + if (!identifier) { + throw new Error(`Identifier ${did} not found`); + } + if (!identifier.controllerKeyId) { + throw new Error(`Identifier ${did} does not have link to the controller key...`); + } + const key = await KeyService.instance.get(identifier.controllerKeyId); + if (!key) { + throw new Error(`Key for ${did} not found`); + } + + const resourceEntity = await ResourceService.instance.createFromLinkedResource( + resource, + customer, + key, + identifier, + encrypted, + symmetricKey + ); + if (!resourceEntity) { + return { + operation: trackOperation, + error: `Resource for ${did} was not tracked`, + }; + } + return { + operation: trackOperation, + error: '', + }; + } +} diff --git a/src/services/track/base.ts b/src/services/track/base.ts index 8db75156..c6d69a94 100644 --- a/src/services/track/base.ts +++ b/src/services/track/base.ts @@ -12,7 +12,7 @@ export class BaseOperationObserver implements IObserver { throw new Error('Method not implemented.'); } - async notify(notifyMessage: INotifyMessage): Promise { + notify(notifyMessage: INotifyMessage): void { this.emitter.emit('notify', notifyMessage); } diff --git a/src/services/track/observer.ts b/src/services/track/observer.ts index 2672d504..3282df73 100644 --- a/src/services/track/observer.ts +++ b/src/services/track/observer.ts @@ -1,6 +1,6 @@ import type { ITrackSubject, IObserver, ITrackType } from './types.js'; -export class Observer implements ITrackSubject { +export class TrackSubject implements ITrackSubject { private observers: IObserver[] = []; public attach(observer: IObserver): void { @@ -24,3 +24,31 @@ export class Observer implements ITrackSubject { Promise.all(this.observers.map((observer) => observer.update(operation))); } } + +export class SubmitSubject implements ITrackSubject { + private observers: IObserver[] = []; + + public attach(observer: IObserver): void { + const isExist = this.observers.includes(observer); + if (isExist) { + return console.warn('TrackOperation: Observer has been attached already.'); + } + this.observers.push(observer); + } + + public detach(observer: IObserver): void { + const observerIndex = this.observers.indexOf(observer); + if (observerIndex === -1) { + return console.warn('TrackOperation: Nonexistent observer.'); + } + + this.observers.splice(observerIndex, 1); + } + + public async notify(operation: ITrackType): Promise { + for (const observer of this.observers) { + await observer.update(operation); + } + } +} + diff --git a/src/services/track/operation-subscriber.ts b/src/services/track/operation-subscriber.ts new file mode 100644 index 00000000..eb1b27a7 --- /dev/null +++ b/src/services/track/operation-subscriber.ts @@ -0,0 +1,157 @@ +import { OperationNameEnum, OperationDefaultFeeEnum } from '../../types/constants.js'; +import { + type IResourceTrack, + type ITrackOperation, + type ITrackResult, + TrackOperationWithPayment, +} from '../../types/track.js'; +import { toCoin } from './helpers.js'; +import { OperationService } from '../api/operation.js'; +import type { IObserver } from './types.js'; +import { BaseOperationObserver } from './base.js'; +import type { LogLevelDesc } from 'loglevel'; +import type { OperationEntity } from '../../database/entities/operation.entity.js'; +import { PaymentService } from '../api/payment.js'; +import type { CustomerEntity } from '../../database/entities/customer.entity.js'; +import type { Coin } from '@cosmjs/amino'; +import { CoinService } from '../api/coin.js'; + +export class DBOperationSubscriber extends BaseOperationObserver implements IObserver { + protected logSeverity: LogLevelDesc = 'debug'; + + async update(trackOperation: ITrackOperation): Promise { + // tracking operation in our DB. It handles all the operations + const result = await this.trackOperation(trackOperation); + const message = result.error + ? `Error while writing information about operation ${trackOperation.name} to DB: ${result.error}` + : `Information about operation ${trackOperation.name} was successfully written to DB`; + // notify about the result of tracking, e.g. log or datadog + await this.notify({ + message: message, + severity: result.error ? 'error' : this.logSeverity, + }); + } + + async trackPayments( + operationWithPayment: TrackOperationWithPayment, + operationEntity: OperationEntity + ): Promise { + const resource = await operationWithPayment.getResourceEntity(); + if (!resource) { + return { + operation: operationWithPayment, + error: `Resource for operation ${operationWithPayment.name} not found. Customer: ${operationWithPayment.customer.customerId}`, + } satisfies ITrackResult; + } + + for (const feePayment of operationWithPayment.feePaymentOptions) { + // Create Fee Coin + const feeCoin = await CoinService.instance.create(BigInt(feePayment.fee.amount), feePayment.fee.denom); + // Create Amount Coin + const amountCoin = await CoinService.instance.create( + BigInt(feePayment.amount.amount), + feePayment.amount.denom + ); + + const payment = await PaymentService.instance.create( + feePayment.txHash as string, + operationWithPayment.customer as CustomerEntity, + operationEntity, + feeCoin, + amountCoin, + feePayment.successful, + feePayment.network, + resource, + feePayment.fromAddress, + feePayment.toAddress, + feePayment.timestamp + ); + if (!payment) { + return { + operation: operationWithPayment, + error: `Payment for operation ${operationWithPayment.name} was not written to DB`, + } satisfies ITrackResult; + } + } + return { + operation: operationWithPayment, + error: '', + } satisfies ITrackResult; + } + + async getDefaultFeeCoin(operation: ITrackOperation): Promise { + const defaultFee = 0; + switch (operation.name) { + case OperationNameEnum.DID_CREATE: + return toCoin(BigInt(OperationDefaultFeeEnum.DID_CREATE)); + case OperationNameEnum.DID_UPDATE: + return toCoin(BigInt(OperationDefaultFeeEnum.DID_UPDATE)); + case OperationNameEnum.DID_DEACTIVATE: + return toCoin(BigInt(OperationDefaultFeeEnum.DID_DEACTIVATE)); + } + if ( + operation.name === OperationNameEnum.RESOURCE_CREATE || + operation.name === OperationNameEnum.CREDENTIAL_STATUS_CREATE_ENCRYPTED || + operation.name === OperationNameEnum.CREDENTIAL_STATUS_CREATE_UNENCRYPTED || + operation.name === OperationNameEnum.CREDENTIAL_STATUS_UPDATE_ENCRYPTED || + operation.name === OperationNameEnum.CREDENTIAL_STATUS_UPDATE_UNENCRYPTED + ) { + const resource = (operation.data as IResourceTrack).resource; + if (!resource) { + return toCoin(BigInt(defaultFee)); + } + if (resource.mediaType === 'application/json') { + return toCoin(BigInt(OperationDefaultFeeEnum.RESOURCE_CREATE_JSON)); + } + if (resource.mediaType.includes('image')) { + return toCoin(BigInt(OperationDefaultFeeEnum.RESOURCE_CREATE_IMAGE)); + } + return toCoin(BigInt(OperationDefaultFeeEnum.RESOURCE_CREATE_OTHER)); + } + return toCoin(BigInt(defaultFee)); + } + + async trackOperation(trackOperation: ITrackOperation): Promise { + try { + // Create Default Fee Coin + const defaultFeeCoin = await this.getDefaultFeeCoin(trackOperation); + const defaultFee = await CoinService.instance.create(BigInt(defaultFeeCoin.amount), defaultFeeCoin.denom); + // Create operation entity + const operationEntity = await OperationService.instance.create( + trackOperation.category, + trackOperation.name, + defaultFee, + false, + trackOperation.successful + ); + + if (!operationEntity) { + throw new Error(`Operation ${trackOperation.name} was not written to DB`); + } + + // Track payments + if (trackOperation.feePaymentOptions) { + const operationWithPayment = new TrackOperationWithPayment(trackOperation); + const paymentValidation = operationWithPayment.validate(); + if (paymentValidation.error) { + return { + operation: trackOperation, + error: `Error while validating payment options: ${paymentValidation.error}`, + } satisfies ITrackResult; + } + return await this.trackPayments(operationWithPayment, operationEntity); + } + + return { + operation: trackOperation, + error: '', + } satisfies ITrackResult; + } catch (error) { + return { + operation: trackOperation, + error: `Error while writing information about operation ${trackOperation.name} to DB: ${(error as Error)?.message || error}`, + } satisfies ITrackResult; + } + } +} + diff --git a/src/services/track/submitter.ts b/src/services/track/submitter.ts new file mode 100644 index 00000000..44adbd1d --- /dev/null +++ b/src/services/track/submitter.ts @@ -0,0 +1,24 @@ +// Type: Interface +export type ISubmitData = ISubmitStripeCustomerCreateData + | ISubmitSubscriptionData; + +export interface ISubmitStripeCustomerCreateData { + customerId: string; + name: string; + email?: string; +} + +export interface ISubmitSubscriptionData { + stripeCustomerId: string; + status: string; + currentPeriodStart: Date; + currentPeriodEnd: Date; + trialStart?: Date; + trialEnd?: Date; + subscriptionId: string; +} + +export interface ISubmitOperation { + operation: string; + data: ISubmitData; +} diff --git a/src/services/track/subscribers.ts b/src/services/track/subscribers.ts deleted file mode 100644 index 1e992e1b..00000000 --- a/src/services/track/subscribers.ts +++ /dev/null @@ -1,463 +0,0 @@ -import type { LinkedResourceMetadataResolutionResult } from '@cheqd/did-provider-cheqd'; -import { OperationNameEnum, OperationCategoryNameEnum, OperationDefaultFeeEnum } from '../../types/constants.js'; -import { - type ICredentialStatusTrack, - type ICredentialTrack, - type IPresentationTrack, - type IResourceTrack, - type IKeyTrack, - type ITrackOperation, - type ITrackResult, - type IDIDTrack, - TrackOperationWithPayment, -} from '../../types/track.js'; -import { isCredentialStatusTrack, isCredentialTrack, isResourceTrack, toCoin } from './helpers.js'; -import { IdentifierService } from '../identifier.js'; -import { KeyService } from '../key.js'; -import { OperationService } from '../operation.js'; -import { ResourceService } from '../resource.js'; -import type { IObserver } from './types.js'; -import { BaseOperationObserver } from './base.js'; -import type { LogLevelDesc } from 'loglevel'; -import type { OperationEntity } from '../../database/entities/operation.entity.js'; -import { PaymentService } from '../payment.js'; -import type { CustomerEntity } from '../../database/entities/customer.entity.js'; -import type { Coin } from '@cosmjs/amino'; -import { CoinService } from '../coin.js'; - -export class DBOperationSubscriber extends BaseOperationObserver implements IObserver { - protected logSeverity: LogLevelDesc = 'debug'; - - async update(trackOperation: ITrackOperation): Promise { - // tracking operation in our DB. It handles all the operations - const result = await this.trackOperation(trackOperation); - const message = result.error - ? `Error while writing information about operation ${trackOperation.name} to DB: ${result.error}` - : `Information about operation ${trackOperation.name} was successfully written to DB`; - // notify about the result of tracking, e.g. log or datadog - await this.notify({ - message: message, - severity: result.error ? 'error' : this.logSeverity, - }); - } - - async trackPayments( - operationWithPayment: TrackOperationWithPayment, - operationEntity: OperationEntity - ): Promise { - const resource = await operationWithPayment.getResourceEntity(); - if (!resource) { - return { - operation: operationWithPayment, - error: `Resource for operation ${operationWithPayment.name} not found. Customer: ${operationWithPayment.customer.customerId}`, - } satisfies ITrackResult; - } - - for (const feePayment of operationWithPayment.feePaymentOptions) { - // Create Fee Coin - const feeCoin = await CoinService.instance.create(BigInt(feePayment.fee.amount), feePayment.fee.denom); - // Create Amount Coin - const amountCoin = await CoinService.instance.create( - BigInt(feePayment.amount.amount), - feePayment.amount.denom - ); - - const payment = await PaymentService.instance.create( - feePayment.txHash as string, - operationWithPayment.customer as CustomerEntity, - operationEntity, - feeCoin, - amountCoin, - feePayment.successful, - feePayment.network, - resource, - feePayment.fromAddress, - feePayment.toAddress, - feePayment.timestamp - ); - if (!payment) { - return { - operation: operationWithPayment, - error: `Payment for operation ${operationWithPayment.name} was not written to DB`, - } satisfies ITrackResult; - } - } - return { - operation: operationWithPayment, - error: '', - } satisfies ITrackResult; - } - - async getDefaultFeeCoin(operation: ITrackOperation): Promise { - const defaultFee = 0; - switch (operation.name) { - case OperationNameEnum.DID_CREATE: - return toCoin(BigInt(OperationDefaultFeeEnum.DID_CREATE)); - case OperationNameEnum.DID_UPDATE: - return toCoin(BigInt(OperationDefaultFeeEnum.DID_UPDATE)); - case OperationNameEnum.DID_DEACTIVATE: - return toCoin(BigInt(OperationDefaultFeeEnum.DID_DEACTIVATE)); - } - if ( - operation.name === OperationNameEnum.RESOURCE_CREATE || - operation.name === OperationNameEnum.CREDENTIAL_STATUS_CREATE_ENCRYPTED || - operation.name === OperationNameEnum.CREDENTIAL_STATUS_CREATE_UNENCRYPTED || - operation.name === OperationNameEnum.CREDENTIAL_STATUS_UPDATE_ENCRYPTED || - operation.name === OperationNameEnum.CREDENTIAL_STATUS_UPDATE_UNENCRYPTED - ) { - const resource = (operation.data as IResourceTrack).resource; - if (!resource) { - return toCoin(BigInt(defaultFee)); - } - if (resource.mediaType === 'application/json') { - return toCoin(BigInt(OperationDefaultFeeEnum.RESOURCE_CREATE_JSON)); - } - if (resource.mediaType.includes('image')) { - return toCoin(BigInt(OperationDefaultFeeEnum.RESOURCE_CREATE_IMAGE)); - } - return toCoin(BigInt(OperationDefaultFeeEnum.RESOURCE_CREATE_OTHER)); - } - return toCoin(BigInt(defaultFee)); - } - - async trackOperation(trackOperation: ITrackOperation): Promise { - try { - // Create Default Fee Coin - const defaultFeeCoin = await this.getDefaultFeeCoin(trackOperation); - const defaultFee = await CoinService.instance.create(BigInt(defaultFeeCoin.amount), defaultFeeCoin.denom); - // Create operation entity - const operationEntity = await OperationService.instance.create( - trackOperation.category, - trackOperation.name, - defaultFee, - false, - trackOperation.successful - ); - - if (!operationEntity) { - throw new Error(`Operation ${trackOperation.name} was not written to DB`); - } - - // Track payments - if (trackOperation.feePaymentOptions) { - const operationWithPayment = new TrackOperationWithPayment(trackOperation); - const paymentValidation = operationWithPayment.validate(); - if (paymentValidation.error) { - return { - operation: trackOperation, - error: `Error while validating payment options: ${paymentValidation.error}`, - } satisfies ITrackResult; - } - return await this.trackPayments(operationWithPayment, operationEntity); - } - - return { - operation: trackOperation, - error: '', - } satisfies ITrackResult; - } catch (error) { - return { - operation: trackOperation, - error: `Error while writing information about operation ${trackOperation.name} to DB: ${(error as Error)?.message || error}`, - } satisfies ITrackResult; - } - } -} - -export class ResourceSubscriber extends BaseOperationObserver implements IObserver { - private static acceptedOperations = [ - OperationNameEnum.RESOURCE_CREATE, - OperationNameEnum.CREDENTIAL_REVOKE, - OperationNameEnum.CREDENTIAL_SUSPEND, - OperationNameEnum.CREDENTIAL_UNSUSPEND, - OperationNameEnum.CREDENTIAL_STATUS_CREATE_UNENCRYPTED, - OperationNameEnum.CREDENTIAL_STATUS_CREATE_ENCRYPTED, - OperationNameEnum.CREDENTIAL_STATUS_UPDATE_UNENCRYPTED, - OperationNameEnum.CREDENTIAL_STATUS_UPDATE_ENCRYPTED, - ]; - - isReactionNeeded(trackOperation: ITrackOperation): boolean { - // Resource tracker reacts on CredentialStatusList, Credential operations like revocation - // and Resource operations like create, update, delete - const isCategoryAccepted = - trackOperation.category === OperationCategoryNameEnum.RESOURCE || - trackOperation.category === OperationCategoryNameEnum.CREDENTIAL || - trackOperation.category === OperationCategoryNameEnum.CREDENTIAL_STATUS; - const isOperationAccepted = ResourceSubscriber.acceptedOperations.includes( - trackOperation.name as OperationNameEnum - ); - return isCategoryAccepted && isOperationAccepted; - } - - public compileMessage(trackResult: ITrackResult): string { - const base_message = super.compileMessage(trackResult); - const data = trackResult.operation.data as IResourceTrack; - return `${base_message} | Resource DID: ${data.did} | ResourceName: ${data.resource.resourceName} | ResourceType: ${data.resource.resourceType} | ResourceId: ${data.resource.resourceId}`; - } - - async update(trackOperation: ITrackOperation): Promise { - if (!this.isReactionNeeded(trackOperation)) { - // Just skip this operation - return; - } - trackOperation.category = OperationCategoryNameEnum.RESOURCE; - trackOperation.name = OperationNameEnum.RESOURCE_CREATE; - // tracking resource creation in DB - const result = await this.trackResourceOperation(trackOperation); - // notify about the result of tracking, e.g. log or datadog - await this.notify({ - message: this.compileMessage(result), - severity: result.error ? 'error' : 'info', - }); - } - - async trackResourceOperation(trackOperation: ITrackOperation): Promise { - // Resource operation may be with CredentialStatusList or with Credential operations like revocation - // and others and also with Resource operations like create, update, delete - const customer = trackOperation.customer; - const data = trackOperation.data as IResourceTrack | ICredentialStatusTrack | ICredentialTrack; - const did = data.did; - let encrypted = false; - let symmetricKey = ''; - let resource: LinkedResourceMetadataResolutionResult | undefined = undefined; - - if (!customer) { - return { - operation: trackOperation, - error: `Customer for resource operation was not specified`, - }; - } - - if (isResourceTrack(data)) { - encrypted = false; - symmetricKey = ''; - resource = (data as IResourceTrack).resource; - } - if (isCredentialStatusTrack(data)) { - encrypted = (data as ICredentialStatusTrack).encrypted || false; - symmetricKey = (data as ICredentialStatusTrack).symmetricKey || ''; - resource = (data as ICredentialStatusTrack).resource; - } - if (isCredentialTrack(data)) { - encrypted = (data as ICredentialTrack).encrypted || false; - symmetricKey = (data as ICredentialTrack).symmetricKey || ''; - resource = (data as ICredentialTrack).resource; - } - - if (!resource) { - return { - operation: trackOperation, - error: `Resource for ${did} was not specified`, - }; - } - - const identifier = await IdentifierService.instance.get(did); - if (!identifier) { - throw new Error(`Identifier ${did} not found`); - } - if (!identifier.controllerKeyId) { - throw new Error(`Identifier ${did} does not have link to the controller key...`); - } - const key = await KeyService.instance.get(identifier.controllerKeyId); - if (!key) { - throw new Error(`Key for ${did} not found`); - } - - const resourceEntity = await ResourceService.instance.createFromLinkedResource( - resource, - customer, - key, - identifier, - encrypted, - symmetricKey - ); - if (!resourceEntity) { - return { - operation: trackOperation, - error: `Resource for ${did} was not tracked`, - }; - } - return { - operation: trackOperation, - error: '', - }; - } -} - -export class CredentialSubscriber extends BaseOperationObserver implements IObserver { - isReactionNeeded(trackOperation: ITrackOperation): boolean { - // Credential tracker reacts on CredentialStatusList, Credential operations like revocation - // and Resource operations like create, update, delete - return trackOperation.category === OperationCategoryNameEnum.CREDENTIAL; - } - - public compileMessage(trackResult: ITrackResult): string { - const base_message = super.compileMessage(trackResult); - const data = trackResult.operation.data as ICredentialTrack; - return `${base_message} | Credential holder: ${data.did}`; - } - - async update(trackOperation: ITrackOperation): Promise { - if (!this.isReactionNeeded(trackOperation)) { - // Just skip this operation - return; - } - // tracking resource creation in DB - const result = await this.trackCredentialOperation(trackOperation); - // notify about the result of tracking, e.g. log or datadog - await this.notify({ - message: this.compileMessage(result), - severity: result.error ? 'error' : 'info', - }); - } - - async trackCredentialOperation(trackOperation: ITrackOperation): Promise { - // We don't have specific credential writes, so we just track credential creation - return { - operation: trackOperation, - error: '', - } satisfies ITrackResult; - } -} - -export class DIDSubscriber extends BaseOperationObserver implements IObserver { - isReactionNeeded(trackOperation: ITrackOperation): boolean { - return trackOperation.category === OperationCategoryNameEnum.DID; - } - - public compileMessage(trackResult: ITrackResult): string { - const base_message = super.compileMessage(trackResult); - const data = trackResult.operation.data as IDIDTrack; - return `${base_message} | Target DID: ${data.did}`; - } - - async update(trackOperation: ITrackOperation): Promise { - if (!this.isReactionNeeded(trackOperation)) { - // Just skip this operation - return; - } - // tracking resource creation in DB - const result = await this.trackDIDOperation(trackOperation); - // notify about the result of tracking, e.g. log or datadog - await this.notify({ - message: this.compileMessage(result), - severity: result.error ? 'error' : 'info', - }); - } - - async trackDIDOperation(trackOperation: ITrackOperation): Promise { - // We don't have specific DID related operations to track - return { - operation: trackOperation, - error: '', - } satisfies ITrackResult; - } -} - -export class CredentialStatusSubscriber extends BaseOperationObserver implements IObserver { - isReactionNeeded(trackOperation: ITrackOperation): boolean { - // Credential tracker reacts on CredentialStatusList, Credential operations like revocation - // and Resource operations like create, update, delete - return trackOperation.category === OperationCategoryNameEnum.CREDENTIAL_STATUS; - } - - public compileMessage(trackResult: ITrackResult): string { - const base_message = super.compileMessage(trackResult); - const data = trackResult.operation.data as ICredentialStatusTrack; - return `${base_message} | Target DID: ${data.did} | Encrypted: ${data.encrypted} | StatusListName: ${data.resource?.resourceName}`; - } - - async update(trackOperation: ITrackOperation): Promise { - if (!this.isReactionNeeded(trackOperation)) { - // Just skip this operation - return; - } - // tracking resource creation in DB - const result = await this.trackCredentialStatusOperation(trackOperation); - // notify about the result of tracking, e.g. log or datadog - await this.notify({ - message: this.compileMessage(result), - severity: result.error ? 'error' : 'info', - }); - } - - async trackCredentialStatusOperation(trackOperation: ITrackOperation): Promise { - // We don't have specific credential status writes, so we just track credential creation - return { - operation: trackOperation, - error: '', - } satisfies ITrackResult; - } -} - -export class PresentationSubscriber extends BaseOperationObserver implements IObserver { - isReactionNeeded(trackOperation: ITrackOperation): boolean { - // Credential tracker reacts on CredentialStatusList, Credential operations like revocation - // and Resource operations like create, update, delete - return trackOperation.category === OperationCategoryNameEnum.PRESENTATION; - } - - public compileMessage(trackResult: ITrackResult): string { - const base_message = super.compileMessage(trackResult); - const data = trackResult.operation.data as IPresentationTrack; - return `${base_message} | Presentation holder: ${data.holder}`; - } - - async update(trackOperation: ITrackOperation): Promise { - if (!this.isReactionNeeded(trackOperation)) { - // Just skip this operation - return; - } - // tracking resource creation in DB - const result = await this.trackPresentationOperation(trackOperation); - // notify about the result of tracking, e.g. log or datadog - await this.notify({ - message: this.compileMessage(result), - severity: result.error ? 'error' : 'info', - }); - } - - async trackPresentationOperation(trackOperation: ITrackOperation): Promise { - // We don't have specific presentation writes, so we just track presentation creation - return { - operation: trackOperation, - error: '', - } satisfies ITrackResult; - } -} - -export class KeySubscriber extends BaseOperationObserver implements IObserver { - isReactionNeeded(trackOperation: ITrackOperation): boolean { - // Credential tracker reacts on CredentialStatusList, Credential operations like revocation - // and Resource operations like create, update, delete - return trackOperation.category === OperationCategoryNameEnum.KEY; - } - - public compileMessage(trackResult: ITrackResult): string { - const base_message = super.compileMessage(trackResult); - const data = trackResult.operation.data as IKeyTrack; - return `${base_message} | keyRef: ${data.keyRef} | keyType: ${data.keyType}`; - } - - async update(trackOperation: ITrackOperation): Promise { - if (!this.isReactionNeeded(trackOperation)) { - // Just skip this operation - return; - } - // tracking resource creation in DB - const result = await this.trackKeyOperation(trackOperation); - // notify about the result of tracking, e.g. log or datadog - await this.notify({ - message: this.compileMessage(result), - severity: result.error ? 'error' : 'info', - }); - } - - async trackKeyOperation(trackOperation: ITrackOperation): Promise { - // We don't have specific presentation writes, so we just track presentation creation - return { - operation: trackOperation, - error: '', - } satisfies ITrackResult; - } -} diff --git a/src/services/track/tracker.ts b/src/services/track/tracker.ts index f73cb1c1..62713d0c 100644 --- a/src/services/track/tracker.ts +++ b/src/services/track/tracker.ts @@ -3,25 +3,31 @@ import type { INotifyMessage, ITrackOperation } from '../../types/track.js'; import { DatadogNotifier, LoggerNotifier } from './notifiers.js'; import { DBOperationSubscriber, - ResourceSubscriber, - CredentialSubscriber, - DIDSubscriber, - CredentialStatusSubscriber, - PresentationSubscriber, -} from './subscribers.js'; +} from './operation-subscriber.js'; +import { + ResourceSubscriber} from './api/resource-subscriber.js'; +import { PresentationSubscriber } from './api/presentation-subscriber.js'; +import { CredentialStatusSubscriber } from './api/credential-status-subscriber.js'; +import { DIDSubscriber } from './api/did-subscriber.js'; +import { CredentialSubscriber } from './api/credential-subscriber.js'; import type { ITrackType } from './types.js'; import { ENABLE_DATADOG } from '../../types/constants.js'; -import { Observer } from './observer.js'; +import { SubmitSubject, TrackSubject } from './observer.js'; +import type { ISubmitOperation } from './submitter.js'; +import { PortalAccountCreateSubmitter } from "./admin/account-submitter.js"; +import { SubscriptionSubmitter } from './admin/subscription-submitter.js'; export class EventTracker { readonly emitter: EventEmitter; - readonly tracker: Observer; - readonly notifier: Observer; + readonly tracker: TrackSubject; + readonly notifier: TrackSubject; + readonly submitter: SubmitSubject; - constructor(emitter?: EventEmitter, tracker?: Observer, notifier?: Observer) { + constructor(emitter?: EventEmitter, tracker?: TrackSubject, notifier?: TrackSubject, submitter?: SubmitSubject) { this.emitter = emitter || new EventEmitter(); - this.tracker = tracker || new Observer(); - this.notifier = notifier || new Observer(); + this.tracker = tracker || new TrackSubject(); + this.notifier = notifier || new TrackSubject(); + this.submitter = submitter || new SubmitSubject(); if (!tracker) { this.setupDefaultTrackers(); @@ -29,6 +35,9 @@ export class EventTracker { if (!notifier) { this.setupDefaultNotifiers(); } + if (!submitter) { + this.setupDefaultSubmitters(); + } this.setupBaseEvents(); } @@ -48,6 +57,11 @@ export class EventTracker { } } + setupDefaultSubmitters() { + this.submitter.attach(new PortalAccountCreateSubmitter(this.getEmitter())); + this.submitter.attach(new SubscriptionSubmitter(this.getEmitter())); + } + getEmitter(): EventEmitter { return this.emitter; } @@ -55,6 +69,7 @@ export class EventTracker { setupBaseEvents() { this.emitter.on('track', this.track.bind(this)); this.emitter.on('notify', this.notify.bind(this)); + this.emitter.on('submit', this.submit.bind(this)); } async track(trackOperation: ITrackOperation): Promise { @@ -65,6 +80,19 @@ export class EventTracker { await this.notifier.notify(notifyMessage); } + async submit(operation: ISubmitOperation): Promise { + await this.submitter.notify(operation); + } + + static compileBasicNotification(message: string, operation?: string): string { + const parts = []; + const date = new Date().toISOString(); + parts.push(date); + if (operation) parts.push('Operation: ' + operation); + parts.push('Message: ' + message); + return parts.join(' | '); + } + emit(eventName: string | symbol, ...args: ITrackType[]): boolean { return this.getEmitter().emit(eventName, ...args); } diff --git a/src/services/track/types.ts b/src/services/track/types.ts index baf52694..9f84a847 100644 --- a/src/services/track/types.ts +++ b/src/services/track/types.ts @@ -1,6 +1,7 @@ import type { ITrackOperation, INotifyMessage } from '../../types/track'; +import type { ISubmitOperation } from './submitter'; -export type ITrackType = ITrackOperation | INotifyMessage; +export type ITrackType = ITrackOperation | INotifyMessage | ISubmitOperation; export interface IObserver { update(operation: ITrackType): Promise; diff --git a/src/static/swagger-admin-options.json b/src/static/swagger-admin-options.json index 4e4498c5..b3382775 100644 --- a/src/static/swagger-admin-options.json +++ b/src/static/swagger-admin-options.json @@ -26,6 +26,9 @@ }, { "name": "Subscription" + }, + { + "name": "Checkout" } ] } diff --git a/src/static/swagger-admin.json b/src/static/swagger-admin.json index 022bcf36..76f95afe 100644 --- a/src/static/swagger-admin.json +++ b/src/static/swagger-admin.json @@ -26,9 +26,45 @@ }, { "name": "Subscription" + }, + { + "name": "Checkout" } ], "paths": { + "/admin/checkout/session/create": { + "post": { + "summary": "Create a checkout session", + "description": "Create a checkout session", + "tags": [ + "Checkout" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CheckoutSessionCreateRequestBody" + } + } + } + }, + "responses": { + "303": { + "description": "A redirect to Stripe prebuilt checkout page" + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, "/admin/price/list": { "get": { "summary": "Get a list of prices", @@ -647,6 +683,37 @@ } } }, + "CheckoutSessionCreateRequestBody": { + "description": "The request body for creating a checkout session", + "type": "object", + "properties": { + "customerId": { + "type": "string", + "description": "The Stripe customer id", + "example": "cus_1234567890" + }, + "price": { + "type": "string", + "description": "The price id", + "example": "price_1234567890" + }, + "successURL": { + "type": "string", + "description": "The URL to redirect to after the customer sucessfully completes the checkout", + "example": "https://example.com/success" + }, + "cancelURL": { + "type": "string", + "description": "The URL to redirect to after the customer cancels the checkout", + "example": "https://example.com/cancel" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": 1234567890 + } + } + }, "NotFoundError": { "description": "The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible.", "type": "object", diff --git a/src/types/constants.ts b/src/types/constants.ts index 6399c57c..f52948e7 100644 --- a/src/types/constants.ts +++ b/src/types/constants.ts @@ -74,6 +74,7 @@ export enum OperationCategoryNameEnum { CREDENTIAL = 'credential', PRESENTATION = 'presentation', KEY = 'key', + SUBSCRIPTION = 'subscription', } export enum OperationDefaultFeeEnum { @@ -121,6 +122,14 @@ export enum OperationNameEnum { // Presentation operations PRESENTATION_CREATE = 'presentation-create', PRESENTATION_VERIFY = 'presentation-verify', + // Subscription + SUBSCRIPTION_CREATE = 'subscription-create', + SUBSCRIPTION_CANCEL = 'subscription-cancel', + SUBSCRIPTION_UPDATE = 'subscription-update', + SUBSCRIPTION_TRIAL_WILL_END = 'subscription-trial-will-end', + + // Stripe operations + STRIPE_ACCOUNT_CREATE = 'stripe-account-create', } export const JWT_PROOF_TYPE = 'JwtProof2020'; diff --git a/src/types/environment.d.ts b/src/types/environment.d.ts index f29c106e..d114b94e 100644 --- a/src/types/environment.d.ts +++ b/src/types/environment.d.ts @@ -60,6 +60,7 @@ declare global { // Stripe STRIPE_SECRET_KEY: string; STRIPE_PUBLISHABLE_KEY: string; + STRIPE_WEBHOOK_SECRET: string; } } diff --git a/src/types/portal.ts b/src/types/portal.ts index e4de0863..4514a4f0 100644 --- a/src/types/portal.ts +++ b/src/types/portal.ts @@ -97,4 +97,22 @@ export type SubscriptionResumeUnsuccessfulResponseBody = UnsuccessfulResponseBod // Customer // Get -export type PortalCustomerGetUnsuccessfulResponseBody = UnsuccessfulResponseBody; \ No newline at end of file +export type PortalCustomerGetUnsuccessfulResponseBody = UnsuccessfulResponseBody; + + +// Checkout Session +export type CheckoutSessionCreateRequestBody = { + price: string; + successURL: string; + cancelURL: string; + quantity?: number; + idempotencyKey?: string; +} +export type CheckoutSessionCreateResponseBody = { + clientSecret: Stripe.Checkout.Session['client_secret']; +} + +export type CheckoutSessionCreateUnsuccessfulResponseBody = UnsuccessfulResponseBody; +// Utils + +export type PaymentBehavior = Stripe.SubscriptionCreateParams.PaymentBehavior; \ No newline at end of file diff --git a/src/types/swagger-admin-types.ts b/src/types/swagger-admin-types.ts index e7ac6ea1..da03eaae 100644 --- a/src/types/swagger-admin-types.ts +++ b/src/types/swagger-admin-types.ts @@ -165,6 +165,26 @@ * subscription: * type: object * description: A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object] + * CheckoutSessionCreateRequestBody: + * description: The request body for creating a checkout session + * type: object + * properties: + * price: + * type: string + * description: The price id + * example: price_1234567890 + * successURL: + * type: string + * description: The URL to redirect to after the customer sucessfully completes the checkout + * example: https://example.com/success + * cancelURL: + * type: string + * description: The URL to redirect to after the customer cancels the checkout + * example: https://example.com/cancel + * idempotencyKey: + * type: string + * description: The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request. + * example: 1234567890 * NotFoundError: * description: The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible. * type: object diff --git a/src/types/track.ts b/src/types/track.ts index c61e3f2d..807a161c 100644 --- a/src/types/track.ts +++ b/src/types/track.ts @@ -4,7 +4,7 @@ import type { CustomerEntity } from '../database/entities/customer.entity.js'; import type { UserEntity } from '../database/entities/user.entity.js'; import type { LogLevelDesc } from 'loglevel'; import type { ResourceEntity } from '../database/entities/resource.entity.js'; -import { ResourceService } from '../services/resource.js'; +import { ResourceService } from '../services/api/resource.js'; import type { Coin } from '@cosmjs/amino'; export type TrackData = From a036a0223badf57799b3e7af2923bde7ef49e2bd Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Sun, 10 Mar 2024 20:46:40 +0100 Subject: [PATCH 04/40] Add auth routes to admin --- src/app.ts | 12 +-- src/controllers/admin/product.ts | 4 +- src/controllers/admin/subscriptions.ts | 18 ++--- src/database/entities/subscription.entity.ts | 8 +- .../auth/routes/admin/admin-auth.ts | 14 ++++ src/middleware/event-tracker.ts | 10 ++- src/services/admin/subscription.ts | 78 ++++++++++++++++++- src/services/api/customer.ts | 7 ++ src/static/swagger-admin.json | 18 +---- src/types/portal.ts | 5 -- 10 files changed, 125 insertions(+), 49 deletions(-) diff --git a/src/app.ts b/src/app.ts index 06771e39..39026780 100644 --- a/src/app.ts +++ b/src/app.ts @@ -21,12 +21,12 @@ dotenv.config(); // Define Swagger file import swaggerAPIDocument from './static/swagger-api.json' assert { type: 'json' }; -// import swaggerAdminDocument from './static/swagger-admin.json' assert { type: 'json' }; +import swaggerAdminDocument from './static/swagger-admin.json' assert { type: 'json' }; import { PresentationController } from './controllers/api/presentation.js'; import { KeyController } from './controllers/api/key.js'; import { DIDController } from './controllers/api/did.js'; import { ResourceController } from './controllers/api/resource.js'; -import { FailedResponseTracker } from './middleware/event-tracker.js'; +import { ResponseTracker } from './middleware/event-tracker.js'; import { ProductController } from './controllers/admin/product.js'; import { SubscriptionController } from './controllers/admin/subscriptions.js'; import { PriceController } from './controllers/admin/prices.js'; @@ -77,7 +77,7 @@ class App { this.express.use(cookieParser()); const auth = new Authentication(); // EventTracking - this.express.use(new FailedResponseTracker().trackJson); + this.express.use(new ResponseTracker().trackJson); // Authentication if (process.env.ENABLE_AUTHENTICATION === 'true') { this.express.use( @@ -103,7 +103,7 @@ class App { this.express.use(express.text()); this.express.use('/swagger', swaggerUi.serveFiles(swaggerAPIDocument, swaggerOptions), swaggerUi.setup(swaggerAPIDocument, swaggerOptions)); - // this.express.use('/admin/swagger', swaggerUi.serveFiles(swaggerAdminDocument), swaggerUi.setup(swaggerAdminDocument)) + this.express.use('/admin/swagger', swaggerUi.serveFiles(swaggerAdminDocument), swaggerUi.setup(swaggerAdminDocument)) this.express.use(auth.handleError); this.express.use(async (req, res, next) => await auth.accessControl(req, res, next)); } @@ -215,8 +215,8 @@ class App { // Portal // Product - app.get('/admin/product/list', ProductController.productListValidator, new ProductController().getListProducts); - app.get('/admin/product/:productId', ProductController.productGetValidator, new ProductController().getProduct); + app.get('/admin/product/list', ProductController.productListValidator, new ProductController().listProducts); + app.get('/admin/product/get/:productId', ProductController.productGetValidator, new ProductController().getProduct); // Prices app.get('/admin/price/list', PriceController.priceListValidator, new PriceController().getListPrices); diff --git a/src/controllers/admin/product.ts b/src/controllers/admin/product.ts index 23f81c35..90ec309e 100644 --- a/src/controllers/admin/product.ts +++ b/src/controllers/admin/product.ts @@ -63,7 +63,7 @@ export class ProductController { * 404: * $ref: '#/components/schemas/NotFoundError' */ - async getListProducts(request: Request, response: Response) { + async listProducts(request: Request, response: Response) { const result = validationResult(request); // handle error if (!result.isEmpty()) { @@ -110,7 +110,7 @@ export class ProductController { /** * @openapi * - * /admin/product/{productId}: + * /admin/product/get/{productId}: * get: * summary: Get a product * description: Get a product by id diff --git a/src/controllers/admin/subscriptions.ts b/src/controllers/admin/subscriptions.ts index 41180ebc..35d8c204 100644 --- a/src/controllers/admin/subscriptions.ts +++ b/src/controllers/admin/subscriptions.ts @@ -5,6 +5,7 @@ import type { SubscriptionCreateRequestBody, SubscriptionCreateResponseBody, Sub import { StatusCodes } from 'http-status-codes'; import { validationResult } from '../validator/index.js'; import { check } from 'express-validator'; +import { SubscriptionService } from '../../services/admin/subscription.js'; dotenv.config(); @@ -140,11 +141,11 @@ export class SubscriptionController { } satisfies SubscriptionCreateUnsuccessfulResponseBody); } - const { customerId, items, idempotencyKey } = request.body satisfies SubscriptionCreateRequestBody; + const { items, idempotencyKey } = request.body satisfies SubscriptionCreateRequestBody; try { // Create the subscription const subscription = await stripe.subscriptions.create({ - customer: customerId, + customer: response.locals.customer.stripeCustomerId, items: items, payment_behavior: "default_incomplete" as PaymentBehavior, }, @@ -236,13 +237,6 @@ export class SubscriptionController { * summary: Get a list of subscriptions * description: Get a list of subscriptions * tags: [Subscription] - * parameters: - * - in: query - * name: customerId - * schema: - * type: string - * description: The customer id. If passed - returns filtered by this customer list of subscriptions. - * required: false * responses: * 200: * description: A list of subscriptions @@ -268,8 +262,10 @@ export class SubscriptionController { error: result.array().pop()?.msg } satisfies SubscriptionListUnsuccessfulResponseBody); } - const customerId = request.query.customerId; + const customerId = response.locals.customer.stripeCustomerId; try { + // Sync our DB with Stripe + await SubscriptionService.instance.stripeSync(response.locals.customer) // Get the subscriptions const subscriptions = customerId ? await stripe.subscriptions.list({ @@ -334,6 +330,8 @@ export class SubscriptionController { } const subscriptionId = request.params.subscriptionId; try { + // Sync our DB with Stripe + await SubscriptionService.instance.stripeSync(response.locals.customer) // Get the subscription const subscription = await stripe.subscriptions.retrieve(subscriptionId as string); if (subscription.lastResponse?.statusCode !== StatusCodes.OK) { diff --git a/src/database/entities/subscription.entity.ts b/src/database/entities/subscription.entity.ts index 125d89de..8c990994 100644 --- a/src/database/entities/subscription.entity.ts +++ b/src/database/entities/subscription.entity.ts @@ -75,15 +75,15 @@ export class SubscriptionEntity { status: string, currentPeriodStart: Date, currentPeriodEnd: Date, - trialStart: Date, - trialEnd: Date, + trialStart?: Date, + trialEnd?: Date, ){ this.subscriptionId = subscriptionId; this.customer = customer; this.status = status; this.currentPeriodStart = currentPeriodStart; this.currentPeriodEnd = currentPeriodEnd; - this.trialStart = trialStart; - this.trialEnd = trialEnd; + if (trialStart ) this.trialStart = trialStart; + if (trialEnd) this.trialEnd = trialEnd; } } diff --git a/src/middleware/auth/routes/admin/admin-auth.ts b/src/middleware/auth/routes/admin/admin-auth.ts index 013ee342..a7a243d8 100644 --- a/src/middleware/auth/routes/admin/admin-auth.ts +++ b/src/middleware/auth/routes/admin/admin-auth.ts @@ -8,6 +8,20 @@ export class AdminHandler extends BaseAuthHandler { // ToDo: define how to get namespace information this.registerRoute('/admin/checkout/session/create', 'POST', 'admin:checkout:session:create:testnet', { skipNamespace: true}); this.registerRoute('/admin/checkout/session/create', 'POST', 'admin:checkout:session:create:mainnet', { skipNamespace: true}); + // Subscriptions + this.registerRoute('/admin/subscription/list', 'GET', 'admin:subscription:list:testnet', { skipNamespace: true}); + this.registerRoute('/admin/subscription/list', 'GET', 'admin:subscription:list:mainnet', { skipNamespace: true}); + this.registerRoute('/admin/subscription/get', 'GET', 'admin:subscription:get:testnet', { skipNamespace: true}); + this.registerRoute('/admin/subscription/get', 'GET', 'admin:subscription:get:mainnet', { skipNamespace: true}); + // Prices + this.registerRoute('/admin/price/list', 'GET', 'admin:price:list:testnet', { skipNamespace: true}); + this.registerRoute('/admin/price/list', 'GET', 'admin:price:list:mainnet', { skipNamespace: true}); + + // Products + this.registerRoute('/admin/product/list', 'GET', 'admin:product:list:testnet', { skipNamespace: true}); + this.registerRoute('/admin/product/list', 'GET', 'admin:product:list:mainnet', { skipNamespace: true}); + this.registerRoute('/admin/product/get', 'GET', 'admin:product:get:testnet', { skipNamespace: true}); + this.registerRoute('/admin/product/get', 'GET', 'admin:product:get:mainnet', { skipNamespace: true}); } public async handle(request: Request, response: Response): Promise { if (!request.path.includes('/admin/')) { diff --git a/src/middleware/event-tracker.ts b/src/middleware/event-tracker.ts index 16d64619..d763dc4c 100644 --- a/src/middleware/event-tracker.ts +++ b/src/middleware/event-tracker.ts @@ -2,7 +2,7 @@ import type { Request, Response, NextFunction } from 'express'; import { eventTracker } from '../services/track/tracker.js'; import type { INotifyMessage } from '../types/track.js'; -export class FailedResponseTracker { +export class ResponseTracker { public async trackJson(request: Request, response: Response, next: NextFunction) { const originalJson = response.json; response.json = (body) => { @@ -14,18 +14,22 @@ export class FailedResponseTracker { parts.push('URL: ' + response.req.url); parts.push('Method: ' + response.req.method); parts.push('Status: ' + response.statusCode); + if (response.locals.customer) { + parts.push('Customer: ' + response.locals.customer.customerId); + } if (body && body.error) { parts.push('Message: ' + body.error); } return parts.join(' | '); }; // Notify - if (body && body.error) { + if (body) { eventTracker.emit('notify', { message: compileMessage(), - severity: 'error', + severity: body.error ? 'error' : 'info', } satisfies INotifyMessage); } + return originalJson.apply(response, [body]); }; return next(); diff --git a/src/services/admin/subscription.ts b/src/services/admin/subscription.ts index 9006adf9..62daba14 100644 --- a/src/services/admin/subscription.ts +++ b/src/services/admin/subscription.ts @@ -3,6 +3,15 @@ import type { Repository } from 'typeorm'; import { Connection } from '../../database/connection/connection.js'; import { SubscriptionEntity } from '../../database/entities/subscription.entity.js'; import type { CustomerEntity } from '../../database/entities/customer.entity.js'; +import type { UserEntity } from '../../database/entities/user.entity.js'; +import Stripe from 'stripe'; +import * as dotenv from 'dotenv'; +import { CustomerService } from '../api/customer.js'; +import { EventTracker, eventTracker } from '../track/tracker.js'; + +dotenv.config(); + +const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); export class SubscriptionService { public subscriptionRepository: Repository; @@ -20,8 +29,8 @@ export class SubscriptionService { status: string, currentPeriodStart: Date, currentPeriodEnd: Date, - trialStart: Date, - trialEnd: Date, + trialStart?: Date, + trialEnd?: Date, ): Promise { const subscriptionEntity = new SubscriptionEntity( subscriptionId, @@ -71,4 +80,69 @@ export class SubscriptionService { relations: ['customer'], }); } + + public async stripeSync(customer?: CustomerEntity, user?: UserEntity): Promise { + let stripeCustomerId: string; + if (!customer && !user) { + throw new Error('StripeSync: customer or user is required'); + } + if (customer) { + stripeCustomerId = customer.stripeCustomerId; + } else { + stripeCustomerId = user?.customer.stripeCustomerId as string; + } + + const subscriptions = await stripe.subscriptions.list({ customer: stripeCustomerId }); + // Get list of all subscription and sort them by created time to make sure that we are processing them in the correct order + for (const subscription of subscriptions.data.sort((a, b) => a.created - b.created)){ + const existing = await this.subscriptionRepository.findOne({ + where: { subscriptionId: subscription.id }, + }); + if (!existing) { + const customer = await CustomerService.instance.findbyStripeCustomerId(stripeCustomerId); + if (!customer) { + throw new Error(`Customer with stripeCustomerId ${stripeCustomerId} not found`); + } + const res = await this.create( + subscription.id, + customer, + subscription.status, + new Date(subscription.current_period_start * 1000), + new Date(subscription.current_period_end * 1000), + subscription.trial_start ? new Date(subscription.trial_start * 1000) : undefined, + subscription.trial_end ? new Date(subscription.trial_end * 1000) : undefined, + ); + if (!res) { + eventTracker.notify({ + message: EventTracker.compileBasicNotification(`Cannot create a new subscription with id ${subscription.id}`, 'Subscription syncronization'), + severity: 'error', + }); + } + eventTracker.notify({ + message: EventTracker.compileBasicNotification(`New subscription with id ${subscription.id} created`, 'Subscription syncronization'), + severity: 'info', + }); + } else { + const res = await this.update( + subscription.id, + subscription.status, + new Date(subscription.current_period_start * 1000), + new Date(subscription.current_period_end * 1000), + subscription.trial_start ? new Date(subscription.trial_start * 1000) : undefined, + subscription.trial_end ? new Date(subscription.trial_end * 1000) : undefined, + ); + if (!res) { + eventTracker.notify({ + message: EventTracker.compileBasicNotification(`Cannot update subscription with id ${subscription.id}`, 'Subscription syncronization'), + severity: 'error', + }); + } + eventTracker.notify({ + message: EventTracker.compileBasicNotification(`Subscription with id ${subscription.id} updated`, 'Subscription syncronization'), + severity: 'info', + }); + } + } + + } } diff --git a/src/services/api/customer.ts b/src/services/api/customer.ts index 9accc137..b33ab7b5 100644 --- a/src/services/api/customer.ts +++ b/src/services/api/customer.ts @@ -77,6 +77,13 @@ export class CustomerService { } } + public async findbyStripeCustomerId(stripeCustomerId: string) { + return await this.customerRepository.findOne({ + where: { stripeCustomerId }, + }); + + } + public async isExist(where: Record) { try { return (await this.customerRepository.findOne({ where })) ? true : false; diff --git a/src/static/swagger-admin.json b/src/static/swagger-admin.json index 76f95afe..8e616f6f 100644 --- a/src/static/swagger-admin.json +++ b/src/static/swagger-admin.json @@ -153,7 +153,7 @@ } } }, - "/admin/product/{productId}": { + "/admin/product/get/{productId}": { "get": { "summary": "Get a product", "description": "Get a product by id", @@ -291,17 +291,6 @@ "tags": [ "Subscription" ], - "parameters": [ - { - "in": "query", - "name": "customerId", - "schema": { - "type": "string", - "description": "The customer id. If passed - returns filtered by this customer list of subscriptions.", - "required": false - } - } - ], "responses": { "200": { "description": "A list of subscriptions", @@ -687,11 +676,6 @@ "description": "The request body for creating a checkout session", "type": "object", "properties": { - "customerId": { - "type": "string", - "description": "The Stripe customer id", - "example": "cus_1234567890" - }, "price": { "type": "string", "description": "The price id", diff --git a/src/types/portal.ts b/src/types/portal.ts index 4514a4f0..1553fb48 100644 --- a/src/types/portal.ts +++ b/src/types/portal.ts @@ -27,7 +27,6 @@ export type PriceListUnsuccessfulResponseBody = UnsuccessfulResponseBody; // Subscription // Create export type SubscriptionCreateRequestBody = { - customerId: string; items: [{ price: string }]; idempotencyKey?: string; } @@ -58,10 +57,6 @@ export type SubscriptionGetResponseBody = { } // List -export type SubscriptionListRequestBody = { - customerId: string; -} - export type SubscriptionListResponseBody = { subscriptions: Stripe.Response>; } From b44b3221abaf0ecdf63a6b32593033ad1cdb85cb Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Sun, 10 Mar 2024 21:40:12 +0100 Subject: [PATCH 05/40] Lint and format --- src/app.ts | 60 +- src/controllers/admin/checkout-session.ts | 200 +- src/controllers/admin/portal-customer.ts | 38 +- src/controllers/admin/prices.ts | 117 +- src/controllers/admin/product.ts | 336 +- src/controllers/admin/subscriptions.ts | 821 +- src/controllers/admin/webhook.ts | 222 +- src/controllers/api/account.ts | 2 +- src/database/entities/subscription.entity.ts | 94 +- .../migrations/CreateSubscriptionTable.ts | 29 +- src/database/types/enum.ts | 10 +- .../auth/routes/admin/admin-auth.ts | 32 +- src/middleware/auth/user-info-fetcher/base.ts | 1 - .../auth/user-info-fetcher/portal-token.ts | 68 +- src/services/admin/subscription.ts | 249 +- src/services/api/customer.ts | 1 - src/services/track/admin/account-submitter.ts | 106 +- .../track/admin/subscription-submitter.ts | 324 +- .../track/api/credential-status-subscriber.ts | 6 +- .../track/api/credential-subscriber.ts | 6 +- src/services/track/api/did-subscriber.ts | 7 +- src/services/track/api/key-subscriber.ts | 7 +- .../track/api/presentation-subscriber.ts | 6 +- src/services/track/api/resource-subscriber.ts | 7 +- src/services/track/observer.ts | 1 - src/services/track/operation-subscriber.ts | 1 - src/services/track/submitter.ts | 27 +- src/services/track/tracker.ts | 9 +- src/static/swagger-admin.json | 1404 ++-- src/static/swagger-api.json | 6880 ++++++++--------- src/types/portal.ts | 93 +- src/types/swagger-admin-types.ts | 16 +- 32 files changed, 5493 insertions(+), 5687 deletions(-) diff --git a/src/app.ts b/src/app.ts index 39026780..c94dc710 100644 --- a/src/app.ts +++ b/src/app.ts @@ -102,8 +102,16 @@ class App { } this.express.use(express.text()); - this.express.use('/swagger', swaggerUi.serveFiles(swaggerAPIDocument, swaggerOptions), swaggerUi.setup(swaggerAPIDocument, swaggerOptions)); - this.express.use('/admin/swagger', swaggerUi.serveFiles(swaggerAdminDocument), swaggerUi.setup(swaggerAdminDocument)) + this.express.use( + '/swagger', + swaggerUi.serveFiles(swaggerAPIDocument, swaggerOptions), + swaggerUi.setup(swaggerAPIDocument, swaggerOptions) + ); + this.express.use( + '/admin/swagger', + swaggerUi.serveFiles(swaggerAdminDocument), + swaggerUi.setup(swaggerAdminDocument) + ); this.express.use(auth.handleError); this.express.use(async (req, res, next) => await auth.accessControl(req, res, next)); } @@ -216,21 +224,53 @@ class App { // Portal // Product app.get('/admin/product/list', ProductController.productListValidator, new ProductController().listProducts); - app.get('/admin/product/get/:productId', ProductController.productGetValidator, new ProductController().getProduct); + app.get( + '/admin/product/get/:productId', + ProductController.productGetValidator, + new ProductController().getProduct + ); // Prices app.get('/admin/price/list', PriceController.priceListValidator, new PriceController().getListPrices); // Subscription - app.post('/admin/subscription/create', SubscriptionController.subscriptionCreateValidator, new SubscriptionController().create); - app.post('/admin/subscription/update', SubscriptionController.subscriptionUpdateValidator, new SubscriptionController().update); - app.get('/admin/subscription/get/:subscriptionId', SubscriptionController.subscriptionGetValidator, new SubscriptionController().get); - app.get('/admin/subscription/list', SubscriptionController.subscriptionListValidator, new SubscriptionController().list); - app.delete('/admin/subscription/cancel', SubscriptionController.subscriptionCancelValidator, new SubscriptionController().cancel); - app.post('/admin/subscription/resume', SubscriptionController.subscriptionResumeValidator, new SubscriptionController().resume); + app.post( + '/admin/subscription/create', + SubscriptionController.subscriptionCreateValidator, + new SubscriptionController().create + ); + app.post( + '/admin/subscription/update', + SubscriptionController.subscriptionUpdateValidator, + new SubscriptionController().update + ); + app.get( + '/admin/subscription/get/:subscriptionId', + SubscriptionController.subscriptionGetValidator, + new SubscriptionController().get + ); + app.get( + '/admin/subscription/list', + SubscriptionController.subscriptionListValidator, + new SubscriptionController().list + ); + app.delete( + '/admin/subscription/cancel', + SubscriptionController.subscriptionCancelValidator, + new SubscriptionController().cancel + ); + app.post( + '/admin/subscription/resume', + SubscriptionController.subscriptionResumeValidator, + new SubscriptionController().resume + ); // Checkout session - app.post('/admin/checkout/session/create', CheckoutSessionController.checkoutSessionCreateValidator, new CheckoutSessionController().create); + app.post( + '/admin/checkout/session/create', + CheckoutSessionController.checkoutSessionCreateValidator, + new CheckoutSessionController().create + ); // Webhook app.post('/admin/webhook', new WebhookController().handleWebhook); diff --git a/src/controllers/admin/checkout-session.ts b/src/controllers/admin/checkout-session.ts index 4477e0e6..151e7bfb 100644 --- a/src/controllers/admin/checkout-session.ts +++ b/src/controllers/admin/checkout-session.ts @@ -1,8 +1,10 @@ - import Stripe from 'stripe'; import type { Request, Response } from 'express'; import * as dotenv from 'dotenv'; -import type { CheckoutSessionCreateRequestBody, CheckoutSessionCreateUnsuccessfulResponseBody } from '../../types/portal.js'; +import type { + CheckoutSessionCreateRequestBody, + CheckoutSessionCreateUnsuccessfulResponseBody, +} from '../../types/portal.js'; import { check, validationResult } from '../validator/index.js'; import { StatusCodes } from 'http-status-codes'; @@ -10,108 +12,106 @@ dotenv.config(); const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); - export class CheckoutSessionController { - static checkoutSessionCreateValidator = [ - check('price') - .exists() - .withMessage('price is required') - .bail() - .isString() - .withMessage('price should be a string') - .bail(), - check('successURL') - .exists() - .withMessage('successURL is required') - .bail() - .isString() - .withMessage('successURL should be a string') - .bail(), - check('cancelURL') - .exists() - .withMessage('cancelURL is required') - .bail() - .isString() - .withMessage('cancelURL should be a string') - .bail(), - check('idempotencyKey') - .optional() - .isString() - .withMessage('idempotencyKey should be a string') - .bail(), - ]; + static checkoutSessionCreateValidator = [ + check('price') + .exists() + .withMessage('price is required') + .bail() + .isString() + .withMessage('price should be a string') + .bail(), + check('successURL') + .exists() + .withMessage('successURL is required') + .bail() + .isString() + .withMessage('successURL should be a string') + .bail(), + check('cancelURL') + .exists() + .withMessage('cancelURL is required') + .bail() + .isString() + .withMessage('cancelURL should be a string') + .bail(), + check('idempotencyKey').optional().isString().withMessage('idempotencyKey should be a string').bail(), + ]; - /** - * @openapi - * - * /admin/checkout/session/create: - * post: - * summary: Create a checkout session - * description: Create a checkout session - * tags: [Checkout] - * requestBody: - * required: true - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/CheckoutSessionCreateRequestBody' - * responses: - * 303: - * description: A redirect to Stripe prebuilt checkout page - * 400: - * $ref: '#/components/schemas/InvalidRequest' - * 401: - * $ref: '#/components/schemas/UnauthorizedError' - * 500: - * $ref: '#/components/schemas/InternalError' - */ + /** + * @openapi + * + * /admin/checkout/session/create: + * post: + * summary: Create a checkout session + * description: Create a checkout session + * tags: [Checkout] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/CheckoutSessionCreateRequestBody' + * responses: + * 303: + * description: A redirect to Stripe prebuilt checkout page + * 400: + * $ref: '#/components/schemas/InvalidRequest' + * 401: + * $ref: '#/components/schemas/UnauthorizedError' + * 500: + * $ref: '#/components/schemas/InternalError' + */ - public async create(request: Request, response: Response) { - const result = validationResult(request); - // handle error - if (!result.isEmpty()) { - return response.status(StatusCodes.BAD_REQUEST).json({ - error: result.array().pop()?.msg - } satisfies CheckoutSessionCreateUnsuccessfulResponseBody); - } + public async create(request: Request, response: Response) { + const result = validationResult(request); + // handle error + if (!result.isEmpty()) { + return response.status(StatusCodes.BAD_REQUEST).json({ + error: result.array().pop()?.msg, + } satisfies CheckoutSessionCreateUnsuccessfulResponseBody); + } - const { price, successURL, cancelURL, quantity, idempotencyKey } = request.body satisfies CheckoutSessionCreateRequestBody; - try { - const session = await stripe.checkout.sessions.create({ - mode: 'subscription', - customer: response.locals.customer.stripeCustomerId, - line_items: [ - { - price: price, - quantity: quantity || 1, - }, - ], - success_url: successURL, - cancel_url: cancelURL, - }, { - idempotencyKey - }); + const { price, successURL, cancelURL, quantity, idempotencyKey } = + request.body satisfies CheckoutSessionCreateRequestBody; + try { + const session = await stripe.checkout.sessions.create( + { + mode: 'subscription', + customer: response.locals.customer.stripeCustomerId, + line_items: [ + { + price: price, + quantity: quantity || 1, + }, + ], + success_url: successURL, + cancel_url: cancelURL, + }, + { + idempotencyKey, + } + ); - if (session.lastResponse?.statusCode !== StatusCodes.OK) { - return response.status(StatusCodes.BAD_GATEWAY).json({ - error: 'Checkout session was not created' - } satisfies CheckoutSessionCreateUnsuccessfulResponseBody); - } + if (session.lastResponse?.statusCode !== StatusCodes.OK) { + return response.status(StatusCodes.BAD_GATEWAY).json({ + error: 'Checkout session was not created', + } satisfies CheckoutSessionCreateUnsuccessfulResponseBody); + } - if (!session.url) { - return response.status(StatusCodes.BAD_GATEWAY).json({ - error: 'Checkout session URL was not provided' - } satisfies CheckoutSessionCreateUnsuccessfulResponseBody); - } + if (!session.url) { + return response.status(StatusCodes.BAD_GATEWAY).json({ + error: 'Checkout session URL was not provided', + } satisfies CheckoutSessionCreateUnsuccessfulResponseBody); + } - return response.json({ - url: session.url as string - }) - - } catch (error) { - return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ - error: `Internal error: ${(error as Error)?.message || error}` - } satisfies CheckoutSessionCreateUnsuccessfulResponseBody); - } - } -} \ No newline at end of file + return response.json({ + url: session.url as string, + }); + } catch (error) { + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: `Internal error: ${(error as Error)?.message || error}`, + } satisfies CheckoutSessionCreateUnsuccessfulResponseBody); + } + } +} diff --git a/src/controllers/admin/portal-customer.ts b/src/controllers/admin/portal-customer.ts index c092d4e9..4c1d1c4d 100644 --- a/src/controllers/admin/portal-customer.ts +++ b/src/controllers/admin/portal-customer.ts @@ -7,27 +7,21 @@ import type { PortalCustomerGetUnsuccessfulResponseBody } from '../../types/port dotenv.config(); export class PortalCustomerController { - static portalCustomerGetValidator = [ - check('logToUserId') - .optional() - .isString() - .withMessage('logToUserId should be a string') - .bail(), - ]; + static portalCustomerGetValidator = [ + check('logToUserId').optional().isString().withMessage('logToUserId should be a string').bail(), + ]; - async get(request: Request, response: Response) { - const result = validationResult(request); - // handle error - if (!result.isEmpty()) { - return response.status(400).json({ - error: result.array().pop()?.msg - } satisfies PortalCustomerGetUnsuccessfulResponseBody); - } + async get(request: Request, response: Response) { + const result = validationResult(request); + // handle error + if (!result.isEmpty()) { + return response.status(400).json({ + error: result.array().pop()?.msg, + } satisfies PortalCustomerGetUnsuccessfulResponseBody); + } - - - return response.status(500).json({ - error: "Not implemented yet" - }) - } -} \ No newline at end of file + return response.status(500).json({ + error: 'Not implemented yet', + }); + } +} diff --git a/src/controllers/admin/prices.ts b/src/controllers/admin/prices.ts index cb9e3178..e78e5dac 100644 --- a/src/controllers/admin/prices.ts +++ b/src/controllers/admin/prices.ts @@ -11,75 +11,70 @@ dotenv.config(); const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); export class PriceController { + static priceListValidator = [ + check('productId').optional().isString().withMessage('productId should be a string').bail(), + ]; - static priceListValidator = [ - check('productId') - .optional() - .isString() - .withMessage('productId should be a string') - .bail(), - ]; - - /** + /** * @openapi * - * /admin/price/list: - * get: - * summary: Get a list of prices - * description: Get a list of prices - * tags: [Price] - * parameters: - * - in: query - * name: productId - * schema: - * type: string - * description: The product id. If passed - returns filtered by this product list of prices. - * required: false - * responses: - * 200: - * description: A list of prices - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/PriceListResponseBody' - * 400: + * /admin/price/list: + * get: + * summary: Get a list of prices + * description: Get a list of prices + * tags: [Price] + * parameters: + * - in: query + * name: productId + * schema: + * type: string + * description: The product id. If passed - returns filtered by this product list of prices. + * required: false + * responses: + * 200: + * description: A list of prices + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/PriceListResponseBody' + * 400: * $ref: '#/components/schemas/InvalidRequest' * 401: * $ref: '#/components/schemas/UnauthorizedError' * 500: * $ref: '#/components/schemas/InternalError' - * 404: - * $ref: '#/components/schemas/NotFoundError' + * 404: + * $ref: '#/components/schemas/NotFoundError' */ - async getListPrices(request: Request, response: Response) { - const result = validationResult(request); - // handle error - if (!result.isEmpty()) { - return response.status(StatusCodes.BAD_REQUEST).json({ - error: result.array().pop()?.msg - } satisfies PriceListUnsuccessfulResponseBody); - } - // Get query parameters - const productId = request.query.productId; + async getListPrices(request: Request, response: Response) { + const result = validationResult(request); + // handle error + if (!result.isEmpty()) { + return response.status(StatusCodes.BAD_REQUEST).json({ + error: result.array().pop()?.msg, + } satisfies PriceListUnsuccessfulResponseBody); + } + // Get query parameters + const productId = request.query.productId; - try { - // Fetch the list of prices - const prices = productId - ? await stripe.prices.list({ - product: productId as string, - active: true, - }) - : await stripe.prices.list({ - active: true, - }) + try { + // Fetch the list of prices + const prices = productId + ? await stripe.prices.list({ + product: productId as string, + active: true, + }) + : await stripe.prices.list({ + active: true, + }); - return response.status(StatusCodes.OK).json({ - prices: prices - } satisfies PriceListResponseBody); - } catch (error) { - return response.status(500).json({ - error: `Internal error: ${(error as Error)?.message || error}` - } satisfies PriceListUnsuccessfulResponseBody); - } - } -} \ No newline at end of file + return response.status(StatusCodes.OK).json({ + prices: prices, + } satisfies PriceListResponseBody); + } catch (error) { + return response.status(500).json({ + error: `Internal error: ${(error as Error)?.message || error}`, + } satisfies PriceListUnsuccessfulResponseBody); + } + } +} diff --git a/src/controllers/admin/product.ts b/src/controllers/admin/product.ts index 90ec309e..e1c7b114 100644 --- a/src/controllers/admin/product.ts +++ b/src/controllers/admin/product.ts @@ -1,7 +1,13 @@ import { Stripe } from 'stripe'; import type { Request, Response } from 'express'; import * as dotenv from 'dotenv'; -import type { ProductGetResponseBody, ProductGetUnsuccessfulResponseBody, ProductListResponseBody, ProductListUnsuccessfulResponseBody, ProductWithPrices } from '../../types/portal.js'; +import type { + ProductGetResponseBody, + ProductGetUnsuccessfulResponseBody, + ProductListResponseBody, + ProductListUnsuccessfulResponseBody, + ProductWithPrices, +} from '../../types/portal.js'; import { StatusCodes } from 'http-status-codes'; import { validationResult } from '../validator/index.js'; import { check } from 'express-validator'; @@ -11,182 +17,168 @@ dotenv.config(); const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); export class ProductController { - - static productListValidator = [ - check('prices') - .optional() - .isBoolean() - .withMessage('prices should be a boolean') - .bail(), - ]; - - static productGetValidator = [ - check('productId') - .exists() - .withMessage('productId was not provided') - .bail(), - check('prices') - .optional() - .isBoolean() - .withMessage('prices should be a boolean') - .bail(), - ]; - - /** - * @openapi - * - * /admin/product/list: - * get: - * summary: Get a list of products - * description: Get a list of products which are on a Stripe side - * tags: [Product] - * parameters: - * - in: query - * name: prices - * schema: - * type: boolean - * description: If setup to true - returns the list of products with prices inside. Default - true - * required: false - * responses: - * 200: - * description: A list of products - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ProductListResponseBody' - * 400: + static productListValidator = [ + check('prices').optional().isBoolean().withMessage('prices should be a boolean').bail(), + ]; + + static productGetValidator = [ + check('productId').exists().withMessage('productId was not provided').bail(), + check('prices').optional().isBoolean().withMessage('prices should be a boolean').bail(), + ]; + + /** + * @openapi + * + * /admin/product/list: + * get: + * summary: Get a list of products + * description: Get a list of products which are on a Stripe side + * tags: [Product] + * parameters: + * - in: query + * name: prices + * schema: + * type: boolean + * description: If setup to true - returns the list of products with prices inside. Default - true + * required: false + * responses: + * 200: + * description: A list of products + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/ProductListResponseBody' + * 400: * $ref: '#/components/schemas/InvalidRequest' * 401: * $ref: '#/components/schemas/UnauthorizedError' * 500: * $ref: '#/components/schemas/InternalError' - * 404: - * $ref: '#/components/schemas/NotFoundError' + * 404: + * $ref: '#/components/schemas/NotFoundError' */ - async listProducts(request: Request, response: Response) { - const result = validationResult(request); - // handle error - if (!result.isEmpty()) { - return response.status(StatusCodes.BAD_REQUEST).json({ - error: result.array().pop()?.msg - } satisfies ProductListUnsuccessfulResponseBody); - } - // Get query parameters - const prices = request.query.prices === 'false' ? false : true; - - try { - const products = await stripe.products.list({ - active: true, - }) as Stripe.ApiList; - - // If no products found return 404 - if (!products.data) { - return response.status(StatusCodes.NOT_FOUND).json({ - error: 'Seems like there no any active products on Stripe side. Please add some.' - } satisfies ProductListUnsuccessfulResponseBody); - } - - if (prices) { - for (const product of products.data) { - const prices = await stripe.prices.list({ - product: product.id, - active: true, - }); - product.prices = prices.data; - } - } - - return response.status(StatusCodes.OK).json({ - products: products - } satisfies ProductListResponseBody); - } catch (error) { - return response.status(500).json({ - error: `Internal error: ${(error as Error)?.message || error}` - } satisfies ProductListUnsuccessfulResponseBody); - } - } - - - /** - * @openapi - * - * /admin/product/get/{productId}: - * get: - * summary: Get a product - * description: Get a product by id - * tags: [Product] - * parameters: - * - in: path - * name: productId - * schema: - * type: string - * description: The product id which identifies the product in Stripe - * required: true - * - in: query - * name: prices - * schema: - * type: boolean - * description: If setup to true - returns the product with prices inside. Default - true - * required: false - * responses: - * 200: - * description: A product - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ProductGetResponseBody' - * 400: - * $ref: '#/components/schemas/InvalidRequest' - * 401: - * $ref: '#/components/schemas/UnauthorizedError' - * 500: - * $ref: '#/components/schemas/InternalError' - * 404: - * $ref: '#/components/schemas/NotFoundError' - */ - async getProduct(request: Request, response: Response) { - const result = validationResult(request); - // handle error - if (!result.isEmpty()) { - return response.status(StatusCodes.BAD_REQUEST).json({ - error: result.array().pop()?.msg - } satisfies ProductGetUnsuccessfulResponseBody); - } - // Get query parameters - const prices = request.query.prices === 'false' ? false : true; - const productId = request.params.productId as string; - - try { - // Get the product - const product = await stripe.products.retrieve(productId) as ProductWithPrices; - - if (prices) { - const prices = await stripe.prices.list({ - product: product.id, - active: true, - }); - if (prices.data) { - product.prices = prices.data; - } - } - - return response.status(StatusCodes.OK).json({ - product: product - } satisfies ProductGetResponseBody); - } catch (error) { - - // define error + async listProducts(request: Request, response: Response) { + const result = validationResult(request); + // handle error + if (!result.isEmpty()) { + return response.status(StatusCodes.BAD_REQUEST).json({ + error: result.array().pop()?.msg, + } satisfies ProductListUnsuccessfulResponseBody); + } + // Get query parameters + const prices = request.query.prices === 'false' ? false : true; + + try { + const products = (await stripe.products.list({ + active: true, + })) as Stripe.ApiList; + + // If no products found return 404 + if (!products.data) { + return response.status(StatusCodes.NOT_FOUND).json({ + error: 'Seems like there no any active products on Stripe side. Please add some.', + } satisfies ProductListUnsuccessfulResponseBody); + } + + if (prices) { + for (const product of products.data) { + const prices = await stripe.prices.list({ + product: product.id, + active: true, + }); + product.prices = prices.data; + } + } + + return response.status(StatusCodes.OK).json({ + products: products, + } satisfies ProductListResponseBody); + } catch (error) { + return response.status(500).json({ + error: `Internal error: ${(error as Error)?.message || error}`, + } satisfies ProductListUnsuccessfulResponseBody); + } + } + + /** + * @openapi + * + * /admin/product/get/{productId}: + * get: + * summary: Get a product + * description: Get a product by id + * tags: [Product] + * parameters: + * - in: path + * name: productId + * schema: + * type: string + * description: The product id which identifies the product in Stripe + * required: true + * - in: query + * name: prices + * schema: + * type: boolean + * description: If setup to true - returns the product with prices inside. Default - true + * required: false + * responses: + * 200: + * description: A product + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/ProductGetResponseBody' + * 400: + * $ref: '#/components/schemas/InvalidRequest' + * 401: + * $ref: '#/components/schemas/UnauthorizedError' + * 500: + * $ref: '#/components/schemas/InternalError' + * 404: + * $ref: '#/components/schemas/NotFoundError' + */ + async getProduct(request: Request, response: Response) { + const result = validationResult(request); + // handle error + if (!result.isEmpty()) { + return response.status(StatusCodes.BAD_REQUEST).json({ + error: result.array().pop()?.msg, + } satisfies ProductGetUnsuccessfulResponseBody); + } + // Get query parameters + const prices = request.query.prices === 'false' ? false : true; + const productId = request.params.productId as string; + + try { + // Get the product + const product = (await stripe.products.retrieve(productId)) as ProductWithPrices; + + if (prices) { + const prices = await stripe.prices.list({ + product: product.id, + active: true, + }); + if (prices.data) { + product.prices = prices.data; + } + } + + return response.status(StatusCodes.OK).json({ + product: product, + } satisfies ProductGetResponseBody); + } catch (error) { + // define error const errorRef = error as Record; - if (errorRef?.statusCode === StatusCodes.NOT_FOUND) { - return response.status(StatusCodes.NOT_FOUND).json({ - error: `Product with id ${productId} not found` - } satisfies ProductGetUnsuccessfulResponseBody); - } - - return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ - error: `Internal error: ${(error as Error)?.message || error}` - } satisfies ProductGetUnsuccessfulResponseBody); - } - } -} \ No newline at end of file + if (errorRef?.statusCode === StatusCodes.NOT_FOUND) { + return response.status(StatusCodes.NOT_FOUND).json({ + error: `Product with id ${productId} not found`, + } satisfies ProductGetUnsuccessfulResponseBody); + } + + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: `Internal error: ${(error as Error)?.message || error}`, + } satisfies ProductGetUnsuccessfulResponseBody); + } + } +} diff --git a/src/controllers/admin/subscriptions.ts b/src/controllers/admin/subscriptions.ts index 35d8c204..fa8e11b7 100644 --- a/src/controllers/admin/subscriptions.ts +++ b/src/controllers/admin/subscriptions.ts @@ -1,7 +1,25 @@ import Stripe from 'stripe'; import type { Request, Response } from 'express'; import * as dotenv from 'dotenv'; -import type { SubscriptionCreateRequestBody, SubscriptionCreateResponseBody, SubscriptionCreateUnsuccessfulResponseBody, SubscriptionCancelResponseBody, SubscriptionCancelUnsuccessfulResponseBody, SubscriptionGetResponseBody, SubscriptionGetUnsuccessfulResponseBody, SubscriptionListResponseBody, SubscriptionListUnsuccessfulResponseBody, SubscriptionUpdateRequestBody, SubscriptionUpdateResponseBody, SubscriptionUpdateUnsuccessfulResponseBody, SubscriptionResumeUnsuccessfulResponseBody, SubscriptionResumeResponseBody, SubscriptionResumeRequestBody, SubscriptionCancelRequestBody, PaymentBehavior } from '../../types/portal.js'; +import type { + SubscriptionCreateRequestBody, + SubscriptionCreateResponseBody, + SubscriptionCreateUnsuccessfulResponseBody, + SubscriptionCancelResponseBody, + SubscriptionCancelUnsuccessfulResponseBody, + SubscriptionGetResponseBody, + SubscriptionGetUnsuccessfulResponseBody, + SubscriptionListResponseBody, + SubscriptionListUnsuccessfulResponseBody, + SubscriptionUpdateRequestBody, + SubscriptionUpdateResponseBody, + SubscriptionUpdateUnsuccessfulResponseBody, + SubscriptionResumeUnsuccessfulResponseBody, + SubscriptionResumeResponseBody, + SubscriptionResumeRequestBody, + SubscriptionCancelRequestBody, + PaymentBehavior, +} from '../../types/portal.js'; import { StatusCodes } from 'http-status-codes'; import { validationResult } from '../validator/index.js'; import { check } from 'express-validator'; @@ -9,116 +27,84 @@ import { SubscriptionService } from '../../services/admin/subscription.js'; dotenv.config(); - const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); export class SubscriptionController { + static subscriptionCreateValidator = [ + check('customerId').exists().withMessage('customerId was not provided').bail(), + check('items') + .exists() + .withMessage('items was not provided') + .bail() + .isArray() + .withMessage('items should be an array') + .bail(), + check('items.*.price') + .exists() + .withMessage('price was not provided') + .bail() + .isString() + .withMessage('price should be a string') + .bail(), + check('idempotencyKey').optional().isString().withMessage('idempotencyKey should be a string').bail(), + ]; - static subscriptionCreateValidator = [ - check('customerId') - .exists() - .withMessage('customerId was not provided') - .bail(), - check('items') - .exists() - .withMessage('items was not provided') - .bail() - .isArray() - .withMessage('items should be an array') - .bail(), - check('items.*.price') - .exists() - .withMessage('price was not provided') - .bail() - .isString() - .withMessage('price should be a string') - .bail(), - check('idempotencyKey') - .optional() - .isString() - .withMessage('idempotencyKey should be a string') - .bail(), - ]; - - static subscriptionUpdateValidator = [ - check('subscriptionId') - .exists() - .withMessage('subscriptionId was not provided') - .bail(), - check('updateParams') - .exists() - .withMessage('updateParams was not provided') - .bail(), - check('idempotencyKey') - .optional() - .isString() - .withMessage('idempotencyKey should be a string') - .bail(), - ]; + static subscriptionUpdateValidator = [ + check('subscriptionId').exists().withMessage('subscriptionId was not provided').bail(), + check('updateParams').exists().withMessage('updateParams was not provided').bail(), + check('idempotencyKey').optional().isString().withMessage('idempotencyKey should be a string').bail(), + ]; - static subscriptionGetValidator = [ - check('subscriptionId') - .exists() - .withMessage('subscriptionId was not provided') - .bail() - .isString() - .withMessage('subscriptionId should be a string') - .bail(), - ]; + static subscriptionGetValidator = [ + check('subscriptionId') + .exists() + .withMessage('subscriptionId was not provided') + .bail() + .isString() + .withMessage('subscriptionId should be a string') + .bail(), + ]; - static subscriptionListValidator = [ - check('customerId') - .optional() - .isString() - .withMessage('customerId should be a string') - .bail(), - ]; + static subscriptionListValidator = [ + check('customerId').optional().isString().withMessage('customerId should be a string').bail(), + ]; - static subscriptionCancelValidator = [ - check('subscriptionId') - .exists() - .withMessage('subscriptionId was not provided') - .bail() - .isString() - .withMessage('subscriptionId should be a string') - .bail(), - check('idempotencyKey') - .optional() - .isString() - .withMessage('idempotencyKey should be a string') - .bail(), - ]; + static subscriptionCancelValidator = [ + check('subscriptionId') + .exists() + .withMessage('subscriptionId was not provided') + .bail() + .isString() + .withMessage('subscriptionId should be a string') + .bail(), + check('idempotencyKey').optional().isString().withMessage('idempotencyKey should be a string').bail(), + ]; - static subscriptionResumeValidator = [ - check('subscriptionId') - .exists() - .withMessage('subscriptionId was not provided') - .bail() - .isString() - .withMessage('subscriptionId should be a string') - .bail(), - check('idempotencyKey') - .optional() - .isString() - .withMessage('idempotencyKey should be a string') - .bail(), - ]; + static subscriptionResumeValidator = [ + check('subscriptionId') + .exists() + .withMessage('subscriptionId was not provided') + .bail() + .isString() + .withMessage('subscriptionId should be a string') + .bail(), + check('idempotencyKey').optional().isString().withMessage('idempotencyKey should be a string').bail(), + ]; - - /** - * @openapi - * - * /admin/subscription/create: - * post: - * summary: Create a subscription - * description: Creates a new subscription for an existing customer - * tags: [Subscription] + /** + * @openapi + * + * /admin/subscription/create: + * post: + * summary: Create a subscription + * description: Creates a new subscription for an existing customer + * tags: [Subscription] * requestBody: * content: * application/json: * schema: * $ref: '#/components/schemas/SubscriptionCreateRequestBody' - * responses: + * responses: * 201: * description: The request was successful. * content: @@ -131,346 +117,339 @@ export class SubscriptionController { * $ref: '#/components/schemas/UnauthorizedError' * 500: * $ref: '#/components/schemas/InternalError' - */ - async create(request: Request, response: Response) { - // Validate request - const result = validationResult(request); - if (!result.isEmpty()) { - return response.status(StatusCodes.BAD_REQUEST).json({ - error: result.array().pop()?.msg - } satisfies SubscriptionCreateUnsuccessfulResponseBody); - } + */ + async create(request: Request, response: Response) { + // Validate request + const result = validationResult(request); + if (!result.isEmpty()) { + return response.status(StatusCodes.BAD_REQUEST).json({ + error: result.array().pop()?.msg, + } satisfies SubscriptionCreateUnsuccessfulResponseBody); + } - const { items, idempotencyKey } = request.body satisfies SubscriptionCreateRequestBody; - try { - // Create the subscription - const subscription = await stripe.subscriptions.create({ - customer: response.locals.customer.stripeCustomerId, - items: items, - payment_behavior: "default_incomplete" as PaymentBehavior, - }, - { - idempotencyKey: idempotencyKey, - }); - if (subscription.lastResponse?.statusCode !== StatusCodes.OK) { - return response.status(StatusCodes.BAD_GATEWAY).json({ - error: `Subscription was not created`, - } satisfies SubscriptionCreateUnsuccessfulResponseBody); - } + const { items, idempotencyKey } = request.body satisfies SubscriptionCreateRequestBody; + try { + // Create the subscription + const subscription = await stripe.subscriptions.create( + { + customer: response.locals.customer.stripeCustomerId, + items: items, + payment_behavior: 'default_incomplete' as PaymentBehavior, + }, + { + idempotencyKey: idempotencyKey, + } + ); + if (subscription.lastResponse?.statusCode !== StatusCodes.OK) { + return response.status(StatusCodes.BAD_GATEWAY).json({ + error: `Subscription was not created`, + } satisfies SubscriptionCreateUnsuccessfulResponseBody); + } - return response.status(StatusCodes.CREATED).json({ - subscription: subscription - } satisfies SubscriptionCreateResponseBody ); - } catch (error) { - return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ - error: `Internal error: ${(error as Error)?.message || error}` - } satisfies SubscriptionCreateUnsuccessfulResponseBody); - } - } + return response.status(StatusCodes.CREATED).json({ + subscription: subscription, + } satisfies SubscriptionCreateResponseBody); + } catch (error) { + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: `Internal error: ${(error as Error)?.message || error}`, + } satisfies SubscriptionCreateUnsuccessfulResponseBody); + } + } - /** - * @openapi - * - * /admin/subscription/update: - * post: - * summary: Update a subscription - * description: Updates an existing subscription - * tags: [Subscription] - * requestBody: - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/SubscriptionUpdateRequestBody' - * responses: - * 200: - * description: The request was successful. - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/SubscriptionUpdateResponseBody' + /** + * @openapi + * + * /admin/subscription/update: + * post: + * summary: Update a subscription + * description: Updates an existing subscription + * tags: [Subscription] + * requestBody: + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/SubscriptionUpdateRequestBody' + * responses: + * 200: + * description: The request was successful. + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/SubscriptionUpdateResponseBody' * 400: * $ref: '#/components/schemas/InvalidRequest' * 401: * $ref: '#/components/schemas/UnauthorizedError' * 500: * $ref: '#/components/schemas/InternalError' - */ - async update(request: Request, response: Response) { - // Validate request - const result = validationResult(request); - if (!result.isEmpty()) { - return response.status(StatusCodes.BAD_REQUEST).json({ - error: result.array().pop()?.msg - } satisfies SubscriptionUpdateUnsuccessfulResponseBody); - } - - const { subscriptionId, updateParams, idempotencyKey} = request.body satisfies SubscriptionUpdateRequestBody; - try { - // Update the subscription - const subscription = await stripe.subscriptions.update( - subscriptionId, - updateParams, - { - idempotencyKey: idempotencyKey, - }); - if (subscription.lastResponse?.statusCode !== StatusCodes.OK) { - return response.status(StatusCodes.BAD_GATEWAY).json({ - error: `Subscription was not updated`, - } satisfies SubscriptionUpdateUnsuccessfulResponseBody); - } - return response.status(StatusCodes.OK).json({ - subscription: subscription - } satisfies SubscriptionUpdateResponseBody); - - } catch (error) { - return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ - error: `Internal error: ${(error as Error)?.message || error}` - } satisfies SubscriptionUpdateUnsuccessfulResponseBody); - } - } + */ + async update(request: Request, response: Response) { + // Validate request + const result = validationResult(request); + if (!result.isEmpty()) { + return response.status(StatusCodes.BAD_REQUEST).json({ + error: result.array().pop()?.msg, + } satisfies SubscriptionUpdateUnsuccessfulResponseBody); + } - /** - * @openapi - * - * /admin/subscription/list: - * get: - * summary: Get a list of subscriptions - * description: Get a list of subscriptions - * tags: [Subscription] - * responses: - * 200: - * description: A list of subscriptions - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/SubscriptionListResponseBody' - * 400: - * $ref: '#/components/schemas/InvalidRequest' - * 401: - * $ref: '#/components/schemas/UnauthorizedError' - * 500: - * $ref: '#/components/schemas/InternalError' - * 404: - * $ref: '#/components/schemas/NotFoundError' - */ + const { subscriptionId, updateParams, idempotencyKey } = request.body satisfies SubscriptionUpdateRequestBody; + try { + // Update the subscription + const subscription = await stripe.subscriptions.update(subscriptionId, updateParams, { + idempotencyKey: idempotencyKey, + }); + if (subscription.lastResponse?.statusCode !== StatusCodes.OK) { + return response.status(StatusCodes.BAD_GATEWAY).json({ + error: `Subscription was not updated`, + } satisfies SubscriptionUpdateUnsuccessfulResponseBody); + } + return response.status(StatusCodes.OK).json({ + subscription: subscription, + } satisfies SubscriptionUpdateResponseBody); + } catch (error) { + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: `Internal error: ${(error as Error)?.message || error}`, + } satisfies SubscriptionUpdateUnsuccessfulResponseBody); + } + } - public async list(request: Request, response: Response) { - // Validate request - const result = validationResult(request); - if (!result.isEmpty()) { - return response.status(StatusCodes.BAD_REQUEST).json({ - error: result.array().pop()?.msg - } satisfies SubscriptionListUnsuccessfulResponseBody); - } - const customerId = response.locals.customer.stripeCustomerId; - try { - // Sync our DB with Stripe - await SubscriptionService.instance.stripeSync(response.locals.customer) - // Get the subscriptions - const subscriptions = customerId - ? await stripe.subscriptions.list({ - customer: customerId as string, - }) - : await stripe.subscriptions.list(); + /** + * @openapi + * + * /admin/subscription/list: + * get: + * summary: Get a list of subscriptions + * description: Get a list of subscriptions + * tags: [Subscription] + * responses: + * 200: + * description: A list of subscriptions + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/SubscriptionListResponseBody' + * 400: + * $ref: '#/components/schemas/InvalidRequest' + * 401: + * $ref: '#/components/schemas/UnauthorizedError' + * 500: + * $ref: '#/components/schemas/InternalError' + * 404: + * $ref: '#/components/schemas/NotFoundError' + */ - if (subscriptions.lastResponse?.statusCode !== StatusCodes.OK) { - return response.status(StatusCodes.NOT_FOUND).json({ - error: `Subscriptions were not found`, - } satisfies SubscriptionListUnsuccessfulResponseBody); - } - return response.status(StatusCodes.OK).json({ - subscriptions: subscriptions - } satisfies SubscriptionListResponseBody); - } catch (error) { - return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ - error: `Internal error: ${(error as Error)?.message || error}` - } satisfies SubscriptionListUnsuccessfulResponseBody); - } - } + public async list(request: Request, response: Response) { + // Validate request + const result = validationResult(request); + if (!result.isEmpty()) { + return response.status(StatusCodes.BAD_REQUEST).json({ + error: result.array().pop()?.msg, + } satisfies SubscriptionListUnsuccessfulResponseBody); + } + const customerId = response.locals.customer.stripeCustomerId; + try { + // Sync our DB with Stripe + await SubscriptionService.instance.stripeSync(response.locals.customer); + // Get the subscriptions + const subscriptions = customerId + ? await stripe.subscriptions.list({ + customer: customerId as string, + }) + : await stripe.subscriptions.list(); + if (subscriptions.lastResponse?.statusCode !== StatusCodes.OK) { + return response.status(StatusCodes.NOT_FOUND).json({ + error: `Subscriptions were not found`, + } satisfies SubscriptionListUnsuccessfulResponseBody); + } + return response.status(StatusCodes.OK).json({ + subscriptions: subscriptions, + } satisfies SubscriptionListResponseBody); + } catch (error) { + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: `Internal error: ${(error as Error)?.message || error}`, + } satisfies SubscriptionListUnsuccessfulResponseBody); + } + } - /** - * @openapi - * - * /admin/subscription/get/{subscriptionId}: - * get: - * summary: Get a subscription - * description: Get a subscription - * tags: [Subscription] - * parameters: - * - in: path - * name: subscriptionId - * schema: - * type: string - * description: The subscription id - * required: true - * responses: - * 200: - * description: The request was successful. - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/SubscriptionGetResponseBody' - * 400: - * $ref: '#/components/schemas/InvalidRequest' - * 401: - * $ref: '#/components/schemas/UnauthorizedError' - * 500: - * $ref: '#/components/schemas/InternalError' - * 404: - * $ref: '#/components/schemas/NotFoundError' - */ - async get(request: Request, response: Response) { - // Validate request - const result = validationResult(request); - if (!result.isEmpty()) { - return response.status(StatusCodes.BAD_REQUEST).json({ - error: result.array().pop()?.msg - } satisfies SubscriptionGetUnsuccessfulResponseBody); - } - const subscriptionId = request.params.subscriptionId; - try { - // Sync our DB with Stripe - await SubscriptionService.instance.stripeSync(response.locals.customer) - // Get the subscription - const subscription = await stripe.subscriptions.retrieve(subscriptionId as string); - if (subscription.lastResponse?.statusCode !== StatusCodes.OK) { - return response.status(StatusCodes.NOT_FOUND).json({ - error: `Subscription was not found`, - } satisfies SubscriptionGetUnsuccessfulResponseBody); - } - return response.status(StatusCodes.OK).json({ - subscription: subscription - } satisfies SubscriptionGetResponseBody); - } catch (error) { - return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ - error: `Internal error: ${(error as Error)?.message || error}` - } satisfies SubscriptionGetUnsuccessfulResponseBody); - } - } + /** + * @openapi + * + * /admin/subscription/get/{subscriptionId}: + * get: + * summary: Get a subscription + * description: Get a subscription + * tags: [Subscription] + * parameters: + * - in: path + * name: subscriptionId + * schema: + * type: string + * description: The subscription id + * required: true + * responses: + * 200: + * description: The request was successful. + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/SubscriptionGetResponseBody' + * 400: + * $ref: '#/components/schemas/InvalidRequest' + * 401: + * $ref: '#/components/schemas/UnauthorizedError' + * 500: + * $ref: '#/components/schemas/InternalError' + * 404: + * $ref: '#/components/schemas/NotFoundError' + */ + async get(request: Request, response: Response) { + // Validate request + const result = validationResult(request); + if (!result.isEmpty()) { + return response.status(StatusCodes.BAD_REQUEST).json({ + error: result.array().pop()?.msg, + } satisfies SubscriptionGetUnsuccessfulResponseBody); + } + const subscriptionId = request.params.subscriptionId; + try { + // Sync our DB with Stripe + await SubscriptionService.instance.stripeSync(response.locals.customer); + // Get the subscription + const subscription = await stripe.subscriptions.retrieve(subscriptionId as string); + if (subscription.lastResponse?.statusCode !== StatusCodes.OK) { + return response.status(StatusCodes.NOT_FOUND).json({ + error: `Subscription was not found`, + } satisfies SubscriptionGetUnsuccessfulResponseBody); + } + return response.status(StatusCodes.OK).json({ + subscription: subscription, + } satisfies SubscriptionGetResponseBody); + } catch (error) { + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: `Internal error: ${(error as Error)?.message || error}`, + } satisfies SubscriptionGetUnsuccessfulResponseBody); + } + } - /** - * @openapi - * - * /admin/subscription/cancel: - * post: - * summary: Cancel a subscription - * description: Cancels an existing subscription - * tags: [Subscription] - * requestBody: - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/SubscriptionCancelRequestBody' - * responses: - * 200: - * description: The request was successful. - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/SubscriptionCancelResponseBody' - * 400: - * $ref: '#/components/schemas/InvalidRequest' - * 401: - * $ref: '#/components/schemas/UnauthorizedError' - * 500: - * $ref: '#/components/schemas/InternalError' - * 404: - * $ref: '#/components/schemas/NotFoundError' - */ - async cancel(request: Request, response: Response) { - // Validate request - const result = validationResult(request); - if (!result.isEmpty()) { - return response.status(StatusCodes.BAD_REQUEST).json({ - error: result.array().pop()?.msg - } satisfies SubscriptionCancelUnsuccessfulResponseBody); - } - const {subscriptionId, idempotencyKey } = request.body satisfies SubscriptionCancelRequestBody; + /** + * @openapi + * + * /admin/subscription/cancel: + * post: + * summary: Cancel a subscription + * description: Cancels an existing subscription + * tags: [Subscription] + * requestBody: + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/SubscriptionCancelRequestBody' + * responses: + * 200: + * description: The request was successful. + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/SubscriptionCancelResponseBody' + * 400: + * $ref: '#/components/schemas/InvalidRequest' + * 401: + * $ref: '#/components/schemas/UnauthorizedError' + * 500: + * $ref: '#/components/schemas/InternalError' + * 404: + * $ref: '#/components/schemas/NotFoundError' + */ + async cancel(request: Request, response: Response) { + // Validate request + const result = validationResult(request); + if (!result.isEmpty()) { + return response.status(StatusCodes.BAD_REQUEST).json({ + error: result.array().pop()?.msg, + } satisfies SubscriptionCancelUnsuccessfulResponseBody); + } + const { subscriptionId, idempotencyKey } = request.body satisfies SubscriptionCancelRequestBody; - try { - // Cancel the subscription - const subscription = await stripe.subscriptions.cancel( - subscriptionId as string, - { - idempotencyKey: idempotencyKey - }); + try { + // Cancel the subscription + const subscription = await stripe.subscriptions.cancel(subscriptionId as string, { + idempotencyKey: idempotencyKey, + }); - // Check if the subscription was cancelled - if (subscription.lastResponse?.statusCode !== StatusCodes.OK) { - return response.status(StatusCodes.BAD_GATEWAY).json({ - error: `Subscription was not deleted`, - } satisfies SubscriptionCancelUnsuccessfulResponseBody); - } - return response.status(StatusCodes.OK).json({ - subscription: subscription - } satisfies SubscriptionCancelResponseBody); - } catch (error) { - return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ - error: `Internal error: ${(error as Error)?.message || error}` - } satisfies SubscriptionCancelUnsuccessfulResponseBody); - } - } + // Check if the subscription was cancelled + if (subscription.lastResponse?.statusCode !== StatusCodes.OK) { + return response.status(StatusCodes.BAD_GATEWAY).json({ + error: `Subscription was not deleted`, + } satisfies SubscriptionCancelUnsuccessfulResponseBody); + } + return response.status(StatusCodes.OK).json({ + subscription: subscription, + } satisfies SubscriptionCancelResponseBody); + } catch (error) { + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: `Internal error: ${(error as Error)?.message || error}`, + } satisfies SubscriptionCancelUnsuccessfulResponseBody); + } + } - /** - * @openapi - * - * /admin/subscription/resume: - * post: - * summary: Resume a subscription - * description: Resumes an existing subscription - * tags: [Subscription] - * requestBody: - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/SubscriptionResumeRequestBody' - * responses: - * 200: - * description: The request was successful. - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/SubscriptionResumeResponseBody' - * 400: - * $ref: '#/components/schemas/InvalidRequest' - * 401: - * $ref: '#/components/schemas/UnauthorizedError' - * 500: - * $ref: '#/components/schemas/InternalError' - * 404: - * $ref: '#/components/schemas/NotFoundError' - */ - async resume(request: Request, response: Response) { - // Validate request - const result = validationResult(request); - if (!result.isEmpty()) { - return response.status(StatusCodes.BAD_REQUEST).json({ - error: result.array().pop()?.msg - } satisfies SubscriptionResumeUnsuccessfulResponseBody); - } - const { subscriptionId, idempotencyKey } = request.body satisfies SubscriptionResumeRequestBody; - try { - // Resume the subscription - const subscription = await stripe.subscriptions.resume( - subscriptionId as string, - { - idempotencyKey: idempotencyKey - }); + /** + * @openapi + * + * /admin/subscription/resume: + * post: + * summary: Resume a subscription + * description: Resumes an existing subscription + * tags: [Subscription] + * requestBody: + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/SubscriptionResumeRequestBody' + * responses: + * 200: + * description: The request was successful. + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/SubscriptionResumeResponseBody' + * 400: + * $ref: '#/components/schemas/InvalidRequest' + * 401: + * $ref: '#/components/schemas/UnauthorizedError' + * 500: + * $ref: '#/components/schemas/InternalError' + * 404: + * $ref: '#/components/schemas/NotFoundError' + */ + async resume(request: Request, response: Response) { + // Validate request + const result = validationResult(request); + if (!result.isEmpty()) { + return response.status(StatusCodes.BAD_REQUEST).json({ + error: result.array().pop()?.msg, + } satisfies SubscriptionResumeUnsuccessfulResponseBody); + } + const { subscriptionId, idempotencyKey } = request.body satisfies SubscriptionResumeRequestBody; + try { + // Resume the subscription + const subscription = await stripe.subscriptions.resume(subscriptionId as string, { + idempotencyKey: idempotencyKey, + }); - // Check if the subscription was resumed - if (subscription.lastResponse?.statusCode !== StatusCodes.OK) { - return response.status(StatusCodes.BAD_GATEWAY).json({ - error: `Subscription was not resumed`, - } satisfies SubscriptionResumeUnsuccessfulResponseBody); - } - return response.status(StatusCodes.OK).json({ - subscription: subscription - } satisfies SubscriptionResumeResponseBody); - } catch (error) { - return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ - error: `Internal error: ${(error as Error)?.message || error}` - } satisfies SubscriptionResumeUnsuccessfulResponseBody); - } - } -} \ No newline at end of file + // Check if the subscription was resumed + if (subscription.lastResponse?.statusCode !== StatusCodes.OK) { + return response.status(StatusCodes.BAD_GATEWAY).json({ + error: `Subscription was not resumed`, + } satisfies SubscriptionResumeUnsuccessfulResponseBody); + } + return response.status(StatusCodes.OK).json({ + subscription: subscription, + } satisfies SubscriptionResumeResponseBody); + } catch (error) { + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: `Internal error: ${(error as Error)?.message || error}`, + } satisfies SubscriptionResumeUnsuccessfulResponseBody); + } + } +} diff --git a/src/controllers/admin/webhook.ts b/src/controllers/admin/webhook.ts index 14debffb..29363b80 100644 --- a/src/controllers/admin/webhook.ts +++ b/src/controllers/admin/webhook.ts @@ -11,111 +11,123 @@ dotenv.config(); const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); export class WebhookController { - public async handleWebhook(request: Request, response: Response) { - let event = request.body; - let subscription; - let status; - const builSubmitOperation = ( function(subscription: Stripe.Subscription, name: string) { - return { - operation: name, - data: { - subscriptionId: subscription.id, - stripeCustomerId: subscription.customer as string, - status: subscription.status, - currentPeriodStart: new Date(subscription.current_period_start * 1000), - currentPeriodEnd: new Date(subscription.current_period_end * 1000), - trialStart: subscription.trial_start ? new Date(subscription.trial_start * 1000) : undefined, - trialEnd: subscription.trial_end ? new Date(subscription.trial_end * 1000) : undefined, - } satisfies ISubmitData, - } satisfies ISubmitOperation; - }) - // Only verify the event if you have an endpoint secret defined. - // Otherwise use the basic event deserialized with JSON.parse - // Get the signature sent by Stripe + public async handleWebhook(request: Request, response: Response) { + let event = request.body; + let subscription; + let status; + const builSubmitOperation = function (subscription: Stripe.Subscription, name: string) { + return { + operation: name, + data: { + subscriptionId: subscription.id, + stripeCustomerId: subscription.customer as string, + status: subscription.status, + currentPeriodStart: new Date(subscription.current_period_start * 1000), + currentPeriodEnd: new Date(subscription.current_period_end * 1000), + trialStart: subscription.trial_start ? new Date(subscription.trial_start * 1000) : undefined, + trialEnd: subscription.trial_end ? new Date(subscription.trial_end * 1000) : undefined, + } satisfies ISubmitData, + } satisfies ISubmitOperation; + }; + // Only verify the event if you have an endpoint secret defined. + // Otherwise use the basic event deserialized with JSON.parse + // Get the signature sent by Stripe - if (!process.env.STRIPE_WEBHOOK_SECRET) { - await eventTracker.notify({ - message: 'Stripe webhook secret not found. Webhook ID: ${request.body.id}.', - severity: 'error', - } satisfies INotifyMessage) - return response.sendStatus(StatusCodes.BAD_REQUEST); - } + if (!process.env.STRIPE_WEBHOOK_SECRET) { + await eventTracker.notify({ + message: 'Stripe webhook secret not found. Webhook ID: ${request.body.id}.', + severity: 'error', + } satisfies INotifyMessage); + return response.sendStatus(StatusCodes.BAD_REQUEST); + } - const signature = request.headers['stripe-signature']; - if (!signature) { - await eventTracker.notify({ - message: 'Webhook signature not found. Webhook ID: ${request.body.id}.', - severity: 'error', - } satisfies INotifyMessage) - return response.sendStatus(StatusCodes.BAD_REQUEST); - } + const signature = request.headers['stripe-signature']; + if (!signature) { + await eventTracker.notify({ + message: 'Webhook signature not found. Webhook ID: ${request.body.id}.', + severity: 'error', + } satisfies INotifyMessage); + return response.sendStatus(StatusCodes.BAD_REQUEST); + } - try { - event = stripe.webhooks.constructEvent( - request.rawBody, - signature, - process.env.STRIPE_WEBHOOK_SECRET - ); - } catch (err) { - - await eventTracker.notify({ - message: `Webhook signature verification failed. Webhook ID: ${request.body.id}. Error: ${(err as Record)?.message || err}`, - severity: 'error', - } satisfies INotifyMessage) - return response.sendStatus(StatusCodes.BAD_REQUEST); - } - // Handle the event - switch (event.type) { - case 'customer.subscription.trial_will_end': - subscription = event.data.object; - status = subscription.status; - await eventTracker.notify({ - message: EventTracker.compileBasicNotification(`Subscription status is ${status} for subscription with id: ${subscription.id}`, 'Stripe Webhook: customer.subscription.trial_will_end'), - severity: 'info', - } satisfies INotifyMessage) - await eventTracker.submit(builSubmitOperation(subscription, OperationNameEnum.SUBSCRIPTION_TRIAL_WILL_END)); - break; - case 'customer.subscription.deleted': - subscription = event.data.object; - status = subscription.status; - await eventTracker.notify({ - message: EventTracker.compileBasicNotification(`Subscription status is ${status} for subscription with id: ${subscription.id}`, 'Stripe Webhook: customer.subscription.deleted'), - severity: 'info', - } satisfies INotifyMessage) - await eventTracker.submit(builSubmitOperation(subscription, OperationNameEnum.SUBSCRIPTION_CANCEL)); - // Then define and call a method to handle the subscription deleted. - // handleSubscriptionDeleted(subscriptionDeleted); - break; - case 'customer.subscription.created': - subscription = event.data.object; - status = subscription.status; - await eventTracker.notify({ - message: EventTracker.compileBasicNotification(`Subscription status is ${status} for subscription with id: ${subscription.id}`, 'Stripe Webhook: customer.subscription.created'), - severity: 'info', - } satisfies INotifyMessage) - await eventTracker.submit(builSubmitOperation(subscription, OperationNameEnum.SUBSCRIPTION_CREATE)); - // Then define and call a method to handle the subscription created. - // handleSubscriptionCreated(subscription); - break; - case 'customer.subscription.updated': - subscription = event.data.object; - status = subscription.status; - await eventTracker.notify({ - message: EventTracker.compileBasicNotification(`Subscription status is ${status} for subscription with id: ${subscription.id}`, 'Stripe Webhook: customer.subscription.updated'), - severity: 'info', - } satisfies INotifyMessage) - await eventTracker.submit(builSubmitOperation(subscription, OperationNameEnum.SUBSCRIPTION_UPDATE)); - // Then define and call a method to handle the subscription update. - // handleSubscriptionUpdated(subscription); - break; - default: - // Unexpected event type - eventTracker.notify({ - message: EventTracker.compileBasicNotification(`Unexpected event type: ${event.type}`, 'Stripe Webhook: unexpected'), - severity: 'error', - } satisfies INotifyMessage) - } - // Return a 200 response to acknowledge receipt of the event - return response.status(StatusCodes.OK).send(); - } -} \ No newline at end of file + try { + event = stripe.webhooks.constructEvent(request.rawBody, signature, process.env.STRIPE_WEBHOOK_SECRET); + } catch (err) { + await eventTracker.notify({ + message: `Webhook signature verification failed. Webhook ID: ${request.body.id}. Error: ${(err as Record)?.message || err}`, + severity: 'error', + } satisfies INotifyMessage); + return response.sendStatus(StatusCodes.BAD_REQUEST); + } + // Handle the event + switch (event.type) { + case 'customer.subscription.trial_will_end': + subscription = event.data.object; + status = subscription.status; + await eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `Subscription status is ${status} for subscription with id: ${subscription.id}`, + 'Stripe Webhook: customer.subscription.trial_will_end' + ), + severity: 'info', + } satisfies INotifyMessage); + await eventTracker.submit( + builSubmitOperation(subscription, OperationNameEnum.SUBSCRIPTION_TRIAL_WILL_END) + ); + break; + case 'customer.subscription.deleted': + subscription = event.data.object; + status = subscription.status; + await eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `Subscription status is ${status} for subscription with id: ${subscription.id}`, + 'Stripe Webhook: customer.subscription.deleted' + ), + severity: 'info', + } satisfies INotifyMessage); + await eventTracker.submit(builSubmitOperation(subscription, OperationNameEnum.SUBSCRIPTION_CANCEL)); + // Then define and call a method to handle the subscription deleted. + // handleSubscriptionDeleted(subscriptionDeleted); + break; + case 'customer.subscription.created': + subscription = event.data.object; + status = subscription.status; + await eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `Subscription status is ${status} for subscription with id: ${subscription.id}`, + 'Stripe Webhook: customer.subscription.created' + ), + severity: 'info', + } satisfies INotifyMessage); + await eventTracker.submit(builSubmitOperation(subscription, OperationNameEnum.SUBSCRIPTION_CREATE)); + // Then define and call a method to handle the subscription created. + // handleSubscriptionCreated(subscription); + break; + case 'customer.subscription.updated': + subscription = event.data.object; + status = subscription.status; + await eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `Subscription status is ${status} for subscription with id: ${subscription.id}`, + 'Stripe Webhook: customer.subscription.updated' + ), + severity: 'info', + } satisfies INotifyMessage); + await eventTracker.submit(builSubmitOperation(subscription, OperationNameEnum.SUBSCRIPTION_UPDATE)); + // Then define and call a method to handle the subscription update. + // handleSubscriptionUpdated(subscription); + break; + default: + // Unexpected event type + eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `Unexpected event type: ${event.type}`, + 'Stripe Webhook: unexpected' + ), + severity: 'error', + } satisfies INotifyMessage); + } + // Return a 200 response to acknowledge receipt of the event + return response.status(StatusCodes.OK).send(); + } +} diff --git a/src/controllers/api/account.ts b/src/controllers/api/account.ts index a9312916..1dbd19d2 100644 --- a/src/controllers/api/account.ts +++ b/src/controllers/api/account.ts @@ -312,7 +312,7 @@ export class AccountController { name: customer.name, customerId: customer.customerId, } satisfies ISubmitStripeCustomerCreateData, - } satisfies ISubmitOperation) + } satisfies ISubmitOperation); } return response.status(StatusCodes.OK).json({}); diff --git a/src/database/entities/subscription.entity.ts b/src/database/entities/subscription.entity.ts index 8c990994..5c2dd197 100644 --- a/src/database/entities/subscription.entity.ts +++ b/src/database/entities/subscription.entity.ts @@ -6,42 +6,42 @@ dotenv.config(); @Entity('subscription') export class SubscriptionEntity { - @Column({ - type: 'text', - nullable: false, - primary: true, - }) + @Column({ + type: 'text', + nullable: false, + primary: true, + }) subscriptionId!: string; - @Column({ - type: 'text', - nullable: false, - }) - status!: string; + @Column({ + type: 'text', + nullable: false, + }) + status!: string; - @Column({ - type: 'timestamptz', - nullable: false, - }) - currentPeriodStart!: Date; + @Column({ + type: 'timestamptz', + nullable: false, + }) + currentPeriodStart!: Date; - @Column({ - type: 'timestamptz', - nullable: false, - }) - currentPeriodEnd!: Date; + @Column({ + type: 'timestamptz', + nullable: false, + }) + currentPeriodEnd!: Date; - @Column({ - type: 'timestamptz', - nullable: true, - }) - trialStart!: Date; + @Column({ + type: 'timestamptz', + nullable: true, + }) + trialStart!: Date; - @Column({ - type: 'timestamptz', - nullable: true, - }) - trialEnd!: Date; + @Column({ + type: 'timestamptz', + nullable: true, + }) + trialEnd!: Date; @Column({ type: 'timestamptz', @@ -65,25 +65,25 @@ export class SubscriptionEntity { this.updatedAt = new Date(); } - @ManyToOne(() => CustomerEntity, (customer) => customer.customerId) - @JoinColumn({ name: 'customerId' }) - customer!: CustomerEntity; + @ManyToOne(() => CustomerEntity, (customer) => customer.customerId) + @JoinColumn({ name: 'customerId' }) + customer!: CustomerEntity; constructor( - subscriptionId: string, - customer: CustomerEntity, - status: string, - currentPeriodStart: Date, - currentPeriodEnd: Date, - trialStart?: Date, - trialEnd?: Date, - ){ + subscriptionId: string, + customer: CustomerEntity, + status: string, + currentPeriodStart: Date, + currentPeriodEnd: Date, + trialStart?: Date, + trialEnd?: Date + ) { this.subscriptionId = subscriptionId; - this.customer = customer; - this.status = status; - this.currentPeriodStart = currentPeriodStart; - this.currentPeriodEnd = currentPeriodEnd; - if (trialStart ) this.trialStart = trialStart; - if (trialEnd) this.trialEnd = trialEnd; + this.customer = customer; + this.status = status; + this.currentPeriodStart = currentPeriodStart; + this.currentPeriodEnd = currentPeriodEnd; + if (trialStart) this.trialStart = trialStart; + if (trialEnd) this.trialEnd = trialEnd; } } diff --git a/src/database/migrations/CreateSubscriptionTable.ts b/src/database/migrations/CreateSubscriptionTable.ts index e117ae37..fc55bc0f 100644 --- a/src/database/migrations/CreateSubscriptionTable.ts +++ b/src/database/migrations/CreateSubscriptionTable.ts @@ -1,22 +1,20 @@ -import { MigrationInterface, QueryRunner, Table, TableForeignKey } from "typeorm"; - +import { MigrationInterface, QueryRunner, Table, TableForeignKey } from 'typeorm'; export class CreateSubscritpionTable1695740346003 implements MigrationInterface { - - public async up(queryRunner: QueryRunner): Promise { + public async up(queryRunner: QueryRunner): Promise { const table = new Table({ name: 'subscription', columns: [ { name: 'subscriptionId', type: 'text', isNullable: false, isPrimary: true }, - { name: 'customerId', type: 'uuid', isNullable: false }, - { name: 'status', type: 'text', isNullable: false }, - { name: 'trialStart', type: 'timestamptz', isNullable: true }, - { name: 'trialEnd', type: 'timestamptz', isNullable: true }, - { name: 'currentPeriodStart', type: 'timestamptz', isNullable: false }, - { name: 'currentPeriodEnd', type: 'timestamptz', isNullable: false }, - { name: 'createdAt', type: 'timestamptz', isNullable: false }, - { name: 'updatedAt', type: 'timestamptz', isNullable: true }, - ], + { name: 'customerId', type: 'uuid', isNullable: false }, + { name: 'status', type: 'text', isNullable: false }, + { name: 'trialStart', type: 'timestamptz', isNullable: true }, + { name: 'trialEnd', type: 'timestamptz', isNullable: true }, + { name: 'currentPeriodStart', type: 'timestamptz', isNullable: false }, + { name: 'currentPeriodEnd', type: 'timestamptz', isNullable: false }, + { name: 'createdAt', type: 'timestamptz', isNullable: false }, + { name: 'updatedAt', type: 'timestamptz', isNullable: true }, + ], }); await queryRunner.createTable(table, true); @@ -29,10 +27,9 @@ export class CreateSubscritpionTable1695740346003 implements MigrationInterface onDelete: 'CASCADE', }) ); - - } + } public async down(queryRunner: QueryRunner): Promise { throw new Error('illegal_operation: cannot roll back initial migration'); } -} \ No newline at end of file +} diff --git a/src/database/types/enum.ts b/src/database/types/enum.ts index 8316c32a..92ff2180 100644 --- a/src/database/types/enum.ts +++ b/src/database/types/enum.ts @@ -8,7 +8,15 @@ export const categoryEnum = { SUBSCRIPTION: 'subscription', toStringList: function (): string[] { - return [this.DID, this.RESOURCE, this.CREDENTIAL, this.CREDENTIAL_STATUS, this.PRESENTATION, this.KEY, this.SUBSCRIPTION]; + return [ + this.DID, + this.RESOURCE, + this.CREDENTIAL, + this.CREDENTIAL_STATUS, + this.PRESENTATION, + this.KEY, + this.SUBSCRIPTION, + ]; }, }; diff --git a/src/middleware/auth/routes/admin/admin-auth.ts b/src/middleware/auth/routes/admin/admin-auth.ts index a7a243d8..6d7afcc9 100644 --- a/src/middleware/auth/routes/admin/admin-auth.ts +++ b/src/middleware/auth/routes/admin/admin-auth.ts @@ -6,22 +6,30 @@ export class AdminHandler extends BaseAuthHandler { constructor() { super(); // ToDo: define how to get namespace information - this.registerRoute('/admin/checkout/session/create', 'POST', 'admin:checkout:session:create:testnet', { skipNamespace: true}); - this.registerRoute('/admin/checkout/session/create', 'POST', 'admin:checkout:session:create:mainnet', { skipNamespace: true}); + this.registerRoute('/admin/checkout/session/create', 'POST', 'admin:checkout:session:create:testnet', { + skipNamespace: true, + }); + this.registerRoute('/admin/checkout/session/create', 'POST', 'admin:checkout:session:create:mainnet', { + skipNamespace: true, + }); // Subscriptions - this.registerRoute('/admin/subscription/list', 'GET', 'admin:subscription:list:testnet', { skipNamespace: true}); - this.registerRoute('/admin/subscription/list', 'GET', 'admin:subscription:list:mainnet', { skipNamespace: true}); - this.registerRoute('/admin/subscription/get', 'GET', 'admin:subscription:get:testnet', { skipNamespace: true}); - this.registerRoute('/admin/subscription/get', 'GET', 'admin:subscription:get:mainnet', { skipNamespace: true}); + this.registerRoute('/admin/subscription/list', 'GET', 'admin:subscription:list:testnet', { + skipNamespace: true, + }); + this.registerRoute('/admin/subscription/list', 'GET', 'admin:subscription:list:mainnet', { + skipNamespace: true, + }); + this.registerRoute('/admin/subscription/get', 'GET', 'admin:subscription:get:testnet', { skipNamespace: true }); + this.registerRoute('/admin/subscription/get', 'GET', 'admin:subscription:get:mainnet', { skipNamespace: true }); // Prices - this.registerRoute('/admin/price/list', 'GET', 'admin:price:list:testnet', { skipNamespace: true}); - this.registerRoute('/admin/price/list', 'GET', 'admin:price:list:mainnet', { skipNamespace: true}); + this.registerRoute('/admin/price/list', 'GET', 'admin:price:list:testnet', { skipNamespace: true }); + this.registerRoute('/admin/price/list', 'GET', 'admin:price:list:mainnet', { skipNamespace: true }); // Products - this.registerRoute('/admin/product/list', 'GET', 'admin:product:list:testnet', { skipNamespace: true}); - this.registerRoute('/admin/product/list', 'GET', 'admin:product:list:mainnet', { skipNamespace: true}); - this.registerRoute('/admin/product/get', 'GET', 'admin:product:get:testnet', { skipNamespace: true}); - this.registerRoute('/admin/product/get', 'GET', 'admin:product:get:mainnet', { skipNamespace: true}); + this.registerRoute('/admin/product/list', 'GET', 'admin:product:list:testnet', { skipNamespace: true }); + this.registerRoute('/admin/product/list', 'GET', 'admin:product:list:mainnet', { skipNamespace: true }); + this.registerRoute('/admin/product/get', 'GET', 'admin:product:get:testnet', { skipNamespace: true }); + this.registerRoute('/admin/product/get', 'GET', 'admin:product:get:mainnet', { skipNamespace: true }); } public async handle(request: Request, response: Response): Promise { if (!request.path.includes('/admin/')) { diff --git a/src/middleware/auth/user-info-fetcher/base.ts b/src/middleware/auth/user-info-fetcher/base.ts index 9cc7ca03..ad373936 100644 --- a/src/middleware/auth/user-info-fetcher/base.ts +++ b/src/middleware/auth/user-info-fetcher/base.ts @@ -2,7 +2,6 @@ import type { Request } from 'express'; import type { IAuthResponse } from '../../../types/authentication.js'; import type { IOAuthProvider } from '../oauth/base.js'; - export interface IUserInfoOptions { [key: string]: any; } diff --git a/src/middleware/auth/user-info-fetcher/portal-token.ts b/src/middleware/auth/user-info-fetcher/portal-token.ts index 08efa54c..a972cbfe 100644 --- a/src/middleware/auth/user-info-fetcher/portal-token.ts +++ b/src/middleware/auth/user-info-fetcher/portal-token.ts @@ -11,52 +11,54 @@ dotenv.config(); export class PortalUserInfoFetcher extends AuthReturn implements IUserInfoFetcher { private m2mToken: string; - private idToken + private idToken; constructor(m2mToken: string, idToken: string) { super(); this.m2mToken = m2mToken; - this.idToken = idToken; + this.idToken = idToken; } async fetchUserInfo(request: Request, oauthProvider: IOAuthProvider): Promise { // Get customerId from header - if (!this.idToken) { - return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: No idToken found in the header.`); - } + if (!this.idToken) { + return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: No idToken found in the header.`); + } - // Check the idToken, provided in header - const idTokenVerification = await this.verifyIdToken(oauthProvider); - if (idTokenVerification.error) { - return idTokenVerification; - } - // return this.returnOk(); + // Check the idToken, provided in header + const idTokenVerification = await this.verifyIdToken(oauthProvider); + if (idTokenVerification.error) { + return idTokenVerification; + } + // return this.returnOk(); return this.verifyM2MToken(oauthProvider); } - public async verifyIdToken(oauthProvider: IOAuthProvider): Promise { - try { - const { payload } = await jwtVerify( - this.idToken, // The raw Bearer Token extracted from the request header - createRemoteJWKSet(new URL(oauthProvider.endpoint_jwks)), // generate a jwks using jwks_uri inquired from Logto server - { - // expected issuer of the token, should be issued by the Logto server - issuer: oauthProvider.endpoint_issuer, - } - ); - // Setup the scopes from the token - if (!payload.sub) { - return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: No sub found in the token. Cannot set customerId.`); - } - this.setUserId(payload.sub); - return this.returnOk(); - } - catch (error) { - console.error(error); - return this.returnError(StatusCodes.INTERNAL_SERVER_ERROR, `Unexpected error: ${error}`); - } - } + public async verifyIdToken(oauthProvider: IOAuthProvider): Promise { + try { + const { payload } = await jwtVerify( + this.idToken, // The raw Bearer Token extracted from the request header + createRemoteJWKSet(new URL(oauthProvider.endpoint_jwks)), // generate a jwks using jwks_uri inquired from Logto server + { + // expected issuer of the token, should be issued by the Logto server + issuer: oauthProvider.endpoint_issuer, + } + ); + // Setup the scopes from the token + if (!payload.sub) { + return this.returnError( + StatusCodes.UNAUTHORIZED, + `Unauthorized error: No sub found in the token. Cannot set customerId.` + ); + } + this.setUserId(payload.sub); + return this.returnOk(); + } catch (error) { + console.error(error); + return this.returnError(StatusCodes.INTERNAL_SERVER_ERROR, `Unexpected error: ${error}`); + } + } public async verifyM2MToken(oauthProvider: IOAuthProvider): Promise { try { diff --git a/src/services/admin/subscription.ts b/src/services/admin/subscription.ts index 62daba14..5c585a2b 100644 --- a/src/services/admin/subscription.ts +++ b/src/services/admin/subscription.ts @@ -19,130 +19,141 @@ export class SubscriptionService { // Get rid of such code and move it to the builder public static instance = new SubscriptionService(); - constructor() { - this.subscriptionRepository = Connection.instance.dbConnection.getRepository(SubscriptionEntity); - } + constructor() { + this.subscriptionRepository = Connection.instance.dbConnection.getRepository(SubscriptionEntity); + } - public async create( - subscriptionId: string, - customer: CustomerEntity, - status: string, - currentPeriodStart: Date, - currentPeriodEnd: Date, - trialStart?: Date, - trialEnd?: Date, - ): Promise { - const subscriptionEntity = new SubscriptionEntity( - subscriptionId, - customer, - status, - currentPeriodStart, - currentPeriodEnd, - trialStart, - trialEnd, - ); - const res = await this.subscriptionRepository.insert(subscriptionEntity); - if (!res) throw new Error(`Cannot create a new subscription`); + public async create( + subscriptionId: string, + customer: CustomerEntity, + status: string, + currentPeriodStart: Date, + currentPeriodEnd: Date, + trialStart?: Date, + trialEnd?: Date + ): Promise { + const subscriptionEntity = new SubscriptionEntity( + subscriptionId, + customer, + status, + currentPeriodStart, + currentPeriodEnd, + trialStart, + trialEnd + ); + const res = await this.subscriptionRepository.insert(subscriptionEntity); + if (!res) throw new Error(`Cannot create a new subscription`); - return subscriptionEntity; - } - - public async update( - subscriptionId: string, - status?: string, - currentPeriodStart?: Date, - currentPeriodEnd?: Date, - trialStart?: Date, - trialEnd?: Date, - ) { - const existing = await this.subscriptionRepository.findOneBy({ subscriptionId }); - if (!existing) { - throw new Error(`Subscription with id ${subscriptionId} not found`); - } - if (status) existing.status = status; - if (currentPeriodStart) existing.currentPeriodStart = currentPeriodStart; - if (currentPeriodEnd) existing.currentPeriodEnd = currentPeriodEnd; - if (trialStart) existing.trialStart = trialStart; - if (trialEnd) existing.trialEnd = trialEnd; - return await this.subscriptionRepository.save(existing); - } + return subscriptionEntity; + } - public async get(subscriptionId?: string): Promise { - return await this.subscriptionRepository.findOne({ - where: { subscriptionId }, - relations: ['customer'], - }); - } + public async update( + subscriptionId: string, + status?: string, + currentPeriodStart?: Date, + currentPeriodEnd?: Date, + trialStart?: Date, + trialEnd?: Date + ) { + const existing = await this.subscriptionRepository.findOneBy({ subscriptionId }); + if (!existing) { + throw new Error(`Subscription with id ${subscriptionId} not found`); + } + if (status) existing.status = status; + if (currentPeriodStart) existing.currentPeriodStart = currentPeriodStart; + if (currentPeriodEnd) existing.currentPeriodEnd = currentPeriodEnd; + if (trialStart) existing.trialStart = trialStart; + if (trialEnd) existing.trialEnd = trialEnd; + return await this.subscriptionRepository.save(existing); + } - public async findOne(where: Record) { - return await this.subscriptionRepository.findOne({ - where: where, - relations: ['customer'], - }); - } + public async get(subscriptionId?: string): Promise { + return await this.subscriptionRepository.findOne({ + where: { subscriptionId }, + relations: ['customer'], + }); + } - public async stripeSync(customer?: CustomerEntity, user?: UserEntity): Promise { - let stripeCustomerId: string; - if (!customer && !user) { - throw new Error('StripeSync: customer or user is required'); - } - if (customer) { - stripeCustomerId = customer.stripeCustomerId; - } else { - stripeCustomerId = user?.customer.stripeCustomerId as string; - } + public async findOne(where: Record) { + return await this.subscriptionRepository.findOne({ + where: where, + relations: ['customer'], + }); + } - const subscriptions = await stripe.subscriptions.list({ customer: stripeCustomerId }); - // Get list of all subscription and sort them by created time to make sure that we are processing them in the correct order - for (const subscription of subscriptions.data.sort((a, b) => a.created - b.created)){ - const existing = await this.subscriptionRepository.findOne({ - where: { subscriptionId: subscription.id }, - }); - if (!existing) { - const customer = await CustomerService.instance.findbyStripeCustomerId(stripeCustomerId); - if (!customer) { - throw new Error(`Customer with stripeCustomerId ${stripeCustomerId} not found`); - } - const res = await this.create( - subscription.id, - customer, - subscription.status, - new Date(subscription.current_period_start * 1000), - new Date(subscription.current_period_end * 1000), - subscription.trial_start ? new Date(subscription.trial_start * 1000) : undefined, - subscription.trial_end ? new Date(subscription.trial_end * 1000) : undefined, - ); - if (!res) { - eventTracker.notify({ - message: EventTracker.compileBasicNotification(`Cannot create a new subscription with id ${subscription.id}`, 'Subscription syncronization'), - severity: 'error', - }); - } - eventTracker.notify({ - message: EventTracker.compileBasicNotification(`New subscription with id ${subscription.id} created`, 'Subscription syncronization'), - severity: 'info', - }); - } else { - const res = await this.update( - subscription.id, - subscription.status, - new Date(subscription.current_period_start * 1000), - new Date(subscription.current_period_end * 1000), - subscription.trial_start ? new Date(subscription.trial_start * 1000) : undefined, - subscription.trial_end ? new Date(subscription.trial_end * 1000) : undefined, - ); - if (!res) { - eventTracker.notify({ - message: EventTracker.compileBasicNotification(`Cannot update subscription with id ${subscription.id}`, 'Subscription syncronization'), - severity: 'error', - }); - } - eventTracker.notify({ - message: EventTracker.compileBasicNotification(`Subscription with id ${subscription.id} updated`, 'Subscription syncronization'), - severity: 'info', - }); - } - } + public async stripeSync(customer?: CustomerEntity, user?: UserEntity): Promise { + let stripeCustomerId: string; + if (!customer && !user) { + throw new Error('StripeSync: customer or user is required'); + } + if (customer) { + stripeCustomerId = customer.stripeCustomerId; + } else { + stripeCustomerId = user?.customer.stripeCustomerId as string; + } - } + const subscriptions = await stripe.subscriptions.list({ customer: stripeCustomerId }); + // Get list of all subscription and sort them by created time to make sure that we are processing them in the correct order + for (const subscription of subscriptions.data.sort((a, b) => a.created - b.created)) { + const existing = await this.subscriptionRepository.findOne({ + where: { subscriptionId: subscription.id }, + }); + if (!existing) { + const customer = await CustomerService.instance.findbyStripeCustomerId(stripeCustomerId); + if (!customer) { + throw new Error(`Customer with stripeCustomerId ${stripeCustomerId} not found`); + } + const res = await this.create( + subscription.id, + customer, + subscription.status, + new Date(subscription.current_period_start * 1000), + new Date(subscription.current_period_end * 1000), + subscription.trial_start ? new Date(subscription.trial_start * 1000) : undefined, + subscription.trial_end ? new Date(subscription.trial_end * 1000) : undefined + ); + if (!res) { + eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `Cannot create a new subscription with id ${subscription.id}`, + 'Subscription syncronization' + ), + severity: 'error', + }); + } + eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `New subscription with id ${subscription.id} created`, + 'Subscription syncronization' + ), + severity: 'info', + }); + } else { + const res = await this.update( + subscription.id, + subscription.status, + new Date(subscription.current_period_start * 1000), + new Date(subscription.current_period_end * 1000), + subscription.trial_start ? new Date(subscription.trial_start * 1000) : undefined, + subscription.trial_end ? new Date(subscription.trial_end * 1000) : undefined + ); + if (!res) { + eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `Cannot update subscription with id ${subscription.id}`, + 'Subscription syncronization' + ), + severity: 'error', + }); + } + eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `Subscription with id ${subscription.id} updated`, + 'Subscription syncronization' + ), + severity: 'info', + }); + } + } + } } diff --git a/src/services/api/customer.ts b/src/services/api/customer.ts index b33ab7b5..85376fef 100644 --- a/src/services/api/customer.ts +++ b/src/services/api/customer.ts @@ -81,7 +81,6 @@ export class CustomerService { return await this.customerRepository.findOne({ where: { stripeCustomerId }, }); - } public async isExist(where: Record) { diff --git a/src/services/track/admin/account-submitter.ts b/src/services/track/admin/account-submitter.ts index b6261ec1..29d7f5f3 100644 --- a/src/services/track/admin/account-submitter.ts +++ b/src/services/track/admin/account-submitter.ts @@ -1,60 +1,68 @@ -import Stripe from "stripe"; -import type { IObserver } from "../types.js"; -import { OperationNameEnum } from "../../../types/constants.js"; -import type { INotifyMessage } from "../../../types/track.js"; -import { EventTracker } from "../tracker.js"; -import { StatusCodes } from "http-status-codes"; -import { CustomerService } from "../../api/customer.js"; -import type { ISubmitOperation, ISubmitStripeCustomerCreateData } from "../submitter.js"; - +import Stripe from 'stripe'; +import type { IObserver } from '../types.js'; +import { OperationNameEnum } from '../../../types/constants.js'; +import type { INotifyMessage } from '../../../types/track.js'; +import { EventTracker } from '../tracker.js'; +import { StatusCodes } from 'http-status-codes'; +import { CustomerService } from '../../api/customer.js'; +import type { ISubmitOperation, ISubmitStripeCustomerCreateData } from '../submitter.js'; export class PortalAccountCreateSubmitter implements IObserver { - private emitter: EventEmitter; - private stripe: Stripe; + private emitter: EventEmitter; + private stripe: Stripe; - constructor(emitter: EventEmitter) { - this.emitter = emitter; - this.stripe = new Stripe(process.env.STRIPE_SECRET_KEY); - } + constructor(emitter: EventEmitter) { + this.emitter = emitter; + this.stripe = new Stripe(process.env.STRIPE_SECRET_KEY); + } - notify(notifyMessage: INotifyMessage): void { + notify(notifyMessage: INotifyMessage): void { this.emitter.emit('notify', notifyMessage); } - async update(operation: ISubmitOperation): Promise { - if (operation.operation === OperationNameEnum.STRIPE_ACCOUNT_CREATE) { - await this.submitStripeAccountCreate(operation); - } - } + async update(operation: ISubmitOperation): Promise { + if (operation.operation === OperationNameEnum.STRIPE_ACCOUNT_CREATE) { + await this.submitStripeAccountCreate(operation); + } + } - async submitStripeAccountCreate(operation: ISubmitOperation): Promise { - const data = operation.data as ISubmitStripeCustomerCreateData; + async submitStripeAccountCreate(operation: ISubmitOperation): Promise { + const data = operation.data as ISubmitStripeCustomerCreateData; - try { - // Create a new Stripe account - const account = await this.stripe.customers.create({ - name: data.name, - email: data.email, - }); - if (account.lastResponse.statusCode !== StatusCodes.OK) { - await this.notify({ - message: EventTracker.compileBasicNotification(`Failed to create Stripe account with name: ${data.name}.`, operation.operation), - severity: 'error', - } as INotifyMessage); - return; - } + try { + // Create a new Stripe account + const account = await this.stripe.customers.create({ + name: data.name, + email: data.email, + }); + if (account.lastResponse.statusCode !== StatusCodes.OK) { + await this.notify({ + message: EventTracker.compileBasicNotification( + `Failed to create Stripe account with name: ${data.name}.`, + operation.operation + ), + severity: 'error', + } as INotifyMessage); + return; + } - // Update the CaaS customer with the new Stripe account - await CustomerService.instance.update(data.customerId, undefined, account.id); - await this.notify({ - message: EventTracker.compileBasicNotification(`Stripe account created with name: ${data.name}.`, operation.operation), - severity: 'info', - } as INotifyMessage); - } catch (error) { - await this.notify({ - message: EventTracker.compileBasicNotification(`Failed to create Stripe account with name: ${data.name as string}.`, operation.operation), - severity: 'error', - } as INotifyMessage); - } - } + // Update the CaaS customer with the new Stripe account + await CustomerService.instance.update(data.customerId, undefined, account.id); + await this.notify({ + message: EventTracker.compileBasicNotification( + `Stripe account created with name: ${data.name}.`, + operation.operation + ), + severity: 'info', + } as INotifyMessage); + } catch (error) { + await this.notify({ + message: EventTracker.compileBasicNotification( + `Failed to create Stripe account with name: ${data.name as string}.`, + operation.operation + ), + severity: 'error', + } as INotifyMessage); + } + } } diff --git a/src/services/track/admin/subscription-submitter.ts b/src/services/track/admin/subscription-submitter.ts index d6f2144b..ccfbaf9d 100644 --- a/src/services/track/admin/subscription-submitter.ts +++ b/src/services/track/admin/subscription-submitter.ts @@ -1,161 +1,189 @@ -import { OperationNameEnum } from "../../../types/constants.js"; -import type { INotifyMessage } from "../../../types/track.js"; -import { SubscriptionService } from "../../admin/subscription.js"; -import { CustomerService } from "../../api/customer.js"; -import type { ISubmitOperation, ISubmitSubscriptionData } from "../submitter.js"; -import { EventTracker, eventTracker } from "../tracker.js"; -import type { IObserver } from "../types.js"; +import { OperationNameEnum } from '../../../types/constants.js'; +import type { INotifyMessage } from '../../../types/track.js'; +import { SubscriptionService } from '../../admin/subscription.js'; +import { CustomerService } from '../../api/customer.js'; +import type { ISubmitOperation, ISubmitSubscriptionData } from '../submitter.js'; +import { EventTracker, eventTracker } from '../tracker.js'; +import type { IObserver } from '../types.js'; //eslint-disable-next-line function isPromise(object: any): object is Promise { - return object && Promise.resolve(object) === object; - } + return object && Promise.resolve(object) === object; +} export const eventDecorator = () => { - return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => { - const { value } = descriptor; - //eslint-disable-next-line - descriptor.value = async (...args: any) => { - try { - const response = value.apply(target, args); - return isPromise(response) ? await response : Promise.resolve(response); - } catch (error) { - eventTracker.notify({ - message: EventTracker.compileBasicNotification(`Error while calling function: ${propertyKey}: ${(error as Record)?.message || error}`), - severity: 'error', - } satisfies INotifyMessage); - } - }; - return descriptor; - } -} + return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => { + const { value } = descriptor; + //eslint-disable-next-line + descriptor.value = async (...args: any) => { + try { + const response = value.apply(target, args); + return isPromise(response) ? await response : Promise.resolve(response); + } catch (error) { + eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `Error while calling function: ${propertyKey}: ${(error as Record)?.message || error}` + ), + severity: 'error', + } satisfies INotifyMessage); + } + }; + return descriptor; + }; +}; export class SubscriptionSubmitter implements IObserver { + private emitter: EventEmitter; - private emitter: EventEmitter; - - constructor(emitter: EventEmitter) { - this.emitter = emitter; - } + constructor(emitter: EventEmitter) { + this.emitter = emitter; + } - notify(notifyMessage: INotifyMessage): void { + notify(notifyMessage: INotifyMessage): void { this.emitter.emit('notify', notifyMessage); } - async update(operation: ISubmitOperation): Promise { - switch (operation.operation) { - case OperationNameEnum.SUBSCRIPTION_CREATE: - await this.submitSubscriptionCreate(operation); - break; - - case OperationNameEnum.SUBSCRIPTION_UPDATE: - await this.submitSubscriptionUpdate(operation); - break; - - case OperationNameEnum.SUBSCRIPTION_CANCEL: - await this.submitSubscriptionCancel(operation); - break; - } - } - - // @eventDecorator() - async submitSubscriptionCreate(operation: ISubmitOperation): Promise { - const data = operation.data as ISubmitSubscriptionData; - try{ - const customers = await CustomerService.instance.find({ - stripeCustomerId: data.stripeCustomerId - }) - - if (customers.length !== 1) { - this.notify({ - message: EventTracker.compileBasicNotification(`It should be only 1 Stripe account associated with CaaS customer. Stripe accountId: ${data.stripeCustomerId}.`, operation.operation), - severity: 'error', - }) - } - const subscription = await SubscriptionService.instance.create( - data.subscriptionId, - customers[0], - data.status, - data.currentPeriodStart, - data.currentPeriodEnd, - data.trialStart as Date, - data.trialEnd as Date, - ) - if (!subscription) { - this.notify({ - message: EventTracker.compileBasicNotification(`Failed to create a new subscription with id: ${data.subscriptionId}.`, operation.operation), - severity: 'error', - }) - } - - this.notify({ - message: EventTracker.compileBasicNotification(`Subscription created with id: ${data.subscriptionId}.`, operation.operation), - severity: 'info', - }) - } catch (error) { - this.notify({ - message: EventTracker.compileBasicNotification(`Failed to create a new subscription with id: ${data.subscriptionId} because of error: ${(error as Error)?.message || error}`, operation.operation), - severity: 'error', - }) - } - } - - // @eventDecorator() - async submitSubscriptionUpdate(operation: ISubmitOperation): Promise { - const data = operation.data as ISubmitSubscriptionData; - try { - const subscription = await SubscriptionService.instance.update( - data.subscriptionId, - data.status, - data.currentPeriodStart, - data.currentPeriodEnd, - data.trialStart as Date, - data.trialEnd as Date, - ) - if (!subscription) { - this.notify({ - message: EventTracker.compileBasicNotification(`Failed to update subscription with id: ${data.subscriptionId}.`, operation.operation), - severity: 'error', - }) - } - - this.notify({ - message: EventTracker.compileBasicNotification(`Subscription updated with id: ${data.subscriptionId}.`, operation.operation), - severity: 'info', - }) - } catch (error) { - this.notify({ - message: EventTracker.compileBasicNotification(`Failed to update subscription with id: ${data.subscriptionId} because of error: ${(error as Error)?.message || error}`, operation.operation), - severity: 'error', - }) - } - } - - // @eventDecorator() - async submitSubscriptionCancel(operation: ISubmitOperation): Promise { - const data = operation.data as ISubmitSubscriptionData; - try { - const subscription = await SubscriptionService.instance.update( - data.subscriptionId, - data.status, - ) - if (!subscription) { - this.notify({ - message: EventTracker.compileBasicNotification(`Failed to cancel subscription with id: ${data.subscriptionId}.`, operation.operation), - severity: 'error', - }) - } - - this.notify({ - message: EventTracker.compileBasicNotification(`Subscription canceled with id: ${data.subscriptionId}.`, operation.operation), - severity: 'info', - }) - } catch (error) { - this.notify({ - message: EventTracker.compileBasicNotification(`Failed to cancel subscription with id: ${data.subscriptionId} because of error: ${(error as Error)?.message || error}`, operation.operation), - severity: 'error', - }) - } - } -} \ No newline at end of file + async update(operation: ISubmitOperation): Promise { + switch (operation.operation) { + case OperationNameEnum.SUBSCRIPTION_CREATE: + await this.submitSubscriptionCreate(operation); + break; + + case OperationNameEnum.SUBSCRIPTION_UPDATE: + await this.submitSubscriptionUpdate(operation); + break; + + case OperationNameEnum.SUBSCRIPTION_CANCEL: + await this.submitSubscriptionCancel(operation); + break; + } + } + + // @eventDecorator() + async submitSubscriptionCreate(operation: ISubmitOperation): Promise { + const data = operation.data as ISubmitSubscriptionData; + try { + const customers = await CustomerService.instance.find({ + stripeCustomerId: data.stripeCustomerId, + }); + + if (customers.length !== 1) { + this.notify({ + message: EventTracker.compileBasicNotification( + `It should be only 1 Stripe account associated with CaaS customer. Stripe accountId: ${data.stripeCustomerId}.`, + operation.operation + ), + severity: 'error', + }); + } + const subscription = await SubscriptionService.instance.create( + data.subscriptionId, + customers[0], + data.status, + data.currentPeriodStart, + data.currentPeriodEnd, + data.trialStart as Date, + data.trialEnd as Date + ); + if (!subscription) { + this.notify({ + message: EventTracker.compileBasicNotification( + `Failed to create a new subscription with id: ${data.subscriptionId}.`, + operation.operation + ), + severity: 'error', + }); + } + + this.notify({ + message: EventTracker.compileBasicNotification( + `Subscription created with id: ${data.subscriptionId}.`, + operation.operation + ), + severity: 'info', + }); + } catch (error) { + this.notify({ + message: EventTracker.compileBasicNotification( + `Failed to create a new subscription with id: ${data.subscriptionId} because of error: ${(error as Error)?.message || error}`, + operation.operation + ), + severity: 'error', + }); + } + } + + // @eventDecorator() + async submitSubscriptionUpdate(operation: ISubmitOperation): Promise { + const data = operation.data as ISubmitSubscriptionData; + try { + const subscription = await SubscriptionService.instance.update( + data.subscriptionId, + data.status, + data.currentPeriodStart, + data.currentPeriodEnd, + data.trialStart as Date, + data.trialEnd as Date + ); + if (!subscription) { + this.notify({ + message: EventTracker.compileBasicNotification( + `Failed to update subscription with id: ${data.subscriptionId}.`, + operation.operation + ), + severity: 'error', + }); + } + + this.notify({ + message: EventTracker.compileBasicNotification( + `Subscription updated with id: ${data.subscriptionId}.`, + operation.operation + ), + severity: 'info', + }); + } catch (error) { + this.notify({ + message: EventTracker.compileBasicNotification( + `Failed to update subscription with id: ${data.subscriptionId} because of error: ${(error as Error)?.message || error}`, + operation.operation + ), + severity: 'error', + }); + } + } + + // @eventDecorator() + async submitSubscriptionCancel(operation: ISubmitOperation): Promise { + const data = operation.data as ISubmitSubscriptionData; + try { + const subscription = await SubscriptionService.instance.update(data.subscriptionId, data.status); + if (!subscription) { + this.notify({ + message: EventTracker.compileBasicNotification( + `Failed to cancel subscription with id: ${data.subscriptionId}.`, + operation.operation + ), + severity: 'error', + }); + } + + this.notify({ + message: EventTracker.compileBasicNotification( + `Subscription canceled with id: ${data.subscriptionId}.`, + operation.operation + ), + severity: 'info', + }); + } catch (error) { + this.notify({ + message: EventTracker.compileBasicNotification( + `Failed to cancel subscription with id: ${data.subscriptionId} because of error: ${(error as Error)?.message || error}`, + operation.operation + ), + severity: 'error', + }); + } + } +} diff --git a/src/services/track/api/credential-status-subscriber.ts b/src/services/track/api/credential-status-subscriber.ts index 41c5d6c9..762d543b 100644 --- a/src/services/track/api/credential-status-subscriber.ts +++ b/src/services/track/api/credential-status-subscriber.ts @@ -1,12 +1,8 @@ import { OperationCategoryNameEnum } from '../../../types/constants.js'; -import type { - ICredentialStatusTrack, ITrackOperation, - ITrackResult -} from '../../../types/track.js'; +import type { ICredentialStatusTrack, ITrackOperation, ITrackResult } from '../../../types/track.js'; import type { IObserver } from '../types.js'; import { BaseOperationObserver } from '../base.js'; - export class CredentialStatusSubscriber extends BaseOperationObserver implements IObserver { isReactionNeeded(trackOperation: ITrackOperation): boolean { // Credential tracker reacts on CredentialStatusList, Credential operations like revocation diff --git a/src/services/track/api/credential-subscriber.ts b/src/services/track/api/credential-subscriber.ts index b1a7af29..7ca1515c 100644 --- a/src/services/track/api/credential-subscriber.ts +++ b/src/services/track/api/credential-subscriber.ts @@ -1,12 +1,8 @@ import { OperationCategoryNameEnum } from '../../../types/constants.js'; -import type { - ICredentialTrack, ITrackOperation, - ITrackResult -} from '../../../types/track.js'; +import type { ICredentialTrack, ITrackOperation, ITrackResult } from '../../../types/track.js'; import type { IObserver } from '../types.js'; import { BaseOperationObserver } from '../base.js'; - export class CredentialSubscriber extends BaseOperationObserver implements IObserver { isReactionNeeded(trackOperation: ITrackOperation): boolean { // Credential tracker reacts on CredentialStatusList, Credential operations like revocation diff --git a/src/services/track/api/did-subscriber.ts b/src/services/track/api/did-subscriber.ts index b6be6b07..5bc38685 100644 --- a/src/services/track/api/did-subscriber.ts +++ b/src/services/track/api/did-subscriber.ts @@ -1,13 +1,8 @@ import { OperationCategoryNameEnum } from '../../../types/constants.js'; -import type { - ITrackOperation, - ITrackResult, - IDIDTrack -} from '../../../types/track.js'; +import type { ITrackOperation, ITrackResult, IDIDTrack } from '../../../types/track.js'; import type { IObserver } from '../types.js'; import { BaseOperationObserver } from '../base.js'; - export class DIDSubscriber extends BaseOperationObserver implements IObserver { isReactionNeeded(trackOperation: ITrackOperation): boolean { return trackOperation.category === OperationCategoryNameEnum.DID; diff --git a/src/services/track/api/key-subscriber.ts b/src/services/track/api/key-subscriber.ts index c5ff1d0b..1e46b6f9 100644 --- a/src/services/track/api/key-subscriber.ts +++ b/src/services/track/api/key-subscriber.ts @@ -1,13 +1,8 @@ import { OperationCategoryNameEnum } from '../../../types/constants.js'; -import type { - IKeyTrack, - ITrackOperation, - ITrackResult -} from '../../../types/track.js'; +import type { IKeyTrack, ITrackOperation, ITrackResult } from '../../../types/track.js'; import type { IObserver } from '../types.js'; import { BaseOperationObserver } from '../base.js'; - export class KeySubscriber extends BaseOperationObserver implements IObserver { isReactionNeeded(trackOperation: ITrackOperation): boolean { // Credential tracker reacts on CredentialStatusList, Credential operations like revocation diff --git a/src/services/track/api/presentation-subscriber.ts b/src/services/track/api/presentation-subscriber.ts index 4d66101f..daee2c07 100644 --- a/src/services/track/api/presentation-subscriber.ts +++ b/src/services/track/api/presentation-subscriber.ts @@ -1,12 +1,8 @@ import { OperationCategoryNameEnum } from '../../../types/constants.js'; -import type { - IPresentationTrack, ITrackOperation, - ITrackResult -} from '../../../types/track.js'; +import type { IPresentationTrack, ITrackOperation, ITrackResult } from '../../../types/track.js'; import type { IObserver } from '../types.js'; import { BaseOperationObserver } from '../base.js'; - export class PresentationSubscriber extends BaseOperationObserver implements IObserver { isReactionNeeded(trackOperation: ITrackOperation): boolean { // Credential tracker reacts on CredentialStatusList, Credential operations like revocation diff --git a/src/services/track/api/resource-subscriber.ts b/src/services/track/api/resource-subscriber.ts index 67e5cc5f..f26dbe05 100644 --- a/src/services/track/api/resource-subscriber.ts +++ b/src/services/track/api/resource-subscriber.ts @@ -5,7 +5,8 @@ import type { ICredentialTrack, IResourceTrack, ITrackOperation, - ITrackResult} from '../../../types/track.js'; + ITrackResult, +} from '../../../types/track.js'; import { isCredentialStatusTrack, isCredentialTrack, isResourceTrack } from '../helpers.js'; import { IdentifierService } from '../../api/identifier.js'; import { KeyService } from '../../api/key.js'; @@ -13,7 +14,6 @@ import { ResourceService } from '../../api/resource.js'; import type { IObserver } from '../types.js'; import { BaseOperationObserver } from '../base.js'; - export class ResourceSubscriber extends BaseOperationObserver implements IObserver { private static acceptedOperations = [ OperationNameEnum.RESOURCE_CREATE, @@ -29,7 +29,8 @@ export class ResourceSubscriber extends BaseOperationObserver implements IObserv isReactionNeeded(trackOperation: ITrackOperation): boolean { // Resource tracker reacts on CredentialStatusList, Credential operations like revocation // and Resource operations like create, update, delete - const isCategoryAccepted = trackOperation.category === OperationCategoryNameEnum.RESOURCE || + const isCategoryAccepted = + trackOperation.category === OperationCategoryNameEnum.RESOURCE || trackOperation.category === OperationCategoryNameEnum.CREDENTIAL || trackOperation.category === OperationCategoryNameEnum.CREDENTIAL_STATUS; const isOperationAccepted = ResourceSubscriber.acceptedOperations.includes( diff --git a/src/services/track/observer.ts b/src/services/track/observer.ts index 3282df73..61dc82f0 100644 --- a/src/services/track/observer.ts +++ b/src/services/track/observer.ts @@ -51,4 +51,3 @@ export class SubmitSubject implements ITrackSubject { } } } - diff --git a/src/services/track/operation-subscriber.ts b/src/services/track/operation-subscriber.ts index eb1b27a7..57409171 100644 --- a/src/services/track/operation-subscriber.ts +++ b/src/services/track/operation-subscriber.ts @@ -154,4 +154,3 @@ export class DBOperationSubscriber extends BaseOperationObserver implements IObs } } } - diff --git a/src/services/track/submitter.ts b/src/services/track/submitter.ts index 44adbd1d..89beb23b 100644 --- a/src/services/track/submitter.ts +++ b/src/services/track/submitter.ts @@ -1,24 +1,23 @@ // Type: Interface -export type ISubmitData = ISubmitStripeCustomerCreateData - | ISubmitSubscriptionData; +export type ISubmitData = ISubmitStripeCustomerCreateData | ISubmitSubscriptionData; export interface ISubmitStripeCustomerCreateData { - customerId: string; - name: string; - email?: string; + customerId: string; + name: string; + email?: string; } export interface ISubmitSubscriptionData { - stripeCustomerId: string; - status: string; - currentPeriodStart: Date; - currentPeriodEnd: Date; - trialStart?: Date; - trialEnd?: Date; - subscriptionId: string; + stripeCustomerId: string; + status: string; + currentPeriodStart: Date; + currentPeriodEnd: Date; + trialStart?: Date; + trialEnd?: Date; + subscriptionId: string; } export interface ISubmitOperation { - operation: string; - data: ISubmitData; + operation: string; + data: ISubmitData; } diff --git a/src/services/track/tracker.ts b/src/services/track/tracker.ts index 62713d0c..b854f2f5 100644 --- a/src/services/track/tracker.ts +++ b/src/services/track/tracker.ts @@ -1,11 +1,8 @@ import EventEmitter from 'node:events'; import type { INotifyMessage, ITrackOperation } from '../../types/track.js'; import { DatadogNotifier, LoggerNotifier } from './notifiers.js'; -import { - DBOperationSubscriber, -} from './operation-subscriber.js'; -import { - ResourceSubscriber} from './api/resource-subscriber.js'; +import { DBOperationSubscriber } from './operation-subscriber.js'; +import { ResourceSubscriber } from './api/resource-subscriber.js'; import { PresentationSubscriber } from './api/presentation-subscriber.js'; import { CredentialStatusSubscriber } from './api/credential-status-subscriber.js'; import { DIDSubscriber } from './api/did-subscriber.js'; @@ -14,7 +11,7 @@ import type { ITrackType } from './types.js'; import { ENABLE_DATADOG } from '../../types/constants.js'; import { SubmitSubject, TrackSubject } from './observer.js'; import type { ISubmitOperation } from './submitter.js'; -import { PortalAccountCreateSubmitter } from "./admin/account-submitter.js"; +import { PortalAccountCreateSubmitter } from './admin/account-submitter.js'; import { SubscriptionSubmitter } from './admin/subscription-submitter.js'; export class EventTracker { diff --git a/src/static/swagger-admin.json b/src/static/swagger-admin.json index 8e616f6f..d898b33c 100644 --- a/src/static/swagger-admin.json +++ b/src/static/swagger-admin.json @@ -1,713 +1,693 @@ { - "openapi": "3.0.0", - "info": { - "title": "Credential Service admin API for cheqd network", - "version": "2.0.0", - "description": "Admin API which handles users subscriptions and payments", - "contact": { - "name": "Cheqd Foundation Limited", - "url": "https://github.com/cheqd/credential-service", - "email": "support-github@cheqd.io" - }, - "license": { - "name": "Apache 2.0", - "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" - } - }, - "tags": [ - { - "name": "Product" - }, - { - "name": "Price" - }, - { - "name": "Customer" - }, - { - "name": "Subscription" - }, - { - "name": "Checkout" - } - ], - "paths": { - "/admin/checkout/session/create": { - "post": { - "summary": "Create a checkout session", - "description": "Create a checkout session", - "tags": [ - "Checkout" - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CheckoutSessionCreateRequestBody" - } - } - } - }, - "responses": { - "303": { - "description": "A redirect to Stripe prebuilt checkout page" - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/price/list": { - "get": { - "summary": "Get a list of prices", - "description": "Get a list of prices", - "tags": [ - "Price" - ], - "parameters": [ - { - "in": "query", - "name": "productId", - "schema": { - "type": "string", - "description": "The product id. If passed - returns filtered by this product list of prices.", - "required": false - } - } - ], - "responses": { - "200": { - "description": "A list of prices", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PriceListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/product/list": { - "get": { - "summary": "Get a list of products", - "description": "Get a list of products which are on a Stripe side", - "tags": [ - "Product" - ], - "parameters": [ - { - "in": "query", - "name": "prices", - "schema": { - "type": "boolean", - "description": "If setup to true - returns the list of products with prices inside. Default - true", - "required": false - } - } - ], - "responses": { - "200": { - "description": "A list of products", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/product/get/{productId}": { - "get": { - "summary": "Get a product", - "description": "Get a product by id", - "tags": [ - "Product" - ], - "parameters": [ - { - "in": "path", - "name": "productId", - "schema": { - "type": "string", - "description": "The product id which identifies the product in Stripe", - "required": true - } - }, - { - "in": "query", - "name": "prices", - "schema": { - "type": "boolean", - "description": "If setup to true - returns the product with prices inside. Default - true", - "required": false - } - } - ], - "responses": { - "200": { - "description": "A product", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductGetResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/create": { - "post": { - "summary": "Create a subscription", - "description": "Creates a new subscription for an existing customer", - "tags": [ - "Subscription" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCreateRequestBody" - } - } - } - }, - "responses": { - "201": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCreateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/update": { - "post": { - "summary": "Update a subscription", - "description": "Updates an existing subscription", - "tags": [ - "Subscription" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionUpdateRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionUpdateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/list": { - "get": { - "summary": "Get a list of subscriptions", - "description": "Get a list of subscriptions", - "tags": [ - "Subscription" - ], - "responses": { - "200": { - "description": "A list of subscriptions", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/get/{subscriptionId}": { - "get": { - "summary": "Get a subscription", - "description": "Get a subscription", - "tags": [ - "Subscription" - ], - "parameters": [ - { - "in": "path", - "name": "subscriptionId", - "schema": { - "type": "string", - "description": "The subscription id", - "required": true - } - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionGetResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/cancel": { - "post": { - "summary": "Cancel a subscription", - "description": "Cancels an existing subscription", - "tags": [ - "Subscription" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCancelRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCancelResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/resume": {}, - "post": { - "summary": "Resume a subscription", - "description": "Resumes an existing subscription", - "tags": [ - "Subscription" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionResumeRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionResumeResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "components": { - "schemas": { - "PriceListResponseBody": { - "description": "A list of active prcies from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/list)", - "type": "object", - "properties": { - "prices": { - "type": "array", - "items": { - "type": "object", - "description": "A price object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/object)" - } - } - } - }, - "ProductListResponseBody": { - "type": "object", - "properties": { - "products": { - "type": "array", - "items": { - "type": "object", - "description": "A product object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/object)" - } - } - } - }, - "ProductGetResponseBody": { - "description": "A product with or without prices inside. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/retrieve)", - "type": "object" - }, - "InvalidRequest": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "InvalidRequest" - } - } - }, - "InternalError": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Internal Error" - } - } - }, - "UnauthorizedError": { - "description": "Access token is missing or invalid", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Unauthorized Error" - } - } - }, - "SubscriptionCreateRequestBody": { - "description": "The request body for creating a subscription", - "type": "object", - "properties": { - "customerId": { - "type": "string", - "description": "The Stripe customer id", - "example": "cus_1234567890" - }, - "items": { - "type": "array", - "items": { - "type": "object", - "properties": { - "price": { - "type": "string", - "description": "The price id", - "example": "price_1234567890" - } - } - } - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": 1234567890 - } - } - }, - "SubscriptionCreateResponseBody": { - "description": "The response body for creating a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" - } - } - }, - "SubscriptionUpdateRequestBody": { - "description": "The request body for updating a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - }, - "updateParams": { - "type": "object", - "description": "The subscription update parameters. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/update)" - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": 1234567890 - } - } - }, - "SubscriptionUpdateResponseBody": { - "description": "The response body for updating a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" - } - } - }, - "SubscriptionGetRequestBody": { - "description": "The request body for getting a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - } - } - }, - "SubscriptionGetResponseBody": { - "description": "The response body for getting a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" - } - } - }, - "SubscriptionListRequestBody": { - "description": "The request body for listing subscriptions", - "type": "object", - "properties": { - "customerId": { - "type": "string", - "description": "The Stripe customer id", - "example": "cus_1234567890" - } - } - }, - "SubscriptionListResponseBody": { - "description": "The response body for listing subscriptions", - "type": "object", - "properties": { - "subscriptions": { - "type": "array", - "items": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" - } - } - } - }, - "SubscriptionCancelRequestBody": { - "description": "The request body for canceling a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - } - } - }, - "SubscriptionCancelResponseBody": { - "description": "The response body for canceling a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": 1234567890 - } - } - }, - "SubscriptionResumeRequestBody": { - "description": "The request body for resuming a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": 1234567890 - } - } - }, - "SubscriptionResumeResponseBody": { - "description": "The response body for resuming a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" - } - } - }, - "CheckoutSessionCreateRequestBody": { - "description": "The request body for creating a checkout session", - "type": "object", - "properties": { - "price": { - "type": "string", - "description": "The price id", - "example": "price_1234567890" - }, - "successURL": { - "type": "string", - "description": "The URL to redirect to after the customer sucessfully completes the checkout", - "example": "https://example.com/success" - }, - "cancelURL": { - "type": "string", - "description": "The URL to redirect to after the customer cancels the checkout", - "example": "https://example.com/cancel" - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": 1234567890 - } - } - }, - "NotFoundError": { - "description": "The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Not Found Error" - } - } - } - } - } -} \ No newline at end of file + "openapi": "3.0.0", + "info": { + "title": "Credential Service admin API for cheqd network", + "version": "2.0.0", + "description": "Admin API which handles users subscriptions and payments", + "contact": { + "name": "Cheqd Foundation Limited", + "url": "https://github.com/cheqd/credential-service", + "email": "support-github@cheqd.io" + }, + "license": { + "name": "Apache 2.0", + "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" + } + }, + "tags": [ + { + "name": "Product" + }, + { + "name": "Price" + }, + { + "name": "Customer" + }, + { + "name": "Subscription" + }, + { + "name": "Checkout" + } + ], + "paths": { + "/admin/checkout/session/create": { + "post": { + "summary": "Create a checkout session", + "description": "Create a checkout session", + "tags": ["Checkout"], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CheckoutSessionCreateRequestBody" + } + } + } + }, + "responses": { + "303": { + "description": "A redirect to Stripe prebuilt checkout page" + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/price/list": { + "get": { + "summary": "Get a list of prices", + "description": "Get a list of prices", + "tags": ["Price"], + "parameters": [ + { + "in": "query", + "name": "productId", + "schema": { + "type": "string", + "description": "The product id. If passed - returns filtered by this product list of prices.", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A list of prices", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PriceListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/product/list": { + "get": { + "summary": "Get a list of products", + "description": "Get a list of products which are on a Stripe side", + "tags": ["Product"], + "parameters": [ + { + "in": "query", + "name": "prices", + "schema": { + "type": "boolean", + "description": "If setup to true - returns the list of products with prices inside. Default - true", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A list of products", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProductListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/product/get/{productId}": { + "get": { + "summary": "Get a product", + "description": "Get a product by id", + "tags": ["Product"], + "parameters": [ + { + "in": "path", + "name": "productId", + "schema": { + "type": "string", + "description": "The product id which identifies the product in Stripe", + "required": true + } + }, + { + "in": "query", + "name": "prices", + "schema": { + "type": "boolean", + "description": "If setup to true - returns the product with prices inside. Default - true", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A product", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProductGetResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/create": { + "post": { + "summary": "Create a subscription", + "description": "Creates a new subscription for an existing customer", + "tags": ["Subscription"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCreateRequestBody" + } + } + } + }, + "responses": { + "201": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCreateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/update": { + "post": { + "summary": "Update a subscription", + "description": "Updates an existing subscription", + "tags": ["Subscription"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionUpdateRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionUpdateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/list": { + "get": { + "summary": "Get a list of subscriptions", + "description": "Get a list of subscriptions", + "tags": ["Subscription"], + "responses": { + "200": { + "description": "A list of subscriptions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/get/{subscriptionId}": { + "get": { + "summary": "Get a subscription", + "description": "Get a subscription", + "tags": ["Subscription"], + "parameters": [ + { + "in": "path", + "name": "subscriptionId", + "schema": { + "type": "string", + "description": "The subscription id", + "required": true + } + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionGetResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/cancel": { + "post": { + "summary": "Cancel a subscription", + "description": "Cancels an existing subscription", + "tags": ["Subscription"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCancelRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCancelResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/resume": {}, + "post": { + "summary": "Resume a subscription", + "description": "Resumes an existing subscription", + "tags": ["Subscription"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionResumeRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionResumeResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "components": { + "schemas": { + "PriceListResponseBody": { + "description": "A list of active prcies from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/list)", + "type": "object", + "properties": { + "prices": { + "type": "array", + "items": { + "type": "object", + "description": "A price object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/object)" + } + } + } + }, + "ProductListResponseBody": { + "type": "object", + "properties": { + "products": { + "type": "array", + "items": { + "type": "object", + "description": "A product object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/object)" + } + } + } + }, + "ProductGetResponseBody": { + "description": "A product with or without prices inside. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/retrieve)", + "type": "object" + }, + "InvalidRequest": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "InvalidRequest" + } + } + }, + "InternalError": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Internal Error" + } + } + }, + "UnauthorizedError": { + "description": "Access token is missing or invalid", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Unauthorized Error" + } + } + }, + "SubscriptionCreateRequestBody": { + "description": "The request body for creating a subscription", + "type": "object", + "properties": { + "customerId": { + "type": "string", + "description": "The Stripe customer id", + "example": "cus_1234567890" + }, + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "price": { + "type": "string", + "description": "The price id", + "example": "price_1234567890" + } + } + } + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": 1234567890 + } + } + }, + "SubscriptionCreateResponseBody": { + "description": "The response body for creating a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" + } + } + }, + "SubscriptionUpdateRequestBody": { + "description": "The request body for updating a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + }, + "updateParams": { + "type": "object", + "description": "The subscription update parameters. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/update)" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": 1234567890 + } + } + }, + "SubscriptionUpdateResponseBody": { + "description": "The response body for updating a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" + } + } + }, + "SubscriptionGetRequestBody": { + "description": "The request body for getting a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + } + } + }, + "SubscriptionGetResponseBody": { + "description": "The response body for getting a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" + } + } + }, + "SubscriptionListRequestBody": { + "description": "The request body for listing subscriptions", + "type": "object", + "properties": { + "customerId": { + "type": "string", + "description": "The Stripe customer id", + "example": "cus_1234567890" + } + } + }, + "SubscriptionListResponseBody": { + "description": "The response body for listing subscriptions", + "type": "object", + "properties": { + "subscriptions": { + "type": "array", + "items": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + } + } + } + }, + "SubscriptionCancelRequestBody": { + "description": "The request body for canceling a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + } + } + }, + "SubscriptionCancelResponseBody": { + "description": "The response body for canceling a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": 1234567890 + } + } + }, + "SubscriptionResumeRequestBody": { + "description": "The request body for resuming a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": 1234567890 + } + } + }, + "SubscriptionResumeResponseBody": { + "description": "The response body for resuming a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + } + } + }, + "CheckoutSessionCreateRequestBody": { + "description": "The request body for creating a checkout session", + "type": "object", + "properties": { + "price": { + "type": "string", + "description": "The price id", + "example": "price_1234567890" + }, + "successURL": { + "type": "string", + "description": "The URL to redirect to after the customer sucessfully completes the checkout", + "example": "https://example.com/success" + }, + "cancelURL": { + "type": "string", + "description": "The URL to redirect to after the customer cancels the checkout", + "example": "https://example.com/cancel" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": 1234567890 + } + } + }, + "NotFoundError": { + "description": "The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Not Found Error" + } + } + } + } + } +} diff --git a/src/static/swagger-api.json b/src/static/swagger-api.json index d8d26cfe..a490ba8a 100644 --- a/src/static/swagger-api.json +++ b/src/static/swagger-api.json @@ -1,3549 +1,3333 @@ { - "openapi": "3.0.0", - "info": { - "title": "Credential Service API for cheqd network", - "version": "2.0.0", - "description": "API service to create and manage DIDs, Verifiable Credentials, and DID-Linked Resources", - "contact": { - "name": "Cheqd Foundation Limited", - "url": "https://github.com/cheqd/credential-service", - "email": "support-github@cheqd.io" - }, - "license": { - "name": "Apache 2.0", - "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" - } - }, - "tags": [ - { - "name": "Account" - }, - { - "name": "Key" - }, - { - "name": "DID" - }, - { - "name": "Resource" - }, - { - "name": "Credential" - }, - { - "name": "Presentation" - }, - { - "name": "Credential Status" - } - ], - "externalDocs": { - "description": "Credential Service API Documentation", - "url": "https://docs.cheqd.io/identity" - }, - "paths": { - "/account": { - "get": { - "tags": [ - "Account" - ], - "summary": "Fetch custodian-mode client details.", - "description": "This endpoint returns the custodian-mode client details for authenticated users.", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Customer" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/account/idtoken": { - "get": { - "tags": [ - "Account" - ], - "summary": "Fetch IdToken.", - "description": "This endpoint returns IdToken as JWT with list of user roles inside", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "idToken": { - "type": "string" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/account/create": { - "post": { - "tags": [ - "Account" - ], - "summary": "Create an client for an authenticated user.", - "description": "This endpoint creates a client in the custodian-mode for an authenticated user", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/AccountCreateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountCreateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "idToken": { - "type": "string" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/create/unencrypted": { - "post": { - "tags": [ - "Credential Status" - ], - "summary": "Create an unencrypted StatusList2021 credential status list.", - "description": "This endpoint creates an unencrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", - "parameters": [ - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", - "required": true, - "schema": { - "type": "string", - "enum": [ - "revocation", - "suspension" - ] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/create/encrypted": { - "post": { - "tags": [ - "Credential Status" - ], - "summary": "Create an encrypted StatusList2021 credential status list.", - "description": "This endpoint creates an encrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", - "parameters": [ - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", - "required": true, - "schema": { - "type": "string", - "enum": [ - "revocation", - "suspension" - ] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateEncryptedFormRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateEncryptedJsonRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateEncryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/update/unencrypted": { - "post": { - "tags": [ - "Credential Status" - ], - "summary": "Update an existing unencrypted StatusList2021 credential status list.", - "parameters": [ - { - "in": "query", - "name": "statusAction", - "description": "The update action to be performed on the unencrypted status list, can be revoke, suspend or reinstate", - "required": true, - "schema": { - "type": "string", - "enum": [ - "revoke", - "suspend", - "reinstate" - ] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/update/encrypted": { - "post": { - "tags": [ - "Credential Status" - ], - "summary": "Update an existing encrypted StatusList2021 credential status list.", - "parameters": [ - { - "in": "query", - "name": "statusAction", - "description": "The update action to be performed on the encrypted status list, can be revoke, suspend or reinstate", - "required": true, - "schema": { - "type": "string", - "enum": [ - "revoke", - "suspend", - "reinstate" - ] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedFormRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedJsonRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/check": { - "post": { - "tags": [ - "Credential Status" - ], - "summary": "Check a StatusList2021 index for a given Verifiable Credential.", - "description": "This endpoint checks a StatusList2021 index for a given Verifiable Credential and reports whether it is revoked or suspended. It offers a standalone method for checking an index without passing the entire Verifiable Credential or Verifiable Presentation.", - "parameters": [ - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension.", - "required": true, - "schema": { - "type": "string", - "enum": [ - "revocation", - "suspension" - ] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCheckRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCheckRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCheckResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/search": { - "get": { - "tags": [ - "Credential Status" - ], - "summary": "Fetch StatusList2021 DID-Linked Resource based on search criteria.", - "parameters": [ - { - "in": "query", - "name": "did", - "description": "The DID of the issuer of the status list.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension.", - "schema": { - "type": "string", - "enum": [ - "revocation", - "suspension" - ] - } - }, - { - "in": "query", - "name": "statusListName", - "description": "The name of the StatusList2021 DID-Linked Resource.", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusListSearchResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/issue": { - "post": { - "tags": [ - "Credential" - ], - "summary": "Issue a Verifiable Credential", - "description": "This endpoint issues a Verifiable Credential. As input it takes the list of issuerDid, subjectDid, attributes, and other parameters of the credential to be issued.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Credential" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/verify": { - "post": { - "tags": [ - "Credential" - ], - "summary": "Verify a Verifiable Credential.", - "description": "This endpoint verifies a Verifiable Credential passed to it. As input, it can take the VC-JWT as a string or the entire credential itself.", - "operationId": "verify", - "parameters": [ - { - "in": "query", - "name": "verifyStatus", - "description": "If set to `true` the verification will also check the status of the credential. Requires the VC to have a `credentialStatus` property.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "fetchRemoteContexts", - "description": "When dealing with JSON-LD you also MUST provide the proper contexts. Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "allowDeactivatedDid", - "description": "If set to `true` allow to verify credential which based on deactivated DID.", - "schema": { - "type": "boolean", - "default": false - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialVerifyRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialVerifyRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/VerifyCredentialResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/revoke": { - "post": { - "tags": [ - "Credential" - ], - "summary": "Revoke a Verifiable Credential.", - "description": "This endpoint revokes a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself. The StatusList2021 resource should already be setup in the VC and `credentialStatus` property present in the VC.", - "operationId": "revoke", - "parameters": [ - { - "in": "query", - "name": "publish", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RevocationResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/suspend": { - "post": { - "tags": [ - "Credential" - ], - "summary": "Suspend a Verifiable Credential.", - "description": "This endpoint suspends a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself.", - "operationId": "suspend", - "parameters": [ - { - "in": "query", - "name": "publish", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "schema": { - "type": "boolean" - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuspensionResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/reinstate": { - "post": { - "tags": [ - "Credential" - ], - "summary": "Reinstate a suspended Verifiable Credential.", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "operationId": "reinstate", - "parameters": [ - { - "in": "query", - "name": "publish", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "schema": { - "type": "boolean" - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnsuspensionResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/create": { - "post": { - "tags": [ - "DID" - ], - "summary": "Create a DID Document.", - "description": "This endpoint creates a DID and associated DID Document. As input, it can take the DID Document parameters via a form, or the fully-assembled DID Document itself.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidCreateRequestFormBased" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidCreateRequestJson" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/did/update": { - "post": { - "tags": [ - "DID" - ], - "summary": "Update a DID Document.", - "description": "This endpoint updates a DID Document. As an input, it can take JUST the sections/parameters that need to be updated in the DID Document (in this scenario, it fetches the current DID Document and applies the updated section). Alternatively, it take the fully-assembled DID Document with updated sections as well as unchanged sections.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidUpdateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidUpdateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidUpdateResponse" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/import": { - "post": { - "tags": [ - "DID" - ], - "summary": "Import a DID Document.", - "description": "This endpoint imports a decentralized identifier associated with the user's account for custodian-mode clients.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidImportRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidImportRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/did/deactivate/{did}": { - "post": { - "tags": [ - "DID" - ], - "summary": "Deactivate a DID Document.", - "description": "This endpoint deactivates a DID Document by taking the DID identifier as input. Must be called and signed by the DID owner.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier to deactivate.", - "schema": { - "type": "string" - }, - "required": true - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidDeactivateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidDeactivateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeactivatedDidResolution" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/list": { - "get": { - "tags": [ - "DID" - ], - "summary": "Fetch DIDs associated with an account.", - "description": "This endpoint returns the list of DIDs controlled by the account.", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/search/{did}": { - "get": { - "tags": [ - "DID" - ], - "summary": "Resolve a DID Document.", - "description": "Resolve a DID Document by DID identifier. Also supports DID Resolution Queries as defined in the W3C DID Resolution specification.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier to resolve.", - "schema": { - "type": "string" - }, - "required": true, - "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - { - "in": "query", - "name": "metadata", - "description": "Return only metadata of DID Document instead of actual DID Document.", - "schema": { - "type": "boolean" - } - }, - { - "in": "query", - "name": "versionId", - "description": "Unique UUID version identifier of DID Document. Allows for fetching a specific version of the DID Document. See cheqd DID Method Specification for more details.", - "schema": { - "type": "string", - "format": "uuid" - }, - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - { - "in": "query", - "name": "versionTime", - "description": "Returns the closest version of the DID Document *at* or *before* specified time. See DID Resolution handling for `did:cheqd` for more details.", - "schema": { - "type": "string", - "format": "date-time" - }, - "example": "1970-01-01T00:00:00Z" - }, - { - "in": "query", - "name": "transformKeys", - "description": "This directive transforms the Verification Method key format from the version in the DID Document to the specified format chosen below.", - "schema": { - "type": "string", - "enum": [ - "Ed25519VerificationKey2018", - "Ed25519VerificationKey2020", - "JsonWebKey2020" - ] - } - }, - { - "in": "query", - "name": "service", - "description": "Query DID Document for a specific Service Endpoint by Service ID (e.g., `service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`). This will typically redirect to the Service Endpoint based on DID Resolution specification algorithm.", - "schema": { - "type": "string" - }, - "example": "service-1" - }, - { - "in": "query", - "name": "relativeRef", - "description": "Relative reference is a query fragment appended to the Service Endpoint URL. **Must** be used along with the `service` query property above. See DID Resolution specification algorithm for more details.", - "schema": { - "type": "string" - }, - "example": "/path/to/file" - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidResolution" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/key/create": { - "post": { - "tags": [ - "Key" - ], - "summary": "Create an identity key pair.", - "description": "This endpoint creates an identity key pair associated with the user's account for custodian-mode clients.", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/key/import": { - "post": { - "tags": [ - "Key" - ], - "summary": "Import an identity key pair.", - "description": "This endpoint imports an identity key pair associated with the user's account for custodian-mode clients.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/KeyImportRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyImportRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/key/read/{kid}": { - "get": { - "tags": [ - "Key" - ], - "summary": "Fetch an identity key pair.", - "description": "This endpoint fetches an identity key pair's details for a given key ID. Only the user account associated with the custodian-mode client can fetch the key pair.", - "parameters": [ - { - "name": "kid", - "description": "Key ID of the identity key pair to fetch.", - "in": "path", - "schema": { - "type": "string" - }, - "required": true - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/presentation/create": { - "post": { - "tags": [ - "Presentation" - ], - "summary": "!!! WARN. Such endpoint is made mostly for testing purposes and it is not supposed to be used in production !!! Create a Verifiable Presentation from credential(s).", - "description": "This endpoint creates a Verifiable Presentation from credential(s). As input, it can take the credential(s) as a string or the entire credential(s) itself. \n !!! WARN. Such endpoint is made only for testing purposes !!!", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/PresentationCreateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/PresentationCreateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PresentationCreateResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/presentation/verify": { - "post": { - "tags": [ - "Presentation" - ], - "summary": "Verify a Verifiable Presentation generated from credential(s).", - "description": "This endpoint verifies the Verifiable Presentation generated from credential(s). As input, it can take the Verifiable Presentation JWT as a string or the entire Verifiable Presentation itself.", - "parameters": [ - { - "in": "query", - "name": "verifyStatus", - "description": "If set to `true` the verification will also check the status of the presentation. Requires the VP to have a `credentialStatus` property.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "fetchRemoteContexts", - "description": "When dealing with JSON-LD you also MUST provide the proper contexts. * Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "allowDeactivatedDid", - "description": "If set to `true` allow to verify credential which based on deactivated DID.", - "schema": { - "type": "boolean", - "default": false - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/PresentationVerifyRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/PresentationVerifyRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/VerifyPresentationResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/resource/create/{did}": { - "post": { - "tags": [ - "Resource" - ], - "summary": "Create a DID-Linked Resource.", - "description": "This endpoint creates a DID-Linked Resource. As input, it can take the DID identifier and the resource parameters via a form, or the fully-assembled resource itself.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier to link the resource to.", - "schema": { - "type": "string" - }, - "required": true - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CreateResourceRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateResourceRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ResourceMetadata" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/resource/search/{did}": { - "get": { - "tags": [ - "Resource" - ], - "summary": "Get a DID-Linked Resource.", - "description": "This endpoint returns the DID-Linked Resource for a given DID identifier and resource identifier.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier", - "schema": { - "type": "string" - }, - "required": true, - "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - { - "in": "query", - "name": "resourceId", - "description": "Fetch a DID-Linked Resource by Resource ID unique identifier. Since this is a unique identifier, other Resource query parameters are not required. See DID-Linked Resources for more details.", - "schema": { - "type": "string", - "format": "uuid" - }, - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - { - "in": "query", - "name": "resourceName", - "description": "Filter a DID-Linked Resource query by Resource Name. See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "cheqd-issuer-logo" - }, - { - "in": "query", - "name": "resourceType", - "description": "Filter a DID-Linked Resource query by Resource Type. See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "CredentialArtwork" - }, - { - "in": "query", - "name": "resourceVersion", - "description": "Filter a DID-Linked Resource query by Resource Version, which is an optional free-text field used by issuers (e.g., \"v1\", \"Final Version\", \"1st January 1970\" etc). See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "v1" - }, - { - "in": "query", - "name": "resourceVersionTime", - "description": "Filter a DID-Linked Resource query which returns the closest version of the Resource *at* or *before* specified time. See DID-Linked Resources for more details.", - "schema": { - "type": "string", - "format": "date-time" - }, - "example": "1970-01-01T00:00:00Z" - }, - { - "in": "query", - "name": "checksum", - "description": "Request integrity check against a given DID-Linked Resource by providing a SHA-256 checksum hash. See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "dc64474d062ed750a66bad58cb609928de55ed0d81defd231a4a4bf97358e9ed" - }, - { - "in": "query", - "name": "resourceMetadata", - "description": "Return only metadata of DID-Linked Resource instead of actual DID-Linked Resource. Mutually exclusive with some of the other parameters.", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "any": { - "schema": { - "type": "object" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - } - }, - "components": { - "schemas": { - "AlsoKnownAs": { - "type": "object", - "properties": { - "alsoKnownAs": { - "type": "array", - "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", - "items": { - "type": "object", - "properties": { - "uri": { - "type": "string", - "format": "uri", - "description": "URI where the DID-Linked Resource can be fetched from. Can be any type of URI (e.g., DID, HTTPS, IPFS, etc.)" - }, - "description": { - "type": "string", - "description": "Optional description of the URI." - } - } - } - } - } - }, - "CredentialRequest": { - "description": "Input fields for the creating a Verifiable Credential.", - "type": "object", - "additionalProperties": false, - "properties": { - "issuerDid": { - "description": "DID of the Verifiable Credential issuer. This needs to be a `did:cheqd` DID.", - "type": "string", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "subjectDid": { - "description": "DID of the Verifiable Credential holder/subject. This needs to be a `did:key` DID.", - "type": "string", - "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" - }, - "attributes": { - "description": "JSON object containing the attributes to be included in the credential.", - "type": "object", - "example": { - "name": "Bob", - "gender": "male" - } - }, - "@context": { - "description": "Optional properties to be included in the `@context` property of the credential.", - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "https://schema.org/schema.jsonld", - "https://veramo.io/contexts/profile/v1" - ] - }, - "type": { - "description": "Optional properties to be included in the `type` property of the credential.", - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "Person" - ] - }, - "expirationDate": { - "description": "Optional expiration date according to the VC Data Model specification.", - "type": "string", - "format": "date-time", - "example": "2023-06-08T13:49:28.000Z" - }, - "format": { - "description": "Format of the Verifiable Credential. Defaults to VC-JWT.", - "type": "string", - "enum": [ - "jwt", - "jsonld" - ], - "example": "jwt" - }, - "credentialStatus": { - "description": "Optional `credentialStatus` properties for VC revocation or suspension. Takes `statusListName` and `statusListPurpose` as inputs.", - "type": "object", - "required": [ - "statusPurpose", - "statusListName" - ], - "properties": { - "statusPurpose": { - "type": "string", - "enum": [ - "revocation", - "suspension" - ] - }, - "statusListName": { - "type": "string" - }, - "statusListIndex": { - "type": "number" - }, - "statusListVersion": { - "type": "string", - "format": "date-time" - }, - "statusListRangeStart": { - "type": "number" - }, - "statusListRangeEnd": { - "type": "number" - }, - "indexNotIn": { - "type": "number" - } - }, - "example": { - "statusPurpose": "revocation", - "statusListName": "employee-credentials" - } - } - }, - "required": [ - "issuerDid", - "subjectDid", - "attributes" - ], - "example": { - "issuerDid": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "subjectDid": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", - "attributes": { - "gender": "male", - "name": "Bob" - }, - "@context": [ - "https://schema.org" - ], - "type": [ - "Person" - ], - "format": "jwt", - "credentialStatus": { - "statusPurpose": "revocation", - "statusListName": "employee-credentials", - "statusListIndex": 10 - } - } - }, - "Credential": { - "description": "Input fields for revoking/suspending a Verifiable Credential.", - "type": "object", - "additionalProperties": false, - "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "https://www.w3.org/2018/credentials/v1", - "https://schema.org", - "https://veramo.io/contexts/profile/v1" - ] - }, - "type": { - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "VerifiableCredential", - "Person" - ] - }, - "expirationDate": { - "type": "string", - "format": "date-time", - "example": "2023-06-08T13:49:28.000Z" - }, - "issuer": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "DID", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - } - } - }, - "credentialSubject": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "DID", - "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" - } - } - }, - "credentialStatus": { - "type": "object", - "properties": { - "id": { - "type": "string", - "example": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20" - }, - "statusListIndex": { - "type": "number", - "example": 20 - }, - "statusPurpose": { - "type": "string", - "enum": [ - "revocation", - "suspension" - ], - "example": "suspension" - }, - "type": { - "type": "string", - "enum": [ - "StatusList2021Entry" - ] - } - } - }, - "issuanceDate": { - "type": "string", - "format": "date-time", - "example": "2023-06-08T13:49:28.000Z" - }, - "proof": { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "jwt": { - "type": "string" - } - }, - "example": { - "type": "JwtProof2020", - "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg" - } - } - }, - "example": { - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://schema.org", - "https://veramo.io/contexts/profile/v1" - ], - "credentialSubject": { - "gender": "male", - "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", - "name": "Bob" - }, - "credentialStatus": { - "id": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20", - "statusIndex": 20, - "statusPurpose": "suspension", - "type": "StatusList2021Entry" - }, - "issuanceDate": "2023-06-08T13:49:28.000Z", - "issuer": { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "proof": { - "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg", - "type": "JwtProof2020" - }, - "type": [ - "VerifiableCredential", - "Person" - ] - } - }, - "CredentialRevokeRequest": { - "type": "object", - "properties": { - "credential": { - "description": "Verifiable Credential to be revoked as a VC-JWT string or a JSON object.", - "oneOf": [ - { - "type": "object" - }, - { - "type": "string" - } - ] - }, - "symmetricKey": { - "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource. Required if the StatusList2021 DID-Linked Resource is encrypted.", - "type": "string" - } - } - }, - "RevocationResult": { - "properties": { - "revoked": { - "type": "boolean", - "example": true - } - } - }, - "SuspensionResult": { - "properties": { - "suspended": { - "type": "boolean", - "example": true - } - } - }, - "UnsuspensionResult": { - "properties": { - "unsuspended": { - "type": "boolean", - "example": true - } - } - }, - "CredentialVerifyRequest": { - "type": "object", - "properties": { - "credential": { - "description": "Verifiable Credential to be verified as a VC-JWT string or a JSON object.", - "type": "object" - }, - "policies": { - "description": "Custom verification policies to execute when verifying credential.", - "type": "object", - "properties": { - "issuanceDate": { - "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "expirationDate": { - "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "audience": { - "description": "Policy to skip the audience check when set to `false`.", - "type": "boolean", - "default": false - } - } - } - } - }, - "VerifyPresentationResult": { - "type": "object", - "properties": { - "verified": { - "type": "boolean" - }, - "issuer": { - "type": "string" - }, - "signer": { - "type": "object" - }, - "jwt": { - "type": "string" - }, - "verifiableCredential": { - "type": "object" - } - } - }, - "VerifyCredentialResult": { - "type": "object", - "properties": { - "verified": { - "type": "boolean" - }, - "issuer": { - "type": "string" - }, - "signer": { - "type": "object" - }, - "jwt": { - "type": "string" - }, - "verifiableCredential": { - "type": "object" - } - }, - "example": { - "verified": true, - "polices": {}, - "issuer": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "signer": { - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", - "type": "Ed25519VerificationKey2018" - } - } - }, - "PresentationCreateRequest": { - "type": "object", - "required": [ - "credentials" - ], - "properties": { - "credentials": { - "description": "Verifiable Credentials to be used for VP-JWT creation as a VP-JWT strings or a JSON objectsf.", - "type": "array", - "items": { - "type": "object" - } - }, - "holderDid": { - "description": "DID of holder", - "type": "string" - }, - "verifierDid": { - "description": "DID of verifier", - "type": "string" - } - } - }, - "PresentationVerifyRequest": { - "type": "object", - "required": [ - "presentation" - ], - "properties": { - "presentation": { - "description": "Verifiable Presentation to be verified as a VP-JWT string or a JSON object.", - "type": "object" - }, - "verifierDid": { - "description": "Provide an optional verifier DID (also known as 'domain' parameter), if the verifier DID in the presentation is not managed in the wallet.", - "type": "string" - }, - "makeFeePayment": { - "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", - "type": "boolean", - "default": false - }, - "policies": { - "description": "Custom verification policies to execute when verifying presentation.", - "type": "object", - "properties": { - "issuanceDate": { - "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "expirationDate": { - "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "audience": { - "description": "Policy to skip the audience check when set to `false`.", - "type": "boolean", - "default": false - } - } - } - } - }, - "CredentialStatusCreateBody": { - "allOf": [ - { - "type": "object", - "required": [ - "did", - "statusListName" - ], - "properties": { - "did": { - "description": "DID of the StatusList2021 publisher.", - "type": "string", - "format": "uri" - }, - "statusListName": { - "description": "The name of the StatusList2021 DID-Linked Resource to be created.", - "type": "string" - }, - "length": { - "description": "The length of the status list to be created. The default and minimum length is 140000 which is 16kb.", - "type": "integer", - "minimum": 0, - "exclusiveMinimum": true, - "default": 140000 - }, - "encoding": { - "description": "The encoding format of the StatusList2021 DiD-Linked Resource to be created.", - "type": "string", - "default": "base64url", - "enum": [ - "base64url", - "base64", - "hex" - ] - }, - "statusListVersion": { - "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - { - "$ref": "#/components/schemas/AlsoKnownAs" - } - ] - }, - "CredentialStatusCreateUnencryptedRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCreateBody" - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials", - "length": 140000, - "encoding": "base64url" - } - }, - "CredentialStatusUnencryptedResult": { - "type": "object", - "properties": { - "resource": { - "type": "object", - "properties": { - "StatusList2021": { - "type": "object", - "properties": { - "encodedList": { - "type": "string", - "example": "H4sIAAAAAAAAA-3BAQ0AAADCoPdPbQ8HFAAAAAAAAAAAAAAAAAAAAADwaDhDr_xcRAAA" - }, - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "validFrom": { - "type": "string", - "format": "date-time", - "example": "2023-06-26T11:45:19.349Z" - } - } - }, - "metadata": { - "type": "object", - "properties": { - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "encoding": { - "type": "string", - "example": "base64url" - }, - "encrypted": { - "type": "boolean", - "example": false - } - } - } - } - }, - "resourceMetadata": { - "type": "object", - "example": { - "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceName": "cheqd-employee-credentials", - "resourceType": "StatusList2021Revocation", - "mediaType": "application/json", - "resourceVersion": "1.0.0", - "created": "2023-06-26T11:45:20Z", - "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", - "previousVersionId": null, - "nextVersionId": null - } - } - } - }, - "CredentialStatusCreateUnencryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "created": { - "type": "boolean", - "example": true - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" - } - ] - }, - "CredentialStatusEncryptedPaymentConditionsBody": { - "type": "object", - "properties": { - "feePaymentAddress": { - "description": "The cheqd/Cosmos payment address where payments to unlock the encrypted StatusList2021 DID-Linked Resource need to be sent.", - "type": "string", - "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" - }, - "feePaymentAmount": { - "description": "Amount in CHEQ tokens to unlock the encrypted StatusList2021 DID-Linked Resource.", - "type": "number", - "minimum": 0, - "exclusiveMinimum": true, - "default": 20 - }, - "feePaymentWindow": { - "description": "Time window (in minutes) within which the payment to unlock the encrypted StatusList2021 DID-Linked Resource is considered valid.", - "type": "number", - "minimum": 0, - "exclusiveMinimum": true, - "default": 10 - } - } - }, - "CredentialStatusEncryptedPaymentConditionsJson": { - "type": "object", - "properties": { - "paymentConditions": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" - } - ] - } - } - }, - "CredentialStatusCreateEncryptedFormRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCreateBody" - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" - }, - { - "type": "object", - "required": [ - "feePaymentAddress", - "feePaymentAmount", - "feePaymentWindow" - ] - } - ] - }, - "CredentialStatusCreateEncryptedJsonRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCreateBody" - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" - }, - { - "type": "object", - "required": [ - "paymentConditions" - ] - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials-encrypted", - "paymentConditions": [ - { - "feePaymentAddress": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg", - "feePaymentAmount": 20, - "feePaymentWindow": 10 - } - ] - } - }, - "CredentialStatusEncryptedResult": { - "type": "object", - "properties": { - "resource": { - "type": "object", - "properties": { - "StatusList2021": { - "type": "object", - "properties": { - "encodedList": { - "type": "string", - "example": "496fdfbeb745b4db03fcdb40566f9c4c4a1c0f184b31255e641b6e7bdfb9b6946c12be87ca3763be0393c00b67ac1e8737c106b32f46ef59c765754415b5e8cc7c65fccaa3374620430ea476301a5e0dd63340e7a27a68bc627518471f22e4a2" - }, - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "validFrom": { - "type": "string", - "format": "date-time", - "example": "2023-06-26T11:45:19.349Z" - } - } - }, - "metadata": { - "type": "object", - "properties": { - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "encoding": { - "type": "string", - "example": "base64url" - }, - "encrypted": { - "type": "boolean", - "example": true - }, - "encryptedSymmetricKey": { - "type": "string", - "example": "b11182dc524b8181f9a6aef4c4ad0a1c14e40033b9112dffd8d1bcf6cc3b85abc07ded2205ee94068a99f4202502cb0855f322583fa6ce1534d3a05bf36891766ea2c5f90a982b3040680762977d404d758a2370224a239c8279aa7d21e980931c42055b17ca4c7dbffa4782480a8b6279cf989b2f166d5fdb4b2c1b5a63927200000000000000203018dcaba26df45a415bb599218b27ca853a70289d7a3ed3ed0e3730452e8f8d9af91b6e71312565d2c069341f6660ab" - }, - "paymentConditions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "feePaymentAddress": { - "type": "string", - "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" - }, - "feePaymentAmount": { - "type": "string", - "example": "20000000000ncheq" - }, - "intervalInSeconds": { - "type": "number", - "example": 600 - }, - "type": { - "type": "string", - "example": "timelockPayment" - } - } - } - } - } - }, - "resourceMetadata": { - "type": "object", - "example": { - "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceName": "cheqd-revocation-encrypted-1", - "resourceType": "StatusList2021Revocation", - "mediaType": "application/json", - "resourceVersion": "2023-06-26T11:45:19.349Z", - "created": "2023-06-26T11:45:20Z", - "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", - "previousVersionId": null, - "nextVersionId": null - } - }, - "symmetricKey": { - "type": "string", - "example": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" - } - } - } - } - }, - "CredentialStatusCreateEncryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "created": { - "type": "boolean", - "example": true - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedResult" - } - ] - }, - "CredentialStatusUpdateBody": { - "type": "object", - "required": [ - "did", - "statusListName", - "indices" - ], - "properties": { - "did": { - "description": "DID of the StatusList2021 publisher.", - "type": "string", - "format": "uri" - }, - "statusListName": { - "description": "The name of the StatusList2021 DID-Linked Resource to be updated.", - "type": "string" - }, - "indices": { - "description": "List of credential status indices to be updated. The indices must be in the range of the status list.", - "type": "array", - "items": { - "type": "integer", - "minimum": 0, - "exclusiveMinimum": false - } - }, - "statusListVersion": { - "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - "CredentialStatusUpdateUnencryptedRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUpdateBody" - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials", - "indices": [ - 10, - 3199, - 12109, - 130999 - ] - } - }, - "CredentialStatusUpdateUnencryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "updated": { - "type": "boolean", - "example": true - } - } - }, - { - "oneOf": [ - { - "$ref": "#/components/schemas/RevocationResult" - }, - { - "$ref": "#/components/schemas/SuspensionResult" - }, - { - "$ref": "#/components/schemas/UnsuspensionResult" - } - ] - }, - { - "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" - } - ] - }, - "CredentialStatusUpdateEncryptedFormRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUpdateBody" - }, - { - "type": "object", - "required": [ - "symmetricKey" - ], - "properties": { - "symmetricKey": { - "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" - } - ] - }, - "CredentialStatusUpdateEncryptedJsonRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUpdateBody" - }, - { - "type": "object", - "required": [ - "symmetricKey" - ], - "properties": { - "symmetricKey": { - "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials-encrypted", - "indices": [ - 10, - 3199, - 12109, - 130999 - ], - "symmetricKey": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" - } - }, - "CredentialStatusUpdateEncryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "updated": { - "type": "boolean", - "example": true - } - } - }, - { - "oneOf": [ - { - "$ref": "#/components/schemas/RevocationResult" - }, - { - "$ref": "#/components/schemas/SuspensionResult" - }, - { - "$ref": "#/components/schemas/UnsuspensionResult" - } - ] - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedResult" - } - ] - }, - "CredentialStatusCheckRequest": { - "type": "object", - "required": [ - "did", - "statusListName", - "index" - ], - "properties": { - "did": { - "description": "DID of the StatusList2021 publisher.", - "type": "string", - "format": "uri" - }, - "statusListName": { - "description": "The name of the StatusList2021 DID-Linked Resource to be checked.", - "type": "string" - }, - "index": { - "description": "Credential status index to be checked for revocation or suspension.", - "type": "integer", - "minimum": 0, - "exclusiveMinimum": false - }, - "makeFeePayment": { - "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", - "type": "boolean", - "default": true - } - } - }, - "CredentialStatusCheckResult": { - "oneOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCheckRevocationResult" - }, - { - "$ref": "#/components/schemas/CredentialStatusCheckSuspensionResult" - } - ] - }, - "CredentialStatusCheckRevocationResult": { - "type": "object", - "properties": { - "checked": { - "type": "boolean", - "example": true - }, - "revoked": { - "type": "boolean", - "example": false - } - } - }, - "CredentialStatusCheckSuspensionResult": { - "type": "object", - "properties": { - "checked": { - "type": "boolean", - "example": true - }, - "suspended": { - "type": "boolean", - "example": false - } - } - }, - "CredentialStatusListSearchResult": { - "allOf": [ - { - "type": "object", - "properties": { - "found": { - "type": "boolean", - "example": true - } - } - }, - { - "oneOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedResult" - } - ] - } - ] - }, - "KeyImportRequest": { - "type": "object", - "properties": { - "alias": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "Ed25519", - "Secp256k1" - ] - }, - "privateKeyHex": { - "type": "string" - } - } - }, - "KeyResult": { - "type": "object", - "properties": { - "kid": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "Ed25519", - "Secp256k1" - ] - }, - "publicKeyHex": { - "type": "string" - } - } - }, - "DidDocument": { - "description": "This input field contains either a complete DID document, or an incremental change (diff) to a DID document. See Universal DID Registrar specification.", - "type": "object", - "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - } - }, - "id": { - "type": "string" - }, - "controllers": { - "type": "array", - "items": { - "type": "string" - } - }, - "verificationMethod": { - "type": "array", - "items": { - "$ref": "#/components/schemas/VerificationMethod" - } - }, - "service": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "authentication": { - "type": "array", - "items": { - "type": "string" - } - }, - "assertionMethod": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityInvocation": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityDelegation": { - "type": "array", - "items": { - "type": "string" - } - }, - "keyAgreement": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "@context": [ - "https://www.w3.org/ns/did/v1" - ], - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "controller": [ - "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - ], - "verificationMethod": [ - { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "type": "Ed25519VerificationKey2018", - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "publicKeyBase58": "z6MkkVbyHJLLjdjU5B62DaJ4mkdMdUkttf9UqySSkA9bVTeZ" - } - ], - "authentication": [ - "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1" - ], - "service": [ - { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", - "type": "LinkedDomains", - "serviceEndpoint": [ - "https://example.com" - ] - } - ] - } - }, - "DidDocumentWithoutVerificationMethod": { - "type": "object", - "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - } - }, - "id": { - "type": "string" - }, - "controllers": { - "type": "array", - "items": { - "type": "string" - } - }, - "service": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "authentication": { - "type": "array", - "items": { - "type": "string" - } - }, - "assertionMethod": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityInvocation": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityDelegation": { - "type": "array", - "items": { - "type": "string" - } - }, - "keyAgreement": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "@context": [ - "https://www.w3.org/ns/did/v1" - ], - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "controller": [ - "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - ], - "authentication": [ - "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1" - ], - "service": [ - { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", - "type": "LinkedDomains", - "serviceEndpoint": [ - "https://example.com" - ] - } - ] - } - }, - "DidCreateRequestFormBased": { - "type": "object", - "properties": { - "network": { - "description": "Network to create the DID on (testnet or mainnet)", - "type": "string", - "enum": [ - "testnet", - "mainnet" - ] - }, - "identifierFormatType": { - "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", - "type": "string", - "enum": [ - "uuid", - "base58btc" - ] - }, - "verificationMethodType": { - "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", - "type": "string", - "enum": [ - "Ed25519VerificationKey2018", - "JsonWebKey2020", - "Ed25519VerificationKey2020" - ] - }, - "service": { - "description": "It's a list of special objects which are designed to build the actual service. It's almost the same as in DID Core specification, but instead of `id` it utilises `idFragment` field for making the right `id` for each service. !!! WARN. Cause swagger-ui does not handle x-ww-form based arrays correctly, please frame all your services in brackets while using swagger UI. !!!", - "type": "array", - "items": { - "type": "object", - "properties": { - "idFragment": { - "type": "string" - }, - "type": { - "type": "string" - }, - "serviceEndpoint": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "example": [ - { - "idFragment": "service-1", - "type": "LinkedDomains", - "serviceEndpoint": [ - "https://example.com" - ] - } - ] - }, - "key": { - "description": "The unique identifier in hexadecimal public key format used in the verification method to create the DID.", - "type": "string" - }, - "@context": { - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "https://www.w3.org/ns/did/v1" - ] - } - } - }, - "DidCreateRequestJson": { - "type": "object", - "properties": { - "network": { - "description": "Network to create the DID on (testnet or mainnet)", - "type": "string", - "enum": [ - "testnet", - "mainnet" - ] - }, - "identifierFormatType": { - "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", - "type": "string", - "enum": [ - "uuid", - "base58btc" - ] - }, - "assertionMethod": { - "description": "Usually a reference to a Verification Method. An Assertion Method is required to issue JSON-LD credentials. See DID Core specification for more details.", - "type": "boolean", - "default": true - }, - "options": { - "type": "object", - "properties": { - "key": { - "type": "string", - "example": "8255ddadd75695e01f3d98fcec8ccc7861a030b317d4326b0e48a4d579ddc43a" - }, - "verificationMethodType": { - "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", - "type": "string", - "enum": [ - "Ed25519VerificationKey2018", - "JsonWebKey2020", - "Ed25519VerificationKey2020" - ] - } - } - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocumentWithoutVerificationMethod" - } - } - }, - "DidImportRequest": { - "type": "object", - "properties": { - "did": { - "type": "string", - "description": "DID to be imported", - "format": "uri", - "required": true - }, - "keys": { - "type": "array", - "description": "List of keys required to import the DID", - "required": true, - "items": { - "$ref": "#/components/schemas/KeyImportRequest" - } - } - } - }, - "PresentationCreateResult": { - "type": "object", - "properties": { - "vp": { - "type": "object", - "description": "Verifiable Presentation which could be provided to the verifier." - }, - "nbf": { - "type": "integer", - "description": "Unix timestamp of the earliest time that the Verifiable Presentation is valid." - }, - "iss": { - "type": "string", - "description": "DID of the issuer of the Verifiable Presentation. (Here it's supposed to be a holder DID)" - }, - "aud": { - "type": "array", - "items": { - "type": "string" - }, - "description": "DID of the verifier of the Verifiable Presentation." - } - }, - "example": { - "vp": { - "@context": [ - "https://www.w3.org/2018/credentials/v1" - ], - "type": [ - "VerifiablePresentation" - ], - "verifiableCredential": [ - "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc2NoZW1hLm9yZy9zY2hlbWEuanNvbmxkIiwiaHR0cHM6Ly92ZXJhbW8uaW8vY29udGV4dHMvcHJvZmlsZS92MSIsImh0dHBzOi8vdzNpZC5vcmcvdmMtc3RhdHVzLWxpc3QtMjAyMS92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiUGVyc29uIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7Im5hbWUiOiJCb2IiLCJnZW5kZXIiOiJtYWxlIn0sImNyZWRlbnRpYWxTdGF0dXMiOnsiaWQiOiJodHRwczovL3Jlc29sdmVyLmNoZXFkLm5ldC8xLjAvaWRlbnRpZmllcnMvZGlkOmNoZXFkOnRlc3RuZXQ6OTBkNWMxNDEtNzI0Zi00N2FkLTlhZTctYTdjMzNhOWU1NjQzP3Jlc291cmNlTmFtZT1zdXNwZW5zaW9uRW4mcmVzb3VyY2VUeXBlPVN0YXR1c0xpc3QyMDIxU3VzcGVuc2lvbiMxMzMzOCIsInR5cGUiOiJTdGF0dXNMaXN0MjAyMUVudHJ5Iiwic3RhdHVzUHVycG9zZSI6InN1c3BlbnNpb24iLCJzdGF0dXNMaXN0SW5kZXgiOiIxMzMzOCJ9fSwic3ViIjoiZGlkOmtleTp6Nk1raGFYZ0JaRHZvdERrTDUyNTdmYWl6dGlHaUMyUXRLTEdwYm5uRUd0YTJkb0siLCJuYmYiOjE3MDA0NzM0MTYsImlzcyI6ImRpZDpjaGVxZDp0ZXN0bmV0OjkwZDVjMTQxLTcyNGYtNDdhZC05YWU3LWE3YzMzYTllNTY0MyJ9.-14Ril1pZEy2HEEo48gTJr2yOtGxBhUGTFmzVdjAtyhFRsW5zZg9onHt6V9JQ8BaiYBlTkP9GzTnJ-O6hdiyCw" - ] - }, - "nbf": 1700744275, - "iss": "did:cheqd:testnet:4b846d0f-2f6c-4ab6-9fe2-5b8db301c83c", - "aud": [ - "did:cheqd:testnet:8c71e9b6-c5a3-4250-8c58-fa591533cd22" - ] - } - }, - "DidResult": { - "type": "object", - "properties": { - "did": { - "type": "string" - }, - "controllerKeyId": { - "type": "string" - }, - "keys": { - "type": "array", - "items": { - "type": "object" - } - }, - "services": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - } - } - }, - "DidUpdateResponse": { - "type": "object", - "properties": { - "did": { - "type": "string" - }, - "controllerKeyId": { - "type": "string", - "description": "The default key id of which is the key associated with the first verificationMethod" - }, - "keys": { - "type": "array", - "description": "The list of keys associated with the list of verificationMethod's of DIDDocument", - "items": { - "type": "object" - } - }, - "services": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "controllerKeyRefs": { - "type": "array", - "description": "The list of keyRefs which were used for signing the transaction", - "items": { - "type": "string" - } - }, - "controllerKeys": { - "type": "array", - "description": "The list of all possible keys, inlcuding all controller's keys", - "items": { - "type": "string" - } - } - } - }, - "VerificationMethod": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string" - }, - "controller": { - "type": "string" - }, - "publicKeyMultibase": { - "type": "string" - }, - "publicKeyJwk": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "id": "did:cheqd:testnet :7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", - "type": "Ed25519VerificationKey2018" - } - }, - "Service": { - "description": "Communicating or interacting with the DID subject or associated entities via one or more service endpoints. See DID Core specification for more details.", - "type": "object", - "properties": { - "id": { - "description": "DID appended with Service fragment ID (e.g., `#service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`)", - "type": "string", - "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1" - }, - "type": { - "description": "Service type as defined in DID Specification Registries.", - "type": "string", - "example": "LinkedDomains" - }, - "serviceEndpoint": { - "description": "Service endpoint as defined in DID Core Specification.", - "type": "array", - "items": { - "type": "string", - "example": "https://example.com" - } - } - } - }, - "DidUpdateRequest": { - "type": "object", - "properties": { - "did": { - "description": "DID identifier to be updated.", - "type": "string", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "service": { - "type": "array", - "description": "Service section of the DID Document.", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "verificationMethod": { - "type": "array", - "description": "Verification Method section of the DID Document.", - "items": { - "$ref": "#/components/schemas/VerificationMethod" - } - }, - "authentication": { - "description": "Authentication section of the DID Document.", - "type": "array", - "items": { - "type": "string" - } - }, - "publicKeyHexs": { - "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", - "type": "array", - "items": { - "type": "string" - } - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - } - } - }, - "DidDeactivateRequest": { - "type": "object", - "properties": { - "publicKeyHexs": { - "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "CreateResourceRequest": { - "description": "Input fields for DID-Linked Resource creation.", - "type": "object", - "additionalProperties": false, - "required": [ - "name", - "type", - "data", - "encoding" - ], - "properties": { - "data": { - "description": "Encoded string containing the data to be stored in the DID-Linked Resource.", - "type": "string" - }, - "encoding": { - "description": "Encoding format used to encode the data.", - "type": "string", - "enum": [ - "base64url", - "base64", - "hex" - ] - }, - "name": { - "description": "Name of DID-Linked Resource.", - "type": "string" - }, - "type": { - "description": "Type of DID-Linked Resource. This is NOT the same as the media type, which is calculated automatically ledger-side.", - "type": "string" - }, - "alsoKnownAs": { - "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", - "type": "array", - "items": { - "type": "object", - "properties": { - "uri": { - "type": "string" - }, - "description": { - "type": "string" - } - } - } - }, - "version": { - "description": "Optional field to assign a human-readable version in the DID-Linked Resource.", - "type": "string" - }, - "publicKeyHexs": { - "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "data": "SGVsbG8gV29ybGQ=", - "encoding": "base64url", - "name": "ResourceName", - "type": "TextDocument" - } - }, - "ResourceList": { - "type": "object", - "properties": { - "@context": { - "type": "string", - "example": "https://w3id.org/did-resolution/v1" - }, - "contentMetadata": { - "type": "object" - }, - "contentStream": { - "type": "object" - }, - "dereferencingMetadata": { - "$ref": "#/components/schemas/DereferencingMetadata" - } - } - }, - "DereferencingMetadata": { - "type": "object", - "properties": { - "contentType": { - "type": "string", - "example": "application/did+ld+json" - }, - "did": { - "$ref": "#/components/schemas/DidProperties" - }, - "retrieved": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - } - } - }, - "DidResolution": { - "type": "object", - "properties": { - "@context": { - "type": "string", - "example": "https://w3id.org/did-resolution/v1" - }, - "didDidResolutionMetadata": { - "$ref": "#/components/schemas/DidResolutionMetadata" - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - }, - "didDocumentMetadata": { - "$ref": "#/components/schemas/DidDocumentMetadata" - } - } - }, - "DeactivatedDidResolution": { - "type": "object", - "properties": { - "@context": { - "type": "string", - "example": "https://w3id.org/did-resolution/v1" - }, - "didDidResolutionMetadata": { - "$ref": "#/components/schemas/DidResolutionMetadata" - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - }, - "didDocumentMetadata": { - "$ref": "#/components/schemas/DeactivatedDidDocumentMetadata" - } - } - }, - "DidDocumentMetadata": { - "type": "object", - "properties": { - "created": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "deactivated": { - "type": "boolean", - "example": false - }, - "updated": { - "type": "string", - "example": "2021-09-10T12:00:00Z" - }, - "versionId": { - "type": "string", - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - "linkedResourceMetadata": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ResourceMetadata" - } - } - } - }, - "DeactivatedDidDocumentMetadata": { - "type": "object", - "properties": { - "created": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "deactivated": { - "type": "boolean", - "example": true - }, - "updated": { - "type": "string", - "example": "2021-09-10T12:00:00Z" - }, - "versionId": { - "type": "string", - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - "linkedResourceMetadata": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ResourceMetadata" - } - } - } - }, - "ResourceMetadata": { - "type": "object", - "properties": { - "resourceURI": { - "type": "string", - "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47/resources/398cee0a-efac-4643-9f4c-74c48c72a14b" - }, - "resourceCollectionId": { - "type": "string", - "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" - }, - "resourceId": { - "type": "string", - "example": "398cee0a-efac-4643-9f4c-74c48c72a14b" - }, - "resourceName": { - "type": "string", - "example": "cheqd-issuer-logo" - }, - "resourceType": { - "type": "string", - "example": "CredentialArtwork" - }, - "mediaType": { - "type": "string", - "example": "image/png" - }, - "resourceVersion": { - "type": "string", - "example": "1.0" - }, - "checksum": { - "type": "string", - "example": "a95380f460e63ad939541a57aecbfd795fcd37c6d78ee86c885340e33a91b559" - }, - "created": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "nextVersionId": { - "type": "string", - "example": "d4829ac7-4566-478c-a408-b44767eddadc" - }, - "previousVersionId": { - "type": "string", - "example": "ad7a8442-3531-46eb-a024-53953ec6e4ff" - } - } - }, - "DidResolutionMetadata": { - "type": "object", - "properties": { - "contentType": { - "allOf": [ - { - "$ref": "#/components/schemas/ContentType" - } - ], - "example": "application/did+ld+json" - }, - "retrieved": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "did": { - "$ref": "#/components/schemas/DidProperties" - } - } - }, - "ContentType": { - "type": "string", - "enum": [ - "application/did+json", - "application/did+ld+json", - "application/ld+json", - "application/json" - ] - }, - "DidProperties": { - "type": "object", - "properties": { - "didString": { - "type": "string", - "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" - }, - "method": { - "type": "string", - "example": "cheqd" - }, - "methodSpecificId": { - "type": "string", - "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" - } - } - }, - "Customer": { - "type": "object", - "properties": { - "customerId": { - "type": "string", - "example": "6w5drpiiwhhs" - }, - "address": { - "type": "string", - "example": "cheqd1wgsvqwlkmdp60f4dek26ak0sjw6au3ytd3pz7f" - } - } - }, - "AccountCreateRequest": { - "type": "object", - "properties": { - "user": { - "type": "object", - "properties": { - "primaryEmail": { - "type": "string" - } - } - } - } - }, - "InvalidRequest": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "InvalidRequest" - } - } - }, - "InternalError": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Internal Error" - } - } - }, - "UnauthorizedError": { - "description": "Access token is missing or invalid", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Unauthorized Error" - } - } - } - } - } -} \ No newline at end of file + "openapi": "3.0.0", + "info": { + "title": "Credential Service API for cheqd network", + "version": "2.0.0", + "description": "API service to create and manage DIDs, Verifiable Credentials, and DID-Linked Resources", + "contact": { + "name": "Cheqd Foundation Limited", + "url": "https://github.com/cheqd/credential-service", + "email": "support-github@cheqd.io" + }, + "license": { + "name": "Apache 2.0", + "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" + } + }, + "tags": [ + { + "name": "Account" + }, + { + "name": "Key" + }, + { + "name": "DID" + }, + { + "name": "Resource" + }, + { + "name": "Credential" + }, + { + "name": "Presentation" + }, + { + "name": "Credential Status" + } + ], + "externalDocs": { + "description": "Credential Service API Documentation", + "url": "https://docs.cheqd.io/identity" + }, + "paths": { + "/account": { + "get": { + "tags": ["Account"], + "summary": "Fetch custodian-mode client details.", + "description": "This endpoint returns the custodian-mode client details for authenticated users.", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Customer" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/account/idtoken": { + "get": { + "tags": ["Account"], + "summary": "Fetch IdToken.", + "description": "This endpoint returns IdToken as JWT with list of user roles inside", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "idToken": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/account/create": { + "post": { + "tags": ["Account"], + "summary": "Create an client for an authenticated user.", + "description": "This endpoint creates a client in the custodian-mode for an authenticated user", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/AccountCreateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "idToken": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/create/unencrypted": { + "post": { + "tags": ["Credential Status"], + "summary": "Create an unencrypted StatusList2021 credential status list.", + "description": "This endpoint creates an unencrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", + "required": true, + "schema": { + "type": "string", + "enum": ["revocation", "suspension"] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/create/encrypted": { + "post": { + "tags": ["Credential Status"], + "summary": "Create an encrypted StatusList2021 credential status list.", + "description": "This endpoint creates an encrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", + "required": true, + "schema": { + "type": "string", + "enum": ["revocation", "suspension"] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateEncryptedFormRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateEncryptedJsonRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateEncryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/update/unencrypted": { + "post": { + "tags": ["Credential Status"], + "summary": "Update an existing unencrypted StatusList2021 credential status list.", + "parameters": [ + { + "in": "query", + "name": "statusAction", + "description": "The update action to be performed on the unencrypted status list, can be revoke, suspend or reinstate", + "required": true, + "schema": { + "type": "string", + "enum": ["revoke", "suspend", "reinstate"] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/update/encrypted": { + "post": { + "tags": ["Credential Status"], + "summary": "Update an existing encrypted StatusList2021 credential status list.", + "parameters": [ + { + "in": "query", + "name": "statusAction", + "description": "The update action to be performed on the encrypted status list, can be revoke, suspend or reinstate", + "required": true, + "schema": { + "type": "string", + "enum": ["revoke", "suspend", "reinstate"] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedFormRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedJsonRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/check": { + "post": { + "tags": ["Credential Status"], + "summary": "Check a StatusList2021 index for a given Verifiable Credential.", + "description": "This endpoint checks a StatusList2021 index for a given Verifiable Credential and reports whether it is revoked or suspended. It offers a standalone method for checking an index without passing the entire Verifiable Credential or Verifiable Presentation.", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension.", + "required": true, + "schema": { + "type": "string", + "enum": ["revocation", "suspension"] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCheckRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCheckRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCheckResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/search": { + "get": { + "tags": ["Credential Status"], + "summary": "Fetch StatusList2021 DID-Linked Resource based on search criteria.", + "parameters": [ + { + "in": "query", + "name": "did", + "description": "The DID of the issuer of the status list.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension.", + "schema": { + "type": "string", + "enum": ["revocation", "suspension"] + } + }, + { + "in": "query", + "name": "statusListName", + "description": "The name of the StatusList2021 DID-Linked Resource.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusListSearchResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/issue": { + "post": { + "tags": ["Credential"], + "summary": "Issue a Verifiable Credential", + "description": "This endpoint issues a Verifiable Credential. As input it takes the list of issuerDid, subjectDid, attributes, and other parameters of the credential to be issued.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Credential" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/verify": { + "post": { + "tags": ["Credential"], + "summary": "Verify a Verifiable Credential.", + "description": "This endpoint verifies a Verifiable Credential passed to it. As input, it can take the VC-JWT as a string or the entire credential itself.", + "operationId": "verify", + "parameters": [ + { + "in": "query", + "name": "verifyStatus", + "description": "If set to `true` the verification will also check the status of the credential. Requires the VC to have a `credentialStatus` property.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "fetchRemoteContexts", + "description": "When dealing with JSON-LD you also MUST provide the proper contexts. Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "allowDeactivatedDid", + "description": "If set to `true` allow to verify credential which based on deactivated DID.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialVerifyRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialVerifyRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyCredentialResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/revoke": { + "post": { + "tags": ["Credential"], + "summary": "Revoke a Verifiable Credential.", + "description": "This endpoint revokes a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself. The StatusList2021 resource should already be setup in the VC and `credentialStatus` property present in the VC.", + "operationId": "revoke", + "parameters": [ + { + "in": "query", + "name": "publish", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RevocationResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/suspend": { + "post": { + "tags": ["Credential"], + "summary": "Suspend a Verifiable Credential.", + "description": "This endpoint suspends a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself.", + "operationId": "suspend", + "parameters": [ + { + "in": "query", + "name": "publish", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuspensionResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/reinstate": { + "post": { + "tags": ["Credential"], + "summary": "Reinstate a suspended Verifiable Credential.", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "operationId": "reinstate", + "parameters": [ + { + "in": "query", + "name": "publish", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnsuspensionResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/create": { + "post": { + "tags": ["DID"], + "summary": "Create a DID Document.", + "description": "This endpoint creates a DID and associated DID Document. As input, it can take the DID Document parameters via a form, or the fully-assembled DID Document itself.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidCreateRequestFormBased" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidCreateRequestJson" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/did/update": { + "post": { + "tags": ["DID"], + "summary": "Update a DID Document.", + "description": "This endpoint updates a DID Document. As an input, it can take JUST the sections/parameters that need to be updated in the DID Document (in this scenario, it fetches the current DID Document and applies the updated section). Alternatively, it take the fully-assembled DID Document with updated sections as well as unchanged sections.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidUpdateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidUpdateResponse" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/import": { + "post": { + "tags": ["DID"], + "summary": "Import a DID Document.", + "description": "This endpoint imports a decentralized identifier associated with the user's account for custodian-mode clients.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidImportRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidImportRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/did/deactivate/{did}": { + "post": { + "tags": ["DID"], + "summary": "Deactivate a DID Document.", + "description": "This endpoint deactivates a DID Document by taking the DID identifier as input. Must be called and signed by the DID owner.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier to deactivate.", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidDeactivateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidDeactivateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeactivatedDidResolution" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/list": { + "get": { + "tags": ["DID"], + "summary": "Fetch DIDs associated with an account.", + "description": "This endpoint returns the list of DIDs controlled by the account.", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/search/{did}": { + "get": { + "tags": ["DID"], + "summary": "Resolve a DID Document.", + "description": "Resolve a DID Document by DID identifier. Also supports DID Resolution Queries as defined in the W3C DID Resolution specification.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier to resolve.", + "schema": { + "type": "string" + }, + "required": true, + "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + { + "in": "query", + "name": "metadata", + "description": "Return only metadata of DID Document instead of actual DID Document.", + "schema": { + "type": "boolean" + } + }, + { + "in": "query", + "name": "versionId", + "description": "Unique UUID version identifier of DID Document. Allows for fetching a specific version of the DID Document. See cheqd DID Method Specification for more details.", + "schema": { + "type": "string", + "format": "uuid" + }, + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + { + "in": "query", + "name": "versionTime", + "description": "Returns the closest version of the DID Document *at* or *before* specified time. See DID Resolution handling for `did:cheqd` for more details.", + "schema": { + "type": "string", + "format": "date-time" + }, + "example": "1970-01-01T00:00:00Z" + }, + { + "in": "query", + "name": "transformKeys", + "description": "This directive transforms the Verification Method key format from the version in the DID Document to the specified format chosen below.", + "schema": { + "type": "string", + "enum": ["Ed25519VerificationKey2018", "Ed25519VerificationKey2020", "JsonWebKey2020"] + } + }, + { + "in": "query", + "name": "service", + "description": "Query DID Document for a specific Service Endpoint by Service ID (e.g., `service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`). This will typically redirect to the Service Endpoint based on DID Resolution specification algorithm.", + "schema": { + "type": "string" + }, + "example": "service-1" + }, + { + "in": "query", + "name": "relativeRef", + "description": "Relative reference is a query fragment appended to the Service Endpoint URL. **Must** be used along with the `service` query property above. See DID Resolution specification algorithm for more details.", + "schema": { + "type": "string" + }, + "example": "/path/to/file" + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResolution" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/key/create": { + "post": { + "tags": ["Key"], + "summary": "Create an identity key pair.", + "description": "This endpoint creates an identity key pair associated with the user's account for custodian-mode clients.", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/key/import": { + "post": { + "tags": ["Key"], + "summary": "Import an identity key pair.", + "description": "This endpoint imports an identity key pair associated with the user's account for custodian-mode clients.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/KeyImportRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyImportRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/key/read/{kid}": { + "get": { + "tags": ["Key"], + "summary": "Fetch an identity key pair.", + "description": "This endpoint fetches an identity key pair's details for a given key ID. Only the user account associated with the custodian-mode client can fetch the key pair.", + "parameters": [ + { + "name": "kid", + "description": "Key ID of the identity key pair to fetch.", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/presentation/create": { + "post": { + "tags": ["Presentation"], + "summary": "!!! WARN. Such endpoint is made mostly for testing purposes and it is not supposed to be used in production !!! Create a Verifiable Presentation from credential(s).", + "description": "This endpoint creates a Verifiable Presentation from credential(s). As input, it can take the credential(s) as a string or the entire credential(s) itself. \n !!! WARN. Such endpoint is made only for testing purposes !!!", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/PresentationCreateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationCreateResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/presentation/verify": { + "post": { + "tags": ["Presentation"], + "summary": "Verify a Verifiable Presentation generated from credential(s).", + "description": "This endpoint verifies the Verifiable Presentation generated from credential(s). As input, it can take the Verifiable Presentation JWT as a string or the entire Verifiable Presentation itself.", + "parameters": [ + { + "in": "query", + "name": "verifyStatus", + "description": "If set to `true` the verification will also check the status of the presentation. Requires the VP to have a `credentialStatus` property.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "fetchRemoteContexts", + "description": "When dealing with JSON-LD you also MUST provide the proper contexts. * Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "allowDeactivatedDid", + "description": "If set to `true` allow to verify credential which based on deactivated DID.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/PresentationVerifyRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationVerifyRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyPresentationResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/resource/create/{did}": { + "post": { + "tags": ["Resource"], + "summary": "Create a DID-Linked Resource.", + "description": "This endpoint creates a DID-Linked Resource. As input, it can take the DID identifier and the resource parameters via a form, or the fully-assembled resource itself.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier to link the resource to.", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CreateResourceRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateResourceRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceMetadata" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/resource/search/{did}": { + "get": { + "tags": ["Resource"], + "summary": "Get a DID-Linked Resource.", + "description": "This endpoint returns the DID-Linked Resource for a given DID identifier and resource identifier.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier", + "schema": { + "type": "string" + }, + "required": true, + "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + { + "in": "query", + "name": "resourceId", + "description": "Fetch a DID-Linked Resource by Resource ID unique identifier. Since this is a unique identifier, other Resource query parameters are not required. See DID-Linked Resources for more details.", + "schema": { + "type": "string", + "format": "uuid" + }, + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + { + "in": "query", + "name": "resourceName", + "description": "Filter a DID-Linked Resource query by Resource Name. See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "cheqd-issuer-logo" + }, + { + "in": "query", + "name": "resourceType", + "description": "Filter a DID-Linked Resource query by Resource Type. See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "CredentialArtwork" + }, + { + "in": "query", + "name": "resourceVersion", + "description": "Filter a DID-Linked Resource query by Resource Version, which is an optional free-text field used by issuers (e.g., \"v1\", \"Final Version\", \"1st January 1970\" etc). See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "v1" + }, + { + "in": "query", + "name": "resourceVersionTime", + "description": "Filter a DID-Linked Resource query which returns the closest version of the Resource *at* or *before* specified time. See DID-Linked Resources for more details.", + "schema": { + "type": "string", + "format": "date-time" + }, + "example": "1970-01-01T00:00:00Z" + }, + { + "in": "query", + "name": "checksum", + "description": "Request integrity check against a given DID-Linked Resource by providing a SHA-256 checksum hash. See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "dc64474d062ed750a66bad58cb609928de55ed0d81defd231a4a4bf97358e9ed" + }, + { + "in": "query", + "name": "resourceMetadata", + "description": "Return only metadata of DID-Linked Resource instead of actual DID-Linked Resource. Mutually exclusive with some of the other parameters.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "any": { + "schema": { + "type": "object" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + } + }, + "components": { + "schemas": { + "AlsoKnownAs": { + "type": "object", + "properties": { + "alsoKnownAs": { + "type": "array", + "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", + "items": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "format": "uri", + "description": "URI where the DID-Linked Resource can be fetched from. Can be any type of URI (e.g., DID, HTTPS, IPFS, etc.)" + }, + "description": { + "type": "string", + "description": "Optional description of the URI." + } + } + } + } + } + }, + "CredentialRequest": { + "description": "Input fields for the creating a Verifiable Credential.", + "type": "object", + "additionalProperties": false, + "properties": { + "issuerDid": { + "description": "DID of the Verifiable Credential issuer. This needs to be a `did:cheqd` DID.", + "type": "string", + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + "subjectDid": { + "description": "DID of the Verifiable Credential holder/subject. This needs to be a `did:key` DID.", + "type": "string", + "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" + }, + "attributes": { + "description": "JSON object containing the attributes to be included in the credential.", + "type": "object", + "example": { + "name": "Bob", + "gender": "male" + } + }, + "@context": { + "description": "Optional properties to be included in the `@context` property of the credential.", + "type": "array", + "items": { + "type": "string" + }, + "example": ["https://schema.org/schema.jsonld", "https://veramo.io/contexts/profile/v1"] + }, + "type": { + "description": "Optional properties to be included in the `type` property of the credential.", + "type": "array", + "items": { + "type": "string" + }, + "example": ["Person"] + }, + "expirationDate": { + "description": "Optional expiration date according to the VC Data Model specification.", + "type": "string", + "format": "date-time", + "example": "2023-06-08T13:49:28.000Z" + }, + "format": { + "description": "Format of the Verifiable Credential. Defaults to VC-JWT.", + "type": "string", + "enum": ["jwt", "jsonld"], + "example": "jwt" + }, + "credentialStatus": { + "description": "Optional `credentialStatus` properties for VC revocation or suspension. Takes `statusListName` and `statusListPurpose` as inputs.", + "type": "object", + "required": ["statusPurpose", "statusListName"], + "properties": { + "statusPurpose": { + "type": "string", + "enum": ["revocation", "suspension"] + }, + "statusListName": { + "type": "string" + }, + "statusListIndex": { + "type": "number" + }, + "statusListVersion": { + "type": "string", + "format": "date-time" + }, + "statusListRangeStart": { + "type": "number" + }, + "statusListRangeEnd": { + "type": "number" + }, + "indexNotIn": { + "type": "number" + } + }, + "example": { + "statusPurpose": "revocation", + "statusListName": "employee-credentials" + } + } + }, + "required": ["issuerDid", "subjectDid", "attributes"], + "example": { + "issuerDid": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "subjectDid": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", + "attributes": { + "gender": "male", + "name": "Bob" + }, + "@context": ["https://schema.org"], + "type": ["Person"], + "format": "jwt", + "credentialStatus": { + "statusPurpose": "revocation", + "statusListName": "employee-credentials", + "statusListIndex": 10 + } + } + }, + "Credential": { + "description": "Input fields for revoking/suspending a Verifiable Credential.", + "type": "object", + "additionalProperties": false, + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "https://www.w3.org/2018/credentials/v1", + "https://schema.org", + "https://veramo.io/contexts/profile/v1" + ] + }, + "type": { + "type": "array", + "items": { + "type": "string" + }, + "example": ["VerifiableCredential", "Person"] + }, + "expirationDate": { + "type": "string", + "format": "date-time", + "example": "2023-06-08T13:49:28.000Z" + }, + "issuer": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "DID", + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + } + } + }, + "credentialSubject": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "DID", + "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" + } + } + }, + "credentialStatus": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20" + }, + "statusListIndex": { + "type": "number", + "example": 20 + }, + "statusPurpose": { + "type": "string", + "enum": ["revocation", "suspension"], + "example": "suspension" + }, + "type": { + "type": "string", + "enum": ["StatusList2021Entry"] + } + } + }, + "issuanceDate": { + "type": "string", + "format": "date-time", + "example": "2023-06-08T13:49:28.000Z" + }, + "proof": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "jwt": { + "type": "string" + } + }, + "example": { + "type": "JwtProof2020", + "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg" + } + } + }, + "example": { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://schema.org", + "https://veramo.io/contexts/profile/v1" + ], + "credentialSubject": { + "gender": "male", + "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", + "name": "Bob" + }, + "credentialStatus": { + "id": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20", + "statusIndex": 20, + "statusPurpose": "suspension", + "type": "StatusList2021Entry" + }, + "issuanceDate": "2023-06-08T13:49:28.000Z", + "issuer": { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + "proof": { + "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg", + "type": "JwtProof2020" + }, + "type": ["VerifiableCredential", "Person"] + } + }, + "CredentialRevokeRequest": { + "type": "object", + "properties": { + "credential": { + "description": "Verifiable Credential to be revoked as a VC-JWT string or a JSON object.", + "oneOf": [ + { + "type": "object" + }, + { + "type": "string" + } + ] + }, + "symmetricKey": { + "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource. Required if the StatusList2021 DID-Linked Resource is encrypted.", + "type": "string" + } + } + }, + "RevocationResult": { + "properties": { + "revoked": { + "type": "boolean", + "example": true + } + } + }, + "SuspensionResult": { + "properties": { + "suspended": { + "type": "boolean", + "example": true + } + } + }, + "UnsuspensionResult": { + "properties": { + "unsuspended": { + "type": "boolean", + "example": true + } + } + }, + "CredentialVerifyRequest": { + "type": "object", + "properties": { + "credential": { + "description": "Verifiable Credential to be verified as a VC-JWT string or a JSON object.", + "type": "object" + }, + "policies": { + "description": "Custom verification policies to execute when verifying credential.", + "type": "object", + "properties": { + "issuanceDate": { + "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "expirationDate": { + "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "audience": { + "description": "Policy to skip the audience check when set to `false`.", + "type": "boolean", + "default": false + } + } + } + } + }, + "VerifyPresentationResult": { + "type": "object", + "properties": { + "verified": { + "type": "boolean" + }, + "issuer": { + "type": "string" + }, + "signer": { + "type": "object" + }, + "jwt": { + "type": "string" + }, + "verifiableCredential": { + "type": "object" + } + } + }, + "VerifyCredentialResult": { + "type": "object", + "properties": { + "verified": { + "type": "boolean" + }, + "issuer": { + "type": "string" + }, + "signer": { + "type": "object" + }, + "jwt": { + "type": "string" + }, + "verifiableCredential": { + "type": "object" + } + }, + "example": { + "verified": true, + "polices": {}, + "issuer": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "signer": { + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", + "type": "Ed25519VerificationKey2018" + } + } + }, + "PresentationCreateRequest": { + "type": "object", + "required": ["credentials"], + "properties": { + "credentials": { + "description": "Verifiable Credentials to be used for VP-JWT creation as a VP-JWT strings or a JSON objectsf.", + "type": "array", + "items": { + "type": "object" + } + }, + "holderDid": { + "description": "DID of holder", + "type": "string" + }, + "verifierDid": { + "description": "DID of verifier", + "type": "string" + } + } + }, + "PresentationVerifyRequest": { + "type": "object", + "required": ["presentation"], + "properties": { + "presentation": { + "description": "Verifiable Presentation to be verified as a VP-JWT string or a JSON object.", + "type": "object" + }, + "verifierDid": { + "description": "Provide an optional verifier DID (also known as 'domain' parameter), if the verifier DID in the presentation is not managed in the wallet.", + "type": "string" + }, + "makeFeePayment": { + "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", + "type": "boolean", + "default": false + }, + "policies": { + "description": "Custom verification policies to execute when verifying presentation.", + "type": "object", + "properties": { + "issuanceDate": { + "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "expirationDate": { + "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "audience": { + "description": "Policy to skip the audience check when set to `false`.", + "type": "boolean", + "default": false + } + } + } + } + }, + "CredentialStatusCreateBody": { + "allOf": [ + { + "type": "object", + "required": ["did", "statusListName"], + "properties": { + "did": { + "description": "DID of the StatusList2021 publisher.", + "type": "string", + "format": "uri" + }, + "statusListName": { + "description": "The name of the StatusList2021 DID-Linked Resource to be created.", + "type": "string" + }, + "length": { + "description": "The length of the status list to be created. The default and minimum length is 140000 which is 16kb.", + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true, + "default": 140000 + }, + "encoding": { + "description": "The encoding format of the StatusList2021 DiD-Linked Resource to be created.", + "type": "string", + "default": "base64url", + "enum": ["base64url", "base64", "hex"] + }, + "statusListVersion": { + "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/AlsoKnownAs" + } + ] + }, + "CredentialStatusCreateUnencryptedRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCreateBody" + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials", + "length": 140000, + "encoding": "base64url" + } + }, + "CredentialStatusUnencryptedResult": { + "type": "object", + "properties": { + "resource": { + "type": "object", + "properties": { + "StatusList2021": { + "type": "object", + "properties": { + "encodedList": { + "type": "string", + "example": "H4sIAAAAAAAAA-3BAQ0AAADCoPdPbQ8HFAAAAAAAAAAAAAAAAAAAAADwaDhDr_xcRAAA" + }, + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "validFrom": { + "type": "string", + "format": "date-time", + "example": "2023-06-26T11:45:19.349Z" + } + } + }, + "metadata": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "encoding": { + "type": "string", + "example": "base64url" + }, + "encrypted": { + "type": "boolean", + "example": false + } + } + } + } + }, + "resourceMetadata": { + "type": "object", + "example": { + "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceName": "cheqd-employee-credentials", + "resourceType": "StatusList2021Revocation", + "mediaType": "application/json", + "resourceVersion": "1.0.0", + "created": "2023-06-26T11:45:20Z", + "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", + "previousVersionId": null, + "nextVersionId": null + } + } + } + }, + "CredentialStatusCreateUnencryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "created": { + "type": "boolean", + "example": true + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" + } + ] + }, + "CredentialStatusEncryptedPaymentConditionsBody": { + "type": "object", + "properties": { + "feePaymentAddress": { + "description": "The cheqd/Cosmos payment address where payments to unlock the encrypted StatusList2021 DID-Linked Resource need to be sent.", + "type": "string", + "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" + }, + "feePaymentAmount": { + "description": "Amount in CHEQ tokens to unlock the encrypted StatusList2021 DID-Linked Resource.", + "type": "number", + "minimum": 0, + "exclusiveMinimum": true, + "default": 20 + }, + "feePaymentWindow": { + "description": "Time window (in minutes) within which the payment to unlock the encrypted StatusList2021 DID-Linked Resource is considered valid.", + "type": "number", + "minimum": 0, + "exclusiveMinimum": true, + "default": 10 + } + } + }, + "CredentialStatusEncryptedPaymentConditionsJson": { + "type": "object", + "properties": { + "paymentConditions": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" + } + ] + } + } + }, + "CredentialStatusCreateEncryptedFormRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCreateBody" + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" + }, + { + "type": "object", + "required": ["feePaymentAddress", "feePaymentAmount", "feePaymentWindow"] + } + ] + }, + "CredentialStatusCreateEncryptedJsonRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCreateBody" + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" + }, + { + "type": "object", + "required": ["paymentConditions"] + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials-encrypted", + "paymentConditions": [ + { + "feePaymentAddress": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg", + "feePaymentAmount": 20, + "feePaymentWindow": 10 + } + ] + } + }, + "CredentialStatusEncryptedResult": { + "type": "object", + "properties": { + "resource": { + "type": "object", + "properties": { + "StatusList2021": { + "type": "object", + "properties": { + "encodedList": { + "type": "string", + "example": "496fdfbeb745b4db03fcdb40566f9c4c4a1c0f184b31255e641b6e7bdfb9b6946c12be87ca3763be0393c00b67ac1e8737c106b32f46ef59c765754415b5e8cc7c65fccaa3374620430ea476301a5e0dd63340e7a27a68bc627518471f22e4a2" + }, + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "validFrom": { + "type": "string", + "format": "date-time", + "example": "2023-06-26T11:45:19.349Z" + } + } + }, + "metadata": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "encoding": { + "type": "string", + "example": "base64url" + }, + "encrypted": { + "type": "boolean", + "example": true + }, + "encryptedSymmetricKey": { + "type": "string", + "example": "b11182dc524b8181f9a6aef4c4ad0a1c14e40033b9112dffd8d1bcf6cc3b85abc07ded2205ee94068a99f4202502cb0855f322583fa6ce1534d3a05bf36891766ea2c5f90a982b3040680762977d404d758a2370224a239c8279aa7d21e980931c42055b17ca4c7dbffa4782480a8b6279cf989b2f166d5fdb4b2c1b5a63927200000000000000203018dcaba26df45a415bb599218b27ca853a70289d7a3ed3ed0e3730452e8f8d9af91b6e71312565d2c069341f6660ab" + }, + "paymentConditions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "feePaymentAddress": { + "type": "string", + "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" + }, + "feePaymentAmount": { + "type": "string", + "example": "20000000000ncheq" + }, + "intervalInSeconds": { + "type": "number", + "example": 600 + }, + "type": { + "type": "string", + "example": "timelockPayment" + } + } + } + } + } + }, + "resourceMetadata": { + "type": "object", + "example": { + "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceName": "cheqd-revocation-encrypted-1", + "resourceType": "StatusList2021Revocation", + "mediaType": "application/json", + "resourceVersion": "2023-06-26T11:45:19.349Z", + "created": "2023-06-26T11:45:20Z", + "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", + "previousVersionId": null, + "nextVersionId": null + } + }, + "symmetricKey": { + "type": "string", + "example": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" + } + } + } + } + }, + "CredentialStatusCreateEncryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "created": { + "type": "boolean", + "example": true + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedResult" + } + ] + }, + "CredentialStatusUpdateBody": { + "type": "object", + "required": ["did", "statusListName", "indices"], + "properties": { + "did": { + "description": "DID of the StatusList2021 publisher.", + "type": "string", + "format": "uri" + }, + "statusListName": { + "description": "The name of the StatusList2021 DID-Linked Resource to be updated.", + "type": "string" + }, + "indices": { + "description": "List of credential status indices to be updated. The indices must be in the range of the status list.", + "type": "array", + "items": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": false + } + }, + "statusListVersion": { + "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + "CredentialStatusUpdateUnencryptedRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUpdateBody" + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials", + "indices": [10, 3199, 12109, 130999] + } + }, + "CredentialStatusUpdateUnencryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "updated": { + "type": "boolean", + "example": true + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/RevocationResult" + }, + { + "$ref": "#/components/schemas/SuspensionResult" + }, + { + "$ref": "#/components/schemas/UnsuspensionResult" + } + ] + }, + { + "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" + } + ] + }, + "CredentialStatusUpdateEncryptedFormRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUpdateBody" + }, + { + "type": "object", + "required": ["symmetricKey"], + "properties": { + "symmetricKey": { + "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" + } + ] + }, + "CredentialStatusUpdateEncryptedJsonRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUpdateBody" + }, + { + "type": "object", + "required": ["symmetricKey"], + "properties": { + "symmetricKey": { + "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials-encrypted", + "indices": [10, 3199, 12109, 130999], + "symmetricKey": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" + } + }, + "CredentialStatusUpdateEncryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "updated": { + "type": "boolean", + "example": true + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/RevocationResult" + }, + { + "$ref": "#/components/schemas/SuspensionResult" + }, + { + "$ref": "#/components/schemas/UnsuspensionResult" + } + ] + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedResult" + } + ] + }, + "CredentialStatusCheckRequest": { + "type": "object", + "required": ["did", "statusListName", "index"], + "properties": { + "did": { + "description": "DID of the StatusList2021 publisher.", + "type": "string", + "format": "uri" + }, + "statusListName": { + "description": "The name of the StatusList2021 DID-Linked Resource to be checked.", + "type": "string" + }, + "index": { + "description": "Credential status index to be checked for revocation or suspension.", + "type": "integer", + "minimum": 0, + "exclusiveMinimum": false + }, + "makeFeePayment": { + "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", + "type": "boolean", + "default": true + } + } + }, + "CredentialStatusCheckResult": { + "oneOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCheckRevocationResult" + }, + { + "$ref": "#/components/schemas/CredentialStatusCheckSuspensionResult" + } + ] + }, + "CredentialStatusCheckRevocationResult": { + "type": "object", + "properties": { + "checked": { + "type": "boolean", + "example": true + }, + "revoked": { + "type": "boolean", + "example": false + } + } + }, + "CredentialStatusCheckSuspensionResult": { + "type": "object", + "properties": { + "checked": { + "type": "boolean", + "example": true + }, + "suspended": { + "type": "boolean", + "example": false + } + } + }, + "CredentialStatusListSearchResult": { + "allOf": [ + { + "type": "object", + "properties": { + "found": { + "type": "boolean", + "example": true + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedResult" + } + ] + } + ] + }, + "KeyImportRequest": { + "type": "object", + "properties": { + "alias": { + "type": "string" + }, + "type": { + "type": "string", + "enum": ["Ed25519", "Secp256k1"] + }, + "privateKeyHex": { + "type": "string" + } + } + }, + "KeyResult": { + "type": "object", + "properties": { + "kid": { + "type": "string" + }, + "type": { + "type": "string", + "enum": ["Ed25519", "Secp256k1"] + }, + "publicKeyHex": { + "type": "string" + } + } + }, + "DidDocument": { + "description": "This input field contains either a complete DID document, or an incremental change (diff) to a DID document. See Universal DID Registrar specification.", + "type": "object", + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "controllers": { + "type": "array", + "items": { + "type": "string" + } + }, + "verificationMethod": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VerificationMethod" + } + }, + "service": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "authentication": { + "type": "array", + "items": { + "type": "string" + } + }, + "assertionMethod": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityInvocation": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityDelegation": { + "type": "array", + "items": { + "type": "string" + } + }, + "keyAgreement": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "@context": ["https://www.w3.org/ns/did/v1"], + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "controller": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0"], + "verificationMethod": [ + { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "type": "Ed25519VerificationKey2018", + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "publicKeyBase58": "z6MkkVbyHJLLjdjU5B62DaJ4mkdMdUkttf9UqySSkA9bVTeZ" + } + ], + "authentication": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1"], + "service": [ + { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", + "type": "LinkedDomains", + "serviceEndpoint": ["https://example.com"] + } + ] + } + }, + "DidDocumentWithoutVerificationMethod": { + "type": "object", + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "controllers": { + "type": "array", + "items": { + "type": "string" + } + }, + "service": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "authentication": { + "type": "array", + "items": { + "type": "string" + } + }, + "assertionMethod": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityInvocation": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityDelegation": { + "type": "array", + "items": { + "type": "string" + } + }, + "keyAgreement": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "@context": ["https://www.w3.org/ns/did/v1"], + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "controller": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0"], + "authentication": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1"], + "service": [ + { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", + "type": "LinkedDomains", + "serviceEndpoint": ["https://example.com"] + } + ] + } + }, + "DidCreateRequestFormBased": { + "type": "object", + "properties": { + "network": { + "description": "Network to create the DID on (testnet or mainnet)", + "type": "string", + "enum": ["testnet", "mainnet"] + }, + "identifierFormatType": { + "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", + "type": "string", + "enum": ["uuid", "base58btc"] + }, + "verificationMethodType": { + "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", + "type": "string", + "enum": ["Ed25519VerificationKey2018", "JsonWebKey2020", "Ed25519VerificationKey2020"] + }, + "service": { + "description": "It's a list of special objects which are designed to build the actual service. It's almost the same as in DID Core specification, but instead of `id` it utilises `idFragment` field for making the right `id` for each service. !!! WARN. Cause swagger-ui does not handle x-ww-form based arrays correctly, please frame all your services in brackets while using swagger UI. !!!", + "type": "array", + "items": { + "type": "object", + "properties": { + "idFragment": { + "type": "string" + }, + "type": { + "type": "string" + }, + "serviceEndpoint": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "example": [ + { + "idFragment": "service-1", + "type": "LinkedDomains", + "serviceEndpoint": ["https://example.com"] + } + ] + }, + "key": { + "description": "The unique identifier in hexadecimal public key format used in the verification method to create the DID.", + "type": "string" + }, + "@context": { + "type": "array", + "items": { + "type": "string" + }, + "example": ["https://www.w3.org/ns/did/v1"] + } + } + }, + "DidCreateRequestJson": { + "type": "object", + "properties": { + "network": { + "description": "Network to create the DID on (testnet or mainnet)", + "type": "string", + "enum": ["testnet", "mainnet"] + }, + "identifierFormatType": { + "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", + "type": "string", + "enum": ["uuid", "base58btc"] + }, + "assertionMethod": { + "description": "Usually a reference to a Verification Method. An Assertion Method is required to issue JSON-LD credentials. See DID Core specification for more details.", + "type": "boolean", + "default": true + }, + "options": { + "type": "object", + "properties": { + "key": { + "type": "string", + "example": "8255ddadd75695e01f3d98fcec8ccc7861a030b317d4326b0e48a4d579ddc43a" + }, + "verificationMethodType": { + "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", + "type": "string", + "enum": ["Ed25519VerificationKey2018", "JsonWebKey2020", "Ed25519VerificationKey2020"] + } + } + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocumentWithoutVerificationMethod" + } + } + }, + "DidImportRequest": { + "type": "object", + "properties": { + "did": { + "type": "string", + "description": "DID to be imported", + "format": "uri", + "required": true + }, + "keys": { + "type": "array", + "description": "List of keys required to import the DID", + "required": true, + "items": { + "$ref": "#/components/schemas/KeyImportRequest" + } + } + } + }, + "PresentationCreateResult": { + "type": "object", + "properties": { + "vp": { + "type": "object", + "description": "Verifiable Presentation which could be provided to the verifier." + }, + "nbf": { + "type": "integer", + "description": "Unix timestamp of the earliest time that the Verifiable Presentation is valid." + }, + "iss": { + "type": "string", + "description": "DID of the issuer of the Verifiable Presentation. (Here it's supposed to be a holder DID)" + }, + "aud": { + "type": "array", + "items": { + "type": "string" + }, + "description": "DID of the verifier of the Verifiable Presentation." + } + }, + "example": { + "vp": { + "@context": ["https://www.w3.org/2018/credentials/v1"], + "type": ["VerifiablePresentation"], + "verifiableCredential": [ + "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc2NoZW1hLm9yZy9zY2hlbWEuanNvbmxkIiwiaHR0cHM6Ly92ZXJhbW8uaW8vY29udGV4dHMvcHJvZmlsZS92MSIsImh0dHBzOi8vdzNpZC5vcmcvdmMtc3RhdHVzLWxpc3QtMjAyMS92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiUGVyc29uIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7Im5hbWUiOiJCb2IiLCJnZW5kZXIiOiJtYWxlIn0sImNyZWRlbnRpYWxTdGF0dXMiOnsiaWQiOiJodHRwczovL3Jlc29sdmVyLmNoZXFkLm5ldC8xLjAvaWRlbnRpZmllcnMvZGlkOmNoZXFkOnRlc3RuZXQ6OTBkNWMxNDEtNzI0Zi00N2FkLTlhZTctYTdjMzNhOWU1NjQzP3Jlc291cmNlTmFtZT1zdXNwZW5zaW9uRW4mcmVzb3VyY2VUeXBlPVN0YXR1c0xpc3QyMDIxU3VzcGVuc2lvbiMxMzMzOCIsInR5cGUiOiJTdGF0dXNMaXN0MjAyMUVudHJ5Iiwic3RhdHVzUHVycG9zZSI6InN1c3BlbnNpb24iLCJzdGF0dXNMaXN0SW5kZXgiOiIxMzMzOCJ9fSwic3ViIjoiZGlkOmtleTp6Nk1raGFYZ0JaRHZvdERrTDUyNTdmYWl6dGlHaUMyUXRLTEdwYm5uRUd0YTJkb0siLCJuYmYiOjE3MDA0NzM0MTYsImlzcyI6ImRpZDpjaGVxZDp0ZXN0bmV0OjkwZDVjMTQxLTcyNGYtNDdhZC05YWU3LWE3YzMzYTllNTY0MyJ9.-14Ril1pZEy2HEEo48gTJr2yOtGxBhUGTFmzVdjAtyhFRsW5zZg9onHt6V9JQ8BaiYBlTkP9GzTnJ-O6hdiyCw" + ] + }, + "nbf": 1700744275, + "iss": "did:cheqd:testnet:4b846d0f-2f6c-4ab6-9fe2-5b8db301c83c", + "aud": ["did:cheqd:testnet:8c71e9b6-c5a3-4250-8c58-fa591533cd22"] + } + }, + "DidResult": { + "type": "object", + "properties": { + "did": { + "type": "string" + }, + "controllerKeyId": { + "type": "string" + }, + "keys": { + "type": "array", + "items": { + "type": "object" + } + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + } + } + }, + "DidUpdateResponse": { + "type": "object", + "properties": { + "did": { + "type": "string" + }, + "controllerKeyId": { + "type": "string", + "description": "The default key id of which is the key associated with the first verificationMethod" + }, + "keys": { + "type": "array", + "description": "The list of keys associated with the list of verificationMethod's of DIDDocument", + "items": { + "type": "object" + } + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "controllerKeyRefs": { + "type": "array", + "description": "The list of keyRefs which were used for signing the transaction", + "items": { + "type": "string" + } + }, + "controllerKeys": { + "type": "array", + "description": "The list of all possible keys, inlcuding all controller's keys", + "items": { + "type": "string" + } + } + } + }, + "VerificationMethod": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + }, + "controller": { + "type": "string" + }, + "publicKeyMultibase": { + "type": "string" + }, + "publicKeyJwk": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "id": "did:cheqd:testnet :7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", + "type": "Ed25519VerificationKey2018" + } + }, + "Service": { + "description": "Communicating or interacting with the DID subject or associated entities via one or more service endpoints. See DID Core specification for more details.", + "type": "object", + "properties": { + "id": { + "description": "DID appended with Service fragment ID (e.g., `#service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`)", + "type": "string", + "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1" + }, + "type": { + "description": "Service type as defined in DID Specification Registries.", + "type": "string", + "example": "LinkedDomains" + }, + "serviceEndpoint": { + "description": "Service endpoint as defined in DID Core Specification.", + "type": "array", + "items": { + "type": "string", + "example": "https://example.com" + } + } + } + }, + "DidUpdateRequest": { + "type": "object", + "properties": { + "did": { + "description": "DID identifier to be updated.", + "type": "string", + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + "service": { + "type": "array", + "description": "Service section of the DID Document.", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "verificationMethod": { + "type": "array", + "description": "Verification Method section of the DID Document.", + "items": { + "$ref": "#/components/schemas/VerificationMethod" + } + }, + "authentication": { + "description": "Authentication section of the DID Document.", + "type": "array", + "items": { + "type": "string" + } + }, + "publicKeyHexs": { + "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", + "type": "array", + "items": { + "type": "string" + } + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + } + } + }, + "DidDeactivateRequest": { + "type": "object", + "properties": { + "publicKeyHexs": { + "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "CreateResourceRequest": { + "description": "Input fields for DID-Linked Resource creation.", + "type": "object", + "additionalProperties": false, + "required": ["name", "type", "data", "encoding"], + "properties": { + "data": { + "description": "Encoded string containing the data to be stored in the DID-Linked Resource.", + "type": "string" + }, + "encoding": { + "description": "Encoding format used to encode the data.", + "type": "string", + "enum": ["base64url", "base64", "hex"] + }, + "name": { + "description": "Name of DID-Linked Resource.", + "type": "string" + }, + "type": { + "description": "Type of DID-Linked Resource. This is NOT the same as the media type, which is calculated automatically ledger-side.", + "type": "string" + }, + "alsoKnownAs": { + "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", + "type": "array", + "items": { + "type": "object", + "properties": { + "uri": { + "type": "string" + }, + "description": { + "type": "string" + } + } + } + }, + "version": { + "description": "Optional field to assign a human-readable version in the DID-Linked Resource.", + "type": "string" + }, + "publicKeyHexs": { + "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "data": "SGVsbG8gV29ybGQ=", + "encoding": "base64url", + "name": "ResourceName", + "type": "TextDocument" + } + }, + "ResourceList": { + "type": "object", + "properties": { + "@context": { + "type": "string", + "example": "https://w3id.org/did-resolution/v1" + }, + "contentMetadata": { + "type": "object" + }, + "contentStream": { + "type": "object" + }, + "dereferencingMetadata": { + "$ref": "#/components/schemas/DereferencingMetadata" + } + } + }, + "DereferencingMetadata": { + "type": "object", + "properties": { + "contentType": { + "type": "string", + "example": "application/did+ld+json" + }, + "did": { + "$ref": "#/components/schemas/DidProperties" + }, + "retrieved": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + } + } + }, + "DidResolution": { + "type": "object", + "properties": { + "@context": { + "type": "string", + "example": "https://w3id.org/did-resolution/v1" + }, + "didDidResolutionMetadata": { + "$ref": "#/components/schemas/DidResolutionMetadata" + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + }, + "didDocumentMetadata": { + "$ref": "#/components/schemas/DidDocumentMetadata" + } + } + }, + "DeactivatedDidResolution": { + "type": "object", + "properties": { + "@context": { + "type": "string", + "example": "https://w3id.org/did-resolution/v1" + }, + "didDidResolutionMetadata": { + "$ref": "#/components/schemas/DidResolutionMetadata" + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + }, + "didDocumentMetadata": { + "$ref": "#/components/schemas/DeactivatedDidDocumentMetadata" + } + } + }, + "DidDocumentMetadata": { + "type": "object", + "properties": { + "created": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "deactivated": { + "type": "boolean", + "example": false + }, + "updated": { + "type": "string", + "example": "2021-09-10T12:00:00Z" + }, + "versionId": { + "type": "string", + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + "linkedResourceMetadata": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ResourceMetadata" + } + } + } + }, + "DeactivatedDidDocumentMetadata": { + "type": "object", + "properties": { + "created": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "deactivated": { + "type": "boolean", + "example": true + }, + "updated": { + "type": "string", + "example": "2021-09-10T12:00:00Z" + }, + "versionId": { + "type": "string", + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + "linkedResourceMetadata": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ResourceMetadata" + } + } + } + }, + "ResourceMetadata": { + "type": "object", + "properties": { + "resourceURI": { + "type": "string", + "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47/resources/398cee0a-efac-4643-9f4c-74c48c72a14b" + }, + "resourceCollectionId": { + "type": "string", + "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" + }, + "resourceId": { + "type": "string", + "example": "398cee0a-efac-4643-9f4c-74c48c72a14b" + }, + "resourceName": { + "type": "string", + "example": "cheqd-issuer-logo" + }, + "resourceType": { + "type": "string", + "example": "CredentialArtwork" + }, + "mediaType": { + "type": "string", + "example": "image/png" + }, + "resourceVersion": { + "type": "string", + "example": "1.0" + }, + "checksum": { + "type": "string", + "example": "a95380f460e63ad939541a57aecbfd795fcd37c6d78ee86c885340e33a91b559" + }, + "created": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "nextVersionId": { + "type": "string", + "example": "d4829ac7-4566-478c-a408-b44767eddadc" + }, + "previousVersionId": { + "type": "string", + "example": "ad7a8442-3531-46eb-a024-53953ec6e4ff" + } + } + }, + "DidResolutionMetadata": { + "type": "object", + "properties": { + "contentType": { + "allOf": [ + { + "$ref": "#/components/schemas/ContentType" + } + ], + "example": "application/did+ld+json" + }, + "retrieved": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "did": { + "$ref": "#/components/schemas/DidProperties" + } + } + }, + "ContentType": { + "type": "string", + "enum": ["application/did+json", "application/did+ld+json", "application/ld+json", "application/json"] + }, + "DidProperties": { + "type": "object", + "properties": { + "didString": { + "type": "string", + "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" + }, + "method": { + "type": "string", + "example": "cheqd" + }, + "methodSpecificId": { + "type": "string", + "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" + } + } + }, + "Customer": { + "type": "object", + "properties": { + "customerId": { + "type": "string", + "example": "6w5drpiiwhhs" + }, + "address": { + "type": "string", + "example": "cheqd1wgsvqwlkmdp60f4dek26ak0sjw6au3ytd3pz7f" + } + } + }, + "AccountCreateRequest": { + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": { + "primaryEmail": { + "type": "string" + } + } + } + } + }, + "InvalidRequest": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "InvalidRequest" + } + } + }, + "InternalError": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Internal Error" + } + } + }, + "UnauthorizedError": { + "description": "Access token is missing or invalid", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Unauthorized Error" + } + } + } + } + } +} diff --git a/src/types/portal.ts b/src/types/portal.ts index 1553fb48..866e73dd 100644 --- a/src/types/portal.ts +++ b/src/types/portal.ts @@ -1,86 +1,84 @@ -import type Stripe from "stripe"; -import type { UnsuccessfulResponseBody } from "./shared.js"; +import type Stripe from 'stripe'; +import type { UnsuccessfulResponseBody } from './shared.js'; export type ProductWithPrices = Stripe.Product & { - prices?: Stripe.Price[]; + prices?: Stripe.Price[]; }; export type ProductListUnsuccessfulResponseBody = UnsuccessfulResponseBody; export type ProductGetUnsuccessfulResponseBody = UnsuccessfulResponseBody; - export type ProductListResponseBody = { - products: Stripe.ApiList; -} + products: Stripe.ApiList; +}; export type ProductGetResponseBody = { - product: ProductWithPrices; -} + product: ProductWithPrices; +}; // Prices // List export type PriceListResponseBody = { - prices: Stripe.ApiList; -} + prices: Stripe.ApiList; +}; export type PriceListUnsuccessfulResponseBody = UnsuccessfulResponseBody; // Subscription // Create export type SubscriptionCreateRequestBody = { - items: [{ price: string }]; - idempotencyKey?: string; -} + items: [{ price: string }]; + idempotencyKey?: string; +}; export type SubscriptionCreateResponseBody = { - subscription: Stripe.Response; -} + subscription: Stripe.Response; +}; // Update export type SubscriptionUpdateRequestBody = { - subscriptionId: string; - updateParams: Stripe.SubscriptionUpdateParams; - idempotencyKey?: string; - -} + subscriptionId: string; + updateParams: Stripe.SubscriptionUpdateParams; + idempotencyKey?: string; +}; export type SubscriptionUpdateResponseBody = { - subscription: Stripe.Response; -} + subscription: Stripe.Response; +}; // Get export type SubscriptionGetRequestBody = { - subscriptionId: string; -} + subscriptionId: string; +}; export type SubscriptionGetResponseBody = { - subscription: Stripe.Response; -} + subscription: Stripe.Response; +}; // List export type SubscriptionListResponseBody = { - subscriptions: Stripe.Response>; -} + subscriptions: Stripe.Response>; +}; // Delete export type SubscriptionCancelRequestBody = { - subscriptionId: string; -} + subscriptionId: string; +}; export type SubscriptionCancelResponseBody = { - subscription: Stripe.Subscription; - idempotencyKey?: string; -} + subscription: Stripe.Subscription; + idempotencyKey?: string; +}; //Resume export type SubscriptionResumeRequestBody = { - subscriptionId: string; - idempotencyKey?: string; -} + subscriptionId: string; + idempotencyKey?: string; +}; export type SubscriptionResumeResponseBody = { - subscription: Stripe.Response; -} + subscription: Stripe.Response; +}; export type SubscriptionCreateUnsuccessfulResponseBody = UnsuccessfulResponseBody; export type SubscriptionListUnsuccessfulResponseBody = UnsuccessfulResponseBody; @@ -94,20 +92,19 @@ export type SubscriptionResumeUnsuccessfulResponseBody = UnsuccessfulResponseBod export type PortalCustomerGetUnsuccessfulResponseBody = UnsuccessfulResponseBody; - // Checkout Session export type CheckoutSessionCreateRequestBody = { - price: string; - successURL: string; - cancelURL: string; - quantity?: number; - idempotencyKey?: string; -} + price: string; + successURL: string; + cancelURL: string; + quantity?: number; + idempotencyKey?: string; +}; export type CheckoutSessionCreateResponseBody = { - clientSecret: Stripe.Checkout.Session['client_secret']; -} + clientSecret: Stripe.Checkout.Session['client_secret']; +}; export type CheckoutSessionCreateUnsuccessfulResponseBody = UnsuccessfulResponseBody; // Utils -export type PaymentBehavior = Stripe.SubscriptionCreateParams.PaymentBehavior; \ No newline at end of file +export type PaymentBehavior = Stripe.SubscriptionCreateParams.PaymentBehavior; diff --git a/src/types/swagger-admin-types.ts b/src/types/swagger-admin-types.ts index da03eaae..987064c2 100644 --- a/src/types/swagger-admin-types.ts +++ b/src/types/swagger-admin-types.ts @@ -64,8 +64,8 @@ * idempotencyKey: * type: string * description: The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request. - * example: 1234567890 - * + * example: abcdefghijklmnopqrstuvwxyz + * * SubscriptionCreateResponseBody: * description: The response body for creating a subscription * type: object @@ -80,14 +80,14 @@ * subscriptionId: * type: string * description: The subscription id - * example: sub_1234567890 + * example: sub_1234567890 * updateParams: * type: object * description: The subscription update parameters. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/update) * idempotencyKey: * type: string * description: The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request. - * example: 1234567890 + * example: abcdefghijklmnopqrstuvwxyz * SubscriptionUpdateResponseBody: * description: The response body for updating a subscription * type: object @@ -125,7 +125,7 @@ * subscriptions: * type: array * items: - * type: object + * type: object * description: A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object] * SubscriptionCancelRequestBody: * description: The request body for canceling a subscription @@ -145,7 +145,7 @@ * idempotencyKey: * type: string * description: The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request. - * example: 1234567890 + * example: abcdefghijklmnopqrstuvwxyz * SubscriptionResumeRequestBody: * description: The request body for resuming a subscription * type: object @@ -157,7 +157,7 @@ * idempotencyKey: * type: string * description: The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request. - * example: 1234567890 + * example: abcdefghijklmnopqrstuvwxyz * SubscriptionResumeResponseBody: * description: The response body for resuming a subscription * type: object @@ -184,7 +184,7 @@ * idempotencyKey: * type: string * description: The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request. - * example: 1234567890 + * example: abcdefghijklmnopqrstuvwxyz * NotFoundError: * description: The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible. * type: object From d987e5466c58a8dab58aef8c5bcf04e574296cb9 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Sun, 10 Mar 2024 23:08:59 +0100 Subject: [PATCH 06/40] swagger changes --- src/static/swagger-admin.json | 1404 +++---- src/static/swagger-api.json | 6880 +++++++++++++++++---------------- 2 files changed, 4260 insertions(+), 4024 deletions(-) diff --git a/src/static/swagger-admin.json b/src/static/swagger-admin.json index d898b33c..25d1c408 100644 --- a/src/static/swagger-admin.json +++ b/src/static/swagger-admin.json @@ -1,693 +1,713 @@ { - "openapi": "3.0.0", - "info": { - "title": "Credential Service admin API for cheqd network", - "version": "2.0.0", - "description": "Admin API which handles users subscriptions and payments", - "contact": { - "name": "Cheqd Foundation Limited", - "url": "https://github.com/cheqd/credential-service", - "email": "support-github@cheqd.io" - }, - "license": { - "name": "Apache 2.0", - "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" - } - }, - "tags": [ - { - "name": "Product" - }, - { - "name": "Price" - }, - { - "name": "Customer" - }, - { - "name": "Subscription" - }, - { - "name": "Checkout" - } - ], - "paths": { - "/admin/checkout/session/create": { - "post": { - "summary": "Create a checkout session", - "description": "Create a checkout session", - "tags": ["Checkout"], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CheckoutSessionCreateRequestBody" - } - } - } - }, - "responses": { - "303": { - "description": "A redirect to Stripe prebuilt checkout page" - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/price/list": { - "get": { - "summary": "Get a list of prices", - "description": "Get a list of prices", - "tags": ["Price"], - "parameters": [ - { - "in": "query", - "name": "productId", - "schema": { - "type": "string", - "description": "The product id. If passed - returns filtered by this product list of prices.", - "required": false - } - } - ], - "responses": { - "200": { - "description": "A list of prices", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PriceListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/product/list": { - "get": { - "summary": "Get a list of products", - "description": "Get a list of products which are on a Stripe side", - "tags": ["Product"], - "parameters": [ - { - "in": "query", - "name": "prices", - "schema": { - "type": "boolean", - "description": "If setup to true - returns the list of products with prices inside. Default - true", - "required": false - } - } - ], - "responses": { - "200": { - "description": "A list of products", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/product/get/{productId}": { - "get": { - "summary": "Get a product", - "description": "Get a product by id", - "tags": ["Product"], - "parameters": [ - { - "in": "path", - "name": "productId", - "schema": { - "type": "string", - "description": "The product id which identifies the product in Stripe", - "required": true - } - }, - { - "in": "query", - "name": "prices", - "schema": { - "type": "boolean", - "description": "If setup to true - returns the product with prices inside. Default - true", - "required": false - } - } - ], - "responses": { - "200": { - "description": "A product", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductGetResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/create": { - "post": { - "summary": "Create a subscription", - "description": "Creates a new subscription for an existing customer", - "tags": ["Subscription"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCreateRequestBody" - } - } - } - }, - "responses": { - "201": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCreateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/update": { - "post": { - "summary": "Update a subscription", - "description": "Updates an existing subscription", - "tags": ["Subscription"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionUpdateRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionUpdateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/list": { - "get": { - "summary": "Get a list of subscriptions", - "description": "Get a list of subscriptions", - "tags": ["Subscription"], - "responses": { - "200": { - "description": "A list of subscriptions", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/get/{subscriptionId}": { - "get": { - "summary": "Get a subscription", - "description": "Get a subscription", - "tags": ["Subscription"], - "parameters": [ - { - "in": "path", - "name": "subscriptionId", - "schema": { - "type": "string", - "description": "The subscription id", - "required": true - } - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionGetResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/cancel": { - "post": { - "summary": "Cancel a subscription", - "description": "Cancels an existing subscription", - "tags": ["Subscription"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCancelRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCancelResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/resume": {}, - "post": { - "summary": "Resume a subscription", - "description": "Resumes an existing subscription", - "tags": ["Subscription"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionResumeRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionResumeResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "components": { - "schemas": { - "PriceListResponseBody": { - "description": "A list of active prcies from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/list)", - "type": "object", - "properties": { - "prices": { - "type": "array", - "items": { - "type": "object", - "description": "A price object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/object)" - } - } - } - }, - "ProductListResponseBody": { - "type": "object", - "properties": { - "products": { - "type": "array", - "items": { - "type": "object", - "description": "A product object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/object)" - } - } - } - }, - "ProductGetResponseBody": { - "description": "A product with or without prices inside. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/retrieve)", - "type": "object" - }, - "InvalidRequest": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "InvalidRequest" - } - } - }, - "InternalError": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Internal Error" - } - } - }, - "UnauthorizedError": { - "description": "Access token is missing or invalid", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Unauthorized Error" - } - } - }, - "SubscriptionCreateRequestBody": { - "description": "The request body for creating a subscription", - "type": "object", - "properties": { - "customerId": { - "type": "string", - "description": "The Stripe customer id", - "example": "cus_1234567890" - }, - "items": { - "type": "array", - "items": { - "type": "object", - "properties": { - "price": { - "type": "string", - "description": "The price id", - "example": "price_1234567890" - } - } - } - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": 1234567890 - } - } - }, - "SubscriptionCreateResponseBody": { - "description": "The response body for creating a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" - } - } - }, - "SubscriptionUpdateRequestBody": { - "description": "The request body for updating a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - }, - "updateParams": { - "type": "object", - "description": "The subscription update parameters. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/update)" - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": 1234567890 - } - } - }, - "SubscriptionUpdateResponseBody": { - "description": "The response body for updating a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" - } - } - }, - "SubscriptionGetRequestBody": { - "description": "The request body for getting a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - } - } - }, - "SubscriptionGetResponseBody": { - "description": "The response body for getting a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" - } - } - }, - "SubscriptionListRequestBody": { - "description": "The request body for listing subscriptions", - "type": "object", - "properties": { - "customerId": { - "type": "string", - "description": "The Stripe customer id", - "example": "cus_1234567890" - } - } - }, - "SubscriptionListResponseBody": { - "description": "The response body for listing subscriptions", - "type": "object", - "properties": { - "subscriptions": { - "type": "array", - "items": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" - } - } - } - }, - "SubscriptionCancelRequestBody": { - "description": "The request body for canceling a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - } - } - }, - "SubscriptionCancelResponseBody": { - "description": "The response body for canceling a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": 1234567890 - } - } - }, - "SubscriptionResumeRequestBody": { - "description": "The request body for resuming a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": 1234567890 - } - } - }, - "SubscriptionResumeResponseBody": { - "description": "The response body for resuming a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" - } - } - }, - "CheckoutSessionCreateRequestBody": { - "description": "The request body for creating a checkout session", - "type": "object", - "properties": { - "price": { - "type": "string", - "description": "The price id", - "example": "price_1234567890" - }, - "successURL": { - "type": "string", - "description": "The URL to redirect to after the customer sucessfully completes the checkout", - "example": "https://example.com/success" - }, - "cancelURL": { - "type": "string", - "description": "The URL to redirect to after the customer cancels the checkout", - "example": "https://example.com/cancel" - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": 1234567890 - } - } - }, - "NotFoundError": { - "description": "The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Not Found Error" - } - } - } - } - } -} + "openapi": "3.0.0", + "info": { + "title": "Credential Service admin API for cheqd network", + "version": "2.0.0", + "description": "Admin API which handles users subscriptions and payments", + "contact": { + "name": "Cheqd Foundation Limited", + "url": "https://github.com/cheqd/credential-service", + "email": "support-github@cheqd.io" + }, + "license": { + "name": "Apache 2.0", + "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" + } + }, + "tags": [ + { + "name": "Product" + }, + { + "name": "Price" + }, + { + "name": "Customer" + }, + { + "name": "Subscription" + }, + { + "name": "Checkout" + } + ], + "paths": { + "/admin/checkout/session/create": { + "post": { + "summary": "Create a checkout session", + "description": "Create a checkout session", + "tags": [ + "Checkout" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CheckoutSessionCreateRequestBody" + } + } + } + }, + "responses": { + "303": { + "description": "A redirect to Stripe prebuilt checkout page" + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/price/list": { + "get": { + "summary": "Get a list of prices", + "description": "Get a list of prices", + "tags": [ + "Price" + ], + "parameters": [ + { + "in": "query", + "name": "productId", + "schema": { + "type": "string", + "description": "The product id. If passed - returns filtered by this product list of prices.", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A list of prices", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PriceListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/product/list": { + "get": { + "summary": "Get a list of products", + "description": "Get a list of products which are on a Stripe side", + "tags": [ + "Product" + ], + "parameters": [ + { + "in": "query", + "name": "prices", + "schema": { + "type": "boolean", + "description": "If setup to true - returns the list of products with prices inside. Default - true", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A list of products", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProductListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/product/get/{productId}": { + "get": { + "summary": "Get a product", + "description": "Get a product by id", + "tags": [ + "Product" + ], + "parameters": [ + { + "in": "path", + "name": "productId", + "schema": { + "type": "string", + "description": "The product id which identifies the product in Stripe" + }, + "required": true + }, + { + "in": "query", + "name": "prices", + "schema": { + "type": "boolean", + "description": "If setup to true - returns the product with prices inside. Default - true", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A product", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProductGetResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/create": { + "post": { + "summary": "Create a subscription", + "description": "Creates a new subscription for an existing customer", + "tags": [ + "Subscription" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCreateRequestBody" + } + } + } + }, + "responses": { + "201": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCreateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/update": { + "post": { + "summary": "Update a subscription", + "description": "Updates an existing subscription", + "tags": [ + "Subscription" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionUpdateRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionUpdateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/list": { + "get": { + "summary": "Get a list of subscriptions", + "description": "Get a list of subscriptions", + "tags": [ + "Subscription" + ], + "responses": { + "200": { + "description": "A list of subscriptions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/get/{subscriptionId}": { + "get": { + "summary": "Get a subscription", + "description": "Get a subscription", + "tags": [ + "Subscription" + ], + "parameters": [ + { + "in": "path", + "name": "subscriptionId", + "schema": { + "type": "string", + "description": "The subscription id" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionGetResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/cancel": { + "post": { + "summary": "Cancel a subscription", + "description": "Cancels an existing subscription", + "tags": [ + "Subscription" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCancelRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCancelResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/resume": {}, + "post": { + "summary": "Resume a subscription", + "description": "Resumes an existing subscription", + "tags": [ + "Subscription" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionResumeRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionResumeResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "components": { + "schemas": { + "PriceListResponseBody": { + "description": "A list of active prcies from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/list)", + "type": "object", + "properties": { + "prices": { + "type": "array", + "items": { + "type": "object", + "description": "A price object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/object)" + } + } + } + }, + "ProductListResponseBody": { + "type": "object", + "properties": { + "products": { + "type": "array", + "items": { + "type": "object", + "description": "A product object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/object)" + } + } + } + }, + "ProductGetResponseBody": { + "description": "A product with or without prices inside. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/retrieve)", + "type": "object" + }, + "InvalidRequest": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "InvalidRequest" + } + } + }, + "InternalError": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Internal Error" + } + } + }, + "UnauthorizedError": { + "description": "Access token is missing or invalid", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Unauthorized Error" + } + } + }, + "SubscriptionCreateRequestBody": { + "description": "The request body for creating a subscription", + "type": "object", + "properties": { + "customerId": { + "type": "string", + "description": "The Stripe customer id", + "example": "cus_1234567890" + }, + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "price": { + "type": "string", + "description": "The price id", + "example": "price_1234567890" + } + } + } + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": "abcdefghijklmnopqrstuvwxyz" + } + } + }, + "SubscriptionCreateResponseBody": { + "description": "The response body for creating a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" + } + } + }, + "SubscriptionUpdateRequestBody": { + "description": "The request body for updating a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + }, + "updateParams": { + "type": "object", + "description": "The subscription update parameters. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/update)" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": "abcdefghijklmnopqrstuvwxyz" + } + } + }, + "SubscriptionUpdateResponseBody": { + "description": "The response body for updating a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" + } + } + }, + "SubscriptionGetRequestBody": { + "description": "The request body for getting a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + } + } + }, + "SubscriptionGetResponseBody": { + "description": "The response body for getting a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" + } + } + }, + "SubscriptionListRequestBody": { + "description": "The request body for listing subscriptions", + "type": "object", + "properties": { + "customerId": { + "type": "string", + "description": "The Stripe customer id", + "example": "cus_1234567890" + } + } + }, + "SubscriptionListResponseBody": { + "description": "The response body for listing subscriptions", + "type": "object", + "properties": { + "subscriptions": { + "type": "array", + "items": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + } + } + } + }, + "SubscriptionCancelRequestBody": { + "description": "The request body for canceling a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + } + } + }, + "SubscriptionCancelResponseBody": { + "description": "The response body for canceling a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": "abcdefghijklmnopqrstuvwxyz" + } + } + }, + "SubscriptionResumeRequestBody": { + "description": "The request body for resuming a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": "abcdefghijklmnopqrstuvwxyz" + } + } + }, + "SubscriptionResumeResponseBody": { + "description": "The response body for resuming a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + } + } + }, + "CheckoutSessionCreateRequestBody": { + "description": "The request body for creating a checkout session", + "type": "object", + "properties": { + "price": { + "type": "string", + "description": "The price id", + "example": "price_1234567890" + }, + "successURL": { + "type": "string", + "description": "The URL to redirect to after the customer sucessfully completes the checkout", + "example": "https://example.com/success" + }, + "cancelURL": { + "type": "string", + "description": "The URL to redirect to after the customer cancels the checkout", + "example": "https://example.com/cancel" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": "abcdefghijklmnopqrstuvwxyz" + } + } + }, + "NotFoundError": { + "description": "The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Not Found Error" + } + } + } + } + } +} \ No newline at end of file diff --git a/src/static/swagger-api.json b/src/static/swagger-api.json index a490ba8a..d8d26cfe 100644 --- a/src/static/swagger-api.json +++ b/src/static/swagger-api.json @@ -1,3333 +1,3549 @@ { - "openapi": "3.0.0", - "info": { - "title": "Credential Service API for cheqd network", - "version": "2.0.0", - "description": "API service to create and manage DIDs, Verifiable Credentials, and DID-Linked Resources", - "contact": { - "name": "Cheqd Foundation Limited", - "url": "https://github.com/cheqd/credential-service", - "email": "support-github@cheqd.io" - }, - "license": { - "name": "Apache 2.0", - "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" - } - }, - "tags": [ - { - "name": "Account" - }, - { - "name": "Key" - }, - { - "name": "DID" - }, - { - "name": "Resource" - }, - { - "name": "Credential" - }, - { - "name": "Presentation" - }, - { - "name": "Credential Status" - } - ], - "externalDocs": { - "description": "Credential Service API Documentation", - "url": "https://docs.cheqd.io/identity" - }, - "paths": { - "/account": { - "get": { - "tags": ["Account"], - "summary": "Fetch custodian-mode client details.", - "description": "This endpoint returns the custodian-mode client details for authenticated users.", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Customer" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/account/idtoken": { - "get": { - "tags": ["Account"], - "summary": "Fetch IdToken.", - "description": "This endpoint returns IdToken as JWT with list of user roles inside", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "idToken": { - "type": "string" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/account/create": { - "post": { - "tags": ["Account"], - "summary": "Create an client for an authenticated user.", - "description": "This endpoint creates a client in the custodian-mode for an authenticated user", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/AccountCreateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountCreateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "idToken": { - "type": "string" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/create/unencrypted": { - "post": { - "tags": ["Credential Status"], - "summary": "Create an unencrypted StatusList2021 credential status list.", - "description": "This endpoint creates an unencrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", - "parameters": [ - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", - "required": true, - "schema": { - "type": "string", - "enum": ["revocation", "suspension"] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/create/encrypted": { - "post": { - "tags": ["Credential Status"], - "summary": "Create an encrypted StatusList2021 credential status list.", - "description": "This endpoint creates an encrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", - "parameters": [ - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", - "required": true, - "schema": { - "type": "string", - "enum": ["revocation", "suspension"] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateEncryptedFormRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateEncryptedJsonRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateEncryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/update/unencrypted": { - "post": { - "tags": ["Credential Status"], - "summary": "Update an existing unencrypted StatusList2021 credential status list.", - "parameters": [ - { - "in": "query", - "name": "statusAction", - "description": "The update action to be performed on the unencrypted status list, can be revoke, suspend or reinstate", - "required": true, - "schema": { - "type": "string", - "enum": ["revoke", "suspend", "reinstate"] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/update/encrypted": { - "post": { - "tags": ["Credential Status"], - "summary": "Update an existing encrypted StatusList2021 credential status list.", - "parameters": [ - { - "in": "query", - "name": "statusAction", - "description": "The update action to be performed on the encrypted status list, can be revoke, suspend or reinstate", - "required": true, - "schema": { - "type": "string", - "enum": ["revoke", "suspend", "reinstate"] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedFormRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedJsonRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/check": { - "post": { - "tags": ["Credential Status"], - "summary": "Check a StatusList2021 index for a given Verifiable Credential.", - "description": "This endpoint checks a StatusList2021 index for a given Verifiable Credential and reports whether it is revoked or suspended. It offers a standalone method for checking an index without passing the entire Verifiable Credential or Verifiable Presentation.", - "parameters": [ - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension.", - "required": true, - "schema": { - "type": "string", - "enum": ["revocation", "suspension"] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCheckRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCheckRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCheckResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/search": { - "get": { - "tags": ["Credential Status"], - "summary": "Fetch StatusList2021 DID-Linked Resource based on search criteria.", - "parameters": [ - { - "in": "query", - "name": "did", - "description": "The DID of the issuer of the status list.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension.", - "schema": { - "type": "string", - "enum": ["revocation", "suspension"] - } - }, - { - "in": "query", - "name": "statusListName", - "description": "The name of the StatusList2021 DID-Linked Resource.", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusListSearchResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/issue": { - "post": { - "tags": ["Credential"], - "summary": "Issue a Verifiable Credential", - "description": "This endpoint issues a Verifiable Credential. As input it takes the list of issuerDid, subjectDid, attributes, and other parameters of the credential to be issued.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Credential" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/verify": { - "post": { - "tags": ["Credential"], - "summary": "Verify a Verifiable Credential.", - "description": "This endpoint verifies a Verifiable Credential passed to it. As input, it can take the VC-JWT as a string or the entire credential itself.", - "operationId": "verify", - "parameters": [ - { - "in": "query", - "name": "verifyStatus", - "description": "If set to `true` the verification will also check the status of the credential. Requires the VC to have a `credentialStatus` property.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "fetchRemoteContexts", - "description": "When dealing with JSON-LD you also MUST provide the proper contexts. Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "allowDeactivatedDid", - "description": "If set to `true` allow to verify credential which based on deactivated DID.", - "schema": { - "type": "boolean", - "default": false - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialVerifyRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialVerifyRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/VerifyCredentialResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/revoke": { - "post": { - "tags": ["Credential"], - "summary": "Revoke a Verifiable Credential.", - "description": "This endpoint revokes a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself. The StatusList2021 resource should already be setup in the VC and `credentialStatus` property present in the VC.", - "operationId": "revoke", - "parameters": [ - { - "in": "query", - "name": "publish", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RevocationResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/suspend": { - "post": { - "tags": ["Credential"], - "summary": "Suspend a Verifiable Credential.", - "description": "This endpoint suspends a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself.", - "operationId": "suspend", - "parameters": [ - { - "in": "query", - "name": "publish", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "schema": { - "type": "boolean" - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuspensionResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/reinstate": { - "post": { - "tags": ["Credential"], - "summary": "Reinstate a suspended Verifiable Credential.", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "operationId": "reinstate", - "parameters": [ - { - "in": "query", - "name": "publish", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "schema": { - "type": "boolean" - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnsuspensionResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/create": { - "post": { - "tags": ["DID"], - "summary": "Create a DID Document.", - "description": "This endpoint creates a DID and associated DID Document. As input, it can take the DID Document parameters via a form, or the fully-assembled DID Document itself.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidCreateRequestFormBased" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidCreateRequestJson" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/did/update": { - "post": { - "tags": ["DID"], - "summary": "Update a DID Document.", - "description": "This endpoint updates a DID Document. As an input, it can take JUST the sections/parameters that need to be updated in the DID Document (in this scenario, it fetches the current DID Document and applies the updated section). Alternatively, it take the fully-assembled DID Document with updated sections as well as unchanged sections.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidUpdateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidUpdateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidUpdateResponse" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/import": { - "post": { - "tags": ["DID"], - "summary": "Import a DID Document.", - "description": "This endpoint imports a decentralized identifier associated with the user's account for custodian-mode clients.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidImportRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidImportRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/did/deactivate/{did}": { - "post": { - "tags": ["DID"], - "summary": "Deactivate a DID Document.", - "description": "This endpoint deactivates a DID Document by taking the DID identifier as input. Must be called and signed by the DID owner.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier to deactivate.", - "schema": { - "type": "string" - }, - "required": true - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidDeactivateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidDeactivateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeactivatedDidResolution" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/list": { - "get": { - "tags": ["DID"], - "summary": "Fetch DIDs associated with an account.", - "description": "This endpoint returns the list of DIDs controlled by the account.", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/search/{did}": { - "get": { - "tags": ["DID"], - "summary": "Resolve a DID Document.", - "description": "Resolve a DID Document by DID identifier. Also supports DID Resolution Queries as defined in the W3C DID Resolution specification.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier to resolve.", - "schema": { - "type": "string" - }, - "required": true, - "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - { - "in": "query", - "name": "metadata", - "description": "Return only metadata of DID Document instead of actual DID Document.", - "schema": { - "type": "boolean" - } - }, - { - "in": "query", - "name": "versionId", - "description": "Unique UUID version identifier of DID Document. Allows for fetching a specific version of the DID Document. See cheqd DID Method Specification for more details.", - "schema": { - "type": "string", - "format": "uuid" - }, - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - { - "in": "query", - "name": "versionTime", - "description": "Returns the closest version of the DID Document *at* or *before* specified time. See DID Resolution handling for `did:cheqd` for more details.", - "schema": { - "type": "string", - "format": "date-time" - }, - "example": "1970-01-01T00:00:00Z" - }, - { - "in": "query", - "name": "transformKeys", - "description": "This directive transforms the Verification Method key format from the version in the DID Document to the specified format chosen below.", - "schema": { - "type": "string", - "enum": ["Ed25519VerificationKey2018", "Ed25519VerificationKey2020", "JsonWebKey2020"] - } - }, - { - "in": "query", - "name": "service", - "description": "Query DID Document for a specific Service Endpoint by Service ID (e.g., `service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`). This will typically redirect to the Service Endpoint based on DID Resolution specification algorithm.", - "schema": { - "type": "string" - }, - "example": "service-1" - }, - { - "in": "query", - "name": "relativeRef", - "description": "Relative reference is a query fragment appended to the Service Endpoint URL. **Must** be used along with the `service` query property above. See DID Resolution specification algorithm for more details.", - "schema": { - "type": "string" - }, - "example": "/path/to/file" - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidResolution" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/key/create": { - "post": { - "tags": ["Key"], - "summary": "Create an identity key pair.", - "description": "This endpoint creates an identity key pair associated with the user's account for custodian-mode clients.", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/key/import": { - "post": { - "tags": ["Key"], - "summary": "Import an identity key pair.", - "description": "This endpoint imports an identity key pair associated with the user's account for custodian-mode clients.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/KeyImportRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyImportRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/key/read/{kid}": { - "get": { - "tags": ["Key"], - "summary": "Fetch an identity key pair.", - "description": "This endpoint fetches an identity key pair's details for a given key ID. Only the user account associated with the custodian-mode client can fetch the key pair.", - "parameters": [ - { - "name": "kid", - "description": "Key ID of the identity key pair to fetch.", - "in": "path", - "schema": { - "type": "string" - }, - "required": true - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/presentation/create": { - "post": { - "tags": ["Presentation"], - "summary": "!!! WARN. Such endpoint is made mostly for testing purposes and it is not supposed to be used in production !!! Create a Verifiable Presentation from credential(s).", - "description": "This endpoint creates a Verifiable Presentation from credential(s). As input, it can take the credential(s) as a string or the entire credential(s) itself. \n !!! WARN. Such endpoint is made only for testing purposes !!!", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/PresentationCreateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/PresentationCreateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PresentationCreateResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/presentation/verify": { - "post": { - "tags": ["Presentation"], - "summary": "Verify a Verifiable Presentation generated from credential(s).", - "description": "This endpoint verifies the Verifiable Presentation generated from credential(s). As input, it can take the Verifiable Presentation JWT as a string or the entire Verifiable Presentation itself.", - "parameters": [ - { - "in": "query", - "name": "verifyStatus", - "description": "If set to `true` the verification will also check the status of the presentation. Requires the VP to have a `credentialStatus` property.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "fetchRemoteContexts", - "description": "When dealing with JSON-LD you also MUST provide the proper contexts. * Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "allowDeactivatedDid", - "description": "If set to `true` allow to verify credential which based on deactivated DID.", - "schema": { - "type": "boolean", - "default": false - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/PresentationVerifyRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/PresentationVerifyRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/VerifyPresentationResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/resource/create/{did}": { - "post": { - "tags": ["Resource"], - "summary": "Create a DID-Linked Resource.", - "description": "This endpoint creates a DID-Linked Resource. As input, it can take the DID identifier and the resource parameters via a form, or the fully-assembled resource itself.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier to link the resource to.", - "schema": { - "type": "string" - }, - "required": true - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CreateResourceRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateResourceRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ResourceMetadata" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/resource/search/{did}": { - "get": { - "tags": ["Resource"], - "summary": "Get a DID-Linked Resource.", - "description": "This endpoint returns the DID-Linked Resource for a given DID identifier and resource identifier.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier", - "schema": { - "type": "string" - }, - "required": true, - "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - { - "in": "query", - "name": "resourceId", - "description": "Fetch a DID-Linked Resource by Resource ID unique identifier. Since this is a unique identifier, other Resource query parameters are not required. See DID-Linked Resources for more details.", - "schema": { - "type": "string", - "format": "uuid" - }, - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - { - "in": "query", - "name": "resourceName", - "description": "Filter a DID-Linked Resource query by Resource Name. See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "cheqd-issuer-logo" - }, - { - "in": "query", - "name": "resourceType", - "description": "Filter a DID-Linked Resource query by Resource Type. See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "CredentialArtwork" - }, - { - "in": "query", - "name": "resourceVersion", - "description": "Filter a DID-Linked Resource query by Resource Version, which is an optional free-text field used by issuers (e.g., \"v1\", \"Final Version\", \"1st January 1970\" etc). See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "v1" - }, - { - "in": "query", - "name": "resourceVersionTime", - "description": "Filter a DID-Linked Resource query which returns the closest version of the Resource *at* or *before* specified time. See DID-Linked Resources for more details.", - "schema": { - "type": "string", - "format": "date-time" - }, - "example": "1970-01-01T00:00:00Z" - }, - { - "in": "query", - "name": "checksum", - "description": "Request integrity check against a given DID-Linked Resource by providing a SHA-256 checksum hash. See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "dc64474d062ed750a66bad58cb609928de55ed0d81defd231a4a4bf97358e9ed" - }, - { - "in": "query", - "name": "resourceMetadata", - "description": "Return only metadata of DID-Linked Resource instead of actual DID-Linked Resource. Mutually exclusive with some of the other parameters.", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "any": { - "schema": { - "type": "object" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - } - }, - "components": { - "schemas": { - "AlsoKnownAs": { - "type": "object", - "properties": { - "alsoKnownAs": { - "type": "array", - "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", - "items": { - "type": "object", - "properties": { - "uri": { - "type": "string", - "format": "uri", - "description": "URI where the DID-Linked Resource can be fetched from. Can be any type of URI (e.g., DID, HTTPS, IPFS, etc.)" - }, - "description": { - "type": "string", - "description": "Optional description of the URI." - } - } - } - } - } - }, - "CredentialRequest": { - "description": "Input fields for the creating a Verifiable Credential.", - "type": "object", - "additionalProperties": false, - "properties": { - "issuerDid": { - "description": "DID of the Verifiable Credential issuer. This needs to be a `did:cheqd` DID.", - "type": "string", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "subjectDid": { - "description": "DID of the Verifiable Credential holder/subject. This needs to be a `did:key` DID.", - "type": "string", - "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" - }, - "attributes": { - "description": "JSON object containing the attributes to be included in the credential.", - "type": "object", - "example": { - "name": "Bob", - "gender": "male" - } - }, - "@context": { - "description": "Optional properties to be included in the `@context` property of the credential.", - "type": "array", - "items": { - "type": "string" - }, - "example": ["https://schema.org/schema.jsonld", "https://veramo.io/contexts/profile/v1"] - }, - "type": { - "description": "Optional properties to be included in the `type` property of the credential.", - "type": "array", - "items": { - "type": "string" - }, - "example": ["Person"] - }, - "expirationDate": { - "description": "Optional expiration date according to the VC Data Model specification.", - "type": "string", - "format": "date-time", - "example": "2023-06-08T13:49:28.000Z" - }, - "format": { - "description": "Format of the Verifiable Credential. Defaults to VC-JWT.", - "type": "string", - "enum": ["jwt", "jsonld"], - "example": "jwt" - }, - "credentialStatus": { - "description": "Optional `credentialStatus` properties for VC revocation or suspension. Takes `statusListName` and `statusListPurpose` as inputs.", - "type": "object", - "required": ["statusPurpose", "statusListName"], - "properties": { - "statusPurpose": { - "type": "string", - "enum": ["revocation", "suspension"] - }, - "statusListName": { - "type": "string" - }, - "statusListIndex": { - "type": "number" - }, - "statusListVersion": { - "type": "string", - "format": "date-time" - }, - "statusListRangeStart": { - "type": "number" - }, - "statusListRangeEnd": { - "type": "number" - }, - "indexNotIn": { - "type": "number" - } - }, - "example": { - "statusPurpose": "revocation", - "statusListName": "employee-credentials" - } - } - }, - "required": ["issuerDid", "subjectDid", "attributes"], - "example": { - "issuerDid": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "subjectDid": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", - "attributes": { - "gender": "male", - "name": "Bob" - }, - "@context": ["https://schema.org"], - "type": ["Person"], - "format": "jwt", - "credentialStatus": { - "statusPurpose": "revocation", - "statusListName": "employee-credentials", - "statusListIndex": 10 - } - } - }, - "Credential": { - "description": "Input fields for revoking/suspending a Verifiable Credential.", - "type": "object", - "additionalProperties": false, - "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "https://www.w3.org/2018/credentials/v1", - "https://schema.org", - "https://veramo.io/contexts/profile/v1" - ] - }, - "type": { - "type": "array", - "items": { - "type": "string" - }, - "example": ["VerifiableCredential", "Person"] - }, - "expirationDate": { - "type": "string", - "format": "date-time", - "example": "2023-06-08T13:49:28.000Z" - }, - "issuer": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "DID", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - } - } - }, - "credentialSubject": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "DID", - "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" - } - } - }, - "credentialStatus": { - "type": "object", - "properties": { - "id": { - "type": "string", - "example": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20" - }, - "statusListIndex": { - "type": "number", - "example": 20 - }, - "statusPurpose": { - "type": "string", - "enum": ["revocation", "suspension"], - "example": "suspension" - }, - "type": { - "type": "string", - "enum": ["StatusList2021Entry"] - } - } - }, - "issuanceDate": { - "type": "string", - "format": "date-time", - "example": "2023-06-08T13:49:28.000Z" - }, - "proof": { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "jwt": { - "type": "string" - } - }, - "example": { - "type": "JwtProof2020", - "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg" - } - } - }, - "example": { - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://schema.org", - "https://veramo.io/contexts/profile/v1" - ], - "credentialSubject": { - "gender": "male", - "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", - "name": "Bob" - }, - "credentialStatus": { - "id": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20", - "statusIndex": 20, - "statusPurpose": "suspension", - "type": "StatusList2021Entry" - }, - "issuanceDate": "2023-06-08T13:49:28.000Z", - "issuer": { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "proof": { - "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg", - "type": "JwtProof2020" - }, - "type": ["VerifiableCredential", "Person"] - } - }, - "CredentialRevokeRequest": { - "type": "object", - "properties": { - "credential": { - "description": "Verifiable Credential to be revoked as a VC-JWT string or a JSON object.", - "oneOf": [ - { - "type": "object" - }, - { - "type": "string" - } - ] - }, - "symmetricKey": { - "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource. Required if the StatusList2021 DID-Linked Resource is encrypted.", - "type": "string" - } - } - }, - "RevocationResult": { - "properties": { - "revoked": { - "type": "boolean", - "example": true - } - } - }, - "SuspensionResult": { - "properties": { - "suspended": { - "type": "boolean", - "example": true - } - } - }, - "UnsuspensionResult": { - "properties": { - "unsuspended": { - "type": "boolean", - "example": true - } - } - }, - "CredentialVerifyRequest": { - "type": "object", - "properties": { - "credential": { - "description": "Verifiable Credential to be verified as a VC-JWT string or a JSON object.", - "type": "object" - }, - "policies": { - "description": "Custom verification policies to execute when verifying credential.", - "type": "object", - "properties": { - "issuanceDate": { - "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "expirationDate": { - "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "audience": { - "description": "Policy to skip the audience check when set to `false`.", - "type": "boolean", - "default": false - } - } - } - } - }, - "VerifyPresentationResult": { - "type": "object", - "properties": { - "verified": { - "type": "boolean" - }, - "issuer": { - "type": "string" - }, - "signer": { - "type": "object" - }, - "jwt": { - "type": "string" - }, - "verifiableCredential": { - "type": "object" - } - } - }, - "VerifyCredentialResult": { - "type": "object", - "properties": { - "verified": { - "type": "boolean" - }, - "issuer": { - "type": "string" - }, - "signer": { - "type": "object" - }, - "jwt": { - "type": "string" - }, - "verifiableCredential": { - "type": "object" - } - }, - "example": { - "verified": true, - "polices": {}, - "issuer": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "signer": { - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", - "type": "Ed25519VerificationKey2018" - } - } - }, - "PresentationCreateRequest": { - "type": "object", - "required": ["credentials"], - "properties": { - "credentials": { - "description": "Verifiable Credentials to be used for VP-JWT creation as a VP-JWT strings or a JSON objectsf.", - "type": "array", - "items": { - "type": "object" - } - }, - "holderDid": { - "description": "DID of holder", - "type": "string" - }, - "verifierDid": { - "description": "DID of verifier", - "type": "string" - } - } - }, - "PresentationVerifyRequest": { - "type": "object", - "required": ["presentation"], - "properties": { - "presentation": { - "description": "Verifiable Presentation to be verified as a VP-JWT string or a JSON object.", - "type": "object" - }, - "verifierDid": { - "description": "Provide an optional verifier DID (also known as 'domain' parameter), if the verifier DID in the presentation is not managed in the wallet.", - "type": "string" - }, - "makeFeePayment": { - "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", - "type": "boolean", - "default": false - }, - "policies": { - "description": "Custom verification policies to execute when verifying presentation.", - "type": "object", - "properties": { - "issuanceDate": { - "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "expirationDate": { - "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "audience": { - "description": "Policy to skip the audience check when set to `false`.", - "type": "boolean", - "default": false - } - } - } - } - }, - "CredentialStatusCreateBody": { - "allOf": [ - { - "type": "object", - "required": ["did", "statusListName"], - "properties": { - "did": { - "description": "DID of the StatusList2021 publisher.", - "type": "string", - "format": "uri" - }, - "statusListName": { - "description": "The name of the StatusList2021 DID-Linked Resource to be created.", - "type": "string" - }, - "length": { - "description": "The length of the status list to be created. The default and minimum length is 140000 which is 16kb.", - "type": "integer", - "minimum": 0, - "exclusiveMinimum": true, - "default": 140000 - }, - "encoding": { - "description": "The encoding format of the StatusList2021 DiD-Linked Resource to be created.", - "type": "string", - "default": "base64url", - "enum": ["base64url", "base64", "hex"] - }, - "statusListVersion": { - "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - { - "$ref": "#/components/schemas/AlsoKnownAs" - } - ] - }, - "CredentialStatusCreateUnencryptedRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCreateBody" - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials", - "length": 140000, - "encoding": "base64url" - } - }, - "CredentialStatusUnencryptedResult": { - "type": "object", - "properties": { - "resource": { - "type": "object", - "properties": { - "StatusList2021": { - "type": "object", - "properties": { - "encodedList": { - "type": "string", - "example": "H4sIAAAAAAAAA-3BAQ0AAADCoPdPbQ8HFAAAAAAAAAAAAAAAAAAAAADwaDhDr_xcRAAA" - }, - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "validFrom": { - "type": "string", - "format": "date-time", - "example": "2023-06-26T11:45:19.349Z" - } - } - }, - "metadata": { - "type": "object", - "properties": { - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "encoding": { - "type": "string", - "example": "base64url" - }, - "encrypted": { - "type": "boolean", - "example": false - } - } - } - } - }, - "resourceMetadata": { - "type": "object", - "example": { - "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceName": "cheqd-employee-credentials", - "resourceType": "StatusList2021Revocation", - "mediaType": "application/json", - "resourceVersion": "1.0.0", - "created": "2023-06-26T11:45:20Z", - "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", - "previousVersionId": null, - "nextVersionId": null - } - } - } - }, - "CredentialStatusCreateUnencryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "created": { - "type": "boolean", - "example": true - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" - } - ] - }, - "CredentialStatusEncryptedPaymentConditionsBody": { - "type": "object", - "properties": { - "feePaymentAddress": { - "description": "The cheqd/Cosmos payment address where payments to unlock the encrypted StatusList2021 DID-Linked Resource need to be sent.", - "type": "string", - "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" - }, - "feePaymentAmount": { - "description": "Amount in CHEQ tokens to unlock the encrypted StatusList2021 DID-Linked Resource.", - "type": "number", - "minimum": 0, - "exclusiveMinimum": true, - "default": 20 - }, - "feePaymentWindow": { - "description": "Time window (in minutes) within which the payment to unlock the encrypted StatusList2021 DID-Linked Resource is considered valid.", - "type": "number", - "minimum": 0, - "exclusiveMinimum": true, - "default": 10 - } - } - }, - "CredentialStatusEncryptedPaymentConditionsJson": { - "type": "object", - "properties": { - "paymentConditions": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" - } - ] - } - } - }, - "CredentialStatusCreateEncryptedFormRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCreateBody" - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" - }, - { - "type": "object", - "required": ["feePaymentAddress", "feePaymentAmount", "feePaymentWindow"] - } - ] - }, - "CredentialStatusCreateEncryptedJsonRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCreateBody" - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" - }, - { - "type": "object", - "required": ["paymentConditions"] - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials-encrypted", - "paymentConditions": [ - { - "feePaymentAddress": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg", - "feePaymentAmount": 20, - "feePaymentWindow": 10 - } - ] - } - }, - "CredentialStatusEncryptedResult": { - "type": "object", - "properties": { - "resource": { - "type": "object", - "properties": { - "StatusList2021": { - "type": "object", - "properties": { - "encodedList": { - "type": "string", - "example": "496fdfbeb745b4db03fcdb40566f9c4c4a1c0f184b31255e641b6e7bdfb9b6946c12be87ca3763be0393c00b67ac1e8737c106b32f46ef59c765754415b5e8cc7c65fccaa3374620430ea476301a5e0dd63340e7a27a68bc627518471f22e4a2" - }, - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "validFrom": { - "type": "string", - "format": "date-time", - "example": "2023-06-26T11:45:19.349Z" - } - } - }, - "metadata": { - "type": "object", - "properties": { - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "encoding": { - "type": "string", - "example": "base64url" - }, - "encrypted": { - "type": "boolean", - "example": true - }, - "encryptedSymmetricKey": { - "type": "string", - "example": "b11182dc524b8181f9a6aef4c4ad0a1c14e40033b9112dffd8d1bcf6cc3b85abc07ded2205ee94068a99f4202502cb0855f322583fa6ce1534d3a05bf36891766ea2c5f90a982b3040680762977d404d758a2370224a239c8279aa7d21e980931c42055b17ca4c7dbffa4782480a8b6279cf989b2f166d5fdb4b2c1b5a63927200000000000000203018dcaba26df45a415bb599218b27ca853a70289d7a3ed3ed0e3730452e8f8d9af91b6e71312565d2c069341f6660ab" - }, - "paymentConditions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "feePaymentAddress": { - "type": "string", - "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" - }, - "feePaymentAmount": { - "type": "string", - "example": "20000000000ncheq" - }, - "intervalInSeconds": { - "type": "number", - "example": 600 - }, - "type": { - "type": "string", - "example": "timelockPayment" - } - } - } - } - } - }, - "resourceMetadata": { - "type": "object", - "example": { - "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceName": "cheqd-revocation-encrypted-1", - "resourceType": "StatusList2021Revocation", - "mediaType": "application/json", - "resourceVersion": "2023-06-26T11:45:19.349Z", - "created": "2023-06-26T11:45:20Z", - "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", - "previousVersionId": null, - "nextVersionId": null - } - }, - "symmetricKey": { - "type": "string", - "example": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" - } - } - } - } - }, - "CredentialStatusCreateEncryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "created": { - "type": "boolean", - "example": true - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedResult" - } - ] - }, - "CredentialStatusUpdateBody": { - "type": "object", - "required": ["did", "statusListName", "indices"], - "properties": { - "did": { - "description": "DID of the StatusList2021 publisher.", - "type": "string", - "format": "uri" - }, - "statusListName": { - "description": "The name of the StatusList2021 DID-Linked Resource to be updated.", - "type": "string" - }, - "indices": { - "description": "List of credential status indices to be updated. The indices must be in the range of the status list.", - "type": "array", - "items": { - "type": "integer", - "minimum": 0, - "exclusiveMinimum": false - } - }, - "statusListVersion": { - "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - "CredentialStatusUpdateUnencryptedRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUpdateBody" - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials", - "indices": [10, 3199, 12109, 130999] - } - }, - "CredentialStatusUpdateUnencryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "updated": { - "type": "boolean", - "example": true - } - } - }, - { - "oneOf": [ - { - "$ref": "#/components/schemas/RevocationResult" - }, - { - "$ref": "#/components/schemas/SuspensionResult" - }, - { - "$ref": "#/components/schemas/UnsuspensionResult" - } - ] - }, - { - "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" - } - ] - }, - "CredentialStatusUpdateEncryptedFormRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUpdateBody" - }, - { - "type": "object", - "required": ["symmetricKey"], - "properties": { - "symmetricKey": { - "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" - } - ] - }, - "CredentialStatusUpdateEncryptedJsonRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUpdateBody" - }, - { - "type": "object", - "required": ["symmetricKey"], - "properties": { - "symmetricKey": { - "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials-encrypted", - "indices": [10, 3199, 12109, 130999], - "symmetricKey": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" - } - }, - "CredentialStatusUpdateEncryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "updated": { - "type": "boolean", - "example": true - } - } - }, - { - "oneOf": [ - { - "$ref": "#/components/schemas/RevocationResult" - }, - { - "$ref": "#/components/schemas/SuspensionResult" - }, - { - "$ref": "#/components/schemas/UnsuspensionResult" - } - ] - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedResult" - } - ] - }, - "CredentialStatusCheckRequest": { - "type": "object", - "required": ["did", "statusListName", "index"], - "properties": { - "did": { - "description": "DID of the StatusList2021 publisher.", - "type": "string", - "format": "uri" - }, - "statusListName": { - "description": "The name of the StatusList2021 DID-Linked Resource to be checked.", - "type": "string" - }, - "index": { - "description": "Credential status index to be checked for revocation or suspension.", - "type": "integer", - "minimum": 0, - "exclusiveMinimum": false - }, - "makeFeePayment": { - "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", - "type": "boolean", - "default": true - } - } - }, - "CredentialStatusCheckResult": { - "oneOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCheckRevocationResult" - }, - { - "$ref": "#/components/schemas/CredentialStatusCheckSuspensionResult" - } - ] - }, - "CredentialStatusCheckRevocationResult": { - "type": "object", - "properties": { - "checked": { - "type": "boolean", - "example": true - }, - "revoked": { - "type": "boolean", - "example": false - } - } - }, - "CredentialStatusCheckSuspensionResult": { - "type": "object", - "properties": { - "checked": { - "type": "boolean", - "example": true - }, - "suspended": { - "type": "boolean", - "example": false - } - } - }, - "CredentialStatusListSearchResult": { - "allOf": [ - { - "type": "object", - "properties": { - "found": { - "type": "boolean", - "example": true - } - } - }, - { - "oneOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedResult" - } - ] - } - ] - }, - "KeyImportRequest": { - "type": "object", - "properties": { - "alias": { - "type": "string" - }, - "type": { - "type": "string", - "enum": ["Ed25519", "Secp256k1"] - }, - "privateKeyHex": { - "type": "string" - } - } - }, - "KeyResult": { - "type": "object", - "properties": { - "kid": { - "type": "string" - }, - "type": { - "type": "string", - "enum": ["Ed25519", "Secp256k1"] - }, - "publicKeyHex": { - "type": "string" - } - } - }, - "DidDocument": { - "description": "This input field contains either a complete DID document, or an incremental change (diff) to a DID document. See Universal DID Registrar specification.", - "type": "object", - "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - } - }, - "id": { - "type": "string" - }, - "controllers": { - "type": "array", - "items": { - "type": "string" - } - }, - "verificationMethod": { - "type": "array", - "items": { - "$ref": "#/components/schemas/VerificationMethod" - } - }, - "service": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "authentication": { - "type": "array", - "items": { - "type": "string" - } - }, - "assertionMethod": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityInvocation": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityDelegation": { - "type": "array", - "items": { - "type": "string" - } - }, - "keyAgreement": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "@context": ["https://www.w3.org/ns/did/v1"], - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "controller": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0"], - "verificationMethod": [ - { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "type": "Ed25519VerificationKey2018", - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "publicKeyBase58": "z6MkkVbyHJLLjdjU5B62DaJ4mkdMdUkttf9UqySSkA9bVTeZ" - } - ], - "authentication": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1"], - "service": [ - { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", - "type": "LinkedDomains", - "serviceEndpoint": ["https://example.com"] - } - ] - } - }, - "DidDocumentWithoutVerificationMethod": { - "type": "object", - "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - } - }, - "id": { - "type": "string" - }, - "controllers": { - "type": "array", - "items": { - "type": "string" - } - }, - "service": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "authentication": { - "type": "array", - "items": { - "type": "string" - } - }, - "assertionMethod": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityInvocation": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityDelegation": { - "type": "array", - "items": { - "type": "string" - } - }, - "keyAgreement": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "@context": ["https://www.w3.org/ns/did/v1"], - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "controller": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0"], - "authentication": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1"], - "service": [ - { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", - "type": "LinkedDomains", - "serviceEndpoint": ["https://example.com"] - } - ] - } - }, - "DidCreateRequestFormBased": { - "type": "object", - "properties": { - "network": { - "description": "Network to create the DID on (testnet or mainnet)", - "type": "string", - "enum": ["testnet", "mainnet"] - }, - "identifierFormatType": { - "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", - "type": "string", - "enum": ["uuid", "base58btc"] - }, - "verificationMethodType": { - "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", - "type": "string", - "enum": ["Ed25519VerificationKey2018", "JsonWebKey2020", "Ed25519VerificationKey2020"] - }, - "service": { - "description": "It's a list of special objects which are designed to build the actual service. It's almost the same as in DID Core specification, but instead of `id` it utilises `idFragment` field for making the right `id` for each service. !!! WARN. Cause swagger-ui does not handle x-ww-form based arrays correctly, please frame all your services in brackets while using swagger UI. !!!", - "type": "array", - "items": { - "type": "object", - "properties": { - "idFragment": { - "type": "string" - }, - "type": { - "type": "string" - }, - "serviceEndpoint": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "example": [ - { - "idFragment": "service-1", - "type": "LinkedDomains", - "serviceEndpoint": ["https://example.com"] - } - ] - }, - "key": { - "description": "The unique identifier in hexadecimal public key format used in the verification method to create the DID.", - "type": "string" - }, - "@context": { - "type": "array", - "items": { - "type": "string" - }, - "example": ["https://www.w3.org/ns/did/v1"] - } - } - }, - "DidCreateRequestJson": { - "type": "object", - "properties": { - "network": { - "description": "Network to create the DID on (testnet or mainnet)", - "type": "string", - "enum": ["testnet", "mainnet"] - }, - "identifierFormatType": { - "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", - "type": "string", - "enum": ["uuid", "base58btc"] - }, - "assertionMethod": { - "description": "Usually a reference to a Verification Method. An Assertion Method is required to issue JSON-LD credentials. See DID Core specification for more details.", - "type": "boolean", - "default": true - }, - "options": { - "type": "object", - "properties": { - "key": { - "type": "string", - "example": "8255ddadd75695e01f3d98fcec8ccc7861a030b317d4326b0e48a4d579ddc43a" - }, - "verificationMethodType": { - "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", - "type": "string", - "enum": ["Ed25519VerificationKey2018", "JsonWebKey2020", "Ed25519VerificationKey2020"] - } - } - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocumentWithoutVerificationMethod" - } - } - }, - "DidImportRequest": { - "type": "object", - "properties": { - "did": { - "type": "string", - "description": "DID to be imported", - "format": "uri", - "required": true - }, - "keys": { - "type": "array", - "description": "List of keys required to import the DID", - "required": true, - "items": { - "$ref": "#/components/schemas/KeyImportRequest" - } - } - } - }, - "PresentationCreateResult": { - "type": "object", - "properties": { - "vp": { - "type": "object", - "description": "Verifiable Presentation which could be provided to the verifier." - }, - "nbf": { - "type": "integer", - "description": "Unix timestamp of the earliest time that the Verifiable Presentation is valid." - }, - "iss": { - "type": "string", - "description": "DID of the issuer of the Verifiable Presentation. (Here it's supposed to be a holder DID)" - }, - "aud": { - "type": "array", - "items": { - "type": "string" - }, - "description": "DID of the verifier of the Verifiable Presentation." - } - }, - "example": { - "vp": { - "@context": ["https://www.w3.org/2018/credentials/v1"], - "type": ["VerifiablePresentation"], - "verifiableCredential": [ - "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc2NoZW1hLm9yZy9zY2hlbWEuanNvbmxkIiwiaHR0cHM6Ly92ZXJhbW8uaW8vY29udGV4dHMvcHJvZmlsZS92MSIsImh0dHBzOi8vdzNpZC5vcmcvdmMtc3RhdHVzLWxpc3QtMjAyMS92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiUGVyc29uIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7Im5hbWUiOiJCb2IiLCJnZW5kZXIiOiJtYWxlIn0sImNyZWRlbnRpYWxTdGF0dXMiOnsiaWQiOiJodHRwczovL3Jlc29sdmVyLmNoZXFkLm5ldC8xLjAvaWRlbnRpZmllcnMvZGlkOmNoZXFkOnRlc3RuZXQ6OTBkNWMxNDEtNzI0Zi00N2FkLTlhZTctYTdjMzNhOWU1NjQzP3Jlc291cmNlTmFtZT1zdXNwZW5zaW9uRW4mcmVzb3VyY2VUeXBlPVN0YXR1c0xpc3QyMDIxU3VzcGVuc2lvbiMxMzMzOCIsInR5cGUiOiJTdGF0dXNMaXN0MjAyMUVudHJ5Iiwic3RhdHVzUHVycG9zZSI6InN1c3BlbnNpb24iLCJzdGF0dXNMaXN0SW5kZXgiOiIxMzMzOCJ9fSwic3ViIjoiZGlkOmtleTp6Nk1raGFYZ0JaRHZvdERrTDUyNTdmYWl6dGlHaUMyUXRLTEdwYm5uRUd0YTJkb0siLCJuYmYiOjE3MDA0NzM0MTYsImlzcyI6ImRpZDpjaGVxZDp0ZXN0bmV0OjkwZDVjMTQxLTcyNGYtNDdhZC05YWU3LWE3YzMzYTllNTY0MyJ9.-14Ril1pZEy2HEEo48gTJr2yOtGxBhUGTFmzVdjAtyhFRsW5zZg9onHt6V9JQ8BaiYBlTkP9GzTnJ-O6hdiyCw" - ] - }, - "nbf": 1700744275, - "iss": "did:cheqd:testnet:4b846d0f-2f6c-4ab6-9fe2-5b8db301c83c", - "aud": ["did:cheqd:testnet:8c71e9b6-c5a3-4250-8c58-fa591533cd22"] - } - }, - "DidResult": { - "type": "object", - "properties": { - "did": { - "type": "string" - }, - "controllerKeyId": { - "type": "string" - }, - "keys": { - "type": "array", - "items": { - "type": "object" - } - }, - "services": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - } - } - }, - "DidUpdateResponse": { - "type": "object", - "properties": { - "did": { - "type": "string" - }, - "controllerKeyId": { - "type": "string", - "description": "The default key id of which is the key associated with the first verificationMethod" - }, - "keys": { - "type": "array", - "description": "The list of keys associated with the list of verificationMethod's of DIDDocument", - "items": { - "type": "object" - } - }, - "services": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "controllerKeyRefs": { - "type": "array", - "description": "The list of keyRefs which were used for signing the transaction", - "items": { - "type": "string" - } - }, - "controllerKeys": { - "type": "array", - "description": "The list of all possible keys, inlcuding all controller's keys", - "items": { - "type": "string" - } - } - } - }, - "VerificationMethod": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string" - }, - "controller": { - "type": "string" - }, - "publicKeyMultibase": { - "type": "string" - }, - "publicKeyJwk": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "id": "did:cheqd:testnet :7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", - "type": "Ed25519VerificationKey2018" - } - }, - "Service": { - "description": "Communicating or interacting with the DID subject or associated entities via one or more service endpoints. See DID Core specification for more details.", - "type": "object", - "properties": { - "id": { - "description": "DID appended with Service fragment ID (e.g., `#service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`)", - "type": "string", - "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1" - }, - "type": { - "description": "Service type as defined in DID Specification Registries.", - "type": "string", - "example": "LinkedDomains" - }, - "serviceEndpoint": { - "description": "Service endpoint as defined in DID Core Specification.", - "type": "array", - "items": { - "type": "string", - "example": "https://example.com" - } - } - } - }, - "DidUpdateRequest": { - "type": "object", - "properties": { - "did": { - "description": "DID identifier to be updated.", - "type": "string", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "service": { - "type": "array", - "description": "Service section of the DID Document.", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "verificationMethod": { - "type": "array", - "description": "Verification Method section of the DID Document.", - "items": { - "$ref": "#/components/schemas/VerificationMethod" - } - }, - "authentication": { - "description": "Authentication section of the DID Document.", - "type": "array", - "items": { - "type": "string" - } - }, - "publicKeyHexs": { - "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", - "type": "array", - "items": { - "type": "string" - } - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - } - } - }, - "DidDeactivateRequest": { - "type": "object", - "properties": { - "publicKeyHexs": { - "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "CreateResourceRequest": { - "description": "Input fields for DID-Linked Resource creation.", - "type": "object", - "additionalProperties": false, - "required": ["name", "type", "data", "encoding"], - "properties": { - "data": { - "description": "Encoded string containing the data to be stored in the DID-Linked Resource.", - "type": "string" - }, - "encoding": { - "description": "Encoding format used to encode the data.", - "type": "string", - "enum": ["base64url", "base64", "hex"] - }, - "name": { - "description": "Name of DID-Linked Resource.", - "type": "string" - }, - "type": { - "description": "Type of DID-Linked Resource. This is NOT the same as the media type, which is calculated automatically ledger-side.", - "type": "string" - }, - "alsoKnownAs": { - "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", - "type": "array", - "items": { - "type": "object", - "properties": { - "uri": { - "type": "string" - }, - "description": { - "type": "string" - } - } - } - }, - "version": { - "description": "Optional field to assign a human-readable version in the DID-Linked Resource.", - "type": "string" - }, - "publicKeyHexs": { - "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "data": "SGVsbG8gV29ybGQ=", - "encoding": "base64url", - "name": "ResourceName", - "type": "TextDocument" - } - }, - "ResourceList": { - "type": "object", - "properties": { - "@context": { - "type": "string", - "example": "https://w3id.org/did-resolution/v1" - }, - "contentMetadata": { - "type": "object" - }, - "contentStream": { - "type": "object" - }, - "dereferencingMetadata": { - "$ref": "#/components/schemas/DereferencingMetadata" - } - } - }, - "DereferencingMetadata": { - "type": "object", - "properties": { - "contentType": { - "type": "string", - "example": "application/did+ld+json" - }, - "did": { - "$ref": "#/components/schemas/DidProperties" - }, - "retrieved": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - } - } - }, - "DidResolution": { - "type": "object", - "properties": { - "@context": { - "type": "string", - "example": "https://w3id.org/did-resolution/v1" - }, - "didDidResolutionMetadata": { - "$ref": "#/components/schemas/DidResolutionMetadata" - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - }, - "didDocumentMetadata": { - "$ref": "#/components/schemas/DidDocumentMetadata" - } - } - }, - "DeactivatedDidResolution": { - "type": "object", - "properties": { - "@context": { - "type": "string", - "example": "https://w3id.org/did-resolution/v1" - }, - "didDidResolutionMetadata": { - "$ref": "#/components/schemas/DidResolutionMetadata" - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - }, - "didDocumentMetadata": { - "$ref": "#/components/schemas/DeactivatedDidDocumentMetadata" - } - } - }, - "DidDocumentMetadata": { - "type": "object", - "properties": { - "created": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "deactivated": { - "type": "boolean", - "example": false - }, - "updated": { - "type": "string", - "example": "2021-09-10T12:00:00Z" - }, - "versionId": { - "type": "string", - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - "linkedResourceMetadata": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ResourceMetadata" - } - } - } - }, - "DeactivatedDidDocumentMetadata": { - "type": "object", - "properties": { - "created": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "deactivated": { - "type": "boolean", - "example": true - }, - "updated": { - "type": "string", - "example": "2021-09-10T12:00:00Z" - }, - "versionId": { - "type": "string", - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - "linkedResourceMetadata": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ResourceMetadata" - } - } - } - }, - "ResourceMetadata": { - "type": "object", - "properties": { - "resourceURI": { - "type": "string", - "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47/resources/398cee0a-efac-4643-9f4c-74c48c72a14b" - }, - "resourceCollectionId": { - "type": "string", - "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" - }, - "resourceId": { - "type": "string", - "example": "398cee0a-efac-4643-9f4c-74c48c72a14b" - }, - "resourceName": { - "type": "string", - "example": "cheqd-issuer-logo" - }, - "resourceType": { - "type": "string", - "example": "CredentialArtwork" - }, - "mediaType": { - "type": "string", - "example": "image/png" - }, - "resourceVersion": { - "type": "string", - "example": "1.0" - }, - "checksum": { - "type": "string", - "example": "a95380f460e63ad939541a57aecbfd795fcd37c6d78ee86c885340e33a91b559" - }, - "created": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "nextVersionId": { - "type": "string", - "example": "d4829ac7-4566-478c-a408-b44767eddadc" - }, - "previousVersionId": { - "type": "string", - "example": "ad7a8442-3531-46eb-a024-53953ec6e4ff" - } - } - }, - "DidResolutionMetadata": { - "type": "object", - "properties": { - "contentType": { - "allOf": [ - { - "$ref": "#/components/schemas/ContentType" - } - ], - "example": "application/did+ld+json" - }, - "retrieved": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "did": { - "$ref": "#/components/schemas/DidProperties" - } - } - }, - "ContentType": { - "type": "string", - "enum": ["application/did+json", "application/did+ld+json", "application/ld+json", "application/json"] - }, - "DidProperties": { - "type": "object", - "properties": { - "didString": { - "type": "string", - "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" - }, - "method": { - "type": "string", - "example": "cheqd" - }, - "methodSpecificId": { - "type": "string", - "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" - } - } - }, - "Customer": { - "type": "object", - "properties": { - "customerId": { - "type": "string", - "example": "6w5drpiiwhhs" - }, - "address": { - "type": "string", - "example": "cheqd1wgsvqwlkmdp60f4dek26ak0sjw6au3ytd3pz7f" - } - } - }, - "AccountCreateRequest": { - "type": "object", - "properties": { - "user": { - "type": "object", - "properties": { - "primaryEmail": { - "type": "string" - } - } - } - } - }, - "InvalidRequest": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "InvalidRequest" - } - } - }, - "InternalError": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Internal Error" - } - } - }, - "UnauthorizedError": { - "description": "Access token is missing or invalid", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Unauthorized Error" - } - } - } - } - } -} + "openapi": "3.0.0", + "info": { + "title": "Credential Service API for cheqd network", + "version": "2.0.0", + "description": "API service to create and manage DIDs, Verifiable Credentials, and DID-Linked Resources", + "contact": { + "name": "Cheqd Foundation Limited", + "url": "https://github.com/cheqd/credential-service", + "email": "support-github@cheqd.io" + }, + "license": { + "name": "Apache 2.0", + "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" + } + }, + "tags": [ + { + "name": "Account" + }, + { + "name": "Key" + }, + { + "name": "DID" + }, + { + "name": "Resource" + }, + { + "name": "Credential" + }, + { + "name": "Presentation" + }, + { + "name": "Credential Status" + } + ], + "externalDocs": { + "description": "Credential Service API Documentation", + "url": "https://docs.cheqd.io/identity" + }, + "paths": { + "/account": { + "get": { + "tags": [ + "Account" + ], + "summary": "Fetch custodian-mode client details.", + "description": "This endpoint returns the custodian-mode client details for authenticated users.", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Customer" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/account/idtoken": { + "get": { + "tags": [ + "Account" + ], + "summary": "Fetch IdToken.", + "description": "This endpoint returns IdToken as JWT with list of user roles inside", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "idToken": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/account/create": { + "post": { + "tags": [ + "Account" + ], + "summary": "Create an client for an authenticated user.", + "description": "This endpoint creates a client in the custodian-mode for an authenticated user", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/AccountCreateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "idToken": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/create/unencrypted": { + "post": { + "tags": [ + "Credential Status" + ], + "summary": "Create an unencrypted StatusList2021 credential status list.", + "description": "This endpoint creates an unencrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", + "required": true, + "schema": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/create/encrypted": { + "post": { + "tags": [ + "Credential Status" + ], + "summary": "Create an encrypted StatusList2021 credential status list.", + "description": "This endpoint creates an encrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", + "required": true, + "schema": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateEncryptedFormRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateEncryptedJsonRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateEncryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/update/unencrypted": { + "post": { + "tags": [ + "Credential Status" + ], + "summary": "Update an existing unencrypted StatusList2021 credential status list.", + "parameters": [ + { + "in": "query", + "name": "statusAction", + "description": "The update action to be performed on the unencrypted status list, can be revoke, suspend or reinstate", + "required": true, + "schema": { + "type": "string", + "enum": [ + "revoke", + "suspend", + "reinstate" + ] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/update/encrypted": { + "post": { + "tags": [ + "Credential Status" + ], + "summary": "Update an existing encrypted StatusList2021 credential status list.", + "parameters": [ + { + "in": "query", + "name": "statusAction", + "description": "The update action to be performed on the encrypted status list, can be revoke, suspend or reinstate", + "required": true, + "schema": { + "type": "string", + "enum": [ + "revoke", + "suspend", + "reinstate" + ] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedFormRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedJsonRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/check": { + "post": { + "tags": [ + "Credential Status" + ], + "summary": "Check a StatusList2021 index for a given Verifiable Credential.", + "description": "This endpoint checks a StatusList2021 index for a given Verifiable Credential and reports whether it is revoked or suspended. It offers a standalone method for checking an index without passing the entire Verifiable Credential or Verifiable Presentation.", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension.", + "required": true, + "schema": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCheckRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCheckRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCheckResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/search": { + "get": { + "tags": [ + "Credential Status" + ], + "summary": "Fetch StatusList2021 DID-Linked Resource based on search criteria.", + "parameters": [ + { + "in": "query", + "name": "did", + "description": "The DID of the issuer of the status list.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension.", + "schema": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ] + } + }, + { + "in": "query", + "name": "statusListName", + "description": "The name of the StatusList2021 DID-Linked Resource.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusListSearchResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/issue": { + "post": { + "tags": [ + "Credential" + ], + "summary": "Issue a Verifiable Credential", + "description": "This endpoint issues a Verifiable Credential. As input it takes the list of issuerDid, subjectDid, attributes, and other parameters of the credential to be issued.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Credential" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/verify": { + "post": { + "tags": [ + "Credential" + ], + "summary": "Verify a Verifiable Credential.", + "description": "This endpoint verifies a Verifiable Credential passed to it. As input, it can take the VC-JWT as a string or the entire credential itself.", + "operationId": "verify", + "parameters": [ + { + "in": "query", + "name": "verifyStatus", + "description": "If set to `true` the verification will also check the status of the credential. Requires the VC to have a `credentialStatus` property.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "fetchRemoteContexts", + "description": "When dealing with JSON-LD you also MUST provide the proper contexts. Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "allowDeactivatedDid", + "description": "If set to `true` allow to verify credential which based on deactivated DID.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialVerifyRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialVerifyRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyCredentialResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/revoke": { + "post": { + "tags": [ + "Credential" + ], + "summary": "Revoke a Verifiable Credential.", + "description": "This endpoint revokes a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself. The StatusList2021 resource should already be setup in the VC and `credentialStatus` property present in the VC.", + "operationId": "revoke", + "parameters": [ + { + "in": "query", + "name": "publish", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RevocationResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/suspend": { + "post": { + "tags": [ + "Credential" + ], + "summary": "Suspend a Verifiable Credential.", + "description": "This endpoint suspends a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself.", + "operationId": "suspend", + "parameters": [ + { + "in": "query", + "name": "publish", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuspensionResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/reinstate": { + "post": { + "tags": [ + "Credential" + ], + "summary": "Reinstate a suspended Verifiable Credential.", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "operationId": "reinstate", + "parameters": [ + { + "in": "query", + "name": "publish", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnsuspensionResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/create": { + "post": { + "tags": [ + "DID" + ], + "summary": "Create a DID Document.", + "description": "This endpoint creates a DID and associated DID Document. As input, it can take the DID Document parameters via a form, or the fully-assembled DID Document itself.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidCreateRequestFormBased" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidCreateRequestJson" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/did/update": { + "post": { + "tags": [ + "DID" + ], + "summary": "Update a DID Document.", + "description": "This endpoint updates a DID Document. As an input, it can take JUST the sections/parameters that need to be updated in the DID Document (in this scenario, it fetches the current DID Document and applies the updated section). Alternatively, it take the fully-assembled DID Document with updated sections as well as unchanged sections.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidUpdateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidUpdateResponse" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/import": { + "post": { + "tags": [ + "DID" + ], + "summary": "Import a DID Document.", + "description": "This endpoint imports a decentralized identifier associated with the user's account for custodian-mode clients.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidImportRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidImportRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/did/deactivate/{did}": { + "post": { + "tags": [ + "DID" + ], + "summary": "Deactivate a DID Document.", + "description": "This endpoint deactivates a DID Document by taking the DID identifier as input. Must be called and signed by the DID owner.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier to deactivate.", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidDeactivateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidDeactivateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeactivatedDidResolution" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/list": { + "get": { + "tags": [ + "DID" + ], + "summary": "Fetch DIDs associated with an account.", + "description": "This endpoint returns the list of DIDs controlled by the account.", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/search/{did}": { + "get": { + "tags": [ + "DID" + ], + "summary": "Resolve a DID Document.", + "description": "Resolve a DID Document by DID identifier. Also supports DID Resolution Queries as defined in the W3C DID Resolution specification.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier to resolve.", + "schema": { + "type": "string" + }, + "required": true, + "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + { + "in": "query", + "name": "metadata", + "description": "Return only metadata of DID Document instead of actual DID Document.", + "schema": { + "type": "boolean" + } + }, + { + "in": "query", + "name": "versionId", + "description": "Unique UUID version identifier of DID Document. Allows for fetching a specific version of the DID Document. See cheqd DID Method Specification for more details.", + "schema": { + "type": "string", + "format": "uuid" + }, + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + { + "in": "query", + "name": "versionTime", + "description": "Returns the closest version of the DID Document *at* or *before* specified time. See DID Resolution handling for `did:cheqd` for more details.", + "schema": { + "type": "string", + "format": "date-time" + }, + "example": "1970-01-01T00:00:00Z" + }, + { + "in": "query", + "name": "transformKeys", + "description": "This directive transforms the Verification Method key format from the version in the DID Document to the specified format chosen below.", + "schema": { + "type": "string", + "enum": [ + "Ed25519VerificationKey2018", + "Ed25519VerificationKey2020", + "JsonWebKey2020" + ] + } + }, + { + "in": "query", + "name": "service", + "description": "Query DID Document for a specific Service Endpoint by Service ID (e.g., `service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`). This will typically redirect to the Service Endpoint based on DID Resolution specification algorithm.", + "schema": { + "type": "string" + }, + "example": "service-1" + }, + { + "in": "query", + "name": "relativeRef", + "description": "Relative reference is a query fragment appended to the Service Endpoint URL. **Must** be used along with the `service` query property above. See DID Resolution specification algorithm for more details.", + "schema": { + "type": "string" + }, + "example": "/path/to/file" + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResolution" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/key/create": { + "post": { + "tags": [ + "Key" + ], + "summary": "Create an identity key pair.", + "description": "This endpoint creates an identity key pair associated with the user's account for custodian-mode clients.", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/key/import": { + "post": { + "tags": [ + "Key" + ], + "summary": "Import an identity key pair.", + "description": "This endpoint imports an identity key pair associated with the user's account for custodian-mode clients.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/KeyImportRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyImportRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/key/read/{kid}": { + "get": { + "tags": [ + "Key" + ], + "summary": "Fetch an identity key pair.", + "description": "This endpoint fetches an identity key pair's details for a given key ID. Only the user account associated with the custodian-mode client can fetch the key pair.", + "parameters": [ + { + "name": "kid", + "description": "Key ID of the identity key pair to fetch.", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/presentation/create": { + "post": { + "tags": [ + "Presentation" + ], + "summary": "!!! WARN. Such endpoint is made mostly for testing purposes and it is not supposed to be used in production !!! Create a Verifiable Presentation from credential(s).", + "description": "This endpoint creates a Verifiable Presentation from credential(s). As input, it can take the credential(s) as a string or the entire credential(s) itself. \n !!! WARN. Such endpoint is made only for testing purposes !!!", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/PresentationCreateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationCreateResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/presentation/verify": { + "post": { + "tags": [ + "Presentation" + ], + "summary": "Verify a Verifiable Presentation generated from credential(s).", + "description": "This endpoint verifies the Verifiable Presentation generated from credential(s). As input, it can take the Verifiable Presentation JWT as a string or the entire Verifiable Presentation itself.", + "parameters": [ + { + "in": "query", + "name": "verifyStatus", + "description": "If set to `true` the verification will also check the status of the presentation. Requires the VP to have a `credentialStatus` property.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "fetchRemoteContexts", + "description": "When dealing with JSON-LD you also MUST provide the proper contexts. * Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "allowDeactivatedDid", + "description": "If set to `true` allow to verify credential which based on deactivated DID.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/PresentationVerifyRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationVerifyRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyPresentationResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/resource/create/{did}": { + "post": { + "tags": [ + "Resource" + ], + "summary": "Create a DID-Linked Resource.", + "description": "This endpoint creates a DID-Linked Resource. As input, it can take the DID identifier and the resource parameters via a form, or the fully-assembled resource itself.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier to link the resource to.", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CreateResourceRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateResourceRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceMetadata" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/resource/search/{did}": { + "get": { + "tags": [ + "Resource" + ], + "summary": "Get a DID-Linked Resource.", + "description": "This endpoint returns the DID-Linked Resource for a given DID identifier and resource identifier.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier", + "schema": { + "type": "string" + }, + "required": true, + "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + { + "in": "query", + "name": "resourceId", + "description": "Fetch a DID-Linked Resource by Resource ID unique identifier. Since this is a unique identifier, other Resource query parameters are not required. See DID-Linked Resources for more details.", + "schema": { + "type": "string", + "format": "uuid" + }, + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + { + "in": "query", + "name": "resourceName", + "description": "Filter a DID-Linked Resource query by Resource Name. See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "cheqd-issuer-logo" + }, + { + "in": "query", + "name": "resourceType", + "description": "Filter a DID-Linked Resource query by Resource Type. See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "CredentialArtwork" + }, + { + "in": "query", + "name": "resourceVersion", + "description": "Filter a DID-Linked Resource query by Resource Version, which is an optional free-text field used by issuers (e.g., \"v1\", \"Final Version\", \"1st January 1970\" etc). See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "v1" + }, + { + "in": "query", + "name": "resourceVersionTime", + "description": "Filter a DID-Linked Resource query which returns the closest version of the Resource *at* or *before* specified time. See DID-Linked Resources for more details.", + "schema": { + "type": "string", + "format": "date-time" + }, + "example": "1970-01-01T00:00:00Z" + }, + { + "in": "query", + "name": "checksum", + "description": "Request integrity check against a given DID-Linked Resource by providing a SHA-256 checksum hash. See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "dc64474d062ed750a66bad58cb609928de55ed0d81defd231a4a4bf97358e9ed" + }, + { + "in": "query", + "name": "resourceMetadata", + "description": "Return only metadata of DID-Linked Resource instead of actual DID-Linked Resource. Mutually exclusive with some of the other parameters.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "any": { + "schema": { + "type": "object" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + } + }, + "components": { + "schemas": { + "AlsoKnownAs": { + "type": "object", + "properties": { + "alsoKnownAs": { + "type": "array", + "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", + "items": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "format": "uri", + "description": "URI where the DID-Linked Resource can be fetched from. Can be any type of URI (e.g., DID, HTTPS, IPFS, etc.)" + }, + "description": { + "type": "string", + "description": "Optional description of the URI." + } + } + } + } + } + }, + "CredentialRequest": { + "description": "Input fields for the creating a Verifiable Credential.", + "type": "object", + "additionalProperties": false, + "properties": { + "issuerDid": { + "description": "DID of the Verifiable Credential issuer. This needs to be a `did:cheqd` DID.", + "type": "string", + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + "subjectDid": { + "description": "DID of the Verifiable Credential holder/subject. This needs to be a `did:key` DID.", + "type": "string", + "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" + }, + "attributes": { + "description": "JSON object containing the attributes to be included in the credential.", + "type": "object", + "example": { + "name": "Bob", + "gender": "male" + } + }, + "@context": { + "description": "Optional properties to be included in the `@context` property of the credential.", + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "https://schema.org/schema.jsonld", + "https://veramo.io/contexts/profile/v1" + ] + }, + "type": { + "description": "Optional properties to be included in the `type` property of the credential.", + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "Person" + ] + }, + "expirationDate": { + "description": "Optional expiration date according to the VC Data Model specification.", + "type": "string", + "format": "date-time", + "example": "2023-06-08T13:49:28.000Z" + }, + "format": { + "description": "Format of the Verifiable Credential. Defaults to VC-JWT.", + "type": "string", + "enum": [ + "jwt", + "jsonld" + ], + "example": "jwt" + }, + "credentialStatus": { + "description": "Optional `credentialStatus` properties for VC revocation or suspension. Takes `statusListName` and `statusListPurpose` as inputs.", + "type": "object", + "required": [ + "statusPurpose", + "statusListName" + ], + "properties": { + "statusPurpose": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ] + }, + "statusListName": { + "type": "string" + }, + "statusListIndex": { + "type": "number" + }, + "statusListVersion": { + "type": "string", + "format": "date-time" + }, + "statusListRangeStart": { + "type": "number" + }, + "statusListRangeEnd": { + "type": "number" + }, + "indexNotIn": { + "type": "number" + } + }, + "example": { + "statusPurpose": "revocation", + "statusListName": "employee-credentials" + } + } + }, + "required": [ + "issuerDid", + "subjectDid", + "attributes" + ], + "example": { + "issuerDid": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "subjectDid": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", + "attributes": { + "gender": "male", + "name": "Bob" + }, + "@context": [ + "https://schema.org" + ], + "type": [ + "Person" + ], + "format": "jwt", + "credentialStatus": { + "statusPurpose": "revocation", + "statusListName": "employee-credentials", + "statusListIndex": 10 + } + } + }, + "Credential": { + "description": "Input fields for revoking/suspending a Verifiable Credential.", + "type": "object", + "additionalProperties": false, + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "https://www.w3.org/2018/credentials/v1", + "https://schema.org", + "https://veramo.io/contexts/profile/v1" + ] + }, + "type": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "VerifiableCredential", + "Person" + ] + }, + "expirationDate": { + "type": "string", + "format": "date-time", + "example": "2023-06-08T13:49:28.000Z" + }, + "issuer": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "DID", + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + } + } + }, + "credentialSubject": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "DID", + "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" + } + } + }, + "credentialStatus": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20" + }, + "statusListIndex": { + "type": "number", + "example": 20 + }, + "statusPurpose": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ], + "example": "suspension" + }, + "type": { + "type": "string", + "enum": [ + "StatusList2021Entry" + ] + } + } + }, + "issuanceDate": { + "type": "string", + "format": "date-time", + "example": "2023-06-08T13:49:28.000Z" + }, + "proof": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "jwt": { + "type": "string" + } + }, + "example": { + "type": "JwtProof2020", + "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg" + } + } + }, + "example": { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://schema.org", + "https://veramo.io/contexts/profile/v1" + ], + "credentialSubject": { + "gender": "male", + "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", + "name": "Bob" + }, + "credentialStatus": { + "id": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20", + "statusIndex": 20, + "statusPurpose": "suspension", + "type": "StatusList2021Entry" + }, + "issuanceDate": "2023-06-08T13:49:28.000Z", + "issuer": { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + "proof": { + "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg", + "type": "JwtProof2020" + }, + "type": [ + "VerifiableCredential", + "Person" + ] + } + }, + "CredentialRevokeRequest": { + "type": "object", + "properties": { + "credential": { + "description": "Verifiable Credential to be revoked as a VC-JWT string or a JSON object.", + "oneOf": [ + { + "type": "object" + }, + { + "type": "string" + } + ] + }, + "symmetricKey": { + "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource. Required if the StatusList2021 DID-Linked Resource is encrypted.", + "type": "string" + } + } + }, + "RevocationResult": { + "properties": { + "revoked": { + "type": "boolean", + "example": true + } + } + }, + "SuspensionResult": { + "properties": { + "suspended": { + "type": "boolean", + "example": true + } + } + }, + "UnsuspensionResult": { + "properties": { + "unsuspended": { + "type": "boolean", + "example": true + } + } + }, + "CredentialVerifyRequest": { + "type": "object", + "properties": { + "credential": { + "description": "Verifiable Credential to be verified as a VC-JWT string or a JSON object.", + "type": "object" + }, + "policies": { + "description": "Custom verification policies to execute when verifying credential.", + "type": "object", + "properties": { + "issuanceDate": { + "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "expirationDate": { + "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "audience": { + "description": "Policy to skip the audience check when set to `false`.", + "type": "boolean", + "default": false + } + } + } + } + }, + "VerifyPresentationResult": { + "type": "object", + "properties": { + "verified": { + "type": "boolean" + }, + "issuer": { + "type": "string" + }, + "signer": { + "type": "object" + }, + "jwt": { + "type": "string" + }, + "verifiableCredential": { + "type": "object" + } + } + }, + "VerifyCredentialResult": { + "type": "object", + "properties": { + "verified": { + "type": "boolean" + }, + "issuer": { + "type": "string" + }, + "signer": { + "type": "object" + }, + "jwt": { + "type": "string" + }, + "verifiableCredential": { + "type": "object" + } + }, + "example": { + "verified": true, + "polices": {}, + "issuer": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "signer": { + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", + "type": "Ed25519VerificationKey2018" + } + } + }, + "PresentationCreateRequest": { + "type": "object", + "required": [ + "credentials" + ], + "properties": { + "credentials": { + "description": "Verifiable Credentials to be used for VP-JWT creation as a VP-JWT strings or a JSON objectsf.", + "type": "array", + "items": { + "type": "object" + } + }, + "holderDid": { + "description": "DID of holder", + "type": "string" + }, + "verifierDid": { + "description": "DID of verifier", + "type": "string" + } + } + }, + "PresentationVerifyRequest": { + "type": "object", + "required": [ + "presentation" + ], + "properties": { + "presentation": { + "description": "Verifiable Presentation to be verified as a VP-JWT string or a JSON object.", + "type": "object" + }, + "verifierDid": { + "description": "Provide an optional verifier DID (also known as 'domain' parameter), if the verifier DID in the presentation is not managed in the wallet.", + "type": "string" + }, + "makeFeePayment": { + "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", + "type": "boolean", + "default": false + }, + "policies": { + "description": "Custom verification policies to execute when verifying presentation.", + "type": "object", + "properties": { + "issuanceDate": { + "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "expirationDate": { + "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "audience": { + "description": "Policy to skip the audience check when set to `false`.", + "type": "boolean", + "default": false + } + } + } + } + }, + "CredentialStatusCreateBody": { + "allOf": [ + { + "type": "object", + "required": [ + "did", + "statusListName" + ], + "properties": { + "did": { + "description": "DID of the StatusList2021 publisher.", + "type": "string", + "format": "uri" + }, + "statusListName": { + "description": "The name of the StatusList2021 DID-Linked Resource to be created.", + "type": "string" + }, + "length": { + "description": "The length of the status list to be created. The default and minimum length is 140000 which is 16kb.", + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true, + "default": 140000 + }, + "encoding": { + "description": "The encoding format of the StatusList2021 DiD-Linked Resource to be created.", + "type": "string", + "default": "base64url", + "enum": [ + "base64url", + "base64", + "hex" + ] + }, + "statusListVersion": { + "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/AlsoKnownAs" + } + ] + }, + "CredentialStatusCreateUnencryptedRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCreateBody" + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials", + "length": 140000, + "encoding": "base64url" + } + }, + "CredentialStatusUnencryptedResult": { + "type": "object", + "properties": { + "resource": { + "type": "object", + "properties": { + "StatusList2021": { + "type": "object", + "properties": { + "encodedList": { + "type": "string", + "example": "H4sIAAAAAAAAA-3BAQ0AAADCoPdPbQ8HFAAAAAAAAAAAAAAAAAAAAADwaDhDr_xcRAAA" + }, + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "validFrom": { + "type": "string", + "format": "date-time", + "example": "2023-06-26T11:45:19.349Z" + } + } + }, + "metadata": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "encoding": { + "type": "string", + "example": "base64url" + }, + "encrypted": { + "type": "boolean", + "example": false + } + } + } + } + }, + "resourceMetadata": { + "type": "object", + "example": { + "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceName": "cheqd-employee-credentials", + "resourceType": "StatusList2021Revocation", + "mediaType": "application/json", + "resourceVersion": "1.0.0", + "created": "2023-06-26T11:45:20Z", + "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", + "previousVersionId": null, + "nextVersionId": null + } + } + } + }, + "CredentialStatusCreateUnencryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "created": { + "type": "boolean", + "example": true + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" + } + ] + }, + "CredentialStatusEncryptedPaymentConditionsBody": { + "type": "object", + "properties": { + "feePaymentAddress": { + "description": "The cheqd/Cosmos payment address where payments to unlock the encrypted StatusList2021 DID-Linked Resource need to be sent.", + "type": "string", + "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" + }, + "feePaymentAmount": { + "description": "Amount in CHEQ tokens to unlock the encrypted StatusList2021 DID-Linked Resource.", + "type": "number", + "minimum": 0, + "exclusiveMinimum": true, + "default": 20 + }, + "feePaymentWindow": { + "description": "Time window (in minutes) within which the payment to unlock the encrypted StatusList2021 DID-Linked Resource is considered valid.", + "type": "number", + "minimum": 0, + "exclusiveMinimum": true, + "default": 10 + } + } + }, + "CredentialStatusEncryptedPaymentConditionsJson": { + "type": "object", + "properties": { + "paymentConditions": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" + } + ] + } + } + }, + "CredentialStatusCreateEncryptedFormRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCreateBody" + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" + }, + { + "type": "object", + "required": [ + "feePaymentAddress", + "feePaymentAmount", + "feePaymentWindow" + ] + } + ] + }, + "CredentialStatusCreateEncryptedJsonRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCreateBody" + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" + }, + { + "type": "object", + "required": [ + "paymentConditions" + ] + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials-encrypted", + "paymentConditions": [ + { + "feePaymentAddress": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg", + "feePaymentAmount": 20, + "feePaymentWindow": 10 + } + ] + } + }, + "CredentialStatusEncryptedResult": { + "type": "object", + "properties": { + "resource": { + "type": "object", + "properties": { + "StatusList2021": { + "type": "object", + "properties": { + "encodedList": { + "type": "string", + "example": "496fdfbeb745b4db03fcdb40566f9c4c4a1c0f184b31255e641b6e7bdfb9b6946c12be87ca3763be0393c00b67ac1e8737c106b32f46ef59c765754415b5e8cc7c65fccaa3374620430ea476301a5e0dd63340e7a27a68bc627518471f22e4a2" + }, + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "validFrom": { + "type": "string", + "format": "date-time", + "example": "2023-06-26T11:45:19.349Z" + } + } + }, + "metadata": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "encoding": { + "type": "string", + "example": "base64url" + }, + "encrypted": { + "type": "boolean", + "example": true + }, + "encryptedSymmetricKey": { + "type": "string", + "example": "b11182dc524b8181f9a6aef4c4ad0a1c14e40033b9112dffd8d1bcf6cc3b85abc07ded2205ee94068a99f4202502cb0855f322583fa6ce1534d3a05bf36891766ea2c5f90a982b3040680762977d404d758a2370224a239c8279aa7d21e980931c42055b17ca4c7dbffa4782480a8b6279cf989b2f166d5fdb4b2c1b5a63927200000000000000203018dcaba26df45a415bb599218b27ca853a70289d7a3ed3ed0e3730452e8f8d9af91b6e71312565d2c069341f6660ab" + }, + "paymentConditions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "feePaymentAddress": { + "type": "string", + "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" + }, + "feePaymentAmount": { + "type": "string", + "example": "20000000000ncheq" + }, + "intervalInSeconds": { + "type": "number", + "example": 600 + }, + "type": { + "type": "string", + "example": "timelockPayment" + } + } + } + } + } + }, + "resourceMetadata": { + "type": "object", + "example": { + "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceName": "cheqd-revocation-encrypted-1", + "resourceType": "StatusList2021Revocation", + "mediaType": "application/json", + "resourceVersion": "2023-06-26T11:45:19.349Z", + "created": "2023-06-26T11:45:20Z", + "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", + "previousVersionId": null, + "nextVersionId": null + } + }, + "symmetricKey": { + "type": "string", + "example": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" + } + } + } + } + }, + "CredentialStatusCreateEncryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "created": { + "type": "boolean", + "example": true + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedResult" + } + ] + }, + "CredentialStatusUpdateBody": { + "type": "object", + "required": [ + "did", + "statusListName", + "indices" + ], + "properties": { + "did": { + "description": "DID of the StatusList2021 publisher.", + "type": "string", + "format": "uri" + }, + "statusListName": { + "description": "The name of the StatusList2021 DID-Linked Resource to be updated.", + "type": "string" + }, + "indices": { + "description": "List of credential status indices to be updated. The indices must be in the range of the status list.", + "type": "array", + "items": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": false + } + }, + "statusListVersion": { + "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + "CredentialStatusUpdateUnencryptedRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUpdateBody" + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials", + "indices": [ + 10, + 3199, + 12109, + 130999 + ] + } + }, + "CredentialStatusUpdateUnencryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "updated": { + "type": "boolean", + "example": true + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/RevocationResult" + }, + { + "$ref": "#/components/schemas/SuspensionResult" + }, + { + "$ref": "#/components/schemas/UnsuspensionResult" + } + ] + }, + { + "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" + } + ] + }, + "CredentialStatusUpdateEncryptedFormRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUpdateBody" + }, + { + "type": "object", + "required": [ + "symmetricKey" + ], + "properties": { + "symmetricKey": { + "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" + } + ] + }, + "CredentialStatusUpdateEncryptedJsonRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUpdateBody" + }, + { + "type": "object", + "required": [ + "symmetricKey" + ], + "properties": { + "symmetricKey": { + "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials-encrypted", + "indices": [ + 10, + 3199, + 12109, + 130999 + ], + "symmetricKey": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" + } + }, + "CredentialStatusUpdateEncryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "updated": { + "type": "boolean", + "example": true + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/RevocationResult" + }, + { + "$ref": "#/components/schemas/SuspensionResult" + }, + { + "$ref": "#/components/schemas/UnsuspensionResult" + } + ] + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedResult" + } + ] + }, + "CredentialStatusCheckRequest": { + "type": "object", + "required": [ + "did", + "statusListName", + "index" + ], + "properties": { + "did": { + "description": "DID of the StatusList2021 publisher.", + "type": "string", + "format": "uri" + }, + "statusListName": { + "description": "The name of the StatusList2021 DID-Linked Resource to be checked.", + "type": "string" + }, + "index": { + "description": "Credential status index to be checked for revocation or suspension.", + "type": "integer", + "minimum": 0, + "exclusiveMinimum": false + }, + "makeFeePayment": { + "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", + "type": "boolean", + "default": true + } + } + }, + "CredentialStatusCheckResult": { + "oneOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCheckRevocationResult" + }, + { + "$ref": "#/components/schemas/CredentialStatusCheckSuspensionResult" + } + ] + }, + "CredentialStatusCheckRevocationResult": { + "type": "object", + "properties": { + "checked": { + "type": "boolean", + "example": true + }, + "revoked": { + "type": "boolean", + "example": false + } + } + }, + "CredentialStatusCheckSuspensionResult": { + "type": "object", + "properties": { + "checked": { + "type": "boolean", + "example": true + }, + "suspended": { + "type": "boolean", + "example": false + } + } + }, + "CredentialStatusListSearchResult": { + "allOf": [ + { + "type": "object", + "properties": { + "found": { + "type": "boolean", + "example": true + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedResult" + } + ] + } + ] + }, + "KeyImportRequest": { + "type": "object", + "properties": { + "alias": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "Ed25519", + "Secp256k1" + ] + }, + "privateKeyHex": { + "type": "string" + } + } + }, + "KeyResult": { + "type": "object", + "properties": { + "kid": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "Ed25519", + "Secp256k1" + ] + }, + "publicKeyHex": { + "type": "string" + } + } + }, + "DidDocument": { + "description": "This input field contains either a complete DID document, or an incremental change (diff) to a DID document. See Universal DID Registrar specification.", + "type": "object", + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "controllers": { + "type": "array", + "items": { + "type": "string" + } + }, + "verificationMethod": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VerificationMethod" + } + }, + "service": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "authentication": { + "type": "array", + "items": { + "type": "string" + } + }, + "assertionMethod": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityInvocation": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityDelegation": { + "type": "array", + "items": { + "type": "string" + } + }, + "keyAgreement": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "@context": [ + "https://www.w3.org/ns/did/v1" + ], + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "controller": [ + "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + ], + "verificationMethod": [ + { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "type": "Ed25519VerificationKey2018", + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "publicKeyBase58": "z6MkkVbyHJLLjdjU5B62DaJ4mkdMdUkttf9UqySSkA9bVTeZ" + } + ], + "authentication": [ + "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1" + ], + "service": [ + { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", + "type": "LinkedDomains", + "serviceEndpoint": [ + "https://example.com" + ] + } + ] + } + }, + "DidDocumentWithoutVerificationMethod": { + "type": "object", + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "controllers": { + "type": "array", + "items": { + "type": "string" + } + }, + "service": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "authentication": { + "type": "array", + "items": { + "type": "string" + } + }, + "assertionMethod": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityInvocation": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityDelegation": { + "type": "array", + "items": { + "type": "string" + } + }, + "keyAgreement": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "@context": [ + "https://www.w3.org/ns/did/v1" + ], + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "controller": [ + "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + ], + "authentication": [ + "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1" + ], + "service": [ + { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", + "type": "LinkedDomains", + "serviceEndpoint": [ + "https://example.com" + ] + } + ] + } + }, + "DidCreateRequestFormBased": { + "type": "object", + "properties": { + "network": { + "description": "Network to create the DID on (testnet or mainnet)", + "type": "string", + "enum": [ + "testnet", + "mainnet" + ] + }, + "identifierFormatType": { + "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", + "type": "string", + "enum": [ + "uuid", + "base58btc" + ] + }, + "verificationMethodType": { + "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", + "type": "string", + "enum": [ + "Ed25519VerificationKey2018", + "JsonWebKey2020", + "Ed25519VerificationKey2020" + ] + }, + "service": { + "description": "It's a list of special objects which are designed to build the actual service. It's almost the same as in DID Core specification, but instead of `id` it utilises `idFragment` field for making the right `id` for each service. !!! WARN. Cause swagger-ui does not handle x-ww-form based arrays correctly, please frame all your services in brackets while using swagger UI. !!!", + "type": "array", + "items": { + "type": "object", + "properties": { + "idFragment": { + "type": "string" + }, + "type": { + "type": "string" + }, + "serviceEndpoint": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "example": [ + { + "idFragment": "service-1", + "type": "LinkedDomains", + "serviceEndpoint": [ + "https://example.com" + ] + } + ] + }, + "key": { + "description": "The unique identifier in hexadecimal public key format used in the verification method to create the DID.", + "type": "string" + }, + "@context": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "https://www.w3.org/ns/did/v1" + ] + } + } + }, + "DidCreateRequestJson": { + "type": "object", + "properties": { + "network": { + "description": "Network to create the DID on (testnet or mainnet)", + "type": "string", + "enum": [ + "testnet", + "mainnet" + ] + }, + "identifierFormatType": { + "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", + "type": "string", + "enum": [ + "uuid", + "base58btc" + ] + }, + "assertionMethod": { + "description": "Usually a reference to a Verification Method. An Assertion Method is required to issue JSON-LD credentials. See DID Core specification for more details.", + "type": "boolean", + "default": true + }, + "options": { + "type": "object", + "properties": { + "key": { + "type": "string", + "example": "8255ddadd75695e01f3d98fcec8ccc7861a030b317d4326b0e48a4d579ddc43a" + }, + "verificationMethodType": { + "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", + "type": "string", + "enum": [ + "Ed25519VerificationKey2018", + "JsonWebKey2020", + "Ed25519VerificationKey2020" + ] + } + } + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocumentWithoutVerificationMethod" + } + } + }, + "DidImportRequest": { + "type": "object", + "properties": { + "did": { + "type": "string", + "description": "DID to be imported", + "format": "uri", + "required": true + }, + "keys": { + "type": "array", + "description": "List of keys required to import the DID", + "required": true, + "items": { + "$ref": "#/components/schemas/KeyImportRequest" + } + } + } + }, + "PresentationCreateResult": { + "type": "object", + "properties": { + "vp": { + "type": "object", + "description": "Verifiable Presentation which could be provided to the verifier." + }, + "nbf": { + "type": "integer", + "description": "Unix timestamp of the earliest time that the Verifiable Presentation is valid." + }, + "iss": { + "type": "string", + "description": "DID of the issuer of the Verifiable Presentation. (Here it's supposed to be a holder DID)" + }, + "aud": { + "type": "array", + "items": { + "type": "string" + }, + "description": "DID of the verifier of the Verifiable Presentation." + } + }, + "example": { + "vp": { + "@context": [ + "https://www.w3.org/2018/credentials/v1" + ], + "type": [ + "VerifiablePresentation" + ], + "verifiableCredential": [ + "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc2NoZW1hLm9yZy9zY2hlbWEuanNvbmxkIiwiaHR0cHM6Ly92ZXJhbW8uaW8vY29udGV4dHMvcHJvZmlsZS92MSIsImh0dHBzOi8vdzNpZC5vcmcvdmMtc3RhdHVzLWxpc3QtMjAyMS92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiUGVyc29uIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7Im5hbWUiOiJCb2IiLCJnZW5kZXIiOiJtYWxlIn0sImNyZWRlbnRpYWxTdGF0dXMiOnsiaWQiOiJodHRwczovL3Jlc29sdmVyLmNoZXFkLm5ldC8xLjAvaWRlbnRpZmllcnMvZGlkOmNoZXFkOnRlc3RuZXQ6OTBkNWMxNDEtNzI0Zi00N2FkLTlhZTctYTdjMzNhOWU1NjQzP3Jlc291cmNlTmFtZT1zdXNwZW5zaW9uRW4mcmVzb3VyY2VUeXBlPVN0YXR1c0xpc3QyMDIxU3VzcGVuc2lvbiMxMzMzOCIsInR5cGUiOiJTdGF0dXNMaXN0MjAyMUVudHJ5Iiwic3RhdHVzUHVycG9zZSI6InN1c3BlbnNpb24iLCJzdGF0dXNMaXN0SW5kZXgiOiIxMzMzOCJ9fSwic3ViIjoiZGlkOmtleTp6Nk1raGFYZ0JaRHZvdERrTDUyNTdmYWl6dGlHaUMyUXRLTEdwYm5uRUd0YTJkb0siLCJuYmYiOjE3MDA0NzM0MTYsImlzcyI6ImRpZDpjaGVxZDp0ZXN0bmV0OjkwZDVjMTQxLTcyNGYtNDdhZC05YWU3LWE3YzMzYTllNTY0MyJ9.-14Ril1pZEy2HEEo48gTJr2yOtGxBhUGTFmzVdjAtyhFRsW5zZg9onHt6V9JQ8BaiYBlTkP9GzTnJ-O6hdiyCw" + ] + }, + "nbf": 1700744275, + "iss": "did:cheqd:testnet:4b846d0f-2f6c-4ab6-9fe2-5b8db301c83c", + "aud": [ + "did:cheqd:testnet:8c71e9b6-c5a3-4250-8c58-fa591533cd22" + ] + } + }, + "DidResult": { + "type": "object", + "properties": { + "did": { + "type": "string" + }, + "controllerKeyId": { + "type": "string" + }, + "keys": { + "type": "array", + "items": { + "type": "object" + } + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + } + } + }, + "DidUpdateResponse": { + "type": "object", + "properties": { + "did": { + "type": "string" + }, + "controllerKeyId": { + "type": "string", + "description": "The default key id of which is the key associated with the first verificationMethod" + }, + "keys": { + "type": "array", + "description": "The list of keys associated with the list of verificationMethod's of DIDDocument", + "items": { + "type": "object" + } + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "controllerKeyRefs": { + "type": "array", + "description": "The list of keyRefs which were used for signing the transaction", + "items": { + "type": "string" + } + }, + "controllerKeys": { + "type": "array", + "description": "The list of all possible keys, inlcuding all controller's keys", + "items": { + "type": "string" + } + } + } + }, + "VerificationMethod": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + }, + "controller": { + "type": "string" + }, + "publicKeyMultibase": { + "type": "string" + }, + "publicKeyJwk": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "id": "did:cheqd:testnet :7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", + "type": "Ed25519VerificationKey2018" + } + }, + "Service": { + "description": "Communicating or interacting with the DID subject or associated entities via one or more service endpoints. See DID Core specification for more details.", + "type": "object", + "properties": { + "id": { + "description": "DID appended with Service fragment ID (e.g., `#service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`)", + "type": "string", + "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1" + }, + "type": { + "description": "Service type as defined in DID Specification Registries.", + "type": "string", + "example": "LinkedDomains" + }, + "serviceEndpoint": { + "description": "Service endpoint as defined in DID Core Specification.", + "type": "array", + "items": { + "type": "string", + "example": "https://example.com" + } + } + } + }, + "DidUpdateRequest": { + "type": "object", + "properties": { + "did": { + "description": "DID identifier to be updated.", + "type": "string", + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + "service": { + "type": "array", + "description": "Service section of the DID Document.", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "verificationMethod": { + "type": "array", + "description": "Verification Method section of the DID Document.", + "items": { + "$ref": "#/components/schemas/VerificationMethod" + } + }, + "authentication": { + "description": "Authentication section of the DID Document.", + "type": "array", + "items": { + "type": "string" + } + }, + "publicKeyHexs": { + "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", + "type": "array", + "items": { + "type": "string" + } + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + } + } + }, + "DidDeactivateRequest": { + "type": "object", + "properties": { + "publicKeyHexs": { + "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "CreateResourceRequest": { + "description": "Input fields for DID-Linked Resource creation.", + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "type", + "data", + "encoding" + ], + "properties": { + "data": { + "description": "Encoded string containing the data to be stored in the DID-Linked Resource.", + "type": "string" + }, + "encoding": { + "description": "Encoding format used to encode the data.", + "type": "string", + "enum": [ + "base64url", + "base64", + "hex" + ] + }, + "name": { + "description": "Name of DID-Linked Resource.", + "type": "string" + }, + "type": { + "description": "Type of DID-Linked Resource. This is NOT the same as the media type, which is calculated automatically ledger-side.", + "type": "string" + }, + "alsoKnownAs": { + "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", + "type": "array", + "items": { + "type": "object", + "properties": { + "uri": { + "type": "string" + }, + "description": { + "type": "string" + } + } + } + }, + "version": { + "description": "Optional field to assign a human-readable version in the DID-Linked Resource.", + "type": "string" + }, + "publicKeyHexs": { + "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "data": "SGVsbG8gV29ybGQ=", + "encoding": "base64url", + "name": "ResourceName", + "type": "TextDocument" + } + }, + "ResourceList": { + "type": "object", + "properties": { + "@context": { + "type": "string", + "example": "https://w3id.org/did-resolution/v1" + }, + "contentMetadata": { + "type": "object" + }, + "contentStream": { + "type": "object" + }, + "dereferencingMetadata": { + "$ref": "#/components/schemas/DereferencingMetadata" + } + } + }, + "DereferencingMetadata": { + "type": "object", + "properties": { + "contentType": { + "type": "string", + "example": "application/did+ld+json" + }, + "did": { + "$ref": "#/components/schemas/DidProperties" + }, + "retrieved": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + } + } + }, + "DidResolution": { + "type": "object", + "properties": { + "@context": { + "type": "string", + "example": "https://w3id.org/did-resolution/v1" + }, + "didDidResolutionMetadata": { + "$ref": "#/components/schemas/DidResolutionMetadata" + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + }, + "didDocumentMetadata": { + "$ref": "#/components/schemas/DidDocumentMetadata" + } + } + }, + "DeactivatedDidResolution": { + "type": "object", + "properties": { + "@context": { + "type": "string", + "example": "https://w3id.org/did-resolution/v1" + }, + "didDidResolutionMetadata": { + "$ref": "#/components/schemas/DidResolutionMetadata" + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + }, + "didDocumentMetadata": { + "$ref": "#/components/schemas/DeactivatedDidDocumentMetadata" + } + } + }, + "DidDocumentMetadata": { + "type": "object", + "properties": { + "created": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "deactivated": { + "type": "boolean", + "example": false + }, + "updated": { + "type": "string", + "example": "2021-09-10T12:00:00Z" + }, + "versionId": { + "type": "string", + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + "linkedResourceMetadata": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ResourceMetadata" + } + } + } + }, + "DeactivatedDidDocumentMetadata": { + "type": "object", + "properties": { + "created": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "deactivated": { + "type": "boolean", + "example": true + }, + "updated": { + "type": "string", + "example": "2021-09-10T12:00:00Z" + }, + "versionId": { + "type": "string", + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + "linkedResourceMetadata": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ResourceMetadata" + } + } + } + }, + "ResourceMetadata": { + "type": "object", + "properties": { + "resourceURI": { + "type": "string", + "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47/resources/398cee0a-efac-4643-9f4c-74c48c72a14b" + }, + "resourceCollectionId": { + "type": "string", + "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" + }, + "resourceId": { + "type": "string", + "example": "398cee0a-efac-4643-9f4c-74c48c72a14b" + }, + "resourceName": { + "type": "string", + "example": "cheqd-issuer-logo" + }, + "resourceType": { + "type": "string", + "example": "CredentialArtwork" + }, + "mediaType": { + "type": "string", + "example": "image/png" + }, + "resourceVersion": { + "type": "string", + "example": "1.0" + }, + "checksum": { + "type": "string", + "example": "a95380f460e63ad939541a57aecbfd795fcd37c6d78ee86c885340e33a91b559" + }, + "created": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "nextVersionId": { + "type": "string", + "example": "d4829ac7-4566-478c-a408-b44767eddadc" + }, + "previousVersionId": { + "type": "string", + "example": "ad7a8442-3531-46eb-a024-53953ec6e4ff" + } + } + }, + "DidResolutionMetadata": { + "type": "object", + "properties": { + "contentType": { + "allOf": [ + { + "$ref": "#/components/schemas/ContentType" + } + ], + "example": "application/did+ld+json" + }, + "retrieved": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "did": { + "$ref": "#/components/schemas/DidProperties" + } + } + }, + "ContentType": { + "type": "string", + "enum": [ + "application/did+json", + "application/did+ld+json", + "application/ld+json", + "application/json" + ] + }, + "DidProperties": { + "type": "object", + "properties": { + "didString": { + "type": "string", + "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" + }, + "method": { + "type": "string", + "example": "cheqd" + }, + "methodSpecificId": { + "type": "string", + "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" + } + } + }, + "Customer": { + "type": "object", + "properties": { + "customerId": { + "type": "string", + "example": "6w5drpiiwhhs" + }, + "address": { + "type": "string", + "example": "cheqd1wgsvqwlkmdp60f4dek26ak0sjw6au3ytd3pz7f" + } + } + }, + "AccountCreateRequest": { + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": { + "primaryEmail": { + "type": "string" + } + } + } + } + }, + "InvalidRequest": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "InvalidRequest" + } + } + }, + "InternalError": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Internal Error" + } + } + }, + "UnauthorizedError": { + "description": "Access token is missing or invalid", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Unauthorized Error" + } + } + } + } + } +} \ No newline at end of file From a4c28dc96106c329dc20608d2aa68d0a662f35b1 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Mon, 18 Mar 2024 18:10:47 +0100 Subject: [PATCH 07/40] Get rid of /admin/checkout and move it to /admin/subscriptions --- src/app.ts | 11 +- src/controllers/admin/checkout-session.ts | 117 ---------------- src/controllers/admin/subscriptions.ts | 127 +++++++++--------- .../auth/routes/admin/admin-auth.ts | 11 +- src/types/portal.ts | 34 ++--- src/types/swagger-admin-types.ts | 56 +++----- 6 files changed, 103 insertions(+), 253 deletions(-) delete mode 100644 src/controllers/admin/checkout-session.ts diff --git a/src/app.ts b/src/app.ts index c94dc710..7e9d41bf 100644 --- a/src/app.ts +++ b/src/app.ts @@ -31,7 +31,6 @@ import { ProductController } from './controllers/admin/product.js'; import { SubscriptionController } from './controllers/admin/subscriptions.js'; import { PriceController } from './controllers/admin/prices.js'; import { WebhookController } from './controllers/admin/webhook.js'; -import { CheckoutSessionController } from './controllers/admin/checkout-session.js'; let swaggerOptions = {}; if (process.env.ENABLE_AUTHENTICATION === 'true') { @@ -245,8 +244,7 @@ class App { new SubscriptionController().update ); app.get( - '/admin/subscription/get/:subscriptionId', - SubscriptionController.subscriptionGetValidator, + '/admin/subscription/get', new SubscriptionController().get ); app.get( @@ -265,13 +263,6 @@ class App { new SubscriptionController().resume ); - // Checkout session - app.post( - '/admin/checkout/session/create', - CheckoutSessionController.checkoutSessionCreateValidator, - new CheckoutSessionController().create - ); - // Webhook app.post('/admin/webhook', new WebhookController().handleWebhook); diff --git a/src/controllers/admin/checkout-session.ts b/src/controllers/admin/checkout-session.ts deleted file mode 100644 index 151e7bfb..00000000 --- a/src/controllers/admin/checkout-session.ts +++ /dev/null @@ -1,117 +0,0 @@ -import Stripe from 'stripe'; -import type { Request, Response } from 'express'; -import * as dotenv from 'dotenv'; -import type { - CheckoutSessionCreateRequestBody, - CheckoutSessionCreateUnsuccessfulResponseBody, -} from '../../types/portal.js'; -import { check, validationResult } from '../validator/index.js'; -import { StatusCodes } from 'http-status-codes'; - -dotenv.config(); - -const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); - -export class CheckoutSessionController { - static checkoutSessionCreateValidator = [ - check('price') - .exists() - .withMessage('price is required') - .bail() - .isString() - .withMessage('price should be a string') - .bail(), - check('successURL') - .exists() - .withMessage('successURL is required') - .bail() - .isString() - .withMessage('successURL should be a string') - .bail(), - check('cancelURL') - .exists() - .withMessage('cancelURL is required') - .bail() - .isString() - .withMessage('cancelURL should be a string') - .bail(), - check('idempotencyKey').optional().isString().withMessage('idempotencyKey should be a string').bail(), - ]; - - /** - * @openapi - * - * /admin/checkout/session/create: - * post: - * summary: Create a checkout session - * description: Create a checkout session - * tags: [Checkout] - * requestBody: - * required: true - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/CheckoutSessionCreateRequestBody' - * responses: - * 303: - * description: A redirect to Stripe prebuilt checkout page - * 400: - * $ref: '#/components/schemas/InvalidRequest' - * 401: - * $ref: '#/components/schemas/UnauthorizedError' - * 500: - * $ref: '#/components/schemas/InternalError' - */ - - public async create(request: Request, response: Response) { - const result = validationResult(request); - // handle error - if (!result.isEmpty()) { - return response.status(StatusCodes.BAD_REQUEST).json({ - error: result.array().pop()?.msg, - } satisfies CheckoutSessionCreateUnsuccessfulResponseBody); - } - - const { price, successURL, cancelURL, quantity, idempotencyKey } = - request.body satisfies CheckoutSessionCreateRequestBody; - try { - const session = await stripe.checkout.sessions.create( - { - mode: 'subscription', - customer: response.locals.customer.stripeCustomerId, - line_items: [ - { - price: price, - quantity: quantity || 1, - }, - ], - success_url: successURL, - cancel_url: cancelURL, - }, - { - idempotencyKey, - } - ); - - if (session.lastResponse?.statusCode !== StatusCodes.OK) { - return response.status(StatusCodes.BAD_GATEWAY).json({ - error: 'Checkout session was not created', - } satisfies CheckoutSessionCreateUnsuccessfulResponseBody); - } - - if (!session.url) { - return response.status(StatusCodes.BAD_GATEWAY).json({ - error: 'Checkout session URL was not provided', - } satisfies CheckoutSessionCreateUnsuccessfulResponseBody); - } - - return response.json({ - url: session.url as string, - }); - } catch (error) { - return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ - error: `Internal error: ${(error as Error)?.message || error}`, - } satisfies CheckoutSessionCreateUnsuccessfulResponseBody); - } - } -} diff --git a/src/controllers/admin/subscriptions.ts b/src/controllers/admin/subscriptions.ts index fa8e11b7..9b8293dd 100644 --- a/src/controllers/admin/subscriptions.ts +++ b/src/controllers/admin/subscriptions.ts @@ -17,8 +17,7 @@ import type { SubscriptionResumeUnsuccessfulResponseBody, SubscriptionResumeResponseBody, SubscriptionResumeRequestBody, - SubscriptionCancelRequestBody, - PaymentBehavior, + SubscriptionCancelRequestBody } from '../../types/portal.js'; import { StatusCodes } from 'http-status-codes'; import { validationResult } from '../validator/index.js'; @@ -31,38 +30,14 @@ const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); export class SubscriptionController { static subscriptionCreateValidator = [ - check('customerId').exists().withMessage('customerId was not provided').bail(), - check('items') - .exists() - .withMessage('items was not provided') - .bail() - .isArray() - .withMessage('items should be an array') - .bail(), - check('items.*.price') - .exists() - .withMessage('price was not provided') - .bail() - .isString() - .withMessage('price should be a string') - .bail(), - check('idempotencyKey').optional().isString().withMessage('idempotencyKey should be a string').bail(), + check('price').exists().withMessage('price was not provided').bail().isString().withMessage('price should be a string').bail(), + check('successURL').exists().withMessage('successURL was not provided').bail().isString().withMessage('successURL should be a string').bail(), + check('cancelURL').exists().withMessage('cancelURL was not provided').bail().isString().withMessage('cancelURL should be a string').bail(), + check('quantity').optional().isInt().withMessage('quantity should be an integer').bail(), ]; static subscriptionUpdateValidator = [ - check('subscriptionId').exists().withMessage('subscriptionId was not provided').bail(), - check('updateParams').exists().withMessage('updateParams was not provided').bail(), - check('idempotencyKey').optional().isString().withMessage('idempotencyKey should be a string').bail(), - ]; - - static subscriptionGetValidator = [ - check('subscriptionId') - .exists() - .withMessage('subscriptionId was not provided') - .bail() - .isString() - .withMessage('subscriptionId should be a string') - .bail(), + check('returnUrl').exists().withMessage('returnUrl was not provided').bail().isString().withMessage('returnUrl should be a string').bail(), ]; static subscriptionListValidator = [ @@ -121,33 +96,48 @@ export class SubscriptionController { async create(request: Request, response: Response) { // Validate request const result = validationResult(request); + // handle error if (!result.isEmpty()) { return response.status(StatusCodes.BAD_REQUEST).json({ error: result.array().pop()?.msg, } satisfies SubscriptionCreateUnsuccessfulResponseBody); } - const { items, idempotencyKey } = request.body satisfies SubscriptionCreateRequestBody; + const { price, successURL, cancelURL, quantity, idempotencyKey } = + request.body satisfies SubscriptionCreateRequestBody; try { - // Create the subscription - const subscription = await stripe.subscriptions.create( + const session = await stripe.checkout.sessions.create( { + mode: 'subscription', customer: response.locals.customer.stripeCustomerId, - items: items, - payment_behavior: 'default_incomplete' as PaymentBehavior, + line_items: [ + { + price: price, + quantity: quantity || 1, + }, + ], + success_url: successURL, + cancel_url: cancelURL, }, { - idempotencyKey: idempotencyKey, + idempotencyKey, } ); - if (subscription.lastResponse?.statusCode !== StatusCodes.OK) { + + if (session.lastResponse?.statusCode !== StatusCodes.OK) { return response.status(StatusCodes.BAD_GATEWAY).json({ - error: `Subscription was not created`, + error: 'Checkout session was not created', } satisfies SubscriptionCreateUnsuccessfulResponseBody); } - return response.status(StatusCodes.CREATED).json({ - subscription: subscription, + if (!session.url) { + return response.status(StatusCodes.BAD_GATEWAY).json({ + error: 'Checkout session URL was not provided', + } satisfies SubscriptionCreateUnsuccessfulResponseBody); + } + + return response.json({ + clientSecret: session.url as string, } satisfies SubscriptionCreateResponseBody); } catch (error) { return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ @@ -165,10 +155,10 @@ export class SubscriptionController { * description: Updates an existing subscription * tags: [Subscription] * requestBody: - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/SubscriptionUpdateRequestBody' + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/SubscriptionUpdateRequestBody' * responses: * 200: * description: The request was successful. @@ -192,20 +182,35 @@ export class SubscriptionController { } satisfies SubscriptionUpdateUnsuccessfulResponseBody); } - const { subscriptionId, updateParams, idempotencyKey } = request.body satisfies SubscriptionUpdateRequestBody; + const { returnUrl } = request.body satisfies SubscriptionUpdateRequestBody; + try { - // Update the subscription - const subscription = await stripe.subscriptions.update(subscriptionId, updateParams, { - idempotencyKey: idempotencyKey, + // Sync with Stripe + await SubscriptionService.instance.stripeSync(response.locals.customer); + + // Get the subscription object from the DB + const subscription = await SubscriptionService.instance.findOne({customer: response.locals.customer}); + if (!subscription) { + return response.status(StatusCodes.NOT_FOUND).json({ + error: `Subscription was not found`, + } satisfies SubscriptionUpdateUnsuccessfulResponseBody); + } + + // Create portal link + const session = await stripe.billingPortal.sessions.create({ + customer: response.locals.customer.stripeCustomerId, + return_url: returnUrl, }); - if (subscription.lastResponse?.statusCode !== StatusCodes.OK) { + + if (session.lastResponse?.statusCode !== StatusCodes.OK) { return response.status(StatusCodes.BAD_GATEWAY).json({ - error: `Subscription was not updated`, + error: 'Billing portal session for upgrading the subscription was not created', } satisfies SubscriptionUpdateUnsuccessfulResponseBody); } return response.status(StatusCodes.OK).json({ - subscription: subscription, + clientSecret: session.url, } satisfies SubscriptionUpdateResponseBody); + } catch (error) { return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ error: `Internal error: ${(error as Error)?.message || error}`, @@ -280,13 +285,6 @@ export class SubscriptionController { * summary: Get a subscription * description: Get a subscription * tags: [Subscription] - * parameters: - * - in: path - * name: subscriptionId - * schema: - * type: string - * description: The subscription id - * required: true * responses: * 200: * description: The request was successful. @@ -311,12 +309,17 @@ export class SubscriptionController { error: result.array().pop()?.msg, } satisfies SubscriptionGetUnsuccessfulResponseBody); } - const subscriptionId = request.params.subscriptionId; try { // Sync our DB with Stripe await SubscriptionService.instance.stripeSync(response.locals.customer); - // Get the subscription - const subscription = await stripe.subscriptions.retrieve(subscriptionId as string); + // Get the subscriptionId from the request + const _sub = await SubscriptionService.instance.findOne({customer: response.locals.customer}); + if (!_sub) { + return response.status(StatusCodes.NOT_FOUND).json({ + error: `Subscription was not found`, + } satisfies SubscriptionGetUnsuccessfulResponseBody); + } + const subscription = await stripe.subscriptions.retrieve(_sub.subscriptionId as string); if (subscription.lastResponse?.statusCode !== StatusCodes.OK) { return response.status(StatusCodes.NOT_FOUND).json({ error: `Subscription was not found`, diff --git a/src/middleware/auth/routes/admin/admin-auth.ts b/src/middleware/auth/routes/admin/admin-auth.ts index 6d7afcc9..1b719c6d 100644 --- a/src/middleware/auth/routes/admin/admin-auth.ts +++ b/src/middleware/auth/routes/admin/admin-auth.ts @@ -5,18 +5,17 @@ import type { IAuthResponse } from '../../../../types/authentication.js'; export class AdminHandler extends BaseAuthHandler { constructor() { super(); - // ToDo: define how to get namespace information - this.registerRoute('/admin/checkout/session/create', 'POST', 'admin:checkout:session:create:testnet', { + // Subscriptions + this.registerRoute('/admin/subscription/list', 'GET', 'admin:subscription:list:testnet', { skipNamespace: true, }); - this.registerRoute('/admin/checkout/session/create', 'POST', 'admin:checkout:session:create:mainnet', { + this.registerRoute('/admin/subscription/list', 'GET', 'admin:subscription:list:mainnet', { skipNamespace: true, }); - // Subscriptions - this.registerRoute('/admin/subscription/list', 'GET', 'admin:subscription:list:testnet', { + this.registerRoute('/admin/subscription/update', 'POST', 'admin:subscription:update:testnet', { skipNamespace: true, }); - this.registerRoute('/admin/subscription/list', 'GET', 'admin:subscription:list:mainnet', { + this.registerRoute('/admin/subscription/update', 'POST', 'admin:subscription:update:mainnet', { skipNamespace: true, }); this.registerRoute('/admin/subscription/get', 'GET', 'admin:subscription:get:testnet', { skipNamespace: true }); diff --git a/src/types/portal.ts b/src/types/portal.ts index 866e73dd..01fd8ea1 100644 --- a/src/types/portal.ts +++ b/src/types/portal.ts @@ -26,25 +26,26 @@ export type PriceListUnsuccessfulResponseBody = UnsuccessfulResponseBody; // Subscription // Create export type SubscriptionCreateRequestBody = { - items: [{ price: string }]; + price: string; + successURL: string; + cancelURL: string; + quantity?: number; idempotencyKey?: string; }; export type SubscriptionCreateResponseBody = { - subscription: Stripe.Response; -}; - -// Update -export type SubscriptionUpdateRequestBody = { - subscriptionId: string; - updateParams: Stripe.SubscriptionUpdateParams; - idempotencyKey?: string; + clientSecret: Stripe.Checkout.Session['client_secret']; }; export type SubscriptionUpdateResponseBody = { - subscription: Stripe.Response; + clientSecret: string; }; +// Update +export type SubscriptionUpdateRequestBody = { + returnUrl: string +} + // Get export type SubscriptionGetRequestBody = { subscriptionId: string; @@ -92,19 +93,6 @@ export type SubscriptionResumeUnsuccessfulResponseBody = UnsuccessfulResponseBod export type PortalCustomerGetUnsuccessfulResponseBody = UnsuccessfulResponseBody; -// Checkout Session -export type CheckoutSessionCreateRequestBody = { - price: string; - successURL: string; - cancelURL: string; - quantity?: number; - idempotencyKey?: string; -}; -export type CheckoutSessionCreateResponseBody = { - clientSecret: Stripe.Checkout.Session['client_secret']; -}; - -export type CheckoutSessionCreateUnsuccessfulResponseBody = UnsuccessfulResponseBody; // Utils export type PaymentBehavior = Stripe.SubscriptionCreateParams.PaymentBehavior; diff --git a/src/types/swagger-admin-types.ts b/src/types/swagger-admin-types.ts index 987064c2..08dad75a 100644 --- a/src/types/swagger-admin-types.ts +++ b/src/types/swagger-admin-types.ts @@ -48,31 +48,33 @@ * description: The request body for creating a subscription * type: object * properties: - * customerId: + * price: * type: string - * description: The Stripe customer id - * example: cus_1234567890 - * items: - * type: array - * items: - * type: object - * properties: - * price: - * type: string - * description: The price id - * example: price_1234567890 + * description: The price id + * example: price_1234567890 + * successURL: + * type: string + * description: The URL to redirect to after the customer sucessfully completes the checkout + * example: https://example.com/success + * cancelURL: + * type: string + * description: The URL to redirect to after the customer cancels the checkout + * example: https://example.com/cancel * idempotencyKey: * type: string * description: The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request. * example: abcdefghijklmnopqrstuvwxyz - * * SubscriptionCreateResponseBody: * description: The response body for creating a subscription * type: object * properties: * subscription: * type: object - * description: A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object) + * description: An object with link to checkout session. For more information see the [Stripe API documentation](https://docs.stripe.com/api/checkout/sessions/object) + * properties: + * url: + * type: string + * description: URL which user should follow to manage subscription * SubscriptionUpdateRequestBody: * description: The request body for updating a subscription * type: object @@ -94,7 +96,11 @@ * properties: * subscription: * type: object - * description: A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object) + * description: Object with redirect url inside + * properties: + * clientSecret: + * type: string + * description: URL with session URL rediect to * SubscriptionGetRequestBody: * description: The request body for getting a subscription * type: object @@ -165,26 +171,6 @@ * subscription: * type: object * description: A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object] - * CheckoutSessionCreateRequestBody: - * description: The request body for creating a checkout session - * type: object - * properties: - * price: - * type: string - * description: The price id - * example: price_1234567890 - * successURL: - * type: string - * description: The URL to redirect to after the customer sucessfully completes the checkout - * example: https://example.com/success - * cancelURL: - * type: string - * description: The URL to redirect to after the customer cancels the checkout - * example: https://example.com/cancel - * idempotencyKey: - * type: string - * description: The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request. - * example: abcdefghijklmnopqrstuvwxyz * NotFoundError: * description: The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible. * type: object From 39d8a4222de0539002eeb7a1f86d2eea47ec8dbe Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Tue, 19 Mar 2024 14:53:59 +0100 Subject: [PATCH 08/40] Change endpoint in swagger --- src/controllers/admin/subscriptions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/admin/subscriptions.ts b/src/controllers/admin/subscriptions.ts index 9b8293dd..d5aa6fd5 100644 --- a/src/controllers/admin/subscriptions.ts +++ b/src/controllers/admin/subscriptions.ts @@ -280,7 +280,7 @@ export class SubscriptionController { /** * @openapi * - * /admin/subscription/get/{subscriptionId}: + * /admin/subscription/get: * get: * summary: Get a subscription * description: Get a subscription From 46baaa6688f9bb68320e4454659ea75a9e31fde0 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Wed, 20 Mar 2024 15:55:54 +0100 Subject: [PATCH 09/40] Fix swagger generation and add API routes --- src/controllers/admin/subscriptions.ts | 6 +- .../auth/routes/admin/admin-auth.ts | 6 + src/static/swagger-admin.json | 141 ++++-------------- src/types/swagger-admin-types.ts | 16 +- 4 files changed, 43 insertions(+), 126 deletions(-) diff --git a/src/controllers/admin/subscriptions.ts b/src/controllers/admin/subscriptions.ts index d5aa6fd5..3ff2cc35 100644 --- a/src/controllers/admin/subscriptions.ts +++ b/src/controllers/admin/subscriptions.ts @@ -156,9 +156,9 @@ export class SubscriptionController { * tags: [Subscription] * requestBody: * content: - * application/json: - * schema: - * $ref: '#/components/schemas/SubscriptionUpdateRequestBody' + * application/json: + * schema: + * $ref: '#/components/schemas/SubscriptionUpdateRequestBody' * responses: * 200: * description: The request was successful. diff --git a/src/middleware/auth/routes/admin/admin-auth.ts b/src/middleware/auth/routes/admin/admin-auth.ts index 1b719c6d..84cc5a99 100644 --- a/src/middleware/auth/routes/admin/admin-auth.ts +++ b/src/middleware/auth/routes/admin/admin-auth.ts @@ -6,6 +6,12 @@ export class AdminHandler extends BaseAuthHandler { constructor() { super(); // Subscriptions + this.registerRoute('/admin/subscription/create', 'POST', 'admin:subscription:create:testnet', { + skipNamespace: true, + }); + this.registerRoute('/admin/subscription/create', 'POST', 'admin:subscription:create:mainnet', { + skipNamespace: true, + }); this.registerRoute('/admin/subscription/list', 'GET', 'admin:subscription:list:testnet', { skipNamespace: true, }); diff --git a/src/static/swagger-admin.json b/src/static/swagger-admin.json index 25d1c408..3a591b7d 100644 --- a/src/static/swagger-admin.json +++ b/src/static/swagger-admin.json @@ -32,39 +32,6 @@ } ], "paths": { - "/admin/checkout/session/create": { - "post": { - "summary": "Create a checkout session", - "description": "Create a checkout session", - "tags": [ - "Checkout" - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CheckoutSessionCreateRequestBody" - } - } - } - }, - "responses": { - "303": { - "description": "A redirect to Stripe prebuilt checkout page" - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, "/admin/price/list": { "get": { "summary": "Get a list of prices", @@ -252,12 +219,11 @@ "tags": [ "Subscription" ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionUpdateRequestBody" - } + "requestBody": null, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionUpdateRequestBody" } } }, @@ -317,24 +283,13 @@ } } }, - "/admin/subscription/get/{subscriptionId}": { + "/admin/subscription/get": { "get": { "summary": "Get a subscription", "description": "Get a subscription", "tags": [ "Subscription" ], - "parameters": [ - { - "in": "path", - "name": "subscriptionId", - "schema": { - "type": "string", - "description": "The subscription id" - }, - "required": true - } - ], "responses": { "200": { "description": "The request was successful.", @@ -510,28 +465,20 @@ "description": "The request body for creating a subscription", "type": "object", "properties": { - "customerId": { + "price": { "type": "string", - "description": "The Stripe customer id", - "example": "cus_1234567890" + "description": "The price id", + "example": "price_1234567890" }, - "items": { - "type": "array", - "items": { - "type": "object", - "properties": { - "price": { - "type": "string", - "description": "The price id", - "example": "price_1234567890" - } - } - } + "successURL": { + "type": "string", + "description": "The URL to redirect to after the customer sucessfully completes the checkout", + "example": "https://example.com/success" }, - "idempotencyKey": { + "cancelURL": { "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": "abcdefghijklmnopqrstuvwxyz" + "description": "The URL to redirect to after the customer cancels the checkout", + "example": "https://example.com/cancel" } } }, @@ -541,7 +488,13 @@ "properties": { "subscription": { "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" + "description": "An object with link to checkout session. For more information see the [Stripe API documentation](https://docs.stripe.com/api/checkout/sessions/object)", + "properties": { + "url": { + "type": "string", + "description": "URL which user should follow to manage subscription" + } + } } } }, @@ -549,19 +502,9 @@ "description": "The request body for updating a subscription", "type": "object", "properties": { - "subscriptionId": { + "returnUrl": { "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - }, - "updateParams": { - "type": "object", - "description": "The subscription update parameters. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/update)" - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": "abcdefghijklmnopqrstuvwxyz" + "description": "URL which is used to redirect to the page with ability to update the subscription" } } }, @@ -571,7 +514,13 @@ "properties": { "subscription": { "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" + "description": "Object with redirect url inside", + "properties": { + "clientSecret": { + "type": "string", + "description": "URL with session URL rediect to" + } + } } } }, @@ -672,32 +621,6 @@ } } }, - "CheckoutSessionCreateRequestBody": { - "description": "The request body for creating a checkout session", - "type": "object", - "properties": { - "price": { - "type": "string", - "description": "The price id", - "example": "price_1234567890" - }, - "successURL": { - "type": "string", - "description": "The URL to redirect to after the customer sucessfully completes the checkout", - "example": "https://example.com/success" - }, - "cancelURL": { - "type": "string", - "description": "The URL to redirect to after the customer cancels the checkout", - "example": "https://example.com/cancel" - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": "abcdefghijklmnopqrstuvwxyz" - } - } - }, "NotFoundError": { "description": "The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible.", "type": "object", diff --git a/src/types/swagger-admin-types.ts b/src/types/swagger-admin-types.ts index 08dad75a..2ed76988 100644 --- a/src/types/swagger-admin-types.ts +++ b/src/types/swagger-admin-types.ts @@ -60,10 +60,6 @@ * type: string * description: The URL to redirect to after the customer cancels the checkout * example: https://example.com/cancel - * idempotencyKey: - * type: string - * description: The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request. - * example: abcdefghijklmnopqrstuvwxyz * SubscriptionCreateResponseBody: * description: The response body for creating a subscription * type: object @@ -79,17 +75,9 @@ * description: The request body for updating a subscription * type: object * properties: - * subscriptionId: - * type: string - * description: The subscription id - * example: sub_1234567890 - * updateParams: - * type: object - * description: The subscription update parameters. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/update) - * idempotencyKey: + * returnUrl: * type: string - * description: The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request. - * example: abcdefghijklmnopqrstuvwxyz + * description: URL which is used to redirect to the page with ability to update the subscription * SubscriptionUpdateResponseBody: * description: The response body for updating a subscription * type: object From 769b520fcfd2912e79db837bb546046aaea6c6b7 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Wed, 20 Mar 2024 16:54:58 +0100 Subject: [PATCH 10/40] Fix swagger request body for subscription update --- src/controllers/admin/subscriptions.ts | 8 ++++---- src/static/swagger-admin.json | 11 ++++++----- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/controllers/admin/subscriptions.ts b/src/controllers/admin/subscriptions.ts index 3ff2cc35..8638e39e 100644 --- a/src/controllers/admin/subscriptions.ts +++ b/src/controllers/admin/subscriptions.ts @@ -155,10 +155,10 @@ export class SubscriptionController { * description: Updates an existing subscription * tags: [Subscription] * requestBody: - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/SubscriptionUpdateRequestBody' + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/SubscriptionUpdateRequestBody' * responses: * 200: * description: The request was successful. diff --git a/src/static/swagger-admin.json b/src/static/swagger-admin.json index 3a591b7d..f106acf7 100644 --- a/src/static/swagger-admin.json +++ b/src/static/swagger-admin.json @@ -219,11 +219,12 @@ "tags": [ "Subscription" ], - "requestBody": null, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionUpdateRequestBody" + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionUpdateRequestBody" + } } } }, From d39e55f9d2779d42879d9c4b9fb4f811aa0b4966 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Wed, 20 Mar 2024 21:46:26 +0100 Subject: [PATCH 11/40] Fix stripeSync function --- src/app.ts | 5 +-- src/controllers/admin/subscriptions.ts | 44 +++++++++++++++++++++----- src/services/admin/subscription.ts | 9 +++++- src/static/swagger-admin.json | 7 +++- src/types/portal.ts | 4 +-- src/types/swagger-admin-types.ts | 6 +++- 6 files changed, 58 insertions(+), 17 deletions(-) diff --git a/src/app.ts b/src/app.ts index 7e9d41bf..a35f2b53 100644 --- a/src/app.ts +++ b/src/app.ts @@ -243,10 +243,7 @@ class App { SubscriptionController.subscriptionUpdateValidator, new SubscriptionController().update ); - app.get( - '/admin/subscription/get', - new SubscriptionController().get - ); + app.get('/admin/subscription/get', new SubscriptionController().get); app.get( '/admin/subscription/list', SubscriptionController.subscriptionListValidator, diff --git a/src/controllers/admin/subscriptions.ts b/src/controllers/admin/subscriptions.ts index 8638e39e..f54c79b0 100644 --- a/src/controllers/admin/subscriptions.ts +++ b/src/controllers/admin/subscriptions.ts @@ -17,7 +17,7 @@ import type { SubscriptionResumeUnsuccessfulResponseBody, SubscriptionResumeResponseBody, SubscriptionResumeRequestBody, - SubscriptionCancelRequestBody + SubscriptionCancelRequestBody, } from '../../types/portal.js'; import { StatusCodes } from 'http-status-codes'; import { validationResult } from '../validator/index.js'; @@ -30,14 +30,39 @@ const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); export class SubscriptionController { static subscriptionCreateValidator = [ - check('price').exists().withMessage('price was not provided').bail().isString().withMessage('price should be a string').bail(), - check('successURL').exists().withMessage('successURL was not provided').bail().isString().withMessage('successURL should be a string').bail(), - check('cancelURL').exists().withMessage('cancelURL was not provided').bail().isString().withMessage('cancelURL should be a string').bail(), + check('price') + .exists() + .withMessage('price was not provided') + .bail() + .isString() + .withMessage('price should be a string') + .bail(), + check('successURL') + .exists() + .withMessage('successURL was not provided') + .bail() + .isString() + .withMessage('successURL should be a string') + .bail(), + check('cancelURL') + .exists() + .withMessage('cancelURL was not provided') + .bail() + .isString() + .withMessage('cancelURL should be a string') + .bail(), check('quantity').optional().isInt().withMessage('quantity should be an integer').bail(), + check('idempotencyKey').optional().isString().withMessage('idempotencyKey should be a string').bail(), ]; static subscriptionUpdateValidator = [ - check('returnUrl').exists().withMessage('returnUrl was not provided').bail().isString().withMessage('returnUrl should be a string').bail(), + check('returnURL') + .exists() + .withMessage('returnUrl was not provided') + .bail() + .isString() + .withMessage('returnUrl should be a string') + .bail(), ]; static subscriptionListValidator = [ @@ -93,6 +118,7 @@ export class SubscriptionController { * 500: * $ref: '#/components/schemas/InternalError' */ + async create(request: Request, response: Response) { // Validate request const result = validationResult(request); @@ -189,7 +215,7 @@ export class SubscriptionController { await SubscriptionService.instance.stripeSync(response.locals.customer); // Get the subscription object from the DB - const subscription = await SubscriptionService.instance.findOne({customer: response.locals.customer}); + const subscription = await SubscriptionService.instance.findOne({ customer: response.locals.customer }); if (!subscription) { return response.status(StatusCodes.NOT_FOUND).json({ error: `Subscription was not found`, @@ -210,7 +236,6 @@ export class SubscriptionController { return response.status(StatusCodes.OK).json({ clientSecret: session.url, } satisfies SubscriptionUpdateResponseBody); - } catch (error) { return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ error: `Internal error: ${(error as Error)?.message || error}`, @@ -313,7 +338,10 @@ export class SubscriptionController { // Sync our DB with Stripe await SubscriptionService.instance.stripeSync(response.locals.customer); // Get the subscriptionId from the request - const _sub = await SubscriptionService.instance.findOne({customer: response.locals.customer}); + const _sub = await SubscriptionService.instance.findOne({ + customer: response.locals.customer, + status: 'active' + }); if (!_sub) { return response.status(StatusCodes.NOT_FOUND).json({ error: `Subscription was not found`, diff --git a/src/services/admin/subscription.ts b/src/services/admin/subscription.ts index 5c585a2b..a4343462 100644 --- a/src/services/admin/subscription.ts +++ b/src/services/admin/subscription.ts @@ -92,7 +92,13 @@ export class SubscriptionService { stripeCustomerId = user?.customer.stripeCustomerId as string; } - const subscriptions = await stripe.subscriptions.list({ customer: stripeCustomerId }); + // ToDo: add pagination + + const subscriptions = await stripe.subscriptions.list({ + customer: stripeCustomerId, + status: 'all', + limit: 100, + }); // Get list of all subscription and sort them by created time to make sure that we are processing them in the correct order for (const subscription of subscriptions.data.sort((a, b) => a.created - b.created)) { const existing = await this.subscriptionRepository.findOne({ @@ -129,6 +135,7 @@ export class SubscriptionService { severity: 'info', }); } else { + // ToDo: Update only if there are changes const res = await this.update( subscription.id, subscription.status, diff --git a/src/static/swagger-admin.json b/src/static/swagger-admin.json index f106acf7..cb9b28ea 100644 --- a/src/static/swagger-admin.json +++ b/src/static/swagger-admin.json @@ -480,6 +480,11 @@ "type": "string", "description": "The URL to redirect to after the customer cancels the checkout", "example": "https://example.com/cancel" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": "abcdefghijklmnopqrstuvwxyz" } } }, @@ -503,7 +508,7 @@ "description": "The request body for updating a subscription", "type": "object", "properties": { - "returnUrl": { + "returnURL": { "type": "string", "description": "URL which is used to redirect to the page with ability to update the subscription" } diff --git a/src/types/portal.ts b/src/types/portal.ts index 01fd8ea1..32d2efd3 100644 --- a/src/types/portal.ts +++ b/src/types/portal.ts @@ -43,8 +43,8 @@ export type SubscriptionUpdateResponseBody = { // Update export type SubscriptionUpdateRequestBody = { - returnUrl: string -} + returnUrl: string; +}; // Get export type SubscriptionGetRequestBody = { diff --git a/src/types/swagger-admin-types.ts b/src/types/swagger-admin-types.ts index 2ed76988..03ab7225 100644 --- a/src/types/swagger-admin-types.ts +++ b/src/types/swagger-admin-types.ts @@ -60,6 +60,10 @@ * type: string * description: The URL to redirect to after the customer cancels the checkout * example: https://example.com/cancel + * idempotencyKey: + * type: string + * description: The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request. + * example: abcdefghijklmnopqrstuvwxyz * SubscriptionCreateResponseBody: * description: The response body for creating a subscription * type: object @@ -75,7 +79,7 @@ * description: The request body for updating a subscription * type: object * properties: - * returnUrl: + * returnURL: * type: string * description: URL which is used to redirect to the page with ability to update the subscription * SubscriptionUpdateResponseBody: From 4fcd102b859e61f1b68073d201b8652092202e64 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Sun, 24 Mar 2024 00:09:48 +0100 Subject: [PATCH 12/40] Get permissions from the M2M token --- .../user-info-fetcher/{m2m-token.ts => m2m-creds-token.ts} | 2 +- src/middleware/auth/user-info-fetcher/portal-token.ts | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) rename src/middleware/auth/user-info-fetcher/{m2m-token.ts => m2m-creds-token.ts} (95%) diff --git a/src/middleware/auth/user-info-fetcher/m2m-token.ts b/src/middleware/auth/user-info-fetcher/m2m-creds-token.ts similarity index 95% rename from src/middleware/auth/user-info-fetcher/m2m-token.ts rename to src/middleware/auth/user-info-fetcher/m2m-creds-token.ts index a865decb..f07a9cac 100644 --- a/src/middleware/auth/user-info-fetcher/m2m-token.ts +++ b/src/middleware/auth/user-info-fetcher/m2m-creds-token.ts @@ -9,7 +9,7 @@ import { createRemoteJWKSet, jwtVerify } from 'jose'; import * as dotenv from 'dotenv'; dotenv.config(); -export class M2MTokenUserInfoFetcher extends AuthReturn implements IUserInfoFetcher { +export class M2MCredsTokenUserInfoFetcher extends AuthReturn implements IUserInfoFetcher { token: string; constructor(token: string) { diff --git a/src/middleware/auth/user-info-fetcher/portal-token.ts b/src/middleware/auth/user-info-fetcher/portal-token.ts index a972cbfe..f11844b5 100644 --- a/src/middleware/auth/user-info-fetcher/portal-token.ts +++ b/src/middleware/auth/user-info-fetcher/portal-token.ts @@ -74,10 +74,7 @@ export class PortalUserInfoFetcher extends AuthReturn implements IUserInfoFetche if (!payload.sub) { return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: No sub found in the token.`); } - const { error, data: scopes } = await oauthProvider.getAppScopes(payload.sub); - if (error) { - return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: No scopes found for the roles.`); - } + const scopes = payload.scope ? (payload.scope as string).split(' ') : []; this.setScopes(scopes); return this.returnOk(); } catch (error) { From b985ec5c680ffa7b73eba26f2445cba185cfed0d Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Sun, 24 Mar 2024 13:06:39 +0100 Subject: [PATCH 13/40] Sync updated and small clean-ups --- src/controllers/admin/prices.ts | 12 +- src/controllers/admin/product.ts | 20 +-- src/controllers/admin/subscriptions.ts | 100 ++++++----- src/controllers/admin/webhook.ts | 7 +- src/controllers/validator/decorator.ts | 32 ++++ src/middleware/auth/base-auth-handler.ts | 4 +- .../auth/routes/admin/admin-auth.ts | 13 ++ src/services/admin/stripe.ts | 164 ++++++++++++++++++ src/services/admin/subscription.ts | 104 ++--------- 9 files changed, 292 insertions(+), 164 deletions(-) create mode 100644 src/controllers/validator/decorator.ts create mode 100644 src/services/admin/stripe.ts diff --git a/src/controllers/admin/prices.ts b/src/controllers/admin/prices.ts index e78e5dac..e0569ad9 100644 --- a/src/controllers/admin/prices.ts +++ b/src/controllers/admin/prices.ts @@ -3,8 +3,8 @@ import type { Request, Response } from 'express'; import * as dotenv from 'dotenv'; import type { PriceListResponseBody, PriceListUnsuccessfulResponseBody } from '../../types/portal.js'; import { StatusCodes } from 'http-status-codes'; -import { validationResult } from '../validator/index.js'; -import { check } from 'express-validator'; +import { check } from '../validator/index.js'; +import { validate } from '../validator/decorator.js'; dotenv.config(); @@ -46,14 +46,8 @@ export class PriceController { * 404: * $ref: '#/components/schemas/NotFoundError' */ + @validate async getListPrices(request: Request, response: Response) { - const result = validationResult(request); - // handle error - if (!result.isEmpty()) { - return response.status(StatusCodes.BAD_REQUEST).json({ - error: result.array().pop()?.msg, - } satisfies PriceListUnsuccessfulResponseBody); - } // Get query parameters const productId = request.query.productId; diff --git a/src/controllers/admin/product.ts b/src/controllers/admin/product.ts index e1c7b114..d28041f7 100644 --- a/src/controllers/admin/product.ts +++ b/src/controllers/admin/product.ts @@ -9,8 +9,8 @@ import type { ProductWithPrices, } from '../../types/portal.js'; import { StatusCodes } from 'http-status-codes'; -import { validationResult } from '../validator/index.js'; -import { check } from 'express-validator'; +import { check } from '../validator/index.js'; +import { validate } from '../validator/decorator.js'; dotenv.config(); @@ -57,14 +57,8 @@ export class ProductController { * 404: * $ref: '#/components/schemas/NotFoundError' */ + @validate async listProducts(request: Request, response: Response) { - const result = validationResult(request); - // handle error - if (!result.isEmpty()) { - return response.status(StatusCodes.BAD_REQUEST).json({ - error: result.array().pop()?.msg, - } satisfies ProductListUnsuccessfulResponseBody); - } // Get query parameters const prices = request.query.prices === 'false' ? false : true; @@ -137,14 +131,8 @@ export class ProductController { * 404: * $ref: '#/components/schemas/NotFoundError' */ + @validate async getProduct(request: Request, response: Response) { - const result = validationResult(request); - // handle error - if (!result.isEmpty()) { - return response.status(StatusCodes.BAD_REQUEST).json({ - error: result.array().pop()?.msg, - } satisfies ProductGetUnsuccessfulResponseBody); - } // Get query parameters const prices = request.query.prices === 'false' ? false : true; const productId = request.params.productId as string; diff --git a/src/controllers/admin/subscriptions.ts b/src/controllers/admin/subscriptions.ts index f54c79b0..ea0e6b54 100644 --- a/src/controllers/admin/subscriptions.ts +++ b/src/controllers/admin/subscriptions.ts @@ -20,14 +20,45 @@ import type { SubscriptionCancelRequestBody, } from '../../types/portal.js'; import { StatusCodes } from 'http-status-codes'; -import { validationResult } from '../validator/index.js'; -import { check } from 'express-validator'; +import { check, validationResult } from '../validator/index.js'; import { SubscriptionService } from '../../services/admin/subscription.js'; +import { stripeService } from '../../services/admin/stripe.js'; +import { UnsuccessfulResponseBody } from '../../types/shared.js'; +import { validate } from '../validator/decorator.js'; dotenv.config(); const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); +export function stripeSync(target: any, key: string, descriptor: PropertyDescriptor | undefined) { + + // save a reference to the original method this way we keep the values currently in the + // descriptor and don't overwrite what another decorator might have done to the descriptor. + if(descriptor === undefined) { + descriptor = Object.getOwnPropertyDescriptor(target, key) as PropertyDescriptor; + } + + const originalMethod = descriptor.value; + + //editing the descriptor/value parameter + descriptor.value = async function (...args: any[]) { + const response: Response = args[1]; + if (response.locals.customer) { + try { + await stripeService.syncCustomer(response.locals.customer); + } catch (error) { + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: `Internal error: ${(error as Error)?.message || error}`, + } satisfies UnsuccessfulResponseBody); + } + } + return originalMethod.apply(this, args); + }; + + // return edited descriptor as opposed to overwriting the descriptor + return descriptor; +} + export class SubscriptionController { static subscriptionCreateValidator = [ check('price') @@ -58,15 +89,15 @@ export class SubscriptionController { static subscriptionUpdateValidator = [ check('returnURL') .exists() - .withMessage('returnUrl was not provided') + .withMessage('returnURL was not provided') .bail() .isString() - .withMessage('returnUrl should be a string') + .withMessage('returnURL should be a string') .bail(), ]; static subscriptionListValidator = [ - check('customerId').optional().isString().withMessage('customerId should be a string').bail(), + check('stripeCustomerId').optional().isString().withMessage('customerId should be a string').bail(), ]; static subscriptionCancelValidator = [ @@ -119,6 +150,7 @@ export class SubscriptionController { * $ref: '#/components/schemas/InternalError' */ + @validate async create(request: Request, response: Response) { // Validate request const result = validationResult(request); @@ -199,20 +231,11 @@ export class SubscriptionController { * 500: * $ref: '#/components/schemas/InternalError' */ + @validate + @stripeSync async update(request: Request, response: Response) { - // Validate request - const result = validationResult(request); - if (!result.isEmpty()) { - return response.status(StatusCodes.BAD_REQUEST).json({ - error: result.array().pop()?.msg, - } satisfies SubscriptionUpdateUnsuccessfulResponseBody); - } - const { returnUrl } = request.body satisfies SubscriptionUpdateRequestBody; - try { - // Sync with Stripe - await SubscriptionService.instance.stripeSync(response.locals.customer); // Get the subscription object from the DB const subscription = await SubscriptionService.instance.findOne({ customer: response.locals.customer }); @@ -251,6 +274,12 @@ export class SubscriptionController { * summary: Get a list of subscriptions * description: Get a list of subscriptions * tags: [Subscription] + * parameters: + * - in: query + * name: stripeCustomerId + * schema: + * type: string + * description: The customer id. If passed - returns filtered by this customer list of subscriptions. * responses: * 200: * description: A list of subscriptions @@ -268,22 +297,15 @@ export class SubscriptionController { * $ref: '#/components/schemas/NotFoundError' */ + @validate + @stripeSync public async list(request: Request, response: Response) { - // Validate request - const result = validationResult(request); - if (!result.isEmpty()) { - return response.status(StatusCodes.BAD_REQUEST).json({ - error: result.array().pop()?.msg, - } satisfies SubscriptionListUnsuccessfulResponseBody); - } - const customerId = response.locals.customer.stripeCustomerId; + const stripeCustomerId = response.locals.customer.stripeCustomerId; try { - // Sync our DB with Stripe - await SubscriptionService.instance.stripeSync(response.locals.customer); // Get the subscriptions - const subscriptions = customerId + const subscriptions = stripeCustomerId ? await stripe.subscriptions.list({ - customer: customerId as string, + customer: stripeCustomerId as string, }) : await stripe.subscriptions.list(); @@ -326,17 +348,10 @@ export class SubscriptionController { * 404: * $ref: '#/components/schemas/NotFoundError' */ + @validate + @stripeSync async get(request: Request, response: Response) { - // Validate request - const result = validationResult(request); - if (!result.isEmpty()) { - return response.status(StatusCodes.BAD_REQUEST).json({ - error: result.array().pop()?.msg, - } satisfies SubscriptionGetUnsuccessfulResponseBody); - } try { - // Sync our DB with Stripe - await SubscriptionService.instance.stripeSync(response.locals.customer); // Get the subscriptionId from the request const _sub = await SubscriptionService.instance.findOne({ customer: response.locals.customer, @@ -392,14 +407,9 @@ export class SubscriptionController { * 404: * $ref: '#/components/schemas/NotFoundError' */ + @validate + @stripeSync async cancel(request: Request, response: Response) { - // Validate request - const result = validationResult(request); - if (!result.isEmpty()) { - return response.status(StatusCodes.BAD_REQUEST).json({ - error: result.array().pop()?.msg, - } satisfies SubscriptionCancelUnsuccessfulResponseBody); - } const { subscriptionId, idempotencyKey } = request.body satisfies SubscriptionCancelRequestBody; try { @@ -453,6 +463,8 @@ export class SubscriptionController { * 404: * $ref: '#/components/schemas/NotFoundError' */ + @validate + @stripeSync async resume(request: Request, response: Response) { // Validate request const result = validationResult(request); diff --git a/src/controllers/admin/webhook.ts b/src/controllers/admin/webhook.ts index 29363b80..42421bd9 100644 --- a/src/controllers/admin/webhook.ts +++ b/src/controllers/admin/webhook.ts @@ -12,6 +12,8 @@ dotenv.config(); const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); export class WebhookController { public async handleWebhook(request: Request, response: Response) { + // Signature verification and webhook handling is placed in the same method + // cause stripe uses the mthod which validate the signature and provides the event. let event = request.body; let subscription; let status; @@ -29,9 +31,6 @@ export class WebhookController { } satisfies ISubmitData, } satisfies ISubmitOperation; }; - // Only verify the event if you have an endpoint secret defined. - // Otherwise use the basic event deserialized with JSON.parse - // Get the signature sent by Stripe if (!process.env.STRIPE_WEBHOOK_SECRET) { await eventTracker.notify({ @@ -114,8 +113,6 @@ export class WebhookController { severity: 'info', } satisfies INotifyMessage); await eventTracker.submit(builSubmitOperation(subscription, OperationNameEnum.SUBSCRIPTION_UPDATE)); - // Then define and call a method to handle the subscription update. - // handleSubscriptionUpdated(subscription); break; default: // Unexpected event type diff --git a/src/controllers/validator/decorator.ts b/src/controllers/validator/decorator.ts new file mode 100644 index 00000000..1bb3673b --- /dev/null +++ b/src/controllers/validator/decorator.ts @@ -0,0 +1,32 @@ + +import type { ValidationErrorResponseBody } from '../../types/shared.js'; +import { Request, Response } from 'express'; +import { validationResult } from './index.js'; +import { StatusCodes } from 'http-status-codes'; + +export function validate(target: any, key: string, descriptor: PropertyDescriptor | undefined) { + + // save a reference to the original method this way we keep the values currently in the + // descriptor and don't overwrite what another decorator might have done to the descriptor. + if(descriptor === undefined) { + descriptor = Object.getOwnPropertyDescriptor(target, key) as PropertyDescriptor; + } + + const originalMethod = descriptor.value; + + //editing the descriptor/value parameter + descriptor.value = async function (...args: any[]) { + const request: Request = args[0]; + const response: Response = args[1]; + const result = validationResult(request); + if (!result.isEmpty()) { + return response.status(StatusCodes.BAD_REQUEST).json({ + error: result.array().pop()?.msg, + } satisfies ValidationErrorResponseBody); + } + return originalMethod.apply(this, args); + }; + + // return edited descriptor as opposed to overwriting the descriptor + return descriptor; +} \ No newline at end of file diff --git a/src/middleware/auth/base-auth-handler.ts b/src/middleware/auth/base-auth-handler.ts index 255810fe..18ae8e17 100644 --- a/src/middleware/auth/base-auth-handler.ts +++ b/src/middleware/auth/base-auth-handler.ts @@ -8,7 +8,7 @@ import { APITokenUserInfoFetcher } from './user-info-fetcher/api-token.js'; import type { IUserInfoFetcher } from './user-info-fetcher/base.js'; import { IAuthHandler, RuleRoutine, IAPIGuard } from './routine.js'; import type { IAuthResponse, MethodToScopeRule } from '../../types/authentication.js'; -import { M2MTokenUserInfoFetcher } from './user-info-fetcher/m2m-token.js'; +import { M2MCredsTokenUserInfoFetcher } from './user-info-fetcher/m2m-creds-token.js'; import { decodeJwt } from 'jose'; import { PortalUserInfoFetcher } from './user-info-fetcher/portal-token.js'; @@ -140,7 +140,7 @@ export class BaseAuthHandler extends BaseAPIGuard implements IAuthHandler { if (payload.aud === process.env.LOGTO_APP_ID) { this.setUserInfoStrategy(new APITokenUserInfoFetcher(token)); } else { - this.setUserInfoStrategy(new M2MTokenUserInfoFetcher(token)); + this.setUserInfoStrategy(new M2MCredsTokenUserInfoFetcher(token)); } } else { this.setUserInfoStrategy(new SwaggerUserInfoFetcher()); diff --git a/src/middleware/auth/routes/admin/admin-auth.ts b/src/middleware/auth/routes/admin/admin-auth.ts index 84cc5a99..4c10144f 100644 --- a/src/middleware/auth/routes/admin/admin-auth.ts +++ b/src/middleware/auth/routes/admin/admin-auth.ts @@ -6,6 +6,7 @@ export class AdminHandler extends BaseAuthHandler { constructor() { super(); // Subscriptions + // skipNamespace is set to true cause we don't have the information about the namespace in the request this.registerRoute('/admin/subscription/create', 'POST', 'admin:subscription:create:testnet', { skipNamespace: true, }); @@ -24,6 +25,18 @@ export class AdminHandler extends BaseAuthHandler { this.registerRoute('/admin/subscription/update', 'POST', 'admin:subscription:update:mainnet', { skipNamespace: true, }); + this.registerRoute('/admin/subscription/cancel', 'POST', 'admin:subscription:cancel:testnet', { + skipNamespace: true, + }); + this.registerRoute('/admin/subscription/cancel', 'POST', 'admin:subscription:cancel:mainnet', { + skipNamespace: true, + }); + this.registerRoute('/admin/subscription/resume', 'POST', 'admin:subscription:resume:testnet', { + skipNamespace: true, + }); + this.registerRoute('/admin/subscription/resume', 'POST', 'admin:subscription:resume:mainnet', { + skipNamespace: true, + }); this.registerRoute('/admin/subscription/get', 'GET', 'admin:subscription:get:testnet', { skipNamespace: true }); this.registerRoute('/admin/subscription/get', 'GET', 'admin:subscription:get:mainnet', { skipNamespace: true }); // Prices diff --git a/src/services/admin/stripe.ts b/src/services/admin/stripe.ts new file mode 100644 index 00000000..8db2e3c6 --- /dev/null +++ b/src/services/admin/stripe.ts @@ -0,0 +1,164 @@ +import Stripe from 'stripe'; +import * as dotenv from 'dotenv'; +import { SubscriptionService } from './subscription.js'; +import type { CustomerEntity } from '../../database/entities/customer.entity.js'; +import { EventTracker, eventTracker } from '../track/tracker.js'; +import { CustomerService } from '../api/customer.js'; +import type { SubscriptionEntity } from '../../database/entities/subscription.entity.js'; + +dotenv.config(); + +const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); + +export class StripeService { + + private stripeToCustomer: Map = new Map(); + + async syncFull(): Promise { + // Set all customers + await this.setStripeCustomers(); + // Sync all subscriptions + for await (const subscription of stripe.subscriptions.list()) { + const current = await SubscriptionService.instance.subscriptionRepository.findOne({ + where: { subscriptionId: subscription.id } + }) + if (current) { + await this.updateSubscription(subscription, current); + } + else { + await this.createSubscription(subscription); + } + } + eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `Subscription syncronization completed`, + 'Subscription syncronization' + ), + severity: 'info', + }) + } + + // Sync all the subscriptions for current customer + async syncCustomer(customer: CustomerEntity): Promise { + for await (const subscription of stripe.subscriptions.list({ + customer: customer.stripeCustomerId, + status: 'all' + })) { + const current = await SubscriptionService.instance.subscriptionRepository.findOne({ + where: { subscriptionId: subscription.id } + }) + if (current) { + await this.updateSubscription(subscription, current); + } + else { + await this.createSubscription(subscription, customer); + } + } + } + + async setStripeCustomers(): Promise { + const customers = await CustomerService.instance.customerRepository.createQueryBuilder('customer') + .select('customer.customerId', 'customer.stripeCustomerId') + .where('customer.stripeCustomerId IS NOT NULL') + .getMany(); + customers.forEach((customer) => { + this.stripeToCustomer.set(customer.stripeCustomerId, customer); + }); + } + + async isExists(subscriptionId: string): Promise { + const subscriptionEntity = await SubscriptionService.instance.subscriptionRepository.findOne({ + where: { subscriptionId } + }); + return !!subscriptionEntity; + } + + async createSubscription(subscription: Stripe.Subscription, customerEntity?: CustomerEntity): Promise { + const customer = customerEntity + ? customerEntity + : this.stripeToCustomer.get(subscription.customer as string); + + if (!customer) { + eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `Cannot find a customer for subscription with id ${subscription.id}`, + 'Subscription syncronization' + ), + severity: 'error', + }); + return; + } + // Create a new subscription in the database + const subscriptionEntity = SubscriptionService.instance.create( + subscription.id, + customer, + subscription.status, + new Date(subscription.current_period_start * 1000), + new Date(subscription.current_period_end * 1000), + subscription.trial_start ? new Date(subscription.trial_start * 1000) : undefined, + subscription.trial_end ? new Date(subscription.trial_end * 1000) : undefined + ); + + // Track the event + if (!subscriptionEntity) { + eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `Cannot create a new subscription with id ${subscription.id}`, + 'Subscription syncronization' + ), + severity: 'error', + }); + } + eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `New subscription with id ${subscription.id} created`, + 'Subscription syncronization' + ), + severity: 'info', + }); + } + + async updateSubscription(subscription: Stripe.Subscription, current: SubscriptionEntity): Promise { + // Update only if there are changes + if (SubscriptionService.instance.equals(current, subscription)) { + eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `Subscription with id ${subscription.id} has no changes`, + 'Subscription syncronization' + ), + severity: 'debug', + }) + return + } + + // Update subscription in the database + const subscriptionEntity = SubscriptionService.instance.update( + subscription.id, + subscription.status, + new Date(subscription.current_period_start * 1000), + new Date(subscription.current_period_end * 1000), + subscription.trial_start ? new Date(subscription.trial_start * 1000) : undefined, + subscription.trial_end ? new Date(subscription.trial_end * 1000) : undefined + ); + + // Track the event + if (!subscriptionEntity) { + eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `Cannot update subscription with id ${subscription.id}`, + 'Subscription syncronization' + ), + severity: 'error', + }); + } + eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `Subscription with id ${subscription.id} updated`, + 'Subscription syncronization' + ), + severity: 'info', + }); + } +} + +export const stripeService = new StripeService(); \ No newline at end of file diff --git a/src/services/admin/subscription.ts b/src/services/admin/subscription.ts index a4343462..07cb2142 100644 --- a/src/services/admin/subscription.ts +++ b/src/services/admin/subscription.ts @@ -3,15 +3,7 @@ import type { Repository } from 'typeorm'; import { Connection } from '../../database/connection/connection.js'; import { SubscriptionEntity } from '../../database/entities/subscription.entity.js'; import type { CustomerEntity } from '../../database/entities/customer.entity.js'; -import type { UserEntity } from '../../database/entities/user.entity.js'; -import Stripe from 'stripe'; -import * as dotenv from 'dotenv'; -import { CustomerService } from '../api/customer.js'; -import { EventTracker, eventTracker } from '../track/tracker.js'; - -dotenv.config(); - -const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); +import type Stripe from 'stripe'; export class SubscriptionService { public subscriptionRepository: Repository; @@ -81,86 +73,22 @@ export class SubscriptionService { }); } - public async stripeSync(customer?: CustomerEntity, user?: UserEntity): Promise { - let stripeCustomerId: string; - if (!customer && !user) { - throw new Error('StripeSync: customer or user is required'); - } - if (customer) { - stripeCustomerId = customer.stripeCustomerId; - } else { - stripeCustomerId = user?.customer.stripeCustomerId as string; + public equals(subscriptionEntity: SubscriptionEntity, subscription: Stripe.Subscription): boolean { + const required = + subscriptionEntity.subscriptionId === subscription.id && + subscriptionEntity.status === subscription.status && + subscriptionEntity.currentPeriodStart.getTime() === subscription.current_period_start * 1000 && + subscriptionEntity.currentPeriodEnd.getTime() === subscription.current_period_end * 1000; + if (!required) return false; + // Check trial dates only if they are present in the subscription + if (subscription.trial_start) { + if (!subscriptionEntity.trialStart || subscriptionEntity.trialStart.getTime() !== subscription.trial_start * 1000) + return false; } - - // ToDo: add pagination - - const subscriptions = await stripe.subscriptions.list({ - customer: stripeCustomerId, - status: 'all', - limit: 100, - }); - // Get list of all subscription and sort them by created time to make sure that we are processing them in the correct order - for (const subscription of subscriptions.data.sort((a, b) => a.created - b.created)) { - const existing = await this.subscriptionRepository.findOne({ - where: { subscriptionId: subscription.id }, - }); - if (!existing) { - const customer = await CustomerService.instance.findbyStripeCustomerId(stripeCustomerId); - if (!customer) { - throw new Error(`Customer with stripeCustomerId ${stripeCustomerId} not found`); - } - const res = await this.create( - subscription.id, - customer, - subscription.status, - new Date(subscription.current_period_start * 1000), - new Date(subscription.current_period_end * 1000), - subscription.trial_start ? new Date(subscription.trial_start * 1000) : undefined, - subscription.trial_end ? new Date(subscription.trial_end * 1000) : undefined - ); - if (!res) { - eventTracker.notify({ - message: EventTracker.compileBasicNotification( - `Cannot create a new subscription with id ${subscription.id}`, - 'Subscription syncronization' - ), - severity: 'error', - }); - } - eventTracker.notify({ - message: EventTracker.compileBasicNotification( - `New subscription with id ${subscription.id} created`, - 'Subscription syncronization' - ), - severity: 'info', - }); - } else { - // ToDo: Update only if there are changes - const res = await this.update( - subscription.id, - subscription.status, - new Date(subscription.current_period_start * 1000), - new Date(subscription.current_period_end * 1000), - subscription.trial_start ? new Date(subscription.trial_start * 1000) : undefined, - subscription.trial_end ? new Date(subscription.trial_end * 1000) : undefined - ); - if (!res) { - eventTracker.notify({ - message: EventTracker.compileBasicNotification( - `Cannot update subscription with id ${subscription.id}`, - 'Subscription syncronization' - ), - severity: 'error', - }); - } - eventTracker.notify({ - message: EventTracker.compileBasicNotification( - `Subscription with id ${subscription.id} updated`, - 'Subscription syncronization' - ), - severity: 'info', - }); - } + if (subscription.trial_end) { + if (!subscriptionEntity.trialEnd || subscriptionEntity.trialEnd.getTime() !== subscription.trial_end * 1000) + return false; } + return true; } } From 64ea85b6f2a6fe1bcd237eb01132c0f99510fad8 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Sun, 24 Mar 2024 15:53:14 +0100 Subject: [PATCH 14/40] Clean-ups --- README.md | 7 +- docker/Dockerfile | 2 + src/app.ts | 89 ++++---- src/controllers/admin/prices.ts | 5 +- src/controllers/admin/product.ts | 6 +- src/controllers/admin/subscriptions.ts | 65 +++--- src/controllers/admin/webhook.ts | 19 +- src/controllers/validator/decorator.ts | 34 ++- src/middleware/middleware.ts | 10 + src/services/admin/stripe.ts | 209 ++++++------------ src/services/admin/subscription.ts | 5 +- src/services/track/admin/account-submitter.ts | 5 +- .../track/admin/subscription-submitter.ts | 62 ++---- src/services/track/helpers.ts | 19 ++ src/services/track/submitter.ts | 3 + src/services/track/types.ts | 5 + src/static/swagger-admin.json | 14 +- src/types/environment.d.ts | 1 + src/types/portal.ts | 4 +- src/types/swagger-admin-types.ts | 4 +- 20 files changed, 245 insertions(+), 323 deletions(-) diff --git a/README.md b/README.md index 916a6c33..e2158ef1 100644 --- a/README.md +++ b/README.md @@ -111,9 +111,10 @@ some tokens on the testnet for making the process simpler. The application supports Stripe integration for payment processing. -1. `STRIPE_SECRET_KEY`: Secret key for Stripe API. Please, keep it secret on deploying -2. `STRIPE_PUBLISHABLE_KEY` - Publishable key for Stripe API. -3. `STRIPE_WEBHOOK_SECRET` - Secret for Stripe Webhook. +1. `STRIPE_ENABLED` - Enable/disable Stripe integration (`false` by default) +2. `STRIPE_SECRET_KEY` - Secret key for Stripe API. Please, keep it secret on deploying +3. `STRIPE_PUBLISHABLE_KEY` - Publishable key for Stripe API. +4. `STRIPE_WEBHOOK_SECRET` - Secret for Stripe Webhook. ### 3rd Party Connectors diff --git a/docker/Dockerfile b/docker/Dockerfile index c3da44e0..2eadb5da 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -82,6 +82,7 @@ ARG FAUCET_URI=https://faucet-api.cheqd.network/credit ARG TESTNET_MINIMUM_BALANCE=1000 # Stripe +ARG STRIPE_ENABLED=false ARG STRIPE_SECRET_KEY ARG STRIPE_PUBLISHABLE_KEY ARG STRIPE_WEBHOOK_SECRET @@ -134,6 +135,7 @@ ENV POLYGON_PRIVATE_KEY ${POLYGON_PRIVATE_KEY} ENV STRIPE_SECRET_KEY ${STRIPE_SECRET_KEY} ENV STRIPE_PUBLISHABLE_KEY ${STRIPE_PUBLISHABLE_KEY} ENV STRIPE_WEBHOOK_SECRET ${STRIPE_WEBHOOK_SECRET} +ENV STRIPE_ENABLED ${STRIPE_ENABLED} # Set ownership permissions RUN chown -R node:node /home/node/app diff --git a/src/app.ts b/src/app.ts index a35f2b53..c6043c99 100644 --- a/src/app.ts +++ b/src/app.ts @@ -106,11 +106,14 @@ class App { swaggerUi.serveFiles(swaggerAPIDocument, swaggerOptions), swaggerUi.setup(swaggerAPIDocument, swaggerOptions) ); - this.express.use( - '/admin/swagger', - swaggerUi.serveFiles(swaggerAdminDocument), - swaggerUi.setup(swaggerAdminDocument) - ); + if (process.env.STRIPE_ENABLED === 'true') { + this.express.use( + '/admin/swagger', + swaggerUi.serveFiles(swaggerAdminDocument), + swaggerUi.setup(swaggerAdminDocument) + ); + this.express.use(Middleware.setStripeClient) + } this.express.use(auth.handleError); this.express.use(async (req, res, next) => await auth.accessControl(req, res, next)); } @@ -222,46 +225,48 @@ class App { // Portal // Product - app.get('/admin/product/list', ProductController.productListValidator, new ProductController().listProducts); - app.get( - '/admin/product/get/:productId', - ProductController.productGetValidator, - new ProductController().getProduct - ); + if (process.env.STRIPE_ENABLED === 'true') { + app.get('/admin/product/list', ProductController.productListValidator, new ProductController().listProducts); + app.get( + '/admin/product/get/:productId', + ProductController.productGetValidator, + new ProductController().getProduct + ); - // Prices - app.get('/admin/price/list', PriceController.priceListValidator, new PriceController().getListPrices); + // Prices + app.get('/admin/price/list', PriceController.priceListValidator, new PriceController().getListPrices); - // Subscription - app.post( - '/admin/subscription/create', - SubscriptionController.subscriptionCreateValidator, - new SubscriptionController().create - ); - app.post( - '/admin/subscription/update', - SubscriptionController.subscriptionUpdateValidator, - new SubscriptionController().update - ); - app.get('/admin/subscription/get', new SubscriptionController().get); - app.get( - '/admin/subscription/list', - SubscriptionController.subscriptionListValidator, - new SubscriptionController().list - ); - app.delete( - '/admin/subscription/cancel', - SubscriptionController.subscriptionCancelValidator, - new SubscriptionController().cancel - ); - app.post( - '/admin/subscription/resume', - SubscriptionController.subscriptionResumeValidator, - new SubscriptionController().resume - ); + // Subscription + app.post( + '/admin/subscription/create', + SubscriptionController.subscriptionCreateValidator, + new SubscriptionController().create + ); + app.post( + '/admin/subscription/update', + SubscriptionController.subscriptionUpdateValidator, + new SubscriptionController().update + ); + app.get('/admin/subscription/get', new SubscriptionController().get); + app.get( + '/admin/subscription/list', + SubscriptionController.subscriptionListValidator, + new SubscriptionController().list + ); + app.delete( + '/admin/subscription/cancel', + SubscriptionController.subscriptionCancelValidator, + new SubscriptionController().cancel + ); + app.post( + '/admin/subscription/resume', + SubscriptionController.subscriptionResumeValidator, + new SubscriptionController().resume + ); - // Webhook - app.post('/admin/webhook', new WebhookController().handleWebhook); + // Webhook + app.post('/admin/webhook', new WebhookController().handleWebhook); + } // 404 for all other requests app.all('*', (_req, res) => res.status(StatusCodes.BAD_REQUEST).send('Bad request')); diff --git a/src/controllers/admin/prices.ts b/src/controllers/admin/prices.ts index e0569ad9..935b554d 100644 --- a/src/controllers/admin/prices.ts +++ b/src/controllers/admin/prices.ts @@ -1,4 +1,4 @@ -import { Stripe } from 'stripe'; +import type { Stripe } from 'stripe'; import type { Request, Response } from 'express'; import * as dotenv from 'dotenv'; import type { PriceListResponseBody, PriceListUnsuccessfulResponseBody } from '../../types/portal.js'; @@ -8,8 +8,6 @@ import { validate } from '../validator/decorator.js'; dotenv.config(); -const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); - export class PriceController { static priceListValidator = [ check('productId').optional().isString().withMessage('productId should be a string').bail(), @@ -48,6 +46,7 @@ export class PriceController { */ @validate async getListPrices(request: Request, response: Response) { + const stripe = response.locals.stripe as Stripe; // Get query parameters const productId = request.query.productId; diff --git a/src/controllers/admin/product.ts b/src/controllers/admin/product.ts index d28041f7..920695a0 100644 --- a/src/controllers/admin/product.ts +++ b/src/controllers/admin/product.ts @@ -1,4 +1,4 @@ -import { Stripe } from 'stripe'; +import type { Stripe } from 'stripe'; import type { Request, Response } from 'express'; import * as dotenv from 'dotenv'; import type { @@ -14,8 +14,6 @@ import { validate } from '../validator/decorator.js'; dotenv.config(); -const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); - export class ProductController { static productListValidator = [ check('prices').optional().isBoolean().withMessage('prices should be a boolean').bail(), @@ -59,6 +57,7 @@ export class ProductController { */ @validate async listProducts(request: Request, response: Response) { + const stripe = response.locals.stripe as Stripe; // Get query parameters const prices = request.query.prices === 'false' ? false : true; @@ -133,6 +132,7 @@ export class ProductController { */ @validate async getProduct(request: Request, response: Response) { + const stripe = response.locals.stripe as Stripe; // Get query parameters const prices = request.query.prices === 'false' ? false : true; const productId = request.params.productId as string; diff --git a/src/controllers/admin/subscriptions.ts b/src/controllers/admin/subscriptions.ts index ea0e6b54..f181b38e 100644 --- a/src/controllers/admin/subscriptions.ts +++ b/src/controllers/admin/subscriptions.ts @@ -1,4 +1,4 @@ -import Stripe from 'stripe'; +import type Stripe from 'stripe'; import type { Request, Response } from 'express'; import * as dotenv from 'dotenv'; import type { @@ -20,28 +20,25 @@ import type { SubscriptionCancelRequestBody, } from '../../types/portal.js'; import { StatusCodes } from 'http-status-codes'; -import { check, validationResult } from '../validator/index.js'; +import { check } from '../validator/index.js'; import { SubscriptionService } from '../../services/admin/subscription.js'; import { stripeService } from '../../services/admin/stripe.js'; -import { UnsuccessfulResponseBody } from '../../types/shared.js'; +import type { UnsuccessfulResponseBody } from '../../types/shared.js'; import { validate } from '../validator/decorator.js'; dotenv.config(); -const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); - export function stripeSync(target: any, key: string, descriptor: PropertyDescriptor | undefined) { - - // save a reference to the original method this way we keep the values currently in the - // descriptor and don't overwrite what another decorator might have done to the descriptor. - if(descriptor === undefined) { - descriptor = Object.getOwnPropertyDescriptor(target, key) as PropertyDescriptor; - } + // save a reference to the original method this way we keep the values currently in the + // descriptor and don't overwrite what another decorator might have done to the descriptor. + if (descriptor === undefined) { + descriptor = Object.getOwnPropertyDescriptor(target, key) as PropertyDescriptor; + } + + const originalMethod = descriptor.value; - const originalMethod = descriptor.value; - - //editing the descriptor/value parameter - descriptor.value = async function (...args: any[]) { + //editing the descriptor/value parameter + descriptor.value = async function (...args: any[]) { const response: Response = args[1]; if (response.locals.customer) { try { @@ -53,10 +50,10 @@ export function stripeSync(target: any, key: string, descriptor: PropertyDescrip } } return originalMethod.apply(this, args); - }; - - // return edited descriptor as opposed to overwriting the descriptor - return descriptor; + }; + + // return edited descriptor as opposed to overwriting the descriptor + return descriptor; } export class SubscriptionController { @@ -152,14 +149,7 @@ export class SubscriptionController { @validate async create(request: Request, response: Response) { - // Validate request - const result = validationResult(request); - // handle error - if (!result.isEmpty()) { - return response.status(StatusCodes.BAD_REQUEST).json({ - error: result.array().pop()?.msg, - } satisfies SubscriptionCreateUnsuccessfulResponseBody); - } + const stripe = response.locals.stripe as Stripe; const { price, successURL, cancelURL, quantity, idempotencyKey } = request.body satisfies SubscriptionCreateRequestBody; @@ -195,7 +185,7 @@ export class SubscriptionController { } return response.json({ - clientSecret: session.url as string, + sessionURL: session.url as string, } satisfies SubscriptionCreateResponseBody); } catch (error) { return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ @@ -234,9 +224,9 @@ export class SubscriptionController { @validate @stripeSync async update(request: Request, response: Response) { + const stripe = response.locals.stripe as Stripe; const { returnUrl } = request.body satisfies SubscriptionUpdateRequestBody; try { - // Get the subscription object from the DB const subscription = await SubscriptionService.instance.findOne({ customer: response.locals.customer }); if (!subscription) { @@ -257,7 +247,7 @@ export class SubscriptionController { } satisfies SubscriptionUpdateUnsuccessfulResponseBody); } return response.status(StatusCodes.OK).json({ - clientSecret: session.url, + sessionURL: session.url, } satisfies SubscriptionUpdateResponseBody); } catch (error) { return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ @@ -300,6 +290,7 @@ export class SubscriptionController { @validate @stripeSync public async list(request: Request, response: Response) { + const stripe = response.locals.stripe as Stripe; const stripeCustomerId = response.locals.customer.stripeCustomerId; try { // Get the subscriptions @@ -351,11 +342,12 @@ export class SubscriptionController { @validate @stripeSync async get(request: Request, response: Response) { + const stripe = response.locals.stripe as Stripe; try { // Get the subscriptionId from the request - const _sub = await SubscriptionService.instance.findOne({ + const _sub = await SubscriptionService.instance.findOne({ customer: response.locals.customer, - status: 'active' + status: 'active', }); if (!_sub) { return response.status(StatusCodes.NOT_FOUND).json({ @@ -410,6 +402,7 @@ export class SubscriptionController { @validate @stripeSync async cancel(request: Request, response: Response) { + const stripe = response.locals.stripe as Stripe; const { subscriptionId, idempotencyKey } = request.body satisfies SubscriptionCancelRequestBody; try { @@ -466,13 +459,7 @@ export class SubscriptionController { @validate @stripeSync async resume(request: Request, response: Response) { - // Validate request - const result = validationResult(request); - if (!result.isEmpty()) { - return response.status(StatusCodes.BAD_REQUEST).json({ - error: result.array().pop()?.msg, - } satisfies SubscriptionResumeUnsuccessfulResponseBody); - } + const stripe = response.locals.stripe as Stripe; const { subscriptionId, idempotencyKey } = request.body satisfies SubscriptionResumeRequestBody; try { // Resume the subscription diff --git a/src/controllers/admin/webhook.ts b/src/controllers/admin/webhook.ts index 42421bd9..c105c924 100644 --- a/src/controllers/admin/webhook.ts +++ b/src/controllers/admin/webhook.ts @@ -5,11 +5,9 @@ import { StatusCodes } from 'http-status-codes'; import { EventTracker, eventTracker } from '../../services/track/tracker.js'; import type { INotifyMessage } from '../../types/track.js'; import { OperationNameEnum } from '../../types/constants.js'; -import type { ISubmitOperation, ISubmitData } from '../../services/track/submitter.js'; +import { builSubmitOperation } from '../../services/track/helpers.js'; dotenv.config(); - -const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); export class WebhookController { public async handleWebhook(request: Request, response: Response) { // Signature verification and webhook handling is placed in the same method @@ -17,20 +15,7 @@ export class WebhookController { let event = request.body; let subscription; let status; - const builSubmitOperation = function (subscription: Stripe.Subscription, name: string) { - return { - operation: name, - data: { - subscriptionId: subscription.id, - stripeCustomerId: subscription.customer as string, - status: subscription.status, - currentPeriodStart: new Date(subscription.current_period_start * 1000), - currentPeriodEnd: new Date(subscription.current_period_end * 1000), - trialStart: subscription.trial_start ? new Date(subscription.trial_start * 1000) : undefined, - trialEnd: subscription.trial_end ? new Date(subscription.trial_end * 1000) : undefined, - } satisfies ISubmitData, - } satisfies ISubmitOperation; - }; + const stripe = new Stripe(process.env.STRIPE_SECRET_KEY) if (!process.env.STRIPE_WEBHOOK_SECRET) { await eventTracker.notify({ diff --git a/src/controllers/validator/decorator.ts b/src/controllers/validator/decorator.ts index 1bb3673b..2657d46c 100644 --- a/src/controllers/validator/decorator.ts +++ b/src/controllers/validator/decorator.ts @@ -1,22 +1,20 @@ - import type { ValidationErrorResponseBody } from '../../types/shared.js'; -import { Request, Response } from 'express'; +import type { Request, Response } from 'express'; import { validationResult } from './index.js'; import { StatusCodes } from 'http-status-codes'; export function validate(target: any, key: string, descriptor: PropertyDescriptor | undefined) { - - // save a reference to the original method this way we keep the values currently in the - // descriptor and don't overwrite what another decorator might have done to the descriptor. - if(descriptor === undefined) { - descriptor = Object.getOwnPropertyDescriptor(target, key) as PropertyDescriptor; - } + // save a reference to the original method this way we keep the values currently in the + // descriptor and don't overwrite what another decorator might have done to the descriptor. + if (descriptor === undefined) { + descriptor = Object.getOwnPropertyDescriptor(target, key) as PropertyDescriptor; + } + + const originalMethod = descriptor.value; - const originalMethod = descriptor.value; - - //editing the descriptor/value parameter - descriptor.value = async function (...args: any[]) { - const request: Request = args[0]; + //editing the descriptor/value parameter + descriptor.value = async function (...args: any[]) { + const request: Request = args[0]; const response: Response = args[1]; const result = validationResult(request); if (!result.isEmpty()) { @@ -25,8 +23,8 @@ export function validate(target: any, key: string, descriptor: PropertyDescripto } satisfies ValidationErrorResponseBody); } return originalMethod.apply(this, args); - }; - - // return edited descriptor as opposed to overwriting the descriptor - return descriptor; -} \ No newline at end of file + }; + + // return edited descriptor as opposed to overwriting the descriptor + return descriptor; +} diff --git a/src/middleware/middleware.ts b/src/middleware/middleware.ts index 7ebade0d..a797e8ec 100644 --- a/src/middleware/middleware.ts +++ b/src/middleware/middleware.ts @@ -1,4 +1,7 @@ import type { Request, Response, NextFunction } from 'express'; +import Stripe from 'stripe'; +import * as dotenv from 'dotenv'; +dotenv.config(); export class Middleware { static async parseUrlEncodedJson(request: Request, response: Response, next: NextFunction) { @@ -23,4 +26,11 @@ export class Middleware { } next(); } + + static async setStripeClient(request: Request, response: Response, next: NextFunction) { + // Set the Stripe client + const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); + response.locals.stripe = stripe; + next(); + } } diff --git a/src/services/admin/stripe.ts b/src/services/admin/stripe.ts index 8db2e3c6..257dba67 100644 --- a/src/services/admin/stripe.ts +++ b/src/services/admin/stripe.ts @@ -3,162 +3,81 @@ import * as dotenv from 'dotenv'; import { SubscriptionService } from './subscription.js'; import type { CustomerEntity } from '../../database/entities/customer.entity.js'; import { EventTracker, eventTracker } from '../track/tracker.js'; -import { CustomerService } from '../api/customer.js'; import type { SubscriptionEntity } from '../../database/entities/subscription.entity.js'; +import { builSubmitOperation } from '../track/helpers.js'; +import { OperationNameEnum } from '../../types/constants.js'; +import { SubscriptionSubmitter } from '../track/admin/subscription-submitter.js'; dotenv.config(); -const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); - export class StripeService { - private stripeToCustomer: Map = new Map(); - - async syncFull(): Promise { - // Set all customers - await this.setStripeCustomers(); - // Sync all subscriptions - for await (const subscription of stripe.subscriptions.list()) { - const current = await SubscriptionService.instance.subscriptionRepository.findOne({ - where: { subscriptionId: subscription.id } - }) - if (current) { - await this.updateSubscription(subscription, current); - } - else { - await this.createSubscription(subscription); - } - } - eventTracker.notify({ - message: EventTracker.compileBasicNotification( - `Subscription syncronization completed`, - 'Subscription syncronization' - ), - severity: 'info', - }) - } - - // Sync all the subscriptions for current customer - async syncCustomer(customer: CustomerEntity): Promise { - for await (const subscription of stripe.subscriptions.list({ - customer: customer.stripeCustomerId, - status: 'all' - })) { - const current = await SubscriptionService.instance.subscriptionRepository.findOne({ - where: { subscriptionId: subscription.id } - }) - if (current) { - await this.updateSubscription(subscription, current); - } - else { - await this.createSubscription(subscription, customer); - } - } - } - - async setStripeCustomers(): Promise { - const customers = await CustomerService.instance.customerRepository.createQueryBuilder('customer') - .select('customer.customerId', 'customer.stripeCustomerId') - .where('customer.stripeCustomerId IS NOT NULL') - .getMany(); - customers.forEach((customer) => { - this.stripeToCustomer.set(customer.stripeCustomerId, customer); - }); - } + submitter: SubscriptionSubmitter; - async isExists(subscriptionId: string): Promise { - const subscriptionEntity = await SubscriptionService.instance.subscriptionRepository.findOne({ - where: { subscriptionId } - }); - return !!subscriptionEntity; + constructor() { + this.submitter = new SubscriptionSubmitter(eventTracker.getEmitter()); } - async createSubscription(subscription: Stripe.Subscription, customerEntity?: CustomerEntity): Promise { - const customer = customerEntity - ? customerEntity - : this.stripeToCustomer.get(subscription.customer as string); + async syncFull(): Promise { + const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); + // Sync all subscriptions + for await (const subscription of stripe.subscriptions.list({ + status: 'all', + })) { + const current = await SubscriptionService.instance.subscriptionRepository.findOne({ + where: { subscriptionId: subscription.id }, + }); + if (current) { + await this.updateSubscription(subscription, current); + } else { + await this.createSubscription(subscription); + } + } + eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `Subscription syncronization completed`, + 'Subscription syncronization' + ), + severity: 'info', + }); + } - if (!customer) { - eventTracker.notify({ - message: EventTracker.compileBasicNotification( - `Cannot find a customer for subscription with id ${subscription.id}`, - 'Subscription syncronization' - ), - severity: 'error', - }); - return; - } - // Create a new subscription in the database - const subscriptionEntity = SubscriptionService.instance.create( - subscription.id, - customer, - subscription.status, - new Date(subscription.current_period_start * 1000), - new Date(subscription.current_period_end * 1000), - subscription.trial_start ? new Date(subscription.trial_start * 1000) : undefined, - subscription.trial_end ? new Date(subscription.trial_end * 1000) : undefined - ); + // Sync all the subscriptions for current customer + async syncCustomer(customer: CustomerEntity): Promise { + const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); + for await (const subscription of stripe.subscriptions.list({ + customer: customer.stripeCustomerId, + status: 'all', + })) { + const current = await SubscriptionService.instance.subscriptionRepository.findOne({ + where: { subscriptionId: subscription.id }, + }); + if (current) { + await this.updateSubscription(subscription, current); + } else { + await this.createSubscription(subscription, customer); + } + } + } - // Track the event - if (!subscriptionEntity) { - eventTracker.notify({ - message: EventTracker.compileBasicNotification( - `Cannot create a new subscription with id ${subscription.id}`, - 'Subscription syncronization' - ), - severity: 'error', - }); - } - eventTracker.notify({ - message: EventTracker.compileBasicNotification( - `New subscription with id ${subscription.id} created`, - 'Subscription syncronization' - ), - severity: 'info', - }); - } + async createSubscription(subscription: Stripe.Subscription, customer?: CustomerEntity): Promise { + await this.submitter.submitSubscriptionCreate(builSubmitOperation(subscription, OperationNameEnum.SUBSCRIPTION_CREATE, {customer: customer})); + } - async updateSubscription(subscription: Stripe.Subscription, current: SubscriptionEntity): Promise { - // Update only if there are changes - if (SubscriptionService.instance.equals(current, subscription)) { - eventTracker.notify({ - message: EventTracker.compileBasicNotification( - `Subscription with id ${subscription.id} has no changes`, - 'Subscription syncronization' - ), - severity: 'debug', - }) - return - } - - // Update subscription in the database - const subscriptionEntity = SubscriptionService.instance.update( - subscription.id, - subscription.status, - new Date(subscription.current_period_start * 1000), - new Date(subscription.current_period_end * 1000), - subscription.trial_start ? new Date(subscription.trial_start * 1000) : undefined, - subscription.trial_end ? new Date(subscription.trial_end * 1000) : undefined - ); - - // Track the event - if (!subscriptionEntity) { - eventTracker.notify({ - message: EventTracker.compileBasicNotification( - `Cannot update subscription with id ${subscription.id}`, - 'Subscription syncronization' - ), - severity: 'error', - }); - } - eventTracker.notify({ - message: EventTracker.compileBasicNotification( - `Subscription with id ${subscription.id} updated`, - 'Subscription syncronization' - ), - severity: 'info', - }); - } + async updateSubscription(subscription: Stripe.Subscription, current: SubscriptionEntity): Promise { + // Update only if there are changes + if (SubscriptionService.instance.equals(current, subscription)) { + eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `Subscription with id ${subscription.id} has no changes`, + 'Subscription syncronization' + ), + severity: 'debug', + }); + return; + } + await this.submitter.submitSubscriptionUpdate(builSubmitOperation(subscription, OperationNameEnum.SUBSCRIPTION_UPDATE)); + } } -export const stripeService = new StripeService(); \ No newline at end of file +export const stripeService = new StripeService(); diff --git a/src/services/admin/subscription.ts b/src/services/admin/subscription.ts index 07cb2142..7219c7a6 100644 --- a/src/services/admin/subscription.ts +++ b/src/services/admin/subscription.ts @@ -82,7 +82,10 @@ export class SubscriptionService { if (!required) return false; // Check trial dates only if they are present in the subscription if (subscription.trial_start) { - if (!subscriptionEntity.trialStart || subscriptionEntity.trialStart.getTime() !== subscription.trial_start * 1000) + if ( + !subscriptionEntity.trialStart || + subscriptionEntity.trialStart.getTime() !== subscription.trial_start * 1000 + ) return false; } if (subscription.trial_end) { diff --git a/src/services/track/admin/account-submitter.ts b/src/services/track/admin/account-submitter.ts index 29d7f5f3..de5346fa 100644 --- a/src/services/track/admin/account-submitter.ts +++ b/src/services/track/admin/account-submitter.ts @@ -9,11 +9,9 @@ import type { ISubmitOperation, ISubmitStripeCustomerCreateData } from '../submi export class PortalAccountCreateSubmitter implements IObserver { private emitter: EventEmitter; - private stripe: Stripe; constructor(emitter: EventEmitter) { this.emitter = emitter; - this.stripe = new Stripe(process.env.STRIPE_SECRET_KEY); } notify(notifyMessage: INotifyMessage): void { @@ -28,10 +26,11 @@ export class PortalAccountCreateSubmitter implements IObserver { async submitStripeAccountCreate(operation: ISubmitOperation): Promise { const data = operation.data as ISubmitStripeCustomerCreateData; + const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); try { // Create a new Stripe account - const account = await this.stripe.customers.create({ + const account = await stripe.customers.create({ name: data.name, email: data.email, }); diff --git a/src/services/track/admin/subscription-submitter.ts b/src/services/track/admin/subscription-submitter.ts index ccfbaf9d..8dfcc30f 100644 --- a/src/services/track/admin/subscription-submitter.ts +++ b/src/services/track/admin/subscription-submitter.ts @@ -1,38 +1,12 @@ +import type { CustomerEntity } from '../../../database/entities/customer.entity.js'; import { OperationNameEnum } from '../../../types/constants.js'; import type { INotifyMessage } from '../../../types/track.js'; import { SubscriptionService } from '../../admin/subscription.js'; import { CustomerService } from '../../api/customer.js'; import type { ISubmitOperation, ISubmitSubscriptionData } from '../submitter.js'; -import { EventTracker, eventTracker } from '../tracker.js'; +import { EventTracker } from '../tracker.js'; import type { IObserver } from '../types.js'; -//eslint-disable-next-line - -function isPromise(object: any): object is Promise { - return object && Promise.resolve(object) === object; -} - -export const eventDecorator = () => { - return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => { - const { value } = descriptor; - //eslint-disable-next-line - descriptor.value = async (...args: any) => { - try { - const response = value.apply(target, args); - return isPromise(response) ? await response : Promise.resolve(response); - } catch (error) { - eventTracker.notify({ - message: EventTracker.compileBasicNotification( - `Error while calling function: ${propertyKey}: ${(error as Record)?.message || error}` - ), - severity: 'error', - } satisfies INotifyMessage); - } - }; - return descriptor; - }; -}; - export class SubscriptionSubmitter implements IObserver { private emitter: EventEmitter; @@ -60,26 +34,30 @@ export class SubscriptionSubmitter implements IObserver { } } - // @eventDecorator() async submitSubscriptionCreate(operation: ISubmitOperation): Promise { const data = operation.data as ISubmitSubscriptionData; + let customer: CustomerEntity | undefined = operation.options?.customer; try { - const customers = await CustomerService.instance.find({ - stripeCustomerId: data.stripeCustomerId, - }); - - if (customers.length !== 1) { - this.notify({ - message: EventTracker.compileBasicNotification( - `It should be only 1 Stripe account associated with CaaS customer. Stripe accountId: ${data.stripeCustomerId}.`, - operation.operation - ), - severity: 'error', + if (!customer) { + const customers = await CustomerService.instance.find({ + stripeCustomerId: data.stripeCustomerId, }); + + if (customers.length !== 1) { + this.notify({ + message: EventTracker.compileBasicNotification( + `It should be only 1 Stripe account associated with CaaS customer. Stripe accountId: ${data.stripeCustomerId}.`, + operation.operation + ), + severity: 'error', + }); + } + customer = customers[0]; } + const subscription = await SubscriptionService.instance.create( data.subscriptionId, - customers[0], + customer, data.status, data.currentPeriodStart, data.currentPeriodEnd, @@ -114,7 +92,6 @@ export class SubscriptionSubmitter implements IObserver { } } - // @eventDecorator() async submitSubscriptionUpdate(operation: ISubmitOperation): Promise { const data = operation.data as ISubmitSubscriptionData; try { @@ -154,7 +131,6 @@ export class SubscriptionSubmitter implements IObserver { } } - // @eventDecorator() async submitSubscriptionCancel(operation: ISubmitOperation): Promise { const data = operation.data as ISubmitSubscriptionData; try { diff --git a/src/services/track/helpers.ts b/src/services/track/helpers.ts index 1b720b9b..192c4259 100644 --- a/src/services/track/helpers.ts +++ b/src/services/track/helpers.ts @@ -7,6 +7,9 @@ import type { ICredentialTrack, IDIDTrack, } from '../../types/track.js'; +import type Stripe from 'stripe'; +import type { ISubmitData, ISubmitOperation } from './submitter.js'; +import type { ISubmitOptions } from './types.js'; export function isResourceTrack(data: TrackData): data is IResourceTrack { return Object.keys(data).length === 2 && (data as IResourceTrack).resource !== undefined; @@ -31,3 +34,19 @@ export function isDIDTrack(data: TrackData): data is IDIDTrack { export function toCoin(amount: bigint, denom = MINIMAL_DENOM): Coin { return coin(amount.toString(), denom); } + +export function builSubmitOperation (subscription: Stripe.Subscription, name: string, options?: ISubmitOptions) { + return { + operation: name, + data: { + subscriptionId: subscription.id, + stripeCustomerId: subscription.customer as string, + status: subscription.status, + currentPeriodStart: new Date(subscription.current_period_start * 1000), + currentPeriodEnd: new Date(subscription.current_period_end * 1000), + trialStart: subscription.trial_start ? new Date(subscription.trial_start * 1000) : undefined, + trialEnd: subscription.trial_end ? new Date(subscription.trial_end * 1000) : undefined, + } satisfies ISubmitData, + options, + } satisfies ISubmitOperation; +}; diff --git a/src/services/track/submitter.ts b/src/services/track/submitter.ts index 89beb23b..acaf1c81 100644 --- a/src/services/track/submitter.ts +++ b/src/services/track/submitter.ts @@ -1,3 +1,5 @@ +import type { ISubmitOptions } from "./types"; + // Type: Interface export type ISubmitData = ISubmitStripeCustomerCreateData | ISubmitSubscriptionData; @@ -20,4 +22,5 @@ export interface ISubmitSubscriptionData { export interface ISubmitOperation { operation: string; data: ISubmitData; + options?: ISubmitOptions; } diff --git a/src/services/track/types.ts b/src/services/track/types.ts index 9f84a847..2b61b251 100644 --- a/src/services/track/types.ts +++ b/src/services/track/types.ts @@ -1,3 +1,4 @@ +import type { CustomerEntity } from '../../database/entities/customer.entity'; import type { ITrackOperation, INotifyMessage } from '../../types/track'; import type { ISubmitOperation } from './submitter'; @@ -17,3 +18,7 @@ export interface ITrackSubject { // Notify all observers about an event. notify(operation: ITrackType): void; } + +export interface ISubmitOptions { + customer?: CustomerEntity; +} diff --git a/src/static/swagger-admin.json b/src/static/swagger-admin.json index cb9b28ea..7f52ed7c 100644 --- a/src/static/swagger-admin.json +++ b/src/static/swagger-admin.json @@ -258,6 +258,16 @@ "tags": [ "Subscription" ], + "parameters": [ + { + "in": "query", + "name": "stripeCustomerId", + "schema": { + "type": "string", + "description": "The customer id. If passed - returns filtered by this customer list of subscriptions." + } + } + ], "responses": { "200": { "description": "A list of subscriptions", @@ -496,7 +506,7 @@ "type": "object", "description": "An object with link to checkout session. For more information see the [Stripe API documentation](https://docs.stripe.com/api/checkout/sessions/object)", "properties": { - "url": { + "sessionURL": { "type": "string", "description": "URL which user should follow to manage subscription" } @@ -522,7 +532,7 @@ "type": "object", "description": "Object with redirect url inside", "properties": { - "clientSecret": { + "sessionURL": { "type": "string", "description": "URL with session URL rediect to" } diff --git a/src/types/environment.d.ts b/src/types/environment.d.ts index d114b94e..abd5ffae 100644 --- a/src/types/environment.d.ts +++ b/src/types/environment.d.ts @@ -58,6 +58,7 @@ declare global { CREDS_DECRYPTION_SECRET: string; // Stripe + STRIPE_ENABLED: string | 'false'; STRIPE_SECRET_KEY: string; STRIPE_PUBLISHABLE_KEY: string; STRIPE_WEBHOOK_SECRET: string; diff --git a/src/types/portal.ts b/src/types/portal.ts index 32d2efd3..b528c710 100644 --- a/src/types/portal.ts +++ b/src/types/portal.ts @@ -34,11 +34,11 @@ export type SubscriptionCreateRequestBody = { }; export type SubscriptionCreateResponseBody = { - clientSecret: Stripe.Checkout.Session['client_secret']; + sessionURL: Stripe.Checkout.Session['client_secret']; }; export type SubscriptionUpdateResponseBody = { - clientSecret: string; + sessionURL: string; }; // Update diff --git a/src/types/swagger-admin-types.ts b/src/types/swagger-admin-types.ts index 03ab7225..4acce51c 100644 --- a/src/types/swagger-admin-types.ts +++ b/src/types/swagger-admin-types.ts @@ -72,7 +72,7 @@ * type: object * description: An object with link to checkout session. For more information see the [Stripe API documentation](https://docs.stripe.com/api/checkout/sessions/object) * properties: - * url: + * sessionURL: * type: string * description: URL which user should follow to manage subscription * SubscriptionUpdateRequestBody: @@ -90,7 +90,7 @@ * type: object * description: Object with redirect url inside * properties: - * clientSecret: + * sessionURL: * type: string * description: URL with session URL rediect to * SubscriptionGetRequestBody: From ab0da5bbca6b3bca4c8eb10ee13a7700ad42e65f Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Sun, 24 Mar 2024 16:50:07 +0100 Subject: [PATCH 15/40] Add trial period days to subscription creation --- src/app.ts | 3 ++ src/controllers/admin/subscriptions.ts | 47 ++++++++++++++++++++---- src/services/admin/stripe.ts | 49 ++++++++++++++++++++++++++ src/types/portal.ts | 1 + src/types/swagger-admin-types.ts | 8 +++++ 5 files changed, 101 insertions(+), 7 deletions(-) diff --git a/src/app.ts b/src/app.ts index c6043c99..69b070b8 100644 --- a/src/app.ts +++ b/src/app.ts @@ -31,6 +31,7 @@ import { ProductController } from './controllers/admin/product.js'; import { SubscriptionController } from './controllers/admin/subscriptions.js'; import { PriceController } from './controllers/admin/prices.js'; import { WebhookController } from './controllers/admin/webhook.js'; +import { stripeService } from './services/admin/stripe.js'; let swaggerOptions = {}; if (process.env.ENABLE_AUTHENTICATION === 'true') { @@ -113,6 +114,8 @@ class App { swaggerUi.setup(swaggerAdminDocument) ); this.express.use(Middleware.setStripeClient) + // ToDo: move it to Setup phase. + this.express.use(async (_req, _res, next) => await stripeService.syncAll(next)) } this.express.use(auth.handleError); this.express.use(async (req, res, next) => await auth.accessControl(req, res, next)); diff --git a/src/controllers/admin/subscriptions.ts b/src/controllers/admin/subscriptions.ts index f181b38e..fde4d082 100644 --- a/src/controllers/admin/subscriptions.ts +++ b/src/controllers/admin/subscriptions.ts @@ -28,7 +28,7 @@ import { validate } from '../validator/decorator.js'; dotenv.config(); -export function stripeSync(target: any, key: string, descriptor: PropertyDescriptor | undefined) { +export function syncCustomer(target: any, key: string, descriptor: PropertyDescriptor | undefined) { // save a reference to the original method this way we keep the values currently in the // descriptor and don't overwrite what another decorator might have done to the descriptor. if (descriptor === undefined) { @@ -56,6 +56,35 @@ export function stripeSync(target: any, key: string, descriptor: PropertyDescrip return descriptor; } +export function syncOne(target: any, key: string, descriptor: PropertyDescriptor | undefined) { + // save a reference to the original method this way we keep the values currently in the + // descriptor and don't overwrite what another decorator might have done to the descriptor. + if (descriptor === undefined) { + descriptor = Object.getOwnPropertyDescriptor(target, key) as PropertyDescriptor; + } + + const originalMethod = descriptor.value; + + //editing the descriptor/value parameter + descriptor.value = async function (...args: any[]) { + const response: Response = args[1]; + if (response.locals.customer) { + try { + await stripeService.syncOne(response.locals.customer); + } catch (error) { + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: `Internal error: ${(error as Error)?.message || error}`, + } satisfies UnsuccessfulResponseBody); + } + } + return originalMethod.apply(this, args); + }; + + // return edited descriptor as opposed to overwriting the descriptor + return descriptor; +} + + export class SubscriptionController { static subscriptionCreateValidator = [ check('price') @@ -80,6 +109,7 @@ export class SubscriptionController { .withMessage('cancelURL should be a string') .bail(), check('quantity').optional().isInt().withMessage('quantity should be an integer').bail(), + check('trialPeriodDays').optional().isInt().withMessage('trialPeriodDays should be an integer').bail(), check('idempotencyKey').optional().isString().withMessage('idempotencyKey should be a string').bail(), ]; @@ -151,7 +181,7 @@ export class SubscriptionController { async create(request: Request, response: Response) { const stripe = response.locals.stripe as Stripe; - const { price, successURL, cancelURL, quantity, idempotencyKey } = + const { price, successURL, cancelURL, quantity, idempotencyKey, trialPeriodDays } = request.body satisfies SubscriptionCreateRequestBody; try { const session = await stripe.checkout.sessions.create( @@ -166,6 +196,9 @@ export class SubscriptionController { ], success_url: successURL, cancel_url: cancelURL, + subscription_data: { + trial_period_days: trialPeriodDays, + } }, { idempotencyKey, @@ -222,7 +255,7 @@ export class SubscriptionController { * $ref: '#/components/schemas/InternalError' */ @validate - @stripeSync + @syncOne async update(request: Request, response: Response) { const stripe = response.locals.stripe as Stripe; const { returnUrl } = request.body satisfies SubscriptionUpdateRequestBody; @@ -288,7 +321,7 @@ export class SubscriptionController { */ @validate - @stripeSync + @syncCustomer public async list(request: Request, response: Response) { const stripe = response.locals.stripe as Stripe; const stripeCustomerId = response.locals.customer.stripeCustomerId; @@ -340,7 +373,7 @@ export class SubscriptionController { * $ref: '#/components/schemas/NotFoundError' */ @validate - @stripeSync + @syncOne async get(request: Request, response: Response) { const stripe = response.locals.stripe as Stripe; try { @@ -400,7 +433,7 @@ export class SubscriptionController { * $ref: '#/components/schemas/NotFoundError' */ @validate - @stripeSync + @syncOne async cancel(request: Request, response: Response) { const stripe = response.locals.stripe as Stripe; const { subscriptionId, idempotencyKey } = request.body satisfies SubscriptionCancelRequestBody; @@ -457,7 +490,7 @@ export class SubscriptionController { * $ref: '#/components/schemas/NotFoundError' */ @validate - @stripeSync + @syncOne async resume(request: Request, response: Response) { const stripe = response.locals.stripe as Stripe; const { subscriptionId, idempotencyKey } = request.body satisfies SubscriptionResumeRequestBody; diff --git a/src/services/admin/stripe.ts b/src/services/admin/stripe.ts index 257dba67..1c3613b1 100644 --- a/src/services/admin/stripe.ts +++ b/src/services/admin/stripe.ts @@ -7,17 +7,27 @@ import type { SubscriptionEntity } from '../../database/entities/subscription.en import { builSubmitOperation } from '../track/helpers.js'; import { OperationNameEnum } from '../../types/constants.js'; import { SubscriptionSubmitter } from '../track/admin/subscription-submitter.js'; +import type { NextFunction } from 'express'; dotenv.config(); export class StripeService { submitter: SubscriptionSubmitter; + private isFullySynced = false; constructor() { this.submitter = new SubscriptionSubmitter(eventTracker.getEmitter()); } + async syncAll(next: NextFunction): Promise { + if (!this.isFullySynced) { + await this.syncFull(); + this.isFullySynced = true; + } + next() + } + async syncFull(): Promise { const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); // Sync all subscriptions @@ -60,6 +70,45 @@ export class StripeService { } } + async syncOne(customer: CustomerEntity): Promise { + const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); + + const local = await SubscriptionService.instance.findOne({ + customer: customer, + status: 'active', + }); + if (!local) { + eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `Active subscription not found for customer with id ${customer.customerId}`, + 'Subscription syncronization' + ), + severity: 'debug', + }); + return; + } + const subscriptionId = local.subscriptionId; + const remote = await stripe.subscriptions.retrieve(subscriptionId); + if (!remote) { + eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `Subscription with id ${subscriptionId} could not be retrieved from Stripe`, + 'Subscription syncronization' + ), + severity: 'error', + }); + return; + } + const current = await SubscriptionService.instance.subscriptionRepository.findOne({ + where: { subscriptionId: remote.id }, + }); + if (current) { + await this.updateSubscription(remote, current); + } else { + await this.createSubscription(remote); + } + } + async createSubscription(subscription: Stripe.Subscription, customer?: CustomerEntity): Promise { await this.submitter.submitSubscriptionCreate(builSubmitOperation(subscription, OperationNameEnum.SUBSCRIPTION_CREATE, {customer: customer})); } diff --git a/src/types/portal.ts b/src/types/portal.ts index b528c710..2e4fcaa7 100644 --- a/src/types/portal.ts +++ b/src/types/portal.ts @@ -30,6 +30,7 @@ export type SubscriptionCreateRequestBody = { successURL: string; cancelURL: string; quantity?: number; + trialPeriodDays?: number; idempotencyKey?: string; }; diff --git a/src/types/swagger-admin-types.ts b/src/types/swagger-admin-types.ts index 4acce51c..33249863 100644 --- a/src/types/swagger-admin-types.ts +++ b/src/types/swagger-admin-types.ts @@ -60,6 +60,14 @@ * type: string * description: The URL to redirect to after the customer cancels the checkout * example: https://example.com/cancel + * quantity: + * type: number + * description: The quantity of the product + * example: 1 + * trialPeriodDays: + * type: number + * description: The number of days the customer has to pay for the product + * example: 7 * idempotencyKey: * type: string * description: The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request. From 71f60d32f175379773f45f57891a483df7812e81 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Mon, 25 Mar 2024 14:22:43 +0100 Subject: [PATCH 16/40] Get also trilaing subsriptions --- src/controllers/admin/subscriptions.ts | 17 +++++++++++------ src/services/admin/stripe.ts | 13 +++++++++---- src/services/admin/subscription.ts | 2 +- src/static/swagger-admin.json | 10 ++++++++++ 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/controllers/admin/subscriptions.ts b/src/controllers/admin/subscriptions.ts index fde4d082..777edc1e 100644 --- a/src/controllers/admin/subscriptions.ts +++ b/src/controllers/admin/subscriptions.ts @@ -261,7 +261,7 @@ export class SubscriptionController { const { returnUrl } = request.body satisfies SubscriptionUpdateRequestBody; try { // Get the subscription object from the DB - const subscription = await SubscriptionService.instance.findOne({ customer: response.locals.customer }); + const subscription = await SubscriptionService.instance.findOne([{ customer: response.locals.customer }]); if (!subscription) { return response.status(StatusCodes.NOT_FOUND).json({ error: `Subscription was not found`, @@ -373,15 +373,20 @@ export class SubscriptionController { * $ref: '#/components/schemas/NotFoundError' */ @validate - @syncOne + @syncCustomer async get(request: Request, response: Response) { const stripe = response.locals.stripe as Stripe; try { // Get the subscriptionId from the request - const _sub = await SubscriptionService.instance.findOne({ - customer: response.locals.customer, - status: 'active', - }); + const _sub = await SubscriptionService.instance.findOne([ + { + customer: response.locals.customer, + status: 'active'}, + { + customer: response.locals.customer, + status: 'trialing' + } + ]); if (!_sub) { return response.status(StatusCodes.NOT_FOUND).json({ error: `Subscription was not found`, diff --git a/src/services/admin/stripe.ts b/src/services/admin/stripe.ts index 1c3613b1..5e94cab4 100644 --- a/src/services/admin/stripe.ts +++ b/src/services/admin/stripe.ts @@ -73,10 +73,15 @@ export class StripeService { async syncOne(customer: CustomerEntity): Promise { const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); - const local = await SubscriptionService.instance.findOne({ - customer: customer, - status: 'active', - }); + const local = await SubscriptionService.instance.findOne([ + { + customer: customer, + status: 'active'}, + { + customer: customer, + status: 'trialing' + } + ]); if (!local) { eventTracker.notify({ message: EventTracker.compileBasicNotification( diff --git a/src/services/admin/subscription.ts b/src/services/admin/subscription.ts index 7219c7a6..9ef45843 100644 --- a/src/services/admin/subscription.ts +++ b/src/services/admin/subscription.ts @@ -66,7 +66,7 @@ export class SubscriptionService { }); } - public async findOne(where: Record) { + public async findOne(where: Array>) { return await this.subscriptionRepository.findOne({ where: where, relations: ['customer'], diff --git a/src/static/swagger-admin.json b/src/static/swagger-admin.json index 7f52ed7c..b5717e54 100644 --- a/src/static/swagger-admin.json +++ b/src/static/swagger-admin.json @@ -491,6 +491,16 @@ "description": "The URL to redirect to after the customer cancels the checkout", "example": "https://example.com/cancel" }, + "quantity": { + "type": "number", + "description": "The quantity of the product", + "example": 1 + }, + "trialPeriodDays": { + "type": "number", + "description": "The number of days the customer has to pay for the product", + "example": 7 + }, "idempotencyKey": { "type": "string", "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", From 042174bb320dea3fe776f17f8bb2f4b49ea26b82 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Mon, 25 Mar 2024 17:02:54 +0100 Subject: [PATCH 17/40] Get rd of Stripe naming --- src/app.ts | 3 -- src/controllers/admin/subscriptions.ts | 28 ++++++--------- src/controllers/api/account.ts | 2 +- src/database/entities/customer.entity.ts | 2 +- src/database/migrations/AlterCustomerTable.ts | 2 +- src/database/types/types.ts | 2 +- src/services/admin/stripe.ts | 34 +++++++++++++------ src/services/admin/subscription.ts | 9 ++++- src/services/api/customer.ts | 10 +++--- .../track/admin/subscription-submitter.ts | 4 +-- src/services/track/helpers.ts | 2 +- src/services/track/submitter.ts | 2 +- 12 files changed, 55 insertions(+), 45 deletions(-) diff --git a/src/app.ts b/src/app.ts index 69b070b8..c6043c99 100644 --- a/src/app.ts +++ b/src/app.ts @@ -31,7 +31,6 @@ import { ProductController } from './controllers/admin/product.js'; import { SubscriptionController } from './controllers/admin/subscriptions.js'; import { PriceController } from './controllers/admin/prices.js'; import { WebhookController } from './controllers/admin/webhook.js'; -import { stripeService } from './services/admin/stripe.js'; let swaggerOptions = {}; if (process.env.ENABLE_AUTHENTICATION === 'true') { @@ -114,8 +113,6 @@ class App { swaggerUi.setup(swaggerAdminDocument) ); this.express.use(Middleware.setStripeClient) - // ToDo: move it to Setup phase. - this.express.use(async (_req, _res, next) => await stripeService.syncAll(next)) } this.express.use(auth.handleError); this.express.use(async (req, res, next) => await auth.accessControl(req, res, next)); diff --git a/src/controllers/admin/subscriptions.ts b/src/controllers/admin/subscriptions.ts index 777edc1e..e64346ac 100644 --- a/src/controllers/admin/subscriptions.ts +++ b/src/controllers/admin/subscriptions.ts @@ -124,7 +124,7 @@ export class SubscriptionController { ]; static subscriptionListValidator = [ - check('stripeCustomerId').optional().isString().withMessage('customerId should be a string').bail(), + check('paymentProviderId').optional().isString().withMessage('customerId should be a string').bail(), ]; static subscriptionCancelValidator = [ @@ -187,7 +187,7 @@ export class SubscriptionController { const session = await stripe.checkout.sessions.create( { mode: 'subscription', - customer: response.locals.customer.stripeCustomerId, + customer: response.locals.customer.paymentProviderId, line_items: [ { price: price, @@ -261,7 +261,7 @@ export class SubscriptionController { const { returnUrl } = request.body satisfies SubscriptionUpdateRequestBody; try { // Get the subscription object from the DB - const subscription = await SubscriptionService.instance.findOne([{ customer: response.locals.customer }]); + const subscription = await SubscriptionService.instance.findOne({ customer: response.locals.customer }); if (!subscription) { return response.status(StatusCodes.NOT_FOUND).json({ error: `Subscription was not found`, @@ -270,7 +270,7 @@ export class SubscriptionController { // Create portal link const session = await stripe.billingPortal.sessions.create({ - customer: response.locals.customer.stripeCustomerId, + customer: response.locals.customer.paymentProviderId, return_url: returnUrl, }); @@ -299,7 +299,7 @@ export class SubscriptionController { * tags: [Subscription] * parameters: * - in: query - * name: stripeCustomerId + * name: paymentProviderId * schema: * type: string * description: The customer id. If passed - returns filtered by this customer list of subscriptions. @@ -324,12 +324,12 @@ export class SubscriptionController { @syncCustomer public async list(request: Request, response: Response) { const stripe = response.locals.stripe as Stripe; - const stripeCustomerId = response.locals.customer.stripeCustomerId; + const paymentProviderId = response.locals.customer.paymentProviderId; try { // Get the subscriptions - const subscriptions = stripeCustomerId + const subscriptions = paymentProviderId ? await stripe.subscriptions.list({ - customer: stripeCustomerId as string, + customer: paymentProviderId as string, }) : await stripe.subscriptions.list(); @@ -373,20 +373,12 @@ export class SubscriptionController { * $ref: '#/components/schemas/NotFoundError' */ @validate - @syncCustomer + @syncOne async get(request: Request, response: Response) { const stripe = response.locals.stripe as Stripe; try { // Get the subscriptionId from the request - const _sub = await SubscriptionService.instance.findOne([ - { - customer: response.locals.customer, - status: 'active'}, - { - customer: response.locals.customer, - status: 'trialing' - } - ]); + const _sub = await SubscriptionService.instance.findCurrent(response.locals.customer); if (!_sub) { return response.status(StatusCodes.NOT_FOUND).json({ error: `Subscription was not found`, diff --git a/src/controllers/api/account.ts b/src/controllers/api/account.ts index 1dbd19d2..65fdc083 100644 --- a/src/controllers/api/account.ts +++ b/src/controllers/api/account.ts @@ -305,7 +305,7 @@ export class AccountController { } } // 8. Add the Stripe account to the Customer - if (customer.stripeCustomerId === null) { + if (customer.paymentProviderId === null) { eventTracker.submit({ operation: OperationNameEnum.STRIPE_ACCOUNT_CREATE, data: { diff --git a/src/database/entities/customer.entity.ts b/src/database/entities/customer.entity.ts index 6d5f8a52..de774c1f 100644 --- a/src/database/entities/customer.entity.ts +++ b/src/database/entities/customer.entity.ts @@ -30,7 +30,7 @@ export class CustomerEntity { type: 'text', nullable: true, }) - stripeCustomerId!: string; + paymentProviderId!: string; @BeforeInsert() setCreatedAt() { diff --git a/src/database/migrations/AlterCustomerTable.ts b/src/database/migrations/AlterCustomerTable.ts index 7792647d..c19df230 100644 --- a/src/database/migrations/AlterCustomerTable.ts +++ b/src/database/migrations/AlterCustomerTable.ts @@ -7,7 +7,7 @@ export class AlterCustomerTable1695740346000 implements MigrationInterface { await queryRunner.addColumn( table_name, new TableColumn({ - name: 'stripeAccountId', + name: 'paymentProviderId', type: 'text', isNullable: true, }) diff --git a/src/database/types/types.ts b/src/database/types/types.ts index 61e38972..eb896d4c 100644 --- a/src/database/types/types.ts +++ b/src/database/types/types.ts @@ -100,7 +100,7 @@ export class Postgres implements AbstractDatabase { AlterOperationTable1695740345978, // Change payment table structure AlterPaymentTable1695740345979, - // Add stripeCustomerId to customer table + // Add paymentProviderId to customer table AlterCustomerTable1695740346000, // Add new category AlterOperationTable1695740346001, diff --git a/src/services/admin/stripe.ts b/src/services/admin/stripe.ts index 5e94cab4..cb27205c 100644 --- a/src/services/admin/stripe.ts +++ b/src/services/admin/stripe.ts @@ -56,7 +56,7 @@ export class StripeService { async syncCustomer(customer: CustomerEntity): Promise { const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); for await (const subscription of stripe.subscriptions.list({ - customer: customer.stripeCustomerId, + customer: customer.paymentProviderId, status: 'all', })) { const current = await SubscriptionService.instance.subscriptionRepository.findOne({ @@ -73,15 +73,7 @@ export class StripeService { async syncOne(customer: CustomerEntity): Promise { const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); - const local = await SubscriptionService.instance.findOne([ - { - customer: customer, - status: 'active'}, - { - customer: customer, - status: 'trialing' - } - ]); + const local = await SubscriptionService.instance.findCurrent(customer) if (!local) { eventTracker.notify({ message: EventTracker.compileBasicNotification( @@ -90,6 +82,28 @@ export class StripeService { ), severity: 'debug', }); + const activeSubs = await stripe.subscriptions.list({ + customer: customer.paymentProviderId, + status: 'active', + }); + const trialSubs = await stripe.subscriptions.list({ + customer: customer.paymentProviderId, + status: 'trialing', + }); + const subs = [...activeSubs.data, ...trialSubs.data]; + if (subs.length > 1) { + eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `Multiple active subscriptions found for customer with id ${customer.customerId}`, + 'Subscription syncronization' + ), + severity: 'error', + }); + return; + } + if (subs.length > 0) { + await this.createSubscription(subs[0], customer); + } return; } const subscriptionId = local.subscriptionId; diff --git a/src/services/admin/subscription.ts b/src/services/admin/subscription.ts index 9ef45843..0d8ca45f 100644 --- a/src/services/admin/subscription.ts +++ b/src/services/admin/subscription.ts @@ -66,13 +66,20 @@ export class SubscriptionService { }); } - public async findOne(where: Array>) { + public async findOne(where: Record) { return await this.subscriptionRepository.findOne({ where: where, relations: ['customer'], }); } + public async findCurrent(customer: CustomerEntity) { + return await this.subscriptionRepository.findOne({ + where: [{ customer: customer, status: 'active' }, { customer: customer, status: 'trialing' }], + relations: ['customer'], + }); + } + public equals(subscriptionEntity: SubscriptionEntity, subscription: Stripe.Subscription): boolean { const required = subscriptionEntity.subscriptionId === subscription.id && diff --git a/src/services/api/customer.ts b/src/services/api/customer.ts index 85376fef..254290c4 100644 --- a/src/services/api/customer.ts +++ b/src/services/api/customer.ts @@ -42,7 +42,7 @@ export class CustomerService { }; } - public async update(customerId: string, name?: string, stripeCustomerId?: string) { + public async update(customerId: string, name?: string, paymentProviderId?: string) { const existingCustomer = await this.customerRepository.findOneBy({ customerId }); if (!existingCustomer) { throw new Error(`CustomerId not found`); @@ -51,8 +51,8 @@ export class CustomerService { existingCustomer.name = name; } - if (stripeCustomerId) { - existingCustomer.stripeCustomerId = stripeCustomerId; + if (paymentProviderId) { + existingCustomer.paymentProviderId = paymentProviderId; } return await this.customerRepository.save(existingCustomer); } @@ -77,9 +77,9 @@ export class CustomerService { } } - public async findbyStripeCustomerId(stripeCustomerId: string) { + public async findbyPaymentProviderId(paymentProviderId: string) { return await this.customerRepository.findOne({ - where: { stripeCustomerId }, + where: { paymentProviderId: paymentProviderId }, }); } diff --git a/src/services/track/admin/subscription-submitter.ts b/src/services/track/admin/subscription-submitter.ts index 8dfcc30f..bf808a77 100644 --- a/src/services/track/admin/subscription-submitter.ts +++ b/src/services/track/admin/subscription-submitter.ts @@ -40,13 +40,13 @@ export class SubscriptionSubmitter implements IObserver { try { if (!customer) { const customers = await CustomerService.instance.find({ - stripeCustomerId: data.stripeCustomerId, + paymentProviderId: data.paymentProviderId, }); if (customers.length !== 1) { this.notify({ message: EventTracker.compileBasicNotification( - `It should be only 1 Stripe account associated with CaaS customer. Stripe accountId: ${data.stripeCustomerId}.`, + `It should be only 1 Stripe account associated with CaaS customer. Stripe accountId: ${data.paymentProviderId}.`, operation.operation ), severity: 'error', diff --git a/src/services/track/helpers.ts b/src/services/track/helpers.ts index 192c4259..1a25fb3b 100644 --- a/src/services/track/helpers.ts +++ b/src/services/track/helpers.ts @@ -40,7 +40,7 @@ export function builSubmitOperation (subscription: Stripe.Subscription, name: st operation: name, data: { subscriptionId: subscription.id, - stripeCustomerId: subscription.customer as string, + paymentProviderId: subscription.customer as string, status: subscription.status, currentPeriodStart: new Date(subscription.current_period_start * 1000), currentPeriodEnd: new Date(subscription.current_period_end * 1000), diff --git a/src/services/track/submitter.ts b/src/services/track/submitter.ts index acaf1c81..01796f73 100644 --- a/src/services/track/submitter.ts +++ b/src/services/track/submitter.ts @@ -10,7 +10,7 @@ export interface ISubmitStripeCustomerCreateData { } export interface ISubmitSubscriptionData { - stripeCustomerId: string; + paymentProviderId: string; status: string; currentPeriodStart: Date; currentPeriodEnd: Date; From b36693575401ec9969f0e43e7ce7cdc8ef3b7156 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Tue, 26 Mar 2024 19:46:44 +0100 Subject: [PATCH 18/40] Small cleeanups and refactoring --- src/helpers/helpers.ts | 19 ------- src/middleware/auth/base-auth-handler.ts | 7 +-- src/middleware/authentication.ts | 68 ++++++++++-------------- 3 files changed, 31 insertions(+), 63 deletions(-) diff --git a/src/helpers/helpers.ts b/src/helpers/helpers.ts index df51363a..3148ca78 100644 --- a/src/helpers/helpers.ts +++ b/src/helpers/helpers.ts @@ -237,22 +237,3 @@ export async function decryptPrivateKey(encryptedPrivateKeyHex: string, ivHex: s return secretKey; } - -// export function eventDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) { -// const originalMethod = descriptor.value; -// descriptor.value = async function (...args: any[]) { -// const response = await originalMethod.apply(this, args) as Response; - -// response.on('finish', () => { -// console.log("Response finished"); -// if (response.statusCode !== StatusCodes.OK) { -// eventTracker.emit('notify', { -// message: `Response status code: ${response.statusCode}. Message to client: ${response.statusMessage}`, -// severity: 'error' -// } satisfies INotifyMessage) -// } -// }) -// return response; -// }; -// return descriptor; -// } diff --git a/src/middleware/auth/base-auth-handler.ts b/src/middleware/auth/base-auth-handler.ts index 18ae8e17..89c59454 100644 --- a/src/middleware/auth/base-auth-handler.ts +++ b/src/middleware/auth/base-auth-handler.ts @@ -25,8 +25,8 @@ export class BaseAPIGuard extends RuleRoutine implements IAPIGuard { if (!rule) { return this.returnError( - StatusCodes.INTERNAL_SERVER_ERROR, - `Internal error. There is no auth rule for such request. Please contact administrator` + StatusCodes.BAD_REQUEST, + `Bad Request. No atuh rules for handling such request: ${request.method} ${request.path}` ); } // If the rule is not found - skip the auth check @@ -148,8 +148,9 @@ export class BaseAuthHandler extends BaseAPIGuard implements IAuthHandler { } } - public setOAuthProvider(oauthProvider: IOAuthProvider): void { + public setOAuthProvider(oauthProvider: IOAuthProvider): IAuthHandler { this.oauthProvider = oauthProvider; + return this; } public setUserInfoStrategy(strategy: IUserInfoFetcher): void { diff --git a/src/middleware/authentication.ts b/src/middleware/authentication.ts index 2f3e6fa7..227510c1 100644 --- a/src/middleware/authentication.ts +++ b/src/middleware/authentication.ts @@ -24,13 +24,13 @@ dotenv.config(); const { ENABLE_EXTERNAL_DB } = process.env; export class Authentication { - private authHandler: BaseAuthHandler; + private initHandler: BaseAuthHandler; private isSetup = false; private logToHelper: LogToHelper; constructor() { // Initial auth handler - this.authHandler = new AccountAuthHandler(); + this.initHandler = new AccountAuthHandler(); this.logToHelper = new LogToHelper(); } @@ -42,41 +42,26 @@ export class Authentication { error: _r.error, }); } - const oauthProvider = new LogToProvider(); - oauthProvider.setHelper(this.logToHelper); - - const didAuthHandler = new DidAuthHandler(); - const keyAuthHandler = new KeyAuthHandler(); - const credentialAuthHandler = new CredentialAuthHandler(); - const credentialStatusAuthHandler = new CredentialStatusAuthHandler(); - const resourceAuthHandler = new ResourceAuthHandler(); - const presentationAuthHandler = new PresentationAuthHandler(); - const authInfoHandler = new AuthInfoHandler(); - - const adminAuthHandler = new AdminHandler(); - - // Set logToHelper. We do it for avoiding re-asking LogToHelper.setup() in each auth handler - // cause it does a lot of requests to LogTo - this.authHandler.setOAuthProvider(oauthProvider); - didAuthHandler.setOAuthProvider(oauthProvider); - keyAuthHandler.setOAuthProvider(oauthProvider); - credentialAuthHandler.setOAuthProvider(oauthProvider); - credentialStatusAuthHandler.setOAuthProvider(oauthProvider); - resourceAuthHandler.setOAuthProvider(oauthProvider); - presentationAuthHandler.setOAuthProvider(oauthProvider); - authInfoHandler.setOAuthProvider(oauthProvider); - adminAuthHandler.setOAuthProvider(oauthProvider); - - // Set chain of responsibility - this.authHandler - .setNext(didAuthHandler) - .setNext(keyAuthHandler) - .setNext(credentialAuthHandler) - .setNext(credentialStatusAuthHandler) - .setNext(resourceAuthHandler) - .setNext(presentationAuthHandler) - .setNext(authInfoHandler) - .setNext(adminAuthHandler); + const fillChain = async (handler: BaseAuthHandler[]) => { + const oauthProvider = new LogToProvider(); + oauthProvider.setHelper(this.logToHelper); + for (let i = 0; i < handler.length - 1; i++) { + handler[i].setOAuthProvider(oauthProvider); + handler[i].setNext(handler[i + 1]); + } + }; + + fillChain([ + this.initHandler, + new DidAuthHandler(), + new KeyAuthHandler(), + new CredentialAuthHandler(), + new CredentialStatusAuthHandler(), + new ResourceAuthHandler(), + new PresentationAuthHandler(), + new AuthInfoHandler(), + new AdminHandler(), + ]) this.isSetup = true; } @@ -93,8 +78,9 @@ export class Authentication { } public async accessControl(request: Request, response: Response, next: NextFunction) { - if (this.authHandler.skipPath(request.path)) return next(); + if (this.initHandler.skipPath(request.path)) return next(); + // ToDo: Make it more readable if (ENABLE_EXTERNAL_DB === 'false') { if (['/account', '/did/create', '/key/create'].includes(request.path)) { return response.status(StatusCodes.METHOD_NOT_ALLOWED).json({ @@ -115,7 +101,7 @@ export class Authentication { } public async withLogtoWrapper(request: Request, response: Response, next: NextFunction) { - if (this.authHandler.skipPath(request.path)) return next(); + if (this.initHandler.skipPath(request.path)) return next(); try { return withLogto({ ...configLogToExpress, scopes: ['roles'] })(request, response, next); } catch (err) { @@ -134,11 +120,11 @@ export class Authentication { public async guard(request: Request, response: Response, next: NextFunction) { const { provider } = request.body as { claim: string; provider: string }; - if (this.authHandler.skipPath(request.path)) return next(); + if (this.initHandler.skipPath(request.path)) return next(); try { // If response got back that means error was raised - const _resp = await this.authHandler.handle(request, response); + const _resp = await this.initHandler.handle(request, response); if (_resp.status !== StatusCodes.OK) { return response.status(_resp.status).json({ error: _resp.error, From 9ef7459c8733b6a43658e6512b11441dfebe27b2 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Wed, 27 Mar 2024 16:26:05 +0100 Subject: [PATCH 19/40] Make swagger changes --- src/static/swagger-admin.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/static/swagger-admin.json b/src/static/swagger-admin.json index b5717e54..8b44d945 100644 --- a/src/static/swagger-admin.json +++ b/src/static/swagger-admin.json @@ -261,7 +261,7 @@ "parameters": [ { "in": "query", - "name": "stripeCustomerId", + "name": "paymentProviderId", "schema": { "type": "string", "description": "The customer id. If passed - returns filtered by this customer list of subscriptions." From dea3a2334a5551b111053fda18538190baaf368a Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Mon, 1 Apr 2024 11:52:32 +0200 Subject: [PATCH 20/40] Add encryption/decryption to API key --- src/controllers/api/account.ts | 1 + src/database/entities/api.key.entity.ts | 14 +++--- src/database/migrations/AlterAPIKeyTable.ts | 23 ++++++++++ src/database/types/types.ts | 3 ++ src/services/api/api-key.ts | 48 +++++++++++++++------ 5 files changed, 70 insertions(+), 19 deletions(-) create mode 100644 src/database/migrations/AlterAPIKeyTable.ts diff --git a/src/controllers/api/account.ts b/src/controllers/api/account.ts index 65fdc083..9fc99d35 100644 --- a/src/controllers/api/account.ts +++ b/src/controllers/api/account.ts @@ -90,6 +90,7 @@ export class AccountController { * tags: [Account] * summary: Fetch IdToken. * description: This endpoint returns IdToken as JWT with list of user roles inside + * deprecated: true * responses: * 200: * description: The request was successful. diff --git a/src/database/entities/api.key.entity.ts b/src/database/entities/api.key.entity.ts index 95c3e4e1..1725e2b0 100644 --- a/src/database/entities/api.key.entity.ts +++ b/src/database/entities/api.key.entity.ts @@ -7,15 +7,19 @@ dotenv.config(); @Entity('apiKey') export class APIKeyEntity { - @PrimaryGeneratedColumn('uuid') - apiKeyId!: string; - @Column({ type: 'text', nullable: false, + primary: true, }) apiKey!: string; + @Column({ + type: 'boolean', + nullable: false, + }) + revoked!: boolean; + @Column({ type: 'timestamptz', nullable: false, @@ -56,11 +60,11 @@ export class APIKeyEntity { return this.expiresAt < new Date(); } - constructor(apiKeyId: string, apiKey: string, expiresAt: Date, customer: CustomerEntity, user: UserEntity) { - this.apiKeyId = apiKeyId; + constructor(apiKey: string, expiresAt: Date, customer: CustomerEntity, user: UserEntity, revoked = false) { this.apiKey = apiKey; this.expiresAt = expiresAt; this.customer = customer; this.user = user; + this.revoked = revoked; } } diff --git a/src/database/migrations/AlterAPIKeyTable.ts b/src/database/migrations/AlterAPIKeyTable.ts new file mode 100644 index 00000000..3e0b8746 --- /dev/null +++ b/src/database/migrations/AlterAPIKeyTable.ts @@ -0,0 +1,23 @@ +import { TableColumn, type MigrationInterface, type QueryRunner } from 'typeorm'; + +export class AlterAPIKeyTableAddRevoked1695740346004 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + const table_name = 'apiKey'; + + await queryRunner.addColumn( + table_name, + new TableColumn({ + name: 'revoked', + type: 'boolean', + isNullable: true, + }) + ); + + // Remove unused apiKeyId column + await queryRunner.dropColumn(table_name, 'apiKeyId'); + } + + public async down(queryRunner: QueryRunner): Promise { + throw new Error('illegal_operation: cannot roll back initial migration'); + } +} diff --git a/src/database/types/types.ts b/src/database/types/types.ts index eb896d4c..7008623b 100644 --- a/src/database/types/types.ts +++ b/src/database/types/types.ts @@ -36,6 +36,7 @@ import { AlterCustomerTable1695740346000 } from '../migrations/AlterCustomerTabl import { AlterOperationTable1695740346001 } from '../migrations/AlterOperationTableNewCategory.js'; import { SubscriptionEntity } from '../entities/subscription.entity.js'; import { CreateSubscritpionTable1695740346003 } from '../migrations/CreateSubscriptionTable.js'; +import { AlterAPIKeyTableAddRevoked1695740346004 } from '../migrations/AlterAPIKeyTable.js'; dotenv.config(); const { EXTERNAL_DB_CONNECTION_URL, EXTERNAL_DB_CERT } = process.env; @@ -106,6 +107,8 @@ export class Postgres implements AbstractDatabase { AlterOperationTable1695740346001, // Add subscription table CreateSubscritpionTable1695740346003, + // Add revoked field to APIKey table + AlterAPIKeyTableAddRevoked1695740346004, ], entities: [ ...Entities, diff --git a/src/services/api/api-key.ts b/src/services/api/api-key.ts index 63bdedb8..d8e24773 100644 --- a/src/services/api/api-key.ts +++ b/src/services/api/api-key.ts @@ -7,18 +7,21 @@ import type { CustomerEntity } from '../../database/entities/customer.entity.js' import { APIKeyEntity } from '../../database/entities/api.key.entity.js'; import type { UserEntity } from '../../database/entities/user.entity.js'; import { v4 } from 'uuid'; +import { SecretBox } from '@veramo/kms-local'; dotenv.config(); export class APIKeyService { public apiKeyRepository: Repository; + private secretBox: SecretBox; public static instance = new APIKeyService(); constructor() { this.apiKeyRepository = Connection.instance.dbConnection.getRepository(APIKeyEntity); + this.secretBox = new SecretBox(process.env.EXTERNAL_DB_ENCRYPTION_KEY) } - public async create(apiKey: string, customer: CustomerEntity, user: UserEntity): Promise { + public async create(apiKey: string, customer: CustomerEntity, user: UserEntity, revoked = false): Promise { const apiKeyId = v4(); if (!apiKey) { throw new Error('API key is not specified'); @@ -32,26 +35,24 @@ export class APIKeyService { if (!customer) { throw new Error('Customer id is not specified'); } + const encryptedAPIKey = await this.secretBox.encrypt(apiKey); const expiresAt = await this.getExpiryDate(apiKey); - const apiKeyEntity = new APIKeyEntity(apiKeyId, apiKey, expiresAt, customer, user); + const apiKeyEntity = new APIKeyEntity(encryptedAPIKey, expiresAt, customer, user, revoked); const apiKeyRecord = (await this.apiKeyRepository.insert(apiKeyEntity)).identifiers[0]; if (!apiKeyRecord) throw new Error(`Cannot create a new API key`); return apiKeyEntity; } public async update( - apiKeyId: string, - apiKey?: string, + apiKey: string, expiresAt?: Date, customer?: CustomerEntity, - user?: UserEntity + user?: UserEntity, + revoked?: boolean ) { - const existingAPIKey = await this.apiKeyRepository.findOneBy({ apiKeyId }); + const existingAPIKey = await this.apiKeyRepository.findOneBy({ apiKey }); if (!existingAPIKey) { - throw new Error(`API with key id ${apiKeyId} not found`); - } - if (apiKey) { - existingAPIKey.apiKey = apiKey; + throw new Error(`API with key id ${apiKey} not found`); } if (expiresAt) { existingAPIKey.expiresAt = expiresAt; @@ -62,23 +63,42 @@ export class APIKeyService { if (user) { existingAPIKey.user = user; } + if (revoked) { + existingAPIKey.revoked = revoked; + } return await this.apiKeyRepository.save(existingAPIKey); } - public async get(apiKeyId: string) { - return await this.apiKeyRepository.findOne({ - where: { apiKeyId }, + public async get(apiKey: string) { + const apiKeyEntity = await this.apiKeyRepository.findOne({ + where: { apiKey }, relations: ['customer', 'user'], }); + if (!apiKeyEntity) { + throw new Error(`API key ${apiKey} not found`); + } + + if (this.secretBox && apiKeyEntity.apiKey) { + apiKeyEntity.apiKey = await this.secretBox.decrypt(apiKeyEntity.apiKey); + } + return apiKeyEntity; } public async find(where: Record) { try { - return await this.apiKeyRepository.find({ + const apiKeyList = await this.apiKeyRepository.find({ where: where, relations: ['customer', 'user'], }); + // decrypt the API keys + if (this.secretBox) { + for (const apiKey of apiKeyList) { + apiKey.apiKey = await this.secretBox.decrypt(apiKey.apiKey); + } + } + return apiKeyList; + } catch { return []; } From 0413eb299931d9c07ceae363a9f3307709a36542 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Mon, 1 Apr 2024 18:37:05 +0200 Subject: [PATCH 21/40] Change API logic a bit and introduce API key endpoints --- README.md | 3 + package-lock.json | 36 +- package.json | 1 + src/app.ts | 16 +- src/controllers/admin/api-key.ts | 374 + src/controllers/admin/subscriptions.ts | 3 +- src/controllers/admin/webhook.ts | 2 +- src/database/entities/api.key.entity.ts | 18 +- src/database/migrations/AlterAPIKeyTable.ts | 31 +- src/database/types/types.ts | 4 +- .../auth/routes/admin/admin-auth.ts | 11 + src/middleware/authentication.ts | 2 +- src/services/admin/api-key.ts | 160 + src/services/admin/stripe.ts | 151 +- src/services/admin/subscription.ts | 5 +- src/services/api/api-key.ts | 111 - src/services/identity/abstract.ts | 4 + src/services/identity/index.ts | 1 + src/services/identity/postgres.ts | 21 +- src/services/track/helpers.ts | 4 +- src/services/track/submitter.ts | 2 +- src/static/swagger-admin-options.json | 5 +- src/static/swagger-admin.json | 1680 ++-- src/static/swagger-api.json | 6881 ++++++++--------- src/types/constants.ts | 11 + src/types/environment.d.ts | 3 + src/types/portal.ts | 48 + src/types/swagger-admin-types.ts | 149 + 28 files changed, 5311 insertions(+), 4426 deletions(-) create mode 100644 src/controllers/admin/api-key.ts create mode 100644 src/services/admin/api-key.ts delete mode 100644 src/services/api/api-key.ts diff --git a/README.md b/README.md index e2158ef1..cf79aca4 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,9 @@ By default, `ENABLE_AUTHENTICATION` is set to off/`false`. To enable external Ve 2. `LOGTO_WEBHOOK_SECRET`: Webhook secret to authenticate incoming webhook requests from LogTo. 5. **Miscellaneous** 1. `COOKIE_SECRET`: Secret for cookie encryption. + 2. `API_KEY_PREFIX` (optional): Prefix for API keys. (Default "caas") + 3. `API_KEY_LENGTH` (optional): Length of API keys. (Default 32) + 4. `API_KEY_EXPIRATION` (optional): Expiration time for API keys in month. (Default 1 month) #### Faucet settings diff --git a/package-lock.json b/package-lock.json index 7da177b5..c12225e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cheqd/credential-service", - "version": "2.18.1-develop.1", + "version": "2.18.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@cheqd/credential-service", - "version": "2.18.1-develop.1", + "version": "2.18.3", "license": "Apache-2.0", "dependencies": { "@cheqd/did-provider-cheqd": "^3.7.0", @@ -43,6 +43,7 @@ "express-validator": "^7.0.1", "helmet": "^7.1.0", "http-status-codes": "^2.3.0", + "js-sha3": "^0.9.3", "json-stringify-safe": "^5.0.1", "jsonwebtoken": "^9.0.2", "jwt-decode": "^4.0.0", @@ -3711,6 +3712,11 @@ "js-sha3": "0.8.0" } }, + "node_modules/@ethersproject/keccak256/node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" + }, "node_modules/@ethersproject/logger": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", @@ -10906,6 +10912,11 @@ "uint8arrays": "^3.0.0" } }, + "node_modules/@verida/account/node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" + }, "node_modules/@verida/account/node_modules/multiformats": { "version": "9.9.0", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", @@ -10988,6 +10999,11 @@ "resolved": "https://registry.npmjs.org/did-resolver/-/did-resolver-3.2.2.tgz", "integrity": "sha512-Eeo2F524VM5N3W4GwglZrnul2y6TLTwMQP3In62JdG34NZoqihYyOZLk+5wUW8sSgvIYIcJM8Dlt3xsdKZZ3tg==" }, + "node_modules/@verida/client-ts/node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" + }, "node_modules/@verida/client-ts/node_modules/multiformats": { "version": "9.9.0", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", @@ -11878,6 +11894,11 @@ "@ethersproject/wordlists": "5.5.0" } }, + "node_modules/@verida/vda-common/node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" + }, "node_modules/@verida/vda-common/node_modules/ws": { "version": "7.4.6", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", @@ -15051,6 +15072,11 @@ "uint8arrays": "^3.0.0" } }, + "node_modules/credential-status/node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" + }, "node_modules/credential-status/node_modules/multiformats": { "version": "9.9.0", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", @@ -20344,9 +20370,9 @@ "integrity": "sha512-NPrWuHFxFUknr1KqJRDgUQPexQF0uIJWjeT+2KjEePhitQxQEx5EJBG1lVn5/hc8aLycTpXrDOgPQ6Zq+EDiTA==" }, "node_modules/js-sha3": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.9.3.tgz", + "integrity": "sha512-BcJPCQeLg6WjEx3FE591wVAevlli8lxsxm9/FzV4HXkV49TmBH38Yvrpce6fjbADGMKFrBMGTqrVz3qPIZ88Gg==" }, "node_modules/js-tokens": { "version": "4.0.0", diff --git a/package.json b/package.json index 48bf9b93..2d3e7a0f 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "express-validator": "^7.0.1", "helmet": "^7.1.0", "http-status-codes": "^2.3.0", + "js-sha3": "^0.9.3", "json-stringify-safe": "^5.0.1", "jsonwebtoken": "^9.0.2", "jwt-decode": "^4.0.0", diff --git a/src/app.ts b/src/app.ts index c6043c99..0cb65d33 100644 --- a/src/app.ts +++ b/src/app.ts @@ -31,6 +31,7 @@ import { ProductController } from './controllers/admin/product.js'; import { SubscriptionController } from './controllers/admin/subscriptions.js'; import { PriceController } from './controllers/admin/prices.js'; import { WebhookController } from './controllers/admin/webhook.js'; +import { APIKeyController } from './controllers/admin/api-key.js'; let swaggerOptions = {}; if (process.env.ENABLE_AUTHENTICATION === 'true') { @@ -112,7 +113,7 @@ class App { swaggerUi.serveFiles(swaggerAdminDocument), swaggerUi.setup(swaggerAdminDocument) ); - this.express.use(Middleware.setStripeClient) + this.express.use(Middleware.setStripeClient); } this.express.use(auth.handleError); this.express.use(async (req, res, next) => await auth.accessControl(req, res, next)); @@ -226,7 +227,11 @@ class App { // Portal // Product if (process.env.STRIPE_ENABLED === 'true') { - app.get('/admin/product/list', ProductController.productListValidator, new ProductController().listProducts); + app.get( + '/admin/product/list', + ProductController.productListValidator, + new ProductController().listProducts + ); app.get( '/admin/product/get/:productId', ProductController.productGetValidator, @@ -264,6 +269,13 @@ class App { new SubscriptionController().resume ); + // API key + app.post('/admin/api-key/create', APIKeyController.apiKeyCreateValidator, new APIKeyController().create); + app.post('/admin/api-key/update', APIKeyController.apiKeyUpdateValidator, new APIKeyController().update); + app.get('/admin/api-key/get', APIKeyController.apiKeyGetValidator, new APIKeyController().get); + app.get('/admin/api-key/list', APIKeyController.apiKeyListValidator, new APIKeyController().list); + app.delete('/admin/api-key/revoke', APIKeyController.apiKeyRevokeValidator, new APIKeyController().revoke); + // Webhook app.post('/admin/webhook', new WebhookController().handleWebhook); } diff --git a/src/controllers/admin/api-key.ts b/src/controllers/admin/api-key.ts new file mode 100644 index 00000000..3341e079 --- /dev/null +++ b/src/controllers/admin/api-key.ts @@ -0,0 +1,374 @@ +import type { Request, Response } from 'express'; +import * as dotenv from 'dotenv'; +import { StatusCodes } from 'http-status-codes'; +import { check } from '../validator/index.js'; +import { validate } from '../validator/decorator.js'; +import { APIKeyService } from '../../services/admin/api-key.js'; +import type { + APIKeyCreateRequestBody, + APIKeyCreateResponseBody, + APIKeyCreateUnsuccessfulResponseBody, + APIKeyGetResponseBody, + APIKeyGetUnsuccessfulResponseBody, + APIKeyListResponseBody, + APIKeyListUnsuccessfulResponseBody, + APIKeyRevokeRequestBody, + APIKeyRevokeResponseBody, + APIKeyRevokeUnsuccessfulResponseBody, + APIKeyUpdateRequestBody, + APIKeyUpdateResponseBody, + APIKeyUpdateUnsuccessfulResponseBody, +} from '../../types/portal.js'; +import { EventTracker, eventTracker } from '../../services/track/tracker.js'; +import { OperationNameEnum } from '../../types/constants.js'; + +dotenv.config(); + +export class APIKeyController { + static apiKeyCreateValidator = [ + check('expiresAt') + .optional() + .isISO8601() + .toDate() + .withMessage('Invalid date format') + .custom((value) => { + if (value < new Date()) { + throw new Error('expiresAt must be in the future'); + } + return true; + }) + .toDate() + .bail(), + ]; + static apiKeyUpdateValidator = [ + check('apiKey') + .exists() + .withMessage('API key is not specified') + .bail() + .isString() + .withMessage('Invalid API key') + .bail(), + check('expiresAt') + .optional() + .isISO8601() + .toDate() + .withMessage('Invalid date format') + .custom((value) => { + if (value < new Date()) { + throw new Error('expiresAt must be in the future'); + } + return true; + }) + .toDate() + .bail(), + check('revoked').optional().isBoolean().withMessage('Invalid boolean value').bail(), + ]; + static apiKeyRevokeValidator = [ + check('apiKey') + .exists() + .withMessage('API key is not specified') + .bail() + .isString() + .withMessage('Invalid API key') + .bail(), + ]; + static apiKeyListValidator = [ + // No validation + ]; + static apiKeyGetValidator = [check('apiKey').optional().isString().withMessage('Invalid API key').bail()]; + + /** + * @openapi + * + * /admin/api-key/create: + * post: + * summary: Create a new API key + * description: Create a new API key + * tags: [API Key] + * requestBody: + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/APIKeyCreateRequestBody' + * responses: + * 201: + * description: A new API key has been created + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/APIKeyCreateResponseBody' + * 400: + * $ref: '#/components/schemas/APIKeyCreateUnsuccessfulResponseBody' + * 401: + * $ref: '#/components/schemas/UnauthorizedError' + * 500: + * $ref: '#/components/schemas/InternalError' + */ + @validate + public async create(request: Request, response: Response) { + try { + const { expiresAt } = request.body satisfies APIKeyCreateRequestBody; + + const apiKey = APIKeyService.instance.generateAPIKey(); + const apiKeyEntity = await APIKeyService.instance.create(apiKey, response.locals.user, expiresAt); + if (!apiKeyEntity) { + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + message: 'Cannot create a new API key', + }); + } + eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `API key for customer: ${response.locals.customer.customerId} has been created`, + OperationNameEnum.API_KEY_CREATE + ), + severity: 'info', + }); + return response.status(StatusCodes.CREATED).json({ + apiKey: apiKeyEntity.apiKey, + expiresAt: apiKeyEntity.expiresAt.toISOString(), + revoked: apiKeyEntity.revoked, + } satisfies APIKeyCreateResponseBody); + } catch (error) { + return response.status(500).json({ + error: `Internal error: ${(error as Error)?.message || error}`, + } satisfies APIKeyCreateUnsuccessfulResponseBody); + } + } + + /** + * @openapi + * + * /admin/api-key/update: + * post: + * summary: Update an existing API key + * description: Update an existing API key + * tags: [API Key] + * requestBody: + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/APIKeyUpdateRequestBody' + * responses: + * 200: + * description: The API key has been updated + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/APIKeyUpdateResponseBody' + * 400: + * $ref: '#/components/schemas/APIKeyUpdateUnsuccessfulResponseBody' + * 401: + * $ref: '#/components/schemas/UnauthorizedError' + * 500: + * $ref: '#/components/schemas/InternalError' + * + */ + @validate + public async update(request: Request, response: Response) { + try { + const { apiKey, expiresAt, revoked } = request.body satisfies APIKeyUpdateRequestBody; + const apiKeyEntity = await APIKeyService.instance.update(apiKey, expiresAt, revoked); + if (!apiKeyEntity) { + return response.status(StatusCodes.NOT_FOUND).json({ + error: 'Cannot update API key cause it\'s not found', + } satisfies APIKeyUpdateUnsuccessfulResponseBody); + } + + eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `API key for customer: ${response.locals.customer.customerId} has been updated`, + OperationNameEnum.API_KEY_UPDATE + ), + severity: 'info', + }); + return response.status(StatusCodes.OK).json({ + apiKey: apiKeyEntity.apiKey, + expiresAt: apiKeyEntity.expiresAt.toISOString(), + revoked: apiKeyEntity.revoked, + } satisfies APIKeyUpdateResponseBody); + } catch (error) { + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: `Internal error: ${(error as Error)?.message || error}`, + } satisfies APIKeyUpdateUnsuccessfulResponseBody); + } + } + + /** + * @openapi + * + * /admin/api-key/revoke: + * delete: + * summary: Revoke an existing API key + * description: Revoke an existing API key + * tags: [API Key] + * requestBody: + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/APIKeyRevokeRequestBody' + * responses: + * 200: + * description: The API key has been revoked + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/APIKeyRevokeResponseBody' + * 400: + * $ref: '#/components/schemas/APIKeyRevokeUnsuccessfulResponseBody' + * 401: + * $ref: '#/components/schemas/UnauthorizedError' + * 500: + * $ref: '#/components/schemas/InternalError' + * + */ + @validate + public async revoke(request: Request, response: Response) { + try { + const { apiKey } = request.body satisfies APIKeyRevokeRequestBody; + const apiKeyEntity = await APIKeyService.instance.revoke(apiKey); + if (!apiKeyEntity) { + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: 'Cannot revoke API key', + } satisfies APIKeyRevokeUnsuccessfulResponseBody); + } + eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `API key for customer: ${response.locals.customer.customerId} has been revoked`, + OperationNameEnum.API_KEY_REVOKE + ), + severity: 'info', + }); + return response.status(StatusCodes.OK).json({ + apiKey: apiKeyEntity.apiKey, + revoked: apiKeyEntity.revoked, + } satisfies APIKeyRevokeResponseBody); + } catch (error) { + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: `Internal error: ${(error as Error)?.message || error}`, + } satisfies APIKeyRevokeUnsuccessfulResponseBody); + } + } + + /** + * @openapi + * + * /admin/api-key/list: + * get: + * summary: List all API keys + * description: List all API keys + * tags: [API Key] + * responses: + * 200: + * description: A list of API keys + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/APIKeyListResponseBody' + * 400: + * $ref: '#/components/schemas/InvalidRequest' + * 401: + * $ref: '#/components/schemas/UnauthorizedError' + * 500: + * $ref: '#/components/schemas/InternalError' + * 404: + * $ref: '#/components/schemas/NotFoundError' + * + */ + @validate + public async list(request: Request, response: Response) { + try { + const apiKeyList = await APIKeyService.instance.find({ + customer: response.locals.customer, + }); + const keys = apiKeyList.map((apiKey) => { + return { + apiKey: apiKey.apiKey, + expiresAt: apiKey.expiresAt.toISOString(), + revoked: apiKey.revoked, + }; + }); + return response.status(StatusCodes.OK).json({ + apiKeys: keys, + } satisfies APIKeyListResponseBody); + } catch (error) { + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: `Internal error: ${(error as Error)?.message || error}`, + } satisfies APIKeyListUnsuccessfulResponseBody); + } + } + + /** + * @openapi + * + * /admin/api-key/get: + * get: + * summary: Get an API key + * description: Get an API key. If the API key is not provided, the latest not revoked API key it returns. + * tags: [API Key] + * parameters: + * - name: apiKey + * in: query + * required: false + * schema: + * type: string + * responses: + * 200: + * description: The API key + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/APIKeyGetResponseBody' + * 400: + * $ref: '#/components/schemas/InvalidRequest' + * 401: + * $ref: '#/components/schemas/UnauthorizedError' + * 500: + * $ref: '#/components/schemas/InternalError' + * 404: + * $ref: '#/components/schemas/NotFoundError' + * + */ + @validate + public async get(request: Request, response: Response) { + try { + const apiKey = request.query.apiKey as string; + if (apiKey) { + const apiKeyEntity = await APIKeyService.instance.get(apiKey); + if (!apiKeyEntity) { + return response.status(StatusCodes.NOT_FOUND).json({ + error: 'API key not found', + }); + } + return response.status(StatusCodes.OK).json({ + apiKey: apiKeyEntity.apiKey, + expiresAt: apiKeyEntity.expiresAt.toISOString(), + revoked: apiKeyEntity.revoked, + }); + } + // Otherwise try to get the latest not revoked API key + const keys = await APIKeyService.instance.find( + { + customer: response.locals.customer, + revoked: false, + }, + { + createdAt: 'DESC', + } + ); + if (keys.length == 0) { + return response.status(StatusCodes.NOT_FOUND).json({ + error: 'API key not found', + }); + } + return response.status(StatusCodes.OK).json({ + apiKey: keys[0].apiKey, + expiresAt: keys[0].expiresAt.toISOString(), + revoked: keys[0].revoked, + } satisfies APIKeyGetResponseBody); + } catch (error) { + return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: `Internal error: ${(error as Error)?.message || error}`, + } satisfies APIKeyGetUnsuccessfulResponseBody); + } + } +} diff --git a/src/controllers/admin/subscriptions.ts b/src/controllers/admin/subscriptions.ts index e64346ac..9c21b2bf 100644 --- a/src/controllers/admin/subscriptions.ts +++ b/src/controllers/admin/subscriptions.ts @@ -84,7 +84,6 @@ export function syncOne(target: any, key: string, descriptor: PropertyDescriptor return descriptor; } - export class SubscriptionController { static subscriptionCreateValidator = [ check('price') @@ -198,7 +197,7 @@ export class SubscriptionController { cancel_url: cancelURL, subscription_data: { trial_period_days: trialPeriodDays, - } + }, }, { idempotencyKey, diff --git a/src/controllers/admin/webhook.ts b/src/controllers/admin/webhook.ts index c105c924..e232b712 100644 --- a/src/controllers/admin/webhook.ts +++ b/src/controllers/admin/webhook.ts @@ -15,7 +15,7 @@ export class WebhookController { let event = request.body; let subscription; let status; - const stripe = new Stripe(process.env.STRIPE_SECRET_KEY) + const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); if (!process.env.STRIPE_WEBHOOK_SECRET) { await eventTracker.notify({ diff --git a/src/database/entities/api.key.entity.ts b/src/database/entities/api.key.entity.ts index 1725e2b0..161f0ed7 100644 --- a/src/database/entities/api.key.entity.ts +++ b/src/database/entities/api.key.entity.ts @@ -1,4 +1,4 @@ -import { BeforeInsert, BeforeUpdate, Column, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'; +import { BeforeInsert, BeforeUpdate, Column, Entity, JoinColumn, ManyToOne } from 'typeorm'; import * as dotenv from 'dotenv'; import { CustomerEntity } from './customer.entity.js'; @@ -12,6 +12,12 @@ export class APIKeyEntity { nullable: false, primary: true, }) + apiKeyHash!: string; + + @Column({ + type: 'text', + nullable: false, + }) apiKey!: string; @Column({ @@ -60,7 +66,15 @@ export class APIKeyEntity { return this.expiresAt < new Date(); } - constructor(apiKey: string, expiresAt: Date, customer: CustomerEntity, user: UserEntity, revoked = false) { + constructor( + apiKeyHash: string, + apiKey: string, + expiresAt: Date, + customer: CustomerEntity, + user: UserEntity, + revoked = false + ) { + this.apiKeyHash = apiKeyHash; this.apiKey = apiKey; this.expiresAt = expiresAt; this.customer = customer; diff --git a/src/database/migrations/AlterAPIKeyTable.ts b/src/database/migrations/AlterAPIKeyTable.ts index 3e0b8746..23e4f4b7 100644 --- a/src/database/migrations/AlterAPIKeyTable.ts +++ b/src/database/migrations/AlterAPIKeyTable.ts @@ -1,6 +1,8 @@ import { TableColumn, type MigrationInterface, type QueryRunner } from 'typeorm'; +import pkg from 'js-sha3'; +const { sha3_512 } = pkg; -export class AlterAPIKeyTableAddRevoked1695740346004 implements MigrationInterface { +export class AlterAPIKeyTable1695740346004 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise { const table_name = 'apiKey'; @@ -15,6 +17,33 @@ export class AlterAPIKeyTableAddRevoked1695740346004 implements MigrationInterfa // Remove unused apiKeyId column await queryRunner.dropColumn(table_name, 'apiKeyId'); + // Add column apiKeyHash + await queryRunner.addColumn( + table_name, + new TableColumn({ + name: 'apiKeyHash', + type: 'text', + isNullable: true, + }) + ); + // Data migration + // Make all current API keys as revoked cause we need to force API key recreation + for (const apiKey of await queryRunner.query(`SELECT * FROM "${table_name}"`)) { + await queryRunner.query( + `UPDATE "${table_name}" SET "apiKeyHash" = '${sha3_512(apiKey.apiKey)}', "revoked" = 'true' WHERE "apiKey" = '${apiKey.apiKey}'` + ); + } + // Make apiKeyHash not nullable + await queryRunner.changeColumn( + table_name, + 'apiKeyHash', + new TableColumn({ + name: 'apiKeyHash', + type: 'text', + isNullable: false, + isPrimary: true, + }) + ); } public async down(queryRunner: QueryRunner): Promise { diff --git a/src/database/types/types.ts b/src/database/types/types.ts index 7008623b..28c6fa1b 100644 --- a/src/database/types/types.ts +++ b/src/database/types/types.ts @@ -36,7 +36,7 @@ import { AlterCustomerTable1695740346000 } from '../migrations/AlterCustomerTabl import { AlterOperationTable1695740346001 } from '../migrations/AlterOperationTableNewCategory.js'; import { SubscriptionEntity } from '../entities/subscription.entity.js'; import { CreateSubscritpionTable1695740346003 } from '../migrations/CreateSubscriptionTable.js'; -import { AlterAPIKeyTableAddRevoked1695740346004 } from '../migrations/AlterAPIKeyTable.js'; +import { AlterAPIKeyTable1695740346004 } from '../migrations/AlterAPIKeyTable.js'; dotenv.config(); const { EXTERNAL_DB_CONNECTION_URL, EXTERNAL_DB_CERT } = process.env; @@ -108,7 +108,7 @@ export class Postgres implements AbstractDatabase { // Add subscription table CreateSubscritpionTable1695740346003, // Add revoked field to APIKey table - AlterAPIKeyTableAddRevoked1695740346004, + AlterAPIKeyTable1695740346004, ], entities: [ ...Entities, diff --git a/src/middleware/auth/routes/admin/admin-auth.ts b/src/middleware/auth/routes/admin/admin-auth.ts index 4c10144f..21ec9dae 100644 --- a/src/middleware/auth/routes/admin/admin-auth.ts +++ b/src/middleware/auth/routes/admin/admin-auth.ts @@ -48,6 +48,17 @@ export class AdminHandler extends BaseAuthHandler { this.registerRoute('/admin/product/list', 'GET', 'admin:product:list:mainnet', { skipNamespace: true }); this.registerRoute('/admin/product/get', 'GET', 'admin:product:get:testnet', { skipNamespace: true }); this.registerRoute('/admin/product/get', 'GET', 'admin:product:get:mainnet', { skipNamespace: true }); + // API Key + this.registerRoute('/admin/api-key/create', 'POST', 'admin:api-key:create:testnet', { skipNamespace: true }); + this.registerRoute('/admin/api-key/create', 'POST', 'admin:api-key:create:mainnet', { skipNamespace: true }); + this.registerRoute('/admin/api-key/update', 'POST', 'admin:api-key:update:testnet', { skipNamespace: true }); + this.registerRoute('/admin/api-key/update', 'POST', 'admin:api-key:update:mainnet', { skipNamespace: true }); + this.registerRoute('/admin/api-key/revoke', 'DELETE', 'admin:api-key:revoke:testnet', { skipNamespace: true }); + this.registerRoute('/admin/api-key/revoke', 'DELETE', 'admin:api-key:revoke:mainnet', { skipNamespace: true }); + this.registerRoute('/admin/api-key/get', 'GET', 'admin:api-key:get:testnet', { skipNamespace: true }); + this.registerRoute('/admin/api-key/get', 'GET', 'admin:api-key:get:mainnet', { skipNamespace: true }); + this.registerRoute('/admin/api-key/list', 'GET', 'admin:api-key:list:testnet', { skipNamespace: true }); + this.registerRoute('/admin/api-key/list', 'GET', 'admin:api-key:list:mainnet', { skipNamespace: true }); } public async handle(request: Request, response: Response): Promise { if (!request.path.includes('/admin/')) { diff --git a/src/middleware/authentication.ts b/src/middleware/authentication.ts index 227510c1..695be967 100644 --- a/src/middleware/authentication.ts +++ b/src/middleware/authentication.ts @@ -61,7 +61,7 @@ export class Authentication { new PresentationAuthHandler(), new AuthInfoHandler(), new AdminHandler(), - ]) + ]); this.isSetup = true; } diff --git a/src/services/admin/api-key.ts b/src/services/admin/api-key.ts new file mode 100644 index 00000000..185ec1c7 --- /dev/null +++ b/src/services/admin/api-key.ts @@ -0,0 +1,160 @@ +import type { Repository } from 'typeorm'; +import { decodeJWT } from 'did-jwt'; +import { randomBytes } from 'crypto'; +import { Connection } from '../../database/connection/connection.js'; + +import * as dotenv from 'dotenv'; +import type { CustomerEntity } from '../../database/entities/customer.entity.js'; +import { APIKeyEntity } from '../../database/entities/api.key.entity.js'; +import type { UserEntity } from '../../database/entities/user.entity.js'; +import { SecretBox } from '@veramo/kms-local'; +import { API_KEY_LENGTH, API_KEY_PREFIX, API_KEY_EXPIRATION } from '../../types/constants.js'; +import pkg from 'js-sha3'; +dotenv.config(); + +const { sha3_512 } = pkg; + +// Returns the decrypted API key +export function decryptAPIKey(target: any, key: string, descriptor: PropertyDescriptor | undefined) { + // save a reference to the original method this way we keep the values currently in the + // descriptor and don't overwrite what another decorator might have done to the descriptor. + if (descriptor === undefined) { + descriptor = Object.getOwnPropertyDescriptor(target, key) as PropertyDescriptor; + } + + const originalMethod = descriptor.value; + + //editing the descriptor/value parameter + descriptor.value = async function (...args: any[]) { + const decryptOne = async (entity: APIKeyEntity) => { + if (entity && entity.apiKey) { + entity.apiKey = await APIKeyService.instance.decryptAPIKey(entity.apiKey); + } + return entity; + }; + const entity = await originalMethod.apply(this, args); + if (Array.isArray(entity)) { + for (const apiKey of entity) { + await decryptOne(apiKey); + } + } else { + await decryptOne(entity); + } + return entity; + }; + + // return edited descriptor as opposed to overwriting the descriptor + return descriptor; +} + +export class APIKeyService { + public apiKeyRepository: Repository; + private secretBox: SecretBox; + + public static instance = new APIKeyService(); + + constructor() { + this.apiKeyRepository = Connection.instance.dbConnection.getRepository(APIKeyEntity); + this.secretBox = new SecretBox(process.env.EXTERNAL_DB_ENCRYPTION_KEY); + } + + // ToDo: Maybe we also need to store not the API key but the hash of it? + // But in that case the API key will be shown once and then it will be lost. + @decryptAPIKey + public async create(apiKey: string, user: UserEntity, expiresAt?: Date, revoked = false): Promise { + if (!apiKey) { + throw new Error('API key is not specified'); + } + if (!user) { + throw new Error('API key user is not specified'); + } + if (!expiresAt) { + expiresAt = new Date(); + expiresAt.setMonth(expiresAt.getMonth() + API_KEY_EXPIRATION); + } + const apiKeyHash = APIKeyService.hashAPIKey(apiKey); + const encryptedAPIKey = await this.secretBox.encrypt(apiKey); + // Create entity + const apiKeyEntity = new APIKeyEntity(apiKeyHash, encryptedAPIKey, expiresAt, user.customer, user, revoked); + const apiKeyRecord = (await this.apiKeyRepository.insert(apiKeyEntity)).identifiers[0]; + if (!apiKeyRecord) throw new Error(`Cannot create a new API key`); + return apiKeyEntity; + } + + @decryptAPIKey + public async update( + apiKey: string, + expiresAt?: Date, + revoked?: boolean, + customer?: CustomerEntity, + user?: UserEntity + ) { + const apiKeyHash = APIKeyService.hashAPIKey(apiKey); + const existingAPIKey = await this.apiKeyRepository.findOneBy({ apiKeyHash }); + if (!existingAPIKey) { + throw new Error(`API with key id ${apiKey} not found`); + } + if (expiresAt) { + existingAPIKey.expiresAt = expiresAt; + } + if (customer) { + existingAPIKey.customer = customer; + } + if (user) { + existingAPIKey.user = user; + } + if (revoked) { + existingAPIKey.revoked = revoked; + } + + const entity = await this.apiKeyRepository.save(existingAPIKey); + return entity; + } + + public async revoke(apiKey: string) { + return this.update(apiKey, undefined, true); + } + + public async decryptAPIKey(apiKey: string) { + return await this.secretBox.decrypt(apiKey); + } + + @decryptAPIKey + public async get(apiKey: string) { + const apiKeyHash = APIKeyService.hashAPIKey(apiKey); + const apiKeyEntity = await this.apiKeyRepository.findOne({ + where: { apiKeyHash: apiKeyHash }, + relations: ['customer', 'user'], + }); + return apiKeyEntity; + } + + @decryptAPIKey + public async find(where: Record, order?: Record) { + try { + const apiKeyList = await this.apiKeyRepository.find({ + where: where, + relations: ['customer', 'user'], + order: order, + }); + return apiKeyList; + } catch { + return []; + } + } + + // Utils + + public generateAPIKey(): string { + return `${API_KEY_PREFIX}_${randomBytes(API_KEY_LENGTH).toString('hex')}`; + } + + public async getExpiryDate(apiKey: string): Promise { + const decrypted = await decodeJWT(apiKey); + return new Date(decrypted.payload.exp ? decrypted.payload.exp * 1000 : 0); + } + + public static hashAPIKey(apiKey: string): string { + return sha3_512(apiKey); + } +} diff --git a/src/services/admin/stripe.ts b/src/services/admin/stripe.ts index cb27205c..bc859b2f 100644 --- a/src/services/admin/stripe.ts +++ b/src/services/admin/stripe.ts @@ -12,24 +12,23 @@ import type { NextFunction } from 'express'; dotenv.config(); export class StripeService { + submitter: SubscriptionSubmitter; + private isFullySynced = false; - submitter: SubscriptionSubmitter; - private isFullySynced = false; - - constructor() { - this.submitter = new SubscriptionSubmitter(eventTracker.getEmitter()); - } + constructor() { + this.submitter = new SubscriptionSubmitter(eventTracker.getEmitter()); + } - async syncAll(next: NextFunction): Promise { - if (!this.isFullySynced) { - await this.syncFull(); - this.isFullySynced = true; - } - next() - } + async syncAll(next: NextFunction): Promise { + if (!this.isFullySynced) { + await this.syncFull(); + this.isFullySynced = true; + } + next(); + } async syncFull(): Promise { - const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); + const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); // Sync all subscriptions for await (const subscription of stripe.subscriptions.list({ status: 'all', @@ -54,7 +53,7 @@ export class StripeService { // Sync all the subscriptions for current customer async syncCustomer(customer: CustomerEntity): Promise { - const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); + const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); for await (const subscription of stripe.subscriptions.list({ customer: customer.paymentProviderId, status: 'all', @@ -70,66 +69,68 @@ export class StripeService { } } - async syncOne(customer: CustomerEntity): Promise { - const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); - - const local = await SubscriptionService.instance.findCurrent(customer) - if (!local) { - eventTracker.notify({ - message: EventTracker.compileBasicNotification( - `Active subscription not found for customer with id ${customer.customerId}`, - 'Subscription syncronization' - ), - severity: 'debug', - }); - const activeSubs = await stripe.subscriptions.list({ - customer: customer.paymentProviderId, - status: 'active', - }); - const trialSubs = await stripe.subscriptions.list({ - customer: customer.paymentProviderId, - status: 'trialing', - }); - const subs = [...activeSubs.data, ...trialSubs.data]; - if (subs.length > 1) { - eventTracker.notify({ - message: EventTracker.compileBasicNotification( - `Multiple active subscriptions found for customer with id ${customer.customerId}`, - 'Subscription syncronization' - ), - severity: 'error', - }); - return; - } - if (subs.length > 0) { - await this.createSubscription(subs[0], customer); - } - return; - } - const subscriptionId = local.subscriptionId; - const remote = await stripe.subscriptions.retrieve(subscriptionId); - if (!remote) { - eventTracker.notify({ - message: EventTracker.compileBasicNotification( - `Subscription with id ${subscriptionId} could not be retrieved from Stripe`, - 'Subscription syncronization' - ), - severity: 'error', - }); - return; - } - const current = await SubscriptionService.instance.subscriptionRepository.findOne({ - where: { subscriptionId: remote.id }, - }); - if (current) { - await this.updateSubscription(remote, current); - } else { - await this.createSubscription(remote); - } - } + async syncOne(customer: CustomerEntity): Promise { + const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); + + const local = await SubscriptionService.instance.findCurrent(customer); + if (!local) { + eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `Active subscription not found for customer with id ${customer.customerId}`, + 'Subscription syncronization' + ), + severity: 'debug', + }); + const activeSubs = await stripe.subscriptions.list({ + customer: customer.paymentProviderId, + status: 'active', + }); + const trialSubs = await stripe.subscriptions.list({ + customer: customer.paymentProviderId, + status: 'trialing', + }); + const subs = [...activeSubs.data, ...trialSubs.data]; + if (subs.length > 1) { + eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `Multiple active subscriptions found for customer with id ${customer.customerId}`, + 'Subscription syncronization' + ), + severity: 'error', + }); + return; + } + if (subs.length > 0) { + await this.createSubscription(subs[0], customer); + } + return; + } + const subscriptionId = local.subscriptionId; + const remote = await stripe.subscriptions.retrieve(subscriptionId); + if (!remote) { + eventTracker.notify({ + message: EventTracker.compileBasicNotification( + `Subscription with id ${subscriptionId} could not be retrieved from Stripe`, + 'Subscription syncronization' + ), + severity: 'error', + }); + return; + } + const current = await SubscriptionService.instance.subscriptionRepository.findOne({ + where: { subscriptionId: remote.id }, + }); + if (current) { + await this.updateSubscription(remote, current); + } else { + await this.createSubscription(remote); + } + } async createSubscription(subscription: Stripe.Subscription, customer?: CustomerEntity): Promise { - await this.submitter.submitSubscriptionCreate(builSubmitOperation(subscription, OperationNameEnum.SUBSCRIPTION_CREATE, {customer: customer})); + await this.submitter.submitSubscriptionCreate( + builSubmitOperation(subscription, OperationNameEnum.SUBSCRIPTION_CREATE, { customer: customer }) + ); } async updateSubscription(subscription: Stripe.Subscription, current: SubscriptionEntity): Promise { @@ -144,7 +145,9 @@ export class StripeService { }); return; } - await this.submitter.submitSubscriptionUpdate(builSubmitOperation(subscription, OperationNameEnum.SUBSCRIPTION_UPDATE)); + await this.submitter.submitSubscriptionUpdate( + builSubmitOperation(subscription, OperationNameEnum.SUBSCRIPTION_UPDATE) + ); } } diff --git a/src/services/admin/subscription.ts b/src/services/admin/subscription.ts index 0d8ca45f..6e4b8eb3 100644 --- a/src/services/admin/subscription.ts +++ b/src/services/admin/subscription.ts @@ -75,7 +75,10 @@ export class SubscriptionService { public async findCurrent(customer: CustomerEntity) { return await this.subscriptionRepository.findOne({ - where: [{ customer: customer, status: 'active' }, { customer: customer, status: 'trialing' }], + where: [ + { customer: customer, status: 'active' }, + { customer: customer, status: 'trialing' }, + ], relations: ['customer'], }); } diff --git a/src/services/api/api-key.ts b/src/services/api/api-key.ts deleted file mode 100644 index d8e24773..00000000 --- a/src/services/api/api-key.ts +++ /dev/null @@ -1,111 +0,0 @@ -import type { Repository } from 'typeorm'; -import { decodeJWT } from 'did-jwt'; -import { Connection } from '../../database/connection/connection.js'; - -import * as dotenv from 'dotenv'; -import type { CustomerEntity } from '../../database/entities/customer.entity.js'; -import { APIKeyEntity } from '../../database/entities/api.key.entity.js'; -import type { UserEntity } from '../../database/entities/user.entity.js'; -import { v4 } from 'uuid'; -import { SecretBox } from '@veramo/kms-local'; -dotenv.config(); - -export class APIKeyService { - public apiKeyRepository: Repository; - private secretBox: SecretBox; - - public static instance = new APIKeyService(); - - constructor() { - this.apiKeyRepository = Connection.instance.dbConnection.getRepository(APIKeyEntity); - this.secretBox = new SecretBox(process.env.EXTERNAL_DB_ENCRYPTION_KEY) - } - - public async create(apiKey: string, customer: CustomerEntity, user: UserEntity, revoked = false): Promise { - const apiKeyId = v4(); - if (!apiKey) { - throw new Error('API key is not specified'); - } - if (!customer) { - throw new Error('API key customer is not specified'); - } - if (!user) { - throw new Error('API key user is not specified'); - } - if (!customer) { - throw new Error('Customer id is not specified'); - } - const encryptedAPIKey = await this.secretBox.encrypt(apiKey); - const expiresAt = await this.getExpiryDate(apiKey); - const apiKeyEntity = new APIKeyEntity(encryptedAPIKey, expiresAt, customer, user, revoked); - const apiKeyRecord = (await this.apiKeyRepository.insert(apiKeyEntity)).identifiers[0]; - if (!apiKeyRecord) throw new Error(`Cannot create a new API key`); - return apiKeyEntity; - } - - public async update( - apiKey: string, - expiresAt?: Date, - customer?: CustomerEntity, - user?: UserEntity, - revoked?: boolean - ) { - const existingAPIKey = await this.apiKeyRepository.findOneBy({ apiKey }); - if (!existingAPIKey) { - throw new Error(`API with key id ${apiKey} not found`); - } - if (expiresAt) { - existingAPIKey.expiresAt = expiresAt; - } - if (customer) { - existingAPIKey.customer = customer; - } - if (user) { - existingAPIKey.user = user; - } - if (revoked) { - existingAPIKey.revoked = revoked; - } - - return await this.apiKeyRepository.save(existingAPIKey); - } - - public async get(apiKey: string) { - const apiKeyEntity = await this.apiKeyRepository.findOne({ - where: { apiKey }, - relations: ['customer', 'user'], - }); - if (!apiKeyEntity) { - throw new Error(`API key ${apiKey} not found`); - } - - if (this.secretBox && apiKeyEntity.apiKey) { - apiKeyEntity.apiKey = await this.secretBox.decrypt(apiKeyEntity.apiKey); - } - return apiKeyEntity; - } - - public async find(where: Record) { - try { - const apiKeyList = await this.apiKeyRepository.find({ - where: where, - relations: ['customer', 'user'], - }); - // decrypt the API keys - if (this.secretBox) { - for (const apiKey of apiKeyList) { - apiKey.apiKey = await this.secretBox.decrypt(apiKey.apiKey); - } - } - return apiKeyList; - - } catch { - return []; - } - } - - public async getExpiryDate(apiKey: string): Promise { - const decrypted = await decodeJWT(apiKey); - return new Date(decrypted.payload.exp ? decrypted.payload.exp * 1000 : 0); - } -} diff --git a/src/services/identity/abstract.ts b/src/services/identity/abstract.ts index 5d1ee489..4b5fd4c6 100644 --- a/src/services/identity/abstract.ts +++ b/src/services/identity/abstract.ts @@ -221,6 +221,7 @@ export abstract class AbstractIdentityService implements IIdentityService { ): Promise { throw new Error(`Not supported`); } + // ToDo: All the next functions should be removed after adding new API key mechanism setAPIKey(apiKey: string, customer: CustomerEntity, user: UserEntity): Promise { throw new Error(`Not supported`); } @@ -230,4 +231,7 @@ export abstract class AbstractIdentityService implements IIdentityService { getAPIKey(customer: CustomerEntity, user: UserEntity): Promise { throw new Error(`Not supported`); } + decryptAPIKey(apiKey: string): Promise { + throw new Error(`Not supported`); + } } diff --git a/src/services/identity/index.ts b/src/services/identity/index.ts index de6bd310..7cb54abe 100644 --- a/src/services/identity/index.ts +++ b/src/services/identity/index.ts @@ -171,6 +171,7 @@ export interface IIdentityService { setAPIKey(apiKey: string, customer: CustomerEntity, user: UserEntity): Promise; updateAPIKey(apiKey: APIKeyEntity, newApiKey: string): Promise; getAPIKey(customer: CustomerEntity, user: UserEntity): Promise; + decryptAPIKey(apiKey: string): Promise; } export class IdentityServiceStrategySetup { diff --git a/src/services/identity/postgres.ts b/src/services/identity/postgres.ts index cd433ba5..8c35727b 100644 --- a/src/services/identity/postgres.ts +++ b/src/services/identity/postgres.ts @@ -48,7 +48,7 @@ import { CheqdNetwork } from '@cheqd/sdk'; import { IdentifierService } from '../api/identifier.js'; import type { KeyEntity } from '../../database/entities/key.entity.js'; import type { UserEntity } from '../../database/entities/user.entity.js'; -import { APIKeyService } from '../api/api-key.js'; +import { APIKeyService } from '../admin/api-key.js'; import type { APIKeyEntity } from '../../database/entities/api.key.entity.js'; import { KeyDIDProvider } from '@veramo/did-provider-key'; import type { AbstractIdentifierProvider } from '@veramo/did-manager'; @@ -524,35 +524,36 @@ export class PostgresIdentityService extends DefaultIdentityService { } async setAPIKey(apiKey: string, customer: CustomerEntity, user: UserEntity): Promise { - const keys = await APIKeyService.instance.find({ customer: customer, user: user }); + const keys = await APIKeyService.instance.find({ customer: customer, user: user, revoked: false }); if (keys.length > 0) { throw new Error(`API key for customer ${customer.customerId} and user ${user.logToId} already exists`); } - const apiKeyEntity = await APIKeyService.instance.create(apiKey, customer, user); + const apiKeyEntity = await APIKeyService.instance.create(apiKey, user); if (!apiKeyEntity) { throw new Error(`Cannot create API key for customer ${customer.customerId} and user ${user.logToId}`); } + apiKeyEntity.apiKey = await this.decryptAPIKey(apiKeyEntity.apiKey); return apiKeyEntity; } async updateAPIKey(apiKey: APIKeyEntity, newApiKey: string): Promise { - const key = await APIKeyService.instance.get(apiKey.apiKeyId); + const key = await APIKeyService.instance.get(apiKey.apiKey); if (!key) { - throw new Error(`API key with id ${apiKey.apiKeyId} not found`); + throw new Error(`API key not found`); } const apiKeyEntity = await APIKeyService.instance.update( - key.apiKeyId, newApiKey, await APIKeyService.instance.getExpiryDate(newApiKey) ); if (!apiKeyEntity) { - throw new Error(`Cannot update API key with id ${apiKey.apiKeyId}`); + throw new Error(`Cannot update API key`); } + apiKeyEntity.apiKey = await this.decryptAPIKey(apiKeyEntity.apiKey); return apiKeyEntity; } async getAPIKey(customer: CustomerEntity, user: UserEntity): Promise { - const keys = await APIKeyService.instance.find({ customer: customer, user: user }); + const keys = await APIKeyService.instance.find({ customer: customer, user: user, revoked: false }); if (keys.length > 1) { throw new Error( `For the customer with customer id ${customer.customerId} and user with logToId ${user.logToId} there more then 1 API key` @@ -563,4 +564,8 @@ export class PostgresIdentityService extends DefaultIdentityService { } return keys[0]; } + + async decryptAPIKey(apiKey: string): Promise { + return await APIKeyService.instance.decryptAPIKey(apiKey); + } } diff --git a/src/services/track/helpers.ts b/src/services/track/helpers.ts index 1a25fb3b..c88d7a12 100644 --- a/src/services/track/helpers.ts +++ b/src/services/track/helpers.ts @@ -35,7 +35,7 @@ export function toCoin(amount: bigint, denom = MINIMAL_DENOM): Coin { return coin(amount.toString(), denom); } -export function builSubmitOperation (subscription: Stripe.Subscription, name: string, options?: ISubmitOptions) { +export function builSubmitOperation(subscription: Stripe.Subscription, name: string, options?: ISubmitOptions) { return { operation: name, data: { @@ -49,4 +49,4 @@ export function builSubmitOperation (subscription: Stripe.Subscription, name: st } satisfies ISubmitData, options, } satisfies ISubmitOperation; -}; +} diff --git a/src/services/track/submitter.ts b/src/services/track/submitter.ts index 01796f73..207660e2 100644 --- a/src/services/track/submitter.ts +++ b/src/services/track/submitter.ts @@ -1,4 +1,4 @@ -import type { ISubmitOptions } from "./types"; +import type { ISubmitOptions } from './types'; // Type: Interface export type ISubmitData = ISubmitStripeCustomerCreateData | ISubmitSubscriptionData; diff --git a/src/static/swagger-admin-options.json b/src/static/swagger-admin-options.json index b3382775..1b041cf1 100644 --- a/src/static/swagger-admin-options.json +++ b/src/static/swagger-admin-options.json @@ -21,14 +21,11 @@ { "name": "Price" }, - { - "name": "Customer" - }, { "name": "Subscription" }, { - "name": "Checkout" + "name": "API Key" } ] } diff --git a/src/static/swagger-admin.json b/src/static/swagger-admin.json index 8b44d945..fccdefcd 100644 --- a/src/static/swagger-admin.json +++ b/src/static/swagger-admin.json @@ -1,662 +1,1020 @@ { - "openapi": "3.0.0", - "info": { - "title": "Credential Service admin API for cheqd network", - "version": "2.0.0", - "description": "Admin API which handles users subscriptions and payments", - "contact": { - "name": "Cheqd Foundation Limited", - "url": "https://github.com/cheqd/credential-service", - "email": "support-github@cheqd.io" - }, - "license": { - "name": "Apache 2.0", - "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" - } - }, - "tags": [ - { - "name": "Product" - }, - { - "name": "Price" - }, - { - "name": "Customer" - }, - { - "name": "Subscription" - }, - { - "name": "Checkout" - } - ], - "paths": { - "/admin/price/list": { - "get": { - "summary": "Get a list of prices", - "description": "Get a list of prices", - "tags": [ - "Price" - ], - "parameters": [ - { - "in": "query", - "name": "productId", - "schema": { - "type": "string", - "description": "The product id. If passed - returns filtered by this product list of prices.", - "required": false - } - } - ], - "responses": { - "200": { - "description": "A list of prices", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PriceListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/product/list": { - "get": { - "summary": "Get a list of products", - "description": "Get a list of products which are on a Stripe side", - "tags": [ - "Product" - ], - "parameters": [ - { - "in": "query", - "name": "prices", - "schema": { - "type": "boolean", - "description": "If setup to true - returns the list of products with prices inside. Default - true", - "required": false - } - } - ], - "responses": { - "200": { - "description": "A list of products", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/product/get/{productId}": { - "get": { - "summary": "Get a product", - "description": "Get a product by id", - "tags": [ - "Product" - ], - "parameters": [ - { - "in": "path", - "name": "productId", - "schema": { - "type": "string", - "description": "The product id which identifies the product in Stripe" - }, - "required": true - }, - { - "in": "query", - "name": "prices", - "schema": { - "type": "boolean", - "description": "If setup to true - returns the product with prices inside. Default - true", - "required": false - } - } - ], - "responses": { - "200": { - "description": "A product", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductGetResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/create": { - "post": { - "summary": "Create a subscription", - "description": "Creates a new subscription for an existing customer", - "tags": [ - "Subscription" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCreateRequestBody" - } - } - } - }, - "responses": { - "201": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCreateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/update": { - "post": { - "summary": "Update a subscription", - "description": "Updates an existing subscription", - "tags": [ - "Subscription" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionUpdateRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionUpdateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/list": { - "get": { - "summary": "Get a list of subscriptions", - "description": "Get a list of subscriptions", - "tags": [ - "Subscription" - ], - "parameters": [ - { - "in": "query", - "name": "paymentProviderId", - "schema": { - "type": "string", - "description": "The customer id. If passed - returns filtered by this customer list of subscriptions." - } - } - ], - "responses": { - "200": { - "description": "A list of subscriptions", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/get": { - "get": { - "summary": "Get a subscription", - "description": "Get a subscription", - "tags": [ - "Subscription" - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionGetResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/cancel": { - "post": { - "summary": "Cancel a subscription", - "description": "Cancels an existing subscription", - "tags": [ - "Subscription" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCancelRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCancelResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/resume": {}, - "post": { - "summary": "Resume a subscription", - "description": "Resumes an existing subscription", - "tags": [ - "Subscription" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionResumeRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionResumeResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "components": { - "schemas": { - "PriceListResponseBody": { - "description": "A list of active prcies from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/list)", - "type": "object", - "properties": { - "prices": { - "type": "array", - "items": { - "type": "object", - "description": "A price object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/object)" - } - } - } - }, - "ProductListResponseBody": { - "type": "object", - "properties": { - "products": { - "type": "array", - "items": { - "type": "object", - "description": "A product object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/object)" - } - } - } - }, - "ProductGetResponseBody": { - "description": "A product with or without prices inside. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/retrieve)", - "type": "object" - }, - "InvalidRequest": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "InvalidRequest" - } - } - }, - "InternalError": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Internal Error" - } - } - }, - "UnauthorizedError": { - "description": "Access token is missing or invalid", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Unauthorized Error" - } - } - }, - "SubscriptionCreateRequestBody": { - "description": "The request body for creating a subscription", - "type": "object", - "properties": { - "price": { - "type": "string", - "description": "The price id", - "example": "price_1234567890" - }, - "successURL": { - "type": "string", - "description": "The URL to redirect to after the customer sucessfully completes the checkout", - "example": "https://example.com/success" - }, - "cancelURL": { - "type": "string", - "description": "The URL to redirect to after the customer cancels the checkout", - "example": "https://example.com/cancel" - }, - "quantity": { - "type": "number", - "description": "The quantity of the product", - "example": 1 - }, - "trialPeriodDays": { - "type": "number", - "description": "The number of days the customer has to pay for the product", - "example": 7 - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": "abcdefghijklmnopqrstuvwxyz" - } - } - }, - "SubscriptionCreateResponseBody": { - "description": "The response body for creating a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "An object with link to checkout session. For more information see the [Stripe API documentation](https://docs.stripe.com/api/checkout/sessions/object)", - "properties": { - "sessionURL": { - "type": "string", - "description": "URL which user should follow to manage subscription" - } - } - } - } - }, - "SubscriptionUpdateRequestBody": { - "description": "The request body for updating a subscription", - "type": "object", - "properties": { - "returnURL": { - "type": "string", - "description": "URL which is used to redirect to the page with ability to update the subscription" - } - } - }, - "SubscriptionUpdateResponseBody": { - "description": "The response body for updating a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "Object with redirect url inside", - "properties": { - "sessionURL": { - "type": "string", - "description": "URL with session URL rediect to" - } - } - } - } - }, - "SubscriptionGetRequestBody": { - "description": "The request body for getting a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - } - } - }, - "SubscriptionGetResponseBody": { - "description": "The response body for getting a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" - } - } - }, - "SubscriptionListRequestBody": { - "description": "The request body for listing subscriptions", - "type": "object", - "properties": { - "customerId": { - "type": "string", - "description": "The Stripe customer id", - "example": "cus_1234567890" - } - } - }, - "SubscriptionListResponseBody": { - "description": "The response body for listing subscriptions", - "type": "object", - "properties": { - "subscriptions": { - "type": "array", - "items": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" - } - } - } - }, - "SubscriptionCancelRequestBody": { - "description": "The request body for canceling a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - } - } - }, - "SubscriptionCancelResponseBody": { - "description": "The response body for canceling a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": "abcdefghijklmnopqrstuvwxyz" - } - } - }, - "SubscriptionResumeRequestBody": { - "description": "The request body for resuming a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": "abcdefghijklmnopqrstuvwxyz" - } - } - }, - "SubscriptionResumeResponseBody": { - "description": "The response body for resuming a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" - } - } - }, - "NotFoundError": { - "description": "The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Not Found Error" - } - } - } - } - } -} \ No newline at end of file + "openapi": "3.0.0", + "info": { + "title": "Credential Service admin API for cheqd network", + "version": "2.0.0", + "description": "Admin API which handles users subscriptions and payments", + "contact": { + "name": "Cheqd Foundation Limited", + "url": "https://github.com/cheqd/credential-service", + "email": "support-github@cheqd.io" + }, + "license": { + "name": "Apache 2.0", + "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" + } + }, + "tags": [ + { + "name": "Product" + }, + { + "name": "Price" + }, + { + "name": "Subscription" + }, + { + "name": "API Key" + } + ], + "paths": { + "/admin/api-key/create": { + "post": { + "summary": "Create a new API key", + "description": "Create a new API key", + "tags": ["API Key"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyCreateRequestBody" + } + } + } + }, + "responses": { + "201": { + "description": "A new API key has been created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyCreateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/APIKeyCreateUnsuccessfulResponseBody" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/api-key/update": { + "post": { + "summary": "Update an existing API key", + "description": "Update an existing API key", + "tags": ["API Key"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyUpdateRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The API key has been updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyUpdateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/APIKeyUpdateUnsuccessfulResponseBody" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/api-key/revoke": { + "delete": { + "summary": "Revoke an existing API key", + "description": "Revoke an existing API key", + "tags": ["API Key"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyRevokeRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The API key has been revoked", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyRevokeResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/APIKeyRevokeUnsuccessfulResponseBody" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/api-key/list": { + "get": { + "summary": "List all API keys", + "description": "List all API keys", + "tags": ["API Key"], + "responses": { + "200": { + "description": "A list of API keys", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/api-key/get": { + "get": { + "summary": "Get an API key", + "description": "Get an API key. If the API key is not provided, the latest not revoked API key it returns.", + "tags": ["API Key"], + "parameters": [ + { + "name": "apiKey", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyGetResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/price/list": { + "get": { + "summary": "Get a list of prices", + "description": "Get a list of prices", + "tags": ["Price"], + "parameters": [ + { + "in": "query", + "name": "productId", + "schema": { + "type": "string", + "description": "The product id. If passed - returns filtered by this product list of prices.", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A list of prices", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PriceListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/product/list": { + "get": { + "summary": "Get a list of products", + "description": "Get a list of products which are on a Stripe side", + "tags": ["Product"], + "parameters": [ + { + "in": "query", + "name": "prices", + "schema": { + "type": "boolean", + "description": "If setup to true - returns the list of products with prices inside. Default - true", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A list of products", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProductListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/product/get/{productId}": { + "get": { + "summary": "Get a product", + "description": "Get a product by id", + "tags": ["Product"], + "parameters": [ + { + "in": "path", + "name": "productId", + "schema": { + "type": "string", + "description": "The product id which identifies the product in Stripe" + }, + "required": true + }, + { + "in": "query", + "name": "prices", + "schema": { + "type": "boolean", + "description": "If setup to true - returns the product with prices inside. Default - true", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A product", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProductGetResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/create": { + "post": { + "summary": "Create a subscription", + "description": "Creates a new subscription for an existing customer", + "tags": ["Subscription"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCreateRequestBody" + } + } + } + }, + "responses": { + "201": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCreateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/update": { + "post": { + "summary": "Update a subscription", + "description": "Updates an existing subscription", + "tags": ["Subscription"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionUpdateRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionUpdateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/list": { + "get": { + "summary": "Get a list of subscriptions", + "description": "Get a list of subscriptions", + "tags": ["Subscription"], + "parameters": [ + { + "in": "query", + "name": "paymentProviderId", + "schema": { + "type": "string", + "description": "The customer id. If passed - returns filtered by this customer list of subscriptions." + } + } + ], + "responses": { + "200": { + "description": "A list of subscriptions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/get": { + "get": { + "summary": "Get a subscription", + "description": "Get a subscription", + "tags": ["Subscription"], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionGetResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/cancel": { + "post": { + "summary": "Cancel a subscription", + "description": "Cancels an existing subscription", + "tags": ["Subscription"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCancelRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCancelResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/resume": {}, + "post": { + "summary": "Resume a subscription", + "description": "Resumes an existing subscription", + "tags": ["Subscription"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionResumeRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionResumeResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "components": { + "schemas": { + "PriceListResponseBody": { + "description": "A list of active prcies from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/list)", + "type": "object", + "properties": { + "prices": { + "type": "array", + "items": { + "type": "object", + "description": "A price object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/object)" + } + } + } + }, + "ProductListResponseBody": { + "type": "object", + "properties": { + "products": { + "type": "array", + "items": { + "type": "object", + "description": "A product object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/object)" + } + } + } + }, + "ProductGetResponseBody": { + "description": "A product with or without prices inside. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/retrieve)", + "type": "object" + }, + "InvalidRequest": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "InvalidRequest" + } + } + }, + "InternalError": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Internal Error" + } + } + }, + "UnauthorizedError": { + "description": "Access token is missing or invalid", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Unauthorized Error" + } + } + }, + "SubscriptionCreateRequestBody": { + "description": "The request body for creating a subscription", + "type": "object", + "properties": { + "price": { + "type": "string", + "description": "The price id", + "example": "price_1234567890" + }, + "successURL": { + "type": "string", + "description": "The URL to redirect to after the customer sucessfully completes the checkout", + "example": "https://example.com/success" + }, + "cancelURL": { + "type": "string", + "description": "The URL to redirect to after the customer cancels the checkout", + "example": "https://example.com/cancel" + }, + "quantity": { + "type": "number", + "description": "The quantity of the product", + "example": 1 + }, + "trialPeriodDays": { + "type": "number", + "description": "The number of days the customer has to pay for the product", + "example": 7 + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": "abcdefghijklmnopqrstuvwxyz" + } + } + }, + "SubscriptionCreateResponseBody": { + "description": "The response body for creating a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "An object with link to checkout session. For more information see the [Stripe API documentation](https://docs.stripe.com/api/checkout/sessions/object)", + "properties": { + "sessionURL": { + "type": "string", + "description": "URL which user should follow to manage subscription" + } + } + } + } + }, + "SubscriptionUpdateRequestBody": { + "description": "The request body for updating a subscription", + "type": "object", + "properties": { + "returnURL": { + "type": "string", + "description": "URL which is used to redirect to the page with ability to update the subscription" + } + } + }, + "SubscriptionUpdateResponseBody": { + "description": "The response body for updating a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "Object with redirect url inside", + "properties": { + "sessionURL": { + "type": "string", + "description": "URL with session URL rediect to" + } + } + } + } + }, + "SubscriptionGetRequestBody": { + "description": "The request body for getting a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + } + } + }, + "SubscriptionGetResponseBody": { + "description": "The response body for getting a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" + } + } + }, + "SubscriptionListRequestBody": { + "description": "The request body for listing subscriptions", + "type": "object", + "properties": { + "customerId": { + "type": "string", + "description": "The Stripe customer id", + "example": "cus_1234567890" + } + } + }, + "SubscriptionListResponseBody": { + "description": "The response body for listing subscriptions", + "type": "object", + "properties": { + "subscriptions": { + "type": "array", + "items": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + } + } + } + }, + "SubscriptionCancelRequestBody": { + "description": "The request body for canceling a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + } + } + }, + "SubscriptionCancelResponseBody": { + "description": "The response body for canceling a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": "abcdefghijklmnopqrstuvwxyz" + } + } + }, + "SubscriptionResumeRequestBody": { + "description": "The request body for resuming a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": "abcdefghijklmnopqrstuvwxyz" + } + } + }, + "SubscriptionResumeResponseBody": { + "description": "The response body for resuming a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + } + } + }, + "APIKeyCreateRequestBody": { + "description": "The request body for creating an API key", + "type": "object", + "properties": { + "expiresAt": { + "type": "string", + "description": "The expiration date of the API key", + "example": "2000-10-31T01:30:00.000-05:00", + "format": "date", + "required": false + } + } + }, + "APIKeyCreateResponseBody": { + "description": "The response body for creating an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + }, + "expiresAt": { + "type": "string", + "description": "The expiration date of the API key", + "example": "2000-10-31T01:30:00.000-05:00", + "format": "date" + }, + "revoked": { + "type": "boolean", + "description": "The status of the API key", + "example": false + } + } + }, + "APIKeyCreateUnsuccessfulResponseBody": { + "description": "The response body for an unsuccessful API key creation", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "API key creation unsuccessful" + } + } + }, + "APIKeyUpdateRequestBody": { + "description": "The request body for updating an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz", + "required": true + }, + "expiresAt": { + "type": "string", + "description": "The expiration date of the API key", + "example": "2000-10-31T01:30:00.000-05:00", + "format": "date", + "required": false + }, + "revoked": { + "type": "boolean", + "description": "The status of the API key", + "example": false, + "required": false, + "default": false + } + } + }, + "APIKeyUpdateResponseBody": { + "description": "The response body for an unsuccessful API key update", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + }, + "expiresAt": { + "type": "string", + "description": "The expiration date of the API key", + "example": "2000-10-31T01:30:00.000-05:00", + "format": "date" + }, + "revoked": { + "type": "boolean", + "description": "The status of the API key", + "example": false + } + } + }, + "APIKeyRevokeRequestBody": { + "description": "The request body for revoking an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz", + "required": true + } + } + }, + "APIKeyRevokeResponseBody": { + "description": "The response body for revoking an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz", + "required": true + }, + "revoked": { + "type": "boolean", + "description": "The status of the API key", + "example": true + } + } + }, + "APIKeyRevokeUnsuccessfulResponseBody": { + "description": "The response body for an unsuccessful API key revocation", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "API key revocation unsuccessful" + } + } + }, + "APIKeyListResponseBody": { + "description": "The response body for listing API keys", + "type": "object", + "properties": { + "apiKeys": { + "type": "array", + "items": { + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + }, + "expiresAt": { + "type": "string", + "description": "The expiration date of the API key", + "example": "2000-10-31T01:30:00.000-05:00", + "format": "date" + }, + "revoked": { + "type": "boolean", + "description": "The status of the API key", + "example": false + } + } + } + } + } + }, + "APIKeyGetRequestBody": { + "description": "The request body for getting an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz", + "required": false + } + } + }, + "APIKeyGetResponseBody": { + "description": "The response body for getting an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + }, + "expiresAt": { + "type": "string", + "description": "The expiration date of the API key", + "example": "2000-10-31T01:30:00.000-05:00", + "format": "date" + }, + "revoked": { + "type": "boolean", + "description": "The status of the API key", + "example": false + } + } + }, + "NotFoundError": { + "description": "The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Not Found Error" + } + } + } + } + } +} diff --git a/src/static/swagger-api.json b/src/static/swagger-api.json index d8d26cfe..b2cf4b99 100644 --- a/src/static/swagger-api.json +++ b/src/static/swagger-api.json @@ -1,3549 +1,3334 @@ { - "openapi": "3.0.0", - "info": { - "title": "Credential Service API for cheqd network", - "version": "2.0.0", - "description": "API service to create and manage DIDs, Verifiable Credentials, and DID-Linked Resources", - "contact": { - "name": "Cheqd Foundation Limited", - "url": "https://github.com/cheqd/credential-service", - "email": "support-github@cheqd.io" - }, - "license": { - "name": "Apache 2.0", - "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" - } - }, - "tags": [ - { - "name": "Account" - }, - { - "name": "Key" - }, - { - "name": "DID" - }, - { - "name": "Resource" - }, - { - "name": "Credential" - }, - { - "name": "Presentation" - }, - { - "name": "Credential Status" - } - ], - "externalDocs": { - "description": "Credential Service API Documentation", - "url": "https://docs.cheqd.io/identity" - }, - "paths": { - "/account": { - "get": { - "tags": [ - "Account" - ], - "summary": "Fetch custodian-mode client details.", - "description": "This endpoint returns the custodian-mode client details for authenticated users.", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Customer" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/account/idtoken": { - "get": { - "tags": [ - "Account" - ], - "summary": "Fetch IdToken.", - "description": "This endpoint returns IdToken as JWT with list of user roles inside", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "idToken": { - "type": "string" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/account/create": { - "post": { - "tags": [ - "Account" - ], - "summary": "Create an client for an authenticated user.", - "description": "This endpoint creates a client in the custodian-mode for an authenticated user", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/AccountCreateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountCreateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "idToken": { - "type": "string" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/create/unencrypted": { - "post": { - "tags": [ - "Credential Status" - ], - "summary": "Create an unencrypted StatusList2021 credential status list.", - "description": "This endpoint creates an unencrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", - "parameters": [ - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", - "required": true, - "schema": { - "type": "string", - "enum": [ - "revocation", - "suspension" - ] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/create/encrypted": { - "post": { - "tags": [ - "Credential Status" - ], - "summary": "Create an encrypted StatusList2021 credential status list.", - "description": "This endpoint creates an encrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", - "parameters": [ - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", - "required": true, - "schema": { - "type": "string", - "enum": [ - "revocation", - "suspension" - ] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateEncryptedFormRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateEncryptedJsonRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateEncryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/update/unencrypted": { - "post": { - "tags": [ - "Credential Status" - ], - "summary": "Update an existing unencrypted StatusList2021 credential status list.", - "parameters": [ - { - "in": "query", - "name": "statusAction", - "description": "The update action to be performed on the unencrypted status list, can be revoke, suspend or reinstate", - "required": true, - "schema": { - "type": "string", - "enum": [ - "revoke", - "suspend", - "reinstate" - ] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/update/encrypted": { - "post": { - "tags": [ - "Credential Status" - ], - "summary": "Update an existing encrypted StatusList2021 credential status list.", - "parameters": [ - { - "in": "query", - "name": "statusAction", - "description": "The update action to be performed on the encrypted status list, can be revoke, suspend or reinstate", - "required": true, - "schema": { - "type": "string", - "enum": [ - "revoke", - "suspend", - "reinstate" - ] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedFormRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedJsonRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/check": { - "post": { - "tags": [ - "Credential Status" - ], - "summary": "Check a StatusList2021 index for a given Verifiable Credential.", - "description": "This endpoint checks a StatusList2021 index for a given Verifiable Credential and reports whether it is revoked or suspended. It offers a standalone method for checking an index without passing the entire Verifiable Credential or Verifiable Presentation.", - "parameters": [ - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension.", - "required": true, - "schema": { - "type": "string", - "enum": [ - "revocation", - "suspension" - ] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCheckRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCheckRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCheckResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/search": { - "get": { - "tags": [ - "Credential Status" - ], - "summary": "Fetch StatusList2021 DID-Linked Resource based on search criteria.", - "parameters": [ - { - "in": "query", - "name": "did", - "description": "The DID of the issuer of the status list.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension.", - "schema": { - "type": "string", - "enum": [ - "revocation", - "suspension" - ] - } - }, - { - "in": "query", - "name": "statusListName", - "description": "The name of the StatusList2021 DID-Linked Resource.", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusListSearchResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/issue": { - "post": { - "tags": [ - "Credential" - ], - "summary": "Issue a Verifiable Credential", - "description": "This endpoint issues a Verifiable Credential. As input it takes the list of issuerDid, subjectDid, attributes, and other parameters of the credential to be issued.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Credential" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/verify": { - "post": { - "tags": [ - "Credential" - ], - "summary": "Verify a Verifiable Credential.", - "description": "This endpoint verifies a Verifiable Credential passed to it. As input, it can take the VC-JWT as a string or the entire credential itself.", - "operationId": "verify", - "parameters": [ - { - "in": "query", - "name": "verifyStatus", - "description": "If set to `true` the verification will also check the status of the credential. Requires the VC to have a `credentialStatus` property.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "fetchRemoteContexts", - "description": "When dealing with JSON-LD you also MUST provide the proper contexts. Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "allowDeactivatedDid", - "description": "If set to `true` allow to verify credential which based on deactivated DID.", - "schema": { - "type": "boolean", - "default": false - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialVerifyRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialVerifyRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/VerifyCredentialResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/revoke": { - "post": { - "tags": [ - "Credential" - ], - "summary": "Revoke a Verifiable Credential.", - "description": "This endpoint revokes a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself. The StatusList2021 resource should already be setup in the VC and `credentialStatus` property present in the VC.", - "operationId": "revoke", - "parameters": [ - { - "in": "query", - "name": "publish", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RevocationResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/suspend": { - "post": { - "tags": [ - "Credential" - ], - "summary": "Suspend a Verifiable Credential.", - "description": "This endpoint suspends a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself.", - "operationId": "suspend", - "parameters": [ - { - "in": "query", - "name": "publish", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "schema": { - "type": "boolean" - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuspensionResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/reinstate": { - "post": { - "tags": [ - "Credential" - ], - "summary": "Reinstate a suspended Verifiable Credential.", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "operationId": "reinstate", - "parameters": [ - { - "in": "query", - "name": "publish", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "schema": { - "type": "boolean" - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnsuspensionResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/create": { - "post": { - "tags": [ - "DID" - ], - "summary": "Create a DID Document.", - "description": "This endpoint creates a DID and associated DID Document. As input, it can take the DID Document parameters via a form, or the fully-assembled DID Document itself.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidCreateRequestFormBased" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidCreateRequestJson" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/did/update": { - "post": { - "tags": [ - "DID" - ], - "summary": "Update a DID Document.", - "description": "This endpoint updates a DID Document. As an input, it can take JUST the sections/parameters that need to be updated in the DID Document (in this scenario, it fetches the current DID Document and applies the updated section). Alternatively, it take the fully-assembled DID Document with updated sections as well as unchanged sections.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidUpdateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidUpdateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidUpdateResponse" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/import": { - "post": { - "tags": [ - "DID" - ], - "summary": "Import a DID Document.", - "description": "This endpoint imports a decentralized identifier associated with the user's account for custodian-mode clients.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidImportRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidImportRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/did/deactivate/{did}": { - "post": { - "tags": [ - "DID" - ], - "summary": "Deactivate a DID Document.", - "description": "This endpoint deactivates a DID Document by taking the DID identifier as input. Must be called and signed by the DID owner.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier to deactivate.", - "schema": { - "type": "string" - }, - "required": true - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidDeactivateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidDeactivateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeactivatedDidResolution" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/list": { - "get": { - "tags": [ - "DID" - ], - "summary": "Fetch DIDs associated with an account.", - "description": "This endpoint returns the list of DIDs controlled by the account.", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/search/{did}": { - "get": { - "tags": [ - "DID" - ], - "summary": "Resolve a DID Document.", - "description": "Resolve a DID Document by DID identifier. Also supports DID Resolution Queries as defined in the W3C DID Resolution specification.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier to resolve.", - "schema": { - "type": "string" - }, - "required": true, - "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - { - "in": "query", - "name": "metadata", - "description": "Return only metadata of DID Document instead of actual DID Document.", - "schema": { - "type": "boolean" - } - }, - { - "in": "query", - "name": "versionId", - "description": "Unique UUID version identifier of DID Document. Allows for fetching a specific version of the DID Document. See cheqd DID Method Specification for more details.", - "schema": { - "type": "string", - "format": "uuid" - }, - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - { - "in": "query", - "name": "versionTime", - "description": "Returns the closest version of the DID Document *at* or *before* specified time. See DID Resolution handling for `did:cheqd` for more details.", - "schema": { - "type": "string", - "format": "date-time" - }, - "example": "1970-01-01T00:00:00Z" - }, - { - "in": "query", - "name": "transformKeys", - "description": "This directive transforms the Verification Method key format from the version in the DID Document to the specified format chosen below.", - "schema": { - "type": "string", - "enum": [ - "Ed25519VerificationKey2018", - "Ed25519VerificationKey2020", - "JsonWebKey2020" - ] - } - }, - { - "in": "query", - "name": "service", - "description": "Query DID Document for a specific Service Endpoint by Service ID (e.g., `service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`). This will typically redirect to the Service Endpoint based on DID Resolution specification algorithm.", - "schema": { - "type": "string" - }, - "example": "service-1" - }, - { - "in": "query", - "name": "relativeRef", - "description": "Relative reference is a query fragment appended to the Service Endpoint URL. **Must** be used along with the `service` query property above. See DID Resolution specification algorithm for more details.", - "schema": { - "type": "string" - }, - "example": "/path/to/file" - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidResolution" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/key/create": { - "post": { - "tags": [ - "Key" - ], - "summary": "Create an identity key pair.", - "description": "This endpoint creates an identity key pair associated with the user's account for custodian-mode clients.", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/key/import": { - "post": { - "tags": [ - "Key" - ], - "summary": "Import an identity key pair.", - "description": "This endpoint imports an identity key pair associated with the user's account for custodian-mode clients.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/KeyImportRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyImportRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/key/read/{kid}": { - "get": { - "tags": [ - "Key" - ], - "summary": "Fetch an identity key pair.", - "description": "This endpoint fetches an identity key pair's details for a given key ID. Only the user account associated with the custodian-mode client can fetch the key pair.", - "parameters": [ - { - "name": "kid", - "description": "Key ID of the identity key pair to fetch.", - "in": "path", - "schema": { - "type": "string" - }, - "required": true - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/presentation/create": { - "post": { - "tags": [ - "Presentation" - ], - "summary": "!!! WARN. Such endpoint is made mostly for testing purposes and it is not supposed to be used in production !!! Create a Verifiable Presentation from credential(s).", - "description": "This endpoint creates a Verifiable Presentation from credential(s). As input, it can take the credential(s) as a string or the entire credential(s) itself. \n !!! WARN. Such endpoint is made only for testing purposes !!!", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/PresentationCreateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/PresentationCreateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PresentationCreateResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/presentation/verify": { - "post": { - "tags": [ - "Presentation" - ], - "summary": "Verify a Verifiable Presentation generated from credential(s).", - "description": "This endpoint verifies the Verifiable Presentation generated from credential(s). As input, it can take the Verifiable Presentation JWT as a string or the entire Verifiable Presentation itself.", - "parameters": [ - { - "in": "query", - "name": "verifyStatus", - "description": "If set to `true` the verification will also check the status of the presentation. Requires the VP to have a `credentialStatus` property.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "fetchRemoteContexts", - "description": "When dealing with JSON-LD you also MUST provide the proper contexts. * Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "allowDeactivatedDid", - "description": "If set to `true` allow to verify credential which based on deactivated DID.", - "schema": { - "type": "boolean", - "default": false - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/PresentationVerifyRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/PresentationVerifyRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/VerifyPresentationResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/resource/create/{did}": { - "post": { - "tags": [ - "Resource" - ], - "summary": "Create a DID-Linked Resource.", - "description": "This endpoint creates a DID-Linked Resource. As input, it can take the DID identifier and the resource parameters via a form, or the fully-assembled resource itself.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier to link the resource to.", - "schema": { - "type": "string" - }, - "required": true - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CreateResourceRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateResourceRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ResourceMetadata" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/resource/search/{did}": { - "get": { - "tags": [ - "Resource" - ], - "summary": "Get a DID-Linked Resource.", - "description": "This endpoint returns the DID-Linked Resource for a given DID identifier and resource identifier.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier", - "schema": { - "type": "string" - }, - "required": true, - "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - { - "in": "query", - "name": "resourceId", - "description": "Fetch a DID-Linked Resource by Resource ID unique identifier. Since this is a unique identifier, other Resource query parameters are not required. See DID-Linked Resources for more details.", - "schema": { - "type": "string", - "format": "uuid" - }, - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - { - "in": "query", - "name": "resourceName", - "description": "Filter a DID-Linked Resource query by Resource Name. See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "cheqd-issuer-logo" - }, - { - "in": "query", - "name": "resourceType", - "description": "Filter a DID-Linked Resource query by Resource Type. See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "CredentialArtwork" - }, - { - "in": "query", - "name": "resourceVersion", - "description": "Filter a DID-Linked Resource query by Resource Version, which is an optional free-text field used by issuers (e.g., \"v1\", \"Final Version\", \"1st January 1970\" etc). See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "v1" - }, - { - "in": "query", - "name": "resourceVersionTime", - "description": "Filter a DID-Linked Resource query which returns the closest version of the Resource *at* or *before* specified time. See DID-Linked Resources for more details.", - "schema": { - "type": "string", - "format": "date-time" - }, - "example": "1970-01-01T00:00:00Z" - }, - { - "in": "query", - "name": "checksum", - "description": "Request integrity check against a given DID-Linked Resource by providing a SHA-256 checksum hash. See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "dc64474d062ed750a66bad58cb609928de55ed0d81defd231a4a4bf97358e9ed" - }, - { - "in": "query", - "name": "resourceMetadata", - "description": "Return only metadata of DID-Linked Resource instead of actual DID-Linked Resource. Mutually exclusive with some of the other parameters.", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "any": { - "schema": { - "type": "object" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - } - }, - "components": { - "schemas": { - "AlsoKnownAs": { - "type": "object", - "properties": { - "alsoKnownAs": { - "type": "array", - "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", - "items": { - "type": "object", - "properties": { - "uri": { - "type": "string", - "format": "uri", - "description": "URI where the DID-Linked Resource can be fetched from. Can be any type of URI (e.g., DID, HTTPS, IPFS, etc.)" - }, - "description": { - "type": "string", - "description": "Optional description of the URI." - } - } - } - } - } - }, - "CredentialRequest": { - "description": "Input fields for the creating a Verifiable Credential.", - "type": "object", - "additionalProperties": false, - "properties": { - "issuerDid": { - "description": "DID of the Verifiable Credential issuer. This needs to be a `did:cheqd` DID.", - "type": "string", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "subjectDid": { - "description": "DID of the Verifiable Credential holder/subject. This needs to be a `did:key` DID.", - "type": "string", - "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" - }, - "attributes": { - "description": "JSON object containing the attributes to be included in the credential.", - "type": "object", - "example": { - "name": "Bob", - "gender": "male" - } - }, - "@context": { - "description": "Optional properties to be included in the `@context` property of the credential.", - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "https://schema.org/schema.jsonld", - "https://veramo.io/contexts/profile/v1" - ] - }, - "type": { - "description": "Optional properties to be included in the `type` property of the credential.", - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "Person" - ] - }, - "expirationDate": { - "description": "Optional expiration date according to the VC Data Model specification.", - "type": "string", - "format": "date-time", - "example": "2023-06-08T13:49:28.000Z" - }, - "format": { - "description": "Format of the Verifiable Credential. Defaults to VC-JWT.", - "type": "string", - "enum": [ - "jwt", - "jsonld" - ], - "example": "jwt" - }, - "credentialStatus": { - "description": "Optional `credentialStatus` properties for VC revocation or suspension. Takes `statusListName` and `statusListPurpose` as inputs.", - "type": "object", - "required": [ - "statusPurpose", - "statusListName" - ], - "properties": { - "statusPurpose": { - "type": "string", - "enum": [ - "revocation", - "suspension" - ] - }, - "statusListName": { - "type": "string" - }, - "statusListIndex": { - "type": "number" - }, - "statusListVersion": { - "type": "string", - "format": "date-time" - }, - "statusListRangeStart": { - "type": "number" - }, - "statusListRangeEnd": { - "type": "number" - }, - "indexNotIn": { - "type": "number" - } - }, - "example": { - "statusPurpose": "revocation", - "statusListName": "employee-credentials" - } - } - }, - "required": [ - "issuerDid", - "subjectDid", - "attributes" - ], - "example": { - "issuerDid": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "subjectDid": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", - "attributes": { - "gender": "male", - "name": "Bob" - }, - "@context": [ - "https://schema.org" - ], - "type": [ - "Person" - ], - "format": "jwt", - "credentialStatus": { - "statusPurpose": "revocation", - "statusListName": "employee-credentials", - "statusListIndex": 10 - } - } - }, - "Credential": { - "description": "Input fields for revoking/suspending a Verifiable Credential.", - "type": "object", - "additionalProperties": false, - "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "https://www.w3.org/2018/credentials/v1", - "https://schema.org", - "https://veramo.io/contexts/profile/v1" - ] - }, - "type": { - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "VerifiableCredential", - "Person" - ] - }, - "expirationDate": { - "type": "string", - "format": "date-time", - "example": "2023-06-08T13:49:28.000Z" - }, - "issuer": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "DID", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - } - } - }, - "credentialSubject": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "DID", - "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" - } - } - }, - "credentialStatus": { - "type": "object", - "properties": { - "id": { - "type": "string", - "example": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20" - }, - "statusListIndex": { - "type": "number", - "example": 20 - }, - "statusPurpose": { - "type": "string", - "enum": [ - "revocation", - "suspension" - ], - "example": "suspension" - }, - "type": { - "type": "string", - "enum": [ - "StatusList2021Entry" - ] - } - } - }, - "issuanceDate": { - "type": "string", - "format": "date-time", - "example": "2023-06-08T13:49:28.000Z" - }, - "proof": { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "jwt": { - "type": "string" - } - }, - "example": { - "type": "JwtProof2020", - "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg" - } - } - }, - "example": { - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://schema.org", - "https://veramo.io/contexts/profile/v1" - ], - "credentialSubject": { - "gender": "male", - "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", - "name": "Bob" - }, - "credentialStatus": { - "id": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20", - "statusIndex": 20, - "statusPurpose": "suspension", - "type": "StatusList2021Entry" - }, - "issuanceDate": "2023-06-08T13:49:28.000Z", - "issuer": { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "proof": { - "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg", - "type": "JwtProof2020" - }, - "type": [ - "VerifiableCredential", - "Person" - ] - } - }, - "CredentialRevokeRequest": { - "type": "object", - "properties": { - "credential": { - "description": "Verifiable Credential to be revoked as a VC-JWT string or a JSON object.", - "oneOf": [ - { - "type": "object" - }, - { - "type": "string" - } - ] - }, - "symmetricKey": { - "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource. Required if the StatusList2021 DID-Linked Resource is encrypted.", - "type": "string" - } - } - }, - "RevocationResult": { - "properties": { - "revoked": { - "type": "boolean", - "example": true - } - } - }, - "SuspensionResult": { - "properties": { - "suspended": { - "type": "boolean", - "example": true - } - } - }, - "UnsuspensionResult": { - "properties": { - "unsuspended": { - "type": "boolean", - "example": true - } - } - }, - "CredentialVerifyRequest": { - "type": "object", - "properties": { - "credential": { - "description": "Verifiable Credential to be verified as a VC-JWT string or a JSON object.", - "type": "object" - }, - "policies": { - "description": "Custom verification policies to execute when verifying credential.", - "type": "object", - "properties": { - "issuanceDate": { - "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "expirationDate": { - "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "audience": { - "description": "Policy to skip the audience check when set to `false`.", - "type": "boolean", - "default": false - } - } - } - } - }, - "VerifyPresentationResult": { - "type": "object", - "properties": { - "verified": { - "type": "boolean" - }, - "issuer": { - "type": "string" - }, - "signer": { - "type": "object" - }, - "jwt": { - "type": "string" - }, - "verifiableCredential": { - "type": "object" - } - } - }, - "VerifyCredentialResult": { - "type": "object", - "properties": { - "verified": { - "type": "boolean" - }, - "issuer": { - "type": "string" - }, - "signer": { - "type": "object" - }, - "jwt": { - "type": "string" - }, - "verifiableCredential": { - "type": "object" - } - }, - "example": { - "verified": true, - "polices": {}, - "issuer": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "signer": { - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", - "type": "Ed25519VerificationKey2018" - } - } - }, - "PresentationCreateRequest": { - "type": "object", - "required": [ - "credentials" - ], - "properties": { - "credentials": { - "description": "Verifiable Credentials to be used for VP-JWT creation as a VP-JWT strings or a JSON objectsf.", - "type": "array", - "items": { - "type": "object" - } - }, - "holderDid": { - "description": "DID of holder", - "type": "string" - }, - "verifierDid": { - "description": "DID of verifier", - "type": "string" - } - } - }, - "PresentationVerifyRequest": { - "type": "object", - "required": [ - "presentation" - ], - "properties": { - "presentation": { - "description": "Verifiable Presentation to be verified as a VP-JWT string or a JSON object.", - "type": "object" - }, - "verifierDid": { - "description": "Provide an optional verifier DID (also known as 'domain' parameter), if the verifier DID in the presentation is not managed in the wallet.", - "type": "string" - }, - "makeFeePayment": { - "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", - "type": "boolean", - "default": false - }, - "policies": { - "description": "Custom verification policies to execute when verifying presentation.", - "type": "object", - "properties": { - "issuanceDate": { - "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "expirationDate": { - "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "audience": { - "description": "Policy to skip the audience check when set to `false`.", - "type": "boolean", - "default": false - } - } - } - } - }, - "CredentialStatusCreateBody": { - "allOf": [ - { - "type": "object", - "required": [ - "did", - "statusListName" - ], - "properties": { - "did": { - "description": "DID of the StatusList2021 publisher.", - "type": "string", - "format": "uri" - }, - "statusListName": { - "description": "The name of the StatusList2021 DID-Linked Resource to be created.", - "type": "string" - }, - "length": { - "description": "The length of the status list to be created. The default and minimum length is 140000 which is 16kb.", - "type": "integer", - "minimum": 0, - "exclusiveMinimum": true, - "default": 140000 - }, - "encoding": { - "description": "The encoding format of the StatusList2021 DiD-Linked Resource to be created.", - "type": "string", - "default": "base64url", - "enum": [ - "base64url", - "base64", - "hex" - ] - }, - "statusListVersion": { - "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - { - "$ref": "#/components/schemas/AlsoKnownAs" - } - ] - }, - "CredentialStatusCreateUnencryptedRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCreateBody" - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials", - "length": 140000, - "encoding": "base64url" - } - }, - "CredentialStatusUnencryptedResult": { - "type": "object", - "properties": { - "resource": { - "type": "object", - "properties": { - "StatusList2021": { - "type": "object", - "properties": { - "encodedList": { - "type": "string", - "example": "H4sIAAAAAAAAA-3BAQ0AAADCoPdPbQ8HFAAAAAAAAAAAAAAAAAAAAADwaDhDr_xcRAAA" - }, - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "validFrom": { - "type": "string", - "format": "date-time", - "example": "2023-06-26T11:45:19.349Z" - } - } - }, - "metadata": { - "type": "object", - "properties": { - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "encoding": { - "type": "string", - "example": "base64url" - }, - "encrypted": { - "type": "boolean", - "example": false - } - } - } - } - }, - "resourceMetadata": { - "type": "object", - "example": { - "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceName": "cheqd-employee-credentials", - "resourceType": "StatusList2021Revocation", - "mediaType": "application/json", - "resourceVersion": "1.0.0", - "created": "2023-06-26T11:45:20Z", - "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", - "previousVersionId": null, - "nextVersionId": null - } - } - } - }, - "CredentialStatusCreateUnencryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "created": { - "type": "boolean", - "example": true - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" - } - ] - }, - "CredentialStatusEncryptedPaymentConditionsBody": { - "type": "object", - "properties": { - "feePaymentAddress": { - "description": "The cheqd/Cosmos payment address where payments to unlock the encrypted StatusList2021 DID-Linked Resource need to be sent.", - "type": "string", - "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" - }, - "feePaymentAmount": { - "description": "Amount in CHEQ tokens to unlock the encrypted StatusList2021 DID-Linked Resource.", - "type": "number", - "minimum": 0, - "exclusiveMinimum": true, - "default": 20 - }, - "feePaymentWindow": { - "description": "Time window (in minutes) within which the payment to unlock the encrypted StatusList2021 DID-Linked Resource is considered valid.", - "type": "number", - "minimum": 0, - "exclusiveMinimum": true, - "default": 10 - } - } - }, - "CredentialStatusEncryptedPaymentConditionsJson": { - "type": "object", - "properties": { - "paymentConditions": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" - } - ] - } - } - }, - "CredentialStatusCreateEncryptedFormRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCreateBody" - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" - }, - { - "type": "object", - "required": [ - "feePaymentAddress", - "feePaymentAmount", - "feePaymentWindow" - ] - } - ] - }, - "CredentialStatusCreateEncryptedJsonRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCreateBody" - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" - }, - { - "type": "object", - "required": [ - "paymentConditions" - ] - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials-encrypted", - "paymentConditions": [ - { - "feePaymentAddress": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg", - "feePaymentAmount": 20, - "feePaymentWindow": 10 - } - ] - } - }, - "CredentialStatusEncryptedResult": { - "type": "object", - "properties": { - "resource": { - "type": "object", - "properties": { - "StatusList2021": { - "type": "object", - "properties": { - "encodedList": { - "type": "string", - "example": "496fdfbeb745b4db03fcdb40566f9c4c4a1c0f184b31255e641b6e7bdfb9b6946c12be87ca3763be0393c00b67ac1e8737c106b32f46ef59c765754415b5e8cc7c65fccaa3374620430ea476301a5e0dd63340e7a27a68bc627518471f22e4a2" - }, - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "validFrom": { - "type": "string", - "format": "date-time", - "example": "2023-06-26T11:45:19.349Z" - } - } - }, - "metadata": { - "type": "object", - "properties": { - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "encoding": { - "type": "string", - "example": "base64url" - }, - "encrypted": { - "type": "boolean", - "example": true - }, - "encryptedSymmetricKey": { - "type": "string", - "example": "b11182dc524b8181f9a6aef4c4ad0a1c14e40033b9112dffd8d1bcf6cc3b85abc07ded2205ee94068a99f4202502cb0855f322583fa6ce1534d3a05bf36891766ea2c5f90a982b3040680762977d404d758a2370224a239c8279aa7d21e980931c42055b17ca4c7dbffa4782480a8b6279cf989b2f166d5fdb4b2c1b5a63927200000000000000203018dcaba26df45a415bb599218b27ca853a70289d7a3ed3ed0e3730452e8f8d9af91b6e71312565d2c069341f6660ab" - }, - "paymentConditions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "feePaymentAddress": { - "type": "string", - "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" - }, - "feePaymentAmount": { - "type": "string", - "example": "20000000000ncheq" - }, - "intervalInSeconds": { - "type": "number", - "example": 600 - }, - "type": { - "type": "string", - "example": "timelockPayment" - } - } - } - } - } - }, - "resourceMetadata": { - "type": "object", - "example": { - "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceName": "cheqd-revocation-encrypted-1", - "resourceType": "StatusList2021Revocation", - "mediaType": "application/json", - "resourceVersion": "2023-06-26T11:45:19.349Z", - "created": "2023-06-26T11:45:20Z", - "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", - "previousVersionId": null, - "nextVersionId": null - } - }, - "symmetricKey": { - "type": "string", - "example": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" - } - } - } - } - }, - "CredentialStatusCreateEncryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "created": { - "type": "boolean", - "example": true - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedResult" - } - ] - }, - "CredentialStatusUpdateBody": { - "type": "object", - "required": [ - "did", - "statusListName", - "indices" - ], - "properties": { - "did": { - "description": "DID of the StatusList2021 publisher.", - "type": "string", - "format": "uri" - }, - "statusListName": { - "description": "The name of the StatusList2021 DID-Linked Resource to be updated.", - "type": "string" - }, - "indices": { - "description": "List of credential status indices to be updated. The indices must be in the range of the status list.", - "type": "array", - "items": { - "type": "integer", - "minimum": 0, - "exclusiveMinimum": false - } - }, - "statusListVersion": { - "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - "CredentialStatusUpdateUnencryptedRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUpdateBody" - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials", - "indices": [ - 10, - 3199, - 12109, - 130999 - ] - } - }, - "CredentialStatusUpdateUnencryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "updated": { - "type": "boolean", - "example": true - } - } - }, - { - "oneOf": [ - { - "$ref": "#/components/schemas/RevocationResult" - }, - { - "$ref": "#/components/schemas/SuspensionResult" - }, - { - "$ref": "#/components/schemas/UnsuspensionResult" - } - ] - }, - { - "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" - } - ] - }, - "CredentialStatusUpdateEncryptedFormRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUpdateBody" - }, - { - "type": "object", - "required": [ - "symmetricKey" - ], - "properties": { - "symmetricKey": { - "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" - } - ] - }, - "CredentialStatusUpdateEncryptedJsonRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUpdateBody" - }, - { - "type": "object", - "required": [ - "symmetricKey" - ], - "properties": { - "symmetricKey": { - "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials-encrypted", - "indices": [ - 10, - 3199, - 12109, - 130999 - ], - "symmetricKey": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" - } - }, - "CredentialStatusUpdateEncryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "updated": { - "type": "boolean", - "example": true - } - } - }, - { - "oneOf": [ - { - "$ref": "#/components/schemas/RevocationResult" - }, - { - "$ref": "#/components/schemas/SuspensionResult" - }, - { - "$ref": "#/components/schemas/UnsuspensionResult" - } - ] - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedResult" - } - ] - }, - "CredentialStatusCheckRequest": { - "type": "object", - "required": [ - "did", - "statusListName", - "index" - ], - "properties": { - "did": { - "description": "DID of the StatusList2021 publisher.", - "type": "string", - "format": "uri" - }, - "statusListName": { - "description": "The name of the StatusList2021 DID-Linked Resource to be checked.", - "type": "string" - }, - "index": { - "description": "Credential status index to be checked for revocation or suspension.", - "type": "integer", - "minimum": 0, - "exclusiveMinimum": false - }, - "makeFeePayment": { - "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", - "type": "boolean", - "default": true - } - } - }, - "CredentialStatusCheckResult": { - "oneOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCheckRevocationResult" - }, - { - "$ref": "#/components/schemas/CredentialStatusCheckSuspensionResult" - } - ] - }, - "CredentialStatusCheckRevocationResult": { - "type": "object", - "properties": { - "checked": { - "type": "boolean", - "example": true - }, - "revoked": { - "type": "boolean", - "example": false - } - } - }, - "CredentialStatusCheckSuspensionResult": { - "type": "object", - "properties": { - "checked": { - "type": "boolean", - "example": true - }, - "suspended": { - "type": "boolean", - "example": false - } - } - }, - "CredentialStatusListSearchResult": { - "allOf": [ - { - "type": "object", - "properties": { - "found": { - "type": "boolean", - "example": true - } - } - }, - { - "oneOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedResult" - } - ] - } - ] - }, - "KeyImportRequest": { - "type": "object", - "properties": { - "alias": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "Ed25519", - "Secp256k1" - ] - }, - "privateKeyHex": { - "type": "string" - } - } - }, - "KeyResult": { - "type": "object", - "properties": { - "kid": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "Ed25519", - "Secp256k1" - ] - }, - "publicKeyHex": { - "type": "string" - } - } - }, - "DidDocument": { - "description": "This input field contains either a complete DID document, or an incremental change (diff) to a DID document. See Universal DID Registrar specification.", - "type": "object", - "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - } - }, - "id": { - "type": "string" - }, - "controllers": { - "type": "array", - "items": { - "type": "string" - } - }, - "verificationMethod": { - "type": "array", - "items": { - "$ref": "#/components/schemas/VerificationMethod" - } - }, - "service": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "authentication": { - "type": "array", - "items": { - "type": "string" - } - }, - "assertionMethod": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityInvocation": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityDelegation": { - "type": "array", - "items": { - "type": "string" - } - }, - "keyAgreement": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "@context": [ - "https://www.w3.org/ns/did/v1" - ], - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "controller": [ - "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - ], - "verificationMethod": [ - { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "type": "Ed25519VerificationKey2018", - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "publicKeyBase58": "z6MkkVbyHJLLjdjU5B62DaJ4mkdMdUkttf9UqySSkA9bVTeZ" - } - ], - "authentication": [ - "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1" - ], - "service": [ - { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", - "type": "LinkedDomains", - "serviceEndpoint": [ - "https://example.com" - ] - } - ] - } - }, - "DidDocumentWithoutVerificationMethod": { - "type": "object", - "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - } - }, - "id": { - "type": "string" - }, - "controllers": { - "type": "array", - "items": { - "type": "string" - } - }, - "service": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "authentication": { - "type": "array", - "items": { - "type": "string" - } - }, - "assertionMethod": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityInvocation": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityDelegation": { - "type": "array", - "items": { - "type": "string" - } - }, - "keyAgreement": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "@context": [ - "https://www.w3.org/ns/did/v1" - ], - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "controller": [ - "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - ], - "authentication": [ - "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1" - ], - "service": [ - { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", - "type": "LinkedDomains", - "serviceEndpoint": [ - "https://example.com" - ] - } - ] - } - }, - "DidCreateRequestFormBased": { - "type": "object", - "properties": { - "network": { - "description": "Network to create the DID on (testnet or mainnet)", - "type": "string", - "enum": [ - "testnet", - "mainnet" - ] - }, - "identifierFormatType": { - "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", - "type": "string", - "enum": [ - "uuid", - "base58btc" - ] - }, - "verificationMethodType": { - "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", - "type": "string", - "enum": [ - "Ed25519VerificationKey2018", - "JsonWebKey2020", - "Ed25519VerificationKey2020" - ] - }, - "service": { - "description": "It's a list of special objects which are designed to build the actual service. It's almost the same as in DID Core specification, but instead of `id` it utilises `idFragment` field for making the right `id` for each service. !!! WARN. Cause swagger-ui does not handle x-ww-form based arrays correctly, please frame all your services in brackets while using swagger UI. !!!", - "type": "array", - "items": { - "type": "object", - "properties": { - "idFragment": { - "type": "string" - }, - "type": { - "type": "string" - }, - "serviceEndpoint": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "example": [ - { - "idFragment": "service-1", - "type": "LinkedDomains", - "serviceEndpoint": [ - "https://example.com" - ] - } - ] - }, - "key": { - "description": "The unique identifier in hexadecimal public key format used in the verification method to create the DID.", - "type": "string" - }, - "@context": { - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "https://www.w3.org/ns/did/v1" - ] - } - } - }, - "DidCreateRequestJson": { - "type": "object", - "properties": { - "network": { - "description": "Network to create the DID on (testnet or mainnet)", - "type": "string", - "enum": [ - "testnet", - "mainnet" - ] - }, - "identifierFormatType": { - "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", - "type": "string", - "enum": [ - "uuid", - "base58btc" - ] - }, - "assertionMethod": { - "description": "Usually a reference to a Verification Method. An Assertion Method is required to issue JSON-LD credentials. See DID Core specification for more details.", - "type": "boolean", - "default": true - }, - "options": { - "type": "object", - "properties": { - "key": { - "type": "string", - "example": "8255ddadd75695e01f3d98fcec8ccc7861a030b317d4326b0e48a4d579ddc43a" - }, - "verificationMethodType": { - "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", - "type": "string", - "enum": [ - "Ed25519VerificationKey2018", - "JsonWebKey2020", - "Ed25519VerificationKey2020" - ] - } - } - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocumentWithoutVerificationMethod" - } - } - }, - "DidImportRequest": { - "type": "object", - "properties": { - "did": { - "type": "string", - "description": "DID to be imported", - "format": "uri", - "required": true - }, - "keys": { - "type": "array", - "description": "List of keys required to import the DID", - "required": true, - "items": { - "$ref": "#/components/schemas/KeyImportRequest" - } - } - } - }, - "PresentationCreateResult": { - "type": "object", - "properties": { - "vp": { - "type": "object", - "description": "Verifiable Presentation which could be provided to the verifier." - }, - "nbf": { - "type": "integer", - "description": "Unix timestamp of the earliest time that the Verifiable Presentation is valid." - }, - "iss": { - "type": "string", - "description": "DID of the issuer of the Verifiable Presentation. (Here it's supposed to be a holder DID)" - }, - "aud": { - "type": "array", - "items": { - "type": "string" - }, - "description": "DID of the verifier of the Verifiable Presentation." - } - }, - "example": { - "vp": { - "@context": [ - "https://www.w3.org/2018/credentials/v1" - ], - "type": [ - "VerifiablePresentation" - ], - "verifiableCredential": [ - "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc2NoZW1hLm9yZy9zY2hlbWEuanNvbmxkIiwiaHR0cHM6Ly92ZXJhbW8uaW8vY29udGV4dHMvcHJvZmlsZS92MSIsImh0dHBzOi8vdzNpZC5vcmcvdmMtc3RhdHVzLWxpc3QtMjAyMS92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiUGVyc29uIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7Im5hbWUiOiJCb2IiLCJnZW5kZXIiOiJtYWxlIn0sImNyZWRlbnRpYWxTdGF0dXMiOnsiaWQiOiJodHRwczovL3Jlc29sdmVyLmNoZXFkLm5ldC8xLjAvaWRlbnRpZmllcnMvZGlkOmNoZXFkOnRlc3RuZXQ6OTBkNWMxNDEtNzI0Zi00N2FkLTlhZTctYTdjMzNhOWU1NjQzP3Jlc291cmNlTmFtZT1zdXNwZW5zaW9uRW4mcmVzb3VyY2VUeXBlPVN0YXR1c0xpc3QyMDIxU3VzcGVuc2lvbiMxMzMzOCIsInR5cGUiOiJTdGF0dXNMaXN0MjAyMUVudHJ5Iiwic3RhdHVzUHVycG9zZSI6InN1c3BlbnNpb24iLCJzdGF0dXNMaXN0SW5kZXgiOiIxMzMzOCJ9fSwic3ViIjoiZGlkOmtleTp6Nk1raGFYZ0JaRHZvdERrTDUyNTdmYWl6dGlHaUMyUXRLTEdwYm5uRUd0YTJkb0siLCJuYmYiOjE3MDA0NzM0MTYsImlzcyI6ImRpZDpjaGVxZDp0ZXN0bmV0OjkwZDVjMTQxLTcyNGYtNDdhZC05YWU3LWE3YzMzYTllNTY0MyJ9.-14Ril1pZEy2HEEo48gTJr2yOtGxBhUGTFmzVdjAtyhFRsW5zZg9onHt6V9JQ8BaiYBlTkP9GzTnJ-O6hdiyCw" - ] - }, - "nbf": 1700744275, - "iss": "did:cheqd:testnet:4b846d0f-2f6c-4ab6-9fe2-5b8db301c83c", - "aud": [ - "did:cheqd:testnet:8c71e9b6-c5a3-4250-8c58-fa591533cd22" - ] - } - }, - "DidResult": { - "type": "object", - "properties": { - "did": { - "type": "string" - }, - "controllerKeyId": { - "type": "string" - }, - "keys": { - "type": "array", - "items": { - "type": "object" - } - }, - "services": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - } - } - }, - "DidUpdateResponse": { - "type": "object", - "properties": { - "did": { - "type": "string" - }, - "controllerKeyId": { - "type": "string", - "description": "The default key id of which is the key associated with the first verificationMethod" - }, - "keys": { - "type": "array", - "description": "The list of keys associated with the list of verificationMethod's of DIDDocument", - "items": { - "type": "object" - } - }, - "services": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "controllerKeyRefs": { - "type": "array", - "description": "The list of keyRefs which were used for signing the transaction", - "items": { - "type": "string" - } - }, - "controllerKeys": { - "type": "array", - "description": "The list of all possible keys, inlcuding all controller's keys", - "items": { - "type": "string" - } - } - } - }, - "VerificationMethod": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string" - }, - "controller": { - "type": "string" - }, - "publicKeyMultibase": { - "type": "string" - }, - "publicKeyJwk": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "id": "did:cheqd:testnet :7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", - "type": "Ed25519VerificationKey2018" - } - }, - "Service": { - "description": "Communicating or interacting with the DID subject or associated entities via one or more service endpoints. See DID Core specification for more details.", - "type": "object", - "properties": { - "id": { - "description": "DID appended with Service fragment ID (e.g., `#service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`)", - "type": "string", - "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1" - }, - "type": { - "description": "Service type as defined in DID Specification Registries.", - "type": "string", - "example": "LinkedDomains" - }, - "serviceEndpoint": { - "description": "Service endpoint as defined in DID Core Specification.", - "type": "array", - "items": { - "type": "string", - "example": "https://example.com" - } - } - } - }, - "DidUpdateRequest": { - "type": "object", - "properties": { - "did": { - "description": "DID identifier to be updated.", - "type": "string", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "service": { - "type": "array", - "description": "Service section of the DID Document.", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "verificationMethod": { - "type": "array", - "description": "Verification Method section of the DID Document.", - "items": { - "$ref": "#/components/schemas/VerificationMethod" - } - }, - "authentication": { - "description": "Authentication section of the DID Document.", - "type": "array", - "items": { - "type": "string" - } - }, - "publicKeyHexs": { - "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", - "type": "array", - "items": { - "type": "string" - } - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - } - } - }, - "DidDeactivateRequest": { - "type": "object", - "properties": { - "publicKeyHexs": { - "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "CreateResourceRequest": { - "description": "Input fields for DID-Linked Resource creation.", - "type": "object", - "additionalProperties": false, - "required": [ - "name", - "type", - "data", - "encoding" - ], - "properties": { - "data": { - "description": "Encoded string containing the data to be stored in the DID-Linked Resource.", - "type": "string" - }, - "encoding": { - "description": "Encoding format used to encode the data.", - "type": "string", - "enum": [ - "base64url", - "base64", - "hex" - ] - }, - "name": { - "description": "Name of DID-Linked Resource.", - "type": "string" - }, - "type": { - "description": "Type of DID-Linked Resource. This is NOT the same as the media type, which is calculated automatically ledger-side.", - "type": "string" - }, - "alsoKnownAs": { - "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", - "type": "array", - "items": { - "type": "object", - "properties": { - "uri": { - "type": "string" - }, - "description": { - "type": "string" - } - } - } - }, - "version": { - "description": "Optional field to assign a human-readable version in the DID-Linked Resource.", - "type": "string" - }, - "publicKeyHexs": { - "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "data": "SGVsbG8gV29ybGQ=", - "encoding": "base64url", - "name": "ResourceName", - "type": "TextDocument" - } - }, - "ResourceList": { - "type": "object", - "properties": { - "@context": { - "type": "string", - "example": "https://w3id.org/did-resolution/v1" - }, - "contentMetadata": { - "type": "object" - }, - "contentStream": { - "type": "object" - }, - "dereferencingMetadata": { - "$ref": "#/components/schemas/DereferencingMetadata" - } - } - }, - "DereferencingMetadata": { - "type": "object", - "properties": { - "contentType": { - "type": "string", - "example": "application/did+ld+json" - }, - "did": { - "$ref": "#/components/schemas/DidProperties" - }, - "retrieved": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - } - } - }, - "DidResolution": { - "type": "object", - "properties": { - "@context": { - "type": "string", - "example": "https://w3id.org/did-resolution/v1" - }, - "didDidResolutionMetadata": { - "$ref": "#/components/schemas/DidResolutionMetadata" - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - }, - "didDocumentMetadata": { - "$ref": "#/components/schemas/DidDocumentMetadata" - } - } - }, - "DeactivatedDidResolution": { - "type": "object", - "properties": { - "@context": { - "type": "string", - "example": "https://w3id.org/did-resolution/v1" - }, - "didDidResolutionMetadata": { - "$ref": "#/components/schemas/DidResolutionMetadata" - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - }, - "didDocumentMetadata": { - "$ref": "#/components/schemas/DeactivatedDidDocumentMetadata" - } - } - }, - "DidDocumentMetadata": { - "type": "object", - "properties": { - "created": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "deactivated": { - "type": "boolean", - "example": false - }, - "updated": { - "type": "string", - "example": "2021-09-10T12:00:00Z" - }, - "versionId": { - "type": "string", - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - "linkedResourceMetadata": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ResourceMetadata" - } - } - } - }, - "DeactivatedDidDocumentMetadata": { - "type": "object", - "properties": { - "created": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "deactivated": { - "type": "boolean", - "example": true - }, - "updated": { - "type": "string", - "example": "2021-09-10T12:00:00Z" - }, - "versionId": { - "type": "string", - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - "linkedResourceMetadata": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ResourceMetadata" - } - } - } - }, - "ResourceMetadata": { - "type": "object", - "properties": { - "resourceURI": { - "type": "string", - "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47/resources/398cee0a-efac-4643-9f4c-74c48c72a14b" - }, - "resourceCollectionId": { - "type": "string", - "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" - }, - "resourceId": { - "type": "string", - "example": "398cee0a-efac-4643-9f4c-74c48c72a14b" - }, - "resourceName": { - "type": "string", - "example": "cheqd-issuer-logo" - }, - "resourceType": { - "type": "string", - "example": "CredentialArtwork" - }, - "mediaType": { - "type": "string", - "example": "image/png" - }, - "resourceVersion": { - "type": "string", - "example": "1.0" - }, - "checksum": { - "type": "string", - "example": "a95380f460e63ad939541a57aecbfd795fcd37c6d78ee86c885340e33a91b559" - }, - "created": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "nextVersionId": { - "type": "string", - "example": "d4829ac7-4566-478c-a408-b44767eddadc" - }, - "previousVersionId": { - "type": "string", - "example": "ad7a8442-3531-46eb-a024-53953ec6e4ff" - } - } - }, - "DidResolutionMetadata": { - "type": "object", - "properties": { - "contentType": { - "allOf": [ - { - "$ref": "#/components/schemas/ContentType" - } - ], - "example": "application/did+ld+json" - }, - "retrieved": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "did": { - "$ref": "#/components/schemas/DidProperties" - } - } - }, - "ContentType": { - "type": "string", - "enum": [ - "application/did+json", - "application/did+ld+json", - "application/ld+json", - "application/json" - ] - }, - "DidProperties": { - "type": "object", - "properties": { - "didString": { - "type": "string", - "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" - }, - "method": { - "type": "string", - "example": "cheqd" - }, - "methodSpecificId": { - "type": "string", - "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" - } - } - }, - "Customer": { - "type": "object", - "properties": { - "customerId": { - "type": "string", - "example": "6w5drpiiwhhs" - }, - "address": { - "type": "string", - "example": "cheqd1wgsvqwlkmdp60f4dek26ak0sjw6au3ytd3pz7f" - } - } - }, - "AccountCreateRequest": { - "type": "object", - "properties": { - "user": { - "type": "object", - "properties": { - "primaryEmail": { - "type": "string" - } - } - } - } - }, - "InvalidRequest": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "InvalidRequest" - } - } - }, - "InternalError": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Internal Error" - } - } - }, - "UnauthorizedError": { - "description": "Access token is missing or invalid", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Unauthorized Error" - } - } - } - } - } -} \ No newline at end of file + "openapi": "3.0.0", + "info": { + "title": "Credential Service API for cheqd network", + "version": "2.0.0", + "description": "API service to create and manage DIDs, Verifiable Credentials, and DID-Linked Resources", + "contact": { + "name": "Cheqd Foundation Limited", + "url": "https://github.com/cheqd/credential-service", + "email": "support-github@cheqd.io" + }, + "license": { + "name": "Apache 2.0", + "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" + } + }, + "tags": [ + { + "name": "Account" + }, + { + "name": "Key" + }, + { + "name": "DID" + }, + { + "name": "Resource" + }, + { + "name": "Credential" + }, + { + "name": "Presentation" + }, + { + "name": "Credential Status" + } + ], + "externalDocs": { + "description": "Credential Service API Documentation", + "url": "https://docs.cheqd.io/identity" + }, + "paths": { + "/account": { + "get": { + "tags": ["Account"], + "summary": "Fetch custodian-mode client details.", + "description": "This endpoint returns the custodian-mode client details for authenticated users.", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Customer" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/account/idtoken": { + "get": { + "tags": ["Account"], + "summary": "Fetch IdToken.", + "description": "This endpoint returns IdToken as JWT with list of user roles inside", + "deprecated": true, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "idToken": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/account/create": { + "post": { + "tags": ["Account"], + "summary": "Create an client for an authenticated user.", + "description": "This endpoint creates a client in the custodian-mode for an authenticated user", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/AccountCreateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "idToken": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/create/unencrypted": { + "post": { + "tags": ["Credential Status"], + "summary": "Create an unencrypted StatusList2021 credential status list.", + "description": "This endpoint creates an unencrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", + "required": true, + "schema": { + "type": "string", + "enum": ["revocation", "suspension"] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/create/encrypted": { + "post": { + "tags": ["Credential Status"], + "summary": "Create an encrypted StatusList2021 credential status list.", + "description": "This endpoint creates an encrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", + "required": true, + "schema": { + "type": "string", + "enum": ["revocation", "suspension"] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateEncryptedFormRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateEncryptedJsonRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateEncryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/update/unencrypted": { + "post": { + "tags": ["Credential Status"], + "summary": "Update an existing unencrypted StatusList2021 credential status list.", + "parameters": [ + { + "in": "query", + "name": "statusAction", + "description": "The update action to be performed on the unencrypted status list, can be revoke, suspend or reinstate", + "required": true, + "schema": { + "type": "string", + "enum": ["revoke", "suspend", "reinstate"] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/update/encrypted": { + "post": { + "tags": ["Credential Status"], + "summary": "Update an existing encrypted StatusList2021 credential status list.", + "parameters": [ + { + "in": "query", + "name": "statusAction", + "description": "The update action to be performed on the encrypted status list, can be revoke, suspend or reinstate", + "required": true, + "schema": { + "type": "string", + "enum": ["revoke", "suspend", "reinstate"] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedFormRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedJsonRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/check": { + "post": { + "tags": ["Credential Status"], + "summary": "Check a StatusList2021 index for a given Verifiable Credential.", + "description": "This endpoint checks a StatusList2021 index for a given Verifiable Credential and reports whether it is revoked or suspended. It offers a standalone method for checking an index without passing the entire Verifiable Credential or Verifiable Presentation.", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension.", + "required": true, + "schema": { + "type": "string", + "enum": ["revocation", "suspension"] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCheckRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCheckRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCheckResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/search": { + "get": { + "tags": ["Credential Status"], + "summary": "Fetch StatusList2021 DID-Linked Resource based on search criteria.", + "parameters": [ + { + "in": "query", + "name": "did", + "description": "The DID of the issuer of the status list.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension.", + "schema": { + "type": "string", + "enum": ["revocation", "suspension"] + } + }, + { + "in": "query", + "name": "statusListName", + "description": "The name of the StatusList2021 DID-Linked Resource.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusListSearchResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/issue": { + "post": { + "tags": ["Credential"], + "summary": "Issue a Verifiable Credential", + "description": "This endpoint issues a Verifiable Credential. As input it takes the list of issuerDid, subjectDid, attributes, and other parameters of the credential to be issued.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Credential" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/verify": { + "post": { + "tags": ["Credential"], + "summary": "Verify a Verifiable Credential.", + "description": "This endpoint verifies a Verifiable Credential passed to it. As input, it can take the VC-JWT as a string or the entire credential itself.", + "operationId": "verify", + "parameters": [ + { + "in": "query", + "name": "verifyStatus", + "description": "If set to `true` the verification will also check the status of the credential. Requires the VC to have a `credentialStatus` property.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "fetchRemoteContexts", + "description": "When dealing with JSON-LD you also MUST provide the proper contexts. Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "allowDeactivatedDid", + "description": "If set to `true` allow to verify credential which based on deactivated DID.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialVerifyRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialVerifyRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyCredentialResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/revoke": { + "post": { + "tags": ["Credential"], + "summary": "Revoke a Verifiable Credential.", + "description": "This endpoint revokes a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself. The StatusList2021 resource should already be setup in the VC and `credentialStatus` property present in the VC.", + "operationId": "revoke", + "parameters": [ + { + "in": "query", + "name": "publish", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RevocationResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/suspend": { + "post": { + "tags": ["Credential"], + "summary": "Suspend a Verifiable Credential.", + "description": "This endpoint suspends a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself.", + "operationId": "suspend", + "parameters": [ + { + "in": "query", + "name": "publish", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuspensionResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/reinstate": { + "post": { + "tags": ["Credential"], + "summary": "Reinstate a suspended Verifiable Credential.", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "operationId": "reinstate", + "parameters": [ + { + "in": "query", + "name": "publish", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnsuspensionResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/create": { + "post": { + "tags": ["DID"], + "summary": "Create a DID Document.", + "description": "This endpoint creates a DID and associated DID Document. As input, it can take the DID Document parameters via a form, or the fully-assembled DID Document itself.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidCreateRequestFormBased" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidCreateRequestJson" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/did/update": { + "post": { + "tags": ["DID"], + "summary": "Update a DID Document.", + "description": "This endpoint updates a DID Document. As an input, it can take JUST the sections/parameters that need to be updated in the DID Document (in this scenario, it fetches the current DID Document and applies the updated section). Alternatively, it take the fully-assembled DID Document with updated sections as well as unchanged sections.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidUpdateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidUpdateResponse" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/import": { + "post": { + "tags": ["DID"], + "summary": "Import a DID Document.", + "description": "This endpoint imports a decentralized identifier associated with the user's account for custodian-mode clients.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidImportRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidImportRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/did/deactivate/{did}": { + "post": { + "tags": ["DID"], + "summary": "Deactivate a DID Document.", + "description": "This endpoint deactivates a DID Document by taking the DID identifier as input. Must be called and signed by the DID owner.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier to deactivate.", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidDeactivateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidDeactivateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeactivatedDidResolution" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/list": { + "get": { + "tags": ["DID"], + "summary": "Fetch DIDs associated with an account.", + "description": "This endpoint returns the list of DIDs controlled by the account.", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/search/{did}": { + "get": { + "tags": ["DID"], + "summary": "Resolve a DID Document.", + "description": "Resolve a DID Document by DID identifier. Also supports DID Resolution Queries as defined in the W3C DID Resolution specification.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier to resolve.", + "schema": { + "type": "string" + }, + "required": true, + "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + { + "in": "query", + "name": "metadata", + "description": "Return only metadata of DID Document instead of actual DID Document.", + "schema": { + "type": "boolean" + } + }, + { + "in": "query", + "name": "versionId", + "description": "Unique UUID version identifier of DID Document. Allows for fetching a specific version of the DID Document. See cheqd DID Method Specification for more details.", + "schema": { + "type": "string", + "format": "uuid" + }, + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + { + "in": "query", + "name": "versionTime", + "description": "Returns the closest version of the DID Document *at* or *before* specified time. See DID Resolution handling for `did:cheqd` for more details.", + "schema": { + "type": "string", + "format": "date-time" + }, + "example": "1970-01-01T00:00:00Z" + }, + { + "in": "query", + "name": "transformKeys", + "description": "This directive transforms the Verification Method key format from the version in the DID Document to the specified format chosen below.", + "schema": { + "type": "string", + "enum": ["Ed25519VerificationKey2018", "Ed25519VerificationKey2020", "JsonWebKey2020"] + } + }, + { + "in": "query", + "name": "service", + "description": "Query DID Document for a specific Service Endpoint by Service ID (e.g., `service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`). This will typically redirect to the Service Endpoint based on DID Resolution specification algorithm.", + "schema": { + "type": "string" + }, + "example": "service-1" + }, + { + "in": "query", + "name": "relativeRef", + "description": "Relative reference is a query fragment appended to the Service Endpoint URL. **Must** be used along with the `service` query property above. See DID Resolution specification algorithm for more details.", + "schema": { + "type": "string" + }, + "example": "/path/to/file" + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResolution" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/key/create": { + "post": { + "tags": ["Key"], + "summary": "Create an identity key pair.", + "description": "This endpoint creates an identity key pair associated with the user's account for custodian-mode clients.", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/key/import": { + "post": { + "tags": ["Key"], + "summary": "Import an identity key pair.", + "description": "This endpoint imports an identity key pair associated with the user's account for custodian-mode clients.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/KeyImportRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyImportRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/key/read/{kid}": { + "get": { + "tags": ["Key"], + "summary": "Fetch an identity key pair.", + "description": "This endpoint fetches an identity key pair's details for a given key ID. Only the user account associated with the custodian-mode client can fetch the key pair.", + "parameters": [ + { + "name": "kid", + "description": "Key ID of the identity key pair to fetch.", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/presentation/create": { + "post": { + "tags": ["Presentation"], + "summary": "!!! WARN. Such endpoint is made mostly for testing purposes and it is not supposed to be used in production !!! Create a Verifiable Presentation from credential(s).", + "description": "This endpoint creates a Verifiable Presentation from credential(s). As input, it can take the credential(s) as a string or the entire credential(s) itself. \n !!! WARN. Such endpoint is made only for testing purposes !!!", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/PresentationCreateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationCreateResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/presentation/verify": { + "post": { + "tags": ["Presentation"], + "summary": "Verify a Verifiable Presentation generated from credential(s).", + "description": "This endpoint verifies the Verifiable Presentation generated from credential(s). As input, it can take the Verifiable Presentation JWT as a string or the entire Verifiable Presentation itself.", + "parameters": [ + { + "in": "query", + "name": "verifyStatus", + "description": "If set to `true` the verification will also check the status of the presentation. Requires the VP to have a `credentialStatus` property.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "fetchRemoteContexts", + "description": "When dealing with JSON-LD you also MUST provide the proper contexts. * Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "allowDeactivatedDid", + "description": "If set to `true` allow to verify credential which based on deactivated DID.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/PresentationVerifyRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationVerifyRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyPresentationResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/resource/create/{did}": { + "post": { + "tags": ["Resource"], + "summary": "Create a DID-Linked Resource.", + "description": "This endpoint creates a DID-Linked Resource. As input, it can take the DID identifier and the resource parameters via a form, or the fully-assembled resource itself.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier to link the resource to.", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CreateResourceRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateResourceRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceMetadata" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/resource/search/{did}": { + "get": { + "tags": ["Resource"], + "summary": "Get a DID-Linked Resource.", + "description": "This endpoint returns the DID-Linked Resource for a given DID identifier and resource identifier.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier", + "schema": { + "type": "string" + }, + "required": true, + "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + { + "in": "query", + "name": "resourceId", + "description": "Fetch a DID-Linked Resource by Resource ID unique identifier. Since this is a unique identifier, other Resource query parameters are not required. See DID-Linked Resources for more details.", + "schema": { + "type": "string", + "format": "uuid" + }, + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + { + "in": "query", + "name": "resourceName", + "description": "Filter a DID-Linked Resource query by Resource Name. See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "cheqd-issuer-logo" + }, + { + "in": "query", + "name": "resourceType", + "description": "Filter a DID-Linked Resource query by Resource Type. See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "CredentialArtwork" + }, + { + "in": "query", + "name": "resourceVersion", + "description": "Filter a DID-Linked Resource query by Resource Version, which is an optional free-text field used by issuers (e.g., \"v1\", \"Final Version\", \"1st January 1970\" etc). See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "v1" + }, + { + "in": "query", + "name": "resourceVersionTime", + "description": "Filter a DID-Linked Resource query which returns the closest version of the Resource *at* or *before* specified time. See DID-Linked Resources for more details.", + "schema": { + "type": "string", + "format": "date-time" + }, + "example": "1970-01-01T00:00:00Z" + }, + { + "in": "query", + "name": "checksum", + "description": "Request integrity check against a given DID-Linked Resource by providing a SHA-256 checksum hash. See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "dc64474d062ed750a66bad58cb609928de55ed0d81defd231a4a4bf97358e9ed" + }, + { + "in": "query", + "name": "resourceMetadata", + "description": "Return only metadata of DID-Linked Resource instead of actual DID-Linked Resource. Mutually exclusive with some of the other parameters.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "any": { + "schema": { + "type": "object" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + } + }, + "components": { + "schemas": { + "AlsoKnownAs": { + "type": "object", + "properties": { + "alsoKnownAs": { + "type": "array", + "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", + "items": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "format": "uri", + "description": "URI where the DID-Linked Resource can be fetched from. Can be any type of URI (e.g., DID, HTTPS, IPFS, etc.)" + }, + "description": { + "type": "string", + "description": "Optional description of the URI." + } + } + } + } + } + }, + "CredentialRequest": { + "description": "Input fields for the creating a Verifiable Credential.", + "type": "object", + "additionalProperties": false, + "properties": { + "issuerDid": { + "description": "DID of the Verifiable Credential issuer. This needs to be a `did:cheqd` DID.", + "type": "string", + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + "subjectDid": { + "description": "DID of the Verifiable Credential holder/subject. This needs to be a `did:key` DID.", + "type": "string", + "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" + }, + "attributes": { + "description": "JSON object containing the attributes to be included in the credential.", + "type": "object", + "example": { + "name": "Bob", + "gender": "male" + } + }, + "@context": { + "description": "Optional properties to be included in the `@context` property of the credential.", + "type": "array", + "items": { + "type": "string" + }, + "example": ["https://schema.org/schema.jsonld", "https://veramo.io/contexts/profile/v1"] + }, + "type": { + "description": "Optional properties to be included in the `type` property of the credential.", + "type": "array", + "items": { + "type": "string" + }, + "example": ["Person"] + }, + "expirationDate": { + "description": "Optional expiration date according to the VC Data Model specification.", + "type": "string", + "format": "date-time", + "example": "2023-06-08T13:49:28.000Z" + }, + "format": { + "description": "Format of the Verifiable Credential. Defaults to VC-JWT.", + "type": "string", + "enum": ["jwt", "jsonld"], + "example": "jwt" + }, + "credentialStatus": { + "description": "Optional `credentialStatus` properties for VC revocation or suspension. Takes `statusListName` and `statusListPurpose` as inputs.", + "type": "object", + "required": ["statusPurpose", "statusListName"], + "properties": { + "statusPurpose": { + "type": "string", + "enum": ["revocation", "suspension"] + }, + "statusListName": { + "type": "string" + }, + "statusListIndex": { + "type": "number" + }, + "statusListVersion": { + "type": "string", + "format": "date-time" + }, + "statusListRangeStart": { + "type": "number" + }, + "statusListRangeEnd": { + "type": "number" + }, + "indexNotIn": { + "type": "number" + } + }, + "example": { + "statusPurpose": "revocation", + "statusListName": "employee-credentials" + } + } + }, + "required": ["issuerDid", "subjectDid", "attributes"], + "example": { + "issuerDid": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "subjectDid": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", + "attributes": { + "gender": "male", + "name": "Bob" + }, + "@context": ["https://schema.org"], + "type": ["Person"], + "format": "jwt", + "credentialStatus": { + "statusPurpose": "revocation", + "statusListName": "employee-credentials", + "statusListIndex": 10 + } + } + }, + "Credential": { + "description": "Input fields for revoking/suspending a Verifiable Credential.", + "type": "object", + "additionalProperties": false, + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "https://www.w3.org/2018/credentials/v1", + "https://schema.org", + "https://veramo.io/contexts/profile/v1" + ] + }, + "type": { + "type": "array", + "items": { + "type": "string" + }, + "example": ["VerifiableCredential", "Person"] + }, + "expirationDate": { + "type": "string", + "format": "date-time", + "example": "2023-06-08T13:49:28.000Z" + }, + "issuer": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "DID", + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + } + } + }, + "credentialSubject": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "DID", + "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" + } + } + }, + "credentialStatus": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20" + }, + "statusListIndex": { + "type": "number", + "example": 20 + }, + "statusPurpose": { + "type": "string", + "enum": ["revocation", "suspension"], + "example": "suspension" + }, + "type": { + "type": "string", + "enum": ["StatusList2021Entry"] + } + } + }, + "issuanceDate": { + "type": "string", + "format": "date-time", + "example": "2023-06-08T13:49:28.000Z" + }, + "proof": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "jwt": { + "type": "string" + } + }, + "example": { + "type": "JwtProof2020", + "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg" + } + } + }, + "example": { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://schema.org", + "https://veramo.io/contexts/profile/v1" + ], + "credentialSubject": { + "gender": "male", + "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", + "name": "Bob" + }, + "credentialStatus": { + "id": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20", + "statusIndex": 20, + "statusPurpose": "suspension", + "type": "StatusList2021Entry" + }, + "issuanceDate": "2023-06-08T13:49:28.000Z", + "issuer": { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + "proof": { + "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg", + "type": "JwtProof2020" + }, + "type": ["VerifiableCredential", "Person"] + } + }, + "CredentialRevokeRequest": { + "type": "object", + "properties": { + "credential": { + "description": "Verifiable Credential to be revoked as a VC-JWT string or a JSON object.", + "oneOf": [ + { + "type": "object" + }, + { + "type": "string" + } + ] + }, + "symmetricKey": { + "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource. Required if the StatusList2021 DID-Linked Resource is encrypted.", + "type": "string" + } + } + }, + "RevocationResult": { + "properties": { + "revoked": { + "type": "boolean", + "example": true + } + } + }, + "SuspensionResult": { + "properties": { + "suspended": { + "type": "boolean", + "example": true + } + } + }, + "UnsuspensionResult": { + "properties": { + "unsuspended": { + "type": "boolean", + "example": true + } + } + }, + "CredentialVerifyRequest": { + "type": "object", + "properties": { + "credential": { + "description": "Verifiable Credential to be verified as a VC-JWT string or a JSON object.", + "type": "object" + }, + "policies": { + "description": "Custom verification policies to execute when verifying credential.", + "type": "object", + "properties": { + "issuanceDate": { + "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "expirationDate": { + "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "audience": { + "description": "Policy to skip the audience check when set to `false`.", + "type": "boolean", + "default": false + } + } + } + } + }, + "VerifyPresentationResult": { + "type": "object", + "properties": { + "verified": { + "type": "boolean" + }, + "issuer": { + "type": "string" + }, + "signer": { + "type": "object" + }, + "jwt": { + "type": "string" + }, + "verifiableCredential": { + "type": "object" + } + } + }, + "VerifyCredentialResult": { + "type": "object", + "properties": { + "verified": { + "type": "boolean" + }, + "issuer": { + "type": "string" + }, + "signer": { + "type": "object" + }, + "jwt": { + "type": "string" + }, + "verifiableCredential": { + "type": "object" + } + }, + "example": { + "verified": true, + "polices": {}, + "issuer": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "signer": { + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", + "type": "Ed25519VerificationKey2018" + } + } + }, + "PresentationCreateRequest": { + "type": "object", + "required": ["credentials"], + "properties": { + "credentials": { + "description": "Verifiable Credentials to be used for VP-JWT creation as a VP-JWT strings or a JSON objectsf.", + "type": "array", + "items": { + "type": "object" + } + }, + "holderDid": { + "description": "DID of holder", + "type": "string" + }, + "verifierDid": { + "description": "DID of verifier", + "type": "string" + } + } + }, + "PresentationVerifyRequest": { + "type": "object", + "required": ["presentation"], + "properties": { + "presentation": { + "description": "Verifiable Presentation to be verified as a VP-JWT string or a JSON object.", + "type": "object" + }, + "verifierDid": { + "description": "Provide an optional verifier DID (also known as 'domain' parameter), if the verifier DID in the presentation is not managed in the wallet.", + "type": "string" + }, + "makeFeePayment": { + "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", + "type": "boolean", + "default": false + }, + "policies": { + "description": "Custom verification policies to execute when verifying presentation.", + "type": "object", + "properties": { + "issuanceDate": { + "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "expirationDate": { + "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "audience": { + "description": "Policy to skip the audience check when set to `false`.", + "type": "boolean", + "default": false + } + } + } + } + }, + "CredentialStatusCreateBody": { + "allOf": [ + { + "type": "object", + "required": ["did", "statusListName"], + "properties": { + "did": { + "description": "DID of the StatusList2021 publisher.", + "type": "string", + "format": "uri" + }, + "statusListName": { + "description": "The name of the StatusList2021 DID-Linked Resource to be created.", + "type": "string" + }, + "length": { + "description": "The length of the status list to be created. The default and minimum length is 140000 which is 16kb.", + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true, + "default": 140000 + }, + "encoding": { + "description": "The encoding format of the StatusList2021 DiD-Linked Resource to be created.", + "type": "string", + "default": "base64url", + "enum": ["base64url", "base64", "hex"] + }, + "statusListVersion": { + "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/AlsoKnownAs" + } + ] + }, + "CredentialStatusCreateUnencryptedRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCreateBody" + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials", + "length": 140000, + "encoding": "base64url" + } + }, + "CredentialStatusUnencryptedResult": { + "type": "object", + "properties": { + "resource": { + "type": "object", + "properties": { + "StatusList2021": { + "type": "object", + "properties": { + "encodedList": { + "type": "string", + "example": "H4sIAAAAAAAAA-3BAQ0AAADCoPdPbQ8HFAAAAAAAAAAAAAAAAAAAAADwaDhDr_xcRAAA" + }, + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "validFrom": { + "type": "string", + "format": "date-time", + "example": "2023-06-26T11:45:19.349Z" + } + } + }, + "metadata": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "encoding": { + "type": "string", + "example": "base64url" + }, + "encrypted": { + "type": "boolean", + "example": false + } + } + } + } + }, + "resourceMetadata": { + "type": "object", + "example": { + "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceName": "cheqd-employee-credentials", + "resourceType": "StatusList2021Revocation", + "mediaType": "application/json", + "resourceVersion": "1.0.0", + "created": "2023-06-26T11:45:20Z", + "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", + "previousVersionId": null, + "nextVersionId": null + } + } + } + }, + "CredentialStatusCreateUnencryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "created": { + "type": "boolean", + "example": true + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" + } + ] + }, + "CredentialStatusEncryptedPaymentConditionsBody": { + "type": "object", + "properties": { + "feePaymentAddress": { + "description": "The cheqd/Cosmos payment address where payments to unlock the encrypted StatusList2021 DID-Linked Resource need to be sent.", + "type": "string", + "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" + }, + "feePaymentAmount": { + "description": "Amount in CHEQ tokens to unlock the encrypted StatusList2021 DID-Linked Resource.", + "type": "number", + "minimum": 0, + "exclusiveMinimum": true, + "default": 20 + }, + "feePaymentWindow": { + "description": "Time window (in minutes) within which the payment to unlock the encrypted StatusList2021 DID-Linked Resource is considered valid.", + "type": "number", + "minimum": 0, + "exclusiveMinimum": true, + "default": 10 + } + } + }, + "CredentialStatusEncryptedPaymentConditionsJson": { + "type": "object", + "properties": { + "paymentConditions": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" + } + ] + } + } + }, + "CredentialStatusCreateEncryptedFormRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCreateBody" + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" + }, + { + "type": "object", + "required": ["feePaymentAddress", "feePaymentAmount", "feePaymentWindow"] + } + ] + }, + "CredentialStatusCreateEncryptedJsonRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCreateBody" + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" + }, + { + "type": "object", + "required": ["paymentConditions"] + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials-encrypted", + "paymentConditions": [ + { + "feePaymentAddress": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg", + "feePaymentAmount": 20, + "feePaymentWindow": 10 + } + ] + } + }, + "CredentialStatusEncryptedResult": { + "type": "object", + "properties": { + "resource": { + "type": "object", + "properties": { + "StatusList2021": { + "type": "object", + "properties": { + "encodedList": { + "type": "string", + "example": "496fdfbeb745b4db03fcdb40566f9c4c4a1c0f184b31255e641b6e7bdfb9b6946c12be87ca3763be0393c00b67ac1e8737c106b32f46ef59c765754415b5e8cc7c65fccaa3374620430ea476301a5e0dd63340e7a27a68bc627518471f22e4a2" + }, + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "validFrom": { + "type": "string", + "format": "date-time", + "example": "2023-06-26T11:45:19.349Z" + } + } + }, + "metadata": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "encoding": { + "type": "string", + "example": "base64url" + }, + "encrypted": { + "type": "boolean", + "example": true + }, + "encryptedSymmetricKey": { + "type": "string", + "example": "b11182dc524b8181f9a6aef4c4ad0a1c14e40033b9112dffd8d1bcf6cc3b85abc07ded2205ee94068a99f4202502cb0855f322583fa6ce1534d3a05bf36891766ea2c5f90a982b3040680762977d404d758a2370224a239c8279aa7d21e980931c42055b17ca4c7dbffa4782480a8b6279cf989b2f166d5fdb4b2c1b5a63927200000000000000203018dcaba26df45a415bb599218b27ca853a70289d7a3ed3ed0e3730452e8f8d9af91b6e71312565d2c069341f6660ab" + }, + "paymentConditions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "feePaymentAddress": { + "type": "string", + "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" + }, + "feePaymentAmount": { + "type": "string", + "example": "20000000000ncheq" + }, + "intervalInSeconds": { + "type": "number", + "example": 600 + }, + "type": { + "type": "string", + "example": "timelockPayment" + } + } + } + } + } + }, + "resourceMetadata": { + "type": "object", + "example": { + "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceName": "cheqd-revocation-encrypted-1", + "resourceType": "StatusList2021Revocation", + "mediaType": "application/json", + "resourceVersion": "2023-06-26T11:45:19.349Z", + "created": "2023-06-26T11:45:20Z", + "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", + "previousVersionId": null, + "nextVersionId": null + } + }, + "symmetricKey": { + "type": "string", + "example": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" + } + } + } + } + }, + "CredentialStatusCreateEncryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "created": { + "type": "boolean", + "example": true + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedResult" + } + ] + }, + "CredentialStatusUpdateBody": { + "type": "object", + "required": ["did", "statusListName", "indices"], + "properties": { + "did": { + "description": "DID of the StatusList2021 publisher.", + "type": "string", + "format": "uri" + }, + "statusListName": { + "description": "The name of the StatusList2021 DID-Linked Resource to be updated.", + "type": "string" + }, + "indices": { + "description": "List of credential status indices to be updated. The indices must be in the range of the status list.", + "type": "array", + "items": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": false + } + }, + "statusListVersion": { + "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + "CredentialStatusUpdateUnencryptedRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUpdateBody" + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials", + "indices": [10, 3199, 12109, 130999] + } + }, + "CredentialStatusUpdateUnencryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "updated": { + "type": "boolean", + "example": true + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/RevocationResult" + }, + { + "$ref": "#/components/schemas/SuspensionResult" + }, + { + "$ref": "#/components/schemas/UnsuspensionResult" + } + ] + }, + { + "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" + } + ] + }, + "CredentialStatusUpdateEncryptedFormRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUpdateBody" + }, + { + "type": "object", + "required": ["symmetricKey"], + "properties": { + "symmetricKey": { + "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" + } + ] + }, + "CredentialStatusUpdateEncryptedJsonRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUpdateBody" + }, + { + "type": "object", + "required": ["symmetricKey"], + "properties": { + "symmetricKey": { + "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials-encrypted", + "indices": [10, 3199, 12109, 130999], + "symmetricKey": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" + } + }, + "CredentialStatusUpdateEncryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "updated": { + "type": "boolean", + "example": true + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/RevocationResult" + }, + { + "$ref": "#/components/schemas/SuspensionResult" + }, + { + "$ref": "#/components/schemas/UnsuspensionResult" + } + ] + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedResult" + } + ] + }, + "CredentialStatusCheckRequest": { + "type": "object", + "required": ["did", "statusListName", "index"], + "properties": { + "did": { + "description": "DID of the StatusList2021 publisher.", + "type": "string", + "format": "uri" + }, + "statusListName": { + "description": "The name of the StatusList2021 DID-Linked Resource to be checked.", + "type": "string" + }, + "index": { + "description": "Credential status index to be checked for revocation or suspension.", + "type": "integer", + "minimum": 0, + "exclusiveMinimum": false + }, + "makeFeePayment": { + "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", + "type": "boolean", + "default": true + } + } + }, + "CredentialStatusCheckResult": { + "oneOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCheckRevocationResult" + }, + { + "$ref": "#/components/schemas/CredentialStatusCheckSuspensionResult" + } + ] + }, + "CredentialStatusCheckRevocationResult": { + "type": "object", + "properties": { + "checked": { + "type": "boolean", + "example": true + }, + "revoked": { + "type": "boolean", + "example": false + } + } + }, + "CredentialStatusCheckSuspensionResult": { + "type": "object", + "properties": { + "checked": { + "type": "boolean", + "example": true + }, + "suspended": { + "type": "boolean", + "example": false + } + } + }, + "CredentialStatusListSearchResult": { + "allOf": [ + { + "type": "object", + "properties": { + "found": { + "type": "boolean", + "example": true + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedResult" + } + ] + } + ] + }, + "KeyImportRequest": { + "type": "object", + "properties": { + "alias": { + "type": "string" + }, + "type": { + "type": "string", + "enum": ["Ed25519", "Secp256k1"] + }, + "privateKeyHex": { + "type": "string" + } + } + }, + "KeyResult": { + "type": "object", + "properties": { + "kid": { + "type": "string" + }, + "type": { + "type": "string", + "enum": ["Ed25519", "Secp256k1"] + }, + "publicKeyHex": { + "type": "string" + } + } + }, + "DidDocument": { + "description": "This input field contains either a complete DID document, or an incremental change (diff) to a DID document. See Universal DID Registrar specification.", + "type": "object", + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "controllers": { + "type": "array", + "items": { + "type": "string" + } + }, + "verificationMethod": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VerificationMethod" + } + }, + "service": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "authentication": { + "type": "array", + "items": { + "type": "string" + } + }, + "assertionMethod": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityInvocation": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityDelegation": { + "type": "array", + "items": { + "type": "string" + } + }, + "keyAgreement": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "@context": ["https://www.w3.org/ns/did/v1"], + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "controller": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0"], + "verificationMethod": [ + { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "type": "Ed25519VerificationKey2018", + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "publicKeyBase58": "z6MkkVbyHJLLjdjU5B62DaJ4mkdMdUkttf9UqySSkA9bVTeZ" + } + ], + "authentication": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1"], + "service": [ + { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", + "type": "LinkedDomains", + "serviceEndpoint": ["https://example.com"] + } + ] + } + }, + "DidDocumentWithoutVerificationMethod": { + "type": "object", + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "controllers": { + "type": "array", + "items": { + "type": "string" + } + }, + "service": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "authentication": { + "type": "array", + "items": { + "type": "string" + } + }, + "assertionMethod": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityInvocation": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityDelegation": { + "type": "array", + "items": { + "type": "string" + } + }, + "keyAgreement": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "@context": ["https://www.w3.org/ns/did/v1"], + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "controller": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0"], + "authentication": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1"], + "service": [ + { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", + "type": "LinkedDomains", + "serviceEndpoint": ["https://example.com"] + } + ] + } + }, + "DidCreateRequestFormBased": { + "type": "object", + "properties": { + "network": { + "description": "Network to create the DID on (testnet or mainnet)", + "type": "string", + "enum": ["testnet", "mainnet"] + }, + "identifierFormatType": { + "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", + "type": "string", + "enum": ["uuid", "base58btc"] + }, + "verificationMethodType": { + "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", + "type": "string", + "enum": ["Ed25519VerificationKey2018", "JsonWebKey2020", "Ed25519VerificationKey2020"] + }, + "service": { + "description": "It's a list of special objects which are designed to build the actual service. It's almost the same as in DID Core specification, but instead of `id` it utilises `idFragment` field for making the right `id` for each service. !!! WARN. Cause swagger-ui does not handle x-ww-form based arrays correctly, please frame all your services in brackets while using swagger UI. !!!", + "type": "array", + "items": { + "type": "object", + "properties": { + "idFragment": { + "type": "string" + }, + "type": { + "type": "string" + }, + "serviceEndpoint": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "example": [ + { + "idFragment": "service-1", + "type": "LinkedDomains", + "serviceEndpoint": ["https://example.com"] + } + ] + }, + "key": { + "description": "The unique identifier in hexadecimal public key format used in the verification method to create the DID.", + "type": "string" + }, + "@context": { + "type": "array", + "items": { + "type": "string" + }, + "example": ["https://www.w3.org/ns/did/v1"] + } + } + }, + "DidCreateRequestJson": { + "type": "object", + "properties": { + "network": { + "description": "Network to create the DID on (testnet or mainnet)", + "type": "string", + "enum": ["testnet", "mainnet"] + }, + "identifierFormatType": { + "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", + "type": "string", + "enum": ["uuid", "base58btc"] + }, + "assertionMethod": { + "description": "Usually a reference to a Verification Method. An Assertion Method is required to issue JSON-LD credentials. See DID Core specification for more details.", + "type": "boolean", + "default": true + }, + "options": { + "type": "object", + "properties": { + "key": { + "type": "string", + "example": "8255ddadd75695e01f3d98fcec8ccc7861a030b317d4326b0e48a4d579ddc43a" + }, + "verificationMethodType": { + "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", + "type": "string", + "enum": ["Ed25519VerificationKey2018", "JsonWebKey2020", "Ed25519VerificationKey2020"] + } + } + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocumentWithoutVerificationMethod" + } + } + }, + "DidImportRequest": { + "type": "object", + "properties": { + "did": { + "type": "string", + "description": "DID to be imported", + "format": "uri", + "required": true + }, + "keys": { + "type": "array", + "description": "List of keys required to import the DID", + "required": true, + "items": { + "$ref": "#/components/schemas/KeyImportRequest" + } + } + } + }, + "PresentationCreateResult": { + "type": "object", + "properties": { + "vp": { + "type": "object", + "description": "Verifiable Presentation which could be provided to the verifier." + }, + "nbf": { + "type": "integer", + "description": "Unix timestamp of the earliest time that the Verifiable Presentation is valid." + }, + "iss": { + "type": "string", + "description": "DID of the issuer of the Verifiable Presentation. (Here it's supposed to be a holder DID)" + }, + "aud": { + "type": "array", + "items": { + "type": "string" + }, + "description": "DID of the verifier of the Verifiable Presentation." + } + }, + "example": { + "vp": { + "@context": ["https://www.w3.org/2018/credentials/v1"], + "type": ["VerifiablePresentation"], + "verifiableCredential": [ + "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc2NoZW1hLm9yZy9zY2hlbWEuanNvbmxkIiwiaHR0cHM6Ly92ZXJhbW8uaW8vY29udGV4dHMvcHJvZmlsZS92MSIsImh0dHBzOi8vdzNpZC5vcmcvdmMtc3RhdHVzLWxpc3QtMjAyMS92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiUGVyc29uIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7Im5hbWUiOiJCb2IiLCJnZW5kZXIiOiJtYWxlIn0sImNyZWRlbnRpYWxTdGF0dXMiOnsiaWQiOiJodHRwczovL3Jlc29sdmVyLmNoZXFkLm5ldC8xLjAvaWRlbnRpZmllcnMvZGlkOmNoZXFkOnRlc3RuZXQ6OTBkNWMxNDEtNzI0Zi00N2FkLTlhZTctYTdjMzNhOWU1NjQzP3Jlc291cmNlTmFtZT1zdXNwZW5zaW9uRW4mcmVzb3VyY2VUeXBlPVN0YXR1c0xpc3QyMDIxU3VzcGVuc2lvbiMxMzMzOCIsInR5cGUiOiJTdGF0dXNMaXN0MjAyMUVudHJ5Iiwic3RhdHVzUHVycG9zZSI6InN1c3BlbnNpb24iLCJzdGF0dXNMaXN0SW5kZXgiOiIxMzMzOCJ9fSwic3ViIjoiZGlkOmtleTp6Nk1raGFYZ0JaRHZvdERrTDUyNTdmYWl6dGlHaUMyUXRLTEdwYm5uRUd0YTJkb0siLCJuYmYiOjE3MDA0NzM0MTYsImlzcyI6ImRpZDpjaGVxZDp0ZXN0bmV0OjkwZDVjMTQxLTcyNGYtNDdhZC05YWU3LWE3YzMzYTllNTY0MyJ9.-14Ril1pZEy2HEEo48gTJr2yOtGxBhUGTFmzVdjAtyhFRsW5zZg9onHt6V9JQ8BaiYBlTkP9GzTnJ-O6hdiyCw" + ] + }, + "nbf": 1700744275, + "iss": "did:cheqd:testnet:4b846d0f-2f6c-4ab6-9fe2-5b8db301c83c", + "aud": ["did:cheqd:testnet:8c71e9b6-c5a3-4250-8c58-fa591533cd22"] + } + }, + "DidResult": { + "type": "object", + "properties": { + "did": { + "type": "string" + }, + "controllerKeyId": { + "type": "string" + }, + "keys": { + "type": "array", + "items": { + "type": "object" + } + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + } + } + }, + "DidUpdateResponse": { + "type": "object", + "properties": { + "did": { + "type": "string" + }, + "controllerKeyId": { + "type": "string", + "description": "The default key id of which is the key associated with the first verificationMethod" + }, + "keys": { + "type": "array", + "description": "The list of keys associated with the list of verificationMethod's of DIDDocument", + "items": { + "type": "object" + } + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "controllerKeyRefs": { + "type": "array", + "description": "The list of keyRefs which were used for signing the transaction", + "items": { + "type": "string" + } + }, + "controllerKeys": { + "type": "array", + "description": "The list of all possible keys, inlcuding all controller's keys", + "items": { + "type": "string" + } + } + } + }, + "VerificationMethod": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + }, + "controller": { + "type": "string" + }, + "publicKeyMultibase": { + "type": "string" + }, + "publicKeyJwk": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "id": "did:cheqd:testnet :7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", + "type": "Ed25519VerificationKey2018" + } + }, + "Service": { + "description": "Communicating or interacting with the DID subject or associated entities via one or more service endpoints. See DID Core specification for more details.", + "type": "object", + "properties": { + "id": { + "description": "DID appended with Service fragment ID (e.g., `#service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`)", + "type": "string", + "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1" + }, + "type": { + "description": "Service type as defined in DID Specification Registries.", + "type": "string", + "example": "LinkedDomains" + }, + "serviceEndpoint": { + "description": "Service endpoint as defined in DID Core Specification.", + "type": "array", + "items": { + "type": "string", + "example": "https://example.com" + } + } + } + }, + "DidUpdateRequest": { + "type": "object", + "properties": { + "did": { + "description": "DID identifier to be updated.", + "type": "string", + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + "service": { + "type": "array", + "description": "Service section of the DID Document.", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "verificationMethod": { + "type": "array", + "description": "Verification Method section of the DID Document.", + "items": { + "$ref": "#/components/schemas/VerificationMethod" + } + }, + "authentication": { + "description": "Authentication section of the DID Document.", + "type": "array", + "items": { + "type": "string" + } + }, + "publicKeyHexs": { + "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", + "type": "array", + "items": { + "type": "string" + } + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + } + } + }, + "DidDeactivateRequest": { + "type": "object", + "properties": { + "publicKeyHexs": { + "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "CreateResourceRequest": { + "description": "Input fields for DID-Linked Resource creation.", + "type": "object", + "additionalProperties": false, + "required": ["name", "type", "data", "encoding"], + "properties": { + "data": { + "description": "Encoded string containing the data to be stored in the DID-Linked Resource.", + "type": "string" + }, + "encoding": { + "description": "Encoding format used to encode the data.", + "type": "string", + "enum": ["base64url", "base64", "hex"] + }, + "name": { + "description": "Name of DID-Linked Resource.", + "type": "string" + }, + "type": { + "description": "Type of DID-Linked Resource. This is NOT the same as the media type, which is calculated automatically ledger-side.", + "type": "string" + }, + "alsoKnownAs": { + "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", + "type": "array", + "items": { + "type": "object", + "properties": { + "uri": { + "type": "string" + }, + "description": { + "type": "string" + } + } + } + }, + "version": { + "description": "Optional field to assign a human-readable version in the DID-Linked Resource.", + "type": "string" + }, + "publicKeyHexs": { + "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "data": "SGVsbG8gV29ybGQ=", + "encoding": "base64url", + "name": "ResourceName", + "type": "TextDocument" + } + }, + "ResourceList": { + "type": "object", + "properties": { + "@context": { + "type": "string", + "example": "https://w3id.org/did-resolution/v1" + }, + "contentMetadata": { + "type": "object" + }, + "contentStream": { + "type": "object" + }, + "dereferencingMetadata": { + "$ref": "#/components/schemas/DereferencingMetadata" + } + } + }, + "DereferencingMetadata": { + "type": "object", + "properties": { + "contentType": { + "type": "string", + "example": "application/did+ld+json" + }, + "did": { + "$ref": "#/components/schemas/DidProperties" + }, + "retrieved": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + } + } + }, + "DidResolution": { + "type": "object", + "properties": { + "@context": { + "type": "string", + "example": "https://w3id.org/did-resolution/v1" + }, + "didDidResolutionMetadata": { + "$ref": "#/components/schemas/DidResolutionMetadata" + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + }, + "didDocumentMetadata": { + "$ref": "#/components/schemas/DidDocumentMetadata" + } + } + }, + "DeactivatedDidResolution": { + "type": "object", + "properties": { + "@context": { + "type": "string", + "example": "https://w3id.org/did-resolution/v1" + }, + "didDidResolutionMetadata": { + "$ref": "#/components/schemas/DidResolutionMetadata" + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + }, + "didDocumentMetadata": { + "$ref": "#/components/schemas/DeactivatedDidDocumentMetadata" + } + } + }, + "DidDocumentMetadata": { + "type": "object", + "properties": { + "created": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "deactivated": { + "type": "boolean", + "example": false + }, + "updated": { + "type": "string", + "example": "2021-09-10T12:00:00Z" + }, + "versionId": { + "type": "string", + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + "linkedResourceMetadata": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ResourceMetadata" + } + } + } + }, + "DeactivatedDidDocumentMetadata": { + "type": "object", + "properties": { + "created": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "deactivated": { + "type": "boolean", + "example": true + }, + "updated": { + "type": "string", + "example": "2021-09-10T12:00:00Z" + }, + "versionId": { + "type": "string", + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + "linkedResourceMetadata": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ResourceMetadata" + } + } + } + }, + "ResourceMetadata": { + "type": "object", + "properties": { + "resourceURI": { + "type": "string", + "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47/resources/398cee0a-efac-4643-9f4c-74c48c72a14b" + }, + "resourceCollectionId": { + "type": "string", + "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" + }, + "resourceId": { + "type": "string", + "example": "398cee0a-efac-4643-9f4c-74c48c72a14b" + }, + "resourceName": { + "type": "string", + "example": "cheqd-issuer-logo" + }, + "resourceType": { + "type": "string", + "example": "CredentialArtwork" + }, + "mediaType": { + "type": "string", + "example": "image/png" + }, + "resourceVersion": { + "type": "string", + "example": "1.0" + }, + "checksum": { + "type": "string", + "example": "a95380f460e63ad939541a57aecbfd795fcd37c6d78ee86c885340e33a91b559" + }, + "created": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "nextVersionId": { + "type": "string", + "example": "d4829ac7-4566-478c-a408-b44767eddadc" + }, + "previousVersionId": { + "type": "string", + "example": "ad7a8442-3531-46eb-a024-53953ec6e4ff" + } + } + }, + "DidResolutionMetadata": { + "type": "object", + "properties": { + "contentType": { + "allOf": [ + { + "$ref": "#/components/schemas/ContentType" + } + ], + "example": "application/did+ld+json" + }, + "retrieved": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "did": { + "$ref": "#/components/schemas/DidProperties" + } + } + }, + "ContentType": { + "type": "string", + "enum": ["application/did+json", "application/did+ld+json", "application/ld+json", "application/json"] + }, + "DidProperties": { + "type": "object", + "properties": { + "didString": { + "type": "string", + "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" + }, + "method": { + "type": "string", + "example": "cheqd" + }, + "methodSpecificId": { + "type": "string", + "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" + } + } + }, + "Customer": { + "type": "object", + "properties": { + "customerId": { + "type": "string", + "example": "6w5drpiiwhhs" + }, + "address": { + "type": "string", + "example": "cheqd1wgsvqwlkmdp60f4dek26ak0sjw6au3ytd3pz7f" + } + } + }, + "AccountCreateRequest": { + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": { + "primaryEmail": { + "type": "string" + } + } + } + } + }, + "InvalidRequest": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "InvalidRequest" + } + } + }, + "InternalError": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Internal Error" + } + } + }, + "UnauthorizedError": { + "description": "Access token is missing or invalid", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Unauthorized Error" + } + } + } + } + } +} diff --git a/src/types/constants.ts b/src/types/constants.ts index e694965f..2b0546cb 100644 --- a/src/types/constants.ts +++ b/src/types/constants.ts @@ -10,6 +10,9 @@ export const HEADERS = { // Application constants export const APPLICATION_BASE_URL = process.env.APPLICATION_BASE_URL || 'http://localhost:3000'; export const CORS_ALLOWED_ORIGINS = process.env.CORS_ALLOWED_ORIGINS || APPLICATION_BASE_URL; +export const API_KEY_PREFIX = process.env.API_KEY_PREFIX || 'caas'; +export const API_KEY_LENGTH = process.env.API_KEY_LENGTH || 32; +export const API_KEY_EXPIRATION = process.env.API_KEY_EXPIRATION || 1; // By default we don't send events to datadog export const ENABLE_DATADOG = process.env.ENABLE_DATADOG === 'true' ? true : false; // Possible cases 'trace' 'debug' 'info' 'warn' 'error'; @@ -75,6 +78,7 @@ export enum OperationCategoryNameEnum { PRESENTATION = 'presentation', KEY = 'key', SUBSCRIPTION = 'subscription', + API_KEY = 'api-key', } export enum OperationDefaultFeeEnum { @@ -128,6 +132,13 @@ export enum OperationNameEnum { SUBSCRIPTION_UPDATE = 'subscription-update', SUBSCRIPTION_TRIAL_WILL_END = 'subscription-trial-will-end', + // API key operations + API_KEY_CREATE = 'api-key-create', + API_KEY_UPDATE = 'api-key-update', + API_KEY_REVOKE = 'api-key-revoke', + API_KEY_GET = 'api-key-get', + API_KEY_LIST = 'api-key-list', + // Stripe operations STRIPE_ACCOUNT_CREATE = 'stripe-account-create', } diff --git a/src/types/environment.d.ts b/src/types/environment.d.ts index abd5ffae..60aee325 100644 --- a/src/types/environment.d.ts +++ b/src/types/environment.d.ts @@ -20,6 +20,9 @@ declare global { EXTERNAL_DB_CONNECTION_URL: string; EXTERNAL_DB_ENCRYPTION_KEY: string; EXTERNAL_DB_CERT: string | undefined; + API_KEY_PREFIX: string; + API_KEY_LENGTH: number; + API_KEY_EXPIRATION: number; // LogTo LOGTO_ENDPOINT: string; diff --git a/src/types/portal.ts b/src/types/portal.ts index 2e4fcaa7..4cb4ee9f 100644 --- a/src/types/portal.ts +++ b/src/types/portal.ts @@ -94,6 +94,54 @@ export type SubscriptionResumeUnsuccessfulResponseBody = UnsuccessfulResponseBod export type PortalCustomerGetUnsuccessfulResponseBody = UnsuccessfulResponseBody; +// API key +// Create +export type APIKeyCreateRequestBody = { + expiresAt?: Date; +}; +export type APIKeyCreateResponseBody = { + apiKey: string; + expiresAt: string; + revoked: boolean; +}; +export type APIKeyCreateUnsuccessfulResponseBody = UnsuccessfulResponseBody; + +// Update +export type APIKeyUpdateRequestBody = { + apiKey: string; + expiresAt?: Date; + revoked?: boolean; +}; +export type APIKeyUpdateResponseBody = { + apiKey: string; + expiresAt: string; + revoked: boolean; +}; +export type APIKeyUpdateUnsuccessfulResponseBody = UnsuccessfulResponseBody; + +// Revoke +export type APIKeyRevokeRequestBody = { + apiKey: string; +}; +export type APIKeyRevokeResponseBody = { + apiKey: string; + revoked: boolean; +}; +export type APIKeyRevokeUnsuccessfulResponseBody = UnsuccessfulResponseBody; + +// List +export type APIKeyListResponseBody = { + apiKeys: APIKeyCreateResponseBody[]; +}; +export type APIKeyListUnsuccessfulResponseBody = UnsuccessfulResponseBody; + +// Get +export type APIKeyGetRequestBody = { + apiKey: string; +}; +export type APIKeyGetResponseBody = APIKeyCreateResponseBody; +export type APIKeyGetUnsuccessfulResponseBody = UnsuccessfulResponseBody; + // Utils export type PaymentBehavior = Stripe.SubscriptionCreateParams.PaymentBehavior; diff --git a/src/types/swagger-admin-types.ts b/src/types/swagger-admin-types.ts index 33249863..f7511105 100644 --- a/src/types/swagger-admin-types.ts +++ b/src/types/swagger-admin-types.ts @@ -171,6 +171,155 @@ * subscription: * type: object * description: A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object] + * APIKeyCreateRequestBody: + * description: The request body for creating an API key + * type: object + * properties: + * expiresAt: + * type: string + * description: The expiration date of the API key + * example: 2000-10-31T01:30:00.000-05:00 + * format: date + * required: false + * APIKeyCreateResponseBody: + * description: The response body for creating an API key + * type: object + * properties: + * apiKey: + * type: string + * description: The API key + * example: abcdefghijklmnopqrstuvwxyz + * expiresAt: + * type: string + * description: The expiration date of the API key + * example: 2000-10-31T01:30:00.000-05:00 + * format: date + * revoked: + * type: boolean + * description: The status of the API key + * example: false + * APIKeyCreateUnsuccessfulResponseBody: + * description: The response body for an unsuccessful API key creation + * type: object + * properties: + * error: + * type: string + * example: API key creation unsuccessful + * APIKeyUpdateRequestBody: + * description: The request body for updating an API key + * type: object + * properties: + * apiKey: + * type: string + * description: The API key + * example: abcdefghijklmnopqrstuvwxyz + * required: true + * expiresAt: + * type: string + * description: The expiration date of the API key + * example: 2000-10-31T01:30:00.000-05:00 + * format: date + * required: false + * revoked: + * type: boolean + * description: The status of the API key + * example: false + * required: false + * default: false + * APIKeyUpdateResponseBody: + * description: The response body for an unsuccessful API key update + * type: object + * properties: + * apiKey: + * type: string + * description: The API key + * example: abcdefghijklmnopqrstuvwxyz + * expiresAt: + * type: string + * description: The expiration date of the API key + * example: 2000-10-31T01:30:00.000-05:00 + * format: date + * revoked: + * type: boolean + * description: The status of the API key + * example: false + * APIKeyRevokeRequestBody: + * description: The request body for revoking an API key + * type: object + * properties: + * apiKey: + * type: string + * description: The API key + * example: abcdefghijklmnopqrstuvwxyz + * required: true + * APIKeyRevokeResponseBody: + * description: The response body for revoking an API key + * type: object + * properties: + * apiKey: + * type: string + * description: The API key + * example: abcdefghijklmnopqrstuvwxyz + * required: true + * revoked: + * type: boolean + * description: The status of the API key + * example: true + * APIKeyRevokeUnsuccessfulResponseBody: + * description: The response body for an unsuccessful API key revocation + * type: object + * properties: + * error: + * type: string + * example: API key revocation unsuccessful + * APIKeyListResponseBody: + * description: The response body for listing API keys + * type: object + * properties: + * apiKeys: + * type: array + * items: + * type: object + * properties: + * apiKey: + * type: string + * description: The API key + * example: abcdefghijklmnopqrstuvwxyz + * expiresAt: + * type: string + * description: The expiration date of the API key + * example: 2000-10-31T01:30:00.000-05:00 + * format: date + * revoked: + * type: boolean + * description: The status of the API key + * example: false + * APIKeyGetRequestBody: + * description: The request body for getting an API key + * type: object + * properties: + * apiKey: + * type: string + * description: The API key + * example: abcdefghijklmnopqrstuvwxyz + * required: false + * APIKeyGetResponseBody: + * description: The response body for getting an API key + * type: object + * properties: + * apiKey: + * type: string + * description: The API key + * example: abcdefghijklmnopqrstuvwxyz + * expiresAt: + * type: string + * description: The expiration date of the API key + * example: 2000-10-31T01:30:00.000-05:00 + * format: date + * revoked: + * type: boolean + * description: The status of the API key + * example: false * NotFoundError: * description: The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible. * type: object From 91957b674af492a3c15ea19a40fb30e07fc191a6 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Mon, 1 Apr 2024 18:49:40 +0200 Subject: [PATCH 22/40] MAkes linter happy --- docker/Dockerfile | 10 ++++++++++ src/middleware/auth/base-auth-handler.ts | 2 +- src/types/swagger-admin-types.ts | 19 +++++++++++++------ 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index db80d375..f8e1ba09 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -71,6 +71,11 @@ ARG LOGTO_WEBHOOK_SECRET ARG ENABLE_DATADOG=false ARG LOG_LEVEL=info +# API generation +ARG API_KEY_PREFIX="caas" +ARG API_KEY_LENGTH=32 +ARG API_KEY_EXPIRATION=1 + # Verida connector: build-time ARG ENABLE_VERIDA_CONNECTOR=false ARG VERIDA_NETWORK=testnet @@ -119,6 +124,11 @@ ENV LOGTO_WEBHOOK_SECRET ${LOGTO_WEBHOOK_SECRET} ENV ENABLE_DATADOG ${ENABLE_DATADOG} ENV LOG_LEVEL ${LOG_LEVEL} +# API generatioin +ENV API_KEY_PREFIX ${API_KEY_PREFIX} +ENV API_KEY_LENGTH ${API_KEY_LENGTH} +ENV API_KEY_EXPIRATION ${API_KEY_EXPIRATION} + # Faucet setup ENV ENABLE_ACCOUNT_TOPUP ${ENABLE_ACCOUNT_TOPUP} ENV FAUCET_URI ${FAUCET_URI} diff --git a/src/middleware/auth/base-auth-handler.ts b/src/middleware/auth/base-auth-handler.ts index 89c59454..927f98c1 100644 --- a/src/middleware/auth/base-auth-handler.ts +++ b/src/middleware/auth/base-auth-handler.ts @@ -26,7 +26,7 @@ export class BaseAPIGuard extends RuleRoutine implements IAPIGuard { if (!rule) { return this.returnError( StatusCodes.BAD_REQUEST, - `Bad Request. No atuh rules for handling such request: ${request.method} ${request.path}` + `Bad Request. No auth rules for handling such request: ${request.method} ${request.path}` ); } // If the rule is not found - skip the auth check diff --git a/src/types/swagger-admin-types.ts b/src/types/swagger-admin-types.ts index f7511105..ff59f11a 100644 --- a/src/types/swagger-admin-types.ts +++ b/src/types/swagger-admin-types.ts @@ -178,7 +178,7 @@ * expiresAt: * type: string * description: The expiration date of the API key - * example: 2000-10-31T01:30:00.000-05:00 + * example: "2000-10-31T01:30:00.000-05:00" * format: date * required: false * APIKeyCreateResponseBody: @@ -192,7 +192,7 @@ * expiresAt: * type: string * description: The expiration date of the API key - * example: 2000-10-31T01:30:00.000-05:00 + * example: "2000-10-31T01:30:00.000-05:00" * format: date * revoked: * type: boolean @@ -217,7 +217,7 @@ * expiresAt: * type: string * description: The expiration date of the API key - * example: 2000-10-31T01:30:00.000-05:00 + * example: "2000-10-31T01:30:00.000-05:00" * format: date * required: false * revoked: @@ -237,12 +237,19 @@ * expiresAt: * type: string * description: The expiration date of the API key - * example: 2000-10-31T01:30:00.000-05:00 + * example: "2000-10-31T01:30:00.000-05:00" * format: date * revoked: * type: boolean * description: The status of the API key * example: false + * APIKeyUpdateUnsuccessfulResponseBody: + * description: The response body for an unsuccessful API key update + * type: object + * properties: + * error: + * type: string + * example: API key update unsuccessful * APIKeyRevokeRequestBody: * description: The request body for revoking an API key * type: object @@ -288,7 +295,7 @@ * expiresAt: * type: string * description: The expiration date of the API key - * example: 2000-10-31T01:30:00.000-05:00 + * example: "2000-10-31T01:30:00.000-05:00" * format: date * revoked: * type: boolean @@ -314,7 +321,7 @@ * expiresAt: * type: string * description: The expiration date of the API key - * example: 2000-10-31T01:30:00.000-05:00 + * example: "2000-10-31T01:30:00.000-05:00" * format: date * revoked: * type: boolean From 3df21b2d31ebfc2510a9b909820752342de22878 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Mon, 8 Apr 2024 17:33:59 +0200 Subject: [PATCH 23/40] Merge remote-tracking branch 'origin/develop' into DEV-3793 --- src/controllers/admin/api-key.ts | 25 +- src/database/entities/api.key.entity.ts | 8 + src/database/migrations/AlterAPIKeyTable.ts | 9 + src/services/admin/api-key.ts | 13 +- src/services/identity/postgres.ts | 3 +- src/static/swagger-admin.json | 2026 +++--- src/static/swagger-api.json | 6882 ++++++++++--------- src/types/portal.ts | 29 +- src/types/swagger-admin-types.ts | 106 +- 9 files changed, 4653 insertions(+), 4448 deletions(-) diff --git a/src/controllers/admin/api-key.ts b/src/controllers/admin/api-key.ts index 3341e079..2e6df3bf 100644 --- a/src/controllers/admin/api-key.ts +++ b/src/controllers/admin/api-key.ts @@ -12,6 +12,7 @@ import type { APIKeyGetUnsuccessfulResponseBody, APIKeyListResponseBody, APIKeyListUnsuccessfulResponseBody, + APIKeyResponseBody, APIKeyRevokeRequestBody, APIKeyRevokeResponseBody, APIKeyRevokeUnsuccessfulResponseBody, @@ -39,6 +40,7 @@ export class APIKeyController { }) .toDate() .bail(), + check('name').exists().withMessage('Name is not specified').bail().isString().withMessage('Invalid name').bail(), ]; static apiKeyUpdateValidator = [ check('apiKey') @@ -62,6 +64,7 @@ export class APIKeyController { .toDate() .bail(), check('revoked').optional().isBoolean().withMessage('Invalid boolean value').bail(), + check('name').optional().isString().withMessage('Invalid name').bail(), ]; static apiKeyRevokeValidator = [ check('apiKey') @@ -107,10 +110,10 @@ export class APIKeyController { @validate public async create(request: Request, response: Response) { try { - const { expiresAt } = request.body satisfies APIKeyCreateRequestBody; + const { name, expiresAt } = request.body satisfies APIKeyCreateRequestBody; const apiKey = APIKeyService.instance.generateAPIKey(); - const apiKeyEntity = await APIKeyService.instance.create(apiKey, response.locals.user, expiresAt); + const apiKeyEntity = await APIKeyService.instance.create(apiKey, name, response.locals.user, expiresAt); if (!apiKeyEntity) { return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ message: 'Cannot create a new API key', @@ -125,6 +128,8 @@ export class APIKeyController { }); return response.status(StatusCodes.CREATED).json({ apiKey: apiKeyEntity.apiKey, + name: apiKeyEntity.name, + createdAt: apiKeyEntity.createdAt.toISOString(), expiresAt: apiKeyEntity.expiresAt.toISOString(), revoked: apiKeyEntity.revoked, } satisfies APIKeyCreateResponseBody); @@ -166,8 +171,8 @@ export class APIKeyController { @validate public async update(request: Request, response: Response) { try { - const { apiKey, expiresAt, revoked } = request.body satisfies APIKeyUpdateRequestBody; - const apiKeyEntity = await APIKeyService.instance.update(apiKey, expiresAt, revoked); + const { apiKey, name, expiresAt, revoked } = request.body satisfies APIKeyUpdateRequestBody; + const apiKeyEntity = await APIKeyService.instance.update(apiKey, name, expiresAt, revoked); if (!apiKeyEntity) { return response.status(StatusCodes.NOT_FOUND).json({ error: 'Cannot update API key cause it\'s not found', @@ -183,6 +188,8 @@ export class APIKeyController { }); return response.status(StatusCodes.OK).json({ apiKey: apiKeyEntity.apiKey, + name: apiKeyEntity.name, + createdAt: apiKeyEntity.createdAt.toISOString(), expiresAt: apiKeyEntity.expiresAt.toISOString(), revoked: apiKeyEntity.revoked, } satisfies APIKeyUpdateResponseBody); @@ -283,9 +290,11 @@ export class APIKeyController { const keys = apiKeyList.map((apiKey) => { return { apiKey: apiKey.apiKey, + name: apiKey.name, + createdAt: apiKey.createdAt.toISOString(), expiresAt: apiKey.expiresAt.toISOString(), revoked: apiKey.revoked, - }; + } satisfies APIKeyResponseBody; }); return response.status(StatusCodes.OK).json({ apiKeys: keys, @@ -341,9 +350,11 @@ export class APIKeyController { } return response.status(StatusCodes.OK).json({ apiKey: apiKeyEntity.apiKey, + name: apiKeyEntity.name, + createdAt: apiKeyEntity.createdAt.toISOString(), expiresAt: apiKeyEntity.expiresAt.toISOString(), revoked: apiKeyEntity.revoked, - }); + } satisfies APIKeyGetResponseBody); } // Otherwise try to get the latest not revoked API key const keys = await APIKeyService.instance.find( @@ -362,6 +373,8 @@ export class APIKeyController { } return response.status(StatusCodes.OK).json({ apiKey: keys[0].apiKey, + name: keys[0].name, + createdAt: keys[0].createdAt.toISOString(), expiresAt: keys[0].expiresAt.toISOString(), revoked: keys[0].revoked, } satisfies APIKeyGetResponseBody); diff --git a/src/database/entities/api.key.entity.ts b/src/database/entities/api.key.entity.ts index 161f0ed7..26e69a0f 100644 --- a/src/database/entities/api.key.entity.ts +++ b/src/database/entities/api.key.entity.ts @@ -20,6 +20,12 @@ export class APIKeyEntity { }) apiKey!: string; + @Column({ + type: 'text', + nullable: false, + }) + name!: string; + @Column({ type: 'boolean', nullable: false, @@ -69,6 +75,7 @@ export class APIKeyEntity { constructor( apiKeyHash: string, apiKey: string, + name: string, expiresAt: Date, customer: CustomerEntity, user: UserEntity, @@ -76,6 +83,7 @@ export class APIKeyEntity { ) { this.apiKeyHash = apiKeyHash; this.apiKey = apiKey; + this.name = name; this.expiresAt = expiresAt; this.customer = customer; this.user = user; diff --git a/src/database/migrations/AlterAPIKeyTable.ts b/src/database/migrations/AlterAPIKeyTable.ts index 23e4f4b7..72fb2520 100644 --- a/src/database/migrations/AlterAPIKeyTable.ts +++ b/src/database/migrations/AlterAPIKeyTable.ts @@ -15,6 +15,15 @@ export class AlterAPIKeyTable1695740346004 implements MigrationInterface { }) ); + await queryRunner.addColumn( + table_name, + new TableColumn({ + name: 'name', + type: 'text', + isNullable: false, + }) + ); + // Remove unused apiKeyId column await queryRunner.dropColumn(table_name, 'apiKeyId'); // Add column apiKeyHash diff --git a/src/services/admin/api-key.ts b/src/services/admin/api-key.ts index 185ec1c7..655734cb 100644 --- a/src/services/admin/api-key.ts +++ b/src/services/admin/api-key.ts @@ -61,10 +61,13 @@ export class APIKeyService { // ToDo: Maybe we also need to store not the API key but the hash of it? // But in that case the API key will be shown once and then it will be lost. @decryptAPIKey - public async create(apiKey: string, user: UserEntity, expiresAt?: Date, revoked = false): Promise { + public async create(apiKey: string, name: string, user: UserEntity, expiresAt?: Date, revoked = false): Promise { if (!apiKey) { throw new Error('API key is not specified'); } + if (!name) { + throw new Error('API key name is not specified'); + } if (!user) { throw new Error('API key user is not specified'); } @@ -75,7 +78,7 @@ export class APIKeyService { const apiKeyHash = APIKeyService.hashAPIKey(apiKey); const encryptedAPIKey = await this.secretBox.encrypt(apiKey); // Create entity - const apiKeyEntity = new APIKeyEntity(apiKeyHash, encryptedAPIKey, expiresAt, user.customer, user, revoked); + const apiKeyEntity = new APIKeyEntity(apiKeyHash, encryptedAPIKey, name, expiresAt, user.customer, user, revoked); const apiKeyRecord = (await this.apiKeyRepository.insert(apiKeyEntity)).identifiers[0]; if (!apiKeyRecord) throw new Error(`Cannot create a new API key`); return apiKeyEntity; @@ -84,6 +87,7 @@ export class APIKeyService { @decryptAPIKey public async update( apiKey: string, + name?: string, expiresAt?: Date, revoked?: boolean, customer?: CustomerEntity, @@ -94,6 +98,9 @@ export class APIKeyService { if (!existingAPIKey) { throw new Error(`API with key id ${apiKey} not found`); } + if (name) { + existingAPIKey.name = name; + } if (expiresAt) { existingAPIKey.expiresAt = expiresAt; } @@ -112,7 +119,7 @@ export class APIKeyService { } public async revoke(apiKey: string) { - return this.update(apiKey, undefined, true); + return this.update(apiKey, undefined, undefined, true); } public async decryptAPIKey(apiKey: string) { diff --git a/src/services/identity/postgres.ts b/src/services/identity/postgres.ts index 8c35727b..811f5951 100644 --- a/src/services/identity/postgres.ts +++ b/src/services/identity/postgres.ts @@ -528,7 +528,7 @@ export class PostgresIdentityService extends DefaultIdentityService { if (keys.length > 0) { throw new Error(`API key for customer ${customer.customerId} and user ${user.logToId} already exists`); } - const apiKeyEntity = await APIKeyService.instance.create(apiKey, user); + const apiKeyEntity = await APIKeyService.instance.create(apiKey, "idToken", user); if (!apiKeyEntity) { throw new Error(`Cannot create API key for customer ${customer.customerId} and user ${user.logToId}`); } @@ -543,6 +543,7 @@ export class PostgresIdentityService extends DefaultIdentityService { } const apiKeyEntity = await APIKeyService.instance.update( newApiKey, + undefined, await APIKeyService.instance.getExpiryDate(newApiKey) ); if (!apiKeyEntity) { diff --git a/src/static/swagger-admin.json b/src/static/swagger-admin.json index fccdefcd..362f5444 100644 --- a/src/static/swagger-admin.json +++ b/src/static/swagger-admin.json @@ -1,1020 +1,1008 @@ { - "openapi": "3.0.0", - "info": { - "title": "Credential Service admin API for cheqd network", - "version": "2.0.0", - "description": "Admin API which handles users subscriptions and payments", - "contact": { - "name": "Cheqd Foundation Limited", - "url": "https://github.com/cheqd/credential-service", - "email": "support-github@cheqd.io" - }, - "license": { - "name": "Apache 2.0", - "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" - } - }, - "tags": [ - { - "name": "Product" - }, - { - "name": "Price" - }, - { - "name": "Subscription" - }, - { - "name": "API Key" - } - ], - "paths": { - "/admin/api-key/create": { - "post": { - "summary": "Create a new API key", - "description": "Create a new API key", - "tags": ["API Key"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyCreateRequestBody" - } - } - } - }, - "responses": { - "201": { - "description": "A new API key has been created", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyCreateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/APIKeyCreateUnsuccessfulResponseBody" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/api-key/update": { - "post": { - "summary": "Update an existing API key", - "description": "Update an existing API key", - "tags": ["API Key"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyUpdateRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The API key has been updated", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyUpdateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/APIKeyUpdateUnsuccessfulResponseBody" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/api-key/revoke": { - "delete": { - "summary": "Revoke an existing API key", - "description": "Revoke an existing API key", - "tags": ["API Key"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyRevokeRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The API key has been revoked", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyRevokeResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/APIKeyRevokeUnsuccessfulResponseBody" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/api-key/list": { - "get": { - "summary": "List all API keys", - "description": "List all API keys", - "tags": ["API Key"], - "responses": { - "200": { - "description": "A list of API keys", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/api-key/get": { - "get": { - "summary": "Get an API key", - "description": "Get an API key. If the API key is not provided, the latest not revoked API key it returns.", - "tags": ["API Key"], - "parameters": [ - { - "name": "apiKey", - "in": "query", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "The API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyGetResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/price/list": { - "get": { - "summary": "Get a list of prices", - "description": "Get a list of prices", - "tags": ["Price"], - "parameters": [ - { - "in": "query", - "name": "productId", - "schema": { - "type": "string", - "description": "The product id. If passed - returns filtered by this product list of prices.", - "required": false - } - } - ], - "responses": { - "200": { - "description": "A list of prices", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PriceListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/product/list": { - "get": { - "summary": "Get a list of products", - "description": "Get a list of products which are on a Stripe side", - "tags": ["Product"], - "parameters": [ - { - "in": "query", - "name": "prices", - "schema": { - "type": "boolean", - "description": "If setup to true - returns the list of products with prices inside. Default - true", - "required": false - } - } - ], - "responses": { - "200": { - "description": "A list of products", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/product/get/{productId}": { - "get": { - "summary": "Get a product", - "description": "Get a product by id", - "tags": ["Product"], - "parameters": [ - { - "in": "path", - "name": "productId", - "schema": { - "type": "string", - "description": "The product id which identifies the product in Stripe" - }, - "required": true - }, - { - "in": "query", - "name": "prices", - "schema": { - "type": "boolean", - "description": "If setup to true - returns the product with prices inside. Default - true", - "required": false - } - } - ], - "responses": { - "200": { - "description": "A product", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductGetResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/create": { - "post": { - "summary": "Create a subscription", - "description": "Creates a new subscription for an existing customer", - "tags": ["Subscription"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCreateRequestBody" - } - } - } - }, - "responses": { - "201": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCreateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/update": { - "post": { - "summary": "Update a subscription", - "description": "Updates an existing subscription", - "tags": ["Subscription"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionUpdateRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionUpdateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/list": { - "get": { - "summary": "Get a list of subscriptions", - "description": "Get a list of subscriptions", - "tags": ["Subscription"], - "parameters": [ - { - "in": "query", - "name": "paymentProviderId", - "schema": { - "type": "string", - "description": "The customer id. If passed - returns filtered by this customer list of subscriptions." - } - } - ], - "responses": { - "200": { - "description": "A list of subscriptions", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/get": { - "get": { - "summary": "Get a subscription", - "description": "Get a subscription", - "tags": ["Subscription"], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionGetResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/cancel": { - "post": { - "summary": "Cancel a subscription", - "description": "Cancels an existing subscription", - "tags": ["Subscription"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCancelRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCancelResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/resume": {}, - "post": { - "summary": "Resume a subscription", - "description": "Resumes an existing subscription", - "tags": ["Subscription"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionResumeRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionResumeResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "components": { - "schemas": { - "PriceListResponseBody": { - "description": "A list of active prcies from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/list)", - "type": "object", - "properties": { - "prices": { - "type": "array", - "items": { - "type": "object", - "description": "A price object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/object)" - } - } - } - }, - "ProductListResponseBody": { - "type": "object", - "properties": { - "products": { - "type": "array", - "items": { - "type": "object", - "description": "A product object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/object)" - } - } - } - }, - "ProductGetResponseBody": { - "description": "A product with or without prices inside. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/retrieve)", - "type": "object" - }, - "InvalidRequest": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "InvalidRequest" - } - } - }, - "InternalError": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Internal Error" - } - } - }, - "UnauthorizedError": { - "description": "Access token is missing or invalid", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Unauthorized Error" - } - } - }, - "SubscriptionCreateRequestBody": { - "description": "The request body for creating a subscription", - "type": "object", - "properties": { - "price": { - "type": "string", - "description": "The price id", - "example": "price_1234567890" - }, - "successURL": { - "type": "string", - "description": "The URL to redirect to after the customer sucessfully completes the checkout", - "example": "https://example.com/success" - }, - "cancelURL": { - "type": "string", - "description": "The URL to redirect to after the customer cancels the checkout", - "example": "https://example.com/cancel" - }, - "quantity": { - "type": "number", - "description": "The quantity of the product", - "example": 1 - }, - "trialPeriodDays": { - "type": "number", - "description": "The number of days the customer has to pay for the product", - "example": 7 - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": "abcdefghijklmnopqrstuvwxyz" - } - } - }, - "SubscriptionCreateResponseBody": { - "description": "The response body for creating a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "An object with link to checkout session. For more information see the [Stripe API documentation](https://docs.stripe.com/api/checkout/sessions/object)", - "properties": { - "sessionURL": { - "type": "string", - "description": "URL which user should follow to manage subscription" - } - } - } - } - }, - "SubscriptionUpdateRequestBody": { - "description": "The request body for updating a subscription", - "type": "object", - "properties": { - "returnURL": { - "type": "string", - "description": "URL which is used to redirect to the page with ability to update the subscription" - } - } - }, - "SubscriptionUpdateResponseBody": { - "description": "The response body for updating a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "Object with redirect url inside", - "properties": { - "sessionURL": { - "type": "string", - "description": "URL with session URL rediect to" - } - } - } - } - }, - "SubscriptionGetRequestBody": { - "description": "The request body for getting a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - } - } - }, - "SubscriptionGetResponseBody": { - "description": "The response body for getting a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" - } - } - }, - "SubscriptionListRequestBody": { - "description": "The request body for listing subscriptions", - "type": "object", - "properties": { - "customerId": { - "type": "string", - "description": "The Stripe customer id", - "example": "cus_1234567890" - } - } - }, - "SubscriptionListResponseBody": { - "description": "The response body for listing subscriptions", - "type": "object", - "properties": { - "subscriptions": { - "type": "array", - "items": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" - } - } - } - }, - "SubscriptionCancelRequestBody": { - "description": "The request body for canceling a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - } - } - }, - "SubscriptionCancelResponseBody": { - "description": "The response body for canceling a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": "abcdefghijklmnopqrstuvwxyz" - } - } - }, - "SubscriptionResumeRequestBody": { - "description": "The request body for resuming a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": "abcdefghijklmnopqrstuvwxyz" - } - } - }, - "SubscriptionResumeResponseBody": { - "description": "The response body for resuming a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" - } - } - }, - "APIKeyCreateRequestBody": { - "description": "The request body for creating an API key", - "type": "object", - "properties": { - "expiresAt": { - "type": "string", - "description": "The expiration date of the API key", - "example": "2000-10-31T01:30:00.000-05:00", - "format": "date", - "required": false - } - } - }, - "APIKeyCreateResponseBody": { - "description": "The response body for creating an API key", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz" - }, - "expiresAt": { - "type": "string", - "description": "The expiration date of the API key", - "example": "2000-10-31T01:30:00.000-05:00", - "format": "date" - }, - "revoked": { - "type": "boolean", - "description": "The status of the API key", - "example": false - } - } - }, - "APIKeyCreateUnsuccessfulResponseBody": { - "description": "The response body for an unsuccessful API key creation", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "API key creation unsuccessful" - } - } - }, - "APIKeyUpdateRequestBody": { - "description": "The request body for updating an API key", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz", - "required": true - }, - "expiresAt": { - "type": "string", - "description": "The expiration date of the API key", - "example": "2000-10-31T01:30:00.000-05:00", - "format": "date", - "required": false - }, - "revoked": { - "type": "boolean", - "description": "The status of the API key", - "example": false, - "required": false, - "default": false - } - } - }, - "APIKeyUpdateResponseBody": { - "description": "The response body for an unsuccessful API key update", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz" - }, - "expiresAt": { - "type": "string", - "description": "The expiration date of the API key", - "example": "2000-10-31T01:30:00.000-05:00", - "format": "date" - }, - "revoked": { - "type": "boolean", - "description": "The status of the API key", - "example": false - } - } - }, - "APIKeyRevokeRequestBody": { - "description": "The request body for revoking an API key", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz", - "required": true - } - } - }, - "APIKeyRevokeResponseBody": { - "description": "The response body for revoking an API key", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz", - "required": true - }, - "revoked": { - "type": "boolean", - "description": "The status of the API key", - "example": true - } - } - }, - "APIKeyRevokeUnsuccessfulResponseBody": { - "description": "The response body for an unsuccessful API key revocation", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "API key revocation unsuccessful" - } - } - }, - "APIKeyListResponseBody": { - "description": "The response body for listing API keys", - "type": "object", - "properties": { - "apiKeys": { - "type": "array", - "items": { - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz" - }, - "expiresAt": { - "type": "string", - "description": "The expiration date of the API key", - "example": "2000-10-31T01:30:00.000-05:00", - "format": "date" - }, - "revoked": { - "type": "boolean", - "description": "The status of the API key", - "example": false - } - } - } - } - } - }, - "APIKeyGetRequestBody": { - "description": "The request body for getting an API key", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz", - "required": false - } - } - }, - "APIKeyGetResponseBody": { - "description": "The response body for getting an API key", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz" - }, - "expiresAt": { - "type": "string", - "description": "The expiration date of the API key", - "example": "2000-10-31T01:30:00.000-05:00", - "format": "date" - }, - "revoked": { - "type": "boolean", - "description": "The status of the API key", - "example": false - } - } - }, - "NotFoundError": { - "description": "The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Not Found Error" - } - } - } - } - } -} + "openapi": "3.0.0", + "info": { + "title": "Credential Service admin API for cheqd network", + "version": "2.0.0", + "description": "Admin API which handles users subscriptions and payments", + "contact": { + "name": "Cheqd Foundation Limited", + "url": "https://github.com/cheqd/credential-service", + "email": "support-github@cheqd.io" + }, + "license": { + "name": "Apache 2.0", + "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" + } + }, + "tags": [ + { + "name": "Product" + }, + { + "name": "Price" + }, + { + "name": "Subscription" + }, + { + "name": "API Key" + } + ], + "paths": { + "/admin/api-key/create": { + "post": { + "summary": "Create a new API key", + "description": "Create a new API key", + "tags": [ + "API Key" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyCreateRequestBody" + } + } + } + }, + "responses": { + "201": { + "description": "A new API key has been created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyCreateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/APIKeyCreateUnsuccessfulResponseBody" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/api-key/update": { + "post": { + "summary": "Update an existing API key", + "description": "Update an existing API key", + "tags": [ + "API Key" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyUpdateRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The API key has been updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyUpdateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/APIKeyUpdateUnsuccessfulResponseBody" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/api-key/revoke": { + "delete": { + "summary": "Revoke an existing API key", + "description": "Revoke an existing API key", + "tags": [ + "API Key" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyRevokeRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The API key has been revoked", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyRevokeResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/APIKeyRevokeUnsuccessfulResponseBody" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/api-key/list": { + "get": { + "summary": "List all API keys", + "description": "List all API keys", + "tags": [ + "API Key" + ], + "responses": { + "200": { + "description": "A list of API keys", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/api-key/get": { + "get": { + "summary": "Get an API key", + "description": "Get an API key. If the API key is not provided, the latest not revoked API key it returns.", + "tags": [ + "API Key" + ], + "parameters": [ + { + "name": "apiKey", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyGetResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/price/list": { + "get": { + "summary": "Get a list of prices", + "description": "Get a list of prices", + "tags": [ + "Price" + ], + "parameters": [ + { + "in": "query", + "name": "productId", + "schema": { + "type": "string", + "description": "The product id. If passed - returns filtered by this product list of prices.", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A list of prices", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PriceListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/product/list": { + "get": { + "summary": "Get a list of products", + "description": "Get a list of products which are on a Stripe side", + "tags": [ + "Product" + ], + "parameters": [ + { + "in": "query", + "name": "prices", + "schema": { + "type": "boolean", + "description": "If setup to true - returns the list of products with prices inside. Default - true", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A list of products", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProductListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/product/get/{productId}": { + "get": { + "summary": "Get a product", + "description": "Get a product by id", + "tags": [ + "Product" + ], + "parameters": [ + { + "in": "path", + "name": "productId", + "schema": { + "type": "string", + "description": "The product id which identifies the product in Stripe" + }, + "required": true + }, + { + "in": "query", + "name": "prices", + "schema": { + "type": "boolean", + "description": "If setup to true - returns the product with prices inside. Default - true", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A product", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProductGetResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/create": { + "post": { + "summary": "Create a subscription", + "description": "Creates a new subscription for an existing customer", + "tags": [ + "Subscription" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCreateRequestBody" + } + } + } + }, + "responses": { + "201": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCreateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/update": { + "post": { + "summary": "Update a subscription", + "description": "Updates an existing subscription", + "tags": [ + "Subscription" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionUpdateRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionUpdateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/list": { + "get": { + "summary": "Get a list of subscriptions", + "description": "Get a list of subscriptions", + "tags": [ + "Subscription" + ], + "parameters": [ + { + "in": "query", + "name": "paymentProviderId", + "schema": { + "type": "string", + "description": "The customer id. If passed - returns filtered by this customer list of subscriptions." + } + } + ], + "responses": { + "200": { + "description": "A list of subscriptions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/get": { + "get": { + "summary": "Get a subscription", + "description": "Get a subscription", + "tags": [ + "Subscription" + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionGetResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/cancel": { + "post": { + "summary": "Cancel a subscription", + "description": "Cancels an existing subscription", + "tags": [ + "Subscription" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCancelRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCancelResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/resume": {}, + "post": { + "summary": "Resume a subscription", + "description": "Resumes an existing subscription", + "tags": [ + "Subscription" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionResumeRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionResumeResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "components": { + "schemas": { + "PriceListResponseBody": { + "description": "A list of active prcies from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/list)", + "type": "object", + "properties": { + "prices": { + "type": "array", + "items": { + "type": "object", + "description": "A price object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/object)" + } + } + } + }, + "ProductListResponseBody": { + "type": "object", + "properties": { + "products": { + "type": "array", + "items": { + "type": "object", + "description": "A product object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/object)" + } + } + } + }, + "ProductGetResponseBody": { + "description": "A product with or without prices inside. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/retrieve)", + "type": "object" + }, + "InvalidRequest": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "InvalidRequest" + } + } + }, + "InternalError": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Internal Error" + } + } + }, + "UnauthorizedError": { + "description": "Access token is missing or invalid", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Unauthorized Error" + } + } + }, + "SubscriptionCreateRequestBody": { + "description": "The request body for creating a subscription", + "type": "object", + "properties": { + "price": { + "type": "string", + "description": "The price id", + "example": "price_1234567890" + }, + "successURL": { + "type": "string", + "description": "The URL to redirect to after the customer sucessfully completes the checkout", + "example": "https://example.com/success" + }, + "cancelURL": { + "type": "string", + "description": "The URL to redirect to after the customer cancels the checkout", + "example": "https://example.com/cancel" + }, + "quantity": { + "type": "number", + "description": "The quantity of the product", + "example": 1 + }, + "trialPeriodDays": { + "type": "number", + "description": "The number of days the customer has to pay for the product", + "example": 7 + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": "abcdefghijklmnopqrstuvwxyz" + } + } + }, + "SubscriptionCreateResponseBody": { + "description": "The response body for creating a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "An object with link to checkout session. For more information see the [Stripe API documentation](https://docs.stripe.com/api/checkout/sessions/object)", + "properties": { + "sessionURL": { + "type": "string", + "description": "URL which user should follow to manage subscription" + } + } + } + } + }, + "SubscriptionUpdateRequestBody": { + "description": "The request body for updating a subscription", + "type": "object", + "properties": { + "returnURL": { + "type": "string", + "description": "URL which is used to redirect to the page with ability to update the subscription" + } + } + }, + "SubscriptionUpdateResponseBody": { + "description": "The response body for updating a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "Object with redirect url inside", + "properties": { + "sessionURL": { + "type": "string", + "description": "URL with session URL rediect to" + } + } + } + } + }, + "SubscriptionGetRequestBody": { + "description": "The request body for getting a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + } + } + }, + "SubscriptionGetResponseBody": { + "description": "The response body for getting a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" + } + } + }, + "SubscriptionListRequestBody": { + "description": "The request body for listing subscriptions", + "type": "object", + "properties": { + "customerId": { + "type": "string", + "description": "The Stripe customer id", + "example": "cus_1234567890" + } + } + }, + "SubscriptionListResponseBody": { + "description": "The response body for listing subscriptions", + "type": "object", + "properties": { + "subscriptions": { + "type": "array", + "items": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + } + } + } + }, + "SubscriptionCancelRequestBody": { + "description": "The request body for canceling a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + } + } + }, + "SubscriptionCancelResponseBody": { + "description": "The response body for canceling a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": "abcdefghijklmnopqrstuvwxyz" + } + } + }, + "SubscriptionResumeRequestBody": { + "description": "The request body for resuming a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": "abcdefghijklmnopqrstuvwxyz" + } + } + }, + "SubscriptionResumeResponseBody": { + "description": "The response body for resuming a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + } + } + }, + "APIKeyResponse": { + "description": "The general view for API key in response", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + }, + "createdAt": { + "type": "string", + "description": "The creation date of the API key", + "example": "2000-10-31T01:30:00.000-05:00", + "format": "date" + }, + "name": { + "type": "string", + "description": "The name of the API key", + "example": "My API Key" + }, + "expiresAt": { + "type": "string", + "description": "The expiration date of the API key", + "example": "2000-10-31T01:30:00.000-05:00", + "format": "date" + }, + "revoked": { + "type": "boolean", + "description": "The status of the API key", + "example": false + } + } + }, + "APIKeyCreateRequestBody": { + "description": "The request body for creating an API key", + "type": "object", + "properties": { + "expiresAt": { + "type": "string", + "description": "The expiration date of the API key", + "example": "2000-10-31T01:30:00.000-05:00", + "format": "date", + "required": false + }, + "name": { + "type": "string", + "description": "The name of the API key", + "example": "My API Key", + "required": true + } + } + }, + "APIKeyCreateResponseBody": { + "description": "The response body for creating an API key", + "type": "object", + "ref": "#/components/schemas/APIKeyResponse" + }, + "APIKeyCreateUnsuccessfulResponseBody": { + "description": "The response body for an unsuccessful API key creation", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "API key creation unsuccessful" + } + } + }, + "APIKeyUpdateRequestBody": { + "description": "The request body for updating an API key", + "type": "object", + "ref": "#/components/schemas/APIKeyResponse" + }, + "APIKeyUpdateResponseBody": { + "description": "The response body for an unsuccessful API key update", + "type": "object", + "ref": "#/components/schemas/APIKeyResponse" + }, + "APIKeyUpdateUnsuccessfulResponseBody": { + "description": "The response body for an unsuccessful API key update", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "API key update unsuccessful" + } + } + }, + "APIKeyRevokeRequestBody": { + "description": "The request body for revoking an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz", + "required": true + } + } + }, + "APIKeyRevokeResponseBody": { + "description": "The response body for revoking an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz", + "required": true + }, + "revoked": { + "type": "boolean", + "description": "The status of the API key", + "example": true + } + } + }, + "APIKeyRevokeUnsuccessfulResponseBody": { + "description": "The response body for an unsuccessful API key revocation", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "API key revocation unsuccessful" + } + } + }, + "APIKeyListResponseBody": { + "description": "The response body for listing API keys", + "type": "object", + "properties": { + "apiKeys": { + "type": "array", + "items": { + "type": "object", + "ref": "#/components/schemas/APIKeyResponse" + } + } + } + }, + "APIKeyGetRequestBody": { + "description": "The request body for getting an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz", + "required": false + } + } + }, + "APIKeyGetResponseBody": { + "description": "The response body for getting an API key", + "type": "object", + "ref": "#/components/schemas/APIKeyResponse" + }, + "NotFoundError": { + "description": "The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Not Found Error" + } + } + } + } + } +} \ No newline at end of file diff --git a/src/static/swagger-api.json b/src/static/swagger-api.json index b2cf4b99..a42f421f 100644 --- a/src/static/swagger-api.json +++ b/src/static/swagger-api.json @@ -1,3334 +1,3550 @@ { - "openapi": "3.0.0", - "info": { - "title": "Credential Service API for cheqd network", - "version": "2.0.0", - "description": "API service to create and manage DIDs, Verifiable Credentials, and DID-Linked Resources", - "contact": { - "name": "Cheqd Foundation Limited", - "url": "https://github.com/cheqd/credential-service", - "email": "support-github@cheqd.io" - }, - "license": { - "name": "Apache 2.0", - "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" - } - }, - "tags": [ - { - "name": "Account" - }, - { - "name": "Key" - }, - { - "name": "DID" - }, - { - "name": "Resource" - }, - { - "name": "Credential" - }, - { - "name": "Presentation" - }, - { - "name": "Credential Status" - } - ], - "externalDocs": { - "description": "Credential Service API Documentation", - "url": "https://docs.cheqd.io/identity" - }, - "paths": { - "/account": { - "get": { - "tags": ["Account"], - "summary": "Fetch custodian-mode client details.", - "description": "This endpoint returns the custodian-mode client details for authenticated users.", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Customer" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/account/idtoken": { - "get": { - "tags": ["Account"], - "summary": "Fetch IdToken.", - "description": "This endpoint returns IdToken as JWT with list of user roles inside", - "deprecated": true, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "idToken": { - "type": "string" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/account/create": { - "post": { - "tags": ["Account"], - "summary": "Create an client for an authenticated user.", - "description": "This endpoint creates a client in the custodian-mode for an authenticated user", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/AccountCreateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountCreateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "idToken": { - "type": "string" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/create/unencrypted": { - "post": { - "tags": ["Credential Status"], - "summary": "Create an unencrypted StatusList2021 credential status list.", - "description": "This endpoint creates an unencrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", - "parameters": [ - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", - "required": true, - "schema": { - "type": "string", - "enum": ["revocation", "suspension"] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/create/encrypted": { - "post": { - "tags": ["Credential Status"], - "summary": "Create an encrypted StatusList2021 credential status list.", - "description": "This endpoint creates an encrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", - "parameters": [ - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", - "required": true, - "schema": { - "type": "string", - "enum": ["revocation", "suspension"] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateEncryptedFormRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateEncryptedJsonRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateEncryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/update/unencrypted": { - "post": { - "tags": ["Credential Status"], - "summary": "Update an existing unencrypted StatusList2021 credential status list.", - "parameters": [ - { - "in": "query", - "name": "statusAction", - "description": "The update action to be performed on the unencrypted status list, can be revoke, suspend or reinstate", - "required": true, - "schema": { - "type": "string", - "enum": ["revoke", "suspend", "reinstate"] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/update/encrypted": { - "post": { - "tags": ["Credential Status"], - "summary": "Update an existing encrypted StatusList2021 credential status list.", - "parameters": [ - { - "in": "query", - "name": "statusAction", - "description": "The update action to be performed on the encrypted status list, can be revoke, suspend or reinstate", - "required": true, - "schema": { - "type": "string", - "enum": ["revoke", "suspend", "reinstate"] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedFormRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedJsonRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/check": { - "post": { - "tags": ["Credential Status"], - "summary": "Check a StatusList2021 index for a given Verifiable Credential.", - "description": "This endpoint checks a StatusList2021 index for a given Verifiable Credential and reports whether it is revoked or suspended. It offers a standalone method for checking an index without passing the entire Verifiable Credential or Verifiable Presentation.", - "parameters": [ - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension.", - "required": true, - "schema": { - "type": "string", - "enum": ["revocation", "suspension"] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCheckRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCheckRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCheckResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/search": { - "get": { - "tags": ["Credential Status"], - "summary": "Fetch StatusList2021 DID-Linked Resource based on search criteria.", - "parameters": [ - { - "in": "query", - "name": "did", - "description": "The DID of the issuer of the status list.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension.", - "schema": { - "type": "string", - "enum": ["revocation", "suspension"] - } - }, - { - "in": "query", - "name": "statusListName", - "description": "The name of the StatusList2021 DID-Linked Resource.", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusListSearchResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/issue": { - "post": { - "tags": ["Credential"], - "summary": "Issue a Verifiable Credential", - "description": "This endpoint issues a Verifiable Credential. As input it takes the list of issuerDid, subjectDid, attributes, and other parameters of the credential to be issued.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Credential" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/verify": { - "post": { - "tags": ["Credential"], - "summary": "Verify a Verifiable Credential.", - "description": "This endpoint verifies a Verifiable Credential passed to it. As input, it can take the VC-JWT as a string or the entire credential itself.", - "operationId": "verify", - "parameters": [ - { - "in": "query", - "name": "verifyStatus", - "description": "If set to `true` the verification will also check the status of the credential. Requires the VC to have a `credentialStatus` property.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "fetchRemoteContexts", - "description": "When dealing with JSON-LD you also MUST provide the proper contexts. Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "allowDeactivatedDid", - "description": "If set to `true` allow to verify credential which based on deactivated DID.", - "schema": { - "type": "boolean", - "default": false - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialVerifyRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialVerifyRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/VerifyCredentialResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/revoke": { - "post": { - "tags": ["Credential"], - "summary": "Revoke a Verifiable Credential.", - "description": "This endpoint revokes a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself. The StatusList2021 resource should already be setup in the VC and `credentialStatus` property present in the VC.", - "operationId": "revoke", - "parameters": [ - { - "in": "query", - "name": "publish", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RevocationResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/suspend": { - "post": { - "tags": ["Credential"], - "summary": "Suspend a Verifiable Credential.", - "description": "This endpoint suspends a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself.", - "operationId": "suspend", - "parameters": [ - { - "in": "query", - "name": "publish", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "schema": { - "type": "boolean" - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuspensionResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/reinstate": { - "post": { - "tags": ["Credential"], - "summary": "Reinstate a suspended Verifiable Credential.", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "operationId": "reinstate", - "parameters": [ - { - "in": "query", - "name": "publish", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "schema": { - "type": "boolean" - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnsuspensionResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/create": { - "post": { - "tags": ["DID"], - "summary": "Create a DID Document.", - "description": "This endpoint creates a DID and associated DID Document. As input, it can take the DID Document parameters via a form, or the fully-assembled DID Document itself.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidCreateRequestFormBased" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidCreateRequestJson" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/did/update": { - "post": { - "tags": ["DID"], - "summary": "Update a DID Document.", - "description": "This endpoint updates a DID Document. As an input, it can take JUST the sections/parameters that need to be updated in the DID Document (in this scenario, it fetches the current DID Document and applies the updated section). Alternatively, it take the fully-assembled DID Document with updated sections as well as unchanged sections.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidUpdateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidUpdateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidUpdateResponse" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/import": { - "post": { - "tags": ["DID"], - "summary": "Import a DID Document.", - "description": "This endpoint imports a decentralized identifier associated with the user's account for custodian-mode clients.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidImportRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidImportRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/did/deactivate/{did}": { - "post": { - "tags": ["DID"], - "summary": "Deactivate a DID Document.", - "description": "This endpoint deactivates a DID Document by taking the DID identifier as input. Must be called and signed by the DID owner.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier to deactivate.", - "schema": { - "type": "string" - }, - "required": true - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidDeactivateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidDeactivateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeactivatedDidResolution" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/list": { - "get": { - "tags": ["DID"], - "summary": "Fetch DIDs associated with an account.", - "description": "This endpoint returns the list of DIDs controlled by the account.", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/search/{did}": { - "get": { - "tags": ["DID"], - "summary": "Resolve a DID Document.", - "description": "Resolve a DID Document by DID identifier. Also supports DID Resolution Queries as defined in the W3C DID Resolution specification.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier to resolve.", - "schema": { - "type": "string" - }, - "required": true, - "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - { - "in": "query", - "name": "metadata", - "description": "Return only metadata of DID Document instead of actual DID Document.", - "schema": { - "type": "boolean" - } - }, - { - "in": "query", - "name": "versionId", - "description": "Unique UUID version identifier of DID Document. Allows for fetching a specific version of the DID Document. See cheqd DID Method Specification for more details.", - "schema": { - "type": "string", - "format": "uuid" - }, - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - { - "in": "query", - "name": "versionTime", - "description": "Returns the closest version of the DID Document *at* or *before* specified time. See DID Resolution handling for `did:cheqd` for more details.", - "schema": { - "type": "string", - "format": "date-time" - }, - "example": "1970-01-01T00:00:00Z" - }, - { - "in": "query", - "name": "transformKeys", - "description": "This directive transforms the Verification Method key format from the version in the DID Document to the specified format chosen below.", - "schema": { - "type": "string", - "enum": ["Ed25519VerificationKey2018", "Ed25519VerificationKey2020", "JsonWebKey2020"] - } - }, - { - "in": "query", - "name": "service", - "description": "Query DID Document for a specific Service Endpoint by Service ID (e.g., `service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`). This will typically redirect to the Service Endpoint based on DID Resolution specification algorithm.", - "schema": { - "type": "string" - }, - "example": "service-1" - }, - { - "in": "query", - "name": "relativeRef", - "description": "Relative reference is a query fragment appended to the Service Endpoint URL. **Must** be used along with the `service` query property above. See DID Resolution specification algorithm for more details.", - "schema": { - "type": "string" - }, - "example": "/path/to/file" - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidResolution" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/key/create": { - "post": { - "tags": ["Key"], - "summary": "Create an identity key pair.", - "description": "This endpoint creates an identity key pair associated with the user's account for custodian-mode clients.", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/key/import": { - "post": { - "tags": ["Key"], - "summary": "Import an identity key pair.", - "description": "This endpoint imports an identity key pair associated with the user's account for custodian-mode clients.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/KeyImportRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyImportRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/key/read/{kid}": { - "get": { - "tags": ["Key"], - "summary": "Fetch an identity key pair.", - "description": "This endpoint fetches an identity key pair's details for a given key ID. Only the user account associated with the custodian-mode client can fetch the key pair.", - "parameters": [ - { - "name": "kid", - "description": "Key ID of the identity key pair to fetch.", - "in": "path", - "schema": { - "type": "string" - }, - "required": true - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/presentation/create": { - "post": { - "tags": ["Presentation"], - "summary": "!!! WARN. Such endpoint is made mostly for testing purposes and it is not supposed to be used in production !!! Create a Verifiable Presentation from credential(s).", - "description": "This endpoint creates a Verifiable Presentation from credential(s). As input, it can take the credential(s) as a string or the entire credential(s) itself. \n !!! WARN. Such endpoint is made only for testing purposes !!!", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/PresentationCreateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/PresentationCreateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PresentationCreateResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/presentation/verify": { - "post": { - "tags": ["Presentation"], - "summary": "Verify a Verifiable Presentation generated from credential(s).", - "description": "This endpoint verifies the Verifiable Presentation generated from credential(s). As input, it can take the Verifiable Presentation JWT as a string or the entire Verifiable Presentation itself.", - "parameters": [ - { - "in": "query", - "name": "verifyStatus", - "description": "If set to `true` the verification will also check the status of the presentation. Requires the VP to have a `credentialStatus` property.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "fetchRemoteContexts", - "description": "When dealing with JSON-LD you also MUST provide the proper contexts. * Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "allowDeactivatedDid", - "description": "If set to `true` allow to verify credential which based on deactivated DID.", - "schema": { - "type": "boolean", - "default": false - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/PresentationVerifyRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/PresentationVerifyRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/VerifyPresentationResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/resource/create/{did}": { - "post": { - "tags": ["Resource"], - "summary": "Create a DID-Linked Resource.", - "description": "This endpoint creates a DID-Linked Resource. As input, it can take the DID identifier and the resource parameters via a form, or the fully-assembled resource itself.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier to link the resource to.", - "schema": { - "type": "string" - }, - "required": true - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CreateResourceRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateResourceRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ResourceMetadata" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/resource/search/{did}": { - "get": { - "tags": ["Resource"], - "summary": "Get a DID-Linked Resource.", - "description": "This endpoint returns the DID-Linked Resource for a given DID identifier and resource identifier.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier", - "schema": { - "type": "string" - }, - "required": true, - "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - { - "in": "query", - "name": "resourceId", - "description": "Fetch a DID-Linked Resource by Resource ID unique identifier. Since this is a unique identifier, other Resource query parameters are not required. See DID-Linked Resources for more details.", - "schema": { - "type": "string", - "format": "uuid" - }, - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - { - "in": "query", - "name": "resourceName", - "description": "Filter a DID-Linked Resource query by Resource Name. See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "cheqd-issuer-logo" - }, - { - "in": "query", - "name": "resourceType", - "description": "Filter a DID-Linked Resource query by Resource Type. See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "CredentialArtwork" - }, - { - "in": "query", - "name": "resourceVersion", - "description": "Filter a DID-Linked Resource query by Resource Version, which is an optional free-text field used by issuers (e.g., \"v1\", \"Final Version\", \"1st January 1970\" etc). See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "v1" - }, - { - "in": "query", - "name": "resourceVersionTime", - "description": "Filter a DID-Linked Resource query which returns the closest version of the Resource *at* or *before* specified time. See DID-Linked Resources for more details.", - "schema": { - "type": "string", - "format": "date-time" - }, - "example": "1970-01-01T00:00:00Z" - }, - { - "in": "query", - "name": "checksum", - "description": "Request integrity check against a given DID-Linked Resource by providing a SHA-256 checksum hash. See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "dc64474d062ed750a66bad58cb609928de55ed0d81defd231a4a4bf97358e9ed" - }, - { - "in": "query", - "name": "resourceMetadata", - "description": "Return only metadata of DID-Linked Resource instead of actual DID-Linked Resource. Mutually exclusive with some of the other parameters.", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "any": { - "schema": { - "type": "object" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - } - }, - "components": { - "schemas": { - "AlsoKnownAs": { - "type": "object", - "properties": { - "alsoKnownAs": { - "type": "array", - "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", - "items": { - "type": "object", - "properties": { - "uri": { - "type": "string", - "format": "uri", - "description": "URI where the DID-Linked Resource can be fetched from. Can be any type of URI (e.g., DID, HTTPS, IPFS, etc.)" - }, - "description": { - "type": "string", - "description": "Optional description of the URI." - } - } - } - } - } - }, - "CredentialRequest": { - "description": "Input fields for the creating a Verifiable Credential.", - "type": "object", - "additionalProperties": false, - "properties": { - "issuerDid": { - "description": "DID of the Verifiable Credential issuer. This needs to be a `did:cheqd` DID.", - "type": "string", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "subjectDid": { - "description": "DID of the Verifiable Credential holder/subject. This needs to be a `did:key` DID.", - "type": "string", - "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" - }, - "attributes": { - "description": "JSON object containing the attributes to be included in the credential.", - "type": "object", - "example": { - "name": "Bob", - "gender": "male" - } - }, - "@context": { - "description": "Optional properties to be included in the `@context` property of the credential.", - "type": "array", - "items": { - "type": "string" - }, - "example": ["https://schema.org/schema.jsonld", "https://veramo.io/contexts/profile/v1"] - }, - "type": { - "description": "Optional properties to be included in the `type` property of the credential.", - "type": "array", - "items": { - "type": "string" - }, - "example": ["Person"] - }, - "expirationDate": { - "description": "Optional expiration date according to the VC Data Model specification.", - "type": "string", - "format": "date-time", - "example": "2023-06-08T13:49:28.000Z" - }, - "format": { - "description": "Format of the Verifiable Credential. Defaults to VC-JWT.", - "type": "string", - "enum": ["jwt", "jsonld"], - "example": "jwt" - }, - "credentialStatus": { - "description": "Optional `credentialStatus` properties for VC revocation or suspension. Takes `statusListName` and `statusListPurpose` as inputs.", - "type": "object", - "required": ["statusPurpose", "statusListName"], - "properties": { - "statusPurpose": { - "type": "string", - "enum": ["revocation", "suspension"] - }, - "statusListName": { - "type": "string" - }, - "statusListIndex": { - "type": "number" - }, - "statusListVersion": { - "type": "string", - "format": "date-time" - }, - "statusListRangeStart": { - "type": "number" - }, - "statusListRangeEnd": { - "type": "number" - }, - "indexNotIn": { - "type": "number" - } - }, - "example": { - "statusPurpose": "revocation", - "statusListName": "employee-credentials" - } - } - }, - "required": ["issuerDid", "subjectDid", "attributes"], - "example": { - "issuerDid": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "subjectDid": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", - "attributes": { - "gender": "male", - "name": "Bob" - }, - "@context": ["https://schema.org"], - "type": ["Person"], - "format": "jwt", - "credentialStatus": { - "statusPurpose": "revocation", - "statusListName": "employee-credentials", - "statusListIndex": 10 - } - } - }, - "Credential": { - "description": "Input fields for revoking/suspending a Verifiable Credential.", - "type": "object", - "additionalProperties": false, - "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "https://www.w3.org/2018/credentials/v1", - "https://schema.org", - "https://veramo.io/contexts/profile/v1" - ] - }, - "type": { - "type": "array", - "items": { - "type": "string" - }, - "example": ["VerifiableCredential", "Person"] - }, - "expirationDate": { - "type": "string", - "format": "date-time", - "example": "2023-06-08T13:49:28.000Z" - }, - "issuer": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "DID", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - } - } - }, - "credentialSubject": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "DID", - "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" - } - } - }, - "credentialStatus": { - "type": "object", - "properties": { - "id": { - "type": "string", - "example": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20" - }, - "statusListIndex": { - "type": "number", - "example": 20 - }, - "statusPurpose": { - "type": "string", - "enum": ["revocation", "suspension"], - "example": "suspension" - }, - "type": { - "type": "string", - "enum": ["StatusList2021Entry"] - } - } - }, - "issuanceDate": { - "type": "string", - "format": "date-time", - "example": "2023-06-08T13:49:28.000Z" - }, - "proof": { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "jwt": { - "type": "string" - } - }, - "example": { - "type": "JwtProof2020", - "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg" - } - } - }, - "example": { - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://schema.org", - "https://veramo.io/contexts/profile/v1" - ], - "credentialSubject": { - "gender": "male", - "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", - "name": "Bob" - }, - "credentialStatus": { - "id": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20", - "statusIndex": 20, - "statusPurpose": "suspension", - "type": "StatusList2021Entry" - }, - "issuanceDate": "2023-06-08T13:49:28.000Z", - "issuer": { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "proof": { - "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg", - "type": "JwtProof2020" - }, - "type": ["VerifiableCredential", "Person"] - } - }, - "CredentialRevokeRequest": { - "type": "object", - "properties": { - "credential": { - "description": "Verifiable Credential to be revoked as a VC-JWT string or a JSON object.", - "oneOf": [ - { - "type": "object" - }, - { - "type": "string" - } - ] - }, - "symmetricKey": { - "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource. Required if the StatusList2021 DID-Linked Resource is encrypted.", - "type": "string" - } - } - }, - "RevocationResult": { - "properties": { - "revoked": { - "type": "boolean", - "example": true - } - } - }, - "SuspensionResult": { - "properties": { - "suspended": { - "type": "boolean", - "example": true - } - } - }, - "UnsuspensionResult": { - "properties": { - "unsuspended": { - "type": "boolean", - "example": true - } - } - }, - "CredentialVerifyRequest": { - "type": "object", - "properties": { - "credential": { - "description": "Verifiable Credential to be verified as a VC-JWT string or a JSON object.", - "type": "object" - }, - "policies": { - "description": "Custom verification policies to execute when verifying credential.", - "type": "object", - "properties": { - "issuanceDate": { - "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "expirationDate": { - "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "audience": { - "description": "Policy to skip the audience check when set to `false`.", - "type": "boolean", - "default": false - } - } - } - } - }, - "VerifyPresentationResult": { - "type": "object", - "properties": { - "verified": { - "type": "boolean" - }, - "issuer": { - "type": "string" - }, - "signer": { - "type": "object" - }, - "jwt": { - "type": "string" - }, - "verifiableCredential": { - "type": "object" - } - } - }, - "VerifyCredentialResult": { - "type": "object", - "properties": { - "verified": { - "type": "boolean" - }, - "issuer": { - "type": "string" - }, - "signer": { - "type": "object" - }, - "jwt": { - "type": "string" - }, - "verifiableCredential": { - "type": "object" - } - }, - "example": { - "verified": true, - "polices": {}, - "issuer": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "signer": { - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", - "type": "Ed25519VerificationKey2018" - } - } - }, - "PresentationCreateRequest": { - "type": "object", - "required": ["credentials"], - "properties": { - "credentials": { - "description": "Verifiable Credentials to be used for VP-JWT creation as a VP-JWT strings or a JSON objectsf.", - "type": "array", - "items": { - "type": "object" - } - }, - "holderDid": { - "description": "DID of holder", - "type": "string" - }, - "verifierDid": { - "description": "DID of verifier", - "type": "string" - } - } - }, - "PresentationVerifyRequest": { - "type": "object", - "required": ["presentation"], - "properties": { - "presentation": { - "description": "Verifiable Presentation to be verified as a VP-JWT string or a JSON object.", - "type": "object" - }, - "verifierDid": { - "description": "Provide an optional verifier DID (also known as 'domain' parameter), if the verifier DID in the presentation is not managed in the wallet.", - "type": "string" - }, - "makeFeePayment": { - "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", - "type": "boolean", - "default": false - }, - "policies": { - "description": "Custom verification policies to execute when verifying presentation.", - "type": "object", - "properties": { - "issuanceDate": { - "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "expirationDate": { - "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "audience": { - "description": "Policy to skip the audience check when set to `false`.", - "type": "boolean", - "default": false - } - } - } - } - }, - "CredentialStatusCreateBody": { - "allOf": [ - { - "type": "object", - "required": ["did", "statusListName"], - "properties": { - "did": { - "description": "DID of the StatusList2021 publisher.", - "type": "string", - "format": "uri" - }, - "statusListName": { - "description": "The name of the StatusList2021 DID-Linked Resource to be created.", - "type": "string" - }, - "length": { - "description": "The length of the status list to be created. The default and minimum length is 140000 which is 16kb.", - "type": "integer", - "minimum": 0, - "exclusiveMinimum": true, - "default": 140000 - }, - "encoding": { - "description": "The encoding format of the StatusList2021 DiD-Linked Resource to be created.", - "type": "string", - "default": "base64url", - "enum": ["base64url", "base64", "hex"] - }, - "statusListVersion": { - "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - { - "$ref": "#/components/schemas/AlsoKnownAs" - } - ] - }, - "CredentialStatusCreateUnencryptedRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCreateBody" - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials", - "length": 140000, - "encoding": "base64url" - } - }, - "CredentialStatusUnencryptedResult": { - "type": "object", - "properties": { - "resource": { - "type": "object", - "properties": { - "StatusList2021": { - "type": "object", - "properties": { - "encodedList": { - "type": "string", - "example": "H4sIAAAAAAAAA-3BAQ0AAADCoPdPbQ8HFAAAAAAAAAAAAAAAAAAAAADwaDhDr_xcRAAA" - }, - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "validFrom": { - "type": "string", - "format": "date-time", - "example": "2023-06-26T11:45:19.349Z" - } - } - }, - "metadata": { - "type": "object", - "properties": { - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "encoding": { - "type": "string", - "example": "base64url" - }, - "encrypted": { - "type": "boolean", - "example": false - } - } - } - } - }, - "resourceMetadata": { - "type": "object", - "example": { - "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceName": "cheqd-employee-credentials", - "resourceType": "StatusList2021Revocation", - "mediaType": "application/json", - "resourceVersion": "1.0.0", - "created": "2023-06-26T11:45:20Z", - "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", - "previousVersionId": null, - "nextVersionId": null - } - } - } - }, - "CredentialStatusCreateUnencryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "created": { - "type": "boolean", - "example": true - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" - } - ] - }, - "CredentialStatusEncryptedPaymentConditionsBody": { - "type": "object", - "properties": { - "feePaymentAddress": { - "description": "The cheqd/Cosmos payment address where payments to unlock the encrypted StatusList2021 DID-Linked Resource need to be sent.", - "type": "string", - "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" - }, - "feePaymentAmount": { - "description": "Amount in CHEQ tokens to unlock the encrypted StatusList2021 DID-Linked Resource.", - "type": "number", - "minimum": 0, - "exclusiveMinimum": true, - "default": 20 - }, - "feePaymentWindow": { - "description": "Time window (in minutes) within which the payment to unlock the encrypted StatusList2021 DID-Linked Resource is considered valid.", - "type": "number", - "minimum": 0, - "exclusiveMinimum": true, - "default": 10 - } - } - }, - "CredentialStatusEncryptedPaymentConditionsJson": { - "type": "object", - "properties": { - "paymentConditions": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" - } - ] - } - } - }, - "CredentialStatusCreateEncryptedFormRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCreateBody" - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" - }, - { - "type": "object", - "required": ["feePaymentAddress", "feePaymentAmount", "feePaymentWindow"] - } - ] - }, - "CredentialStatusCreateEncryptedJsonRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCreateBody" - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" - }, - { - "type": "object", - "required": ["paymentConditions"] - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials-encrypted", - "paymentConditions": [ - { - "feePaymentAddress": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg", - "feePaymentAmount": 20, - "feePaymentWindow": 10 - } - ] - } - }, - "CredentialStatusEncryptedResult": { - "type": "object", - "properties": { - "resource": { - "type": "object", - "properties": { - "StatusList2021": { - "type": "object", - "properties": { - "encodedList": { - "type": "string", - "example": "496fdfbeb745b4db03fcdb40566f9c4c4a1c0f184b31255e641b6e7bdfb9b6946c12be87ca3763be0393c00b67ac1e8737c106b32f46ef59c765754415b5e8cc7c65fccaa3374620430ea476301a5e0dd63340e7a27a68bc627518471f22e4a2" - }, - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "validFrom": { - "type": "string", - "format": "date-time", - "example": "2023-06-26T11:45:19.349Z" - } - } - }, - "metadata": { - "type": "object", - "properties": { - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "encoding": { - "type": "string", - "example": "base64url" - }, - "encrypted": { - "type": "boolean", - "example": true - }, - "encryptedSymmetricKey": { - "type": "string", - "example": "b11182dc524b8181f9a6aef4c4ad0a1c14e40033b9112dffd8d1bcf6cc3b85abc07ded2205ee94068a99f4202502cb0855f322583fa6ce1534d3a05bf36891766ea2c5f90a982b3040680762977d404d758a2370224a239c8279aa7d21e980931c42055b17ca4c7dbffa4782480a8b6279cf989b2f166d5fdb4b2c1b5a63927200000000000000203018dcaba26df45a415bb599218b27ca853a70289d7a3ed3ed0e3730452e8f8d9af91b6e71312565d2c069341f6660ab" - }, - "paymentConditions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "feePaymentAddress": { - "type": "string", - "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" - }, - "feePaymentAmount": { - "type": "string", - "example": "20000000000ncheq" - }, - "intervalInSeconds": { - "type": "number", - "example": 600 - }, - "type": { - "type": "string", - "example": "timelockPayment" - } - } - } - } - } - }, - "resourceMetadata": { - "type": "object", - "example": { - "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceName": "cheqd-revocation-encrypted-1", - "resourceType": "StatusList2021Revocation", - "mediaType": "application/json", - "resourceVersion": "2023-06-26T11:45:19.349Z", - "created": "2023-06-26T11:45:20Z", - "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", - "previousVersionId": null, - "nextVersionId": null - } - }, - "symmetricKey": { - "type": "string", - "example": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" - } - } - } - } - }, - "CredentialStatusCreateEncryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "created": { - "type": "boolean", - "example": true - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedResult" - } - ] - }, - "CredentialStatusUpdateBody": { - "type": "object", - "required": ["did", "statusListName", "indices"], - "properties": { - "did": { - "description": "DID of the StatusList2021 publisher.", - "type": "string", - "format": "uri" - }, - "statusListName": { - "description": "The name of the StatusList2021 DID-Linked Resource to be updated.", - "type": "string" - }, - "indices": { - "description": "List of credential status indices to be updated. The indices must be in the range of the status list.", - "type": "array", - "items": { - "type": "integer", - "minimum": 0, - "exclusiveMinimum": false - } - }, - "statusListVersion": { - "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - "CredentialStatusUpdateUnencryptedRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUpdateBody" - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials", - "indices": [10, 3199, 12109, 130999] - } - }, - "CredentialStatusUpdateUnencryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "updated": { - "type": "boolean", - "example": true - } - } - }, - { - "oneOf": [ - { - "$ref": "#/components/schemas/RevocationResult" - }, - { - "$ref": "#/components/schemas/SuspensionResult" - }, - { - "$ref": "#/components/schemas/UnsuspensionResult" - } - ] - }, - { - "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" - } - ] - }, - "CredentialStatusUpdateEncryptedFormRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUpdateBody" - }, - { - "type": "object", - "required": ["symmetricKey"], - "properties": { - "symmetricKey": { - "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" - } - ] - }, - "CredentialStatusUpdateEncryptedJsonRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUpdateBody" - }, - { - "type": "object", - "required": ["symmetricKey"], - "properties": { - "symmetricKey": { - "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials-encrypted", - "indices": [10, 3199, 12109, 130999], - "symmetricKey": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" - } - }, - "CredentialStatusUpdateEncryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "updated": { - "type": "boolean", - "example": true - } - } - }, - { - "oneOf": [ - { - "$ref": "#/components/schemas/RevocationResult" - }, - { - "$ref": "#/components/schemas/SuspensionResult" - }, - { - "$ref": "#/components/schemas/UnsuspensionResult" - } - ] - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedResult" - } - ] - }, - "CredentialStatusCheckRequest": { - "type": "object", - "required": ["did", "statusListName", "index"], - "properties": { - "did": { - "description": "DID of the StatusList2021 publisher.", - "type": "string", - "format": "uri" - }, - "statusListName": { - "description": "The name of the StatusList2021 DID-Linked Resource to be checked.", - "type": "string" - }, - "index": { - "description": "Credential status index to be checked for revocation or suspension.", - "type": "integer", - "minimum": 0, - "exclusiveMinimum": false - }, - "makeFeePayment": { - "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", - "type": "boolean", - "default": true - } - } - }, - "CredentialStatusCheckResult": { - "oneOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCheckRevocationResult" - }, - { - "$ref": "#/components/schemas/CredentialStatusCheckSuspensionResult" - } - ] - }, - "CredentialStatusCheckRevocationResult": { - "type": "object", - "properties": { - "checked": { - "type": "boolean", - "example": true - }, - "revoked": { - "type": "boolean", - "example": false - } - } - }, - "CredentialStatusCheckSuspensionResult": { - "type": "object", - "properties": { - "checked": { - "type": "boolean", - "example": true - }, - "suspended": { - "type": "boolean", - "example": false - } - } - }, - "CredentialStatusListSearchResult": { - "allOf": [ - { - "type": "object", - "properties": { - "found": { - "type": "boolean", - "example": true - } - } - }, - { - "oneOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedResult" - } - ] - } - ] - }, - "KeyImportRequest": { - "type": "object", - "properties": { - "alias": { - "type": "string" - }, - "type": { - "type": "string", - "enum": ["Ed25519", "Secp256k1"] - }, - "privateKeyHex": { - "type": "string" - } - } - }, - "KeyResult": { - "type": "object", - "properties": { - "kid": { - "type": "string" - }, - "type": { - "type": "string", - "enum": ["Ed25519", "Secp256k1"] - }, - "publicKeyHex": { - "type": "string" - } - } - }, - "DidDocument": { - "description": "This input field contains either a complete DID document, or an incremental change (diff) to a DID document. See Universal DID Registrar specification.", - "type": "object", - "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - } - }, - "id": { - "type": "string" - }, - "controllers": { - "type": "array", - "items": { - "type": "string" - } - }, - "verificationMethod": { - "type": "array", - "items": { - "$ref": "#/components/schemas/VerificationMethod" - } - }, - "service": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "authentication": { - "type": "array", - "items": { - "type": "string" - } - }, - "assertionMethod": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityInvocation": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityDelegation": { - "type": "array", - "items": { - "type": "string" - } - }, - "keyAgreement": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "@context": ["https://www.w3.org/ns/did/v1"], - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "controller": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0"], - "verificationMethod": [ - { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "type": "Ed25519VerificationKey2018", - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "publicKeyBase58": "z6MkkVbyHJLLjdjU5B62DaJ4mkdMdUkttf9UqySSkA9bVTeZ" - } - ], - "authentication": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1"], - "service": [ - { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", - "type": "LinkedDomains", - "serviceEndpoint": ["https://example.com"] - } - ] - } - }, - "DidDocumentWithoutVerificationMethod": { - "type": "object", - "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - } - }, - "id": { - "type": "string" - }, - "controllers": { - "type": "array", - "items": { - "type": "string" - } - }, - "service": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "authentication": { - "type": "array", - "items": { - "type": "string" - } - }, - "assertionMethod": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityInvocation": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityDelegation": { - "type": "array", - "items": { - "type": "string" - } - }, - "keyAgreement": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "@context": ["https://www.w3.org/ns/did/v1"], - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "controller": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0"], - "authentication": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1"], - "service": [ - { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", - "type": "LinkedDomains", - "serviceEndpoint": ["https://example.com"] - } - ] - } - }, - "DidCreateRequestFormBased": { - "type": "object", - "properties": { - "network": { - "description": "Network to create the DID on (testnet or mainnet)", - "type": "string", - "enum": ["testnet", "mainnet"] - }, - "identifierFormatType": { - "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", - "type": "string", - "enum": ["uuid", "base58btc"] - }, - "verificationMethodType": { - "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", - "type": "string", - "enum": ["Ed25519VerificationKey2018", "JsonWebKey2020", "Ed25519VerificationKey2020"] - }, - "service": { - "description": "It's a list of special objects which are designed to build the actual service. It's almost the same as in DID Core specification, but instead of `id` it utilises `idFragment` field for making the right `id` for each service. !!! WARN. Cause swagger-ui does not handle x-ww-form based arrays correctly, please frame all your services in brackets while using swagger UI. !!!", - "type": "array", - "items": { - "type": "object", - "properties": { - "idFragment": { - "type": "string" - }, - "type": { - "type": "string" - }, - "serviceEndpoint": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "example": [ - { - "idFragment": "service-1", - "type": "LinkedDomains", - "serviceEndpoint": ["https://example.com"] - } - ] - }, - "key": { - "description": "The unique identifier in hexadecimal public key format used in the verification method to create the DID.", - "type": "string" - }, - "@context": { - "type": "array", - "items": { - "type": "string" - }, - "example": ["https://www.w3.org/ns/did/v1"] - } - } - }, - "DidCreateRequestJson": { - "type": "object", - "properties": { - "network": { - "description": "Network to create the DID on (testnet or mainnet)", - "type": "string", - "enum": ["testnet", "mainnet"] - }, - "identifierFormatType": { - "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", - "type": "string", - "enum": ["uuid", "base58btc"] - }, - "assertionMethod": { - "description": "Usually a reference to a Verification Method. An Assertion Method is required to issue JSON-LD credentials. See DID Core specification for more details.", - "type": "boolean", - "default": true - }, - "options": { - "type": "object", - "properties": { - "key": { - "type": "string", - "example": "8255ddadd75695e01f3d98fcec8ccc7861a030b317d4326b0e48a4d579ddc43a" - }, - "verificationMethodType": { - "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", - "type": "string", - "enum": ["Ed25519VerificationKey2018", "JsonWebKey2020", "Ed25519VerificationKey2020"] - } - } - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocumentWithoutVerificationMethod" - } - } - }, - "DidImportRequest": { - "type": "object", - "properties": { - "did": { - "type": "string", - "description": "DID to be imported", - "format": "uri", - "required": true - }, - "keys": { - "type": "array", - "description": "List of keys required to import the DID", - "required": true, - "items": { - "$ref": "#/components/schemas/KeyImportRequest" - } - } - } - }, - "PresentationCreateResult": { - "type": "object", - "properties": { - "vp": { - "type": "object", - "description": "Verifiable Presentation which could be provided to the verifier." - }, - "nbf": { - "type": "integer", - "description": "Unix timestamp of the earliest time that the Verifiable Presentation is valid." - }, - "iss": { - "type": "string", - "description": "DID of the issuer of the Verifiable Presentation. (Here it's supposed to be a holder DID)" - }, - "aud": { - "type": "array", - "items": { - "type": "string" - }, - "description": "DID of the verifier of the Verifiable Presentation." - } - }, - "example": { - "vp": { - "@context": ["https://www.w3.org/2018/credentials/v1"], - "type": ["VerifiablePresentation"], - "verifiableCredential": [ - "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc2NoZW1hLm9yZy9zY2hlbWEuanNvbmxkIiwiaHR0cHM6Ly92ZXJhbW8uaW8vY29udGV4dHMvcHJvZmlsZS92MSIsImh0dHBzOi8vdzNpZC5vcmcvdmMtc3RhdHVzLWxpc3QtMjAyMS92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiUGVyc29uIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7Im5hbWUiOiJCb2IiLCJnZW5kZXIiOiJtYWxlIn0sImNyZWRlbnRpYWxTdGF0dXMiOnsiaWQiOiJodHRwczovL3Jlc29sdmVyLmNoZXFkLm5ldC8xLjAvaWRlbnRpZmllcnMvZGlkOmNoZXFkOnRlc3RuZXQ6OTBkNWMxNDEtNzI0Zi00N2FkLTlhZTctYTdjMzNhOWU1NjQzP3Jlc291cmNlTmFtZT1zdXNwZW5zaW9uRW4mcmVzb3VyY2VUeXBlPVN0YXR1c0xpc3QyMDIxU3VzcGVuc2lvbiMxMzMzOCIsInR5cGUiOiJTdGF0dXNMaXN0MjAyMUVudHJ5Iiwic3RhdHVzUHVycG9zZSI6InN1c3BlbnNpb24iLCJzdGF0dXNMaXN0SW5kZXgiOiIxMzMzOCJ9fSwic3ViIjoiZGlkOmtleTp6Nk1raGFYZ0JaRHZvdERrTDUyNTdmYWl6dGlHaUMyUXRLTEdwYm5uRUd0YTJkb0siLCJuYmYiOjE3MDA0NzM0MTYsImlzcyI6ImRpZDpjaGVxZDp0ZXN0bmV0OjkwZDVjMTQxLTcyNGYtNDdhZC05YWU3LWE3YzMzYTllNTY0MyJ9.-14Ril1pZEy2HEEo48gTJr2yOtGxBhUGTFmzVdjAtyhFRsW5zZg9onHt6V9JQ8BaiYBlTkP9GzTnJ-O6hdiyCw" - ] - }, - "nbf": 1700744275, - "iss": "did:cheqd:testnet:4b846d0f-2f6c-4ab6-9fe2-5b8db301c83c", - "aud": ["did:cheqd:testnet:8c71e9b6-c5a3-4250-8c58-fa591533cd22"] - } - }, - "DidResult": { - "type": "object", - "properties": { - "did": { - "type": "string" - }, - "controllerKeyId": { - "type": "string" - }, - "keys": { - "type": "array", - "items": { - "type": "object" - } - }, - "services": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - } - } - }, - "DidUpdateResponse": { - "type": "object", - "properties": { - "did": { - "type": "string" - }, - "controllerKeyId": { - "type": "string", - "description": "The default key id of which is the key associated with the first verificationMethod" - }, - "keys": { - "type": "array", - "description": "The list of keys associated with the list of verificationMethod's of DIDDocument", - "items": { - "type": "object" - } - }, - "services": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "controllerKeyRefs": { - "type": "array", - "description": "The list of keyRefs which were used for signing the transaction", - "items": { - "type": "string" - } - }, - "controllerKeys": { - "type": "array", - "description": "The list of all possible keys, inlcuding all controller's keys", - "items": { - "type": "string" - } - } - } - }, - "VerificationMethod": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string" - }, - "controller": { - "type": "string" - }, - "publicKeyMultibase": { - "type": "string" - }, - "publicKeyJwk": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "id": "did:cheqd:testnet :7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", - "type": "Ed25519VerificationKey2018" - } - }, - "Service": { - "description": "Communicating or interacting with the DID subject or associated entities via one or more service endpoints. See DID Core specification for more details.", - "type": "object", - "properties": { - "id": { - "description": "DID appended with Service fragment ID (e.g., `#service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`)", - "type": "string", - "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1" - }, - "type": { - "description": "Service type as defined in DID Specification Registries.", - "type": "string", - "example": "LinkedDomains" - }, - "serviceEndpoint": { - "description": "Service endpoint as defined in DID Core Specification.", - "type": "array", - "items": { - "type": "string", - "example": "https://example.com" - } - } - } - }, - "DidUpdateRequest": { - "type": "object", - "properties": { - "did": { - "description": "DID identifier to be updated.", - "type": "string", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "service": { - "type": "array", - "description": "Service section of the DID Document.", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "verificationMethod": { - "type": "array", - "description": "Verification Method section of the DID Document.", - "items": { - "$ref": "#/components/schemas/VerificationMethod" - } - }, - "authentication": { - "description": "Authentication section of the DID Document.", - "type": "array", - "items": { - "type": "string" - } - }, - "publicKeyHexs": { - "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", - "type": "array", - "items": { - "type": "string" - } - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - } - } - }, - "DidDeactivateRequest": { - "type": "object", - "properties": { - "publicKeyHexs": { - "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "CreateResourceRequest": { - "description": "Input fields for DID-Linked Resource creation.", - "type": "object", - "additionalProperties": false, - "required": ["name", "type", "data", "encoding"], - "properties": { - "data": { - "description": "Encoded string containing the data to be stored in the DID-Linked Resource.", - "type": "string" - }, - "encoding": { - "description": "Encoding format used to encode the data.", - "type": "string", - "enum": ["base64url", "base64", "hex"] - }, - "name": { - "description": "Name of DID-Linked Resource.", - "type": "string" - }, - "type": { - "description": "Type of DID-Linked Resource. This is NOT the same as the media type, which is calculated automatically ledger-side.", - "type": "string" - }, - "alsoKnownAs": { - "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", - "type": "array", - "items": { - "type": "object", - "properties": { - "uri": { - "type": "string" - }, - "description": { - "type": "string" - } - } - } - }, - "version": { - "description": "Optional field to assign a human-readable version in the DID-Linked Resource.", - "type": "string" - }, - "publicKeyHexs": { - "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "data": "SGVsbG8gV29ybGQ=", - "encoding": "base64url", - "name": "ResourceName", - "type": "TextDocument" - } - }, - "ResourceList": { - "type": "object", - "properties": { - "@context": { - "type": "string", - "example": "https://w3id.org/did-resolution/v1" - }, - "contentMetadata": { - "type": "object" - }, - "contentStream": { - "type": "object" - }, - "dereferencingMetadata": { - "$ref": "#/components/schemas/DereferencingMetadata" - } - } - }, - "DereferencingMetadata": { - "type": "object", - "properties": { - "contentType": { - "type": "string", - "example": "application/did+ld+json" - }, - "did": { - "$ref": "#/components/schemas/DidProperties" - }, - "retrieved": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - } - } - }, - "DidResolution": { - "type": "object", - "properties": { - "@context": { - "type": "string", - "example": "https://w3id.org/did-resolution/v1" - }, - "didDidResolutionMetadata": { - "$ref": "#/components/schemas/DidResolutionMetadata" - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - }, - "didDocumentMetadata": { - "$ref": "#/components/schemas/DidDocumentMetadata" - } - } - }, - "DeactivatedDidResolution": { - "type": "object", - "properties": { - "@context": { - "type": "string", - "example": "https://w3id.org/did-resolution/v1" - }, - "didDidResolutionMetadata": { - "$ref": "#/components/schemas/DidResolutionMetadata" - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - }, - "didDocumentMetadata": { - "$ref": "#/components/schemas/DeactivatedDidDocumentMetadata" - } - } - }, - "DidDocumentMetadata": { - "type": "object", - "properties": { - "created": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "deactivated": { - "type": "boolean", - "example": false - }, - "updated": { - "type": "string", - "example": "2021-09-10T12:00:00Z" - }, - "versionId": { - "type": "string", - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - "linkedResourceMetadata": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ResourceMetadata" - } - } - } - }, - "DeactivatedDidDocumentMetadata": { - "type": "object", - "properties": { - "created": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "deactivated": { - "type": "boolean", - "example": true - }, - "updated": { - "type": "string", - "example": "2021-09-10T12:00:00Z" - }, - "versionId": { - "type": "string", - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - "linkedResourceMetadata": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ResourceMetadata" - } - } - } - }, - "ResourceMetadata": { - "type": "object", - "properties": { - "resourceURI": { - "type": "string", - "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47/resources/398cee0a-efac-4643-9f4c-74c48c72a14b" - }, - "resourceCollectionId": { - "type": "string", - "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" - }, - "resourceId": { - "type": "string", - "example": "398cee0a-efac-4643-9f4c-74c48c72a14b" - }, - "resourceName": { - "type": "string", - "example": "cheqd-issuer-logo" - }, - "resourceType": { - "type": "string", - "example": "CredentialArtwork" - }, - "mediaType": { - "type": "string", - "example": "image/png" - }, - "resourceVersion": { - "type": "string", - "example": "1.0" - }, - "checksum": { - "type": "string", - "example": "a95380f460e63ad939541a57aecbfd795fcd37c6d78ee86c885340e33a91b559" - }, - "created": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "nextVersionId": { - "type": "string", - "example": "d4829ac7-4566-478c-a408-b44767eddadc" - }, - "previousVersionId": { - "type": "string", - "example": "ad7a8442-3531-46eb-a024-53953ec6e4ff" - } - } - }, - "DidResolutionMetadata": { - "type": "object", - "properties": { - "contentType": { - "allOf": [ - { - "$ref": "#/components/schemas/ContentType" - } - ], - "example": "application/did+ld+json" - }, - "retrieved": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "did": { - "$ref": "#/components/schemas/DidProperties" - } - } - }, - "ContentType": { - "type": "string", - "enum": ["application/did+json", "application/did+ld+json", "application/ld+json", "application/json"] - }, - "DidProperties": { - "type": "object", - "properties": { - "didString": { - "type": "string", - "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" - }, - "method": { - "type": "string", - "example": "cheqd" - }, - "methodSpecificId": { - "type": "string", - "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" - } - } - }, - "Customer": { - "type": "object", - "properties": { - "customerId": { - "type": "string", - "example": "6w5drpiiwhhs" - }, - "address": { - "type": "string", - "example": "cheqd1wgsvqwlkmdp60f4dek26ak0sjw6au3ytd3pz7f" - } - } - }, - "AccountCreateRequest": { - "type": "object", - "properties": { - "user": { - "type": "object", - "properties": { - "primaryEmail": { - "type": "string" - } - } - } - } - }, - "InvalidRequest": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "InvalidRequest" - } - } - }, - "InternalError": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Internal Error" - } - } - }, - "UnauthorizedError": { - "description": "Access token is missing or invalid", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Unauthorized Error" - } - } - } - } - } -} + "openapi": "3.0.0", + "info": { + "title": "Credential Service API for cheqd network", + "version": "2.0.0", + "description": "API service to create and manage DIDs, Verifiable Credentials, and DID-Linked Resources", + "contact": { + "name": "Cheqd Foundation Limited", + "url": "https://github.com/cheqd/credential-service", + "email": "support-github@cheqd.io" + }, + "license": { + "name": "Apache 2.0", + "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" + } + }, + "tags": [ + { + "name": "Account" + }, + { + "name": "Key" + }, + { + "name": "DID" + }, + { + "name": "Resource" + }, + { + "name": "Credential" + }, + { + "name": "Presentation" + }, + { + "name": "Credential Status" + } + ], + "externalDocs": { + "description": "Credential Service API Documentation", + "url": "https://docs.cheqd.io/identity" + }, + "paths": { + "/account": { + "get": { + "tags": [ + "Account" + ], + "summary": "Fetch custodian-mode client details.", + "description": "This endpoint returns the custodian-mode client details for authenticated users.", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Customer" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/account/idtoken": { + "get": { + "tags": [ + "Account" + ], + "summary": "Fetch IdToken.", + "description": "This endpoint returns IdToken as JWT with list of user roles inside", + "deprecated": true, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "idToken": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/account/create": { + "post": { + "tags": [ + "Account" + ], + "summary": "Create an client for an authenticated user.", + "description": "This endpoint creates a client in the custodian-mode for an authenticated user", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/AccountCreateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "idToken": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/create/unencrypted": { + "post": { + "tags": [ + "Credential Status" + ], + "summary": "Create an unencrypted StatusList2021 credential status list.", + "description": "This endpoint creates an unencrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", + "required": true, + "schema": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/create/encrypted": { + "post": { + "tags": [ + "Credential Status" + ], + "summary": "Create an encrypted StatusList2021 credential status list.", + "description": "This endpoint creates an encrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", + "required": true, + "schema": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateEncryptedFormRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateEncryptedJsonRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateEncryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/update/unencrypted": { + "post": { + "tags": [ + "Credential Status" + ], + "summary": "Update an existing unencrypted StatusList2021 credential status list.", + "parameters": [ + { + "in": "query", + "name": "statusAction", + "description": "The update action to be performed on the unencrypted status list, can be revoke, suspend or reinstate", + "required": true, + "schema": { + "type": "string", + "enum": [ + "revoke", + "suspend", + "reinstate" + ] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/update/encrypted": { + "post": { + "tags": [ + "Credential Status" + ], + "summary": "Update an existing encrypted StatusList2021 credential status list.", + "parameters": [ + { + "in": "query", + "name": "statusAction", + "description": "The update action to be performed on the encrypted status list, can be revoke, suspend or reinstate", + "required": true, + "schema": { + "type": "string", + "enum": [ + "revoke", + "suspend", + "reinstate" + ] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedFormRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedJsonRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/check": { + "post": { + "tags": [ + "Credential Status" + ], + "summary": "Check a StatusList2021 index for a given Verifiable Credential.", + "description": "This endpoint checks a StatusList2021 index for a given Verifiable Credential and reports whether it is revoked or suspended. It offers a standalone method for checking an index without passing the entire Verifiable Credential or Verifiable Presentation.", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension.", + "required": true, + "schema": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCheckRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCheckRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCheckResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/search": { + "get": { + "tags": [ + "Credential Status" + ], + "summary": "Fetch StatusList2021 DID-Linked Resource based on search criteria.", + "parameters": [ + { + "in": "query", + "name": "did", + "description": "The DID of the issuer of the status list.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension.", + "schema": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ] + } + }, + { + "in": "query", + "name": "statusListName", + "description": "The name of the StatusList2021 DID-Linked Resource.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusListSearchResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/issue": { + "post": { + "tags": [ + "Credential" + ], + "summary": "Issue a Verifiable Credential", + "description": "This endpoint issues a Verifiable Credential. As input it takes the list of issuerDid, subjectDid, attributes, and other parameters of the credential to be issued.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Credential" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/verify": { + "post": { + "tags": [ + "Credential" + ], + "summary": "Verify a Verifiable Credential.", + "description": "This endpoint verifies a Verifiable Credential passed to it. As input, it can take the VC-JWT as a string or the entire credential itself.", + "operationId": "verify", + "parameters": [ + { + "in": "query", + "name": "verifyStatus", + "description": "If set to `true` the verification will also check the status of the credential. Requires the VC to have a `credentialStatus` property.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "fetchRemoteContexts", + "description": "When dealing with JSON-LD you also MUST provide the proper contexts. Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "allowDeactivatedDid", + "description": "If set to `true` allow to verify credential which based on deactivated DID.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialVerifyRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialVerifyRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyCredentialResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/revoke": { + "post": { + "tags": [ + "Credential" + ], + "summary": "Revoke a Verifiable Credential.", + "description": "This endpoint revokes a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself. The StatusList2021 resource should already be setup in the VC and `credentialStatus` property present in the VC.", + "operationId": "revoke", + "parameters": [ + { + "in": "query", + "name": "publish", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RevocationResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/suspend": { + "post": { + "tags": [ + "Credential" + ], + "summary": "Suspend a Verifiable Credential.", + "description": "This endpoint suspends a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself.", + "operationId": "suspend", + "parameters": [ + { + "in": "query", + "name": "publish", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuspensionResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/reinstate": { + "post": { + "tags": [ + "Credential" + ], + "summary": "Reinstate a suspended Verifiable Credential.", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "operationId": "reinstate", + "parameters": [ + { + "in": "query", + "name": "publish", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnsuspensionResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/create": { + "post": { + "tags": [ + "DID" + ], + "summary": "Create a DID Document.", + "description": "This endpoint creates a DID and associated DID Document. As input, it can take the DID Document parameters via a form, or the fully-assembled DID Document itself.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidCreateRequestFormBased" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidCreateRequestJson" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/did/update": { + "post": { + "tags": [ + "DID" + ], + "summary": "Update a DID Document.", + "description": "This endpoint updates a DID Document. As an input, it can take JUST the sections/parameters that need to be updated in the DID Document (in this scenario, it fetches the current DID Document and applies the updated section). Alternatively, it take the fully-assembled DID Document with updated sections as well as unchanged sections.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidUpdateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidUpdateResponse" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/import": { + "post": { + "tags": [ + "DID" + ], + "summary": "Import a DID Document.", + "description": "This endpoint imports a decentralized identifier associated with the user's account for custodian-mode clients.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidImportRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidImportRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/did/deactivate/{did}": { + "post": { + "tags": [ + "DID" + ], + "summary": "Deactivate a DID Document.", + "description": "This endpoint deactivates a DID Document by taking the DID identifier as input. Must be called and signed by the DID owner.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier to deactivate.", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidDeactivateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidDeactivateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeactivatedDidResolution" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/list": { + "get": { + "tags": [ + "DID" + ], + "summary": "Fetch DIDs associated with an account.", + "description": "This endpoint returns the list of DIDs controlled by the account.", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/search/{did}": { + "get": { + "tags": [ + "DID" + ], + "summary": "Resolve a DID Document.", + "description": "Resolve a DID Document by DID identifier. Also supports DID Resolution Queries as defined in the W3C DID Resolution specification.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier to resolve.", + "schema": { + "type": "string" + }, + "required": true, + "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + { + "in": "query", + "name": "metadata", + "description": "Return only metadata of DID Document instead of actual DID Document.", + "schema": { + "type": "boolean" + } + }, + { + "in": "query", + "name": "versionId", + "description": "Unique UUID version identifier of DID Document. Allows for fetching a specific version of the DID Document. See cheqd DID Method Specification for more details.", + "schema": { + "type": "string", + "format": "uuid" + }, + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + { + "in": "query", + "name": "versionTime", + "description": "Returns the closest version of the DID Document *at* or *before* specified time. See DID Resolution handling for `did:cheqd` for more details.", + "schema": { + "type": "string", + "format": "date-time" + }, + "example": "1970-01-01T00:00:00Z" + }, + { + "in": "query", + "name": "transformKeys", + "description": "This directive transforms the Verification Method key format from the version in the DID Document to the specified format chosen below.", + "schema": { + "type": "string", + "enum": [ + "Ed25519VerificationKey2018", + "Ed25519VerificationKey2020", + "JsonWebKey2020" + ] + } + }, + { + "in": "query", + "name": "service", + "description": "Query DID Document for a specific Service Endpoint by Service ID (e.g., `service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`). This will typically redirect to the Service Endpoint based on DID Resolution specification algorithm.", + "schema": { + "type": "string" + }, + "example": "service-1" + }, + { + "in": "query", + "name": "relativeRef", + "description": "Relative reference is a query fragment appended to the Service Endpoint URL. **Must** be used along with the `service` query property above. See DID Resolution specification algorithm for more details.", + "schema": { + "type": "string" + }, + "example": "/path/to/file" + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResolution" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/key/create": { + "post": { + "tags": [ + "Key" + ], + "summary": "Create an identity key pair.", + "description": "This endpoint creates an identity key pair associated with the user's account for custodian-mode clients.", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/key/import": { + "post": { + "tags": [ + "Key" + ], + "summary": "Import an identity key pair.", + "description": "This endpoint imports an identity key pair associated with the user's account for custodian-mode clients.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/KeyImportRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyImportRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/key/read/{kid}": { + "get": { + "tags": [ + "Key" + ], + "summary": "Fetch an identity key pair.", + "description": "This endpoint fetches an identity key pair's details for a given key ID. Only the user account associated with the custodian-mode client can fetch the key pair.", + "parameters": [ + { + "name": "kid", + "description": "Key ID of the identity key pair to fetch.", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/presentation/create": { + "post": { + "tags": [ + "Presentation" + ], + "summary": "!!! WARN. Such endpoint is made mostly for testing purposes and it is not supposed to be used in production !!! Create a Verifiable Presentation from credential(s).", + "description": "This endpoint creates a Verifiable Presentation from credential(s). As input, it can take the credential(s) as a string or the entire credential(s) itself. \n !!! WARN. Such endpoint is made only for testing purposes !!!", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/PresentationCreateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationCreateResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/presentation/verify": { + "post": { + "tags": [ + "Presentation" + ], + "summary": "Verify a Verifiable Presentation generated from credential(s).", + "description": "This endpoint verifies the Verifiable Presentation generated from credential(s). As input, it can take the Verifiable Presentation JWT as a string or the entire Verifiable Presentation itself.", + "parameters": [ + { + "in": "query", + "name": "verifyStatus", + "description": "If set to `true` the verification will also check the status of the presentation. Requires the VP to have a `credentialStatus` property.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "fetchRemoteContexts", + "description": "When dealing with JSON-LD you also MUST provide the proper contexts. * Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "allowDeactivatedDid", + "description": "If set to `true` allow to verify credential which based on deactivated DID.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/PresentationVerifyRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationVerifyRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyPresentationResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/resource/create/{did}": { + "post": { + "tags": [ + "Resource" + ], + "summary": "Create a DID-Linked Resource.", + "description": "This endpoint creates a DID-Linked Resource. As input, it can take the DID identifier and the resource parameters via a form, or the fully-assembled resource itself.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier to link the resource to.", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CreateResourceRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateResourceRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceMetadata" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/resource/search/{did}": { + "get": { + "tags": [ + "Resource" + ], + "summary": "Get a DID-Linked Resource.", + "description": "This endpoint returns the DID-Linked Resource for a given DID identifier and resource identifier.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier", + "schema": { + "type": "string" + }, + "required": true, + "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + { + "in": "query", + "name": "resourceId", + "description": "Fetch a DID-Linked Resource by Resource ID unique identifier. Since this is a unique identifier, other Resource query parameters are not required. See DID-Linked Resources for more details.", + "schema": { + "type": "string", + "format": "uuid" + }, + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + { + "in": "query", + "name": "resourceName", + "description": "Filter a DID-Linked Resource query by Resource Name. See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "cheqd-issuer-logo" + }, + { + "in": "query", + "name": "resourceType", + "description": "Filter a DID-Linked Resource query by Resource Type. See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "CredentialArtwork" + }, + { + "in": "query", + "name": "resourceVersion", + "description": "Filter a DID-Linked Resource query by Resource Version, which is an optional free-text field used by issuers (e.g., \"v1\", \"Final Version\", \"1st January 1970\" etc). See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "v1" + }, + { + "in": "query", + "name": "resourceVersionTime", + "description": "Filter a DID-Linked Resource query which returns the closest version of the Resource *at* or *before* specified time. See DID-Linked Resources for more details.", + "schema": { + "type": "string", + "format": "date-time" + }, + "example": "1970-01-01T00:00:00Z" + }, + { + "in": "query", + "name": "checksum", + "description": "Request integrity check against a given DID-Linked Resource by providing a SHA-256 checksum hash. See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "dc64474d062ed750a66bad58cb609928de55ed0d81defd231a4a4bf97358e9ed" + }, + { + "in": "query", + "name": "resourceMetadata", + "description": "Return only metadata of DID-Linked Resource instead of actual DID-Linked Resource. Mutually exclusive with some of the other parameters.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "any": { + "schema": { + "type": "object" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + } + }, + "components": { + "schemas": { + "AlsoKnownAs": { + "type": "object", + "properties": { + "alsoKnownAs": { + "type": "array", + "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", + "items": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "format": "uri", + "description": "URI where the DID-Linked Resource can be fetched from. Can be any type of URI (e.g., DID, HTTPS, IPFS, etc.)" + }, + "description": { + "type": "string", + "description": "Optional description of the URI." + } + } + } + } + } + }, + "CredentialRequest": { + "description": "Input fields for the creating a Verifiable Credential.", + "type": "object", + "additionalProperties": false, + "properties": { + "issuerDid": { + "description": "DID of the Verifiable Credential issuer. This needs to be a `did:cheqd` DID.", + "type": "string", + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + "subjectDid": { + "description": "DID of the Verifiable Credential holder/subject. This needs to be a `did:key` DID.", + "type": "string", + "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" + }, + "attributes": { + "description": "JSON object containing the attributes to be included in the credential.", + "type": "object", + "example": { + "name": "Bob", + "gender": "male" + } + }, + "@context": { + "description": "Optional properties to be included in the `@context` property of the credential.", + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "https://schema.org/schema.jsonld", + "https://veramo.io/contexts/profile/v1" + ] + }, + "type": { + "description": "Optional properties to be included in the `type` property of the credential.", + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "Person" + ] + }, + "expirationDate": { + "description": "Optional expiration date according to the VC Data Model specification.", + "type": "string", + "format": "date-time", + "example": "2023-06-08T13:49:28.000Z" + }, + "format": { + "description": "Format of the Verifiable Credential. Defaults to VC-JWT.", + "type": "string", + "enum": [ + "jwt", + "jsonld" + ], + "example": "jwt" + }, + "credentialStatus": { + "description": "Optional `credentialStatus` properties for VC revocation or suspension. Takes `statusListName` and `statusListPurpose` as inputs.", + "type": "object", + "required": [ + "statusPurpose", + "statusListName" + ], + "properties": { + "statusPurpose": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ] + }, + "statusListName": { + "type": "string" + }, + "statusListIndex": { + "type": "number" + }, + "statusListVersion": { + "type": "string", + "format": "date-time" + }, + "statusListRangeStart": { + "type": "number" + }, + "statusListRangeEnd": { + "type": "number" + }, + "indexNotIn": { + "type": "number" + } + }, + "example": { + "statusPurpose": "revocation", + "statusListName": "employee-credentials" + } + } + }, + "required": [ + "issuerDid", + "subjectDid", + "attributes" + ], + "example": { + "issuerDid": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "subjectDid": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", + "attributes": { + "gender": "male", + "name": "Bob" + }, + "@context": [ + "https://schema.org" + ], + "type": [ + "Person" + ], + "format": "jwt", + "credentialStatus": { + "statusPurpose": "revocation", + "statusListName": "employee-credentials", + "statusListIndex": 10 + } + } + }, + "Credential": { + "description": "Input fields for revoking/suspending a Verifiable Credential.", + "type": "object", + "additionalProperties": false, + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "https://www.w3.org/2018/credentials/v1", + "https://schema.org", + "https://veramo.io/contexts/profile/v1" + ] + }, + "type": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "VerifiableCredential", + "Person" + ] + }, + "expirationDate": { + "type": "string", + "format": "date-time", + "example": "2023-06-08T13:49:28.000Z" + }, + "issuer": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "DID", + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + } + } + }, + "credentialSubject": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "DID", + "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" + } + } + }, + "credentialStatus": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20" + }, + "statusListIndex": { + "type": "number", + "example": 20 + }, + "statusPurpose": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ], + "example": "suspension" + }, + "type": { + "type": "string", + "enum": [ + "StatusList2021Entry" + ] + } + } + }, + "issuanceDate": { + "type": "string", + "format": "date-time", + "example": "2023-06-08T13:49:28.000Z" + }, + "proof": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "jwt": { + "type": "string" + } + }, + "example": { + "type": "JwtProof2020", + "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg" + } + } + }, + "example": { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://schema.org", + "https://veramo.io/contexts/profile/v1" + ], + "credentialSubject": { + "gender": "male", + "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", + "name": "Bob" + }, + "credentialStatus": { + "id": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20", + "statusIndex": 20, + "statusPurpose": "suspension", + "type": "StatusList2021Entry" + }, + "issuanceDate": "2023-06-08T13:49:28.000Z", + "issuer": { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + "proof": { + "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg", + "type": "JwtProof2020" + }, + "type": [ + "VerifiableCredential", + "Person" + ] + } + }, + "CredentialRevokeRequest": { + "type": "object", + "properties": { + "credential": { + "description": "Verifiable Credential to be revoked as a VC-JWT string or a JSON object.", + "oneOf": [ + { + "type": "object" + }, + { + "type": "string" + } + ] + }, + "symmetricKey": { + "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource. Required if the StatusList2021 DID-Linked Resource is encrypted.", + "type": "string" + } + } + }, + "RevocationResult": { + "properties": { + "revoked": { + "type": "boolean", + "example": true + } + } + }, + "SuspensionResult": { + "properties": { + "suspended": { + "type": "boolean", + "example": true + } + } + }, + "UnsuspensionResult": { + "properties": { + "unsuspended": { + "type": "boolean", + "example": true + } + } + }, + "CredentialVerifyRequest": { + "type": "object", + "properties": { + "credential": { + "description": "Verifiable Credential to be verified as a VC-JWT string or a JSON object.", + "type": "object" + }, + "policies": { + "description": "Custom verification policies to execute when verifying credential.", + "type": "object", + "properties": { + "issuanceDate": { + "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "expirationDate": { + "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "audience": { + "description": "Policy to skip the audience check when set to `false`.", + "type": "boolean", + "default": false + } + } + } + } + }, + "VerifyPresentationResult": { + "type": "object", + "properties": { + "verified": { + "type": "boolean" + }, + "issuer": { + "type": "string" + }, + "signer": { + "type": "object" + }, + "jwt": { + "type": "string" + }, + "verifiableCredential": { + "type": "object" + } + } + }, + "VerifyCredentialResult": { + "type": "object", + "properties": { + "verified": { + "type": "boolean" + }, + "issuer": { + "type": "string" + }, + "signer": { + "type": "object" + }, + "jwt": { + "type": "string" + }, + "verifiableCredential": { + "type": "object" + } + }, + "example": { + "verified": true, + "polices": {}, + "issuer": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "signer": { + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", + "type": "Ed25519VerificationKey2018" + } + } + }, + "PresentationCreateRequest": { + "type": "object", + "required": [ + "credentials" + ], + "properties": { + "credentials": { + "description": "Verifiable Credentials to be used for VP-JWT creation as a VP-JWT strings or a JSON objectsf.", + "type": "array", + "items": { + "type": "object" + } + }, + "holderDid": { + "description": "DID of holder", + "type": "string" + }, + "verifierDid": { + "description": "DID of verifier", + "type": "string" + } + } + }, + "PresentationVerifyRequest": { + "type": "object", + "required": [ + "presentation" + ], + "properties": { + "presentation": { + "description": "Verifiable Presentation to be verified as a VP-JWT string or a JSON object.", + "type": "object" + }, + "verifierDid": { + "description": "Provide an optional verifier DID (also known as 'domain' parameter), if the verifier DID in the presentation is not managed in the wallet.", + "type": "string" + }, + "makeFeePayment": { + "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", + "type": "boolean", + "default": false + }, + "policies": { + "description": "Custom verification policies to execute when verifying presentation.", + "type": "object", + "properties": { + "issuanceDate": { + "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "expirationDate": { + "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "audience": { + "description": "Policy to skip the audience check when set to `false`.", + "type": "boolean", + "default": false + } + } + } + } + }, + "CredentialStatusCreateBody": { + "allOf": [ + { + "type": "object", + "required": [ + "did", + "statusListName" + ], + "properties": { + "did": { + "description": "DID of the StatusList2021 publisher.", + "type": "string", + "format": "uri" + }, + "statusListName": { + "description": "The name of the StatusList2021 DID-Linked Resource to be created.", + "type": "string" + }, + "length": { + "description": "The length of the status list to be created. The default and minimum length is 140000 which is 16kb.", + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true, + "default": 140000 + }, + "encoding": { + "description": "The encoding format of the StatusList2021 DiD-Linked Resource to be created.", + "type": "string", + "default": "base64url", + "enum": [ + "base64url", + "base64", + "hex" + ] + }, + "statusListVersion": { + "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/AlsoKnownAs" + } + ] + }, + "CredentialStatusCreateUnencryptedRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCreateBody" + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials", + "length": 140000, + "encoding": "base64url" + } + }, + "CredentialStatusUnencryptedResult": { + "type": "object", + "properties": { + "resource": { + "type": "object", + "properties": { + "StatusList2021": { + "type": "object", + "properties": { + "encodedList": { + "type": "string", + "example": "H4sIAAAAAAAAA-3BAQ0AAADCoPdPbQ8HFAAAAAAAAAAAAAAAAAAAAADwaDhDr_xcRAAA" + }, + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "validFrom": { + "type": "string", + "format": "date-time", + "example": "2023-06-26T11:45:19.349Z" + } + } + }, + "metadata": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "encoding": { + "type": "string", + "example": "base64url" + }, + "encrypted": { + "type": "boolean", + "example": false + } + } + } + } + }, + "resourceMetadata": { + "type": "object", + "example": { + "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceName": "cheqd-employee-credentials", + "resourceType": "StatusList2021Revocation", + "mediaType": "application/json", + "resourceVersion": "1.0.0", + "created": "2023-06-26T11:45:20Z", + "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", + "previousVersionId": null, + "nextVersionId": null + } + } + } + }, + "CredentialStatusCreateUnencryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "created": { + "type": "boolean", + "example": true + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" + } + ] + }, + "CredentialStatusEncryptedPaymentConditionsBody": { + "type": "object", + "properties": { + "feePaymentAddress": { + "description": "The cheqd/Cosmos payment address where payments to unlock the encrypted StatusList2021 DID-Linked Resource need to be sent.", + "type": "string", + "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" + }, + "feePaymentAmount": { + "description": "Amount in CHEQ tokens to unlock the encrypted StatusList2021 DID-Linked Resource.", + "type": "number", + "minimum": 0, + "exclusiveMinimum": true, + "default": 20 + }, + "feePaymentWindow": { + "description": "Time window (in minutes) within which the payment to unlock the encrypted StatusList2021 DID-Linked Resource is considered valid.", + "type": "number", + "minimum": 0, + "exclusiveMinimum": true, + "default": 10 + } + } + }, + "CredentialStatusEncryptedPaymentConditionsJson": { + "type": "object", + "properties": { + "paymentConditions": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" + } + ] + } + } + }, + "CredentialStatusCreateEncryptedFormRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCreateBody" + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" + }, + { + "type": "object", + "required": [ + "feePaymentAddress", + "feePaymentAmount", + "feePaymentWindow" + ] + } + ] + }, + "CredentialStatusCreateEncryptedJsonRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCreateBody" + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" + }, + { + "type": "object", + "required": [ + "paymentConditions" + ] + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials-encrypted", + "paymentConditions": [ + { + "feePaymentAddress": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg", + "feePaymentAmount": 20, + "feePaymentWindow": 10 + } + ] + } + }, + "CredentialStatusEncryptedResult": { + "type": "object", + "properties": { + "resource": { + "type": "object", + "properties": { + "StatusList2021": { + "type": "object", + "properties": { + "encodedList": { + "type": "string", + "example": "496fdfbeb745b4db03fcdb40566f9c4c4a1c0f184b31255e641b6e7bdfb9b6946c12be87ca3763be0393c00b67ac1e8737c106b32f46ef59c765754415b5e8cc7c65fccaa3374620430ea476301a5e0dd63340e7a27a68bc627518471f22e4a2" + }, + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "validFrom": { + "type": "string", + "format": "date-time", + "example": "2023-06-26T11:45:19.349Z" + } + } + }, + "metadata": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "encoding": { + "type": "string", + "example": "base64url" + }, + "encrypted": { + "type": "boolean", + "example": true + }, + "encryptedSymmetricKey": { + "type": "string", + "example": "b11182dc524b8181f9a6aef4c4ad0a1c14e40033b9112dffd8d1bcf6cc3b85abc07ded2205ee94068a99f4202502cb0855f322583fa6ce1534d3a05bf36891766ea2c5f90a982b3040680762977d404d758a2370224a239c8279aa7d21e980931c42055b17ca4c7dbffa4782480a8b6279cf989b2f166d5fdb4b2c1b5a63927200000000000000203018dcaba26df45a415bb599218b27ca853a70289d7a3ed3ed0e3730452e8f8d9af91b6e71312565d2c069341f6660ab" + }, + "paymentConditions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "feePaymentAddress": { + "type": "string", + "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" + }, + "feePaymentAmount": { + "type": "string", + "example": "20000000000ncheq" + }, + "intervalInSeconds": { + "type": "number", + "example": 600 + }, + "type": { + "type": "string", + "example": "timelockPayment" + } + } + } + } + } + }, + "resourceMetadata": { + "type": "object", + "example": { + "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceName": "cheqd-revocation-encrypted-1", + "resourceType": "StatusList2021Revocation", + "mediaType": "application/json", + "resourceVersion": "2023-06-26T11:45:19.349Z", + "created": "2023-06-26T11:45:20Z", + "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", + "previousVersionId": null, + "nextVersionId": null + } + }, + "symmetricKey": { + "type": "string", + "example": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" + } + } + } + } + }, + "CredentialStatusCreateEncryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "created": { + "type": "boolean", + "example": true + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedResult" + } + ] + }, + "CredentialStatusUpdateBody": { + "type": "object", + "required": [ + "did", + "statusListName", + "indices" + ], + "properties": { + "did": { + "description": "DID of the StatusList2021 publisher.", + "type": "string", + "format": "uri" + }, + "statusListName": { + "description": "The name of the StatusList2021 DID-Linked Resource to be updated.", + "type": "string" + }, + "indices": { + "description": "List of credential status indices to be updated. The indices must be in the range of the status list.", + "type": "array", + "items": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": false + } + }, + "statusListVersion": { + "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + "CredentialStatusUpdateUnencryptedRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUpdateBody" + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials", + "indices": [ + 10, + 3199, + 12109, + 130999 + ] + } + }, + "CredentialStatusUpdateUnencryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "updated": { + "type": "boolean", + "example": true + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/RevocationResult" + }, + { + "$ref": "#/components/schemas/SuspensionResult" + }, + { + "$ref": "#/components/schemas/UnsuspensionResult" + } + ] + }, + { + "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" + } + ] + }, + "CredentialStatusUpdateEncryptedFormRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUpdateBody" + }, + { + "type": "object", + "required": [ + "symmetricKey" + ], + "properties": { + "symmetricKey": { + "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" + } + ] + }, + "CredentialStatusUpdateEncryptedJsonRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUpdateBody" + }, + { + "type": "object", + "required": [ + "symmetricKey" + ], + "properties": { + "symmetricKey": { + "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials-encrypted", + "indices": [ + 10, + 3199, + 12109, + 130999 + ], + "symmetricKey": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" + } + }, + "CredentialStatusUpdateEncryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "updated": { + "type": "boolean", + "example": true + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/RevocationResult" + }, + { + "$ref": "#/components/schemas/SuspensionResult" + }, + { + "$ref": "#/components/schemas/UnsuspensionResult" + } + ] + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedResult" + } + ] + }, + "CredentialStatusCheckRequest": { + "type": "object", + "required": [ + "did", + "statusListName", + "index" + ], + "properties": { + "did": { + "description": "DID of the StatusList2021 publisher.", + "type": "string", + "format": "uri" + }, + "statusListName": { + "description": "The name of the StatusList2021 DID-Linked Resource to be checked.", + "type": "string" + }, + "index": { + "description": "Credential status index to be checked for revocation or suspension.", + "type": "integer", + "minimum": 0, + "exclusiveMinimum": false + }, + "makeFeePayment": { + "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", + "type": "boolean", + "default": true + } + } + }, + "CredentialStatusCheckResult": { + "oneOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCheckRevocationResult" + }, + { + "$ref": "#/components/schemas/CredentialStatusCheckSuspensionResult" + } + ] + }, + "CredentialStatusCheckRevocationResult": { + "type": "object", + "properties": { + "checked": { + "type": "boolean", + "example": true + }, + "revoked": { + "type": "boolean", + "example": false + } + } + }, + "CredentialStatusCheckSuspensionResult": { + "type": "object", + "properties": { + "checked": { + "type": "boolean", + "example": true + }, + "suspended": { + "type": "boolean", + "example": false + } + } + }, + "CredentialStatusListSearchResult": { + "allOf": [ + { + "type": "object", + "properties": { + "found": { + "type": "boolean", + "example": true + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedResult" + } + ] + } + ] + }, + "KeyImportRequest": { + "type": "object", + "properties": { + "alias": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "Ed25519", + "Secp256k1" + ] + }, + "privateKeyHex": { + "type": "string" + } + } + }, + "KeyResult": { + "type": "object", + "properties": { + "kid": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "Ed25519", + "Secp256k1" + ] + }, + "publicKeyHex": { + "type": "string" + } + } + }, + "DidDocument": { + "description": "This input field contains either a complete DID document, or an incremental change (diff) to a DID document. See Universal DID Registrar specification.", + "type": "object", + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "controllers": { + "type": "array", + "items": { + "type": "string" + } + }, + "verificationMethod": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VerificationMethod" + } + }, + "service": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "authentication": { + "type": "array", + "items": { + "type": "string" + } + }, + "assertionMethod": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityInvocation": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityDelegation": { + "type": "array", + "items": { + "type": "string" + } + }, + "keyAgreement": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "@context": [ + "https://www.w3.org/ns/did/v1" + ], + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "controller": [ + "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + ], + "verificationMethod": [ + { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "type": "Ed25519VerificationKey2018", + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "publicKeyBase58": "z6MkkVbyHJLLjdjU5B62DaJ4mkdMdUkttf9UqySSkA9bVTeZ" + } + ], + "authentication": [ + "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1" + ], + "service": [ + { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", + "type": "LinkedDomains", + "serviceEndpoint": [ + "https://example.com" + ] + } + ] + } + }, + "DidDocumentWithoutVerificationMethod": { + "type": "object", + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "controllers": { + "type": "array", + "items": { + "type": "string" + } + }, + "service": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "authentication": { + "type": "array", + "items": { + "type": "string" + } + }, + "assertionMethod": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityInvocation": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityDelegation": { + "type": "array", + "items": { + "type": "string" + } + }, + "keyAgreement": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "@context": [ + "https://www.w3.org/ns/did/v1" + ], + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "controller": [ + "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + ], + "authentication": [ + "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1" + ], + "service": [ + { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", + "type": "LinkedDomains", + "serviceEndpoint": [ + "https://example.com" + ] + } + ] + } + }, + "DidCreateRequestFormBased": { + "type": "object", + "properties": { + "network": { + "description": "Network to create the DID on (testnet or mainnet)", + "type": "string", + "enum": [ + "testnet", + "mainnet" + ] + }, + "identifierFormatType": { + "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", + "type": "string", + "enum": [ + "uuid", + "base58btc" + ] + }, + "verificationMethodType": { + "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", + "type": "string", + "enum": [ + "Ed25519VerificationKey2018", + "JsonWebKey2020", + "Ed25519VerificationKey2020" + ] + }, + "service": { + "description": "It's a list of special objects which are designed to build the actual service. It's almost the same as in DID Core specification, but instead of `id` it utilises `idFragment` field for making the right `id` for each service. !!! WARN. Cause swagger-ui does not handle x-ww-form based arrays correctly, please frame all your services in brackets while using swagger UI. !!!", + "type": "array", + "items": { + "type": "object", + "properties": { + "idFragment": { + "type": "string" + }, + "type": { + "type": "string" + }, + "serviceEndpoint": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "example": [ + { + "idFragment": "service-1", + "type": "LinkedDomains", + "serviceEndpoint": [ + "https://example.com" + ] + } + ] + }, + "key": { + "description": "The unique identifier in hexadecimal public key format used in the verification method to create the DID.", + "type": "string" + }, + "@context": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "https://www.w3.org/ns/did/v1" + ] + } + } + }, + "DidCreateRequestJson": { + "type": "object", + "properties": { + "network": { + "description": "Network to create the DID on (testnet or mainnet)", + "type": "string", + "enum": [ + "testnet", + "mainnet" + ] + }, + "identifierFormatType": { + "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", + "type": "string", + "enum": [ + "uuid", + "base58btc" + ] + }, + "assertionMethod": { + "description": "Usually a reference to a Verification Method. An Assertion Method is required to issue JSON-LD credentials. See DID Core specification for more details.", + "type": "boolean", + "default": true + }, + "options": { + "type": "object", + "properties": { + "key": { + "type": "string", + "example": "8255ddadd75695e01f3d98fcec8ccc7861a030b317d4326b0e48a4d579ddc43a" + }, + "verificationMethodType": { + "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", + "type": "string", + "enum": [ + "Ed25519VerificationKey2018", + "JsonWebKey2020", + "Ed25519VerificationKey2020" + ] + } + } + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocumentWithoutVerificationMethod" + } + } + }, + "DidImportRequest": { + "type": "object", + "properties": { + "did": { + "type": "string", + "description": "DID to be imported", + "format": "uri", + "required": true + }, + "keys": { + "type": "array", + "description": "List of keys required to import the DID", + "required": true, + "items": { + "$ref": "#/components/schemas/KeyImportRequest" + } + } + } + }, + "PresentationCreateResult": { + "type": "object", + "properties": { + "vp": { + "type": "object", + "description": "Verifiable Presentation which could be provided to the verifier." + }, + "nbf": { + "type": "integer", + "description": "Unix timestamp of the earliest time that the Verifiable Presentation is valid." + }, + "iss": { + "type": "string", + "description": "DID of the issuer of the Verifiable Presentation. (Here it's supposed to be a holder DID)" + }, + "aud": { + "type": "array", + "items": { + "type": "string" + }, + "description": "DID of the verifier of the Verifiable Presentation." + } + }, + "example": { + "vp": { + "@context": [ + "https://www.w3.org/2018/credentials/v1" + ], + "type": [ + "VerifiablePresentation" + ], + "verifiableCredential": [ + "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc2NoZW1hLm9yZy9zY2hlbWEuanNvbmxkIiwiaHR0cHM6Ly92ZXJhbW8uaW8vY29udGV4dHMvcHJvZmlsZS92MSIsImh0dHBzOi8vdzNpZC5vcmcvdmMtc3RhdHVzLWxpc3QtMjAyMS92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiUGVyc29uIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7Im5hbWUiOiJCb2IiLCJnZW5kZXIiOiJtYWxlIn0sImNyZWRlbnRpYWxTdGF0dXMiOnsiaWQiOiJodHRwczovL3Jlc29sdmVyLmNoZXFkLm5ldC8xLjAvaWRlbnRpZmllcnMvZGlkOmNoZXFkOnRlc3RuZXQ6OTBkNWMxNDEtNzI0Zi00N2FkLTlhZTctYTdjMzNhOWU1NjQzP3Jlc291cmNlTmFtZT1zdXNwZW5zaW9uRW4mcmVzb3VyY2VUeXBlPVN0YXR1c0xpc3QyMDIxU3VzcGVuc2lvbiMxMzMzOCIsInR5cGUiOiJTdGF0dXNMaXN0MjAyMUVudHJ5Iiwic3RhdHVzUHVycG9zZSI6InN1c3BlbnNpb24iLCJzdGF0dXNMaXN0SW5kZXgiOiIxMzMzOCJ9fSwic3ViIjoiZGlkOmtleTp6Nk1raGFYZ0JaRHZvdERrTDUyNTdmYWl6dGlHaUMyUXRLTEdwYm5uRUd0YTJkb0siLCJuYmYiOjE3MDA0NzM0MTYsImlzcyI6ImRpZDpjaGVxZDp0ZXN0bmV0OjkwZDVjMTQxLTcyNGYtNDdhZC05YWU3LWE3YzMzYTllNTY0MyJ9.-14Ril1pZEy2HEEo48gTJr2yOtGxBhUGTFmzVdjAtyhFRsW5zZg9onHt6V9JQ8BaiYBlTkP9GzTnJ-O6hdiyCw" + ] + }, + "nbf": 1700744275, + "iss": "did:cheqd:testnet:4b846d0f-2f6c-4ab6-9fe2-5b8db301c83c", + "aud": [ + "did:cheqd:testnet:8c71e9b6-c5a3-4250-8c58-fa591533cd22" + ] + } + }, + "DidResult": { + "type": "object", + "properties": { + "did": { + "type": "string" + }, + "controllerKeyId": { + "type": "string" + }, + "keys": { + "type": "array", + "items": { + "type": "object" + } + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + } + } + }, + "DidUpdateResponse": { + "type": "object", + "properties": { + "did": { + "type": "string" + }, + "controllerKeyId": { + "type": "string", + "description": "The default key id of which is the key associated with the first verificationMethod" + }, + "keys": { + "type": "array", + "description": "The list of keys associated with the list of verificationMethod's of DIDDocument", + "items": { + "type": "object" + } + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "controllerKeyRefs": { + "type": "array", + "description": "The list of keyRefs which were used for signing the transaction", + "items": { + "type": "string" + } + }, + "controllerKeys": { + "type": "array", + "description": "The list of all possible keys, inlcuding all controller's keys", + "items": { + "type": "string" + } + } + } + }, + "VerificationMethod": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + }, + "controller": { + "type": "string" + }, + "publicKeyMultibase": { + "type": "string" + }, + "publicKeyJwk": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "id": "did:cheqd:testnet :7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", + "type": "Ed25519VerificationKey2018" + } + }, + "Service": { + "description": "Communicating or interacting with the DID subject or associated entities via one or more service endpoints. See DID Core specification for more details.", + "type": "object", + "properties": { + "id": { + "description": "DID appended with Service fragment ID (e.g., `#service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`)", + "type": "string", + "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1" + }, + "type": { + "description": "Service type as defined in DID Specification Registries.", + "type": "string", + "example": "LinkedDomains" + }, + "serviceEndpoint": { + "description": "Service endpoint as defined in DID Core Specification.", + "type": "array", + "items": { + "type": "string", + "example": "https://example.com" + } + } + } + }, + "DidUpdateRequest": { + "type": "object", + "properties": { + "did": { + "description": "DID identifier to be updated.", + "type": "string", + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + "service": { + "type": "array", + "description": "Service section of the DID Document.", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "verificationMethod": { + "type": "array", + "description": "Verification Method section of the DID Document.", + "items": { + "$ref": "#/components/schemas/VerificationMethod" + } + }, + "authentication": { + "description": "Authentication section of the DID Document.", + "type": "array", + "items": { + "type": "string" + } + }, + "publicKeyHexs": { + "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", + "type": "array", + "items": { + "type": "string" + } + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + } + } + }, + "DidDeactivateRequest": { + "type": "object", + "properties": { + "publicKeyHexs": { + "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "CreateResourceRequest": { + "description": "Input fields for DID-Linked Resource creation.", + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "type", + "data", + "encoding" + ], + "properties": { + "data": { + "description": "Encoded string containing the data to be stored in the DID-Linked Resource.", + "type": "string" + }, + "encoding": { + "description": "Encoding format used to encode the data.", + "type": "string", + "enum": [ + "base64url", + "base64", + "hex" + ] + }, + "name": { + "description": "Name of DID-Linked Resource.", + "type": "string" + }, + "type": { + "description": "Type of DID-Linked Resource. This is NOT the same as the media type, which is calculated automatically ledger-side.", + "type": "string" + }, + "alsoKnownAs": { + "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", + "type": "array", + "items": { + "type": "object", + "properties": { + "uri": { + "type": "string" + }, + "description": { + "type": "string" + } + } + } + }, + "version": { + "description": "Optional field to assign a human-readable version in the DID-Linked Resource.", + "type": "string" + }, + "publicKeyHexs": { + "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "data": "SGVsbG8gV29ybGQ=", + "encoding": "base64url", + "name": "ResourceName", + "type": "TextDocument" + } + }, + "ResourceList": { + "type": "object", + "properties": { + "@context": { + "type": "string", + "example": "https://w3id.org/did-resolution/v1" + }, + "contentMetadata": { + "type": "object" + }, + "contentStream": { + "type": "object" + }, + "dereferencingMetadata": { + "$ref": "#/components/schemas/DereferencingMetadata" + } + } + }, + "DereferencingMetadata": { + "type": "object", + "properties": { + "contentType": { + "type": "string", + "example": "application/did+ld+json" + }, + "did": { + "$ref": "#/components/schemas/DidProperties" + }, + "retrieved": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + } + } + }, + "DidResolution": { + "type": "object", + "properties": { + "@context": { + "type": "string", + "example": "https://w3id.org/did-resolution/v1" + }, + "didDidResolutionMetadata": { + "$ref": "#/components/schemas/DidResolutionMetadata" + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + }, + "didDocumentMetadata": { + "$ref": "#/components/schemas/DidDocumentMetadata" + } + } + }, + "DeactivatedDidResolution": { + "type": "object", + "properties": { + "@context": { + "type": "string", + "example": "https://w3id.org/did-resolution/v1" + }, + "didDidResolutionMetadata": { + "$ref": "#/components/schemas/DidResolutionMetadata" + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + }, + "didDocumentMetadata": { + "$ref": "#/components/schemas/DeactivatedDidDocumentMetadata" + } + } + }, + "DidDocumentMetadata": { + "type": "object", + "properties": { + "created": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "deactivated": { + "type": "boolean", + "example": false + }, + "updated": { + "type": "string", + "example": "2021-09-10T12:00:00Z" + }, + "versionId": { + "type": "string", + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + "linkedResourceMetadata": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ResourceMetadata" + } + } + } + }, + "DeactivatedDidDocumentMetadata": { + "type": "object", + "properties": { + "created": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "deactivated": { + "type": "boolean", + "example": true + }, + "updated": { + "type": "string", + "example": "2021-09-10T12:00:00Z" + }, + "versionId": { + "type": "string", + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + "linkedResourceMetadata": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ResourceMetadata" + } + } + } + }, + "ResourceMetadata": { + "type": "object", + "properties": { + "resourceURI": { + "type": "string", + "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47/resources/398cee0a-efac-4643-9f4c-74c48c72a14b" + }, + "resourceCollectionId": { + "type": "string", + "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" + }, + "resourceId": { + "type": "string", + "example": "398cee0a-efac-4643-9f4c-74c48c72a14b" + }, + "resourceName": { + "type": "string", + "example": "cheqd-issuer-logo" + }, + "resourceType": { + "type": "string", + "example": "CredentialArtwork" + }, + "mediaType": { + "type": "string", + "example": "image/png" + }, + "resourceVersion": { + "type": "string", + "example": "1.0" + }, + "checksum": { + "type": "string", + "example": "a95380f460e63ad939541a57aecbfd795fcd37c6d78ee86c885340e33a91b559" + }, + "created": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "nextVersionId": { + "type": "string", + "example": "d4829ac7-4566-478c-a408-b44767eddadc" + }, + "previousVersionId": { + "type": "string", + "example": "ad7a8442-3531-46eb-a024-53953ec6e4ff" + } + } + }, + "DidResolutionMetadata": { + "type": "object", + "properties": { + "contentType": { + "allOf": [ + { + "$ref": "#/components/schemas/ContentType" + } + ], + "example": "application/did+ld+json" + }, + "retrieved": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "did": { + "$ref": "#/components/schemas/DidProperties" + } + } + }, + "ContentType": { + "type": "string", + "enum": [ + "application/did+json", + "application/did+ld+json", + "application/ld+json", + "application/json" + ] + }, + "DidProperties": { + "type": "object", + "properties": { + "didString": { + "type": "string", + "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" + }, + "method": { + "type": "string", + "example": "cheqd" + }, + "methodSpecificId": { + "type": "string", + "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" + } + } + }, + "Customer": { + "type": "object", + "properties": { + "customerId": { + "type": "string", + "example": "6w5drpiiwhhs" + }, + "address": { + "type": "string", + "example": "cheqd1wgsvqwlkmdp60f4dek26ak0sjw6au3ytd3pz7f" + } + } + }, + "AccountCreateRequest": { + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": { + "primaryEmail": { + "type": "string" + } + } + } + } + }, + "InvalidRequest": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "InvalidRequest" + } + } + }, + "InternalError": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Internal Error" + } + } + }, + "UnauthorizedError": { + "description": "Access token is missing or invalid", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Unauthorized Error" + } + } + } + } + } +} \ No newline at end of file diff --git a/src/types/portal.ts b/src/types/portal.ts index 4cb4ee9f..e52e4989 100644 --- a/src/types/portal.ts +++ b/src/types/portal.ts @@ -95,28 +95,31 @@ export type SubscriptionResumeUnsuccessfulResponseBody = UnsuccessfulResponseBod export type PortalCustomerGetUnsuccessfulResponseBody = UnsuccessfulResponseBody; // API key -// Create -export type APIKeyCreateRequestBody = { - expiresAt?: Date; -}; -export type APIKeyCreateResponseBody = { +export type APIKeyResponseBody = { apiKey: string; + name: string; + createdAt: string; expiresAt: string; revoked: boolean; }; +// Create +export type APIKeyCreateRequestBody = { + name: string, + expiresAt?: Date; +}; + +export type APIKeyCreateResponseBody = APIKeyResponseBody export type APIKeyCreateUnsuccessfulResponseBody = UnsuccessfulResponseBody; // Update export type APIKeyUpdateRequestBody = { apiKey: string; + name?: string; expiresAt?: Date; revoked?: boolean; }; -export type APIKeyUpdateResponseBody = { - apiKey: string; - expiresAt: string; - revoked: boolean; -}; +export type APIKeyUpdateResponseBody = APIKeyResponseBody; + export type APIKeyUpdateUnsuccessfulResponseBody = UnsuccessfulResponseBody; // Revoke @@ -131,14 +134,12 @@ export type APIKeyRevokeUnsuccessfulResponseBody = UnsuccessfulResponseBody; // List export type APIKeyListResponseBody = { - apiKeys: APIKeyCreateResponseBody[]; + apiKeys: APIKeyResponseBody[]; }; export type APIKeyListUnsuccessfulResponseBody = UnsuccessfulResponseBody; // Get -export type APIKeyGetRequestBody = { - apiKey: string; -}; +export type APIKeyGetRequestBody = APIKeyResponseBody; export type APIKeyGetResponseBody = APIKeyCreateResponseBody; export type APIKeyGetUnsuccessfulResponseBody = UnsuccessfulResponseBody; diff --git a/src/types/swagger-admin-types.ts b/src/types/swagger-admin-types.ts index ff59f11a..98d70cb8 100644 --- a/src/types/swagger-admin-types.ts +++ b/src/types/swagger-admin-types.ts @@ -171,24 +171,23 @@ * subscription: * type: object * description: A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object] - * APIKeyCreateRequestBody: - * description: The request body for creating an API key - * type: object - * properties: - * expiresAt: - * type: string - * description: The expiration date of the API key - * example: "2000-10-31T01:30:00.000-05:00" - * format: date - * required: false - * APIKeyCreateResponseBody: - * description: The response body for creating an API key + * APIKeyResponse: + * description: The general view for API key in response * type: object * properties: * apiKey: * type: string * description: The API key * example: abcdefghijklmnopqrstuvwxyz + * createdAt: + * type: string + * description: The creation date of the API key + * example: "2000-10-31T01:30:00.000-05:00" + * format: date + * name: + * type: string + * description: The name of the API key + * example: My API Key * expiresAt: * type: string * description: The expiration date of the API key @@ -198,6 +197,25 @@ * type: boolean * description: The status of the API key * example: false + * APIKeyCreateRequestBody: + * description: The request body for creating an API key + * type: object + * properties: + * expiresAt: + * type: string + * description: The expiration date of the API key + * example: "2000-10-31T01:30:00.000-05:00" + * format: date + * required: false + * name: + * type: string + * description: The name of the API key + * example: My API Key + * required: true + * APIKeyCreateResponseBody: + * description: The response body for creating an API key + * type: object + * ref: '#/components/schemas/APIKeyResponse' * APIKeyCreateUnsuccessfulResponseBody: * description: The response body for an unsuccessful API key creation * type: object @@ -208,41 +226,11 @@ * APIKeyUpdateRequestBody: * description: The request body for updating an API key * type: object - * properties: - * apiKey: - * type: string - * description: The API key - * example: abcdefghijklmnopqrstuvwxyz - * required: true - * expiresAt: - * type: string - * description: The expiration date of the API key - * example: "2000-10-31T01:30:00.000-05:00" - * format: date - * required: false - * revoked: - * type: boolean - * description: The status of the API key - * example: false - * required: false - * default: false + * ref: '#/components/schemas/APIKeyResponse' * APIKeyUpdateResponseBody: * description: The response body for an unsuccessful API key update * type: object - * properties: - * apiKey: - * type: string - * description: The API key - * example: abcdefghijklmnopqrstuvwxyz - * expiresAt: - * type: string - * description: The expiration date of the API key - * example: "2000-10-31T01:30:00.000-05:00" - * format: date - * revoked: - * type: boolean - * description: The status of the API key - * example: false + * ref: '#/components/schemas/APIKeyResponse' * APIKeyUpdateUnsuccessfulResponseBody: * description: The response body for an unsuccessful API key update * type: object @@ -287,20 +275,7 @@ * type: array * items: * type: object - * properties: - * apiKey: - * type: string - * description: The API key - * example: abcdefghijklmnopqrstuvwxyz - * expiresAt: - * type: string - * description: The expiration date of the API key - * example: "2000-10-31T01:30:00.000-05:00" - * format: date - * revoked: - * type: boolean - * description: The status of the API key - * example: false + * ref: '#/components/schemas/APIKeyResponse' * APIKeyGetRequestBody: * description: The request body for getting an API key * type: object @@ -313,20 +288,7 @@ * APIKeyGetResponseBody: * description: The response body for getting an API key * type: object - * properties: - * apiKey: - * type: string - * description: The API key - * example: abcdefghijklmnopqrstuvwxyz - * expiresAt: - * type: string - * description: The expiration date of the API key - * example: "2000-10-31T01:30:00.000-05:00" - * format: date - * revoked: - * type: boolean - * description: The status of the API key - * example: false + * ref: '#/components/schemas/APIKeyResponse' * NotFoundError: * description: The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible. * type: object From 13be89fb553ec7811afe79409968faa128845d4b Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Tue, 9 Apr 2024 15:42:08 +0200 Subject: [PATCH 24/40] Get rid of apiKeyHash --- src/controllers/admin/api-key.ts | 44 +++++-- src/database/entities/api.key.entity.ts | 14 +- src/database/migrations/AlterAPIKeyTable.ts | 32 ----- src/middleware/auth/base-auth-handler.ts | 30 +++-- .../auth/user-info-fetcher/api-token.ts | 46 +++---- .../auth/user-info-fetcher/idtoken.ts | 51 ++++++++ src/services/admin/api-key.ts | 120 +++++++++--------- src/services/identity/postgres.ts | 22 ++-- src/static/swagger-admin.json | 28 +++- src/types/portal.ts | 6 + src/types/swagger-admin-types.ts | 23 +++- 11 files changed, 260 insertions(+), 156 deletions(-) create mode 100644 src/middleware/auth/user-info-fetcher/idtoken.ts diff --git a/src/controllers/admin/api-key.ts b/src/controllers/admin/api-key.ts index 2e6df3bf..211cbcf2 100644 --- a/src/controllers/admin/api-key.ts +++ b/src/controllers/admin/api-key.ts @@ -19,6 +19,7 @@ import type { APIKeyUpdateRequestBody, APIKeyUpdateResponseBody, APIKeyUpdateUnsuccessfulResponseBody, + APIServiceOptions, } from '../../types/portal.js'; import { EventTracker, eventTracker } from '../../services/track/tracker.js'; import { OperationNameEnum } from '../../types/constants.js'; @@ -109,11 +110,12 @@ export class APIKeyController { */ @validate public async create(request: Request, response: Response) { - try { - const { name, expiresAt } = request.body satisfies APIKeyCreateRequestBody; + const { name, expiresAt } = request.body satisfies APIKeyCreateRequestBody; + const options = { decryptionNeeded: true } satisfies APIServiceOptions + try { const apiKey = APIKeyService.instance.generateAPIKey(); - const apiKeyEntity = await APIKeyService.instance.create(apiKey, name, response.locals.user, expiresAt); + const apiKeyEntity = await APIKeyService.instance.create(apiKey, name, response.locals.user, expiresAt, false, options); if (!apiKeyEntity) { return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ message: 'Cannot create a new API key', @@ -170,9 +172,18 @@ export class APIKeyController { */ @validate public async update(request: Request, response: Response) { + const { apiKey, name, expiresAt, revoked } = request.body satisfies APIKeyUpdateRequestBody; + const options = { decryptionNeeded: true } satisfies APIServiceOptions try { - const { apiKey, name, expiresAt, revoked } = request.body satisfies APIKeyUpdateRequestBody; - const apiKeyEntity = await APIKeyService.instance.update(apiKey, name, expiresAt, revoked); + const apiKeyEntity = await APIKeyService.instance.update({ + customer: response.locals.customer, + apiKey, + name, + expiresAt, + revoked + }, + options + ); if (!apiKeyEntity) { return response.status(StatusCodes.NOT_FOUND).json({ error: 'Cannot update API key cause it\'s not found', @@ -230,9 +241,10 @@ export class APIKeyController { */ @validate public async revoke(request: Request, response: Response) { + const options = { decryptionNeeded: true } satisfies APIServiceOptions + const { apiKey } = request.body satisfies APIKeyRevokeRequestBody; try { - const { apiKey } = request.body satisfies APIKeyRevokeRequestBody; - const apiKeyEntity = await APIKeyService.instance.revoke(apiKey); + const apiKeyEntity = await APIKeyService.instance.revoke(apiKey, response.locals.customer, options); if (!apiKeyEntity) { return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ error: 'Cannot revoke API key', @@ -284,9 +296,13 @@ export class APIKeyController { @validate public async list(request: Request, response: Response) { try { + const options = { decryptionNeeded: true } satisfies APIServiceOptions const apiKeyList = await APIKeyService.instance.find({ - customer: response.locals.customer, - }); + customer: response.locals.customer, + }, + undefined, + options + ); const keys = apiKeyList.map((apiKey) => { return { apiKey: apiKey.apiKey, @@ -339,10 +355,13 @@ export class APIKeyController { */ @validate public async get(request: Request, response: Response) { + + const apiKey = request.query.apiKey as string; + const options = { decryptionNeeded: true } satisfies APIServiceOptions + try { - const apiKey = request.query.apiKey as string; if (apiKey) { - const apiKeyEntity = await APIKeyService.instance.get(apiKey); + const apiKeyEntity = await APIKeyService.instance.get(apiKey, response.locals.customer, options); if (!apiKeyEntity) { return response.status(StatusCodes.NOT_FOUND).json({ error: 'API key not found', @@ -364,7 +383,8 @@ export class APIKeyController { }, { createdAt: 'DESC', - } + }, + options ); if (keys.length == 0) { return response.status(StatusCodes.NOT_FOUND).json({ diff --git a/src/database/entities/api.key.entity.ts b/src/database/entities/api.key.entity.ts index 26e69a0f..ea6ef8a1 100644 --- a/src/database/entities/api.key.entity.ts +++ b/src/database/entities/api.key.entity.ts @@ -1,4 +1,4 @@ -import { BeforeInsert, BeforeUpdate, Column, Entity, JoinColumn, ManyToOne } from 'typeorm'; +import { BeforeInsert, BeforeUpdate, Column, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'; import * as dotenv from 'dotenv'; import { CustomerEntity } from './customer.entity.js'; @@ -7,12 +7,8 @@ dotenv.config(); @Entity('apiKey') export class APIKeyEntity { - @Column({ - type: 'text', - nullable: false, - primary: true, - }) - apiKeyHash!: string; + @PrimaryGeneratedColumn('uuid') + apiKeyId!: string; @Column({ type: 'text', @@ -73,7 +69,7 @@ export class APIKeyEntity { } constructor( - apiKeyHash: string, + apiKeyId: string, apiKey: string, name: string, expiresAt: Date, @@ -81,7 +77,7 @@ export class APIKeyEntity { user: UserEntity, revoked = false ) { - this.apiKeyHash = apiKeyHash; + this.apiKeyId = apiKeyId; this.apiKey = apiKey; this.name = name; this.expiresAt = expiresAt; diff --git a/src/database/migrations/AlterAPIKeyTable.ts b/src/database/migrations/AlterAPIKeyTable.ts index 72fb2520..a0fa7d73 100644 --- a/src/database/migrations/AlterAPIKeyTable.ts +++ b/src/database/migrations/AlterAPIKeyTable.ts @@ -1,6 +1,4 @@ import { TableColumn, type MigrationInterface, type QueryRunner } from 'typeorm'; -import pkg from 'js-sha3'; -const { sha3_512 } = pkg; export class AlterAPIKeyTable1695740346004 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise { @@ -23,36 +21,6 @@ export class AlterAPIKeyTable1695740346004 implements MigrationInterface { isNullable: false, }) ); - - // Remove unused apiKeyId column - await queryRunner.dropColumn(table_name, 'apiKeyId'); - // Add column apiKeyHash - await queryRunner.addColumn( - table_name, - new TableColumn({ - name: 'apiKeyHash', - type: 'text', - isNullable: true, - }) - ); - // Data migration - // Make all current API keys as revoked cause we need to force API key recreation - for (const apiKey of await queryRunner.query(`SELECT * FROM "${table_name}"`)) { - await queryRunner.query( - `UPDATE "${table_name}" SET "apiKeyHash" = '${sha3_512(apiKey.apiKey)}', "revoked" = 'true' WHERE "apiKey" = '${apiKey.apiKey}'` - ); - } - // Make apiKeyHash not nullable - await queryRunner.changeColumn( - table_name, - 'apiKeyHash', - new TableColumn({ - name: 'apiKeyHash', - type: 'text', - isNullable: false, - isPrimary: true, - }) - ); } public async down(queryRunner: QueryRunner): Promise { diff --git a/src/middleware/auth/base-auth-handler.ts b/src/middleware/auth/base-auth-handler.ts index 927f98c1..e1b9dfbe 100644 --- a/src/middleware/auth/base-auth-handler.ts +++ b/src/middleware/auth/base-auth-handler.ts @@ -4,13 +4,14 @@ import type { IncomingHttpHeaders } from 'http'; import type { IOAuthProvider } from './oauth/base.js'; import { LogToProvider } from './oauth/logto-provider.js'; import { SwaggerUserInfoFetcher } from './user-info-fetcher/swagger-ui.js'; -import { APITokenUserInfoFetcher } from './user-info-fetcher/api-token.js'; +import { IdTokenUserInfoFetcher } from './user-info-fetcher/idtoken.js'; import type { IUserInfoFetcher } from './user-info-fetcher/base.js'; import { IAuthHandler, RuleRoutine, IAPIGuard } from './routine.js'; import type { IAuthResponse, MethodToScopeRule } from '../../types/authentication.js'; import { M2MCredsTokenUserInfoFetcher } from './user-info-fetcher/m2m-creds-token.js'; import { decodeJwt } from 'jose'; import { PortalUserInfoFetcher } from './user-info-fetcher/portal-token.js'; +import { APITokenUserInfoFetcher } from './user-info-fetcher/api-token.js'; export class BaseAPIGuard extends RuleRoutine implements IAPIGuard { userInfoFetcher: IUserInfoFetcher = {} as IUserInfoFetcher; @@ -131,21 +132,30 @@ export class BaseAuthHandler extends BaseAPIGuard implements IAuthHandler { private chooseUserFetcherStrategy(request: Request): void { const token = BaseAuthHandler.extractBearerTokenFromHeaders(request.headers) as string; + const apiKey = request.headers['x-api-key'] as string; const headerIdToken = request.headers['id-token'] as string; if (headerIdToken && token) { this.setUserInfoStrategy(new PortalUserInfoFetcher(token, headerIdToken)); - } else { - if (token) { - const payload = decodeJwt(token); - if (payload.aud === process.env.LOGTO_APP_ID) { - this.setUserInfoStrategy(new APITokenUserInfoFetcher(token)); - } else { - this.setUserInfoStrategy(new M2MCredsTokenUserInfoFetcher(token)); - } + return; + } + + if (token) { + const payload = decodeJwt(token); + if (payload.aud === process.env.LOGTO_APP_ID) { + this.setUserInfoStrategy(new IdTokenUserInfoFetcher(token)); + return; } else { - this.setUserInfoStrategy(new SwaggerUserInfoFetcher()); + this.setUserInfoStrategy(new M2MCredsTokenUserInfoFetcher(token)); + return; } } + if (apiKey) { + this.setUserInfoStrategy(new APITokenUserInfoFetcher(apiKey)); + return; + } else { + this.setUserInfoStrategy(new SwaggerUserInfoFetcher()); + } + } public setOAuthProvider(oauthProvider: IOAuthProvider): IAuthHandler { diff --git a/src/middleware/auth/user-info-fetcher/api-token.ts b/src/middleware/auth/user-info-fetcher/api-token.ts index 26f8b661..52588a40 100644 --- a/src/middleware/auth/user-info-fetcher/api-token.ts +++ b/src/middleware/auth/user-info-fetcher/api-token.ts @@ -4,9 +4,10 @@ import type { IAuthResponse } from '../../../types/authentication.js'; import { StatusCodes } from 'http-status-codes'; import type { IUserInfoFetcher } from './base.js'; import type { IOAuthProvider } from '../oauth/base.js'; -import { createRemoteJWKSet, jwtVerify } from 'jose'; import * as dotenv from 'dotenv'; +import { APIKeyService } from '../../../services/admin/api-key.js'; +import { UserService } from '../../../services/api/user.js'; dotenv.config(); export class APITokenUserInfoFetcher extends AuthReturn implements IUserInfoFetcher { @@ -18,31 +19,30 @@ export class APITokenUserInfoFetcher extends AuthReturn implements IUserInfoFetc } async fetchUserInfo(request: Request, oauthProvider: IOAuthProvider): Promise { - return this.verifyJWTToken(this.token as string, oauthProvider); + return this.verifyToken(this.token as string, oauthProvider); } - public async verifyJWTToken(token: string, oauthProvider: IOAuthProvider): Promise { + public async verifyToken(token: string, oauthProvider: IOAuthProvider): Promise { try { - const { payload } = await jwtVerify( - token, // The raw Bearer Token extracted from the request header - createRemoteJWKSet(new URL(oauthProvider.endpoint_jwks)), // generate a jwks using jwks_uri inquired from Logto server - { - // expected issuer of the token, should be issued by the Logto server - issuer: oauthProvider.endpoint_issuer, - // expected audience token, should be the resource indicator of the current API - audience: process.env.LOGTO_APP_ID, - } - ); - // Setup the scopes from the token - if (!payload.roles) { - return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: No roles found in the token.`); - } - const scopes = await oauthProvider.getScopesForRoles(payload.roles as string[]); - if (!scopes) { - return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: No scopes found for the roles.`); - } - this.setScopes(scopes); - this.setUserId(payload.sub as string); + const apiEntity = await APIKeyService.instance.discoverAPIKey(token); + if (!apiEntity) { + return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: API Key not found.`); + } + if (apiEntity.revoked) { + return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: API Key is revoked.`); + } + const userEntity = await UserService.instance.findOne({ customer: apiEntity.customer}); + if (!userEntity) { + return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: User not found.`); + } + const _resp = await oauthProvider.getUserScopes(userEntity.logToId as string); + if (_resp.status !== 200) { + return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: No scopes found for the user.`); + } + if (_resp.data) { + this.setScopes(_resp.data); + } + this.setCustomerId(apiEntity.customer.customerId); return this.returnOk(); } catch (error) { return this.returnError(StatusCodes.INTERNAL_SERVER_ERROR, `Unexpected error: ${error}`); diff --git a/src/middleware/auth/user-info-fetcher/idtoken.ts b/src/middleware/auth/user-info-fetcher/idtoken.ts new file mode 100644 index 00000000..93bff01d --- /dev/null +++ b/src/middleware/auth/user-info-fetcher/idtoken.ts @@ -0,0 +1,51 @@ +import type { Request } from 'express'; +import { AuthReturn } from '../routine.js'; +import type { IAuthResponse } from '../../../types/authentication.js'; +import { StatusCodes } from 'http-status-codes'; +import type { IUserInfoFetcher } from './base.js'; +import type { IOAuthProvider } from '../oauth/base.js'; +import { createRemoteJWKSet, jwtVerify } from 'jose'; + +import * as dotenv from 'dotenv'; +dotenv.config(); + +export class IdTokenUserInfoFetcher extends AuthReturn implements IUserInfoFetcher { + token: string; + + constructor(token: string) { + super(); + this.token = token; + } + + async fetchUserInfo(request: Request, oauthProvider: IOAuthProvider): Promise { + return this.verifyJWTToken(this.token as string, oauthProvider); + } + + public async verifyJWTToken(token: string, oauthProvider: IOAuthProvider): Promise { + try { + const { payload } = await jwtVerify( + token, // The raw Bearer Token extracted from the request header + createRemoteJWKSet(new URL(oauthProvider.endpoint_jwks)), // generate a jwks using jwks_uri inquired from Logto server + { + // expected issuer of the token, should be issued by the Logto server + issuer: oauthProvider.endpoint_issuer, + // expected audience token, should be the resource indicator of the current API + audience: process.env.LOGTO_APP_ID, + } + ); + // Setup the scopes from the token + if (!payload.roles) { + return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: No roles found in the token.`); + } + const scopes = await oauthProvider.getScopesForRoles(payload.roles as string[]); + if (!scopes) { + return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: No scopes found for the roles.`); + } + this.setScopes(scopes); + this.setUserId(payload.sub as string); + return this.returnOk(); + } catch (error) { + return this.returnError(StatusCodes.INTERNAL_SERVER_ERROR, `Unexpected error: ${error}`); + } + } +} diff --git a/src/services/admin/api-key.ts b/src/services/admin/api-key.ts index 655734cb..c1d4060c 100644 --- a/src/services/admin/api-key.ts +++ b/src/services/admin/api-key.ts @@ -10,43 +10,12 @@ import type { UserEntity } from '../../database/entities/user.entity.js'; import { SecretBox } from '@veramo/kms-local'; import { API_KEY_LENGTH, API_KEY_PREFIX, API_KEY_EXPIRATION } from '../../types/constants.js'; import pkg from 'js-sha3'; +import { v4 } from 'uuid'; +import type { APIServiceOptions } from '../../types/portal.js'; dotenv.config(); const { sha3_512 } = pkg; -// Returns the decrypted API key -export function decryptAPIKey(target: any, key: string, descriptor: PropertyDescriptor | undefined) { - // save a reference to the original method this way we keep the values currently in the - // descriptor and don't overwrite what another decorator might have done to the descriptor. - if (descriptor === undefined) { - descriptor = Object.getOwnPropertyDescriptor(target, key) as PropertyDescriptor; - } - - const originalMethod = descriptor.value; - - //editing the descriptor/value parameter - descriptor.value = async function (...args: any[]) { - const decryptOne = async (entity: APIKeyEntity) => { - if (entity && entity.apiKey) { - entity.apiKey = await APIKeyService.instance.decryptAPIKey(entity.apiKey); - } - return entity; - }; - const entity = await originalMethod.apply(this, args); - if (Array.isArray(entity)) { - for (const apiKey of entity) { - await decryptOne(apiKey); - } - } else { - await decryptOne(entity); - } - return entity; - }; - - // return edited descriptor as opposed to overwriting the descriptor - return descriptor; -} - export class APIKeyService { public apiKeyRepository: Repository; private secretBox: SecretBox; @@ -60,8 +29,10 @@ export class APIKeyService { // ToDo: Maybe we also need to store not the API key but the hash of it? // But in that case the API key will be shown once and then it will be lost. - @decryptAPIKey - public async create(apiKey: string, name: string, user: UserEntity, expiresAt?: Date, revoked = false): Promise { + + public async create(apiKey: string, name: string, user: UserEntity, expiresAt?: Date, revoked = false, options?: APIServiceOptions): Promise { + const apiKeyId = v4(); + const { decryptionNeeded } = options || {}; if (!apiKey) { throw new Error('API key is not specified'); } @@ -75,28 +46,36 @@ export class APIKeyService { expiresAt = new Date(); expiresAt.setMonth(expiresAt.getMonth() + API_KEY_EXPIRATION); } - const apiKeyHash = APIKeyService.hashAPIKey(apiKey); const encryptedAPIKey = await this.secretBox.encrypt(apiKey); // Create entity - const apiKeyEntity = new APIKeyEntity(apiKeyHash, encryptedAPIKey, name, expiresAt, user.customer, user, revoked); + const apiKeyEntity = new APIKeyEntity(apiKeyId, encryptedAPIKey, name, expiresAt, user.customer, user, revoked); const apiKeyRecord = (await this.apiKeyRepository.insert(apiKeyEntity)).identifiers[0]; if (!apiKeyRecord) throw new Error(`Cannot create a new API key`); + + if (decryptionNeeded) { + apiKeyEntity.apiKey = apiKey; + } return apiKeyEntity; } - @decryptAPIKey public async update( - apiKey: string, - name?: string, - expiresAt?: Date, - revoked?: boolean, - customer?: CustomerEntity, - user?: UserEntity + item: { + customer: CustomerEntity, + apiKey: string, + name?: string, + expiresAt?: Date, + revoked?: boolean, + user?: UserEntity + }, + options?: APIServiceOptions ) { - const apiKeyHash = APIKeyService.hashAPIKey(apiKey); - const existingAPIKey = await this.apiKeyRepository.findOneBy({ apiKeyHash }); + const { apiKey, name, expiresAt, revoked, customer, user } = item; + const { decryptionNeeded } = options || {}; + + const existingAPIKey = await this.discoverAPIKey(apiKey as string, customer); + if (!existingAPIKey) { - throw new Error(`API with key id ${apiKey} not found`); + throw new Error(`API key for customer ${customer.customerId} not found`); } if (name) { existingAPIKey.name = name; @@ -115,43 +94,66 @@ export class APIKeyService { } const entity = await this.apiKeyRepository.save(existingAPIKey); + if (entity && decryptionNeeded) { + entity.apiKey = await this.decryptAPIKey(existingAPIKey.apiKey); + } return entity; } - public async revoke(apiKey: string) { - return this.update(apiKey, undefined, undefined, true); + public async revoke(apiKey: string, customer: CustomerEntity, options?: APIServiceOptions) { + return this.update({ + customer, + apiKey: apiKey, + revoked: true + }, options); } public async decryptAPIKey(apiKey: string) { return await this.secretBox.decrypt(apiKey); } - @decryptAPIKey - public async get(apiKey: string) { - const apiKeyHash = APIKeyService.hashAPIKey(apiKey); - const apiKeyEntity = await this.apiKeyRepository.findOne({ - where: { apiKeyHash: apiKeyHash }, - relations: ['customer', 'user'], - }); + public async get(apiKey: string, customer: CustomerEntity, options?: APIServiceOptions) { + const { decryptionNeeded } = options || {}; + const apiKeyEntity = await this.discoverAPIKey(apiKey, customer); + + if (apiKeyEntity && decryptionNeeded) { + apiKeyEntity.apiKey = await this.decryptAPIKey(apiKeyEntity.apiKey); + } + return apiKeyEntity; } - @decryptAPIKey - public async find(where: Record, order?: Record) { + public async find(where: Record, order?: Record, options?: APIServiceOptions) { try { + const { decryptionNeeded } = options || {}; const apiKeyList = await this.apiKeyRepository.find({ where: where, relations: ['customer', 'user'], order: order, }); + if (decryptionNeeded) { + for (const apiKey of apiKeyList) { + apiKey.apiKey = await this.decryptAPIKey(apiKey.apiKey); + } + } return apiKeyList; } catch { return []; } } - // Utils + public async discoverAPIKey(apiKey: string, customer?: CustomerEntity) { + const where = customer ? { customer } : {}; + const keys = await this.find(where, { createdAt: 'DESC' }); + for (const key of keys) { + if (await this.decryptAPIKey(key.apiKey) === apiKey) { + return key; + } + } + return undefined; + } + // Utils public generateAPIKey(): string { return `${API_KEY_PREFIX}_${randomBytes(API_KEY_LENGTH).toString('hex')}`; } diff --git a/src/services/identity/postgres.ts b/src/services/identity/postgres.ts index 811f5951..736ad0af 100644 --- a/src/services/identity/postgres.ts +++ b/src/services/identity/postgres.ts @@ -55,6 +55,7 @@ import type { AbstractIdentifierProvider } from '@veramo/did-manager'; import type { CheqdProviderError } from '@cheqd/did-provider-cheqd'; import type { TPublicKeyEd25519 } from '@cheqd/did-provider-cheqd'; import { toTPublicKeyEd25519 } from '../helpers.js'; +import type { APIServiceOptions } from '../../types/portal.js'; dotenv.config(); @@ -524,7 +525,8 @@ export class PostgresIdentityService extends DefaultIdentityService { } async setAPIKey(apiKey: string, customer: CustomerEntity, user: UserEntity): Promise { - const keys = await APIKeyService.instance.find({ customer: customer, user: user, revoked: false }); + const options = { decryptionNeeded: true } satisfies APIServiceOptions + const keys = await APIKeyService.instance.find({ customer: customer, user: user, revoked: false }, undefined, options); if (keys.length > 0) { throw new Error(`API key for customer ${customer.customerId} and user ${user.logToId} already exists`); } @@ -532,29 +534,31 @@ export class PostgresIdentityService extends DefaultIdentityService { if (!apiKeyEntity) { throw new Error(`Cannot create API key for customer ${customer.customerId} and user ${user.logToId}`); } - apiKeyEntity.apiKey = await this.decryptAPIKey(apiKeyEntity.apiKey); return apiKeyEntity; } async updateAPIKey(apiKey: APIKeyEntity, newApiKey: string): Promise { - const key = await APIKeyService.instance.get(apiKey.apiKey); + const options = { decryptionNeeded: true } satisfies APIServiceOptions + const key = await APIKeyService.instance.get(apiKey.apiKey, apiKey.customer, options); if (!key) { throw new Error(`API key not found`); } - const apiKeyEntity = await APIKeyService.instance.update( - newApiKey, - undefined, - await APIKeyService.instance.getExpiryDate(newApiKey) + const apiKeyEntity = await APIKeyService.instance.update({ + customer: key.customer, + apiKey: newApiKey, + expiresAt: await APIKeyService.instance.getExpiryDate(newApiKey) + }, + options ); if (!apiKeyEntity) { throw new Error(`Cannot update API key`); } - apiKeyEntity.apiKey = await this.decryptAPIKey(apiKeyEntity.apiKey); return apiKeyEntity; } async getAPIKey(customer: CustomerEntity, user: UserEntity): Promise { - const keys = await APIKeyService.instance.find({ customer: customer, user: user, revoked: false }); + const options = { decryptionNeeded: true } satisfies APIServiceOptions + const keys = await APIKeyService.instance.find({ customer: customer, user: user, revoked: false }, undefined, options); if (keys.length > 1) { throw new Error( `For the customer with customer id ${customer.customerId} and user with logToId ${user.logToId} there more then 1 API key` diff --git a/src/static/swagger-admin.json b/src/static/swagger-admin.json index 362f5444..d6dddf47 100644 --- a/src/static/swagger-admin.json +++ b/src/static/swagger-admin.json @@ -907,7 +907,33 @@ "APIKeyUpdateRequestBody": { "description": "The request body for updating an API key", "type": "object", - "ref": "#/components/schemas/APIKeyResponse" + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz", + "required": true + }, + "name": { + "type": "string", + "description": "The name of the API key", + "example": "My API Key" + }, + "expiresAt": { + "type": "string", + "description": "The expiration date of the API key", + "example": "2000-10-31T01:30:00.000-05:00", + "format": "date", + "required": false + }, + "revoked": { + "type": "boolean", + "description": "The status of the API key", + "example": false, + "required": false, + "default": false + } + } }, "APIKeyUpdateResponseBody": { "description": "The response body for an unsuccessful API key update", diff --git a/src/types/portal.ts b/src/types/portal.ts index e52e4989..37c7cf32 100644 --- a/src/types/portal.ts +++ b/src/types/portal.ts @@ -5,6 +5,11 @@ export type ProductWithPrices = Stripe.Product & { prices?: Stripe.Price[]; }; + +export type APIServiceOptions = { + decryptionNeeded: boolean; +}; + export type ProductListUnsuccessfulResponseBody = UnsuccessfulResponseBody; export type ProductGetUnsuccessfulResponseBody = UnsuccessfulResponseBody; @@ -146,3 +151,4 @@ export type APIKeyGetUnsuccessfulResponseBody = UnsuccessfulResponseBody; // Utils export type PaymentBehavior = Stripe.SubscriptionCreateParams.PaymentBehavior; + diff --git a/src/types/swagger-admin-types.ts b/src/types/swagger-admin-types.ts index 98d70cb8..5bdcdda9 100644 --- a/src/types/swagger-admin-types.ts +++ b/src/types/swagger-admin-types.ts @@ -226,7 +226,28 @@ * APIKeyUpdateRequestBody: * description: The request body for updating an API key * type: object - * ref: '#/components/schemas/APIKeyResponse' + * properties: + * apiKey: + * type: string + * description: The API key + * example: abcdefghijklmnopqrstuvwxyz + * required: true + * name: + * type: string + * description: The name of the API key + * example: My API Key + * expiresAt: + * type: string + * description: The expiration date of the API key + * example: 2000-10-31T01:30:00.000-05:00 + * format: date + * required: false + * revoked: + * type: boolean + * description: The status of the API key + * example: false + * required: false + * default: false * APIKeyUpdateResponseBody: * description: The response body for an unsuccessful API key update * type: object From e0fc23ebd880995a609be7be0c61e8c1441c5bb9 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Tue, 9 Apr 2024 16:41:28 +0200 Subject: [PATCH 25/40] Lint --- src/types/swagger-admin-types.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/types/swagger-admin-types.ts b/src/types/swagger-admin-types.ts index 5bdcdda9..e46f23e4 100644 --- a/src/types/swagger-admin-types.ts +++ b/src/types/swagger-admin-types.ts @@ -182,7 +182,7 @@ * createdAt: * type: string * description: The creation date of the API key - * example: "2000-10-31T01:30:00.000-05:00" + * example: "2000-10-31T01:23:45Z" * format: date * name: * type: string @@ -191,7 +191,7 @@ * expiresAt: * type: string * description: The expiration date of the API key - * example: "2000-10-31T01:30:00.000-05:00" + * example: "2000-10-31T01:23:45Z" * format: date * revoked: * type: boolean @@ -204,7 +204,7 @@ * expiresAt: * type: string * description: The expiration date of the API key - * example: "2000-10-31T01:30:00.000-05:00" + * example: "2000-10-31T01:23:45Z" * format: date * required: false * name: @@ -239,7 +239,7 @@ * expiresAt: * type: string * description: The expiration date of the API key - * example: 2000-10-31T01:30:00.000-05:00 + * example: 2000-10-31T01:23:45Z * format: date * required: false * revoked: From a2fb347957c004fb21504667f768c3f5c64857c0 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Tue, 9 Apr 2024 16:45:32 +0200 Subject: [PATCH 26/40] Push swagger file --- src/static/swagger-admin.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/static/swagger-admin.json b/src/static/swagger-admin.json index d6dddf47..52abacfc 100644 --- a/src/static/swagger-admin.json +++ b/src/static/swagger-admin.json @@ -849,7 +849,7 @@ "createdAt": { "type": "string", "description": "The creation date of the API key", - "example": "2000-10-31T01:30:00.000-05:00", + "example": "2000-10-31T01:23:45Z", "format": "date" }, "name": { @@ -860,7 +860,7 @@ "expiresAt": { "type": "string", "description": "The expiration date of the API key", - "example": "2000-10-31T01:30:00.000-05:00", + "example": "2000-10-31T01:23:45Z", "format": "date" }, "revoked": { @@ -877,7 +877,7 @@ "expiresAt": { "type": "string", "description": "The expiration date of the API key", - "example": "2000-10-31T01:30:00.000-05:00", + "example": "2000-10-31T01:23:45Z", "format": "date", "required": false }, @@ -922,7 +922,7 @@ "expiresAt": { "type": "string", "description": "The expiration date of the API key", - "example": "2000-10-31T01:30:00.000-05:00", + "example": "2000-10-31T01:23:45Z", "format": "date", "required": false }, From 7b232eb921cd1d838b92cb38da9f6b2bed24fad2 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Tue, 9 Apr 2024 16:58:45 +0200 Subject: [PATCH 27/40] Fix required field in swagger --- src/static/swagger-admin.json | 60 ++++++++++++++++++++------------ src/types/swagger-admin-types.ts | 29 +++++++++------ 2 files changed, 56 insertions(+), 33 deletions(-) diff --git a/src/static/swagger-admin.json b/src/static/swagger-admin.json index 52abacfc..d93fc415 100644 --- a/src/static/swagger-admin.json +++ b/src/static/swagger-admin.json @@ -878,8 +878,7 @@ "type": "string", "description": "The expiration date of the API key", "example": "2000-10-31T01:23:45Z", - "format": "date", - "required": false + "format": "date" }, "name": { "type": "string", @@ -887,12 +886,17 @@ "example": "My API Key", "required": true } - } + }, + "required": [ + "name" + ] }, "APIKeyCreateResponseBody": { "description": "The response body for creating an API key", "type": "object", - "ref": "#/components/schemas/APIKeyResponse" + "schema": { + "ref": "#/components/schemas/APIKeyResponse" + } }, "APIKeyCreateUnsuccessfulResponseBody": { "description": "The response body for an unsuccessful API key creation", @@ -911,8 +915,7 @@ "apiKey": { "type": "string", "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz", - "required": true + "example": "abcdefghijklmnopqrstuvwxyz" }, "name": { "type": "string", @@ -923,22 +926,25 @@ "type": "string", "description": "The expiration date of the API key", "example": "2000-10-31T01:23:45Z", - "format": "date", - "required": false + "format": "date" }, "revoked": { "type": "boolean", "description": "The status of the API key", "example": false, - "required": false, "default": false } - } + }, + "required": [ + "apiKey" + ] }, "APIKeyUpdateResponseBody": { "description": "The response body for an unsuccessful API key update", "type": "object", - "ref": "#/components/schemas/APIKeyResponse" + "schema": { + "ref": "#/components/schemas/APIKeyResponse" + } }, "APIKeyUpdateUnsuccessfulResponseBody": { "description": "The response body for an unsuccessful API key update", @@ -957,10 +963,12 @@ "apiKey": { "type": "string", "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz", - "required": true + "example": "abcdefghijklmnopqrstuvwxyz" } - } + }, + "required": [ + "apiKey" + ] }, "APIKeyRevokeResponseBody": { "description": "The response body for revoking an API key", @@ -969,15 +977,17 @@ "apiKey": { "type": "string", "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz", - "required": true + "example": "abcdefghijklmnopqrstuvwxyz" }, "revoked": { "type": "boolean", "description": "The status of the API key", "example": true } - } + }, + "required": [ + "apiKey" + ] }, "APIKeyRevokeUnsuccessfulResponseBody": { "description": "The response body for an unsuccessful API key revocation", @@ -997,7 +1007,9 @@ "type": "array", "items": { "type": "object", - "ref": "#/components/schemas/APIKeyResponse" + "schema": { + "ref": "#/components/schemas/APIKeyResponse" + } } } } @@ -1009,15 +1021,19 @@ "apiKey": { "type": "string", "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz", - "required": false + "example": "abcdefghijklmnopqrstuvwxyz" } - } + }, + "required": [ + "apiKey" + ] }, "APIKeyGetResponseBody": { "description": "The response body for getting an API key", "type": "object", - "ref": "#/components/schemas/APIKeyResponse" + "schema": { + "ref": "#/components/schemas/APIKeyResponse" + } }, "NotFoundError": { "description": "The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible.", diff --git a/src/types/swagger-admin-types.ts b/src/types/swagger-admin-types.ts index e46f23e4..5421a237 100644 --- a/src/types/swagger-admin-types.ts +++ b/src/types/swagger-admin-types.ts @@ -206,16 +206,18 @@ * description: The expiration date of the API key * example: "2000-10-31T01:23:45Z" * format: date - * required: false * name: * type: string * description: The name of the API key * example: My API Key * required: true + * required: + * - name * APIKeyCreateResponseBody: * description: The response body for creating an API key * type: object - * ref: '#/components/schemas/APIKeyResponse' + * schema: + * ref: '#/components/schemas/APIKeyResponse' * APIKeyCreateUnsuccessfulResponseBody: * description: The response body for an unsuccessful API key creation * type: object @@ -231,7 +233,6 @@ * type: string * description: The API key * example: abcdefghijklmnopqrstuvwxyz - * required: true * name: * type: string * description: The name of the API key @@ -241,17 +242,18 @@ * description: The expiration date of the API key * example: 2000-10-31T01:23:45Z * format: date - * required: false * revoked: * type: boolean * description: The status of the API key * example: false - * required: false * default: false + * required: + * - apiKey * APIKeyUpdateResponseBody: * description: The response body for an unsuccessful API key update * type: object - * ref: '#/components/schemas/APIKeyResponse' + * schema: + * ref: '#/components/schemas/APIKeyResponse' * APIKeyUpdateUnsuccessfulResponseBody: * description: The response body for an unsuccessful API key update * type: object @@ -267,7 +269,8 @@ * type: string * description: The API key * example: abcdefghijklmnopqrstuvwxyz - * required: true + * required: + * - apiKey * APIKeyRevokeResponseBody: * description: The response body for revoking an API key * type: object @@ -276,11 +279,12 @@ * type: string * description: The API key * example: abcdefghijklmnopqrstuvwxyz - * required: true * revoked: * type: boolean * description: The status of the API key * example: true + * required: + * - apiKey * APIKeyRevokeUnsuccessfulResponseBody: * description: The response body for an unsuccessful API key revocation * type: object @@ -296,7 +300,8 @@ * type: array * items: * type: object - * ref: '#/components/schemas/APIKeyResponse' + * schema: + * ref: '#/components/schemas/APIKeyResponse' * APIKeyGetRequestBody: * description: The request body for getting an API key * type: object @@ -305,11 +310,13 @@ * type: string * description: The API key * example: abcdefghijklmnopqrstuvwxyz - * required: false + * required: + * - apiKey * APIKeyGetResponseBody: * description: The response body for getting an API key * type: object - * ref: '#/components/schemas/APIKeyResponse' + * schema: + * ref: '#/components/schemas/APIKeyResponse' * NotFoundError: * description: The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible. * type: object From 2226a48306a9509f375ba031c972417b4634b4d9 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Tue, 9 Apr 2024 17:01:40 +0200 Subject: [PATCH 28/40] Fix swagger date-time --- src/static/swagger-admin.json | 8 ++++---- src/types/swagger-admin-types.ts | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/static/swagger-admin.json b/src/static/swagger-admin.json index d93fc415..af93bdc9 100644 --- a/src/static/swagger-admin.json +++ b/src/static/swagger-admin.json @@ -850,7 +850,7 @@ "type": "string", "description": "The creation date of the API key", "example": "2000-10-31T01:23:45Z", - "format": "date" + "format": "date-time" }, "name": { "type": "string", @@ -861,7 +861,7 @@ "type": "string", "description": "The expiration date of the API key", "example": "2000-10-31T01:23:45Z", - "format": "date" + "format": "date-time" }, "revoked": { "type": "boolean", @@ -878,7 +878,7 @@ "type": "string", "description": "The expiration date of the API key", "example": "2000-10-31T01:23:45Z", - "format": "date" + "format": "date-time" }, "name": { "type": "string", @@ -926,7 +926,7 @@ "type": "string", "description": "The expiration date of the API key", "example": "2000-10-31T01:23:45Z", - "format": "date" + "format": "date-time" }, "revoked": { "type": "boolean", diff --git a/src/types/swagger-admin-types.ts b/src/types/swagger-admin-types.ts index 5421a237..dbada729 100644 --- a/src/types/swagger-admin-types.ts +++ b/src/types/swagger-admin-types.ts @@ -183,7 +183,7 @@ * type: string * description: The creation date of the API key * example: "2000-10-31T01:23:45Z" - * format: date + * format: date-time * name: * type: string * description: The name of the API key @@ -192,7 +192,7 @@ * type: string * description: The expiration date of the API key * example: "2000-10-31T01:23:45Z" - * format: date + * format: date-time * revoked: * type: boolean * description: The status of the API key @@ -205,7 +205,7 @@ * type: string * description: The expiration date of the API key * example: "2000-10-31T01:23:45Z" - * format: date + * format: date-time * name: * type: string * description: The name of the API key @@ -241,7 +241,7 @@ * type: string * description: The expiration date of the API key * example: 2000-10-31T01:23:45Z - * format: date + * format: date-time * revoked: * type: boolean * description: The status of the API key From 5a4fd53d7247378be01549212d5dafd31c8b6fa5 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Tue, 9 Apr 2024 18:14:21 +0200 Subject: [PATCH 29/40] Fix name field in APIKeyCreateRequestBody --- src/static/swagger-admin.json | 3 +-- src/types/swagger-admin-types.ts | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/static/swagger-admin.json b/src/static/swagger-admin.json index af93bdc9..f8d03627 100644 --- a/src/static/swagger-admin.json +++ b/src/static/swagger-admin.json @@ -883,8 +883,7 @@ "name": { "type": "string", "description": "The name of the API key", - "example": "My API Key", - "required": true + "example": "My API Key" } }, "required": [ diff --git a/src/types/swagger-admin-types.ts b/src/types/swagger-admin-types.ts index dbada729..8f320a75 100644 --- a/src/types/swagger-admin-types.ts +++ b/src/types/swagger-admin-types.ts @@ -210,7 +210,6 @@ * type: string * description: The name of the API key * example: My API Key - * required: true * required: * - name * APIKeyCreateResponseBody: From a0a953ae37e483e36353336ffc6b6bddccae9727 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Thu, 11 Apr 2024 13:40:17 +0200 Subject: [PATCH 30/40] Get rid of env variables and make them constants --- README.md | 4 +--- docker/Dockerfile | 6 +----- src/services/admin/api-key.ts | 2 +- src/types/constants.ts | 6 +++--- src/types/environment.d.ts | 2 -- 5 files changed, 6 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 9473875a..e6070e0f 100644 --- a/README.md +++ b/README.md @@ -97,9 +97,7 @@ By default, `ENABLE_AUTHENTICATION` is set to off/`false`. To enable external Ve 2. `LOGTO_WEBHOOK_SECRET`: Webhook secret to authenticate incoming webhook requests from LogTo. 5. **Miscellaneous** 1. `COOKIE_SECRET`: Secret for cookie encryption. - 2. `API_KEY_PREFIX` (optional): Prefix for API keys. (Default "caas") - 3. `API_KEY_LENGTH` (optional): Length of API keys. (Default 32) - 4. `API_KEY_EXPIRATION` (optional): Expiration time for API keys in month. (Default 1 month) + 2. `API_KEY_EXPIRATION` (optional): Expiration time for API keys in days. (Default 30 days) #### Faucet settings diff --git a/docker/Dockerfile b/docker/Dockerfile index 7d9a0ace..5eb787ed 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -72,9 +72,7 @@ ARG ENABLE_DATADOG=false ARG LOG_LEVEL=info # API generation -ARG API_KEY_PREFIX="caas" -ARG API_KEY_LENGTH=32 -ARG API_KEY_EXPIRATION=1 +ARG API_KEY_EXPIRATION=30 # Verida connector: build-time ARG ENABLE_VERIDA_CONNECTOR=false @@ -124,8 +122,6 @@ ENV ENABLE_DATADOG ${ENABLE_DATADOG} ENV LOG_LEVEL ${LOG_LEVEL} # API generatioin -ENV API_KEY_PREFIX ${API_KEY_PREFIX} -ENV API_KEY_LENGTH ${API_KEY_LENGTH} ENV API_KEY_EXPIRATION ${API_KEY_EXPIRATION} # Faucet setup diff --git a/src/services/admin/api-key.ts b/src/services/admin/api-key.ts index c1d4060c..49579680 100644 --- a/src/services/admin/api-key.ts +++ b/src/services/admin/api-key.ts @@ -44,7 +44,7 @@ export class APIKeyService { } if (!expiresAt) { expiresAt = new Date(); - expiresAt.setMonth(expiresAt.getMonth() + API_KEY_EXPIRATION); + expiresAt.setMonth(expiresAt.getDay() + API_KEY_EXPIRATION); } const encryptedAPIKey = await this.secretBox.encrypt(apiKey); // Create entity diff --git a/src/types/constants.ts b/src/types/constants.ts index a92d89f6..1a6fa86a 100644 --- a/src/types/constants.ts +++ b/src/types/constants.ts @@ -11,9 +11,9 @@ export const HEADERS = { // Application constants export const APPLICATION_BASE_URL = process.env.APPLICATION_BASE_URL || 'http://localhost:3000'; export const CORS_ALLOWED_ORIGINS = process.env.CORS_ALLOWED_ORIGINS || APPLICATION_BASE_URL; -export const API_KEY_PREFIX = process.env.API_KEY_PREFIX || 'caas'; -export const API_KEY_LENGTH = process.env.API_KEY_LENGTH || 32; -export const API_KEY_EXPIRATION = process.env.API_KEY_EXPIRATION || 1; +export const API_KEY_PREFIX = 'caas'; +export const API_KEY_LENGTH = 64; +export const API_KEY_EXPIRATION = 30; // By default we don't send events to datadog export const ENABLE_DATADOG = process.env.ENABLE_DATADOG === 'true' ? true : false; // Possible cases 'trace' 'debug' 'info' 'warn' 'error'; diff --git a/src/types/environment.d.ts b/src/types/environment.d.ts index 3a32c77c..f5584c72 100644 --- a/src/types/environment.d.ts +++ b/src/types/environment.d.ts @@ -20,8 +20,6 @@ declare global { EXTERNAL_DB_CONNECTION_URL: string; EXTERNAL_DB_ENCRYPTION_KEY: string; EXTERNAL_DB_CERT: string | undefined; - API_KEY_PREFIX: string; - API_KEY_LENGTH: number; API_KEY_EXPIRATION: number; // LogTo From 180471779aaa3fcd91d410d1cd661bac038a3348 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Sat, 13 Apr 2024 15:57:27 +0200 Subject: [PATCH 31/40] Move to bcrypt and HMAC API key generating --- package-lock.json | 173 +- package.json | 2 + src/controllers/admin/api-key.ts | 57 +- src/database/entities/api.key.entity.ts | 14 +- src/database/migrations/AlterAPIKeyTable.ts | 48 + src/middleware/auth/base-auth-handler.ts | 1 - .../auth/user-info-fetcher/api-token.ts | 36 +- src/services/admin/api-key.ts | 118 +- src/services/identity/postgres.ts | 36 +- src/static/swagger-admin.json | 2056 +++-- src/static/swagger-api.json | 6880 ++++++++--------- src/types/constants.ts | 2 +- src/types/portal.ts | 6 +- 13 files changed, 4708 insertions(+), 4721 deletions(-) diff --git a/package-lock.json b/package-lock.json index 87177282..7006beb7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,6 +31,7 @@ "@verida/encryption-utils": "^3.0.0", "@verida/types": "^3.0.0", "@verida/vda-did-resolver": "^3.0.1", + "bcrypt": "^5.1.1", "bs58": "^5.0.0", "cookie-parser": "^1.4.6", "copyfiles": "^2.4.1", @@ -69,6 +70,7 @@ "@semantic-release/github": "^9.2.6", "@semantic-release/npm": "^11.0.2", "@semantic-release/release-notes-generator": "^12.1.0", + "@types/bcrypt": "^5.0.2", "@types/bs58": "^4.0.4", "@types/cookie-parser": "^1.4.6", "@types/cors": "^2.8.17", @@ -8375,6 +8377,133 @@ "node-fetch": "^2.6.7" } }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/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==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/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==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/@motionone/animation": { "version": "10.17.0", "resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.17.0.tgz", @@ -11404,6 +11533,15 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/bcrypt": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.2.tgz", + "integrity": "sha512-6atioO8Y75fNcbmj0G7UjI9lXN2pQ/IGJ2FWT4a/btd0Lk9lQalHLKhkgKVZ3r+spnmWUKfbMi1GEe9wyHQfNQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/body-parser": { "version": "1.19.5", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", @@ -14386,8 +14524,7 @@ "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "optional": true + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "node_modules/abort-controller": { "version": "3.0.0", @@ -14727,8 +14864,7 @@ "node_modules/aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "optional": true + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" }, "node_modules/are-we-there-yet": { "version": "3.0.1", @@ -15257,6 +15393,19 @@ "node": ">=14" } }, + "node_modules/bcrypt": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz", + "integrity": "sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==", + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.11", + "node-addon-api": "^5.0.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/bech32": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", @@ -16295,7 +16444,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "optional": true, "bin": { "color-support": "bin.js" } @@ -16534,8 +16682,7 @@ "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "optional": true + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" }, "node_modules/content-disposition": { "version": "0.5.4", @@ -17428,8 +17575,7 @@ "node_modules/delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "optional": true + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" }, "node_modules/denodeify": { "version": "1.2.1", @@ -19958,8 +20104,7 @@ "node_modules/has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "optional": true + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" }, "node_modules/hash-base": { "version": "3.1.0", @@ -24966,7 +25111,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "optional": true, "dependencies": { "abbrev": "1" }, @@ -30590,7 +30734,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "devOptional": true, "dependencies": { "glob": "^7.1.3" }, @@ -31365,8 +31508,7 @@ "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "devOptional": true + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "node_modules/signale": { "version": "1.4.0", @@ -34143,7 +34285,6 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "optional": true, "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } diff --git a/package.json b/package.json index 86e21932..88419af8 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "@verida/encryption-utils": "^3.0.0", "@verida/types": "^3.0.0", "@verida/vda-did-resolver": "^3.0.1", + "bcrypt": "^5.1.1", "bs58": "^5.0.0", "cookie-parser": "^1.4.6", "copyfiles": "^2.4.1", @@ -112,6 +113,7 @@ "@semantic-release/github": "^9.2.6", "@semantic-release/npm": "^11.0.2", "@semantic-release/release-notes-generator": "^12.1.0", + "@types/bcrypt": "^5.0.2", "@types/bs58": "^4.0.4", "@types/cookie-parser": "^1.4.6", "@types/cors": "^2.8.17", diff --git a/src/controllers/admin/api-key.ts b/src/controllers/admin/api-key.ts index 211cbcf2..3786cc55 100644 --- a/src/controllers/admin/api-key.ts +++ b/src/controllers/admin/api-key.ts @@ -41,7 +41,13 @@ export class APIKeyController { }) .toDate() .bail(), - check('name').exists().withMessage('Name is not specified').bail().isString().withMessage('Invalid name').bail(), + check('name') + .exists() + .withMessage('Name is not specified') + .bail() + .isString() + .withMessage('Invalid name') + .bail(), ]; static apiKeyUpdateValidator = [ check('apiKey') @@ -111,11 +117,18 @@ export class APIKeyController { @validate public async create(request: Request, response: Response) { const { name, expiresAt } = request.body satisfies APIKeyCreateRequestBody; - const options = { decryptionNeeded: true } satisfies APIServiceOptions + const options = { decryptionNeeded: true } satisfies APIServiceOptions; try { - const apiKey = APIKeyService.instance.generateAPIKey(); - const apiKeyEntity = await APIKeyService.instance.create(apiKey, name, response.locals.user, expiresAt, false, options); + const apiKey = await APIKeyService.generateAPIKey(response.locals.user.logToId as string); + const apiKeyEntity = await APIKeyService.instance.create( + apiKey, + name, + response.locals.user, + expiresAt, + false, + options + ); if (!apiKeyEntity) { return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ message: 'Cannot create a new API key', @@ -173,20 +186,20 @@ export class APIKeyController { @validate public async update(request: Request, response: Response) { const { apiKey, name, expiresAt, revoked } = request.body satisfies APIKeyUpdateRequestBody; - const options = { decryptionNeeded: true } satisfies APIServiceOptions + const options = { decryptionNeeded: true } satisfies APIServiceOptions; try { - const apiKeyEntity = await APIKeyService.instance.update({ - customer: response.locals.customer, - apiKey, - name, - expiresAt, - revoked - }, + const apiKeyEntity = await APIKeyService.instance.update( + { + apiKey, + name, + expiresAt, + revoked, + }, options - ); + ); if (!apiKeyEntity) { return response.status(StatusCodes.NOT_FOUND).json({ - error: 'Cannot update API key cause it\'s not found', + error: "Cannot update API key cause it's not found", } satisfies APIKeyUpdateUnsuccessfulResponseBody); } @@ -241,10 +254,10 @@ export class APIKeyController { */ @validate public async revoke(request: Request, response: Response) { - const options = { decryptionNeeded: true } satisfies APIServiceOptions + const options = { decryptionNeeded: true } satisfies APIServiceOptions; const { apiKey } = request.body satisfies APIKeyRevokeRequestBody; try { - const apiKeyEntity = await APIKeyService.instance.revoke(apiKey, response.locals.customer, options); + const apiKeyEntity = await APIKeyService.instance.revoke(apiKey, options); if (!apiKeyEntity) { return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ error: 'Cannot revoke API key', @@ -296,8 +309,9 @@ export class APIKeyController { @validate public async list(request: Request, response: Response) { try { - const options = { decryptionNeeded: true } satisfies APIServiceOptions - const apiKeyList = await APIKeyService.instance.find({ + const options = { decryptionNeeded: true } satisfies APIServiceOptions; + const apiKeyList = await APIKeyService.instance.find( + { customer: response.locals.customer, }, undefined, @@ -355,13 +369,12 @@ export class APIKeyController { */ @validate public async get(request: Request, response: Response) { - const apiKey = request.query.apiKey as string; - const options = { decryptionNeeded: true } satisfies APIServiceOptions + const options = { decryptionNeeded: true } satisfies APIServiceOptions; try { if (apiKey) { - const apiKeyEntity = await APIKeyService.instance.get(apiKey, response.locals.customer, options); + const apiKeyEntity = await APIKeyService.instance.get(apiKey, options); if (!apiKeyEntity) { return response.status(StatusCodes.NOT_FOUND).json({ error: 'API key not found', @@ -375,7 +388,7 @@ export class APIKeyController { revoked: apiKeyEntity.revoked, } satisfies APIKeyGetResponseBody); } - // Otherwise try to get the latest not revoked API key + // Otherwise try to get the latest not revoked API key const keys = await APIKeyService.instance.find( { customer: response.locals.customer, diff --git a/src/database/entities/api.key.entity.ts b/src/database/entities/api.key.entity.ts index ea6ef8a1..4df2a688 100644 --- a/src/database/entities/api.key.entity.ts +++ b/src/database/entities/api.key.entity.ts @@ -1,4 +1,4 @@ -import { BeforeInsert, BeforeUpdate, Column, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'; +import { BeforeInsert, BeforeUpdate, Column, Entity, JoinColumn, ManyToOne } from 'typeorm'; import * as dotenv from 'dotenv'; import { CustomerEntity } from './customer.entity.js'; @@ -7,8 +7,12 @@ dotenv.config(); @Entity('apiKey') export class APIKeyEntity { - @PrimaryGeneratedColumn('uuid') - apiKeyId!: string; + @Column({ + type: 'text', + primary: true, + nullable: false, + }) + apiKeyHash!: string; @Column({ type: 'text', @@ -69,7 +73,7 @@ export class APIKeyEntity { } constructor( - apiKeyId: string, + apiKeyHash: string, apiKey: string, name: string, expiresAt: Date, @@ -77,7 +81,7 @@ export class APIKeyEntity { user: UserEntity, revoked = false ) { - this.apiKeyId = apiKeyId; + this.apiKeyHash = apiKeyHash; this.apiKey = apiKey; this.name = name; this.expiresAt = expiresAt; diff --git a/src/database/migrations/AlterAPIKeyTable.ts b/src/database/migrations/AlterAPIKeyTable.ts index a0fa7d73..c31c0b66 100644 --- a/src/database/migrations/AlterAPIKeyTable.ts +++ b/src/database/migrations/AlterAPIKeyTable.ts @@ -1,8 +1,11 @@ import { TableColumn, type MigrationInterface, type QueryRunner } from 'typeorm'; +import bcrypt from 'bcrypt'; +import { SecretBox } from '@veramo/kms-local'; export class AlterAPIKeyTable1695740346004 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise { const table_name = 'apiKey'; + const secretBox = new SecretBox(process.env.EXTERNAL_DB_ENCRYPTION_KEY); await queryRunner.addColumn( table_name, @@ -15,6 +18,51 @@ export class AlterAPIKeyTable1695740346004 implements MigrationInterface { await queryRunner.addColumn( table_name, + new TableColumn({ + name: 'name', + type: 'text', + isNullable: true, + }) + ); + + await queryRunner.addColumn( + table_name, + new TableColumn({ + name: 'apiKeyHash', + type: 'varchar', + isNullable: true, + isUnique: true, + }) + ); + + for (const record of await queryRunner.query(`SELECT * FROM "${table_name}"`)) { + const hash = await bcrypt.hash(record.apiKey, 12); + const encryptedHash = await secretBox.encrypt(record.apiKey); + // All the previous idToken should be unique + const name = 'idToken'; + await queryRunner.query( + `UPDATE "${table_name}" SET "apiKeyHash" = '${hash}', "apiKey" = '${encryptedHash}', "name" = '${name}' WHERE "apiKeyId" = '${record.apiKeyId}'` + ); + } + + // Drop old id field + await queryRunner.dropColumn(table_name, 'apiKeyId'); + + // setup apiKeyHash column as primary + await queryRunner.changeColumn( + table_name, + 'apiKeyHash', + new TableColumn({ + name: 'apiKeyHash', + type: 'varchar', + isNullable: false, + isPrimary: true, + isUnique: true, + }) + ); + await queryRunner.changeColumn( + table_name, + 'name', new TableColumn({ name: 'name', type: 'text', diff --git a/src/middleware/auth/base-auth-handler.ts b/src/middleware/auth/base-auth-handler.ts index f928ebc8..a86a3f55 100644 --- a/src/middleware/auth/base-auth-handler.ts +++ b/src/middleware/auth/base-auth-handler.ts @@ -164,7 +164,6 @@ export class BaseAuthHandler extends BaseAPIGuard implements IAuthHandler { this.setUserInfoStrategy(new SwaggerUserInfoFetcher()); } } - } public setOAuthProvider(oauthProvider: IOAuthProvider): IAuthHandler { diff --git a/src/middleware/auth/user-info-fetcher/api-token.ts b/src/middleware/auth/user-info-fetcher/api-token.ts index 52588a40..4964dc16 100644 --- a/src/middleware/auth/user-info-fetcher/api-token.ts +++ b/src/middleware/auth/user-info-fetcher/api-token.ts @@ -24,24 +24,24 @@ export class APITokenUserInfoFetcher extends AuthReturn implements IUserInfoFetc public async verifyToken(token: string, oauthProvider: IOAuthProvider): Promise { try { - const apiEntity = await APIKeyService.instance.discoverAPIKey(token); - if (!apiEntity) { - return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: API Key not found.`); - } - if (apiEntity.revoked) { - return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: API Key is revoked.`); - } - const userEntity = await UserService.instance.findOne({ customer: apiEntity.customer}); - if (!userEntity) { - return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: User not found.`); - } - const _resp = await oauthProvider.getUserScopes(userEntity.logToId as string); - if (_resp.status !== 200) { - return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: No scopes found for the user.`); - } - if (_resp.data) { - this.setScopes(_resp.data); - } + const apiEntity = await APIKeyService.instance.get(token); + if (!apiEntity) { + return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: API Key not found.`); + } + if (apiEntity.revoked) { + return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: API Key is revoked.`); + } + const userEntity = await UserService.instance.findOne({ customer: apiEntity.customer }); + if (!userEntity) { + return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: User not found.`); + } + const _resp = await oauthProvider.getUserScopes(userEntity.logToId as string); + if (_resp.status !== 200) { + return this.returnError(StatusCodes.UNAUTHORIZED, `Unauthorized error: No scopes found for the user.`); + } + if (_resp.data) { + this.setScopes(_resp.data); + } this.setCustomerId(apiEntity.customer.customerId); return this.returnOk(); } catch (error) { diff --git a/src/services/admin/api-key.ts b/src/services/admin/api-key.ts index 49579680..adc843b7 100644 --- a/src/services/admin/api-key.ts +++ b/src/services/admin/api-key.ts @@ -1,6 +1,7 @@ import type { Repository } from 'typeorm'; import { decodeJWT } from 'did-jwt'; -import { randomBytes } from 'crypto'; +import bcrypt from 'bcrypt'; +import { randomBytes, createHmac } from 'crypto'; import { Connection } from '../../database/connection/connection.js'; import * as dotenv from 'dotenv'; @@ -8,14 +9,10 @@ import type { CustomerEntity } from '../../database/entities/customer.entity.js' import { APIKeyEntity } from '../../database/entities/api.key.entity.js'; import type { UserEntity } from '../../database/entities/user.entity.js'; import { SecretBox } from '@veramo/kms-local'; -import { API_KEY_LENGTH, API_KEY_PREFIX, API_KEY_EXPIRATION } from '../../types/constants.js'; -import pkg from 'js-sha3'; -import { v4 } from 'uuid'; +import { API_SECRET_KEY_LENGTH, API_KEY_PREFIX, API_KEY_EXPIRATION } from '../../types/constants.js'; import type { APIServiceOptions } from '../../types/portal.js'; dotenv.config(); -const { sha3_512 } = pkg; - export class APIKeyService { public apiKeyRepository: Repository; private secretBox: SecretBox; @@ -30,8 +27,15 @@ export class APIKeyService { // ToDo: Maybe we also need to store not the API key but the hash of it? // But in that case the API key will be shown once and then it will be lost. - public async create(apiKey: string, name: string, user: UserEntity, expiresAt?: Date, revoked = false, options?: APIServiceOptions): Promise { - const apiKeyId = v4(); + public async create( + apiKey: string, + name: string, + user: UserEntity, + expiresAt?: Date, + revoked = false, + options?: APIServiceOptions + ): Promise { + const apiKeyHash = await APIKeyService.hashAPIKey(apiKey); const { decryptionNeeded } = options || {}; if (!apiKey) { throw new Error('API key is not specified'); @@ -46,9 +50,17 @@ export class APIKeyService { expiresAt = new Date(); expiresAt.setMonth(expiresAt.getDay() + API_KEY_EXPIRATION); } - const encryptedAPIKey = await this.secretBox.encrypt(apiKey); + const encryptedAPIKey = await this.encryptAPIKey(apiKey); // Create entity - const apiKeyEntity = new APIKeyEntity(apiKeyId, encryptedAPIKey, name, expiresAt, user.customer, user, revoked); + const apiKeyEntity = new APIKeyEntity( + apiKeyHash, + encryptedAPIKey, + name, + expiresAt, + user.customer, + user, + revoked + ); const apiKeyRecord = (await this.apiKeyRepository.insert(apiKeyEntity)).identifiers[0]; if (!apiKeyRecord) throw new Error(`Cannot create a new API key`); @@ -60,22 +72,22 @@ export class APIKeyService { public async update( item: { - customer: CustomerEntity, - apiKey: string, - name?: string, - expiresAt?: Date, - revoked?: boolean, - user?: UserEntity + apiKey: string; + name?: string; + expiresAt?: Date; + revoked?: boolean; + customer?: CustomerEntity; + user?: UserEntity; }, options?: APIServiceOptions ) { - const { apiKey, name, expiresAt, revoked, customer, user } = item; + const { apiKey, name, expiresAt, customer, revoked, user } = item; const { decryptionNeeded } = options || {}; - const existingAPIKey = await this.discoverAPIKey(apiKey as string, customer); + const existingAPIKey = await this.get(apiKey); if (!existingAPIKey) { - throw new Error(`API key for customer ${customer.customerId} not found`); + throw new Error(`API key not found`); } if (name) { existingAPIKey.name = name; @@ -100,30 +112,44 @@ export class APIKeyService { return entity; } - public async revoke(apiKey: string, customer: CustomerEntity, options?: APIServiceOptions) { - return this.update({ - customer, - apiKey: apiKey, - revoked: true - }, options); + public async revoke(apiKey: string, options?: APIServiceOptions) { + return this.update( + { + apiKey: apiKey, + revoked: true, + }, + options + ); } public async decryptAPIKey(apiKey: string) { return await this.secretBox.decrypt(apiKey); } - public async get(apiKey: string, customer: CustomerEntity, options?: APIServiceOptions) { + public async encryptAPIKey(apiKey: string) { + return await this.secretBox.encrypt(apiKey); + } + + public async get(apiKey: string, options?: APIServiceOptions) { const { decryptionNeeded } = options || {}; - const apiKeyEntity = await this.discoverAPIKey(apiKey, customer); - if (apiKeyEntity && decryptionNeeded) { - apiKeyEntity.apiKey = await this.decryptAPIKey(apiKeyEntity.apiKey); + // ToDo: possible bottleneck cause we are fetching all the keys + for (const record of await this.find({})) { + if (await APIKeyService.compareAPIKey(apiKey, record.apiKeyHash)) { + if (decryptionNeeded) { + record.apiKey = await this.decryptAPIKey(record.apiKey); + } + return record; + } } - - return apiKeyEntity; + return null; } - public async find(where: Record, order?: Record, options?: APIServiceOptions) { + public async find( + where: Record, + order?: Record, + options?: APIServiceOptions + ) { try { const { decryptionNeeded } = options || {}; const apiKeyList = await this.apiKeyRepository.find({ @@ -142,28 +168,22 @@ export class APIKeyService { } } - public async discoverAPIKey(apiKey: string, customer?: CustomerEntity) { - const where = customer ? { customer } : {}; - const keys = await this.find(where, { createdAt: 'DESC' }); - for (const key of keys) { - if (await this.decryptAPIKey(key.apiKey) === apiKey) { - return key; - } - } - return undefined; - } - // Utils - public generateAPIKey(): string { - return `${API_KEY_PREFIX}_${randomBytes(API_KEY_LENGTH).toString('hex')}`; + public static generateAPIKey(userId: string): string { + const apiKey = createHmac('sha512', randomBytes(API_SECRET_KEY_LENGTH)).update(userId).digest('hex'); + return `${API_KEY_PREFIX}_${apiKey}`; } - public async getExpiryDate(apiKey: string): Promise { - const decrypted = await decodeJWT(apiKey); + public static getExpiryDateJWT(apiKey: string): Date { + const decrypted = decodeJWT(apiKey); return new Date(decrypted.payload.exp ? decrypted.payload.exp * 1000 : 0); } - public static hashAPIKey(apiKey: string): string { - return sha3_512(apiKey); + public static async hashAPIKey(apiKey: string): Promise { + return bcrypt.hash(apiKey, 12); + } + + public static async compareAPIKey(apiKey: string, hash: string): Promise { + return bcrypt.compare(apiKey, hash); } } diff --git a/src/services/identity/postgres.ts b/src/services/identity/postgres.ts index 736ad0af..2b1c3fe9 100644 --- a/src/services/identity/postgres.ts +++ b/src/services/identity/postgres.ts @@ -525,12 +525,23 @@ export class PostgresIdentityService extends DefaultIdentityService { } async setAPIKey(apiKey: string, customer: CustomerEntity, user: UserEntity): Promise { - const options = { decryptionNeeded: true } satisfies APIServiceOptions - const keys = await APIKeyService.instance.find({ customer: customer, user: user, revoked: false }, undefined, options); + const options = { decryptionNeeded: true } satisfies APIServiceOptions; + const keys = await APIKeyService.instance.find( + { customer: customer, user: user, revoked: false }, + undefined, + options + ); if (keys.length > 0) { throw new Error(`API key for customer ${customer.customerId} and user ${user.logToId} already exists`); } - const apiKeyEntity = await APIKeyService.instance.create(apiKey, "idToken", user); + const apiKeyEntity = await APIKeyService.instance.create( + apiKey, + 'idToken', + user, + undefined, + undefined, + options + ); if (!apiKeyEntity) { throw new Error(`Cannot create API key for customer ${customer.customerId} and user ${user.logToId}`); } @@ -538,16 +549,17 @@ export class PostgresIdentityService extends DefaultIdentityService { } async updateAPIKey(apiKey: APIKeyEntity, newApiKey: string): Promise { - const options = { decryptionNeeded: true } satisfies APIServiceOptions - const key = await APIKeyService.instance.get(apiKey.apiKey, apiKey.customer, options); + const options = { decryptionNeeded: true } satisfies APIServiceOptions; + const key = await APIKeyService.instance.get(apiKey.apiKey, options); if (!key) { throw new Error(`API key not found`); } - const apiKeyEntity = await APIKeyService.instance.update({ + const apiKeyEntity = await APIKeyService.instance.update( + { customer: key.customer, apiKey: newApiKey, - expiresAt: await APIKeyService.instance.getExpiryDate(newApiKey) - }, + expiresAt: APIKeyService.getExpiryDateJWT(newApiKey), + }, options ); if (!apiKeyEntity) { @@ -557,8 +569,12 @@ export class PostgresIdentityService extends DefaultIdentityService { } async getAPIKey(customer: CustomerEntity, user: UserEntity): Promise { - const options = { decryptionNeeded: true } satisfies APIServiceOptions - const keys = await APIKeyService.instance.find({ customer: customer, user: user, revoked: false }, undefined, options); + const options = { decryptionNeeded: true } satisfies APIServiceOptions; + const keys = await APIKeyService.instance.find( + { customer: customer, user: user, revoked: false, name: 'idToken' }, + undefined, + options + ); if (keys.length > 1) { throw new Error( `For the customer with customer id ${customer.customerId} and user with logToId ${user.logToId} there more then 1 API key` diff --git a/src/static/swagger-admin.json b/src/static/swagger-admin.json index 8106c31e..72021893 100644 --- a/src/static/swagger-admin.json +++ b/src/static/swagger-admin.json @@ -1,1049 +1,1011 @@ { - "openapi": "3.0.0", - "info": { - "title": "Credential Service admin API for cheqd network", - "version": "2.0.0", - "description": "Admin API which handles users subscriptions and payments", - "contact": { - "name": "Cheqd Foundation Limited", - "url": "https://github.com/cheqd/credential-service", - "email": "support-github@cheqd.io" - }, - "license": { - "name": "Apache 2.0", - "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" - } - }, - "tags": [ - { - "name": "Product" - }, - { - "name": "Price" - }, - { - "name": "Subscription" - }, - { - "name": "API Key" - } - ], - "paths": { - "/admin/api-key/create": { - "post": { - "summary": "Create a new API key", - "description": "Create a new API key", - "tags": [ - "API Key" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyCreateRequestBody" - } - } - } - }, - "responses": { - "201": { - "description": "A new API key has been created", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyCreateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/APIKeyCreateUnsuccessfulResponseBody" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/api-key/update": { - "post": { - "summary": "Update an existing API key", - "description": "Update an existing API key", - "tags": [ - "API Key" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyUpdateRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The API key has been updated", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyUpdateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/APIKeyUpdateUnsuccessfulResponseBody" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/api-key/revoke": { - "delete": { - "summary": "Revoke an existing API key", - "description": "Revoke an existing API key", - "tags": [ - "API Key" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyRevokeRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The API key has been revoked", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyRevokeResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/APIKeyRevokeUnsuccessfulResponseBody" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/api-key/list": { - "get": { - "summary": "List all API keys", - "description": "List all API keys", - "tags": [ - "API Key" - ], - "responses": { - "200": { - "description": "A list of API keys", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/api-key/get": { - "get": { - "summary": "Get an API key", - "description": "Get an API key. If the API key is not provided, the latest not revoked API key it returns.", - "tags": [ - "API Key" - ], - "parameters": [ - { - "name": "apiKey", - "in": "query", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "The API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyGetResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/price/list": { - "get": { - "summary": "Get a list of prices", - "description": "Get a list of prices", - "tags": [ - "Price" - ], - "parameters": [ - { - "in": "query", - "name": "productId", - "schema": { - "type": "string", - "description": "The product id. If passed - returns filtered by this product list of prices.", - "required": false - } - } - ], - "responses": { - "200": { - "description": "A list of prices", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PriceListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/product/list": { - "get": { - "summary": "Get a list of products", - "description": "Get a list of products which are on a Stripe side", - "tags": [ - "Product" - ], - "parameters": [ - { - "in": "query", - "name": "prices", - "schema": { - "type": "boolean", - "description": "If setup to true - returns the list of products with prices inside. Default - true", - "required": false - } - } - ], - "responses": { - "200": { - "description": "A list of products", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/product/get/{productId}": { - "get": { - "summary": "Get a product", - "description": "Get a product by id", - "tags": [ - "Product" - ], - "parameters": [ - { - "in": "path", - "name": "productId", - "schema": { - "type": "string", - "description": "The product id which identifies the product in Stripe" - }, - "required": true - }, - { - "in": "query", - "name": "prices", - "schema": { - "type": "boolean", - "description": "If setup to true - returns the product with prices inside. Default - true", - "required": false - } - } - ], - "responses": { - "200": { - "description": "A product", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductGetResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/create": { - "post": { - "summary": "Create a subscription", - "description": "Creates a new subscription for an existing customer", - "tags": [ - "Subscription" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCreateRequestBody" - } - } - } - }, - "responses": { - "201": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCreateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/update": { - "post": { - "summary": "Update a subscription", - "description": "Updates an existing subscription", - "tags": [ - "Subscription" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionUpdateRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionUpdateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/list": { - "get": { - "summary": "Get a list of subscriptions", - "description": "Get a list of subscriptions", - "tags": [ - "Subscription" - ], - "parameters": [ - { - "in": "query", - "name": "paymentProviderId", - "schema": { - "type": "string", - "description": "The customer id. If passed - returns filtered by this customer list of subscriptions." - } - } - ], - "responses": { - "200": { - "description": "A list of subscriptions", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/get": { - "get": { - "summary": "Get a subscription", - "description": "Get a subscription", - "tags": [ - "Subscription" - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionGetResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/cancel": { - "post": { - "summary": "Cancel a subscription", - "description": "Cancels an existing subscription", - "tags": [ - "Subscription" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCancelRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCancelResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/resume": {}, - "post": { - "summary": "Resume a subscription", - "description": "Resumes an existing subscription", - "tags": [ - "Subscription" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionResumeRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionResumeResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "components": { - "schemas": { - "PriceListResponseBody": { - "description": "A list of active prcies from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/list)", - "type": "object", - "properties": { - "prices": { - "type": "array", - "items": { - "type": "object", - "description": "A price object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/object)" - } - } - } - }, - "ProductListResponseBody": { - "type": "object", - "properties": { - "products": { - "type": "array", - "items": { - "type": "object", - "description": "A product object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/object)" - } - } - } - }, - "ProductGetResponseBody": { - "description": "A product with or without prices inside. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/retrieve)", - "type": "object" - }, - "InvalidRequest": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "InvalidRequest" - } - } - }, - "InternalError": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Internal Error" - } - } - }, - "UnauthorizedError": { - "description": "Access token is missing or invalid", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Unauthorized Error" - } - } - }, - "SubscriptionCreateRequestBody": { - "description": "The request body for creating a subscription", - "type": "object", - "properties": { - "price": { - "type": "string", - "description": "The price id", - "example": "price_1234567890" - }, - "successURL": { - "type": "string", - "description": "The URL to redirect to after the customer sucessfully completes the checkout", - "example": "https://example.com/success" - }, - "cancelURL": { - "type": "string", - "description": "The URL to redirect to after the customer cancels the checkout", - "example": "https://example.com/cancel" - }, - "quantity": { - "type": "number", - "description": "The quantity of the product", - "example": 1 - }, - "trialPeriodDays": { - "type": "number", - "description": "The number of days the customer has to pay for the product", - "example": 7 - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": "abcdefghijklmnopqrstuvwxyz" - } - } - }, - "SubscriptionCreateResponseBody": { - "description": "The response body for creating a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "An object with link to checkout session. For more information see the [Stripe API documentation](https://docs.stripe.com/api/checkout/sessions/object)", - "properties": { - "sessionURL": { - "type": "string", - "description": "URL which user should follow to manage subscription" - } - } - } - } - }, - "SubscriptionUpdateRequestBody": { - "description": "The request body for updating a subscription", - "type": "object", - "properties": { - "returnURL": { - "type": "string", - "description": "URL which is used to redirect to the page with ability to update the subscription" - } - } - }, - "SubscriptionUpdateResponseBody": { - "description": "The response body for updating a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "Object with redirect url inside", - "properties": { - "sessionURL": { - "type": "string", - "description": "URL with session URL rediect to" - } - } - } - } - }, - "SubscriptionGetRequestBody": { - "description": "The request body for getting a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - } - } - }, - "SubscriptionGetResponseBody": { - "description": "The response body for getting a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" - } - } - }, - "SubscriptionListRequestBody": { - "description": "The request body for listing subscriptions", - "type": "object", - "properties": { - "customerId": { - "type": "string", - "description": "The Stripe customer id", - "example": "cus_1234567890" - } - } - }, - "SubscriptionListResponseBody": { - "description": "The response body for listing subscriptions", - "type": "object", - "properties": { - "subscriptions": { - "type": "array", - "items": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" - } - } - } - }, - "SubscriptionCancelRequestBody": { - "description": "The request body for canceling a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - } - } - }, - "SubscriptionCancelResponseBody": { - "description": "The response body for canceling a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": "abcdefghijklmnopqrstuvwxyz" - } - } - }, - "SubscriptionResumeRequestBody": { - "description": "The request body for resuming a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": "abcdefghijklmnopqrstuvwxyz" - } - } - }, - "SubscriptionResumeResponseBody": { - "description": "The response body for resuming a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" - } - } - }, - "APIKeyResponse": { - "description": "The general view for API key in response", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz" - }, - "createdAt": { - "type": "string", - "description": "The creation date of the API key", - "example": "2000-10-31T01:23:45Z", - "format": "date-time" - }, - "name": { - "type": "string", - "description": "The name of the API key", - "example": "My API Key" - }, - "expiresAt": { - "type": "string", - "description": "The expiration date of the API key", - "example": "2000-10-31T01:23:45Z", - "format": "date-time" - }, - "revoked": { - "type": "boolean", - "description": "The status of the API key", - "example": false - } - } - }, - "APIKeyCreateRequestBody": { - "description": "The request body for creating an API key", - "type": "object", - "properties": { - "expiresAt": { - "type": "string", - "description": "The expiration date of the API key", - "example": "2000-10-31T01:23:45Z", - "format": "date-time" - }, - "name": { - "type": "string", - "description": "The name of the API key", - "example": "My API Key" - } - }, - "required": [ - "name" - ] - }, - "APIKeyCreateResponseBody": { - "description": "The response body for creating an API key", - "type": "object", - "schema": { - "ref": "#/components/schemas/APIKeyResponse" - } - }, - "APIKeyCreateUnsuccessfulResponseBody": { - "description": "The response body for an unsuccessful API key creation", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "API key creation unsuccessful" - } - } - }, - "APIKeyUpdateRequestBody": { - "description": "The request body for updating an API key", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz" - }, - "name": { - "type": "string", - "description": "The name of the API key", - "example": "My API Key" - }, - "expiresAt": { - "type": "string", - "description": "The expiration date of the API key", - "example": "2000-10-31T01:23:45Z", - "format": "date-time" - }, - "revoked": { - "type": "boolean", - "description": "The status of the API key", - "example": false, - "default": false - } - }, - "required": [ - "apiKey" - ] - }, - "APIKeyUpdateResponseBody": { - "description": "The response body for an unsuccessful API key update", - "type": "object", - "schema": { - "ref": "#/components/schemas/APIKeyResponse" - } - }, - "APIKeyUpdateUnsuccessfulResponseBody": { - "description": "The response body for an unsuccessful API key update", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "API key update unsuccessful" - } - } - }, - "APIKeyRevokeRequestBody": { - "description": "The request body for revoking an API key", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz" - } - }, - "required": [ - "apiKey" - ] - }, - "APIKeyRevokeResponseBody": { - "description": "The response body for revoking an API key", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz" - }, - "revoked": { - "type": "boolean", - "description": "The status of the API key", - "example": true - } - }, - "required": [ - "apiKey" - ] - }, - "APIKeyRevokeUnsuccessfulResponseBody": { - "description": "The response body for an unsuccessful API key revocation", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "API key revocation unsuccessful" - } - } - }, - "APIKeyListResponseBody": { - "description": "The response body for listing API keys", - "type": "object", - "properties": { - "apiKeys": { - "type": "array", - "items": { - "type": "object", - "schema": { - "ref": "#/components/schemas/APIKeyResponse" - } - } - } - } - }, - "APIKeyGetRequestBody": { - "description": "The request body for getting an API key", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz" - } - }, - "required": [ - "apiKey" - ] - }, - "APIKeyGetResponseBody": { - "description": "The response body for getting an API key", - "type": "object", - "schema": { - "ref": "#/components/schemas/APIKeyResponse" - } - }, - "NotFoundError": { - "description": "The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Not Found Error" - } - } - } - } - } + "openapi": "3.0.0", + "info": { + "title": "Credential Service admin API for cheqd network", + "version": "2.0.0", + "description": "Admin API which handles users subscriptions and payments", + "contact": { + "name": "Cheqd Foundation Limited", + "url": "https://github.com/cheqd/credential-service", + "email": "support-github@cheqd.io" + }, + "license": { + "name": "Apache 2.0", + "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" + } + }, + "tags": [ + { + "name": "Product" + }, + { + "name": "Price" + }, + { + "name": "Subscription" + }, + { + "name": "API Key" + } + ], + "paths": { + "/admin/api-key/create": { + "post": { + "summary": "Create a new API key", + "description": "Create a new API key", + "tags": ["API Key"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyCreateRequestBody" + } + } + } + }, + "responses": { + "201": { + "description": "A new API key has been created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyCreateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/APIKeyCreateUnsuccessfulResponseBody" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/api-key/update": { + "post": { + "summary": "Update an existing API key", + "description": "Update an existing API key", + "tags": ["API Key"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyUpdateRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The API key has been updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyUpdateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/APIKeyUpdateUnsuccessfulResponseBody" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/api-key/revoke": { + "delete": { + "summary": "Revoke an existing API key", + "description": "Revoke an existing API key", + "tags": ["API Key"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyRevokeRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The API key has been revoked", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyRevokeResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/APIKeyRevokeUnsuccessfulResponseBody" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/api-key/list": { + "get": { + "summary": "List all API keys", + "description": "List all API keys", + "tags": ["API Key"], + "responses": { + "200": { + "description": "A list of API keys", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/api-key/get": { + "get": { + "summary": "Get an API key", + "description": "Get an API key. If the API key is not provided, the latest not revoked API key it returns.", + "tags": ["API Key"], + "parameters": [ + { + "name": "apiKey", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyGetResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/price/list": { + "get": { + "summary": "Get a list of prices", + "description": "Get a list of prices", + "tags": ["Price"], + "parameters": [ + { + "in": "query", + "name": "productId", + "schema": { + "type": "string", + "description": "The product id. If passed - returns filtered by this product list of prices.", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A list of prices", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PriceListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/product/list": { + "get": { + "summary": "Get a list of products", + "description": "Get a list of products which are on a Stripe side", + "tags": ["Product"], + "parameters": [ + { + "in": "query", + "name": "prices", + "schema": { + "type": "boolean", + "description": "If setup to true - returns the list of products with prices inside. Default - true", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A list of products", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProductListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/product/get/{productId}": { + "get": { + "summary": "Get a product", + "description": "Get a product by id", + "tags": ["Product"], + "parameters": [ + { + "in": "path", + "name": "productId", + "schema": { + "type": "string", + "description": "The product id which identifies the product in Stripe" + }, + "required": true + }, + { + "in": "query", + "name": "prices", + "schema": { + "type": "boolean", + "description": "If setup to true - returns the product with prices inside. Default - true", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A product", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProductGetResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/create": { + "post": { + "summary": "Create a subscription", + "description": "Creates a new subscription for an existing customer", + "tags": ["Subscription"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCreateRequestBody" + } + } + } + }, + "responses": { + "201": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCreateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/update": { + "post": { + "summary": "Update a subscription", + "description": "Updates an existing subscription", + "tags": ["Subscription"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionUpdateRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionUpdateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/list": { + "get": { + "summary": "Get a list of subscriptions", + "description": "Get a list of subscriptions", + "tags": ["Subscription"], + "parameters": [ + { + "in": "query", + "name": "paymentProviderId", + "schema": { + "type": "string", + "description": "The customer id. If passed - returns filtered by this customer list of subscriptions." + } + } + ], + "responses": { + "200": { + "description": "A list of subscriptions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/get": { + "get": { + "summary": "Get a subscription", + "description": "Get a subscription", + "tags": ["Subscription"], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionGetResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/cancel": { + "post": { + "summary": "Cancel a subscription", + "description": "Cancels an existing subscription", + "tags": ["Subscription"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCancelRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCancelResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/resume": {}, + "post": { + "summary": "Resume a subscription", + "description": "Resumes an existing subscription", + "tags": ["Subscription"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionResumeRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionResumeResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "components": { + "schemas": { + "PriceListResponseBody": { + "description": "A list of active prcies from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/list)", + "type": "object", + "properties": { + "prices": { + "type": "array", + "items": { + "type": "object", + "description": "A price object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/object)" + } + } + } + }, + "ProductListResponseBody": { + "type": "object", + "properties": { + "products": { + "type": "array", + "items": { + "type": "object", + "description": "A product object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/object)" + } + } + } + }, + "ProductGetResponseBody": { + "description": "A product with or without prices inside. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/retrieve)", + "type": "object" + }, + "InvalidRequest": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "InvalidRequest" + } + } + }, + "InternalError": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Internal Error" + } + } + }, + "UnauthorizedError": { + "description": "Access token is missing or invalid", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Unauthorized Error" + } + } + }, + "SubscriptionCreateRequestBody": { + "description": "The request body for creating a subscription", + "type": "object", + "properties": { + "price": { + "type": "string", + "description": "The price id", + "example": "price_1234567890" + }, + "successURL": { + "type": "string", + "description": "The URL to redirect to after the customer sucessfully completes the checkout", + "example": "https://example.com/success" + }, + "cancelURL": { + "type": "string", + "description": "The URL to redirect to after the customer cancels the checkout", + "example": "https://example.com/cancel" + }, + "quantity": { + "type": "number", + "description": "The quantity of the product", + "example": 1 + }, + "trialPeriodDays": { + "type": "number", + "description": "The number of days the customer has to pay for the product", + "example": 7 + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": "abcdefghijklmnopqrstuvwxyz" + } + } + }, + "SubscriptionCreateResponseBody": { + "description": "The response body for creating a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "An object with link to checkout session. For more information see the [Stripe API documentation](https://docs.stripe.com/api/checkout/sessions/object)", + "properties": { + "sessionURL": { + "type": "string", + "description": "URL which user should follow to manage subscription" + } + } + } + } + }, + "SubscriptionUpdateRequestBody": { + "description": "The request body for updating a subscription", + "type": "object", + "properties": { + "returnURL": { + "type": "string", + "description": "URL which is used to redirect to the page with ability to update the subscription" + } + } + }, + "SubscriptionUpdateResponseBody": { + "description": "The response body for updating a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "Object with redirect url inside", + "properties": { + "sessionURL": { + "type": "string", + "description": "URL with session URL rediect to" + } + } + } + } + }, + "SubscriptionGetRequestBody": { + "description": "The request body for getting a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + } + } + }, + "SubscriptionGetResponseBody": { + "description": "The response body for getting a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" + } + } + }, + "SubscriptionListRequestBody": { + "description": "The request body for listing subscriptions", + "type": "object", + "properties": { + "customerId": { + "type": "string", + "description": "The Stripe customer id", + "example": "cus_1234567890" + } + } + }, + "SubscriptionListResponseBody": { + "description": "The response body for listing subscriptions", + "type": "object", + "properties": { + "subscriptions": { + "type": "array", + "items": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + } + } + } + }, + "SubscriptionCancelRequestBody": { + "description": "The request body for canceling a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + } + } + }, + "SubscriptionCancelResponseBody": { + "description": "The response body for canceling a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": "abcdefghijklmnopqrstuvwxyz" + } + } + }, + "SubscriptionResumeRequestBody": { + "description": "The request body for resuming a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": "abcdefghijklmnopqrstuvwxyz" + } + } + }, + "SubscriptionResumeResponseBody": { + "description": "The response body for resuming a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + } + } + }, + "APIKeyResponse": { + "description": "The general view for API key in response", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + }, + "createdAt": { + "type": "string", + "description": "The creation date of the API key", + "example": "2000-10-31T01:23:45Z", + "format": "date-time" + }, + "name": { + "type": "string", + "description": "The name of the API key", + "example": "My API Key" + }, + "expiresAt": { + "type": "string", + "description": "The expiration date of the API key", + "example": "2000-10-31T01:23:45Z", + "format": "date-time" + }, + "revoked": { + "type": "boolean", + "description": "The status of the API key", + "example": false + } + } + }, + "APIKeyCreateRequestBody": { + "description": "The request body for creating an API key", + "type": "object", + "properties": { + "expiresAt": { + "type": "string", + "description": "The expiration date of the API key", + "example": "2000-10-31T01:23:45Z", + "format": "date-time" + }, + "name": { + "type": "string", + "description": "The name of the API key", + "example": "My API Key" + } + }, + "required": ["name"] + }, + "APIKeyCreateResponseBody": { + "description": "The response body for creating an API key", + "type": "object", + "schema": { + "ref": "#/components/schemas/APIKeyResponse" + } + }, + "APIKeyCreateUnsuccessfulResponseBody": { + "description": "The response body for an unsuccessful API key creation", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "API key creation unsuccessful" + } + } + }, + "APIKeyUpdateRequestBody": { + "description": "The request body for updating an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + }, + "name": { + "type": "string", + "description": "The name of the API key", + "example": "My API Key" + }, + "expiresAt": { + "type": "string", + "description": "The expiration date of the API key", + "example": "2000-10-31T01:23:45Z", + "format": "date-time" + }, + "revoked": { + "type": "boolean", + "description": "The status of the API key", + "example": false, + "default": false + } + }, + "required": ["apiKey"] + }, + "APIKeyUpdateResponseBody": { + "description": "The response body for an unsuccessful API key update", + "type": "object", + "schema": { + "ref": "#/components/schemas/APIKeyResponse" + } + }, + "APIKeyUpdateUnsuccessfulResponseBody": { + "description": "The response body for an unsuccessful API key update", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "API key update unsuccessful" + } + } + }, + "APIKeyRevokeRequestBody": { + "description": "The request body for revoking an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + } + }, + "required": ["apiKey"] + }, + "APIKeyRevokeResponseBody": { + "description": "The response body for revoking an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + }, + "revoked": { + "type": "boolean", + "description": "The status of the API key", + "example": true + } + }, + "required": ["apiKey"] + }, + "APIKeyRevokeUnsuccessfulResponseBody": { + "description": "The response body for an unsuccessful API key revocation", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "API key revocation unsuccessful" + } + } + }, + "APIKeyListResponseBody": { + "description": "The response body for listing API keys", + "type": "object", + "properties": { + "apiKeys": { + "type": "array", + "items": { + "type": "object", + "schema": { + "ref": "#/components/schemas/APIKeyResponse" + } + } + } + } + }, + "APIKeyGetRequestBody": { + "description": "The request body for getting an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + } + }, + "required": ["apiKey"] + }, + "APIKeyGetResponseBody": { + "description": "The response body for getting an API key", + "type": "object", + "schema": { + "ref": "#/components/schemas/APIKeyResponse" + } + }, + "NotFoundError": { + "description": "The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Not Found Error" + } + } + } + } + } } diff --git a/src/static/swagger-api.json b/src/static/swagger-api.json index 8edb8fb8..b2cf4b99 100644 --- a/src/static/swagger-api.json +++ b/src/static/swagger-api.json @@ -1,3550 +1,3334 @@ { - "openapi": "3.0.0", - "info": { - "title": "Credential Service API for cheqd network", - "version": "2.0.0", - "description": "API service to create and manage DIDs, Verifiable Credentials, and DID-Linked Resources", - "contact": { - "name": "Cheqd Foundation Limited", - "url": "https://github.com/cheqd/credential-service", - "email": "support-github@cheqd.io" - }, - "license": { - "name": "Apache 2.0", - "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" - } - }, - "tags": [ - { - "name": "Account" - }, - { - "name": "Key" - }, - { - "name": "DID" - }, - { - "name": "Resource" - }, - { - "name": "Credential" - }, - { - "name": "Presentation" - }, - { - "name": "Credential Status" - } - ], - "externalDocs": { - "description": "Credential Service API Documentation", - "url": "https://docs.cheqd.io/identity" - }, - "paths": { - "/account": { - "get": { - "tags": [ - "Account" - ], - "summary": "Fetch custodian-mode client details.", - "description": "This endpoint returns the custodian-mode client details for authenticated users.", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Customer" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/account/idtoken": { - "get": { - "tags": [ - "Account" - ], - "summary": "Fetch IdToken.", - "description": "This endpoint returns IdToken as JWT with list of user roles inside", - "deprecated": true, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "idToken": { - "type": "string" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/account/create": { - "post": { - "tags": [ - "Account" - ], - "summary": "Create an client for an authenticated user.", - "description": "This endpoint creates a client in the custodian-mode for an authenticated user", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/AccountCreateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountCreateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "idToken": { - "type": "string" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/create/unencrypted": { - "post": { - "tags": [ - "Credential Status" - ], - "summary": "Create an unencrypted StatusList2021 credential status list.", - "description": "This endpoint creates an unencrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", - "parameters": [ - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", - "required": true, - "schema": { - "type": "string", - "enum": [ - "revocation", - "suspension" - ] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/create/encrypted": { - "post": { - "tags": [ - "Credential Status" - ], - "summary": "Create an encrypted StatusList2021 credential status list.", - "description": "This endpoint creates an encrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", - "parameters": [ - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", - "required": true, - "schema": { - "type": "string", - "enum": [ - "revocation", - "suspension" - ] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateEncryptedFormRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateEncryptedJsonRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateEncryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/update/unencrypted": { - "post": { - "tags": [ - "Credential Status" - ], - "summary": "Update an existing unencrypted StatusList2021 credential status list.", - "parameters": [ - { - "in": "query", - "name": "statusAction", - "description": "The update action to be performed on the unencrypted status list, can be revoke, suspend or reinstate", - "required": true, - "schema": { - "type": "string", - "enum": [ - "revoke", - "suspend", - "reinstate" - ] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/update/encrypted": { - "post": { - "tags": [ - "Credential Status" - ], - "summary": "Update an existing encrypted StatusList2021 credential status list.", - "parameters": [ - { - "in": "query", - "name": "statusAction", - "description": "The update action to be performed on the encrypted status list, can be revoke, suspend or reinstate", - "required": true, - "schema": { - "type": "string", - "enum": [ - "revoke", - "suspend", - "reinstate" - ] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedFormRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedJsonRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/check": { - "post": { - "tags": [ - "Credential Status" - ], - "summary": "Check a StatusList2021 index for a given Verifiable Credential.", - "description": "This endpoint checks a StatusList2021 index for a given Verifiable Credential and reports whether it is revoked or suspended. It offers a standalone method for checking an index without passing the entire Verifiable Credential or Verifiable Presentation.", - "parameters": [ - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension.", - "required": true, - "schema": { - "type": "string", - "enum": [ - "revocation", - "suspension" - ] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCheckRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCheckRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCheckResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/search": { - "get": { - "tags": [ - "Credential Status" - ], - "summary": "Fetch StatusList2021 DID-Linked Resource based on search criteria.", - "parameters": [ - { - "in": "query", - "name": "did", - "description": "The DID of the issuer of the status list.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension.", - "schema": { - "type": "string", - "enum": [ - "revocation", - "suspension" - ] - } - }, - { - "in": "query", - "name": "statusListName", - "description": "The name of the StatusList2021 DID-Linked Resource.", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusListSearchResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/issue": { - "post": { - "tags": [ - "Credential" - ], - "summary": "Issue a Verifiable Credential", - "description": "This endpoint issues a Verifiable Credential. As input it takes the list of issuerDid, subjectDid, attributes, and other parameters of the credential to be issued.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Credential" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/verify": { - "post": { - "tags": [ - "Credential" - ], - "summary": "Verify a Verifiable Credential.", - "description": "This endpoint verifies a Verifiable Credential passed to it. As input, it can take the VC-JWT as a string or the entire credential itself.", - "operationId": "verify", - "parameters": [ - { - "in": "query", - "name": "verifyStatus", - "description": "If set to `true` the verification will also check the status of the credential. Requires the VC to have a `credentialStatus` property.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "fetchRemoteContexts", - "description": "When dealing with JSON-LD you also MUST provide the proper contexts. Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "allowDeactivatedDid", - "description": "If set to `true` allow to verify credential which based on deactivated DID.", - "schema": { - "type": "boolean", - "default": false - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialVerifyRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialVerifyRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/VerifyCredentialResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/revoke": { - "post": { - "tags": [ - "Credential" - ], - "summary": "Revoke a Verifiable Credential.", - "description": "This endpoint revokes a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself. The StatusList2021 resource should already be setup in the VC and `credentialStatus` property present in the VC.", - "operationId": "revoke", - "parameters": [ - { - "in": "query", - "name": "publish", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RevocationResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/suspend": { - "post": { - "tags": [ - "Credential" - ], - "summary": "Suspend a Verifiable Credential.", - "description": "This endpoint suspends a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself.", - "operationId": "suspend", - "parameters": [ - { - "in": "query", - "name": "publish", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "schema": { - "type": "boolean" - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuspensionResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/reinstate": { - "post": { - "tags": [ - "Credential" - ], - "summary": "Reinstate a suspended Verifiable Credential.", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "operationId": "reinstate", - "parameters": [ - { - "in": "query", - "name": "publish", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "schema": { - "type": "boolean" - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnsuspensionResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/create": { - "post": { - "tags": [ - "DID" - ], - "summary": "Create a DID Document.", - "description": "This endpoint creates a DID and associated DID Document. As input, it can take the DID Document parameters via a form, or the fully-assembled DID Document itself.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidCreateRequestFormBased" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidCreateRequestJson" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/did/update": { - "post": { - "tags": [ - "DID" - ], - "summary": "Update a DID Document.", - "description": "This endpoint updates a DID Document. As an input, it can take JUST the sections/parameters that need to be updated in the DID Document (in this scenario, it fetches the current DID Document and applies the updated section). Alternatively, it take the fully-assembled DID Document with updated sections as well as unchanged sections.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidUpdateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidUpdateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidUpdateResponse" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/import": { - "post": { - "tags": [ - "DID" - ], - "summary": "Import a DID Document.", - "description": "This endpoint imports a decentralized identifier associated with the user's account for custodian-mode clients.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidImportRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidImportRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/did/deactivate/{did}": { - "post": { - "tags": [ - "DID" - ], - "summary": "Deactivate a DID Document.", - "description": "This endpoint deactivates a DID Document by taking the DID identifier as input. Must be called and signed by the DID owner.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier to deactivate.", - "schema": { - "type": "string" - }, - "required": true - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidDeactivateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidDeactivateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeactivatedDidResolution" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/list": { - "get": { - "tags": [ - "DID" - ], - "summary": "Fetch DIDs associated with an account.", - "description": "This endpoint returns the list of DIDs controlled by the account.", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/search/{did}": { - "get": { - "tags": [ - "DID" - ], - "summary": "Resolve a DID Document.", - "description": "Resolve a DID Document by DID identifier. Also supports DID Resolution Queries as defined in the W3C DID Resolution specification.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier to resolve.", - "schema": { - "type": "string" - }, - "required": true, - "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - { - "in": "query", - "name": "metadata", - "description": "Return only metadata of DID Document instead of actual DID Document.", - "schema": { - "type": "boolean" - } - }, - { - "in": "query", - "name": "versionId", - "description": "Unique UUID version identifier of DID Document. Allows for fetching a specific version of the DID Document. See cheqd DID Method Specification for more details.", - "schema": { - "type": "string", - "format": "uuid" - }, - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - { - "in": "query", - "name": "versionTime", - "description": "Returns the closest version of the DID Document *at* or *before* specified time. See DID Resolution handling for `did:cheqd` for more details.", - "schema": { - "type": "string", - "format": "date-time" - }, - "example": "1970-01-01T00:00:00Z" - }, - { - "in": "query", - "name": "transformKeys", - "description": "This directive transforms the Verification Method key format from the version in the DID Document to the specified format chosen below.", - "schema": { - "type": "string", - "enum": [ - "Ed25519VerificationKey2018", - "Ed25519VerificationKey2020", - "JsonWebKey2020" - ] - } - }, - { - "in": "query", - "name": "service", - "description": "Query DID Document for a specific Service Endpoint by Service ID (e.g., `service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`). This will typically redirect to the Service Endpoint based on DID Resolution specification algorithm.", - "schema": { - "type": "string" - }, - "example": "service-1" - }, - { - "in": "query", - "name": "relativeRef", - "description": "Relative reference is a query fragment appended to the Service Endpoint URL. **Must** be used along with the `service` query property above. See DID Resolution specification algorithm for more details.", - "schema": { - "type": "string" - }, - "example": "/path/to/file" - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidResolution" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/key/create": { - "post": { - "tags": [ - "Key" - ], - "summary": "Create an identity key pair.", - "description": "This endpoint creates an identity key pair associated with the user's account for custodian-mode clients.", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/key/import": { - "post": { - "tags": [ - "Key" - ], - "summary": "Import an identity key pair.", - "description": "This endpoint imports an identity key pair associated with the user's account for custodian-mode clients.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/KeyImportRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyImportRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/key/read/{kid}": { - "get": { - "tags": [ - "Key" - ], - "summary": "Fetch an identity key pair.", - "description": "This endpoint fetches an identity key pair's details for a given key ID. Only the user account associated with the custodian-mode client can fetch the key pair.", - "parameters": [ - { - "name": "kid", - "description": "Key ID of the identity key pair to fetch.", - "in": "path", - "schema": { - "type": "string" - }, - "required": true - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/presentation/create": { - "post": { - "tags": [ - "Presentation" - ], - "summary": "!!! WARN. Such endpoint is made mostly for testing purposes and it is not supposed to be used in production !!! Create a Verifiable Presentation from credential(s).", - "description": "This endpoint creates a Verifiable Presentation from credential(s). As input, it can take the credential(s) as a string or the entire credential(s) itself. \n !!! WARN. Such endpoint is made only for testing purposes !!!", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/PresentationCreateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/PresentationCreateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PresentationCreateResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/presentation/verify": { - "post": { - "tags": [ - "Presentation" - ], - "summary": "Verify a Verifiable Presentation generated from credential(s).", - "description": "This endpoint verifies the Verifiable Presentation generated from credential(s). As input, it can take the Verifiable Presentation JWT as a string or the entire Verifiable Presentation itself.", - "parameters": [ - { - "in": "query", - "name": "verifyStatus", - "description": "If set to `true` the verification will also check the status of the presentation. Requires the VP to have a `credentialStatus` property.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "fetchRemoteContexts", - "description": "When dealing with JSON-LD you also MUST provide the proper contexts. * Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "allowDeactivatedDid", - "description": "If set to `true` allow to verify credential which based on deactivated DID.", - "schema": { - "type": "boolean", - "default": false - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/PresentationVerifyRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/PresentationVerifyRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/VerifyPresentationResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/resource/create/{did}": { - "post": { - "tags": [ - "Resource" - ], - "summary": "Create a DID-Linked Resource.", - "description": "This endpoint creates a DID-Linked Resource. As input, it can take the DID identifier and the resource parameters via a form, or the fully-assembled resource itself.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier to link the resource to.", - "schema": { - "type": "string" - }, - "required": true - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CreateResourceRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateResourceRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ResourceMetadata" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/resource/search/{did}": { - "get": { - "tags": [ - "Resource" - ], - "summary": "Get a DID-Linked Resource.", - "description": "This endpoint returns the DID-Linked Resource for a given DID identifier and resource identifier.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier", - "schema": { - "type": "string" - }, - "required": true, - "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - { - "in": "query", - "name": "resourceId", - "description": "Fetch a DID-Linked Resource by Resource ID unique identifier. Since this is a unique identifier, other Resource query parameters are not required. See DID-Linked Resources for more details.", - "schema": { - "type": "string", - "format": "uuid" - }, - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - { - "in": "query", - "name": "resourceName", - "description": "Filter a DID-Linked Resource query by Resource Name. See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "cheqd-issuer-logo" - }, - { - "in": "query", - "name": "resourceType", - "description": "Filter a DID-Linked Resource query by Resource Type. See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "CredentialArtwork" - }, - { - "in": "query", - "name": "resourceVersion", - "description": "Filter a DID-Linked Resource query by Resource Version, which is an optional free-text field used by issuers (e.g., \"v1\", \"Final Version\", \"1st January 1970\" etc). See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "v1" - }, - { - "in": "query", - "name": "resourceVersionTime", - "description": "Filter a DID-Linked Resource query which returns the closest version of the Resource *at* or *before* specified time. See DID-Linked Resources for more details.", - "schema": { - "type": "string", - "format": "date-time" - }, - "example": "1970-01-01T00:00:00Z" - }, - { - "in": "query", - "name": "checksum", - "description": "Request integrity check against a given DID-Linked Resource by providing a SHA-256 checksum hash. See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "dc64474d062ed750a66bad58cb609928de55ed0d81defd231a4a4bf97358e9ed" - }, - { - "in": "query", - "name": "resourceMetadata", - "description": "Return only metadata of DID-Linked Resource instead of actual DID-Linked Resource. Mutually exclusive with some of the other parameters.", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "any": { - "schema": { - "type": "object" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - } - }, - "components": { - "schemas": { - "AlsoKnownAs": { - "type": "object", - "properties": { - "alsoKnownAs": { - "type": "array", - "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", - "items": { - "type": "object", - "properties": { - "uri": { - "type": "string", - "format": "uri", - "description": "URI where the DID-Linked Resource can be fetched from. Can be any type of URI (e.g., DID, HTTPS, IPFS, etc.)" - }, - "description": { - "type": "string", - "description": "Optional description of the URI." - } - } - } - } - } - }, - "CredentialRequest": { - "description": "Input fields for the creating a Verifiable Credential.", - "type": "object", - "additionalProperties": false, - "properties": { - "issuerDid": { - "description": "DID of the Verifiable Credential issuer. This needs to be a `did:cheqd` DID.", - "type": "string", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "subjectDid": { - "description": "DID of the Verifiable Credential holder/subject. This needs to be a `did:key` DID.", - "type": "string", - "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" - }, - "attributes": { - "description": "JSON object containing the attributes to be included in the credential.", - "type": "object", - "example": { - "name": "Bob", - "gender": "male" - } - }, - "@context": { - "description": "Optional properties to be included in the `@context` property of the credential.", - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "https://schema.org/schema.jsonld", - "https://veramo.io/contexts/profile/v1" - ] - }, - "type": { - "description": "Optional properties to be included in the `type` property of the credential.", - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "Person" - ] - }, - "expirationDate": { - "description": "Optional expiration date according to the VC Data Model specification.", - "type": "string", - "format": "date-time", - "example": "2023-06-08T13:49:28.000Z" - }, - "format": { - "description": "Format of the Verifiable Credential. Defaults to VC-JWT.", - "type": "string", - "enum": [ - "jwt", - "jsonld" - ], - "example": "jwt" - }, - "credentialStatus": { - "description": "Optional `credentialStatus` properties for VC revocation or suspension. Takes `statusListName` and `statusListPurpose` as inputs.", - "type": "object", - "required": [ - "statusPurpose", - "statusListName" - ], - "properties": { - "statusPurpose": { - "type": "string", - "enum": [ - "revocation", - "suspension" - ] - }, - "statusListName": { - "type": "string" - }, - "statusListIndex": { - "type": "number" - }, - "statusListVersion": { - "type": "string", - "format": "date-time" - }, - "statusListRangeStart": { - "type": "number" - }, - "statusListRangeEnd": { - "type": "number" - }, - "indexNotIn": { - "type": "number" - } - }, - "example": { - "statusPurpose": "revocation", - "statusListName": "employee-credentials" - } - } - }, - "required": [ - "issuerDid", - "subjectDid", - "attributes" - ], - "example": { - "issuerDid": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "subjectDid": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", - "attributes": { - "gender": "male", - "name": "Bob" - }, - "@context": [ - "https://schema.org" - ], - "type": [ - "Person" - ], - "format": "jwt", - "credentialStatus": { - "statusPurpose": "revocation", - "statusListName": "employee-credentials", - "statusListIndex": 10 - } - } - }, - "Credential": { - "description": "Input fields for revoking/suspending a Verifiable Credential.", - "type": "object", - "additionalProperties": false, - "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "https://www.w3.org/2018/credentials/v1", - "https://schema.org", - "https://veramo.io/contexts/profile/v1" - ] - }, - "type": { - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "VerifiableCredential", - "Person" - ] - }, - "expirationDate": { - "type": "string", - "format": "date-time", - "example": "2023-06-08T13:49:28.000Z" - }, - "issuer": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "DID", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - } - } - }, - "credentialSubject": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "DID", - "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" - } - } - }, - "credentialStatus": { - "type": "object", - "properties": { - "id": { - "type": "string", - "example": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20" - }, - "statusListIndex": { - "type": "number", - "example": 20 - }, - "statusPurpose": { - "type": "string", - "enum": [ - "revocation", - "suspension" - ], - "example": "suspension" - }, - "type": { - "type": "string", - "enum": [ - "StatusList2021Entry" - ] - } - } - }, - "issuanceDate": { - "type": "string", - "format": "date-time", - "example": "2023-06-08T13:49:28.000Z" - }, - "proof": { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "jwt": { - "type": "string" - } - }, - "example": { - "type": "JwtProof2020", - "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg" - } - } - }, - "example": { - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://schema.org", - "https://veramo.io/contexts/profile/v1" - ], - "credentialSubject": { - "gender": "male", - "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", - "name": "Bob" - }, - "credentialStatus": { - "id": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20", - "statusIndex": 20, - "statusPurpose": "suspension", - "type": "StatusList2021Entry" - }, - "issuanceDate": "2023-06-08T13:49:28.000Z", - "issuer": { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "proof": { - "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg", - "type": "JwtProof2020" - }, - "type": [ - "VerifiableCredential", - "Person" - ] - } - }, - "CredentialRevokeRequest": { - "type": "object", - "properties": { - "credential": { - "description": "Verifiable Credential to be revoked as a VC-JWT string or a JSON object.", - "oneOf": [ - { - "type": "object" - }, - { - "type": "string" - } - ] - }, - "symmetricKey": { - "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource. Required if the StatusList2021 DID-Linked Resource is encrypted.", - "type": "string" - } - } - }, - "RevocationResult": { - "properties": { - "revoked": { - "type": "boolean", - "example": true - } - } - }, - "SuspensionResult": { - "properties": { - "suspended": { - "type": "boolean", - "example": true - } - } - }, - "UnsuspensionResult": { - "properties": { - "unsuspended": { - "type": "boolean", - "example": true - } - } - }, - "CredentialVerifyRequest": { - "type": "object", - "properties": { - "credential": { - "description": "Verifiable Credential to be verified as a VC-JWT string or a JSON object.", - "type": "object" - }, - "policies": { - "description": "Custom verification policies to execute when verifying credential.", - "type": "object", - "properties": { - "issuanceDate": { - "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "expirationDate": { - "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "audience": { - "description": "Policy to skip the audience check when set to `false`.", - "type": "boolean", - "default": false - } - } - } - } - }, - "VerifyPresentationResult": { - "type": "object", - "properties": { - "verified": { - "type": "boolean" - }, - "issuer": { - "type": "string" - }, - "signer": { - "type": "object" - }, - "jwt": { - "type": "string" - }, - "verifiableCredential": { - "type": "object" - } - } - }, - "VerifyCredentialResult": { - "type": "object", - "properties": { - "verified": { - "type": "boolean" - }, - "issuer": { - "type": "string" - }, - "signer": { - "type": "object" - }, - "jwt": { - "type": "string" - }, - "verifiableCredential": { - "type": "object" - } - }, - "example": { - "verified": true, - "polices": {}, - "issuer": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "signer": { - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", - "type": "Ed25519VerificationKey2018" - } - } - }, - "PresentationCreateRequest": { - "type": "object", - "required": [ - "credentials" - ], - "properties": { - "credentials": { - "description": "Verifiable Credentials to be used for VP-JWT creation as a VP-JWT strings or a JSON objectsf.", - "type": "array", - "items": { - "type": "object" - } - }, - "holderDid": { - "description": "DID of holder", - "type": "string" - }, - "verifierDid": { - "description": "DID of verifier", - "type": "string" - } - } - }, - "PresentationVerifyRequest": { - "type": "object", - "required": [ - "presentation" - ], - "properties": { - "presentation": { - "description": "Verifiable Presentation to be verified as a VP-JWT string or a JSON object.", - "type": "object" - }, - "verifierDid": { - "description": "Provide an optional verifier DID (also known as 'domain' parameter), if the verifier DID in the presentation is not managed in the wallet.", - "type": "string" - }, - "makeFeePayment": { - "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", - "type": "boolean", - "default": false - }, - "policies": { - "description": "Custom verification policies to execute when verifying presentation.", - "type": "object", - "properties": { - "issuanceDate": { - "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "expirationDate": { - "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "audience": { - "description": "Policy to skip the audience check when set to `false`.", - "type": "boolean", - "default": false - } - } - } - } - }, - "CredentialStatusCreateBody": { - "allOf": [ - { - "type": "object", - "required": [ - "did", - "statusListName" - ], - "properties": { - "did": { - "description": "DID of the StatusList2021 publisher.", - "type": "string", - "format": "uri" - }, - "statusListName": { - "description": "The name of the StatusList2021 DID-Linked Resource to be created.", - "type": "string" - }, - "length": { - "description": "The length of the status list to be created. The default and minimum length is 140000 which is 16kb.", - "type": "integer", - "minimum": 0, - "exclusiveMinimum": true, - "default": 140000 - }, - "encoding": { - "description": "The encoding format of the StatusList2021 DiD-Linked Resource to be created.", - "type": "string", - "default": "base64url", - "enum": [ - "base64url", - "base64", - "hex" - ] - }, - "statusListVersion": { - "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - { - "$ref": "#/components/schemas/AlsoKnownAs" - } - ] - }, - "CredentialStatusCreateUnencryptedRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCreateBody" - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials", - "length": 140000, - "encoding": "base64url" - } - }, - "CredentialStatusUnencryptedResult": { - "type": "object", - "properties": { - "resource": { - "type": "object", - "properties": { - "StatusList2021": { - "type": "object", - "properties": { - "encodedList": { - "type": "string", - "example": "H4sIAAAAAAAAA-3BAQ0AAADCoPdPbQ8HFAAAAAAAAAAAAAAAAAAAAADwaDhDr_xcRAAA" - }, - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "validFrom": { - "type": "string", - "format": "date-time", - "example": "2023-06-26T11:45:19.349Z" - } - } - }, - "metadata": { - "type": "object", - "properties": { - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "encoding": { - "type": "string", - "example": "base64url" - }, - "encrypted": { - "type": "boolean", - "example": false - } - } - } - } - }, - "resourceMetadata": { - "type": "object", - "example": { - "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceName": "cheqd-employee-credentials", - "resourceType": "StatusList2021Revocation", - "mediaType": "application/json", - "resourceVersion": "1.0.0", - "created": "2023-06-26T11:45:20Z", - "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", - "previousVersionId": null, - "nextVersionId": null - } - } - } - }, - "CredentialStatusCreateUnencryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "created": { - "type": "boolean", - "example": true - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" - } - ] - }, - "CredentialStatusEncryptedPaymentConditionsBody": { - "type": "object", - "properties": { - "feePaymentAddress": { - "description": "The cheqd/Cosmos payment address where payments to unlock the encrypted StatusList2021 DID-Linked Resource need to be sent.", - "type": "string", - "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" - }, - "feePaymentAmount": { - "description": "Amount in CHEQ tokens to unlock the encrypted StatusList2021 DID-Linked Resource.", - "type": "number", - "minimum": 0, - "exclusiveMinimum": true, - "default": 20 - }, - "feePaymentWindow": { - "description": "Time window (in minutes) within which the payment to unlock the encrypted StatusList2021 DID-Linked Resource is considered valid.", - "type": "number", - "minimum": 0, - "exclusiveMinimum": true, - "default": 10 - } - } - }, - "CredentialStatusEncryptedPaymentConditionsJson": { - "type": "object", - "properties": { - "paymentConditions": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" - } - ] - } - } - }, - "CredentialStatusCreateEncryptedFormRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCreateBody" - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" - }, - { - "type": "object", - "required": [ - "feePaymentAddress", - "feePaymentAmount", - "feePaymentWindow" - ] - } - ] - }, - "CredentialStatusCreateEncryptedJsonRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCreateBody" - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" - }, - { - "type": "object", - "required": [ - "paymentConditions" - ] - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials-encrypted", - "paymentConditions": [ - { - "feePaymentAddress": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg", - "feePaymentAmount": 20, - "feePaymentWindow": 10 - } - ] - } - }, - "CredentialStatusEncryptedResult": { - "type": "object", - "properties": { - "resource": { - "type": "object", - "properties": { - "StatusList2021": { - "type": "object", - "properties": { - "encodedList": { - "type": "string", - "example": "496fdfbeb745b4db03fcdb40566f9c4c4a1c0f184b31255e641b6e7bdfb9b6946c12be87ca3763be0393c00b67ac1e8737c106b32f46ef59c765754415b5e8cc7c65fccaa3374620430ea476301a5e0dd63340e7a27a68bc627518471f22e4a2" - }, - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "validFrom": { - "type": "string", - "format": "date-time", - "example": "2023-06-26T11:45:19.349Z" - } - } - }, - "metadata": { - "type": "object", - "properties": { - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "encoding": { - "type": "string", - "example": "base64url" - }, - "encrypted": { - "type": "boolean", - "example": true - }, - "encryptedSymmetricKey": { - "type": "string", - "example": "b11182dc524b8181f9a6aef4c4ad0a1c14e40033b9112dffd8d1bcf6cc3b85abc07ded2205ee94068a99f4202502cb0855f322583fa6ce1534d3a05bf36891766ea2c5f90a982b3040680762977d404d758a2370224a239c8279aa7d21e980931c42055b17ca4c7dbffa4782480a8b6279cf989b2f166d5fdb4b2c1b5a63927200000000000000203018dcaba26df45a415bb599218b27ca853a70289d7a3ed3ed0e3730452e8f8d9af91b6e71312565d2c069341f6660ab" - }, - "paymentConditions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "feePaymentAddress": { - "type": "string", - "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" - }, - "feePaymentAmount": { - "type": "string", - "example": "20000000000ncheq" - }, - "intervalInSeconds": { - "type": "number", - "example": 600 - }, - "type": { - "type": "string", - "example": "timelockPayment" - } - } - } - } - } - }, - "resourceMetadata": { - "type": "object", - "example": { - "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceName": "cheqd-revocation-encrypted-1", - "resourceType": "StatusList2021Revocation", - "mediaType": "application/json", - "resourceVersion": "2023-06-26T11:45:19.349Z", - "created": "2023-06-26T11:45:20Z", - "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", - "previousVersionId": null, - "nextVersionId": null - } - }, - "symmetricKey": { - "type": "string", - "example": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" - } - } - } - } - }, - "CredentialStatusCreateEncryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "created": { - "type": "boolean", - "example": true - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedResult" - } - ] - }, - "CredentialStatusUpdateBody": { - "type": "object", - "required": [ - "did", - "statusListName", - "indices" - ], - "properties": { - "did": { - "description": "DID of the StatusList2021 publisher.", - "type": "string", - "format": "uri" - }, - "statusListName": { - "description": "The name of the StatusList2021 DID-Linked Resource to be updated.", - "type": "string" - }, - "indices": { - "description": "List of credential status indices to be updated. The indices must be in the range of the status list.", - "type": "array", - "items": { - "type": "integer", - "minimum": 0, - "exclusiveMinimum": false - } - }, - "statusListVersion": { - "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - "CredentialStatusUpdateUnencryptedRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUpdateBody" - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials", - "indices": [ - 10, - 3199, - 12109, - 130999 - ] - } - }, - "CredentialStatusUpdateUnencryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "updated": { - "type": "boolean", - "example": true - } - } - }, - { - "oneOf": [ - { - "$ref": "#/components/schemas/RevocationResult" - }, - { - "$ref": "#/components/schemas/SuspensionResult" - }, - { - "$ref": "#/components/schemas/UnsuspensionResult" - } - ] - }, - { - "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" - } - ] - }, - "CredentialStatusUpdateEncryptedFormRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUpdateBody" - }, - { - "type": "object", - "required": [ - "symmetricKey" - ], - "properties": { - "symmetricKey": { - "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" - } - ] - }, - "CredentialStatusUpdateEncryptedJsonRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUpdateBody" - }, - { - "type": "object", - "required": [ - "symmetricKey" - ], - "properties": { - "symmetricKey": { - "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials-encrypted", - "indices": [ - 10, - 3199, - 12109, - 130999 - ], - "symmetricKey": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" - } - }, - "CredentialStatusUpdateEncryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "updated": { - "type": "boolean", - "example": true - } - } - }, - { - "oneOf": [ - { - "$ref": "#/components/schemas/RevocationResult" - }, - { - "$ref": "#/components/schemas/SuspensionResult" - }, - { - "$ref": "#/components/schemas/UnsuspensionResult" - } - ] - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedResult" - } - ] - }, - "CredentialStatusCheckRequest": { - "type": "object", - "required": [ - "did", - "statusListName", - "index" - ], - "properties": { - "did": { - "description": "DID of the StatusList2021 publisher.", - "type": "string", - "format": "uri" - }, - "statusListName": { - "description": "The name of the StatusList2021 DID-Linked Resource to be checked.", - "type": "string" - }, - "index": { - "description": "Credential status index to be checked for revocation or suspension.", - "type": "integer", - "minimum": 0, - "exclusiveMinimum": false - }, - "makeFeePayment": { - "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", - "type": "boolean", - "default": true - } - } - }, - "CredentialStatusCheckResult": { - "oneOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCheckRevocationResult" - }, - { - "$ref": "#/components/schemas/CredentialStatusCheckSuspensionResult" - } - ] - }, - "CredentialStatusCheckRevocationResult": { - "type": "object", - "properties": { - "checked": { - "type": "boolean", - "example": true - }, - "revoked": { - "type": "boolean", - "example": false - } - } - }, - "CredentialStatusCheckSuspensionResult": { - "type": "object", - "properties": { - "checked": { - "type": "boolean", - "example": true - }, - "suspended": { - "type": "boolean", - "example": false - } - } - }, - "CredentialStatusListSearchResult": { - "allOf": [ - { - "type": "object", - "properties": { - "found": { - "type": "boolean", - "example": true - } - } - }, - { - "oneOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedResult" - } - ] - } - ] - }, - "KeyImportRequest": { - "type": "object", - "properties": { - "alias": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "Ed25519", - "Secp256k1" - ] - }, - "privateKeyHex": { - "type": "string" - } - } - }, - "KeyResult": { - "type": "object", - "properties": { - "kid": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "Ed25519", - "Secp256k1" - ] - }, - "publicKeyHex": { - "type": "string" - } - } - }, - "DidDocument": { - "description": "This input field contains either a complete DID document, or an incremental change (diff) to a DID document. See Universal DID Registrar specification.", - "type": "object", - "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - } - }, - "id": { - "type": "string" - }, - "controllers": { - "type": "array", - "items": { - "type": "string" - } - }, - "verificationMethod": { - "type": "array", - "items": { - "$ref": "#/components/schemas/VerificationMethod" - } - }, - "service": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "authentication": { - "type": "array", - "items": { - "type": "string" - } - }, - "assertionMethod": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityInvocation": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityDelegation": { - "type": "array", - "items": { - "type": "string" - } - }, - "keyAgreement": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "@context": [ - "https://www.w3.org/ns/did/v1" - ], - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "controller": [ - "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - ], - "verificationMethod": [ - { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "type": "Ed25519VerificationKey2018", - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "publicKeyBase58": "z6MkkVbyHJLLjdjU5B62DaJ4mkdMdUkttf9UqySSkA9bVTeZ" - } - ], - "authentication": [ - "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1" - ], - "service": [ - { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", - "type": "LinkedDomains", - "serviceEndpoint": [ - "https://example.com" - ] - } - ] - } - }, - "DidDocumentWithoutVerificationMethod": { - "type": "object", - "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - } - }, - "id": { - "type": "string" - }, - "controllers": { - "type": "array", - "items": { - "type": "string" - } - }, - "service": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "authentication": { - "type": "array", - "items": { - "type": "string" - } - }, - "assertionMethod": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityInvocation": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityDelegation": { - "type": "array", - "items": { - "type": "string" - } - }, - "keyAgreement": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "@context": [ - "https://www.w3.org/ns/did/v1" - ], - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "controller": [ - "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - ], - "authentication": [ - "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1" - ], - "service": [ - { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", - "type": "LinkedDomains", - "serviceEndpoint": [ - "https://example.com" - ] - } - ] - } - }, - "DidCreateRequestFormBased": { - "type": "object", - "properties": { - "network": { - "description": "Network to create the DID on (testnet or mainnet)", - "type": "string", - "enum": [ - "testnet", - "mainnet" - ] - }, - "identifierFormatType": { - "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", - "type": "string", - "enum": [ - "uuid", - "base58btc" - ] - }, - "verificationMethodType": { - "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", - "type": "string", - "enum": [ - "Ed25519VerificationKey2018", - "JsonWebKey2020", - "Ed25519VerificationKey2020" - ] - }, - "service": { - "description": "It's a list of special objects which are designed to build the actual service. It's almost the same as in DID Core specification, but instead of `id` it utilises `idFragment` field for making the right `id` for each service. !!! WARN. Cause swagger-ui does not handle x-ww-form based arrays correctly, please frame all your services in brackets while using swagger UI. !!!", - "type": "array", - "items": { - "type": "object", - "properties": { - "idFragment": { - "type": "string" - }, - "type": { - "type": "string" - }, - "serviceEndpoint": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "example": [ - { - "idFragment": "service-1", - "type": "LinkedDomains", - "serviceEndpoint": [ - "https://example.com" - ] - } - ] - }, - "key": { - "description": "The unique identifier in hexadecimal public key format used in the verification method to create the DID.", - "type": "string" - }, - "@context": { - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "https://www.w3.org/ns/did/v1" - ] - } - } - }, - "DidCreateRequestJson": { - "type": "object", - "properties": { - "network": { - "description": "Network to create the DID on (testnet or mainnet)", - "type": "string", - "enum": [ - "testnet", - "mainnet" - ] - }, - "identifierFormatType": { - "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", - "type": "string", - "enum": [ - "uuid", - "base58btc" - ] - }, - "assertionMethod": { - "description": "Usually a reference to a Verification Method. An Assertion Method is required to issue JSON-LD credentials. See DID Core specification for more details.", - "type": "boolean", - "default": true - }, - "options": { - "type": "object", - "properties": { - "key": { - "type": "string", - "example": "8255ddadd75695e01f3d98fcec8ccc7861a030b317d4326b0e48a4d579ddc43a" - }, - "verificationMethodType": { - "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", - "type": "string", - "enum": [ - "Ed25519VerificationKey2018", - "JsonWebKey2020", - "Ed25519VerificationKey2020" - ] - } - } - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocumentWithoutVerificationMethod" - } - } - }, - "DidImportRequest": { - "type": "object", - "properties": { - "did": { - "type": "string", - "description": "DID to be imported", - "format": "uri", - "required": true - }, - "keys": { - "type": "array", - "description": "List of keys required to import the DID", - "required": true, - "items": { - "$ref": "#/components/schemas/KeyImportRequest" - } - } - } - }, - "PresentationCreateResult": { - "type": "object", - "properties": { - "vp": { - "type": "object", - "description": "Verifiable Presentation which could be provided to the verifier." - }, - "nbf": { - "type": "integer", - "description": "Unix timestamp of the earliest time that the Verifiable Presentation is valid." - }, - "iss": { - "type": "string", - "description": "DID of the issuer of the Verifiable Presentation. (Here it's supposed to be a holder DID)" - }, - "aud": { - "type": "array", - "items": { - "type": "string" - }, - "description": "DID of the verifier of the Verifiable Presentation." - } - }, - "example": { - "vp": { - "@context": [ - "https://www.w3.org/2018/credentials/v1" - ], - "type": [ - "VerifiablePresentation" - ], - "verifiableCredential": [ - "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc2NoZW1hLm9yZy9zY2hlbWEuanNvbmxkIiwiaHR0cHM6Ly92ZXJhbW8uaW8vY29udGV4dHMvcHJvZmlsZS92MSIsImh0dHBzOi8vdzNpZC5vcmcvdmMtc3RhdHVzLWxpc3QtMjAyMS92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiUGVyc29uIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7Im5hbWUiOiJCb2IiLCJnZW5kZXIiOiJtYWxlIn0sImNyZWRlbnRpYWxTdGF0dXMiOnsiaWQiOiJodHRwczovL3Jlc29sdmVyLmNoZXFkLm5ldC8xLjAvaWRlbnRpZmllcnMvZGlkOmNoZXFkOnRlc3RuZXQ6OTBkNWMxNDEtNzI0Zi00N2FkLTlhZTctYTdjMzNhOWU1NjQzP3Jlc291cmNlTmFtZT1zdXNwZW5zaW9uRW4mcmVzb3VyY2VUeXBlPVN0YXR1c0xpc3QyMDIxU3VzcGVuc2lvbiMxMzMzOCIsInR5cGUiOiJTdGF0dXNMaXN0MjAyMUVudHJ5Iiwic3RhdHVzUHVycG9zZSI6InN1c3BlbnNpb24iLCJzdGF0dXNMaXN0SW5kZXgiOiIxMzMzOCJ9fSwic3ViIjoiZGlkOmtleTp6Nk1raGFYZ0JaRHZvdERrTDUyNTdmYWl6dGlHaUMyUXRLTEdwYm5uRUd0YTJkb0siLCJuYmYiOjE3MDA0NzM0MTYsImlzcyI6ImRpZDpjaGVxZDp0ZXN0bmV0OjkwZDVjMTQxLTcyNGYtNDdhZC05YWU3LWE3YzMzYTllNTY0MyJ9.-14Ril1pZEy2HEEo48gTJr2yOtGxBhUGTFmzVdjAtyhFRsW5zZg9onHt6V9JQ8BaiYBlTkP9GzTnJ-O6hdiyCw" - ] - }, - "nbf": 1700744275, - "iss": "did:cheqd:testnet:4b846d0f-2f6c-4ab6-9fe2-5b8db301c83c", - "aud": [ - "did:cheqd:testnet:8c71e9b6-c5a3-4250-8c58-fa591533cd22" - ] - } - }, - "DidResult": { - "type": "object", - "properties": { - "did": { - "type": "string" - }, - "controllerKeyId": { - "type": "string" - }, - "keys": { - "type": "array", - "items": { - "type": "object" - } - }, - "services": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - } - } - }, - "DidUpdateResponse": { - "type": "object", - "properties": { - "did": { - "type": "string" - }, - "controllerKeyId": { - "type": "string", - "description": "The default key id of which is the key associated with the first verificationMethod" - }, - "keys": { - "type": "array", - "description": "The list of keys associated with the list of verificationMethod's of DIDDocument", - "items": { - "type": "object" - } - }, - "services": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "controllerKeyRefs": { - "type": "array", - "description": "The list of keyRefs which were used for signing the transaction", - "items": { - "type": "string" - } - }, - "controllerKeys": { - "type": "array", - "description": "The list of all possible keys, inlcuding all controller's keys", - "items": { - "type": "string" - } - } - } - }, - "VerificationMethod": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string" - }, - "controller": { - "type": "string" - }, - "publicKeyMultibase": { - "type": "string" - }, - "publicKeyJwk": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "id": "did:cheqd:testnet :7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", - "type": "Ed25519VerificationKey2018" - } - }, - "Service": { - "description": "Communicating or interacting with the DID subject or associated entities via one or more service endpoints. See DID Core specification for more details.", - "type": "object", - "properties": { - "id": { - "description": "DID appended with Service fragment ID (e.g., `#service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`)", - "type": "string", - "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1" - }, - "type": { - "description": "Service type as defined in DID Specification Registries.", - "type": "string", - "example": "LinkedDomains" - }, - "serviceEndpoint": { - "description": "Service endpoint as defined in DID Core Specification.", - "type": "array", - "items": { - "type": "string", - "example": "https://example.com" - } - } - } - }, - "DidUpdateRequest": { - "type": "object", - "properties": { - "did": { - "description": "DID identifier to be updated.", - "type": "string", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "service": { - "type": "array", - "description": "Service section of the DID Document.", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "verificationMethod": { - "type": "array", - "description": "Verification Method section of the DID Document.", - "items": { - "$ref": "#/components/schemas/VerificationMethod" - } - }, - "authentication": { - "description": "Authentication section of the DID Document.", - "type": "array", - "items": { - "type": "string" - } - }, - "publicKeyHexs": { - "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", - "type": "array", - "items": { - "type": "string" - } - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - } - } - }, - "DidDeactivateRequest": { - "type": "object", - "properties": { - "publicKeyHexs": { - "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "CreateResourceRequest": { - "description": "Input fields for DID-Linked Resource creation.", - "type": "object", - "additionalProperties": false, - "required": [ - "name", - "type", - "data", - "encoding" - ], - "properties": { - "data": { - "description": "Encoded string containing the data to be stored in the DID-Linked Resource.", - "type": "string" - }, - "encoding": { - "description": "Encoding format used to encode the data.", - "type": "string", - "enum": [ - "base64url", - "base64", - "hex" - ] - }, - "name": { - "description": "Name of DID-Linked Resource.", - "type": "string" - }, - "type": { - "description": "Type of DID-Linked Resource. This is NOT the same as the media type, which is calculated automatically ledger-side.", - "type": "string" - }, - "alsoKnownAs": { - "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", - "type": "array", - "items": { - "type": "object", - "properties": { - "uri": { - "type": "string" - }, - "description": { - "type": "string" - } - } - } - }, - "version": { - "description": "Optional field to assign a human-readable version in the DID-Linked Resource.", - "type": "string" - }, - "publicKeyHexs": { - "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "data": "SGVsbG8gV29ybGQ=", - "encoding": "base64url", - "name": "ResourceName", - "type": "TextDocument" - } - }, - "ResourceList": { - "type": "object", - "properties": { - "@context": { - "type": "string", - "example": "https://w3id.org/did-resolution/v1" - }, - "contentMetadata": { - "type": "object" - }, - "contentStream": { - "type": "object" - }, - "dereferencingMetadata": { - "$ref": "#/components/schemas/DereferencingMetadata" - } - } - }, - "DereferencingMetadata": { - "type": "object", - "properties": { - "contentType": { - "type": "string", - "example": "application/did+ld+json" - }, - "did": { - "$ref": "#/components/schemas/DidProperties" - }, - "retrieved": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - } - } - }, - "DidResolution": { - "type": "object", - "properties": { - "@context": { - "type": "string", - "example": "https://w3id.org/did-resolution/v1" - }, - "didDidResolutionMetadata": { - "$ref": "#/components/schemas/DidResolutionMetadata" - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - }, - "didDocumentMetadata": { - "$ref": "#/components/schemas/DidDocumentMetadata" - } - } - }, - "DeactivatedDidResolution": { - "type": "object", - "properties": { - "@context": { - "type": "string", - "example": "https://w3id.org/did-resolution/v1" - }, - "didDidResolutionMetadata": { - "$ref": "#/components/schemas/DidResolutionMetadata" - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - }, - "didDocumentMetadata": { - "$ref": "#/components/schemas/DeactivatedDidDocumentMetadata" - } - } - }, - "DidDocumentMetadata": { - "type": "object", - "properties": { - "created": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "deactivated": { - "type": "boolean", - "example": false - }, - "updated": { - "type": "string", - "example": "2021-09-10T12:00:00Z" - }, - "versionId": { - "type": "string", - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - "linkedResourceMetadata": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ResourceMetadata" - } - } - } - }, - "DeactivatedDidDocumentMetadata": { - "type": "object", - "properties": { - "created": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "deactivated": { - "type": "boolean", - "example": true - }, - "updated": { - "type": "string", - "example": "2021-09-10T12:00:00Z" - }, - "versionId": { - "type": "string", - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - "linkedResourceMetadata": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ResourceMetadata" - } - } - } - }, - "ResourceMetadata": { - "type": "object", - "properties": { - "resourceURI": { - "type": "string", - "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47/resources/398cee0a-efac-4643-9f4c-74c48c72a14b" - }, - "resourceCollectionId": { - "type": "string", - "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" - }, - "resourceId": { - "type": "string", - "example": "398cee0a-efac-4643-9f4c-74c48c72a14b" - }, - "resourceName": { - "type": "string", - "example": "cheqd-issuer-logo" - }, - "resourceType": { - "type": "string", - "example": "CredentialArtwork" - }, - "mediaType": { - "type": "string", - "example": "image/png" - }, - "resourceVersion": { - "type": "string", - "example": "1.0" - }, - "checksum": { - "type": "string", - "example": "a95380f460e63ad939541a57aecbfd795fcd37c6d78ee86c885340e33a91b559" - }, - "created": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "nextVersionId": { - "type": "string", - "example": "d4829ac7-4566-478c-a408-b44767eddadc" - }, - "previousVersionId": { - "type": "string", - "example": "ad7a8442-3531-46eb-a024-53953ec6e4ff" - } - } - }, - "DidResolutionMetadata": { - "type": "object", - "properties": { - "contentType": { - "allOf": [ - { - "$ref": "#/components/schemas/ContentType" - } - ], - "example": "application/did+ld+json" - }, - "retrieved": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "did": { - "$ref": "#/components/schemas/DidProperties" - } - } - }, - "ContentType": { - "type": "string", - "enum": [ - "application/did+json", - "application/did+ld+json", - "application/ld+json", - "application/json" - ] - }, - "DidProperties": { - "type": "object", - "properties": { - "didString": { - "type": "string", - "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" - }, - "method": { - "type": "string", - "example": "cheqd" - }, - "methodSpecificId": { - "type": "string", - "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" - } - } - }, - "Customer": { - "type": "object", - "properties": { - "customerId": { - "type": "string", - "example": "6w5drpiiwhhs" - }, - "address": { - "type": "string", - "example": "cheqd1wgsvqwlkmdp60f4dek26ak0sjw6au3ytd3pz7f" - } - } - }, - "AccountCreateRequest": { - "type": "object", - "properties": { - "user": { - "type": "object", - "properties": { - "primaryEmail": { - "type": "string" - } - } - } - } - }, - "InvalidRequest": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "InvalidRequest" - } - } - }, - "InternalError": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Internal Error" - } - } - }, - "UnauthorizedError": { - "description": "Access token is missing or invalid", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Unauthorized Error" - } - } - } - } - } + "openapi": "3.0.0", + "info": { + "title": "Credential Service API for cheqd network", + "version": "2.0.0", + "description": "API service to create and manage DIDs, Verifiable Credentials, and DID-Linked Resources", + "contact": { + "name": "Cheqd Foundation Limited", + "url": "https://github.com/cheqd/credential-service", + "email": "support-github@cheqd.io" + }, + "license": { + "name": "Apache 2.0", + "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" + } + }, + "tags": [ + { + "name": "Account" + }, + { + "name": "Key" + }, + { + "name": "DID" + }, + { + "name": "Resource" + }, + { + "name": "Credential" + }, + { + "name": "Presentation" + }, + { + "name": "Credential Status" + } + ], + "externalDocs": { + "description": "Credential Service API Documentation", + "url": "https://docs.cheqd.io/identity" + }, + "paths": { + "/account": { + "get": { + "tags": ["Account"], + "summary": "Fetch custodian-mode client details.", + "description": "This endpoint returns the custodian-mode client details for authenticated users.", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Customer" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/account/idtoken": { + "get": { + "tags": ["Account"], + "summary": "Fetch IdToken.", + "description": "This endpoint returns IdToken as JWT with list of user roles inside", + "deprecated": true, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "idToken": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/account/create": { + "post": { + "tags": ["Account"], + "summary": "Create an client for an authenticated user.", + "description": "This endpoint creates a client in the custodian-mode for an authenticated user", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/AccountCreateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "idToken": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/create/unencrypted": { + "post": { + "tags": ["Credential Status"], + "summary": "Create an unencrypted StatusList2021 credential status list.", + "description": "This endpoint creates an unencrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", + "required": true, + "schema": { + "type": "string", + "enum": ["revocation", "suspension"] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/create/encrypted": { + "post": { + "tags": ["Credential Status"], + "summary": "Create an encrypted StatusList2021 credential status list.", + "description": "This endpoint creates an encrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", + "required": true, + "schema": { + "type": "string", + "enum": ["revocation", "suspension"] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateEncryptedFormRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateEncryptedJsonRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateEncryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/update/unencrypted": { + "post": { + "tags": ["Credential Status"], + "summary": "Update an existing unencrypted StatusList2021 credential status list.", + "parameters": [ + { + "in": "query", + "name": "statusAction", + "description": "The update action to be performed on the unencrypted status list, can be revoke, suspend or reinstate", + "required": true, + "schema": { + "type": "string", + "enum": ["revoke", "suspend", "reinstate"] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/update/encrypted": { + "post": { + "tags": ["Credential Status"], + "summary": "Update an existing encrypted StatusList2021 credential status list.", + "parameters": [ + { + "in": "query", + "name": "statusAction", + "description": "The update action to be performed on the encrypted status list, can be revoke, suspend or reinstate", + "required": true, + "schema": { + "type": "string", + "enum": ["revoke", "suspend", "reinstate"] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedFormRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedJsonRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/check": { + "post": { + "tags": ["Credential Status"], + "summary": "Check a StatusList2021 index for a given Verifiable Credential.", + "description": "This endpoint checks a StatusList2021 index for a given Verifiable Credential and reports whether it is revoked or suspended. It offers a standalone method for checking an index without passing the entire Verifiable Credential or Verifiable Presentation.", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension.", + "required": true, + "schema": { + "type": "string", + "enum": ["revocation", "suspension"] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCheckRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCheckRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCheckResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/search": { + "get": { + "tags": ["Credential Status"], + "summary": "Fetch StatusList2021 DID-Linked Resource based on search criteria.", + "parameters": [ + { + "in": "query", + "name": "did", + "description": "The DID of the issuer of the status list.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension.", + "schema": { + "type": "string", + "enum": ["revocation", "suspension"] + } + }, + { + "in": "query", + "name": "statusListName", + "description": "The name of the StatusList2021 DID-Linked Resource.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusListSearchResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/issue": { + "post": { + "tags": ["Credential"], + "summary": "Issue a Verifiable Credential", + "description": "This endpoint issues a Verifiable Credential. As input it takes the list of issuerDid, subjectDid, attributes, and other parameters of the credential to be issued.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Credential" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/verify": { + "post": { + "tags": ["Credential"], + "summary": "Verify a Verifiable Credential.", + "description": "This endpoint verifies a Verifiable Credential passed to it. As input, it can take the VC-JWT as a string or the entire credential itself.", + "operationId": "verify", + "parameters": [ + { + "in": "query", + "name": "verifyStatus", + "description": "If set to `true` the verification will also check the status of the credential. Requires the VC to have a `credentialStatus` property.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "fetchRemoteContexts", + "description": "When dealing with JSON-LD you also MUST provide the proper contexts. Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "allowDeactivatedDid", + "description": "If set to `true` allow to verify credential which based on deactivated DID.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialVerifyRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialVerifyRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyCredentialResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/revoke": { + "post": { + "tags": ["Credential"], + "summary": "Revoke a Verifiable Credential.", + "description": "This endpoint revokes a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself. The StatusList2021 resource should already be setup in the VC and `credentialStatus` property present in the VC.", + "operationId": "revoke", + "parameters": [ + { + "in": "query", + "name": "publish", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RevocationResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/suspend": { + "post": { + "tags": ["Credential"], + "summary": "Suspend a Verifiable Credential.", + "description": "This endpoint suspends a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself.", + "operationId": "suspend", + "parameters": [ + { + "in": "query", + "name": "publish", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuspensionResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/reinstate": { + "post": { + "tags": ["Credential"], + "summary": "Reinstate a suspended Verifiable Credential.", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "operationId": "reinstate", + "parameters": [ + { + "in": "query", + "name": "publish", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnsuspensionResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/create": { + "post": { + "tags": ["DID"], + "summary": "Create a DID Document.", + "description": "This endpoint creates a DID and associated DID Document. As input, it can take the DID Document parameters via a form, or the fully-assembled DID Document itself.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidCreateRequestFormBased" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidCreateRequestJson" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/did/update": { + "post": { + "tags": ["DID"], + "summary": "Update a DID Document.", + "description": "This endpoint updates a DID Document. As an input, it can take JUST the sections/parameters that need to be updated in the DID Document (in this scenario, it fetches the current DID Document and applies the updated section). Alternatively, it take the fully-assembled DID Document with updated sections as well as unchanged sections.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidUpdateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidUpdateResponse" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/import": { + "post": { + "tags": ["DID"], + "summary": "Import a DID Document.", + "description": "This endpoint imports a decentralized identifier associated with the user's account for custodian-mode clients.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidImportRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidImportRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/did/deactivate/{did}": { + "post": { + "tags": ["DID"], + "summary": "Deactivate a DID Document.", + "description": "This endpoint deactivates a DID Document by taking the DID identifier as input. Must be called and signed by the DID owner.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier to deactivate.", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidDeactivateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidDeactivateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeactivatedDidResolution" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/list": { + "get": { + "tags": ["DID"], + "summary": "Fetch DIDs associated with an account.", + "description": "This endpoint returns the list of DIDs controlled by the account.", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/search/{did}": { + "get": { + "tags": ["DID"], + "summary": "Resolve a DID Document.", + "description": "Resolve a DID Document by DID identifier. Also supports DID Resolution Queries as defined in the W3C DID Resolution specification.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier to resolve.", + "schema": { + "type": "string" + }, + "required": true, + "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + { + "in": "query", + "name": "metadata", + "description": "Return only metadata of DID Document instead of actual DID Document.", + "schema": { + "type": "boolean" + } + }, + { + "in": "query", + "name": "versionId", + "description": "Unique UUID version identifier of DID Document. Allows for fetching a specific version of the DID Document. See cheqd DID Method Specification for more details.", + "schema": { + "type": "string", + "format": "uuid" + }, + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + { + "in": "query", + "name": "versionTime", + "description": "Returns the closest version of the DID Document *at* or *before* specified time. See DID Resolution handling for `did:cheqd` for more details.", + "schema": { + "type": "string", + "format": "date-time" + }, + "example": "1970-01-01T00:00:00Z" + }, + { + "in": "query", + "name": "transformKeys", + "description": "This directive transforms the Verification Method key format from the version in the DID Document to the specified format chosen below.", + "schema": { + "type": "string", + "enum": ["Ed25519VerificationKey2018", "Ed25519VerificationKey2020", "JsonWebKey2020"] + } + }, + { + "in": "query", + "name": "service", + "description": "Query DID Document for a specific Service Endpoint by Service ID (e.g., `service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`). This will typically redirect to the Service Endpoint based on DID Resolution specification algorithm.", + "schema": { + "type": "string" + }, + "example": "service-1" + }, + { + "in": "query", + "name": "relativeRef", + "description": "Relative reference is a query fragment appended to the Service Endpoint URL. **Must** be used along with the `service` query property above. See DID Resolution specification algorithm for more details.", + "schema": { + "type": "string" + }, + "example": "/path/to/file" + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResolution" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/key/create": { + "post": { + "tags": ["Key"], + "summary": "Create an identity key pair.", + "description": "This endpoint creates an identity key pair associated with the user's account for custodian-mode clients.", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/key/import": { + "post": { + "tags": ["Key"], + "summary": "Import an identity key pair.", + "description": "This endpoint imports an identity key pair associated with the user's account for custodian-mode clients.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/KeyImportRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyImportRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/key/read/{kid}": { + "get": { + "tags": ["Key"], + "summary": "Fetch an identity key pair.", + "description": "This endpoint fetches an identity key pair's details for a given key ID. Only the user account associated with the custodian-mode client can fetch the key pair.", + "parameters": [ + { + "name": "kid", + "description": "Key ID of the identity key pair to fetch.", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/presentation/create": { + "post": { + "tags": ["Presentation"], + "summary": "!!! WARN. Such endpoint is made mostly for testing purposes and it is not supposed to be used in production !!! Create a Verifiable Presentation from credential(s).", + "description": "This endpoint creates a Verifiable Presentation from credential(s). As input, it can take the credential(s) as a string or the entire credential(s) itself. \n !!! WARN. Such endpoint is made only for testing purposes !!!", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/PresentationCreateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationCreateResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/presentation/verify": { + "post": { + "tags": ["Presentation"], + "summary": "Verify a Verifiable Presentation generated from credential(s).", + "description": "This endpoint verifies the Verifiable Presentation generated from credential(s). As input, it can take the Verifiable Presentation JWT as a string or the entire Verifiable Presentation itself.", + "parameters": [ + { + "in": "query", + "name": "verifyStatus", + "description": "If set to `true` the verification will also check the status of the presentation. Requires the VP to have a `credentialStatus` property.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "fetchRemoteContexts", + "description": "When dealing with JSON-LD you also MUST provide the proper contexts. * Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "allowDeactivatedDid", + "description": "If set to `true` allow to verify credential which based on deactivated DID.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/PresentationVerifyRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationVerifyRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyPresentationResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/resource/create/{did}": { + "post": { + "tags": ["Resource"], + "summary": "Create a DID-Linked Resource.", + "description": "This endpoint creates a DID-Linked Resource. As input, it can take the DID identifier and the resource parameters via a form, or the fully-assembled resource itself.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier to link the resource to.", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CreateResourceRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateResourceRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceMetadata" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/resource/search/{did}": { + "get": { + "tags": ["Resource"], + "summary": "Get a DID-Linked Resource.", + "description": "This endpoint returns the DID-Linked Resource for a given DID identifier and resource identifier.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier", + "schema": { + "type": "string" + }, + "required": true, + "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + { + "in": "query", + "name": "resourceId", + "description": "Fetch a DID-Linked Resource by Resource ID unique identifier. Since this is a unique identifier, other Resource query parameters are not required. See DID-Linked Resources for more details.", + "schema": { + "type": "string", + "format": "uuid" + }, + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + { + "in": "query", + "name": "resourceName", + "description": "Filter a DID-Linked Resource query by Resource Name. See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "cheqd-issuer-logo" + }, + { + "in": "query", + "name": "resourceType", + "description": "Filter a DID-Linked Resource query by Resource Type. See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "CredentialArtwork" + }, + { + "in": "query", + "name": "resourceVersion", + "description": "Filter a DID-Linked Resource query by Resource Version, which is an optional free-text field used by issuers (e.g., \"v1\", \"Final Version\", \"1st January 1970\" etc). See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "v1" + }, + { + "in": "query", + "name": "resourceVersionTime", + "description": "Filter a DID-Linked Resource query which returns the closest version of the Resource *at* or *before* specified time. See DID-Linked Resources for more details.", + "schema": { + "type": "string", + "format": "date-time" + }, + "example": "1970-01-01T00:00:00Z" + }, + { + "in": "query", + "name": "checksum", + "description": "Request integrity check against a given DID-Linked Resource by providing a SHA-256 checksum hash. See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "dc64474d062ed750a66bad58cb609928de55ed0d81defd231a4a4bf97358e9ed" + }, + { + "in": "query", + "name": "resourceMetadata", + "description": "Return only metadata of DID-Linked Resource instead of actual DID-Linked Resource. Mutually exclusive with some of the other parameters.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "any": { + "schema": { + "type": "object" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + } + }, + "components": { + "schemas": { + "AlsoKnownAs": { + "type": "object", + "properties": { + "alsoKnownAs": { + "type": "array", + "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", + "items": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "format": "uri", + "description": "URI where the DID-Linked Resource can be fetched from. Can be any type of URI (e.g., DID, HTTPS, IPFS, etc.)" + }, + "description": { + "type": "string", + "description": "Optional description of the URI." + } + } + } + } + } + }, + "CredentialRequest": { + "description": "Input fields for the creating a Verifiable Credential.", + "type": "object", + "additionalProperties": false, + "properties": { + "issuerDid": { + "description": "DID of the Verifiable Credential issuer. This needs to be a `did:cheqd` DID.", + "type": "string", + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + "subjectDid": { + "description": "DID of the Verifiable Credential holder/subject. This needs to be a `did:key` DID.", + "type": "string", + "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" + }, + "attributes": { + "description": "JSON object containing the attributes to be included in the credential.", + "type": "object", + "example": { + "name": "Bob", + "gender": "male" + } + }, + "@context": { + "description": "Optional properties to be included in the `@context` property of the credential.", + "type": "array", + "items": { + "type": "string" + }, + "example": ["https://schema.org/schema.jsonld", "https://veramo.io/contexts/profile/v1"] + }, + "type": { + "description": "Optional properties to be included in the `type` property of the credential.", + "type": "array", + "items": { + "type": "string" + }, + "example": ["Person"] + }, + "expirationDate": { + "description": "Optional expiration date according to the VC Data Model specification.", + "type": "string", + "format": "date-time", + "example": "2023-06-08T13:49:28.000Z" + }, + "format": { + "description": "Format of the Verifiable Credential. Defaults to VC-JWT.", + "type": "string", + "enum": ["jwt", "jsonld"], + "example": "jwt" + }, + "credentialStatus": { + "description": "Optional `credentialStatus` properties for VC revocation or suspension. Takes `statusListName` and `statusListPurpose` as inputs.", + "type": "object", + "required": ["statusPurpose", "statusListName"], + "properties": { + "statusPurpose": { + "type": "string", + "enum": ["revocation", "suspension"] + }, + "statusListName": { + "type": "string" + }, + "statusListIndex": { + "type": "number" + }, + "statusListVersion": { + "type": "string", + "format": "date-time" + }, + "statusListRangeStart": { + "type": "number" + }, + "statusListRangeEnd": { + "type": "number" + }, + "indexNotIn": { + "type": "number" + } + }, + "example": { + "statusPurpose": "revocation", + "statusListName": "employee-credentials" + } + } + }, + "required": ["issuerDid", "subjectDid", "attributes"], + "example": { + "issuerDid": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "subjectDid": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", + "attributes": { + "gender": "male", + "name": "Bob" + }, + "@context": ["https://schema.org"], + "type": ["Person"], + "format": "jwt", + "credentialStatus": { + "statusPurpose": "revocation", + "statusListName": "employee-credentials", + "statusListIndex": 10 + } + } + }, + "Credential": { + "description": "Input fields for revoking/suspending a Verifiable Credential.", + "type": "object", + "additionalProperties": false, + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "https://www.w3.org/2018/credentials/v1", + "https://schema.org", + "https://veramo.io/contexts/profile/v1" + ] + }, + "type": { + "type": "array", + "items": { + "type": "string" + }, + "example": ["VerifiableCredential", "Person"] + }, + "expirationDate": { + "type": "string", + "format": "date-time", + "example": "2023-06-08T13:49:28.000Z" + }, + "issuer": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "DID", + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + } + } + }, + "credentialSubject": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "DID", + "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" + } + } + }, + "credentialStatus": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20" + }, + "statusListIndex": { + "type": "number", + "example": 20 + }, + "statusPurpose": { + "type": "string", + "enum": ["revocation", "suspension"], + "example": "suspension" + }, + "type": { + "type": "string", + "enum": ["StatusList2021Entry"] + } + } + }, + "issuanceDate": { + "type": "string", + "format": "date-time", + "example": "2023-06-08T13:49:28.000Z" + }, + "proof": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "jwt": { + "type": "string" + } + }, + "example": { + "type": "JwtProof2020", + "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg" + } + } + }, + "example": { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://schema.org", + "https://veramo.io/contexts/profile/v1" + ], + "credentialSubject": { + "gender": "male", + "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", + "name": "Bob" + }, + "credentialStatus": { + "id": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20", + "statusIndex": 20, + "statusPurpose": "suspension", + "type": "StatusList2021Entry" + }, + "issuanceDate": "2023-06-08T13:49:28.000Z", + "issuer": { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + "proof": { + "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg", + "type": "JwtProof2020" + }, + "type": ["VerifiableCredential", "Person"] + } + }, + "CredentialRevokeRequest": { + "type": "object", + "properties": { + "credential": { + "description": "Verifiable Credential to be revoked as a VC-JWT string or a JSON object.", + "oneOf": [ + { + "type": "object" + }, + { + "type": "string" + } + ] + }, + "symmetricKey": { + "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource. Required if the StatusList2021 DID-Linked Resource is encrypted.", + "type": "string" + } + } + }, + "RevocationResult": { + "properties": { + "revoked": { + "type": "boolean", + "example": true + } + } + }, + "SuspensionResult": { + "properties": { + "suspended": { + "type": "boolean", + "example": true + } + } + }, + "UnsuspensionResult": { + "properties": { + "unsuspended": { + "type": "boolean", + "example": true + } + } + }, + "CredentialVerifyRequest": { + "type": "object", + "properties": { + "credential": { + "description": "Verifiable Credential to be verified as a VC-JWT string or a JSON object.", + "type": "object" + }, + "policies": { + "description": "Custom verification policies to execute when verifying credential.", + "type": "object", + "properties": { + "issuanceDate": { + "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "expirationDate": { + "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "audience": { + "description": "Policy to skip the audience check when set to `false`.", + "type": "boolean", + "default": false + } + } + } + } + }, + "VerifyPresentationResult": { + "type": "object", + "properties": { + "verified": { + "type": "boolean" + }, + "issuer": { + "type": "string" + }, + "signer": { + "type": "object" + }, + "jwt": { + "type": "string" + }, + "verifiableCredential": { + "type": "object" + } + } + }, + "VerifyCredentialResult": { + "type": "object", + "properties": { + "verified": { + "type": "boolean" + }, + "issuer": { + "type": "string" + }, + "signer": { + "type": "object" + }, + "jwt": { + "type": "string" + }, + "verifiableCredential": { + "type": "object" + } + }, + "example": { + "verified": true, + "polices": {}, + "issuer": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "signer": { + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", + "type": "Ed25519VerificationKey2018" + } + } + }, + "PresentationCreateRequest": { + "type": "object", + "required": ["credentials"], + "properties": { + "credentials": { + "description": "Verifiable Credentials to be used for VP-JWT creation as a VP-JWT strings or a JSON objectsf.", + "type": "array", + "items": { + "type": "object" + } + }, + "holderDid": { + "description": "DID of holder", + "type": "string" + }, + "verifierDid": { + "description": "DID of verifier", + "type": "string" + } + } + }, + "PresentationVerifyRequest": { + "type": "object", + "required": ["presentation"], + "properties": { + "presentation": { + "description": "Verifiable Presentation to be verified as a VP-JWT string or a JSON object.", + "type": "object" + }, + "verifierDid": { + "description": "Provide an optional verifier DID (also known as 'domain' parameter), if the verifier DID in the presentation is not managed in the wallet.", + "type": "string" + }, + "makeFeePayment": { + "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", + "type": "boolean", + "default": false + }, + "policies": { + "description": "Custom verification policies to execute when verifying presentation.", + "type": "object", + "properties": { + "issuanceDate": { + "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "expirationDate": { + "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "audience": { + "description": "Policy to skip the audience check when set to `false`.", + "type": "boolean", + "default": false + } + } + } + } + }, + "CredentialStatusCreateBody": { + "allOf": [ + { + "type": "object", + "required": ["did", "statusListName"], + "properties": { + "did": { + "description": "DID of the StatusList2021 publisher.", + "type": "string", + "format": "uri" + }, + "statusListName": { + "description": "The name of the StatusList2021 DID-Linked Resource to be created.", + "type": "string" + }, + "length": { + "description": "The length of the status list to be created. The default and minimum length is 140000 which is 16kb.", + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true, + "default": 140000 + }, + "encoding": { + "description": "The encoding format of the StatusList2021 DiD-Linked Resource to be created.", + "type": "string", + "default": "base64url", + "enum": ["base64url", "base64", "hex"] + }, + "statusListVersion": { + "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/AlsoKnownAs" + } + ] + }, + "CredentialStatusCreateUnencryptedRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCreateBody" + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials", + "length": 140000, + "encoding": "base64url" + } + }, + "CredentialStatusUnencryptedResult": { + "type": "object", + "properties": { + "resource": { + "type": "object", + "properties": { + "StatusList2021": { + "type": "object", + "properties": { + "encodedList": { + "type": "string", + "example": "H4sIAAAAAAAAA-3BAQ0AAADCoPdPbQ8HFAAAAAAAAAAAAAAAAAAAAADwaDhDr_xcRAAA" + }, + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "validFrom": { + "type": "string", + "format": "date-time", + "example": "2023-06-26T11:45:19.349Z" + } + } + }, + "metadata": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "encoding": { + "type": "string", + "example": "base64url" + }, + "encrypted": { + "type": "boolean", + "example": false + } + } + } + } + }, + "resourceMetadata": { + "type": "object", + "example": { + "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceName": "cheqd-employee-credentials", + "resourceType": "StatusList2021Revocation", + "mediaType": "application/json", + "resourceVersion": "1.0.0", + "created": "2023-06-26T11:45:20Z", + "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", + "previousVersionId": null, + "nextVersionId": null + } + } + } + }, + "CredentialStatusCreateUnencryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "created": { + "type": "boolean", + "example": true + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" + } + ] + }, + "CredentialStatusEncryptedPaymentConditionsBody": { + "type": "object", + "properties": { + "feePaymentAddress": { + "description": "The cheqd/Cosmos payment address where payments to unlock the encrypted StatusList2021 DID-Linked Resource need to be sent.", + "type": "string", + "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" + }, + "feePaymentAmount": { + "description": "Amount in CHEQ tokens to unlock the encrypted StatusList2021 DID-Linked Resource.", + "type": "number", + "minimum": 0, + "exclusiveMinimum": true, + "default": 20 + }, + "feePaymentWindow": { + "description": "Time window (in minutes) within which the payment to unlock the encrypted StatusList2021 DID-Linked Resource is considered valid.", + "type": "number", + "minimum": 0, + "exclusiveMinimum": true, + "default": 10 + } + } + }, + "CredentialStatusEncryptedPaymentConditionsJson": { + "type": "object", + "properties": { + "paymentConditions": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" + } + ] + } + } + }, + "CredentialStatusCreateEncryptedFormRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCreateBody" + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" + }, + { + "type": "object", + "required": ["feePaymentAddress", "feePaymentAmount", "feePaymentWindow"] + } + ] + }, + "CredentialStatusCreateEncryptedJsonRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCreateBody" + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" + }, + { + "type": "object", + "required": ["paymentConditions"] + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials-encrypted", + "paymentConditions": [ + { + "feePaymentAddress": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg", + "feePaymentAmount": 20, + "feePaymentWindow": 10 + } + ] + } + }, + "CredentialStatusEncryptedResult": { + "type": "object", + "properties": { + "resource": { + "type": "object", + "properties": { + "StatusList2021": { + "type": "object", + "properties": { + "encodedList": { + "type": "string", + "example": "496fdfbeb745b4db03fcdb40566f9c4c4a1c0f184b31255e641b6e7bdfb9b6946c12be87ca3763be0393c00b67ac1e8737c106b32f46ef59c765754415b5e8cc7c65fccaa3374620430ea476301a5e0dd63340e7a27a68bc627518471f22e4a2" + }, + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "validFrom": { + "type": "string", + "format": "date-time", + "example": "2023-06-26T11:45:19.349Z" + } + } + }, + "metadata": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "encoding": { + "type": "string", + "example": "base64url" + }, + "encrypted": { + "type": "boolean", + "example": true + }, + "encryptedSymmetricKey": { + "type": "string", + "example": "b11182dc524b8181f9a6aef4c4ad0a1c14e40033b9112dffd8d1bcf6cc3b85abc07ded2205ee94068a99f4202502cb0855f322583fa6ce1534d3a05bf36891766ea2c5f90a982b3040680762977d404d758a2370224a239c8279aa7d21e980931c42055b17ca4c7dbffa4782480a8b6279cf989b2f166d5fdb4b2c1b5a63927200000000000000203018dcaba26df45a415bb599218b27ca853a70289d7a3ed3ed0e3730452e8f8d9af91b6e71312565d2c069341f6660ab" + }, + "paymentConditions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "feePaymentAddress": { + "type": "string", + "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" + }, + "feePaymentAmount": { + "type": "string", + "example": "20000000000ncheq" + }, + "intervalInSeconds": { + "type": "number", + "example": 600 + }, + "type": { + "type": "string", + "example": "timelockPayment" + } + } + } + } + } + }, + "resourceMetadata": { + "type": "object", + "example": { + "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceName": "cheqd-revocation-encrypted-1", + "resourceType": "StatusList2021Revocation", + "mediaType": "application/json", + "resourceVersion": "2023-06-26T11:45:19.349Z", + "created": "2023-06-26T11:45:20Z", + "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", + "previousVersionId": null, + "nextVersionId": null + } + }, + "symmetricKey": { + "type": "string", + "example": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" + } + } + } + } + }, + "CredentialStatusCreateEncryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "created": { + "type": "boolean", + "example": true + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedResult" + } + ] + }, + "CredentialStatusUpdateBody": { + "type": "object", + "required": ["did", "statusListName", "indices"], + "properties": { + "did": { + "description": "DID of the StatusList2021 publisher.", + "type": "string", + "format": "uri" + }, + "statusListName": { + "description": "The name of the StatusList2021 DID-Linked Resource to be updated.", + "type": "string" + }, + "indices": { + "description": "List of credential status indices to be updated. The indices must be in the range of the status list.", + "type": "array", + "items": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": false + } + }, + "statusListVersion": { + "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + "CredentialStatusUpdateUnencryptedRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUpdateBody" + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials", + "indices": [10, 3199, 12109, 130999] + } + }, + "CredentialStatusUpdateUnencryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "updated": { + "type": "boolean", + "example": true + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/RevocationResult" + }, + { + "$ref": "#/components/schemas/SuspensionResult" + }, + { + "$ref": "#/components/schemas/UnsuspensionResult" + } + ] + }, + { + "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" + } + ] + }, + "CredentialStatusUpdateEncryptedFormRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUpdateBody" + }, + { + "type": "object", + "required": ["symmetricKey"], + "properties": { + "symmetricKey": { + "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" + } + ] + }, + "CredentialStatusUpdateEncryptedJsonRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUpdateBody" + }, + { + "type": "object", + "required": ["symmetricKey"], + "properties": { + "symmetricKey": { + "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials-encrypted", + "indices": [10, 3199, 12109, 130999], + "symmetricKey": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" + } + }, + "CredentialStatusUpdateEncryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "updated": { + "type": "boolean", + "example": true + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/RevocationResult" + }, + { + "$ref": "#/components/schemas/SuspensionResult" + }, + { + "$ref": "#/components/schemas/UnsuspensionResult" + } + ] + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedResult" + } + ] + }, + "CredentialStatusCheckRequest": { + "type": "object", + "required": ["did", "statusListName", "index"], + "properties": { + "did": { + "description": "DID of the StatusList2021 publisher.", + "type": "string", + "format": "uri" + }, + "statusListName": { + "description": "The name of the StatusList2021 DID-Linked Resource to be checked.", + "type": "string" + }, + "index": { + "description": "Credential status index to be checked for revocation or suspension.", + "type": "integer", + "minimum": 0, + "exclusiveMinimum": false + }, + "makeFeePayment": { + "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", + "type": "boolean", + "default": true + } + } + }, + "CredentialStatusCheckResult": { + "oneOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCheckRevocationResult" + }, + { + "$ref": "#/components/schemas/CredentialStatusCheckSuspensionResult" + } + ] + }, + "CredentialStatusCheckRevocationResult": { + "type": "object", + "properties": { + "checked": { + "type": "boolean", + "example": true + }, + "revoked": { + "type": "boolean", + "example": false + } + } + }, + "CredentialStatusCheckSuspensionResult": { + "type": "object", + "properties": { + "checked": { + "type": "boolean", + "example": true + }, + "suspended": { + "type": "boolean", + "example": false + } + } + }, + "CredentialStatusListSearchResult": { + "allOf": [ + { + "type": "object", + "properties": { + "found": { + "type": "boolean", + "example": true + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedResult" + } + ] + } + ] + }, + "KeyImportRequest": { + "type": "object", + "properties": { + "alias": { + "type": "string" + }, + "type": { + "type": "string", + "enum": ["Ed25519", "Secp256k1"] + }, + "privateKeyHex": { + "type": "string" + } + } + }, + "KeyResult": { + "type": "object", + "properties": { + "kid": { + "type": "string" + }, + "type": { + "type": "string", + "enum": ["Ed25519", "Secp256k1"] + }, + "publicKeyHex": { + "type": "string" + } + } + }, + "DidDocument": { + "description": "This input field contains either a complete DID document, or an incremental change (diff) to a DID document. See Universal DID Registrar specification.", + "type": "object", + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "controllers": { + "type": "array", + "items": { + "type": "string" + } + }, + "verificationMethod": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VerificationMethod" + } + }, + "service": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "authentication": { + "type": "array", + "items": { + "type": "string" + } + }, + "assertionMethod": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityInvocation": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityDelegation": { + "type": "array", + "items": { + "type": "string" + } + }, + "keyAgreement": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "@context": ["https://www.w3.org/ns/did/v1"], + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "controller": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0"], + "verificationMethod": [ + { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "type": "Ed25519VerificationKey2018", + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "publicKeyBase58": "z6MkkVbyHJLLjdjU5B62DaJ4mkdMdUkttf9UqySSkA9bVTeZ" + } + ], + "authentication": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1"], + "service": [ + { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", + "type": "LinkedDomains", + "serviceEndpoint": ["https://example.com"] + } + ] + } + }, + "DidDocumentWithoutVerificationMethod": { + "type": "object", + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "controllers": { + "type": "array", + "items": { + "type": "string" + } + }, + "service": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "authentication": { + "type": "array", + "items": { + "type": "string" + } + }, + "assertionMethod": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityInvocation": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityDelegation": { + "type": "array", + "items": { + "type": "string" + } + }, + "keyAgreement": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "@context": ["https://www.w3.org/ns/did/v1"], + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "controller": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0"], + "authentication": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1"], + "service": [ + { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", + "type": "LinkedDomains", + "serviceEndpoint": ["https://example.com"] + } + ] + } + }, + "DidCreateRequestFormBased": { + "type": "object", + "properties": { + "network": { + "description": "Network to create the DID on (testnet or mainnet)", + "type": "string", + "enum": ["testnet", "mainnet"] + }, + "identifierFormatType": { + "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", + "type": "string", + "enum": ["uuid", "base58btc"] + }, + "verificationMethodType": { + "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", + "type": "string", + "enum": ["Ed25519VerificationKey2018", "JsonWebKey2020", "Ed25519VerificationKey2020"] + }, + "service": { + "description": "It's a list of special objects which are designed to build the actual service. It's almost the same as in DID Core specification, but instead of `id` it utilises `idFragment` field for making the right `id` for each service. !!! WARN. Cause swagger-ui does not handle x-ww-form based arrays correctly, please frame all your services in brackets while using swagger UI. !!!", + "type": "array", + "items": { + "type": "object", + "properties": { + "idFragment": { + "type": "string" + }, + "type": { + "type": "string" + }, + "serviceEndpoint": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "example": [ + { + "idFragment": "service-1", + "type": "LinkedDomains", + "serviceEndpoint": ["https://example.com"] + } + ] + }, + "key": { + "description": "The unique identifier in hexadecimal public key format used in the verification method to create the DID.", + "type": "string" + }, + "@context": { + "type": "array", + "items": { + "type": "string" + }, + "example": ["https://www.w3.org/ns/did/v1"] + } + } + }, + "DidCreateRequestJson": { + "type": "object", + "properties": { + "network": { + "description": "Network to create the DID on (testnet or mainnet)", + "type": "string", + "enum": ["testnet", "mainnet"] + }, + "identifierFormatType": { + "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", + "type": "string", + "enum": ["uuid", "base58btc"] + }, + "assertionMethod": { + "description": "Usually a reference to a Verification Method. An Assertion Method is required to issue JSON-LD credentials. See DID Core specification for more details.", + "type": "boolean", + "default": true + }, + "options": { + "type": "object", + "properties": { + "key": { + "type": "string", + "example": "8255ddadd75695e01f3d98fcec8ccc7861a030b317d4326b0e48a4d579ddc43a" + }, + "verificationMethodType": { + "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", + "type": "string", + "enum": ["Ed25519VerificationKey2018", "JsonWebKey2020", "Ed25519VerificationKey2020"] + } + } + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocumentWithoutVerificationMethod" + } + } + }, + "DidImportRequest": { + "type": "object", + "properties": { + "did": { + "type": "string", + "description": "DID to be imported", + "format": "uri", + "required": true + }, + "keys": { + "type": "array", + "description": "List of keys required to import the DID", + "required": true, + "items": { + "$ref": "#/components/schemas/KeyImportRequest" + } + } + } + }, + "PresentationCreateResult": { + "type": "object", + "properties": { + "vp": { + "type": "object", + "description": "Verifiable Presentation which could be provided to the verifier." + }, + "nbf": { + "type": "integer", + "description": "Unix timestamp of the earliest time that the Verifiable Presentation is valid." + }, + "iss": { + "type": "string", + "description": "DID of the issuer of the Verifiable Presentation. (Here it's supposed to be a holder DID)" + }, + "aud": { + "type": "array", + "items": { + "type": "string" + }, + "description": "DID of the verifier of the Verifiable Presentation." + } + }, + "example": { + "vp": { + "@context": ["https://www.w3.org/2018/credentials/v1"], + "type": ["VerifiablePresentation"], + "verifiableCredential": [ + "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc2NoZW1hLm9yZy9zY2hlbWEuanNvbmxkIiwiaHR0cHM6Ly92ZXJhbW8uaW8vY29udGV4dHMvcHJvZmlsZS92MSIsImh0dHBzOi8vdzNpZC5vcmcvdmMtc3RhdHVzLWxpc3QtMjAyMS92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiUGVyc29uIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7Im5hbWUiOiJCb2IiLCJnZW5kZXIiOiJtYWxlIn0sImNyZWRlbnRpYWxTdGF0dXMiOnsiaWQiOiJodHRwczovL3Jlc29sdmVyLmNoZXFkLm5ldC8xLjAvaWRlbnRpZmllcnMvZGlkOmNoZXFkOnRlc3RuZXQ6OTBkNWMxNDEtNzI0Zi00N2FkLTlhZTctYTdjMzNhOWU1NjQzP3Jlc291cmNlTmFtZT1zdXNwZW5zaW9uRW4mcmVzb3VyY2VUeXBlPVN0YXR1c0xpc3QyMDIxU3VzcGVuc2lvbiMxMzMzOCIsInR5cGUiOiJTdGF0dXNMaXN0MjAyMUVudHJ5Iiwic3RhdHVzUHVycG9zZSI6InN1c3BlbnNpb24iLCJzdGF0dXNMaXN0SW5kZXgiOiIxMzMzOCJ9fSwic3ViIjoiZGlkOmtleTp6Nk1raGFYZ0JaRHZvdERrTDUyNTdmYWl6dGlHaUMyUXRLTEdwYm5uRUd0YTJkb0siLCJuYmYiOjE3MDA0NzM0MTYsImlzcyI6ImRpZDpjaGVxZDp0ZXN0bmV0OjkwZDVjMTQxLTcyNGYtNDdhZC05YWU3LWE3YzMzYTllNTY0MyJ9.-14Ril1pZEy2HEEo48gTJr2yOtGxBhUGTFmzVdjAtyhFRsW5zZg9onHt6V9JQ8BaiYBlTkP9GzTnJ-O6hdiyCw" + ] + }, + "nbf": 1700744275, + "iss": "did:cheqd:testnet:4b846d0f-2f6c-4ab6-9fe2-5b8db301c83c", + "aud": ["did:cheqd:testnet:8c71e9b6-c5a3-4250-8c58-fa591533cd22"] + } + }, + "DidResult": { + "type": "object", + "properties": { + "did": { + "type": "string" + }, + "controllerKeyId": { + "type": "string" + }, + "keys": { + "type": "array", + "items": { + "type": "object" + } + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + } + } + }, + "DidUpdateResponse": { + "type": "object", + "properties": { + "did": { + "type": "string" + }, + "controllerKeyId": { + "type": "string", + "description": "The default key id of which is the key associated with the first verificationMethod" + }, + "keys": { + "type": "array", + "description": "The list of keys associated with the list of verificationMethod's of DIDDocument", + "items": { + "type": "object" + } + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "controllerKeyRefs": { + "type": "array", + "description": "The list of keyRefs which were used for signing the transaction", + "items": { + "type": "string" + } + }, + "controllerKeys": { + "type": "array", + "description": "The list of all possible keys, inlcuding all controller's keys", + "items": { + "type": "string" + } + } + } + }, + "VerificationMethod": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + }, + "controller": { + "type": "string" + }, + "publicKeyMultibase": { + "type": "string" + }, + "publicKeyJwk": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "id": "did:cheqd:testnet :7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", + "type": "Ed25519VerificationKey2018" + } + }, + "Service": { + "description": "Communicating or interacting with the DID subject or associated entities via one or more service endpoints. See DID Core specification for more details.", + "type": "object", + "properties": { + "id": { + "description": "DID appended with Service fragment ID (e.g., `#service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`)", + "type": "string", + "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1" + }, + "type": { + "description": "Service type as defined in DID Specification Registries.", + "type": "string", + "example": "LinkedDomains" + }, + "serviceEndpoint": { + "description": "Service endpoint as defined in DID Core Specification.", + "type": "array", + "items": { + "type": "string", + "example": "https://example.com" + } + } + } + }, + "DidUpdateRequest": { + "type": "object", + "properties": { + "did": { + "description": "DID identifier to be updated.", + "type": "string", + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + "service": { + "type": "array", + "description": "Service section of the DID Document.", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "verificationMethod": { + "type": "array", + "description": "Verification Method section of the DID Document.", + "items": { + "$ref": "#/components/schemas/VerificationMethod" + } + }, + "authentication": { + "description": "Authentication section of the DID Document.", + "type": "array", + "items": { + "type": "string" + } + }, + "publicKeyHexs": { + "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", + "type": "array", + "items": { + "type": "string" + } + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + } + } + }, + "DidDeactivateRequest": { + "type": "object", + "properties": { + "publicKeyHexs": { + "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "CreateResourceRequest": { + "description": "Input fields for DID-Linked Resource creation.", + "type": "object", + "additionalProperties": false, + "required": ["name", "type", "data", "encoding"], + "properties": { + "data": { + "description": "Encoded string containing the data to be stored in the DID-Linked Resource.", + "type": "string" + }, + "encoding": { + "description": "Encoding format used to encode the data.", + "type": "string", + "enum": ["base64url", "base64", "hex"] + }, + "name": { + "description": "Name of DID-Linked Resource.", + "type": "string" + }, + "type": { + "description": "Type of DID-Linked Resource. This is NOT the same as the media type, which is calculated automatically ledger-side.", + "type": "string" + }, + "alsoKnownAs": { + "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", + "type": "array", + "items": { + "type": "object", + "properties": { + "uri": { + "type": "string" + }, + "description": { + "type": "string" + } + } + } + }, + "version": { + "description": "Optional field to assign a human-readable version in the DID-Linked Resource.", + "type": "string" + }, + "publicKeyHexs": { + "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "data": "SGVsbG8gV29ybGQ=", + "encoding": "base64url", + "name": "ResourceName", + "type": "TextDocument" + } + }, + "ResourceList": { + "type": "object", + "properties": { + "@context": { + "type": "string", + "example": "https://w3id.org/did-resolution/v1" + }, + "contentMetadata": { + "type": "object" + }, + "contentStream": { + "type": "object" + }, + "dereferencingMetadata": { + "$ref": "#/components/schemas/DereferencingMetadata" + } + } + }, + "DereferencingMetadata": { + "type": "object", + "properties": { + "contentType": { + "type": "string", + "example": "application/did+ld+json" + }, + "did": { + "$ref": "#/components/schemas/DidProperties" + }, + "retrieved": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + } + } + }, + "DidResolution": { + "type": "object", + "properties": { + "@context": { + "type": "string", + "example": "https://w3id.org/did-resolution/v1" + }, + "didDidResolutionMetadata": { + "$ref": "#/components/schemas/DidResolutionMetadata" + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + }, + "didDocumentMetadata": { + "$ref": "#/components/schemas/DidDocumentMetadata" + } + } + }, + "DeactivatedDidResolution": { + "type": "object", + "properties": { + "@context": { + "type": "string", + "example": "https://w3id.org/did-resolution/v1" + }, + "didDidResolutionMetadata": { + "$ref": "#/components/schemas/DidResolutionMetadata" + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + }, + "didDocumentMetadata": { + "$ref": "#/components/schemas/DeactivatedDidDocumentMetadata" + } + } + }, + "DidDocumentMetadata": { + "type": "object", + "properties": { + "created": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "deactivated": { + "type": "boolean", + "example": false + }, + "updated": { + "type": "string", + "example": "2021-09-10T12:00:00Z" + }, + "versionId": { + "type": "string", + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + "linkedResourceMetadata": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ResourceMetadata" + } + } + } + }, + "DeactivatedDidDocumentMetadata": { + "type": "object", + "properties": { + "created": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "deactivated": { + "type": "boolean", + "example": true + }, + "updated": { + "type": "string", + "example": "2021-09-10T12:00:00Z" + }, + "versionId": { + "type": "string", + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + "linkedResourceMetadata": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ResourceMetadata" + } + } + } + }, + "ResourceMetadata": { + "type": "object", + "properties": { + "resourceURI": { + "type": "string", + "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47/resources/398cee0a-efac-4643-9f4c-74c48c72a14b" + }, + "resourceCollectionId": { + "type": "string", + "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" + }, + "resourceId": { + "type": "string", + "example": "398cee0a-efac-4643-9f4c-74c48c72a14b" + }, + "resourceName": { + "type": "string", + "example": "cheqd-issuer-logo" + }, + "resourceType": { + "type": "string", + "example": "CredentialArtwork" + }, + "mediaType": { + "type": "string", + "example": "image/png" + }, + "resourceVersion": { + "type": "string", + "example": "1.0" + }, + "checksum": { + "type": "string", + "example": "a95380f460e63ad939541a57aecbfd795fcd37c6d78ee86c885340e33a91b559" + }, + "created": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "nextVersionId": { + "type": "string", + "example": "d4829ac7-4566-478c-a408-b44767eddadc" + }, + "previousVersionId": { + "type": "string", + "example": "ad7a8442-3531-46eb-a024-53953ec6e4ff" + } + } + }, + "DidResolutionMetadata": { + "type": "object", + "properties": { + "contentType": { + "allOf": [ + { + "$ref": "#/components/schemas/ContentType" + } + ], + "example": "application/did+ld+json" + }, + "retrieved": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "did": { + "$ref": "#/components/schemas/DidProperties" + } + } + }, + "ContentType": { + "type": "string", + "enum": ["application/did+json", "application/did+ld+json", "application/ld+json", "application/json"] + }, + "DidProperties": { + "type": "object", + "properties": { + "didString": { + "type": "string", + "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" + }, + "method": { + "type": "string", + "example": "cheqd" + }, + "methodSpecificId": { + "type": "string", + "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" + } + } + }, + "Customer": { + "type": "object", + "properties": { + "customerId": { + "type": "string", + "example": "6w5drpiiwhhs" + }, + "address": { + "type": "string", + "example": "cheqd1wgsvqwlkmdp60f4dek26ak0sjw6au3ytd3pz7f" + } + } + }, + "AccountCreateRequest": { + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": { + "primaryEmail": { + "type": "string" + } + } + } + } + }, + "InvalidRequest": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "InvalidRequest" + } + } + }, + "InternalError": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Internal Error" + } + } + }, + "UnauthorizedError": { + "description": "Access token is missing or invalid", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Unauthorized Error" + } + } + } + } + } } diff --git a/src/types/constants.ts b/src/types/constants.ts index 1a6fa86a..34c30e24 100644 --- a/src/types/constants.ts +++ b/src/types/constants.ts @@ -12,7 +12,7 @@ export const HEADERS = { export const APPLICATION_BASE_URL = process.env.APPLICATION_BASE_URL || 'http://localhost:3000'; export const CORS_ALLOWED_ORIGINS = process.env.CORS_ALLOWED_ORIGINS || APPLICATION_BASE_URL; export const API_KEY_PREFIX = 'caas'; -export const API_KEY_LENGTH = 64; +export const API_SECRET_KEY_LENGTH = 64; export const API_KEY_EXPIRATION = 30; // By default we don't send events to datadog export const ENABLE_DATADOG = process.env.ENABLE_DATADOG === 'true' ? true : false; diff --git a/src/types/portal.ts b/src/types/portal.ts index 37c7cf32..8ab6f0ba 100644 --- a/src/types/portal.ts +++ b/src/types/portal.ts @@ -5,7 +5,6 @@ export type ProductWithPrices = Stripe.Product & { prices?: Stripe.Price[]; }; - export type APIServiceOptions = { decryptionNeeded: boolean; }; @@ -109,11 +108,11 @@ export type APIKeyResponseBody = { }; // Create export type APIKeyCreateRequestBody = { - name: string, + name: string; expiresAt?: Date; }; -export type APIKeyCreateResponseBody = APIKeyResponseBody +export type APIKeyCreateResponseBody = APIKeyResponseBody; export type APIKeyCreateUnsuccessfulResponseBody = UnsuccessfulResponseBody; // Update @@ -151,4 +150,3 @@ export type APIKeyGetUnsuccessfulResponseBody = UnsuccessfulResponseBody; // Utils export type PaymentBehavior = Stripe.SubscriptionCreateParams.PaymentBehavior; - From e7385dda11c62bdce2377e6bc8d9ba565b6e801b Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Tue, 16 Apr 2024 14:22:41 +0200 Subject: [PATCH 32/40] Add an ability to add several endpoints into CORS --- src/app.ts | 10 +- src/static/swagger-admin.json | 2058 +++++----- src/static/swagger-api.json | 6882 +++++++++++++++++---------------- 3 files changed, 4604 insertions(+), 4346 deletions(-) diff --git a/src/app.ts b/src/app.ts index 0cb65d33..a8722571 100644 --- a/src/app.ts +++ b/src/app.ts @@ -67,10 +67,14 @@ class App { cors({ origin: function (origin, callback) { if (!origin) return callback(null, true); - if (CORS_ALLOWED_ORIGINS?.indexOf(origin) === -1) { - return callback(new Error(CORS_ERROR_MSG), false); + const allowedList = CORS_ALLOWED_ORIGINS.split(','); + + for (const allowed of allowedList) { + if (allowed.indexOf(origin) !== -1) { + return callback(null, true); + } } - return callback(null, true); + return callback(new Error(CORS_ERROR_MSG), false); }, }) ); diff --git a/src/static/swagger-admin.json b/src/static/swagger-admin.json index 72021893..f8d03627 100644 --- a/src/static/swagger-admin.json +++ b/src/static/swagger-admin.json @@ -1,1011 +1,1049 @@ { - "openapi": "3.0.0", - "info": { - "title": "Credential Service admin API for cheqd network", - "version": "2.0.0", - "description": "Admin API which handles users subscriptions and payments", - "contact": { - "name": "Cheqd Foundation Limited", - "url": "https://github.com/cheqd/credential-service", - "email": "support-github@cheqd.io" - }, - "license": { - "name": "Apache 2.0", - "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" - } - }, - "tags": [ - { - "name": "Product" - }, - { - "name": "Price" - }, - { - "name": "Subscription" - }, - { - "name": "API Key" - } - ], - "paths": { - "/admin/api-key/create": { - "post": { - "summary": "Create a new API key", - "description": "Create a new API key", - "tags": ["API Key"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyCreateRequestBody" - } - } - } - }, - "responses": { - "201": { - "description": "A new API key has been created", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyCreateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/APIKeyCreateUnsuccessfulResponseBody" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/api-key/update": { - "post": { - "summary": "Update an existing API key", - "description": "Update an existing API key", - "tags": ["API Key"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyUpdateRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The API key has been updated", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyUpdateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/APIKeyUpdateUnsuccessfulResponseBody" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/api-key/revoke": { - "delete": { - "summary": "Revoke an existing API key", - "description": "Revoke an existing API key", - "tags": ["API Key"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyRevokeRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The API key has been revoked", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyRevokeResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/APIKeyRevokeUnsuccessfulResponseBody" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/api-key/list": { - "get": { - "summary": "List all API keys", - "description": "List all API keys", - "tags": ["API Key"], - "responses": { - "200": { - "description": "A list of API keys", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/api-key/get": { - "get": { - "summary": "Get an API key", - "description": "Get an API key. If the API key is not provided, the latest not revoked API key it returns.", - "tags": ["API Key"], - "parameters": [ - { - "name": "apiKey", - "in": "query", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "The API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyGetResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/price/list": { - "get": { - "summary": "Get a list of prices", - "description": "Get a list of prices", - "tags": ["Price"], - "parameters": [ - { - "in": "query", - "name": "productId", - "schema": { - "type": "string", - "description": "The product id. If passed - returns filtered by this product list of prices.", - "required": false - } - } - ], - "responses": { - "200": { - "description": "A list of prices", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PriceListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/product/list": { - "get": { - "summary": "Get a list of products", - "description": "Get a list of products which are on a Stripe side", - "tags": ["Product"], - "parameters": [ - { - "in": "query", - "name": "prices", - "schema": { - "type": "boolean", - "description": "If setup to true - returns the list of products with prices inside. Default - true", - "required": false - } - } - ], - "responses": { - "200": { - "description": "A list of products", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/product/get/{productId}": { - "get": { - "summary": "Get a product", - "description": "Get a product by id", - "tags": ["Product"], - "parameters": [ - { - "in": "path", - "name": "productId", - "schema": { - "type": "string", - "description": "The product id which identifies the product in Stripe" - }, - "required": true - }, - { - "in": "query", - "name": "prices", - "schema": { - "type": "boolean", - "description": "If setup to true - returns the product with prices inside. Default - true", - "required": false - } - } - ], - "responses": { - "200": { - "description": "A product", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductGetResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/create": { - "post": { - "summary": "Create a subscription", - "description": "Creates a new subscription for an existing customer", - "tags": ["Subscription"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCreateRequestBody" - } - } - } - }, - "responses": { - "201": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCreateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/update": { - "post": { - "summary": "Update a subscription", - "description": "Updates an existing subscription", - "tags": ["Subscription"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionUpdateRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionUpdateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/list": { - "get": { - "summary": "Get a list of subscriptions", - "description": "Get a list of subscriptions", - "tags": ["Subscription"], - "parameters": [ - { - "in": "query", - "name": "paymentProviderId", - "schema": { - "type": "string", - "description": "The customer id. If passed - returns filtered by this customer list of subscriptions." - } - } - ], - "responses": { - "200": { - "description": "A list of subscriptions", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/get": { - "get": { - "summary": "Get a subscription", - "description": "Get a subscription", - "tags": ["Subscription"], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionGetResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/cancel": { - "post": { - "summary": "Cancel a subscription", - "description": "Cancels an existing subscription", - "tags": ["Subscription"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCancelRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCancelResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/resume": {}, - "post": { - "summary": "Resume a subscription", - "description": "Resumes an existing subscription", - "tags": ["Subscription"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionResumeRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionResumeResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "components": { - "schemas": { - "PriceListResponseBody": { - "description": "A list of active prcies from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/list)", - "type": "object", - "properties": { - "prices": { - "type": "array", - "items": { - "type": "object", - "description": "A price object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/object)" - } - } - } - }, - "ProductListResponseBody": { - "type": "object", - "properties": { - "products": { - "type": "array", - "items": { - "type": "object", - "description": "A product object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/object)" - } - } - } - }, - "ProductGetResponseBody": { - "description": "A product with or without prices inside. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/retrieve)", - "type": "object" - }, - "InvalidRequest": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "InvalidRequest" - } - } - }, - "InternalError": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Internal Error" - } - } - }, - "UnauthorizedError": { - "description": "Access token is missing or invalid", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Unauthorized Error" - } - } - }, - "SubscriptionCreateRequestBody": { - "description": "The request body for creating a subscription", - "type": "object", - "properties": { - "price": { - "type": "string", - "description": "The price id", - "example": "price_1234567890" - }, - "successURL": { - "type": "string", - "description": "The URL to redirect to after the customer sucessfully completes the checkout", - "example": "https://example.com/success" - }, - "cancelURL": { - "type": "string", - "description": "The URL to redirect to after the customer cancels the checkout", - "example": "https://example.com/cancel" - }, - "quantity": { - "type": "number", - "description": "The quantity of the product", - "example": 1 - }, - "trialPeriodDays": { - "type": "number", - "description": "The number of days the customer has to pay for the product", - "example": 7 - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": "abcdefghijklmnopqrstuvwxyz" - } - } - }, - "SubscriptionCreateResponseBody": { - "description": "The response body for creating a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "An object with link to checkout session. For more information see the [Stripe API documentation](https://docs.stripe.com/api/checkout/sessions/object)", - "properties": { - "sessionURL": { - "type": "string", - "description": "URL which user should follow to manage subscription" - } - } - } - } - }, - "SubscriptionUpdateRequestBody": { - "description": "The request body for updating a subscription", - "type": "object", - "properties": { - "returnURL": { - "type": "string", - "description": "URL which is used to redirect to the page with ability to update the subscription" - } - } - }, - "SubscriptionUpdateResponseBody": { - "description": "The response body for updating a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "Object with redirect url inside", - "properties": { - "sessionURL": { - "type": "string", - "description": "URL with session URL rediect to" - } - } - } - } - }, - "SubscriptionGetRequestBody": { - "description": "The request body for getting a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - } - } - }, - "SubscriptionGetResponseBody": { - "description": "The response body for getting a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" - } - } - }, - "SubscriptionListRequestBody": { - "description": "The request body for listing subscriptions", - "type": "object", - "properties": { - "customerId": { - "type": "string", - "description": "The Stripe customer id", - "example": "cus_1234567890" - } - } - }, - "SubscriptionListResponseBody": { - "description": "The response body for listing subscriptions", - "type": "object", - "properties": { - "subscriptions": { - "type": "array", - "items": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" - } - } - } - }, - "SubscriptionCancelRequestBody": { - "description": "The request body for canceling a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - } - } - }, - "SubscriptionCancelResponseBody": { - "description": "The response body for canceling a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": "abcdefghijklmnopqrstuvwxyz" - } - } - }, - "SubscriptionResumeRequestBody": { - "description": "The request body for resuming a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": "abcdefghijklmnopqrstuvwxyz" - } - } - }, - "SubscriptionResumeResponseBody": { - "description": "The response body for resuming a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" - } - } - }, - "APIKeyResponse": { - "description": "The general view for API key in response", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz" - }, - "createdAt": { - "type": "string", - "description": "The creation date of the API key", - "example": "2000-10-31T01:23:45Z", - "format": "date-time" - }, - "name": { - "type": "string", - "description": "The name of the API key", - "example": "My API Key" - }, - "expiresAt": { - "type": "string", - "description": "The expiration date of the API key", - "example": "2000-10-31T01:23:45Z", - "format": "date-time" - }, - "revoked": { - "type": "boolean", - "description": "The status of the API key", - "example": false - } - } - }, - "APIKeyCreateRequestBody": { - "description": "The request body for creating an API key", - "type": "object", - "properties": { - "expiresAt": { - "type": "string", - "description": "The expiration date of the API key", - "example": "2000-10-31T01:23:45Z", - "format": "date-time" - }, - "name": { - "type": "string", - "description": "The name of the API key", - "example": "My API Key" - } - }, - "required": ["name"] - }, - "APIKeyCreateResponseBody": { - "description": "The response body for creating an API key", - "type": "object", - "schema": { - "ref": "#/components/schemas/APIKeyResponse" - } - }, - "APIKeyCreateUnsuccessfulResponseBody": { - "description": "The response body for an unsuccessful API key creation", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "API key creation unsuccessful" - } - } - }, - "APIKeyUpdateRequestBody": { - "description": "The request body for updating an API key", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz" - }, - "name": { - "type": "string", - "description": "The name of the API key", - "example": "My API Key" - }, - "expiresAt": { - "type": "string", - "description": "The expiration date of the API key", - "example": "2000-10-31T01:23:45Z", - "format": "date-time" - }, - "revoked": { - "type": "boolean", - "description": "The status of the API key", - "example": false, - "default": false - } - }, - "required": ["apiKey"] - }, - "APIKeyUpdateResponseBody": { - "description": "The response body for an unsuccessful API key update", - "type": "object", - "schema": { - "ref": "#/components/schemas/APIKeyResponse" - } - }, - "APIKeyUpdateUnsuccessfulResponseBody": { - "description": "The response body for an unsuccessful API key update", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "API key update unsuccessful" - } - } - }, - "APIKeyRevokeRequestBody": { - "description": "The request body for revoking an API key", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz" - } - }, - "required": ["apiKey"] - }, - "APIKeyRevokeResponseBody": { - "description": "The response body for revoking an API key", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz" - }, - "revoked": { - "type": "boolean", - "description": "The status of the API key", - "example": true - } - }, - "required": ["apiKey"] - }, - "APIKeyRevokeUnsuccessfulResponseBody": { - "description": "The response body for an unsuccessful API key revocation", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "API key revocation unsuccessful" - } - } - }, - "APIKeyListResponseBody": { - "description": "The response body for listing API keys", - "type": "object", - "properties": { - "apiKeys": { - "type": "array", - "items": { - "type": "object", - "schema": { - "ref": "#/components/schemas/APIKeyResponse" - } - } - } - } - }, - "APIKeyGetRequestBody": { - "description": "The request body for getting an API key", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz" - } - }, - "required": ["apiKey"] - }, - "APIKeyGetResponseBody": { - "description": "The response body for getting an API key", - "type": "object", - "schema": { - "ref": "#/components/schemas/APIKeyResponse" - } - }, - "NotFoundError": { - "description": "The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Not Found Error" - } - } - } - } - } -} + "openapi": "3.0.0", + "info": { + "title": "Credential Service admin API for cheqd network", + "version": "2.0.0", + "description": "Admin API which handles users subscriptions and payments", + "contact": { + "name": "Cheqd Foundation Limited", + "url": "https://github.com/cheqd/credential-service", + "email": "support-github@cheqd.io" + }, + "license": { + "name": "Apache 2.0", + "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" + } + }, + "tags": [ + { + "name": "Product" + }, + { + "name": "Price" + }, + { + "name": "Subscription" + }, + { + "name": "API Key" + } + ], + "paths": { + "/admin/api-key/create": { + "post": { + "summary": "Create a new API key", + "description": "Create a new API key", + "tags": [ + "API Key" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyCreateRequestBody" + } + } + } + }, + "responses": { + "201": { + "description": "A new API key has been created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyCreateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/APIKeyCreateUnsuccessfulResponseBody" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/api-key/update": { + "post": { + "summary": "Update an existing API key", + "description": "Update an existing API key", + "tags": [ + "API Key" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyUpdateRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The API key has been updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyUpdateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/APIKeyUpdateUnsuccessfulResponseBody" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/api-key/revoke": { + "delete": { + "summary": "Revoke an existing API key", + "description": "Revoke an existing API key", + "tags": [ + "API Key" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyRevokeRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The API key has been revoked", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyRevokeResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/APIKeyRevokeUnsuccessfulResponseBody" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/api-key/list": { + "get": { + "summary": "List all API keys", + "description": "List all API keys", + "tags": [ + "API Key" + ], + "responses": { + "200": { + "description": "A list of API keys", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/api-key/get": { + "get": { + "summary": "Get an API key", + "description": "Get an API key. If the API key is not provided, the latest not revoked API key it returns.", + "tags": [ + "API Key" + ], + "parameters": [ + { + "name": "apiKey", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyGetResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/price/list": { + "get": { + "summary": "Get a list of prices", + "description": "Get a list of prices", + "tags": [ + "Price" + ], + "parameters": [ + { + "in": "query", + "name": "productId", + "schema": { + "type": "string", + "description": "The product id. If passed - returns filtered by this product list of prices.", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A list of prices", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PriceListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/product/list": { + "get": { + "summary": "Get a list of products", + "description": "Get a list of products which are on a Stripe side", + "tags": [ + "Product" + ], + "parameters": [ + { + "in": "query", + "name": "prices", + "schema": { + "type": "boolean", + "description": "If setup to true - returns the list of products with prices inside. Default - true", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A list of products", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProductListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/product/get/{productId}": { + "get": { + "summary": "Get a product", + "description": "Get a product by id", + "tags": [ + "Product" + ], + "parameters": [ + { + "in": "path", + "name": "productId", + "schema": { + "type": "string", + "description": "The product id which identifies the product in Stripe" + }, + "required": true + }, + { + "in": "query", + "name": "prices", + "schema": { + "type": "boolean", + "description": "If setup to true - returns the product with prices inside. Default - true", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A product", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProductGetResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/create": { + "post": { + "summary": "Create a subscription", + "description": "Creates a new subscription for an existing customer", + "tags": [ + "Subscription" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCreateRequestBody" + } + } + } + }, + "responses": { + "201": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCreateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/update": { + "post": { + "summary": "Update a subscription", + "description": "Updates an existing subscription", + "tags": [ + "Subscription" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionUpdateRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionUpdateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/list": { + "get": { + "summary": "Get a list of subscriptions", + "description": "Get a list of subscriptions", + "tags": [ + "Subscription" + ], + "parameters": [ + { + "in": "query", + "name": "paymentProviderId", + "schema": { + "type": "string", + "description": "The customer id. If passed - returns filtered by this customer list of subscriptions." + } + } + ], + "responses": { + "200": { + "description": "A list of subscriptions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/get": { + "get": { + "summary": "Get a subscription", + "description": "Get a subscription", + "tags": [ + "Subscription" + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionGetResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/cancel": { + "post": { + "summary": "Cancel a subscription", + "description": "Cancels an existing subscription", + "tags": [ + "Subscription" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCancelRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCancelResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/resume": {}, + "post": { + "summary": "Resume a subscription", + "description": "Resumes an existing subscription", + "tags": [ + "Subscription" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionResumeRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionResumeResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "components": { + "schemas": { + "PriceListResponseBody": { + "description": "A list of active prcies from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/list)", + "type": "object", + "properties": { + "prices": { + "type": "array", + "items": { + "type": "object", + "description": "A price object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/object)" + } + } + } + }, + "ProductListResponseBody": { + "type": "object", + "properties": { + "products": { + "type": "array", + "items": { + "type": "object", + "description": "A product object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/object)" + } + } + } + }, + "ProductGetResponseBody": { + "description": "A product with or without prices inside. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/retrieve)", + "type": "object" + }, + "InvalidRequest": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "InvalidRequest" + } + } + }, + "InternalError": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Internal Error" + } + } + }, + "UnauthorizedError": { + "description": "Access token is missing or invalid", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Unauthorized Error" + } + } + }, + "SubscriptionCreateRequestBody": { + "description": "The request body for creating a subscription", + "type": "object", + "properties": { + "price": { + "type": "string", + "description": "The price id", + "example": "price_1234567890" + }, + "successURL": { + "type": "string", + "description": "The URL to redirect to after the customer sucessfully completes the checkout", + "example": "https://example.com/success" + }, + "cancelURL": { + "type": "string", + "description": "The URL to redirect to after the customer cancels the checkout", + "example": "https://example.com/cancel" + }, + "quantity": { + "type": "number", + "description": "The quantity of the product", + "example": 1 + }, + "trialPeriodDays": { + "type": "number", + "description": "The number of days the customer has to pay for the product", + "example": 7 + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": "abcdefghijklmnopqrstuvwxyz" + } + } + }, + "SubscriptionCreateResponseBody": { + "description": "The response body for creating a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "An object with link to checkout session. For more information see the [Stripe API documentation](https://docs.stripe.com/api/checkout/sessions/object)", + "properties": { + "sessionURL": { + "type": "string", + "description": "URL which user should follow to manage subscription" + } + } + } + } + }, + "SubscriptionUpdateRequestBody": { + "description": "The request body for updating a subscription", + "type": "object", + "properties": { + "returnURL": { + "type": "string", + "description": "URL which is used to redirect to the page with ability to update the subscription" + } + } + }, + "SubscriptionUpdateResponseBody": { + "description": "The response body for updating a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "Object with redirect url inside", + "properties": { + "sessionURL": { + "type": "string", + "description": "URL with session URL rediect to" + } + } + } + } + }, + "SubscriptionGetRequestBody": { + "description": "The request body for getting a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + } + } + }, + "SubscriptionGetResponseBody": { + "description": "The response body for getting a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" + } + } + }, + "SubscriptionListRequestBody": { + "description": "The request body for listing subscriptions", + "type": "object", + "properties": { + "customerId": { + "type": "string", + "description": "The Stripe customer id", + "example": "cus_1234567890" + } + } + }, + "SubscriptionListResponseBody": { + "description": "The response body for listing subscriptions", + "type": "object", + "properties": { + "subscriptions": { + "type": "array", + "items": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + } + } + } + }, + "SubscriptionCancelRequestBody": { + "description": "The request body for canceling a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + } + } + }, + "SubscriptionCancelResponseBody": { + "description": "The response body for canceling a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": "abcdefghijklmnopqrstuvwxyz" + } + } + }, + "SubscriptionResumeRequestBody": { + "description": "The request body for resuming a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": "abcdefghijklmnopqrstuvwxyz" + } + } + }, + "SubscriptionResumeResponseBody": { + "description": "The response body for resuming a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + } + } + }, + "APIKeyResponse": { + "description": "The general view for API key in response", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + }, + "createdAt": { + "type": "string", + "description": "The creation date of the API key", + "example": "2000-10-31T01:23:45Z", + "format": "date-time" + }, + "name": { + "type": "string", + "description": "The name of the API key", + "example": "My API Key" + }, + "expiresAt": { + "type": "string", + "description": "The expiration date of the API key", + "example": "2000-10-31T01:23:45Z", + "format": "date-time" + }, + "revoked": { + "type": "boolean", + "description": "The status of the API key", + "example": false + } + } + }, + "APIKeyCreateRequestBody": { + "description": "The request body for creating an API key", + "type": "object", + "properties": { + "expiresAt": { + "type": "string", + "description": "The expiration date of the API key", + "example": "2000-10-31T01:23:45Z", + "format": "date-time" + }, + "name": { + "type": "string", + "description": "The name of the API key", + "example": "My API Key" + } + }, + "required": [ + "name" + ] + }, + "APIKeyCreateResponseBody": { + "description": "The response body for creating an API key", + "type": "object", + "schema": { + "ref": "#/components/schemas/APIKeyResponse" + } + }, + "APIKeyCreateUnsuccessfulResponseBody": { + "description": "The response body for an unsuccessful API key creation", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "API key creation unsuccessful" + } + } + }, + "APIKeyUpdateRequestBody": { + "description": "The request body for updating an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + }, + "name": { + "type": "string", + "description": "The name of the API key", + "example": "My API Key" + }, + "expiresAt": { + "type": "string", + "description": "The expiration date of the API key", + "example": "2000-10-31T01:23:45Z", + "format": "date-time" + }, + "revoked": { + "type": "boolean", + "description": "The status of the API key", + "example": false, + "default": false + } + }, + "required": [ + "apiKey" + ] + }, + "APIKeyUpdateResponseBody": { + "description": "The response body for an unsuccessful API key update", + "type": "object", + "schema": { + "ref": "#/components/schemas/APIKeyResponse" + } + }, + "APIKeyUpdateUnsuccessfulResponseBody": { + "description": "The response body for an unsuccessful API key update", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "API key update unsuccessful" + } + } + }, + "APIKeyRevokeRequestBody": { + "description": "The request body for revoking an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + } + }, + "required": [ + "apiKey" + ] + }, + "APIKeyRevokeResponseBody": { + "description": "The response body for revoking an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + }, + "revoked": { + "type": "boolean", + "description": "The status of the API key", + "example": true + } + }, + "required": [ + "apiKey" + ] + }, + "APIKeyRevokeUnsuccessfulResponseBody": { + "description": "The response body for an unsuccessful API key revocation", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "API key revocation unsuccessful" + } + } + }, + "APIKeyListResponseBody": { + "description": "The response body for listing API keys", + "type": "object", + "properties": { + "apiKeys": { + "type": "array", + "items": { + "type": "object", + "schema": { + "ref": "#/components/schemas/APIKeyResponse" + } + } + } + } + }, + "APIKeyGetRequestBody": { + "description": "The request body for getting an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + } + }, + "required": [ + "apiKey" + ] + }, + "APIKeyGetResponseBody": { + "description": "The response body for getting an API key", + "type": "object", + "schema": { + "ref": "#/components/schemas/APIKeyResponse" + } + }, + "NotFoundError": { + "description": "The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Not Found Error" + } + } + } + } + } +} \ No newline at end of file diff --git a/src/static/swagger-api.json b/src/static/swagger-api.json index b2cf4b99..a42f421f 100644 --- a/src/static/swagger-api.json +++ b/src/static/swagger-api.json @@ -1,3334 +1,3550 @@ { - "openapi": "3.0.0", - "info": { - "title": "Credential Service API for cheqd network", - "version": "2.0.0", - "description": "API service to create and manage DIDs, Verifiable Credentials, and DID-Linked Resources", - "contact": { - "name": "Cheqd Foundation Limited", - "url": "https://github.com/cheqd/credential-service", - "email": "support-github@cheqd.io" - }, - "license": { - "name": "Apache 2.0", - "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" - } - }, - "tags": [ - { - "name": "Account" - }, - { - "name": "Key" - }, - { - "name": "DID" - }, - { - "name": "Resource" - }, - { - "name": "Credential" - }, - { - "name": "Presentation" - }, - { - "name": "Credential Status" - } - ], - "externalDocs": { - "description": "Credential Service API Documentation", - "url": "https://docs.cheqd.io/identity" - }, - "paths": { - "/account": { - "get": { - "tags": ["Account"], - "summary": "Fetch custodian-mode client details.", - "description": "This endpoint returns the custodian-mode client details for authenticated users.", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Customer" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/account/idtoken": { - "get": { - "tags": ["Account"], - "summary": "Fetch IdToken.", - "description": "This endpoint returns IdToken as JWT with list of user roles inside", - "deprecated": true, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "idToken": { - "type": "string" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/account/create": { - "post": { - "tags": ["Account"], - "summary": "Create an client for an authenticated user.", - "description": "This endpoint creates a client in the custodian-mode for an authenticated user", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/AccountCreateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountCreateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "idToken": { - "type": "string" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/create/unencrypted": { - "post": { - "tags": ["Credential Status"], - "summary": "Create an unencrypted StatusList2021 credential status list.", - "description": "This endpoint creates an unencrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", - "parameters": [ - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", - "required": true, - "schema": { - "type": "string", - "enum": ["revocation", "suspension"] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/create/encrypted": { - "post": { - "tags": ["Credential Status"], - "summary": "Create an encrypted StatusList2021 credential status list.", - "description": "This endpoint creates an encrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", - "parameters": [ - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", - "required": true, - "schema": { - "type": "string", - "enum": ["revocation", "suspension"] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateEncryptedFormRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateEncryptedJsonRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateEncryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/update/unencrypted": { - "post": { - "tags": ["Credential Status"], - "summary": "Update an existing unencrypted StatusList2021 credential status list.", - "parameters": [ - { - "in": "query", - "name": "statusAction", - "description": "The update action to be performed on the unencrypted status list, can be revoke, suspend or reinstate", - "required": true, - "schema": { - "type": "string", - "enum": ["revoke", "suspend", "reinstate"] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/update/encrypted": { - "post": { - "tags": ["Credential Status"], - "summary": "Update an existing encrypted StatusList2021 credential status list.", - "parameters": [ - { - "in": "query", - "name": "statusAction", - "description": "The update action to be performed on the encrypted status list, can be revoke, suspend or reinstate", - "required": true, - "schema": { - "type": "string", - "enum": ["revoke", "suspend", "reinstate"] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedFormRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedJsonRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/check": { - "post": { - "tags": ["Credential Status"], - "summary": "Check a StatusList2021 index for a given Verifiable Credential.", - "description": "This endpoint checks a StatusList2021 index for a given Verifiable Credential and reports whether it is revoked or suspended. It offers a standalone method for checking an index without passing the entire Verifiable Credential or Verifiable Presentation.", - "parameters": [ - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension.", - "required": true, - "schema": { - "type": "string", - "enum": ["revocation", "suspension"] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCheckRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCheckRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCheckResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/search": { - "get": { - "tags": ["Credential Status"], - "summary": "Fetch StatusList2021 DID-Linked Resource based on search criteria.", - "parameters": [ - { - "in": "query", - "name": "did", - "description": "The DID of the issuer of the status list.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension.", - "schema": { - "type": "string", - "enum": ["revocation", "suspension"] - } - }, - { - "in": "query", - "name": "statusListName", - "description": "The name of the StatusList2021 DID-Linked Resource.", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusListSearchResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/issue": { - "post": { - "tags": ["Credential"], - "summary": "Issue a Verifiable Credential", - "description": "This endpoint issues a Verifiable Credential. As input it takes the list of issuerDid, subjectDid, attributes, and other parameters of the credential to be issued.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Credential" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/verify": { - "post": { - "tags": ["Credential"], - "summary": "Verify a Verifiable Credential.", - "description": "This endpoint verifies a Verifiable Credential passed to it. As input, it can take the VC-JWT as a string or the entire credential itself.", - "operationId": "verify", - "parameters": [ - { - "in": "query", - "name": "verifyStatus", - "description": "If set to `true` the verification will also check the status of the credential. Requires the VC to have a `credentialStatus` property.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "fetchRemoteContexts", - "description": "When dealing with JSON-LD you also MUST provide the proper contexts. Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "allowDeactivatedDid", - "description": "If set to `true` allow to verify credential which based on deactivated DID.", - "schema": { - "type": "boolean", - "default": false - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialVerifyRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialVerifyRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/VerifyCredentialResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/revoke": { - "post": { - "tags": ["Credential"], - "summary": "Revoke a Verifiable Credential.", - "description": "This endpoint revokes a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself. The StatusList2021 resource should already be setup in the VC and `credentialStatus` property present in the VC.", - "operationId": "revoke", - "parameters": [ - { - "in": "query", - "name": "publish", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RevocationResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/suspend": { - "post": { - "tags": ["Credential"], - "summary": "Suspend a Verifiable Credential.", - "description": "This endpoint suspends a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself.", - "operationId": "suspend", - "parameters": [ - { - "in": "query", - "name": "publish", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "schema": { - "type": "boolean" - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuspensionResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/reinstate": { - "post": { - "tags": ["Credential"], - "summary": "Reinstate a suspended Verifiable Credential.", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "operationId": "reinstate", - "parameters": [ - { - "in": "query", - "name": "publish", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "schema": { - "type": "boolean" - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnsuspensionResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/create": { - "post": { - "tags": ["DID"], - "summary": "Create a DID Document.", - "description": "This endpoint creates a DID and associated DID Document. As input, it can take the DID Document parameters via a form, or the fully-assembled DID Document itself.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidCreateRequestFormBased" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidCreateRequestJson" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/did/update": { - "post": { - "tags": ["DID"], - "summary": "Update a DID Document.", - "description": "This endpoint updates a DID Document. As an input, it can take JUST the sections/parameters that need to be updated in the DID Document (in this scenario, it fetches the current DID Document and applies the updated section). Alternatively, it take the fully-assembled DID Document with updated sections as well as unchanged sections.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidUpdateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidUpdateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidUpdateResponse" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/import": { - "post": { - "tags": ["DID"], - "summary": "Import a DID Document.", - "description": "This endpoint imports a decentralized identifier associated with the user's account for custodian-mode clients.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidImportRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidImportRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/did/deactivate/{did}": { - "post": { - "tags": ["DID"], - "summary": "Deactivate a DID Document.", - "description": "This endpoint deactivates a DID Document by taking the DID identifier as input. Must be called and signed by the DID owner.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier to deactivate.", - "schema": { - "type": "string" - }, - "required": true - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidDeactivateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidDeactivateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeactivatedDidResolution" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/list": { - "get": { - "tags": ["DID"], - "summary": "Fetch DIDs associated with an account.", - "description": "This endpoint returns the list of DIDs controlled by the account.", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/search/{did}": { - "get": { - "tags": ["DID"], - "summary": "Resolve a DID Document.", - "description": "Resolve a DID Document by DID identifier. Also supports DID Resolution Queries as defined in the W3C DID Resolution specification.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier to resolve.", - "schema": { - "type": "string" - }, - "required": true, - "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - { - "in": "query", - "name": "metadata", - "description": "Return only metadata of DID Document instead of actual DID Document.", - "schema": { - "type": "boolean" - } - }, - { - "in": "query", - "name": "versionId", - "description": "Unique UUID version identifier of DID Document. Allows for fetching a specific version of the DID Document. See cheqd DID Method Specification for more details.", - "schema": { - "type": "string", - "format": "uuid" - }, - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - { - "in": "query", - "name": "versionTime", - "description": "Returns the closest version of the DID Document *at* or *before* specified time. See DID Resolution handling for `did:cheqd` for more details.", - "schema": { - "type": "string", - "format": "date-time" - }, - "example": "1970-01-01T00:00:00Z" - }, - { - "in": "query", - "name": "transformKeys", - "description": "This directive transforms the Verification Method key format from the version in the DID Document to the specified format chosen below.", - "schema": { - "type": "string", - "enum": ["Ed25519VerificationKey2018", "Ed25519VerificationKey2020", "JsonWebKey2020"] - } - }, - { - "in": "query", - "name": "service", - "description": "Query DID Document for a specific Service Endpoint by Service ID (e.g., `service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`). This will typically redirect to the Service Endpoint based on DID Resolution specification algorithm.", - "schema": { - "type": "string" - }, - "example": "service-1" - }, - { - "in": "query", - "name": "relativeRef", - "description": "Relative reference is a query fragment appended to the Service Endpoint URL. **Must** be used along with the `service` query property above. See DID Resolution specification algorithm for more details.", - "schema": { - "type": "string" - }, - "example": "/path/to/file" - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidResolution" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/key/create": { - "post": { - "tags": ["Key"], - "summary": "Create an identity key pair.", - "description": "This endpoint creates an identity key pair associated with the user's account for custodian-mode clients.", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/key/import": { - "post": { - "tags": ["Key"], - "summary": "Import an identity key pair.", - "description": "This endpoint imports an identity key pair associated with the user's account for custodian-mode clients.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/KeyImportRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyImportRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/key/read/{kid}": { - "get": { - "tags": ["Key"], - "summary": "Fetch an identity key pair.", - "description": "This endpoint fetches an identity key pair's details for a given key ID. Only the user account associated with the custodian-mode client can fetch the key pair.", - "parameters": [ - { - "name": "kid", - "description": "Key ID of the identity key pair to fetch.", - "in": "path", - "schema": { - "type": "string" - }, - "required": true - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/presentation/create": { - "post": { - "tags": ["Presentation"], - "summary": "!!! WARN. Such endpoint is made mostly for testing purposes and it is not supposed to be used in production !!! Create a Verifiable Presentation from credential(s).", - "description": "This endpoint creates a Verifiable Presentation from credential(s). As input, it can take the credential(s) as a string or the entire credential(s) itself. \n !!! WARN. Such endpoint is made only for testing purposes !!!", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/PresentationCreateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/PresentationCreateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PresentationCreateResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/presentation/verify": { - "post": { - "tags": ["Presentation"], - "summary": "Verify a Verifiable Presentation generated from credential(s).", - "description": "This endpoint verifies the Verifiable Presentation generated from credential(s). As input, it can take the Verifiable Presentation JWT as a string or the entire Verifiable Presentation itself.", - "parameters": [ - { - "in": "query", - "name": "verifyStatus", - "description": "If set to `true` the verification will also check the status of the presentation. Requires the VP to have a `credentialStatus` property.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "fetchRemoteContexts", - "description": "When dealing with JSON-LD you also MUST provide the proper contexts. * Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "allowDeactivatedDid", - "description": "If set to `true` allow to verify credential which based on deactivated DID.", - "schema": { - "type": "boolean", - "default": false - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/PresentationVerifyRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/PresentationVerifyRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/VerifyPresentationResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/resource/create/{did}": { - "post": { - "tags": ["Resource"], - "summary": "Create a DID-Linked Resource.", - "description": "This endpoint creates a DID-Linked Resource. As input, it can take the DID identifier and the resource parameters via a form, or the fully-assembled resource itself.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier to link the resource to.", - "schema": { - "type": "string" - }, - "required": true - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CreateResourceRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateResourceRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ResourceMetadata" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/resource/search/{did}": { - "get": { - "tags": ["Resource"], - "summary": "Get a DID-Linked Resource.", - "description": "This endpoint returns the DID-Linked Resource for a given DID identifier and resource identifier.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier", - "schema": { - "type": "string" - }, - "required": true, - "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - { - "in": "query", - "name": "resourceId", - "description": "Fetch a DID-Linked Resource by Resource ID unique identifier. Since this is a unique identifier, other Resource query parameters are not required. See DID-Linked Resources for more details.", - "schema": { - "type": "string", - "format": "uuid" - }, - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - { - "in": "query", - "name": "resourceName", - "description": "Filter a DID-Linked Resource query by Resource Name. See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "cheqd-issuer-logo" - }, - { - "in": "query", - "name": "resourceType", - "description": "Filter a DID-Linked Resource query by Resource Type. See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "CredentialArtwork" - }, - { - "in": "query", - "name": "resourceVersion", - "description": "Filter a DID-Linked Resource query by Resource Version, which is an optional free-text field used by issuers (e.g., \"v1\", \"Final Version\", \"1st January 1970\" etc). See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "v1" - }, - { - "in": "query", - "name": "resourceVersionTime", - "description": "Filter a DID-Linked Resource query which returns the closest version of the Resource *at* or *before* specified time. See DID-Linked Resources for more details.", - "schema": { - "type": "string", - "format": "date-time" - }, - "example": "1970-01-01T00:00:00Z" - }, - { - "in": "query", - "name": "checksum", - "description": "Request integrity check against a given DID-Linked Resource by providing a SHA-256 checksum hash. See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "dc64474d062ed750a66bad58cb609928de55ed0d81defd231a4a4bf97358e9ed" - }, - { - "in": "query", - "name": "resourceMetadata", - "description": "Return only metadata of DID-Linked Resource instead of actual DID-Linked Resource. Mutually exclusive with some of the other parameters.", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "any": { - "schema": { - "type": "object" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - } - }, - "components": { - "schemas": { - "AlsoKnownAs": { - "type": "object", - "properties": { - "alsoKnownAs": { - "type": "array", - "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", - "items": { - "type": "object", - "properties": { - "uri": { - "type": "string", - "format": "uri", - "description": "URI where the DID-Linked Resource can be fetched from. Can be any type of URI (e.g., DID, HTTPS, IPFS, etc.)" - }, - "description": { - "type": "string", - "description": "Optional description of the URI." - } - } - } - } - } - }, - "CredentialRequest": { - "description": "Input fields for the creating a Verifiable Credential.", - "type": "object", - "additionalProperties": false, - "properties": { - "issuerDid": { - "description": "DID of the Verifiable Credential issuer. This needs to be a `did:cheqd` DID.", - "type": "string", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "subjectDid": { - "description": "DID of the Verifiable Credential holder/subject. This needs to be a `did:key` DID.", - "type": "string", - "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" - }, - "attributes": { - "description": "JSON object containing the attributes to be included in the credential.", - "type": "object", - "example": { - "name": "Bob", - "gender": "male" - } - }, - "@context": { - "description": "Optional properties to be included in the `@context` property of the credential.", - "type": "array", - "items": { - "type": "string" - }, - "example": ["https://schema.org/schema.jsonld", "https://veramo.io/contexts/profile/v1"] - }, - "type": { - "description": "Optional properties to be included in the `type` property of the credential.", - "type": "array", - "items": { - "type": "string" - }, - "example": ["Person"] - }, - "expirationDate": { - "description": "Optional expiration date according to the VC Data Model specification.", - "type": "string", - "format": "date-time", - "example": "2023-06-08T13:49:28.000Z" - }, - "format": { - "description": "Format of the Verifiable Credential. Defaults to VC-JWT.", - "type": "string", - "enum": ["jwt", "jsonld"], - "example": "jwt" - }, - "credentialStatus": { - "description": "Optional `credentialStatus` properties for VC revocation or suspension. Takes `statusListName` and `statusListPurpose` as inputs.", - "type": "object", - "required": ["statusPurpose", "statusListName"], - "properties": { - "statusPurpose": { - "type": "string", - "enum": ["revocation", "suspension"] - }, - "statusListName": { - "type": "string" - }, - "statusListIndex": { - "type": "number" - }, - "statusListVersion": { - "type": "string", - "format": "date-time" - }, - "statusListRangeStart": { - "type": "number" - }, - "statusListRangeEnd": { - "type": "number" - }, - "indexNotIn": { - "type": "number" - } - }, - "example": { - "statusPurpose": "revocation", - "statusListName": "employee-credentials" - } - } - }, - "required": ["issuerDid", "subjectDid", "attributes"], - "example": { - "issuerDid": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "subjectDid": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", - "attributes": { - "gender": "male", - "name": "Bob" - }, - "@context": ["https://schema.org"], - "type": ["Person"], - "format": "jwt", - "credentialStatus": { - "statusPurpose": "revocation", - "statusListName": "employee-credentials", - "statusListIndex": 10 - } - } - }, - "Credential": { - "description": "Input fields for revoking/suspending a Verifiable Credential.", - "type": "object", - "additionalProperties": false, - "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "https://www.w3.org/2018/credentials/v1", - "https://schema.org", - "https://veramo.io/contexts/profile/v1" - ] - }, - "type": { - "type": "array", - "items": { - "type": "string" - }, - "example": ["VerifiableCredential", "Person"] - }, - "expirationDate": { - "type": "string", - "format": "date-time", - "example": "2023-06-08T13:49:28.000Z" - }, - "issuer": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "DID", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - } - } - }, - "credentialSubject": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "DID", - "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" - } - } - }, - "credentialStatus": { - "type": "object", - "properties": { - "id": { - "type": "string", - "example": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20" - }, - "statusListIndex": { - "type": "number", - "example": 20 - }, - "statusPurpose": { - "type": "string", - "enum": ["revocation", "suspension"], - "example": "suspension" - }, - "type": { - "type": "string", - "enum": ["StatusList2021Entry"] - } - } - }, - "issuanceDate": { - "type": "string", - "format": "date-time", - "example": "2023-06-08T13:49:28.000Z" - }, - "proof": { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "jwt": { - "type": "string" - } - }, - "example": { - "type": "JwtProof2020", - "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg" - } - } - }, - "example": { - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://schema.org", - "https://veramo.io/contexts/profile/v1" - ], - "credentialSubject": { - "gender": "male", - "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", - "name": "Bob" - }, - "credentialStatus": { - "id": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20", - "statusIndex": 20, - "statusPurpose": "suspension", - "type": "StatusList2021Entry" - }, - "issuanceDate": "2023-06-08T13:49:28.000Z", - "issuer": { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "proof": { - "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg", - "type": "JwtProof2020" - }, - "type": ["VerifiableCredential", "Person"] - } - }, - "CredentialRevokeRequest": { - "type": "object", - "properties": { - "credential": { - "description": "Verifiable Credential to be revoked as a VC-JWT string or a JSON object.", - "oneOf": [ - { - "type": "object" - }, - { - "type": "string" - } - ] - }, - "symmetricKey": { - "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource. Required if the StatusList2021 DID-Linked Resource is encrypted.", - "type": "string" - } - } - }, - "RevocationResult": { - "properties": { - "revoked": { - "type": "boolean", - "example": true - } - } - }, - "SuspensionResult": { - "properties": { - "suspended": { - "type": "boolean", - "example": true - } - } - }, - "UnsuspensionResult": { - "properties": { - "unsuspended": { - "type": "boolean", - "example": true - } - } - }, - "CredentialVerifyRequest": { - "type": "object", - "properties": { - "credential": { - "description": "Verifiable Credential to be verified as a VC-JWT string or a JSON object.", - "type": "object" - }, - "policies": { - "description": "Custom verification policies to execute when verifying credential.", - "type": "object", - "properties": { - "issuanceDate": { - "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "expirationDate": { - "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "audience": { - "description": "Policy to skip the audience check when set to `false`.", - "type": "boolean", - "default": false - } - } - } - } - }, - "VerifyPresentationResult": { - "type": "object", - "properties": { - "verified": { - "type": "boolean" - }, - "issuer": { - "type": "string" - }, - "signer": { - "type": "object" - }, - "jwt": { - "type": "string" - }, - "verifiableCredential": { - "type": "object" - } - } - }, - "VerifyCredentialResult": { - "type": "object", - "properties": { - "verified": { - "type": "boolean" - }, - "issuer": { - "type": "string" - }, - "signer": { - "type": "object" - }, - "jwt": { - "type": "string" - }, - "verifiableCredential": { - "type": "object" - } - }, - "example": { - "verified": true, - "polices": {}, - "issuer": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "signer": { - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", - "type": "Ed25519VerificationKey2018" - } - } - }, - "PresentationCreateRequest": { - "type": "object", - "required": ["credentials"], - "properties": { - "credentials": { - "description": "Verifiable Credentials to be used for VP-JWT creation as a VP-JWT strings or a JSON objectsf.", - "type": "array", - "items": { - "type": "object" - } - }, - "holderDid": { - "description": "DID of holder", - "type": "string" - }, - "verifierDid": { - "description": "DID of verifier", - "type": "string" - } - } - }, - "PresentationVerifyRequest": { - "type": "object", - "required": ["presentation"], - "properties": { - "presentation": { - "description": "Verifiable Presentation to be verified as a VP-JWT string or a JSON object.", - "type": "object" - }, - "verifierDid": { - "description": "Provide an optional verifier DID (also known as 'domain' parameter), if the verifier DID in the presentation is not managed in the wallet.", - "type": "string" - }, - "makeFeePayment": { - "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", - "type": "boolean", - "default": false - }, - "policies": { - "description": "Custom verification policies to execute when verifying presentation.", - "type": "object", - "properties": { - "issuanceDate": { - "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "expirationDate": { - "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "audience": { - "description": "Policy to skip the audience check when set to `false`.", - "type": "boolean", - "default": false - } - } - } - } - }, - "CredentialStatusCreateBody": { - "allOf": [ - { - "type": "object", - "required": ["did", "statusListName"], - "properties": { - "did": { - "description": "DID of the StatusList2021 publisher.", - "type": "string", - "format": "uri" - }, - "statusListName": { - "description": "The name of the StatusList2021 DID-Linked Resource to be created.", - "type": "string" - }, - "length": { - "description": "The length of the status list to be created. The default and minimum length is 140000 which is 16kb.", - "type": "integer", - "minimum": 0, - "exclusiveMinimum": true, - "default": 140000 - }, - "encoding": { - "description": "The encoding format of the StatusList2021 DiD-Linked Resource to be created.", - "type": "string", - "default": "base64url", - "enum": ["base64url", "base64", "hex"] - }, - "statusListVersion": { - "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - { - "$ref": "#/components/schemas/AlsoKnownAs" - } - ] - }, - "CredentialStatusCreateUnencryptedRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCreateBody" - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials", - "length": 140000, - "encoding": "base64url" - } - }, - "CredentialStatusUnencryptedResult": { - "type": "object", - "properties": { - "resource": { - "type": "object", - "properties": { - "StatusList2021": { - "type": "object", - "properties": { - "encodedList": { - "type": "string", - "example": "H4sIAAAAAAAAA-3BAQ0AAADCoPdPbQ8HFAAAAAAAAAAAAAAAAAAAAADwaDhDr_xcRAAA" - }, - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "validFrom": { - "type": "string", - "format": "date-time", - "example": "2023-06-26T11:45:19.349Z" - } - } - }, - "metadata": { - "type": "object", - "properties": { - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "encoding": { - "type": "string", - "example": "base64url" - }, - "encrypted": { - "type": "boolean", - "example": false - } - } - } - } - }, - "resourceMetadata": { - "type": "object", - "example": { - "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceName": "cheqd-employee-credentials", - "resourceType": "StatusList2021Revocation", - "mediaType": "application/json", - "resourceVersion": "1.0.0", - "created": "2023-06-26T11:45:20Z", - "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", - "previousVersionId": null, - "nextVersionId": null - } - } - } - }, - "CredentialStatusCreateUnencryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "created": { - "type": "boolean", - "example": true - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" - } - ] - }, - "CredentialStatusEncryptedPaymentConditionsBody": { - "type": "object", - "properties": { - "feePaymentAddress": { - "description": "The cheqd/Cosmos payment address where payments to unlock the encrypted StatusList2021 DID-Linked Resource need to be sent.", - "type": "string", - "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" - }, - "feePaymentAmount": { - "description": "Amount in CHEQ tokens to unlock the encrypted StatusList2021 DID-Linked Resource.", - "type": "number", - "minimum": 0, - "exclusiveMinimum": true, - "default": 20 - }, - "feePaymentWindow": { - "description": "Time window (in minutes) within which the payment to unlock the encrypted StatusList2021 DID-Linked Resource is considered valid.", - "type": "number", - "minimum": 0, - "exclusiveMinimum": true, - "default": 10 - } - } - }, - "CredentialStatusEncryptedPaymentConditionsJson": { - "type": "object", - "properties": { - "paymentConditions": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" - } - ] - } - } - }, - "CredentialStatusCreateEncryptedFormRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCreateBody" - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" - }, - { - "type": "object", - "required": ["feePaymentAddress", "feePaymentAmount", "feePaymentWindow"] - } - ] - }, - "CredentialStatusCreateEncryptedJsonRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCreateBody" - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" - }, - { - "type": "object", - "required": ["paymentConditions"] - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials-encrypted", - "paymentConditions": [ - { - "feePaymentAddress": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg", - "feePaymentAmount": 20, - "feePaymentWindow": 10 - } - ] - } - }, - "CredentialStatusEncryptedResult": { - "type": "object", - "properties": { - "resource": { - "type": "object", - "properties": { - "StatusList2021": { - "type": "object", - "properties": { - "encodedList": { - "type": "string", - "example": "496fdfbeb745b4db03fcdb40566f9c4c4a1c0f184b31255e641b6e7bdfb9b6946c12be87ca3763be0393c00b67ac1e8737c106b32f46ef59c765754415b5e8cc7c65fccaa3374620430ea476301a5e0dd63340e7a27a68bc627518471f22e4a2" - }, - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "validFrom": { - "type": "string", - "format": "date-time", - "example": "2023-06-26T11:45:19.349Z" - } - } - }, - "metadata": { - "type": "object", - "properties": { - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "encoding": { - "type": "string", - "example": "base64url" - }, - "encrypted": { - "type": "boolean", - "example": true - }, - "encryptedSymmetricKey": { - "type": "string", - "example": "b11182dc524b8181f9a6aef4c4ad0a1c14e40033b9112dffd8d1bcf6cc3b85abc07ded2205ee94068a99f4202502cb0855f322583fa6ce1534d3a05bf36891766ea2c5f90a982b3040680762977d404d758a2370224a239c8279aa7d21e980931c42055b17ca4c7dbffa4782480a8b6279cf989b2f166d5fdb4b2c1b5a63927200000000000000203018dcaba26df45a415bb599218b27ca853a70289d7a3ed3ed0e3730452e8f8d9af91b6e71312565d2c069341f6660ab" - }, - "paymentConditions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "feePaymentAddress": { - "type": "string", - "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" - }, - "feePaymentAmount": { - "type": "string", - "example": "20000000000ncheq" - }, - "intervalInSeconds": { - "type": "number", - "example": 600 - }, - "type": { - "type": "string", - "example": "timelockPayment" - } - } - } - } - } - }, - "resourceMetadata": { - "type": "object", - "example": { - "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceName": "cheqd-revocation-encrypted-1", - "resourceType": "StatusList2021Revocation", - "mediaType": "application/json", - "resourceVersion": "2023-06-26T11:45:19.349Z", - "created": "2023-06-26T11:45:20Z", - "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", - "previousVersionId": null, - "nextVersionId": null - } - }, - "symmetricKey": { - "type": "string", - "example": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" - } - } - } - } - }, - "CredentialStatusCreateEncryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "created": { - "type": "boolean", - "example": true - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedResult" - } - ] - }, - "CredentialStatusUpdateBody": { - "type": "object", - "required": ["did", "statusListName", "indices"], - "properties": { - "did": { - "description": "DID of the StatusList2021 publisher.", - "type": "string", - "format": "uri" - }, - "statusListName": { - "description": "The name of the StatusList2021 DID-Linked Resource to be updated.", - "type": "string" - }, - "indices": { - "description": "List of credential status indices to be updated. The indices must be in the range of the status list.", - "type": "array", - "items": { - "type": "integer", - "minimum": 0, - "exclusiveMinimum": false - } - }, - "statusListVersion": { - "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - "CredentialStatusUpdateUnencryptedRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUpdateBody" - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials", - "indices": [10, 3199, 12109, 130999] - } - }, - "CredentialStatusUpdateUnencryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "updated": { - "type": "boolean", - "example": true - } - } - }, - { - "oneOf": [ - { - "$ref": "#/components/schemas/RevocationResult" - }, - { - "$ref": "#/components/schemas/SuspensionResult" - }, - { - "$ref": "#/components/schemas/UnsuspensionResult" - } - ] - }, - { - "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" - } - ] - }, - "CredentialStatusUpdateEncryptedFormRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUpdateBody" - }, - { - "type": "object", - "required": ["symmetricKey"], - "properties": { - "symmetricKey": { - "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" - } - ] - }, - "CredentialStatusUpdateEncryptedJsonRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUpdateBody" - }, - { - "type": "object", - "required": ["symmetricKey"], - "properties": { - "symmetricKey": { - "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials-encrypted", - "indices": [10, 3199, 12109, 130999], - "symmetricKey": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" - } - }, - "CredentialStatusUpdateEncryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "updated": { - "type": "boolean", - "example": true - } - } - }, - { - "oneOf": [ - { - "$ref": "#/components/schemas/RevocationResult" - }, - { - "$ref": "#/components/schemas/SuspensionResult" - }, - { - "$ref": "#/components/schemas/UnsuspensionResult" - } - ] - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedResult" - } - ] - }, - "CredentialStatusCheckRequest": { - "type": "object", - "required": ["did", "statusListName", "index"], - "properties": { - "did": { - "description": "DID of the StatusList2021 publisher.", - "type": "string", - "format": "uri" - }, - "statusListName": { - "description": "The name of the StatusList2021 DID-Linked Resource to be checked.", - "type": "string" - }, - "index": { - "description": "Credential status index to be checked for revocation or suspension.", - "type": "integer", - "minimum": 0, - "exclusiveMinimum": false - }, - "makeFeePayment": { - "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", - "type": "boolean", - "default": true - } - } - }, - "CredentialStatusCheckResult": { - "oneOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCheckRevocationResult" - }, - { - "$ref": "#/components/schemas/CredentialStatusCheckSuspensionResult" - } - ] - }, - "CredentialStatusCheckRevocationResult": { - "type": "object", - "properties": { - "checked": { - "type": "boolean", - "example": true - }, - "revoked": { - "type": "boolean", - "example": false - } - } - }, - "CredentialStatusCheckSuspensionResult": { - "type": "object", - "properties": { - "checked": { - "type": "boolean", - "example": true - }, - "suspended": { - "type": "boolean", - "example": false - } - } - }, - "CredentialStatusListSearchResult": { - "allOf": [ - { - "type": "object", - "properties": { - "found": { - "type": "boolean", - "example": true - } - } - }, - { - "oneOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedResult" - } - ] - } - ] - }, - "KeyImportRequest": { - "type": "object", - "properties": { - "alias": { - "type": "string" - }, - "type": { - "type": "string", - "enum": ["Ed25519", "Secp256k1"] - }, - "privateKeyHex": { - "type": "string" - } - } - }, - "KeyResult": { - "type": "object", - "properties": { - "kid": { - "type": "string" - }, - "type": { - "type": "string", - "enum": ["Ed25519", "Secp256k1"] - }, - "publicKeyHex": { - "type": "string" - } - } - }, - "DidDocument": { - "description": "This input field contains either a complete DID document, or an incremental change (diff) to a DID document. See Universal DID Registrar specification.", - "type": "object", - "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - } - }, - "id": { - "type": "string" - }, - "controllers": { - "type": "array", - "items": { - "type": "string" - } - }, - "verificationMethod": { - "type": "array", - "items": { - "$ref": "#/components/schemas/VerificationMethod" - } - }, - "service": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "authentication": { - "type": "array", - "items": { - "type": "string" - } - }, - "assertionMethod": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityInvocation": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityDelegation": { - "type": "array", - "items": { - "type": "string" - } - }, - "keyAgreement": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "@context": ["https://www.w3.org/ns/did/v1"], - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "controller": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0"], - "verificationMethod": [ - { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "type": "Ed25519VerificationKey2018", - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "publicKeyBase58": "z6MkkVbyHJLLjdjU5B62DaJ4mkdMdUkttf9UqySSkA9bVTeZ" - } - ], - "authentication": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1"], - "service": [ - { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", - "type": "LinkedDomains", - "serviceEndpoint": ["https://example.com"] - } - ] - } - }, - "DidDocumentWithoutVerificationMethod": { - "type": "object", - "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - } - }, - "id": { - "type": "string" - }, - "controllers": { - "type": "array", - "items": { - "type": "string" - } - }, - "service": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "authentication": { - "type": "array", - "items": { - "type": "string" - } - }, - "assertionMethod": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityInvocation": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityDelegation": { - "type": "array", - "items": { - "type": "string" - } - }, - "keyAgreement": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "@context": ["https://www.w3.org/ns/did/v1"], - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "controller": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0"], - "authentication": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1"], - "service": [ - { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", - "type": "LinkedDomains", - "serviceEndpoint": ["https://example.com"] - } - ] - } - }, - "DidCreateRequestFormBased": { - "type": "object", - "properties": { - "network": { - "description": "Network to create the DID on (testnet or mainnet)", - "type": "string", - "enum": ["testnet", "mainnet"] - }, - "identifierFormatType": { - "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", - "type": "string", - "enum": ["uuid", "base58btc"] - }, - "verificationMethodType": { - "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", - "type": "string", - "enum": ["Ed25519VerificationKey2018", "JsonWebKey2020", "Ed25519VerificationKey2020"] - }, - "service": { - "description": "It's a list of special objects which are designed to build the actual service. It's almost the same as in DID Core specification, but instead of `id` it utilises `idFragment` field for making the right `id` for each service. !!! WARN. Cause swagger-ui does not handle x-ww-form based arrays correctly, please frame all your services in brackets while using swagger UI. !!!", - "type": "array", - "items": { - "type": "object", - "properties": { - "idFragment": { - "type": "string" - }, - "type": { - "type": "string" - }, - "serviceEndpoint": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "example": [ - { - "idFragment": "service-1", - "type": "LinkedDomains", - "serviceEndpoint": ["https://example.com"] - } - ] - }, - "key": { - "description": "The unique identifier in hexadecimal public key format used in the verification method to create the DID.", - "type": "string" - }, - "@context": { - "type": "array", - "items": { - "type": "string" - }, - "example": ["https://www.w3.org/ns/did/v1"] - } - } - }, - "DidCreateRequestJson": { - "type": "object", - "properties": { - "network": { - "description": "Network to create the DID on (testnet or mainnet)", - "type": "string", - "enum": ["testnet", "mainnet"] - }, - "identifierFormatType": { - "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", - "type": "string", - "enum": ["uuid", "base58btc"] - }, - "assertionMethod": { - "description": "Usually a reference to a Verification Method. An Assertion Method is required to issue JSON-LD credentials. See DID Core specification for more details.", - "type": "boolean", - "default": true - }, - "options": { - "type": "object", - "properties": { - "key": { - "type": "string", - "example": "8255ddadd75695e01f3d98fcec8ccc7861a030b317d4326b0e48a4d579ddc43a" - }, - "verificationMethodType": { - "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", - "type": "string", - "enum": ["Ed25519VerificationKey2018", "JsonWebKey2020", "Ed25519VerificationKey2020"] - } - } - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocumentWithoutVerificationMethod" - } - } - }, - "DidImportRequest": { - "type": "object", - "properties": { - "did": { - "type": "string", - "description": "DID to be imported", - "format": "uri", - "required": true - }, - "keys": { - "type": "array", - "description": "List of keys required to import the DID", - "required": true, - "items": { - "$ref": "#/components/schemas/KeyImportRequest" - } - } - } - }, - "PresentationCreateResult": { - "type": "object", - "properties": { - "vp": { - "type": "object", - "description": "Verifiable Presentation which could be provided to the verifier." - }, - "nbf": { - "type": "integer", - "description": "Unix timestamp of the earliest time that the Verifiable Presentation is valid." - }, - "iss": { - "type": "string", - "description": "DID of the issuer of the Verifiable Presentation. (Here it's supposed to be a holder DID)" - }, - "aud": { - "type": "array", - "items": { - "type": "string" - }, - "description": "DID of the verifier of the Verifiable Presentation." - } - }, - "example": { - "vp": { - "@context": ["https://www.w3.org/2018/credentials/v1"], - "type": ["VerifiablePresentation"], - "verifiableCredential": [ - "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc2NoZW1hLm9yZy9zY2hlbWEuanNvbmxkIiwiaHR0cHM6Ly92ZXJhbW8uaW8vY29udGV4dHMvcHJvZmlsZS92MSIsImh0dHBzOi8vdzNpZC5vcmcvdmMtc3RhdHVzLWxpc3QtMjAyMS92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiUGVyc29uIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7Im5hbWUiOiJCb2IiLCJnZW5kZXIiOiJtYWxlIn0sImNyZWRlbnRpYWxTdGF0dXMiOnsiaWQiOiJodHRwczovL3Jlc29sdmVyLmNoZXFkLm5ldC8xLjAvaWRlbnRpZmllcnMvZGlkOmNoZXFkOnRlc3RuZXQ6OTBkNWMxNDEtNzI0Zi00N2FkLTlhZTctYTdjMzNhOWU1NjQzP3Jlc291cmNlTmFtZT1zdXNwZW5zaW9uRW4mcmVzb3VyY2VUeXBlPVN0YXR1c0xpc3QyMDIxU3VzcGVuc2lvbiMxMzMzOCIsInR5cGUiOiJTdGF0dXNMaXN0MjAyMUVudHJ5Iiwic3RhdHVzUHVycG9zZSI6InN1c3BlbnNpb24iLCJzdGF0dXNMaXN0SW5kZXgiOiIxMzMzOCJ9fSwic3ViIjoiZGlkOmtleTp6Nk1raGFYZ0JaRHZvdERrTDUyNTdmYWl6dGlHaUMyUXRLTEdwYm5uRUd0YTJkb0siLCJuYmYiOjE3MDA0NzM0MTYsImlzcyI6ImRpZDpjaGVxZDp0ZXN0bmV0OjkwZDVjMTQxLTcyNGYtNDdhZC05YWU3LWE3YzMzYTllNTY0MyJ9.-14Ril1pZEy2HEEo48gTJr2yOtGxBhUGTFmzVdjAtyhFRsW5zZg9onHt6V9JQ8BaiYBlTkP9GzTnJ-O6hdiyCw" - ] - }, - "nbf": 1700744275, - "iss": "did:cheqd:testnet:4b846d0f-2f6c-4ab6-9fe2-5b8db301c83c", - "aud": ["did:cheqd:testnet:8c71e9b6-c5a3-4250-8c58-fa591533cd22"] - } - }, - "DidResult": { - "type": "object", - "properties": { - "did": { - "type": "string" - }, - "controllerKeyId": { - "type": "string" - }, - "keys": { - "type": "array", - "items": { - "type": "object" - } - }, - "services": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - } - } - }, - "DidUpdateResponse": { - "type": "object", - "properties": { - "did": { - "type": "string" - }, - "controllerKeyId": { - "type": "string", - "description": "The default key id of which is the key associated with the first verificationMethod" - }, - "keys": { - "type": "array", - "description": "The list of keys associated with the list of verificationMethod's of DIDDocument", - "items": { - "type": "object" - } - }, - "services": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "controllerKeyRefs": { - "type": "array", - "description": "The list of keyRefs which were used for signing the transaction", - "items": { - "type": "string" - } - }, - "controllerKeys": { - "type": "array", - "description": "The list of all possible keys, inlcuding all controller's keys", - "items": { - "type": "string" - } - } - } - }, - "VerificationMethod": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string" - }, - "controller": { - "type": "string" - }, - "publicKeyMultibase": { - "type": "string" - }, - "publicKeyJwk": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "id": "did:cheqd:testnet :7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", - "type": "Ed25519VerificationKey2018" - } - }, - "Service": { - "description": "Communicating or interacting with the DID subject or associated entities via one or more service endpoints. See DID Core specification for more details.", - "type": "object", - "properties": { - "id": { - "description": "DID appended with Service fragment ID (e.g., `#service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`)", - "type": "string", - "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1" - }, - "type": { - "description": "Service type as defined in DID Specification Registries.", - "type": "string", - "example": "LinkedDomains" - }, - "serviceEndpoint": { - "description": "Service endpoint as defined in DID Core Specification.", - "type": "array", - "items": { - "type": "string", - "example": "https://example.com" - } - } - } - }, - "DidUpdateRequest": { - "type": "object", - "properties": { - "did": { - "description": "DID identifier to be updated.", - "type": "string", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "service": { - "type": "array", - "description": "Service section of the DID Document.", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "verificationMethod": { - "type": "array", - "description": "Verification Method section of the DID Document.", - "items": { - "$ref": "#/components/schemas/VerificationMethod" - } - }, - "authentication": { - "description": "Authentication section of the DID Document.", - "type": "array", - "items": { - "type": "string" - } - }, - "publicKeyHexs": { - "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", - "type": "array", - "items": { - "type": "string" - } - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - } - } - }, - "DidDeactivateRequest": { - "type": "object", - "properties": { - "publicKeyHexs": { - "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "CreateResourceRequest": { - "description": "Input fields for DID-Linked Resource creation.", - "type": "object", - "additionalProperties": false, - "required": ["name", "type", "data", "encoding"], - "properties": { - "data": { - "description": "Encoded string containing the data to be stored in the DID-Linked Resource.", - "type": "string" - }, - "encoding": { - "description": "Encoding format used to encode the data.", - "type": "string", - "enum": ["base64url", "base64", "hex"] - }, - "name": { - "description": "Name of DID-Linked Resource.", - "type": "string" - }, - "type": { - "description": "Type of DID-Linked Resource. This is NOT the same as the media type, which is calculated automatically ledger-side.", - "type": "string" - }, - "alsoKnownAs": { - "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", - "type": "array", - "items": { - "type": "object", - "properties": { - "uri": { - "type": "string" - }, - "description": { - "type": "string" - } - } - } - }, - "version": { - "description": "Optional field to assign a human-readable version in the DID-Linked Resource.", - "type": "string" - }, - "publicKeyHexs": { - "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "data": "SGVsbG8gV29ybGQ=", - "encoding": "base64url", - "name": "ResourceName", - "type": "TextDocument" - } - }, - "ResourceList": { - "type": "object", - "properties": { - "@context": { - "type": "string", - "example": "https://w3id.org/did-resolution/v1" - }, - "contentMetadata": { - "type": "object" - }, - "contentStream": { - "type": "object" - }, - "dereferencingMetadata": { - "$ref": "#/components/schemas/DereferencingMetadata" - } - } - }, - "DereferencingMetadata": { - "type": "object", - "properties": { - "contentType": { - "type": "string", - "example": "application/did+ld+json" - }, - "did": { - "$ref": "#/components/schemas/DidProperties" - }, - "retrieved": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - } - } - }, - "DidResolution": { - "type": "object", - "properties": { - "@context": { - "type": "string", - "example": "https://w3id.org/did-resolution/v1" - }, - "didDidResolutionMetadata": { - "$ref": "#/components/schemas/DidResolutionMetadata" - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - }, - "didDocumentMetadata": { - "$ref": "#/components/schemas/DidDocumentMetadata" - } - } - }, - "DeactivatedDidResolution": { - "type": "object", - "properties": { - "@context": { - "type": "string", - "example": "https://w3id.org/did-resolution/v1" - }, - "didDidResolutionMetadata": { - "$ref": "#/components/schemas/DidResolutionMetadata" - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - }, - "didDocumentMetadata": { - "$ref": "#/components/schemas/DeactivatedDidDocumentMetadata" - } - } - }, - "DidDocumentMetadata": { - "type": "object", - "properties": { - "created": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "deactivated": { - "type": "boolean", - "example": false - }, - "updated": { - "type": "string", - "example": "2021-09-10T12:00:00Z" - }, - "versionId": { - "type": "string", - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - "linkedResourceMetadata": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ResourceMetadata" - } - } - } - }, - "DeactivatedDidDocumentMetadata": { - "type": "object", - "properties": { - "created": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "deactivated": { - "type": "boolean", - "example": true - }, - "updated": { - "type": "string", - "example": "2021-09-10T12:00:00Z" - }, - "versionId": { - "type": "string", - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - "linkedResourceMetadata": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ResourceMetadata" - } - } - } - }, - "ResourceMetadata": { - "type": "object", - "properties": { - "resourceURI": { - "type": "string", - "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47/resources/398cee0a-efac-4643-9f4c-74c48c72a14b" - }, - "resourceCollectionId": { - "type": "string", - "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" - }, - "resourceId": { - "type": "string", - "example": "398cee0a-efac-4643-9f4c-74c48c72a14b" - }, - "resourceName": { - "type": "string", - "example": "cheqd-issuer-logo" - }, - "resourceType": { - "type": "string", - "example": "CredentialArtwork" - }, - "mediaType": { - "type": "string", - "example": "image/png" - }, - "resourceVersion": { - "type": "string", - "example": "1.0" - }, - "checksum": { - "type": "string", - "example": "a95380f460e63ad939541a57aecbfd795fcd37c6d78ee86c885340e33a91b559" - }, - "created": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "nextVersionId": { - "type": "string", - "example": "d4829ac7-4566-478c-a408-b44767eddadc" - }, - "previousVersionId": { - "type": "string", - "example": "ad7a8442-3531-46eb-a024-53953ec6e4ff" - } - } - }, - "DidResolutionMetadata": { - "type": "object", - "properties": { - "contentType": { - "allOf": [ - { - "$ref": "#/components/schemas/ContentType" - } - ], - "example": "application/did+ld+json" - }, - "retrieved": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "did": { - "$ref": "#/components/schemas/DidProperties" - } - } - }, - "ContentType": { - "type": "string", - "enum": ["application/did+json", "application/did+ld+json", "application/ld+json", "application/json"] - }, - "DidProperties": { - "type": "object", - "properties": { - "didString": { - "type": "string", - "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" - }, - "method": { - "type": "string", - "example": "cheqd" - }, - "methodSpecificId": { - "type": "string", - "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" - } - } - }, - "Customer": { - "type": "object", - "properties": { - "customerId": { - "type": "string", - "example": "6w5drpiiwhhs" - }, - "address": { - "type": "string", - "example": "cheqd1wgsvqwlkmdp60f4dek26ak0sjw6au3ytd3pz7f" - } - } - }, - "AccountCreateRequest": { - "type": "object", - "properties": { - "user": { - "type": "object", - "properties": { - "primaryEmail": { - "type": "string" - } - } - } - } - }, - "InvalidRequest": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "InvalidRequest" - } - } - }, - "InternalError": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Internal Error" - } - } - }, - "UnauthorizedError": { - "description": "Access token is missing or invalid", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Unauthorized Error" - } - } - } - } - } -} + "openapi": "3.0.0", + "info": { + "title": "Credential Service API for cheqd network", + "version": "2.0.0", + "description": "API service to create and manage DIDs, Verifiable Credentials, and DID-Linked Resources", + "contact": { + "name": "Cheqd Foundation Limited", + "url": "https://github.com/cheqd/credential-service", + "email": "support-github@cheqd.io" + }, + "license": { + "name": "Apache 2.0", + "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" + } + }, + "tags": [ + { + "name": "Account" + }, + { + "name": "Key" + }, + { + "name": "DID" + }, + { + "name": "Resource" + }, + { + "name": "Credential" + }, + { + "name": "Presentation" + }, + { + "name": "Credential Status" + } + ], + "externalDocs": { + "description": "Credential Service API Documentation", + "url": "https://docs.cheqd.io/identity" + }, + "paths": { + "/account": { + "get": { + "tags": [ + "Account" + ], + "summary": "Fetch custodian-mode client details.", + "description": "This endpoint returns the custodian-mode client details for authenticated users.", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Customer" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/account/idtoken": { + "get": { + "tags": [ + "Account" + ], + "summary": "Fetch IdToken.", + "description": "This endpoint returns IdToken as JWT with list of user roles inside", + "deprecated": true, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "idToken": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/account/create": { + "post": { + "tags": [ + "Account" + ], + "summary": "Create an client for an authenticated user.", + "description": "This endpoint creates a client in the custodian-mode for an authenticated user", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/AccountCreateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "idToken": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/create/unencrypted": { + "post": { + "tags": [ + "Credential Status" + ], + "summary": "Create an unencrypted StatusList2021 credential status list.", + "description": "This endpoint creates an unencrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", + "required": true, + "schema": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/create/encrypted": { + "post": { + "tags": [ + "Credential Status" + ], + "summary": "Create an encrypted StatusList2021 credential status list.", + "description": "This endpoint creates an encrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", + "required": true, + "schema": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateEncryptedFormRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateEncryptedJsonRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateEncryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/update/unencrypted": { + "post": { + "tags": [ + "Credential Status" + ], + "summary": "Update an existing unencrypted StatusList2021 credential status list.", + "parameters": [ + { + "in": "query", + "name": "statusAction", + "description": "The update action to be performed on the unencrypted status list, can be revoke, suspend or reinstate", + "required": true, + "schema": { + "type": "string", + "enum": [ + "revoke", + "suspend", + "reinstate" + ] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/update/encrypted": { + "post": { + "tags": [ + "Credential Status" + ], + "summary": "Update an existing encrypted StatusList2021 credential status list.", + "parameters": [ + { + "in": "query", + "name": "statusAction", + "description": "The update action to be performed on the encrypted status list, can be revoke, suspend or reinstate", + "required": true, + "schema": { + "type": "string", + "enum": [ + "revoke", + "suspend", + "reinstate" + ] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedFormRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedJsonRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/check": { + "post": { + "tags": [ + "Credential Status" + ], + "summary": "Check a StatusList2021 index for a given Verifiable Credential.", + "description": "This endpoint checks a StatusList2021 index for a given Verifiable Credential and reports whether it is revoked or suspended. It offers a standalone method for checking an index without passing the entire Verifiable Credential or Verifiable Presentation.", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension.", + "required": true, + "schema": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCheckRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCheckRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCheckResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/search": { + "get": { + "tags": [ + "Credential Status" + ], + "summary": "Fetch StatusList2021 DID-Linked Resource based on search criteria.", + "parameters": [ + { + "in": "query", + "name": "did", + "description": "The DID of the issuer of the status list.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension.", + "schema": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ] + } + }, + { + "in": "query", + "name": "statusListName", + "description": "The name of the StatusList2021 DID-Linked Resource.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusListSearchResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/issue": { + "post": { + "tags": [ + "Credential" + ], + "summary": "Issue a Verifiable Credential", + "description": "This endpoint issues a Verifiable Credential. As input it takes the list of issuerDid, subjectDid, attributes, and other parameters of the credential to be issued.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Credential" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/verify": { + "post": { + "tags": [ + "Credential" + ], + "summary": "Verify a Verifiable Credential.", + "description": "This endpoint verifies a Verifiable Credential passed to it. As input, it can take the VC-JWT as a string or the entire credential itself.", + "operationId": "verify", + "parameters": [ + { + "in": "query", + "name": "verifyStatus", + "description": "If set to `true` the verification will also check the status of the credential. Requires the VC to have a `credentialStatus` property.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "fetchRemoteContexts", + "description": "When dealing with JSON-LD you also MUST provide the proper contexts. Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "allowDeactivatedDid", + "description": "If set to `true` allow to verify credential which based on deactivated DID.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialVerifyRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialVerifyRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyCredentialResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/revoke": { + "post": { + "tags": [ + "Credential" + ], + "summary": "Revoke a Verifiable Credential.", + "description": "This endpoint revokes a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself. The StatusList2021 resource should already be setup in the VC and `credentialStatus` property present in the VC.", + "operationId": "revoke", + "parameters": [ + { + "in": "query", + "name": "publish", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RevocationResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/suspend": { + "post": { + "tags": [ + "Credential" + ], + "summary": "Suspend a Verifiable Credential.", + "description": "This endpoint suspends a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself.", + "operationId": "suspend", + "parameters": [ + { + "in": "query", + "name": "publish", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuspensionResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/reinstate": { + "post": { + "tags": [ + "Credential" + ], + "summary": "Reinstate a suspended Verifiable Credential.", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "operationId": "reinstate", + "parameters": [ + { + "in": "query", + "name": "publish", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnsuspensionResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/create": { + "post": { + "tags": [ + "DID" + ], + "summary": "Create a DID Document.", + "description": "This endpoint creates a DID and associated DID Document. As input, it can take the DID Document parameters via a form, or the fully-assembled DID Document itself.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidCreateRequestFormBased" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidCreateRequestJson" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/did/update": { + "post": { + "tags": [ + "DID" + ], + "summary": "Update a DID Document.", + "description": "This endpoint updates a DID Document. As an input, it can take JUST the sections/parameters that need to be updated in the DID Document (in this scenario, it fetches the current DID Document and applies the updated section). Alternatively, it take the fully-assembled DID Document with updated sections as well as unchanged sections.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidUpdateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidUpdateResponse" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/import": { + "post": { + "tags": [ + "DID" + ], + "summary": "Import a DID Document.", + "description": "This endpoint imports a decentralized identifier associated with the user's account for custodian-mode clients.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidImportRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidImportRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/did/deactivate/{did}": { + "post": { + "tags": [ + "DID" + ], + "summary": "Deactivate a DID Document.", + "description": "This endpoint deactivates a DID Document by taking the DID identifier as input. Must be called and signed by the DID owner.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier to deactivate.", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidDeactivateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidDeactivateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeactivatedDidResolution" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/list": { + "get": { + "tags": [ + "DID" + ], + "summary": "Fetch DIDs associated with an account.", + "description": "This endpoint returns the list of DIDs controlled by the account.", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/search/{did}": { + "get": { + "tags": [ + "DID" + ], + "summary": "Resolve a DID Document.", + "description": "Resolve a DID Document by DID identifier. Also supports DID Resolution Queries as defined in the W3C DID Resolution specification.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier to resolve.", + "schema": { + "type": "string" + }, + "required": true, + "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + { + "in": "query", + "name": "metadata", + "description": "Return only metadata of DID Document instead of actual DID Document.", + "schema": { + "type": "boolean" + } + }, + { + "in": "query", + "name": "versionId", + "description": "Unique UUID version identifier of DID Document. Allows for fetching a specific version of the DID Document. See cheqd DID Method Specification for more details.", + "schema": { + "type": "string", + "format": "uuid" + }, + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + { + "in": "query", + "name": "versionTime", + "description": "Returns the closest version of the DID Document *at* or *before* specified time. See DID Resolution handling for `did:cheqd` for more details.", + "schema": { + "type": "string", + "format": "date-time" + }, + "example": "1970-01-01T00:00:00Z" + }, + { + "in": "query", + "name": "transformKeys", + "description": "This directive transforms the Verification Method key format from the version in the DID Document to the specified format chosen below.", + "schema": { + "type": "string", + "enum": [ + "Ed25519VerificationKey2018", + "Ed25519VerificationKey2020", + "JsonWebKey2020" + ] + } + }, + { + "in": "query", + "name": "service", + "description": "Query DID Document for a specific Service Endpoint by Service ID (e.g., `service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`). This will typically redirect to the Service Endpoint based on DID Resolution specification algorithm.", + "schema": { + "type": "string" + }, + "example": "service-1" + }, + { + "in": "query", + "name": "relativeRef", + "description": "Relative reference is a query fragment appended to the Service Endpoint URL. **Must** be used along with the `service` query property above. See DID Resolution specification algorithm for more details.", + "schema": { + "type": "string" + }, + "example": "/path/to/file" + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResolution" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/key/create": { + "post": { + "tags": [ + "Key" + ], + "summary": "Create an identity key pair.", + "description": "This endpoint creates an identity key pair associated with the user's account for custodian-mode clients.", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/key/import": { + "post": { + "tags": [ + "Key" + ], + "summary": "Import an identity key pair.", + "description": "This endpoint imports an identity key pair associated with the user's account for custodian-mode clients.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/KeyImportRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyImportRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/key/read/{kid}": { + "get": { + "tags": [ + "Key" + ], + "summary": "Fetch an identity key pair.", + "description": "This endpoint fetches an identity key pair's details for a given key ID. Only the user account associated with the custodian-mode client can fetch the key pair.", + "parameters": [ + { + "name": "kid", + "description": "Key ID of the identity key pair to fetch.", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/presentation/create": { + "post": { + "tags": [ + "Presentation" + ], + "summary": "!!! WARN. Such endpoint is made mostly for testing purposes and it is not supposed to be used in production !!! Create a Verifiable Presentation from credential(s).", + "description": "This endpoint creates a Verifiable Presentation from credential(s). As input, it can take the credential(s) as a string or the entire credential(s) itself. \n !!! WARN. Such endpoint is made only for testing purposes !!!", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/PresentationCreateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationCreateResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/presentation/verify": { + "post": { + "tags": [ + "Presentation" + ], + "summary": "Verify a Verifiable Presentation generated from credential(s).", + "description": "This endpoint verifies the Verifiable Presentation generated from credential(s). As input, it can take the Verifiable Presentation JWT as a string or the entire Verifiable Presentation itself.", + "parameters": [ + { + "in": "query", + "name": "verifyStatus", + "description": "If set to `true` the verification will also check the status of the presentation. Requires the VP to have a `credentialStatus` property.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "fetchRemoteContexts", + "description": "When dealing with JSON-LD you also MUST provide the proper contexts. * Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "allowDeactivatedDid", + "description": "If set to `true` allow to verify credential which based on deactivated DID.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/PresentationVerifyRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationVerifyRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyPresentationResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/resource/create/{did}": { + "post": { + "tags": [ + "Resource" + ], + "summary": "Create a DID-Linked Resource.", + "description": "This endpoint creates a DID-Linked Resource. As input, it can take the DID identifier and the resource parameters via a form, or the fully-assembled resource itself.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier to link the resource to.", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CreateResourceRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateResourceRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceMetadata" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/resource/search/{did}": { + "get": { + "tags": [ + "Resource" + ], + "summary": "Get a DID-Linked Resource.", + "description": "This endpoint returns the DID-Linked Resource for a given DID identifier and resource identifier.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier", + "schema": { + "type": "string" + }, + "required": true, + "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + { + "in": "query", + "name": "resourceId", + "description": "Fetch a DID-Linked Resource by Resource ID unique identifier. Since this is a unique identifier, other Resource query parameters are not required. See DID-Linked Resources for more details.", + "schema": { + "type": "string", + "format": "uuid" + }, + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + { + "in": "query", + "name": "resourceName", + "description": "Filter a DID-Linked Resource query by Resource Name. See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "cheqd-issuer-logo" + }, + { + "in": "query", + "name": "resourceType", + "description": "Filter a DID-Linked Resource query by Resource Type. See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "CredentialArtwork" + }, + { + "in": "query", + "name": "resourceVersion", + "description": "Filter a DID-Linked Resource query by Resource Version, which is an optional free-text field used by issuers (e.g., \"v1\", \"Final Version\", \"1st January 1970\" etc). See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "v1" + }, + { + "in": "query", + "name": "resourceVersionTime", + "description": "Filter a DID-Linked Resource query which returns the closest version of the Resource *at* or *before* specified time. See DID-Linked Resources for more details.", + "schema": { + "type": "string", + "format": "date-time" + }, + "example": "1970-01-01T00:00:00Z" + }, + { + "in": "query", + "name": "checksum", + "description": "Request integrity check against a given DID-Linked Resource by providing a SHA-256 checksum hash. See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "dc64474d062ed750a66bad58cb609928de55ed0d81defd231a4a4bf97358e9ed" + }, + { + "in": "query", + "name": "resourceMetadata", + "description": "Return only metadata of DID-Linked Resource instead of actual DID-Linked Resource. Mutually exclusive with some of the other parameters.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "any": { + "schema": { + "type": "object" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + } + }, + "components": { + "schemas": { + "AlsoKnownAs": { + "type": "object", + "properties": { + "alsoKnownAs": { + "type": "array", + "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", + "items": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "format": "uri", + "description": "URI where the DID-Linked Resource can be fetched from. Can be any type of URI (e.g., DID, HTTPS, IPFS, etc.)" + }, + "description": { + "type": "string", + "description": "Optional description of the URI." + } + } + } + } + } + }, + "CredentialRequest": { + "description": "Input fields for the creating a Verifiable Credential.", + "type": "object", + "additionalProperties": false, + "properties": { + "issuerDid": { + "description": "DID of the Verifiable Credential issuer. This needs to be a `did:cheqd` DID.", + "type": "string", + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + "subjectDid": { + "description": "DID of the Verifiable Credential holder/subject. This needs to be a `did:key` DID.", + "type": "string", + "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" + }, + "attributes": { + "description": "JSON object containing the attributes to be included in the credential.", + "type": "object", + "example": { + "name": "Bob", + "gender": "male" + } + }, + "@context": { + "description": "Optional properties to be included in the `@context` property of the credential.", + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "https://schema.org/schema.jsonld", + "https://veramo.io/contexts/profile/v1" + ] + }, + "type": { + "description": "Optional properties to be included in the `type` property of the credential.", + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "Person" + ] + }, + "expirationDate": { + "description": "Optional expiration date according to the VC Data Model specification.", + "type": "string", + "format": "date-time", + "example": "2023-06-08T13:49:28.000Z" + }, + "format": { + "description": "Format of the Verifiable Credential. Defaults to VC-JWT.", + "type": "string", + "enum": [ + "jwt", + "jsonld" + ], + "example": "jwt" + }, + "credentialStatus": { + "description": "Optional `credentialStatus` properties for VC revocation or suspension. Takes `statusListName` and `statusListPurpose` as inputs.", + "type": "object", + "required": [ + "statusPurpose", + "statusListName" + ], + "properties": { + "statusPurpose": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ] + }, + "statusListName": { + "type": "string" + }, + "statusListIndex": { + "type": "number" + }, + "statusListVersion": { + "type": "string", + "format": "date-time" + }, + "statusListRangeStart": { + "type": "number" + }, + "statusListRangeEnd": { + "type": "number" + }, + "indexNotIn": { + "type": "number" + } + }, + "example": { + "statusPurpose": "revocation", + "statusListName": "employee-credentials" + } + } + }, + "required": [ + "issuerDid", + "subjectDid", + "attributes" + ], + "example": { + "issuerDid": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "subjectDid": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", + "attributes": { + "gender": "male", + "name": "Bob" + }, + "@context": [ + "https://schema.org" + ], + "type": [ + "Person" + ], + "format": "jwt", + "credentialStatus": { + "statusPurpose": "revocation", + "statusListName": "employee-credentials", + "statusListIndex": 10 + } + } + }, + "Credential": { + "description": "Input fields for revoking/suspending a Verifiable Credential.", + "type": "object", + "additionalProperties": false, + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "https://www.w3.org/2018/credentials/v1", + "https://schema.org", + "https://veramo.io/contexts/profile/v1" + ] + }, + "type": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "VerifiableCredential", + "Person" + ] + }, + "expirationDate": { + "type": "string", + "format": "date-time", + "example": "2023-06-08T13:49:28.000Z" + }, + "issuer": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "DID", + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + } + } + }, + "credentialSubject": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "DID", + "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" + } + } + }, + "credentialStatus": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20" + }, + "statusListIndex": { + "type": "number", + "example": 20 + }, + "statusPurpose": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ], + "example": "suspension" + }, + "type": { + "type": "string", + "enum": [ + "StatusList2021Entry" + ] + } + } + }, + "issuanceDate": { + "type": "string", + "format": "date-time", + "example": "2023-06-08T13:49:28.000Z" + }, + "proof": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "jwt": { + "type": "string" + } + }, + "example": { + "type": "JwtProof2020", + "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg" + } + } + }, + "example": { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://schema.org", + "https://veramo.io/contexts/profile/v1" + ], + "credentialSubject": { + "gender": "male", + "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", + "name": "Bob" + }, + "credentialStatus": { + "id": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20", + "statusIndex": 20, + "statusPurpose": "suspension", + "type": "StatusList2021Entry" + }, + "issuanceDate": "2023-06-08T13:49:28.000Z", + "issuer": { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + "proof": { + "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg", + "type": "JwtProof2020" + }, + "type": [ + "VerifiableCredential", + "Person" + ] + } + }, + "CredentialRevokeRequest": { + "type": "object", + "properties": { + "credential": { + "description": "Verifiable Credential to be revoked as a VC-JWT string or a JSON object.", + "oneOf": [ + { + "type": "object" + }, + { + "type": "string" + } + ] + }, + "symmetricKey": { + "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource. Required if the StatusList2021 DID-Linked Resource is encrypted.", + "type": "string" + } + } + }, + "RevocationResult": { + "properties": { + "revoked": { + "type": "boolean", + "example": true + } + } + }, + "SuspensionResult": { + "properties": { + "suspended": { + "type": "boolean", + "example": true + } + } + }, + "UnsuspensionResult": { + "properties": { + "unsuspended": { + "type": "boolean", + "example": true + } + } + }, + "CredentialVerifyRequest": { + "type": "object", + "properties": { + "credential": { + "description": "Verifiable Credential to be verified as a VC-JWT string or a JSON object.", + "type": "object" + }, + "policies": { + "description": "Custom verification policies to execute when verifying credential.", + "type": "object", + "properties": { + "issuanceDate": { + "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "expirationDate": { + "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "audience": { + "description": "Policy to skip the audience check when set to `false`.", + "type": "boolean", + "default": false + } + } + } + } + }, + "VerifyPresentationResult": { + "type": "object", + "properties": { + "verified": { + "type": "boolean" + }, + "issuer": { + "type": "string" + }, + "signer": { + "type": "object" + }, + "jwt": { + "type": "string" + }, + "verifiableCredential": { + "type": "object" + } + } + }, + "VerifyCredentialResult": { + "type": "object", + "properties": { + "verified": { + "type": "boolean" + }, + "issuer": { + "type": "string" + }, + "signer": { + "type": "object" + }, + "jwt": { + "type": "string" + }, + "verifiableCredential": { + "type": "object" + } + }, + "example": { + "verified": true, + "polices": {}, + "issuer": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "signer": { + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", + "type": "Ed25519VerificationKey2018" + } + } + }, + "PresentationCreateRequest": { + "type": "object", + "required": [ + "credentials" + ], + "properties": { + "credentials": { + "description": "Verifiable Credentials to be used for VP-JWT creation as a VP-JWT strings or a JSON objectsf.", + "type": "array", + "items": { + "type": "object" + } + }, + "holderDid": { + "description": "DID of holder", + "type": "string" + }, + "verifierDid": { + "description": "DID of verifier", + "type": "string" + } + } + }, + "PresentationVerifyRequest": { + "type": "object", + "required": [ + "presentation" + ], + "properties": { + "presentation": { + "description": "Verifiable Presentation to be verified as a VP-JWT string or a JSON object.", + "type": "object" + }, + "verifierDid": { + "description": "Provide an optional verifier DID (also known as 'domain' parameter), if the verifier DID in the presentation is not managed in the wallet.", + "type": "string" + }, + "makeFeePayment": { + "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", + "type": "boolean", + "default": false + }, + "policies": { + "description": "Custom verification policies to execute when verifying presentation.", + "type": "object", + "properties": { + "issuanceDate": { + "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "expirationDate": { + "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "audience": { + "description": "Policy to skip the audience check when set to `false`.", + "type": "boolean", + "default": false + } + } + } + } + }, + "CredentialStatusCreateBody": { + "allOf": [ + { + "type": "object", + "required": [ + "did", + "statusListName" + ], + "properties": { + "did": { + "description": "DID of the StatusList2021 publisher.", + "type": "string", + "format": "uri" + }, + "statusListName": { + "description": "The name of the StatusList2021 DID-Linked Resource to be created.", + "type": "string" + }, + "length": { + "description": "The length of the status list to be created. The default and minimum length is 140000 which is 16kb.", + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true, + "default": 140000 + }, + "encoding": { + "description": "The encoding format of the StatusList2021 DiD-Linked Resource to be created.", + "type": "string", + "default": "base64url", + "enum": [ + "base64url", + "base64", + "hex" + ] + }, + "statusListVersion": { + "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/AlsoKnownAs" + } + ] + }, + "CredentialStatusCreateUnencryptedRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCreateBody" + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials", + "length": 140000, + "encoding": "base64url" + } + }, + "CredentialStatusUnencryptedResult": { + "type": "object", + "properties": { + "resource": { + "type": "object", + "properties": { + "StatusList2021": { + "type": "object", + "properties": { + "encodedList": { + "type": "string", + "example": "H4sIAAAAAAAAA-3BAQ0AAADCoPdPbQ8HFAAAAAAAAAAAAAAAAAAAAADwaDhDr_xcRAAA" + }, + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "validFrom": { + "type": "string", + "format": "date-time", + "example": "2023-06-26T11:45:19.349Z" + } + } + }, + "metadata": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "encoding": { + "type": "string", + "example": "base64url" + }, + "encrypted": { + "type": "boolean", + "example": false + } + } + } + } + }, + "resourceMetadata": { + "type": "object", + "example": { + "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceName": "cheqd-employee-credentials", + "resourceType": "StatusList2021Revocation", + "mediaType": "application/json", + "resourceVersion": "1.0.0", + "created": "2023-06-26T11:45:20Z", + "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", + "previousVersionId": null, + "nextVersionId": null + } + } + } + }, + "CredentialStatusCreateUnencryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "created": { + "type": "boolean", + "example": true + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" + } + ] + }, + "CredentialStatusEncryptedPaymentConditionsBody": { + "type": "object", + "properties": { + "feePaymentAddress": { + "description": "The cheqd/Cosmos payment address where payments to unlock the encrypted StatusList2021 DID-Linked Resource need to be sent.", + "type": "string", + "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" + }, + "feePaymentAmount": { + "description": "Amount in CHEQ tokens to unlock the encrypted StatusList2021 DID-Linked Resource.", + "type": "number", + "minimum": 0, + "exclusiveMinimum": true, + "default": 20 + }, + "feePaymentWindow": { + "description": "Time window (in minutes) within which the payment to unlock the encrypted StatusList2021 DID-Linked Resource is considered valid.", + "type": "number", + "minimum": 0, + "exclusiveMinimum": true, + "default": 10 + } + } + }, + "CredentialStatusEncryptedPaymentConditionsJson": { + "type": "object", + "properties": { + "paymentConditions": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" + } + ] + } + } + }, + "CredentialStatusCreateEncryptedFormRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCreateBody" + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" + }, + { + "type": "object", + "required": [ + "feePaymentAddress", + "feePaymentAmount", + "feePaymentWindow" + ] + } + ] + }, + "CredentialStatusCreateEncryptedJsonRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCreateBody" + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" + }, + { + "type": "object", + "required": [ + "paymentConditions" + ] + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials-encrypted", + "paymentConditions": [ + { + "feePaymentAddress": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg", + "feePaymentAmount": 20, + "feePaymentWindow": 10 + } + ] + } + }, + "CredentialStatusEncryptedResult": { + "type": "object", + "properties": { + "resource": { + "type": "object", + "properties": { + "StatusList2021": { + "type": "object", + "properties": { + "encodedList": { + "type": "string", + "example": "496fdfbeb745b4db03fcdb40566f9c4c4a1c0f184b31255e641b6e7bdfb9b6946c12be87ca3763be0393c00b67ac1e8737c106b32f46ef59c765754415b5e8cc7c65fccaa3374620430ea476301a5e0dd63340e7a27a68bc627518471f22e4a2" + }, + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "validFrom": { + "type": "string", + "format": "date-time", + "example": "2023-06-26T11:45:19.349Z" + } + } + }, + "metadata": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "encoding": { + "type": "string", + "example": "base64url" + }, + "encrypted": { + "type": "boolean", + "example": true + }, + "encryptedSymmetricKey": { + "type": "string", + "example": "b11182dc524b8181f9a6aef4c4ad0a1c14e40033b9112dffd8d1bcf6cc3b85abc07ded2205ee94068a99f4202502cb0855f322583fa6ce1534d3a05bf36891766ea2c5f90a982b3040680762977d404d758a2370224a239c8279aa7d21e980931c42055b17ca4c7dbffa4782480a8b6279cf989b2f166d5fdb4b2c1b5a63927200000000000000203018dcaba26df45a415bb599218b27ca853a70289d7a3ed3ed0e3730452e8f8d9af91b6e71312565d2c069341f6660ab" + }, + "paymentConditions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "feePaymentAddress": { + "type": "string", + "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" + }, + "feePaymentAmount": { + "type": "string", + "example": "20000000000ncheq" + }, + "intervalInSeconds": { + "type": "number", + "example": 600 + }, + "type": { + "type": "string", + "example": "timelockPayment" + } + } + } + } + } + }, + "resourceMetadata": { + "type": "object", + "example": { + "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceName": "cheqd-revocation-encrypted-1", + "resourceType": "StatusList2021Revocation", + "mediaType": "application/json", + "resourceVersion": "2023-06-26T11:45:19.349Z", + "created": "2023-06-26T11:45:20Z", + "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", + "previousVersionId": null, + "nextVersionId": null + } + }, + "symmetricKey": { + "type": "string", + "example": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" + } + } + } + } + }, + "CredentialStatusCreateEncryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "created": { + "type": "boolean", + "example": true + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedResult" + } + ] + }, + "CredentialStatusUpdateBody": { + "type": "object", + "required": [ + "did", + "statusListName", + "indices" + ], + "properties": { + "did": { + "description": "DID of the StatusList2021 publisher.", + "type": "string", + "format": "uri" + }, + "statusListName": { + "description": "The name of the StatusList2021 DID-Linked Resource to be updated.", + "type": "string" + }, + "indices": { + "description": "List of credential status indices to be updated. The indices must be in the range of the status list.", + "type": "array", + "items": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": false + } + }, + "statusListVersion": { + "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + "CredentialStatusUpdateUnencryptedRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUpdateBody" + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials", + "indices": [ + 10, + 3199, + 12109, + 130999 + ] + } + }, + "CredentialStatusUpdateUnencryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "updated": { + "type": "boolean", + "example": true + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/RevocationResult" + }, + { + "$ref": "#/components/schemas/SuspensionResult" + }, + { + "$ref": "#/components/schemas/UnsuspensionResult" + } + ] + }, + { + "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" + } + ] + }, + "CredentialStatusUpdateEncryptedFormRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUpdateBody" + }, + { + "type": "object", + "required": [ + "symmetricKey" + ], + "properties": { + "symmetricKey": { + "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" + } + ] + }, + "CredentialStatusUpdateEncryptedJsonRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUpdateBody" + }, + { + "type": "object", + "required": [ + "symmetricKey" + ], + "properties": { + "symmetricKey": { + "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials-encrypted", + "indices": [ + 10, + 3199, + 12109, + 130999 + ], + "symmetricKey": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" + } + }, + "CredentialStatusUpdateEncryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "updated": { + "type": "boolean", + "example": true + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/RevocationResult" + }, + { + "$ref": "#/components/schemas/SuspensionResult" + }, + { + "$ref": "#/components/schemas/UnsuspensionResult" + } + ] + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedResult" + } + ] + }, + "CredentialStatusCheckRequest": { + "type": "object", + "required": [ + "did", + "statusListName", + "index" + ], + "properties": { + "did": { + "description": "DID of the StatusList2021 publisher.", + "type": "string", + "format": "uri" + }, + "statusListName": { + "description": "The name of the StatusList2021 DID-Linked Resource to be checked.", + "type": "string" + }, + "index": { + "description": "Credential status index to be checked for revocation or suspension.", + "type": "integer", + "minimum": 0, + "exclusiveMinimum": false + }, + "makeFeePayment": { + "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", + "type": "boolean", + "default": true + } + } + }, + "CredentialStatusCheckResult": { + "oneOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCheckRevocationResult" + }, + { + "$ref": "#/components/schemas/CredentialStatusCheckSuspensionResult" + } + ] + }, + "CredentialStatusCheckRevocationResult": { + "type": "object", + "properties": { + "checked": { + "type": "boolean", + "example": true + }, + "revoked": { + "type": "boolean", + "example": false + } + } + }, + "CredentialStatusCheckSuspensionResult": { + "type": "object", + "properties": { + "checked": { + "type": "boolean", + "example": true + }, + "suspended": { + "type": "boolean", + "example": false + } + } + }, + "CredentialStatusListSearchResult": { + "allOf": [ + { + "type": "object", + "properties": { + "found": { + "type": "boolean", + "example": true + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedResult" + } + ] + } + ] + }, + "KeyImportRequest": { + "type": "object", + "properties": { + "alias": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "Ed25519", + "Secp256k1" + ] + }, + "privateKeyHex": { + "type": "string" + } + } + }, + "KeyResult": { + "type": "object", + "properties": { + "kid": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "Ed25519", + "Secp256k1" + ] + }, + "publicKeyHex": { + "type": "string" + } + } + }, + "DidDocument": { + "description": "This input field contains either a complete DID document, or an incremental change (diff) to a DID document. See Universal DID Registrar specification.", + "type": "object", + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "controllers": { + "type": "array", + "items": { + "type": "string" + } + }, + "verificationMethod": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VerificationMethod" + } + }, + "service": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "authentication": { + "type": "array", + "items": { + "type": "string" + } + }, + "assertionMethod": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityInvocation": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityDelegation": { + "type": "array", + "items": { + "type": "string" + } + }, + "keyAgreement": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "@context": [ + "https://www.w3.org/ns/did/v1" + ], + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "controller": [ + "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + ], + "verificationMethod": [ + { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "type": "Ed25519VerificationKey2018", + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "publicKeyBase58": "z6MkkVbyHJLLjdjU5B62DaJ4mkdMdUkttf9UqySSkA9bVTeZ" + } + ], + "authentication": [ + "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1" + ], + "service": [ + { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", + "type": "LinkedDomains", + "serviceEndpoint": [ + "https://example.com" + ] + } + ] + } + }, + "DidDocumentWithoutVerificationMethod": { + "type": "object", + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "controllers": { + "type": "array", + "items": { + "type": "string" + } + }, + "service": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "authentication": { + "type": "array", + "items": { + "type": "string" + } + }, + "assertionMethod": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityInvocation": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityDelegation": { + "type": "array", + "items": { + "type": "string" + } + }, + "keyAgreement": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "@context": [ + "https://www.w3.org/ns/did/v1" + ], + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "controller": [ + "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + ], + "authentication": [ + "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1" + ], + "service": [ + { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", + "type": "LinkedDomains", + "serviceEndpoint": [ + "https://example.com" + ] + } + ] + } + }, + "DidCreateRequestFormBased": { + "type": "object", + "properties": { + "network": { + "description": "Network to create the DID on (testnet or mainnet)", + "type": "string", + "enum": [ + "testnet", + "mainnet" + ] + }, + "identifierFormatType": { + "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", + "type": "string", + "enum": [ + "uuid", + "base58btc" + ] + }, + "verificationMethodType": { + "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", + "type": "string", + "enum": [ + "Ed25519VerificationKey2018", + "JsonWebKey2020", + "Ed25519VerificationKey2020" + ] + }, + "service": { + "description": "It's a list of special objects which are designed to build the actual service. It's almost the same as in DID Core specification, but instead of `id` it utilises `idFragment` field for making the right `id` for each service. !!! WARN. Cause swagger-ui does not handle x-ww-form based arrays correctly, please frame all your services in brackets while using swagger UI. !!!", + "type": "array", + "items": { + "type": "object", + "properties": { + "idFragment": { + "type": "string" + }, + "type": { + "type": "string" + }, + "serviceEndpoint": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "example": [ + { + "idFragment": "service-1", + "type": "LinkedDomains", + "serviceEndpoint": [ + "https://example.com" + ] + } + ] + }, + "key": { + "description": "The unique identifier in hexadecimal public key format used in the verification method to create the DID.", + "type": "string" + }, + "@context": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "https://www.w3.org/ns/did/v1" + ] + } + } + }, + "DidCreateRequestJson": { + "type": "object", + "properties": { + "network": { + "description": "Network to create the DID on (testnet or mainnet)", + "type": "string", + "enum": [ + "testnet", + "mainnet" + ] + }, + "identifierFormatType": { + "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", + "type": "string", + "enum": [ + "uuid", + "base58btc" + ] + }, + "assertionMethod": { + "description": "Usually a reference to a Verification Method. An Assertion Method is required to issue JSON-LD credentials. See DID Core specification for more details.", + "type": "boolean", + "default": true + }, + "options": { + "type": "object", + "properties": { + "key": { + "type": "string", + "example": "8255ddadd75695e01f3d98fcec8ccc7861a030b317d4326b0e48a4d579ddc43a" + }, + "verificationMethodType": { + "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", + "type": "string", + "enum": [ + "Ed25519VerificationKey2018", + "JsonWebKey2020", + "Ed25519VerificationKey2020" + ] + } + } + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocumentWithoutVerificationMethod" + } + } + }, + "DidImportRequest": { + "type": "object", + "properties": { + "did": { + "type": "string", + "description": "DID to be imported", + "format": "uri", + "required": true + }, + "keys": { + "type": "array", + "description": "List of keys required to import the DID", + "required": true, + "items": { + "$ref": "#/components/schemas/KeyImportRequest" + } + } + } + }, + "PresentationCreateResult": { + "type": "object", + "properties": { + "vp": { + "type": "object", + "description": "Verifiable Presentation which could be provided to the verifier." + }, + "nbf": { + "type": "integer", + "description": "Unix timestamp of the earliest time that the Verifiable Presentation is valid." + }, + "iss": { + "type": "string", + "description": "DID of the issuer of the Verifiable Presentation. (Here it's supposed to be a holder DID)" + }, + "aud": { + "type": "array", + "items": { + "type": "string" + }, + "description": "DID of the verifier of the Verifiable Presentation." + } + }, + "example": { + "vp": { + "@context": [ + "https://www.w3.org/2018/credentials/v1" + ], + "type": [ + "VerifiablePresentation" + ], + "verifiableCredential": [ + "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc2NoZW1hLm9yZy9zY2hlbWEuanNvbmxkIiwiaHR0cHM6Ly92ZXJhbW8uaW8vY29udGV4dHMvcHJvZmlsZS92MSIsImh0dHBzOi8vdzNpZC5vcmcvdmMtc3RhdHVzLWxpc3QtMjAyMS92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiUGVyc29uIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7Im5hbWUiOiJCb2IiLCJnZW5kZXIiOiJtYWxlIn0sImNyZWRlbnRpYWxTdGF0dXMiOnsiaWQiOiJodHRwczovL3Jlc29sdmVyLmNoZXFkLm5ldC8xLjAvaWRlbnRpZmllcnMvZGlkOmNoZXFkOnRlc3RuZXQ6OTBkNWMxNDEtNzI0Zi00N2FkLTlhZTctYTdjMzNhOWU1NjQzP3Jlc291cmNlTmFtZT1zdXNwZW5zaW9uRW4mcmVzb3VyY2VUeXBlPVN0YXR1c0xpc3QyMDIxU3VzcGVuc2lvbiMxMzMzOCIsInR5cGUiOiJTdGF0dXNMaXN0MjAyMUVudHJ5Iiwic3RhdHVzUHVycG9zZSI6InN1c3BlbnNpb24iLCJzdGF0dXNMaXN0SW5kZXgiOiIxMzMzOCJ9fSwic3ViIjoiZGlkOmtleTp6Nk1raGFYZ0JaRHZvdERrTDUyNTdmYWl6dGlHaUMyUXRLTEdwYm5uRUd0YTJkb0siLCJuYmYiOjE3MDA0NzM0MTYsImlzcyI6ImRpZDpjaGVxZDp0ZXN0bmV0OjkwZDVjMTQxLTcyNGYtNDdhZC05YWU3LWE3YzMzYTllNTY0MyJ9.-14Ril1pZEy2HEEo48gTJr2yOtGxBhUGTFmzVdjAtyhFRsW5zZg9onHt6V9JQ8BaiYBlTkP9GzTnJ-O6hdiyCw" + ] + }, + "nbf": 1700744275, + "iss": "did:cheqd:testnet:4b846d0f-2f6c-4ab6-9fe2-5b8db301c83c", + "aud": [ + "did:cheqd:testnet:8c71e9b6-c5a3-4250-8c58-fa591533cd22" + ] + } + }, + "DidResult": { + "type": "object", + "properties": { + "did": { + "type": "string" + }, + "controllerKeyId": { + "type": "string" + }, + "keys": { + "type": "array", + "items": { + "type": "object" + } + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + } + } + }, + "DidUpdateResponse": { + "type": "object", + "properties": { + "did": { + "type": "string" + }, + "controllerKeyId": { + "type": "string", + "description": "The default key id of which is the key associated with the first verificationMethod" + }, + "keys": { + "type": "array", + "description": "The list of keys associated with the list of verificationMethod's of DIDDocument", + "items": { + "type": "object" + } + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "controllerKeyRefs": { + "type": "array", + "description": "The list of keyRefs which were used for signing the transaction", + "items": { + "type": "string" + } + }, + "controllerKeys": { + "type": "array", + "description": "The list of all possible keys, inlcuding all controller's keys", + "items": { + "type": "string" + } + } + } + }, + "VerificationMethod": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + }, + "controller": { + "type": "string" + }, + "publicKeyMultibase": { + "type": "string" + }, + "publicKeyJwk": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "id": "did:cheqd:testnet :7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", + "type": "Ed25519VerificationKey2018" + } + }, + "Service": { + "description": "Communicating or interacting with the DID subject or associated entities via one or more service endpoints. See DID Core specification for more details.", + "type": "object", + "properties": { + "id": { + "description": "DID appended with Service fragment ID (e.g., `#service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`)", + "type": "string", + "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1" + }, + "type": { + "description": "Service type as defined in DID Specification Registries.", + "type": "string", + "example": "LinkedDomains" + }, + "serviceEndpoint": { + "description": "Service endpoint as defined in DID Core Specification.", + "type": "array", + "items": { + "type": "string", + "example": "https://example.com" + } + } + } + }, + "DidUpdateRequest": { + "type": "object", + "properties": { + "did": { + "description": "DID identifier to be updated.", + "type": "string", + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + "service": { + "type": "array", + "description": "Service section of the DID Document.", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "verificationMethod": { + "type": "array", + "description": "Verification Method section of the DID Document.", + "items": { + "$ref": "#/components/schemas/VerificationMethod" + } + }, + "authentication": { + "description": "Authentication section of the DID Document.", + "type": "array", + "items": { + "type": "string" + } + }, + "publicKeyHexs": { + "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", + "type": "array", + "items": { + "type": "string" + } + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + } + } + }, + "DidDeactivateRequest": { + "type": "object", + "properties": { + "publicKeyHexs": { + "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "CreateResourceRequest": { + "description": "Input fields for DID-Linked Resource creation.", + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "type", + "data", + "encoding" + ], + "properties": { + "data": { + "description": "Encoded string containing the data to be stored in the DID-Linked Resource.", + "type": "string" + }, + "encoding": { + "description": "Encoding format used to encode the data.", + "type": "string", + "enum": [ + "base64url", + "base64", + "hex" + ] + }, + "name": { + "description": "Name of DID-Linked Resource.", + "type": "string" + }, + "type": { + "description": "Type of DID-Linked Resource. This is NOT the same as the media type, which is calculated automatically ledger-side.", + "type": "string" + }, + "alsoKnownAs": { + "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", + "type": "array", + "items": { + "type": "object", + "properties": { + "uri": { + "type": "string" + }, + "description": { + "type": "string" + } + } + } + }, + "version": { + "description": "Optional field to assign a human-readable version in the DID-Linked Resource.", + "type": "string" + }, + "publicKeyHexs": { + "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "data": "SGVsbG8gV29ybGQ=", + "encoding": "base64url", + "name": "ResourceName", + "type": "TextDocument" + } + }, + "ResourceList": { + "type": "object", + "properties": { + "@context": { + "type": "string", + "example": "https://w3id.org/did-resolution/v1" + }, + "contentMetadata": { + "type": "object" + }, + "contentStream": { + "type": "object" + }, + "dereferencingMetadata": { + "$ref": "#/components/schemas/DereferencingMetadata" + } + } + }, + "DereferencingMetadata": { + "type": "object", + "properties": { + "contentType": { + "type": "string", + "example": "application/did+ld+json" + }, + "did": { + "$ref": "#/components/schemas/DidProperties" + }, + "retrieved": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + } + } + }, + "DidResolution": { + "type": "object", + "properties": { + "@context": { + "type": "string", + "example": "https://w3id.org/did-resolution/v1" + }, + "didDidResolutionMetadata": { + "$ref": "#/components/schemas/DidResolutionMetadata" + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + }, + "didDocumentMetadata": { + "$ref": "#/components/schemas/DidDocumentMetadata" + } + } + }, + "DeactivatedDidResolution": { + "type": "object", + "properties": { + "@context": { + "type": "string", + "example": "https://w3id.org/did-resolution/v1" + }, + "didDidResolutionMetadata": { + "$ref": "#/components/schemas/DidResolutionMetadata" + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + }, + "didDocumentMetadata": { + "$ref": "#/components/schemas/DeactivatedDidDocumentMetadata" + } + } + }, + "DidDocumentMetadata": { + "type": "object", + "properties": { + "created": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "deactivated": { + "type": "boolean", + "example": false + }, + "updated": { + "type": "string", + "example": "2021-09-10T12:00:00Z" + }, + "versionId": { + "type": "string", + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + "linkedResourceMetadata": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ResourceMetadata" + } + } + } + }, + "DeactivatedDidDocumentMetadata": { + "type": "object", + "properties": { + "created": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "deactivated": { + "type": "boolean", + "example": true + }, + "updated": { + "type": "string", + "example": "2021-09-10T12:00:00Z" + }, + "versionId": { + "type": "string", + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + "linkedResourceMetadata": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ResourceMetadata" + } + } + } + }, + "ResourceMetadata": { + "type": "object", + "properties": { + "resourceURI": { + "type": "string", + "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47/resources/398cee0a-efac-4643-9f4c-74c48c72a14b" + }, + "resourceCollectionId": { + "type": "string", + "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" + }, + "resourceId": { + "type": "string", + "example": "398cee0a-efac-4643-9f4c-74c48c72a14b" + }, + "resourceName": { + "type": "string", + "example": "cheqd-issuer-logo" + }, + "resourceType": { + "type": "string", + "example": "CredentialArtwork" + }, + "mediaType": { + "type": "string", + "example": "image/png" + }, + "resourceVersion": { + "type": "string", + "example": "1.0" + }, + "checksum": { + "type": "string", + "example": "a95380f460e63ad939541a57aecbfd795fcd37c6d78ee86c885340e33a91b559" + }, + "created": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "nextVersionId": { + "type": "string", + "example": "d4829ac7-4566-478c-a408-b44767eddadc" + }, + "previousVersionId": { + "type": "string", + "example": "ad7a8442-3531-46eb-a024-53953ec6e4ff" + } + } + }, + "DidResolutionMetadata": { + "type": "object", + "properties": { + "contentType": { + "allOf": [ + { + "$ref": "#/components/schemas/ContentType" + } + ], + "example": "application/did+ld+json" + }, + "retrieved": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "did": { + "$ref": "#/components/schemas/DidProperties" + } + } + }, + "ContentType": { + "type": "string", + "enum": [ + "application/did+json", + "application/did+ld+json", + "application/ld+json", + "application/json" + ] + }, + "DidProperties": { + "type": "object", + "properties": { + "didString": { + "type": "string", + "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" + }, + "method": { + "type": "string", + "example": "cheqd" + }, + "methodSpecificId": { + "type": "string", + "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" + } + } + }, + "Customer": { + "type": "object", + "properties": { + "customerId": { + "type": "string", + "example": "6w5drpiiwhhs" + }, + "address": { + "type": "string", + "example": "cheqd1wgsvqwlkmdp60f4dek26ak0sjw6au3ytd3pz7f" + } + } + }, + "AccountCreateRequest": { + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": { + "primaryEmail": { + "type": "string" + } + } + } + } + }, + "InvalidRequest": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "InvalidRequest" + } + } + }, + "InternalError": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Internal Error" + } + } + }, + "UnauthorizedError": { + "description": "Access token is missing or invalid", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Unauthorized Error" + } + } + } + } + } +} \ No newline at end of file From 7c1775d4d27d053559dd0f686a0c01470ece5c2e Mon Sep 17 00:00:00 2001 From: Ankur Banerjee Date: Wed, 17 Apr 2024 11:38:55 +0100 Subject: [PATCH 33/40] npm run format --- src/static/swagger-admin.json | 2058 +++++----- src/static/swagger-api.json | 6882 ++++++++++++++++----------------- 2 files changed, 4343 insertions(+), 4597 deletions(-) diff --git a/src/static/swagger-admin.json b/src/static/swagger-admin.json index f8d03627..72021893 100644 --- a/src/static/swagger-admin.json +++ b/src/static/swagger-admin.json @@ -1,1049 +1,1011 @@ { - "openapi": "3.0.0", - "info": { - "title": "Credential Service admin API for cheqd network", - "version": "2.0.0", - "description": "Admin API which handles users subscriptions and payments", - "contact": { - "name": "Cheqd Foundation Limited", - "url": "https://github.com/cheqd/credential-service", - "email": "support-github@cheqd.io" - }, - "license": { - "name": "Apache 2.0", - "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" - } - }, - "tags": [ - { - "name": "Product" - }, - { - "name": "Price" - }, - { - "name": "Subscription" - }, - { - "name": "API Key" - } - ], - "paths": { - "/admin/api-key/create": { - "post": { - "summary": "Create a new API key", - "description": "Create a new API key", - "tags": [ - "API Key" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyCreateRequestBody" - } - } - } - }, - "responses": { - "201": { - "description": "A new API key has been created", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyCreateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/APIKeyCreateUnsuccessfulResponseBody" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/api-key/update": { - "post": { - "summary": "Update an existing API key", - "description": "Update an existing API key", - "tags": [ - "API Key" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyUpdateRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The API key has been updated", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyUpdateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/APIKeyUpdateUnsuccessfulResponseBody" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/api-key/revoke": { - "delete": { - "summary": "Revoke an existing API key", - "description": "Revoke an existing API key", - "tags": [ - "API Key" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyRevokeRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The API key has been revoked", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyRevokeResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/APIKeyRevokeUnsuccessfulResponseBody" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/api-key/list": { - "get": { - "summary": "List all API keys", - "description": "List all API keys", - "tags": [ - "API Key" - ], - "responses": { - "200": { - "description": "A list of API keys", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/api-key/get": { - "get": { - "summary": "Get an API key", - "description": "Get an API key. If the API key is not provided, the latest not revoked API key it returns.", - "tags": [ - "API Key" - ], - "parameters": [ - { - "name": "apiKey", - "in": "query", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "The API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyGetResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/price/list": { - "get": { - "summary": "Get a list of prices", - "description": "Get a list of prices", - "tags": [ - "Price" - ], - "parameters": [ - { - "in": "query", - "name": "productId", - "schema": { - "type": "string", - "description": "The product id. If passed - returns filtered by this product list of prices.", - "required": false - } - } - ], - "responses": { - "200": { - "description": "A list of prices", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PriceListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/product/list": { - "get": { - "summary": "Get a list of products", - "description": "Get a list of products which are on a Stripe side", - "tags": [ - "Product" - ], - "parameters": [ - { - "in": "query", - "name": "prices", - "schema": { - "type": "boolean", - "description": "If setup to true - returns the list of products with prices inside. Default - true", - "required": false - } - } - ], - "responses": { - "200": { - "description": "A list of products", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/product/get/{productId}": { - "get": { - "summary": "Get a product", - "description": "Get a product by id", - "tags": [ - "Product" - ], - "parameters": [ - { - "in": "path", - "name": "productId", - "schema": { - "type": "string", - "description": "The product id which identifies the product in Stripe" - }, - "required": true - }, - { - "in": "query", - "name": "prices", - "schema": { - "type": "boolean", - "description": "If setup to true - returns the product with prices inside. Default - true", - "required": false - } - } - ], - "responses": { - "200": { - "description": "A product", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductGetResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/create": { - "post": { - "summary": "Create a subscription", - "description": "Creates a new subscription for an existing customer", - "tags": [ - "Subscription" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCreateRequestBody" - } - } - } - }, - "responses": { - "201": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCreateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/update": { - "post": { - "summary": "Update a subscription", - "description": "Updates an existing subscription", - "tags": [ - "Subscription" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionUpdateRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionUpdateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/list": { - "get": { - "summary": "Get a list of subscriptions", - "description": "Get a list of subscriptions", - "tags": [ - "Subscription" - ], - "parameters": [ - { - "in": "query", - "name": "paymentProviderId", - "schema": { - "type": "string", - "description": "The customer id. If passed - returns filtered by this customer list of subscriptions." - } - } - ], - "responses": { - "200": { - "description": "A list of subscriptions", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/get": { - "get": { - "summary": "Get a subscription", - "description": "Get a subscription", - "tags": [ - "Subscription" - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionGetResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/cancel": { - "post": { - "summary": "Cancel a subscription", - "description": "Cancels an existing subscription", - "tags": [ - "Subscription" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCancelRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCancelResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/resume": {}, - "post": { - "summary": "Resume a subscription", - "description": "Resumes an existing subscription", - "tags": [ - "Subscription" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionResumeRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionResumeResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "components": { - "schemas": { - "PriceListResponseBody": { - "description": "A list of active prcies from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/list)", - "type": "object", - "properties": { - "prices": { - "type": "array", - "items": { - "type": "object", - "description": "A price object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/object)" - } - } - } - }, - "ProductListResponseBody": { - "type": "object", - "properties": { - "products": { - "type": "array", - "items": { - "type": "object", - "description": "A product object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/object)" - } - } - } - }, - "ProductGetResponseBody": { - "description": "A product with or without prices inside. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/retrieve)", - "type": "object" - }, - "InvalidRequest": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "InvalidRequest" - } - } - }, - "InternalError": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Internal Error" - } - } - }, - "UnauthorizedError": { - "description": "Access token is missing or invalid", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Unauthorized Error" - } - } - }, - "SubscriptionCreateRequestBody": { - "description": "The request body for creating a subscription", - "type": "object", - "properties": { - "price": { - "type": "string", - "description": "The price id", - "example": "price_1234567890" - }, - "successURL": { - "type": "string", - "description": "The URL to redirect to after the customer sucessfully completes the checkout", - "example": "https://example.com/success" - }, - "cancelURL": { - "type": "string", - "description": "The URL to redirect to after the customer cancels the checkout", - "example": "https://example.com/cancel" - }, - "quantity": { - "type": "number", - "description": "The quantity of the product", - "example": 1 - }, - "trialPeriodDays": { - "type": "number", - "description": "The number of days the customer has to pay for the product", - "example": 7 - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": "abcdefghijklmnopqrstuvwxyz" - } - } - }, - "SubscriptionCreateResponseBody": { - "description": "The response body for creating a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "An object with link to checkout session. For more information see the [Stripe API documentation](https://docs.stripe.com/api/checkout/sessions/object)", - "properties": { - "sessionURL": { - "type": "string", - "description": "URL which user should follow to manage subscription" - } - } - } - } - }, - "SubscriptionUpdateRequestBody": { - "description": "The request body for updating a subscription", - "type": "object", - "properties": { - "returnURL": { - "type": "string", - "description": "URL which is used to redirect to the page with ability to update the subscription" - } - } - }, - "SubscriptionUpdateResponseBody": { - "description": "The response body for updating a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "Object with redirect url inside", - "properties": { - "sessionURL": { - "type": "string", - "description": "URL with session URL rediect to" - } - } - } - } - }, - "SubscriptionGetRequestBody": { - "description": "The request body for getting a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - } - } - }, - "SubscriptionGetResponseBody": { - "description": "The response body for getting a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" - } - } - }, - "SubscriptionListRequestBody": { - "description": "The request body for listing subscriptions", - "type": "object", - "properties": { - "customerId": { - "type": "string", - "description": "The Stripe customer id", - "example": "cus_1234567890" - } - } - }, - "SubscriptionListResponseBody": { - "description": "The response body for listing subscriptions", - "type": "object", - "properties": { - "subscriptions": { - "type": "array", - "items": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" - } - } - } - }, - "SubscriptionCancelRequestBody": { - "description": "The request body for canceling a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - } - } - }, - "SubscriptionCancelResponseBody": { - "description": "The response body for canceling a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": "abcdefghijklmnopqrstuvwxyz" - } - } - }, - "SubscriptionResumeRequestBody": { - "description": "The request body for resuming a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": "abcdefghijklmnopqrstuvwxyz" - } - } - }, - "SubscriptionResumeResponseBody": { - "description": "The response body for resuming a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" - } - } - }, - "APIKeyResponse": { - "description": "The general view for API key in response", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz" - }, - "createdAt": { - "type": "string", - "description": "The creation date of the API key", - "example": "2000-10-31T01:23:45Z", - "format": "date-time" - }, - "name": { - "type": "string", - "description": "The name of the API key", - "example": "My API Key" - }, - "expiresAt": { - "type": "string", - "description": "The expiration date of the API key", - "example": "2000-10-31T01:23:45Z", - "format": "date-time" - }, - "revoked": { - "type": "boolean", - "description": "The status of the API key", - "example": false - } - } - }, - "APIKeyCreateRequestBody": { - "description": "The request body for creating an API key", - "type": "object", - "properties": { - "expiresAt": { - "type": "string", - "description": "The expiration date of the API key", - "example": "2000-10-31T01:23:45Z", - "format": "date-time" - }, - "name": { - "type": "string", - "description": "The name of the API key", - "example": "My API Key" - } - }, - "required": [ - "name" - ] - }, - "APIKeyCreateResponseBody": { - "description": "The response body for creating an API key", - "type": "object", - "schema": { - "ref": "#/components/schemas/APIKeyResponse" - } - }, - "APIKeyCreateUnsuccessfulResponseBody": { - "description": "The response body for an unsuccessful API key creation", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "API key creation unsuccessful" - } - } - }, - "APIKeyUpdateRequestBody": { - "description": "The request body for updating an API key", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz" - }, - "name": { - "type": "string", - "description": "The name of the API key", - "example": "My API Key" - }, - "expiresAt": { - "type": "string", - "description": "The expiration date of the API key", - "example": "2000-10-31T01:23:45Z", - "format": "date-time" - }, - "revoked": { - "type": "boolean", - "description": "The status of the API key", - "example": false, - "default": false - } - }, - "required": [ - "apiKey" - ] - }, - "APIKeyUpdateResponseBody": { - "description": "The response body for an unsuccessful API key update", - "type": "object", - "schema": { - "ref": "#/components/schemas/APIKeyResponse" - } - }, - "APIKeyUpdateUnsuccessfulResponseBody": { - "description": "The response body for an unsuccessful API key update", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "API key update unsuccessful" - } - } - }, - "APIKeyRevokeRequestBody": { - "description": "The request body for revoking an API key", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz" - } - }, - "required": [ - "apiKey" - ] - }, - "APIKeyRevokeResponseBody": { - "description": "The response body for revoking an API key", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz" - }, - "revoked": { - "type": "boolean", - "description": "The status of the API key", - "example": true - } - }, - "required": [ - "apiKey" - ] - }, - "APIKeyRevokeUnsuccessfulResponseBody": { - "description": "The response body for an unsuccessful API key revocation", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "API key revocation unsuccessful" - } - } - }, - "APIKeyListResponseBody": { - "description": "The response body for listing API keys", - "type": "object", - "properties": { - "apiKeys": { - "type": "array", - "items": { - "type": "object", - "schema": { - "ref": "#/components/schemas/APIKeyResponse" - } - } - } - } - }, - "APIKeyGetRequestBody": { - "description": "The request body for getting an API key", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz" - } - }, - "required": [ - "apiKey" - ] - }, - "APIKeyGetResponseBody": { - "description": "The response body for getting an API key", - "type": "object", - "schema": { - "ref": "#/components/schemas/APIKeyResponse" - } - }, - "NotFoundError": { - "description": "The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Not Found Error" - } - } - } - } - } -} \ No newline at end of file + "openapi": "3.0.0", + "info": { + "title": "Credential Service admin API for cheqd network", + "version": "2.0.0", + "description": "Admin API which handles users subscriptions and payments", + "contact": { + "name": "Cheqd Foundation Limited", + "url": "https://github.com/cheqd/credential-service", + "email": "support-github@cheqd.io" + }, + "license": { + "name": "Apache 2.0", + "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" + } + }, + "tags": [ + { + "name": "Product" + }, + { + "name": "Price" + }, + { + "name": "Subscription" + }, + { + "name": "API Key" + } + ], + "paths": { + "/admin/api-key/create": { + "post": { + "summary": "Create a new API key", + "description": "Create a new API key", + "tags": ["API Key"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyCreateRequestBody" + } + } + } + }, + "responses": { + "201": { + "description": "A new API key has been created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyCreateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/APIKeyCreateUnsuccessfulResponseBody" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/api-key/update": { + "post": { + "summary": "Update an existing API key", + "description": "Update an existing API key", + "tags": ["API Key"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyUpdateRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The API key has been updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyUpdateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/APIKeyUpdateUnsuccessfulResponseBody" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/api-key/revoke": { + "delete": { + "summary": "Revoke an existing API key", + "description": "Revoke an existing API key", + "tags": ["API Key"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyRevokeRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The API key has been revoked", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyRevokeResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/APIKeyRevokeUnsuccessfulResponseBody" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/api-key/list": { + "get": { + "summary": "List all API keys", + "description": "List all API keys", + "tags": ["API Key"], + "responses": { + "200": { + "description": "A list of API keys", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/api-key/get": { + "get": { + "summary": "Get an API key", + "description": "Get an API key. If the API key is not provided, the latest not revoked API key it returns.", + "tags": ["API Key"], + "parameters": [ + { + "name": "apiKey", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyGetResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/price/list": { + "get": { + "summary": "Get a list of prices", + "description": "Get a list of prices", + "tags": ["Price"], + "parameters": [ + { + "in": "query", + "name": "productId", + "schema": { + "type": "string", + "description": "The product id. If passed - returns filtered by this product list of prices.", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A list of prices", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PriceListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/product/list": { + "get": { + "summary": "Get a list of products", + "description": "Get a list of products which are on a Stripe side", + "tags": ["Product"], + "parameters": [ + { + "in": "query", + "name": "prices", + "schema": { + "type": "boolean", + "description": "If setup to true - returns the list of products with prices inside. Default - true", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A list of products", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProductListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/product/get/{productId}": { + "get": { + "summary": "Get a product", + "description": "Get a product by id", + "tags": ["Product"], + "parameters": [ + { + "in": "path", + "name": "productId", + "schema": { + "type": "string", + "description": "The product id which identifies the product in Stripe" + }, + "required": true + }, + { + "in": "query", + "name": "prices", + "schema": { + "type": "boolean", + "description": "If setup to true - returns the product with prices inside. Default - true", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A product", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProductGetResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/create": { + "post": { + "summary": "Create a subscription", + "description": "Creates a new subscription for an existing customer", + "tags": ["Subscription"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCreateRequestBody" + } + } + } + }, + "responses": { + "201": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCreateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/update": { + "post": { + "summary": "Update a subscription", + "description": "Updates an existing subscription", + "tags": ["Subscription"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionUpdateRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionUpdateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/list": { + "get": { + "summary": "Get a list of subscriptions", + "description": "Get a list of subscriptions", + "tags": ["Subscription"], + "parameters": [ + { + "in": "query", + "name": "paymentProviderId", + "schema": { + "type": "string", + "description": "The customer id. If passed - returns filtered by this customer list of subscriptions." + } + } + ], + "responses": { + "200": { + "description": "A list of subscriptions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/get": { + "get": { + "summary": "Get a subscription", + "description": "Get a subscription", + "tags": ["Subscription"], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionGetResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/cancel": { + "post": { + "summary": "Cancel a subscription", + "description": "Cancels an existing subscription", + "tags": ["Subscription"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCancelRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCancelResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/resume": {}, + "post": { + "summary": "Resume a subscription", + "description": "Resumes an existing subscription", + "tags": ["Subscription"], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionResumeRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionResumeResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "components": { + "schemas": { + "PriceListResponseBody": { + "description": "A list of active prcies from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/list)", + "type": "object", + "properties": { + "prices": { + "type": "array", + "items": { + "type": "object", + "description": "A price object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/object)" + } + } + } + }, + "ProductListResponseBody": { + "type": "object", + "properties": { + "products": { + "type": "array", + "items": { + "type": "object", + "description": "A product object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/object)" + } + } + } + }, + "ProductGetResponseBody": { + "description": "A product with or without prices inside. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/retrieve)", + "type": "object" + }, + "InvalidRequest": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "InvalidRequest" + } + } + }, + "InternalError": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Internal Error" + } + } + }, + "UnauthorizedError": { + "description": "Access token is missing or invalid", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Unauthorized Error" + } + } + }, + "SubscriptionCreateRequestBody": { + "description": "The request body for creating a subscription", + "type": "object", + "properties": { + "price": { + "type": "string", + "description": "The price id", + "example": "price_1234567890" + }, + "successURL": { + "type": "string", + "description": "The URL to redirect to after the customer sucessfully completes the checkout", + "example": "https://example.com/success" + }, + "cancelURL": { + "type": "string", + "description": "The URL to redirect to after the customer cancels the checkout", + "example": "https://example.com/cancel" + }, + "quantity": { + "type": "number", + "description": "The quantity of the product", + "example": 1 + }, + "trialPeriodDays": { + "type": "number", + "description": "The number of days the customer has to pay for the product", + "example": 7 + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": "abcdefghijklmnopqrstuvwxyz" + } + } + }, + "SubscriptionCreateResponseBody": { + "description": "The response body for creating a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "An object with link to checkout session. For more information see the [Stripe API documentation](https://docs.stripe.com/api/checkout/sessions/object)", + "properties": { + "sessionURL": { + "type": "string", + "description": "URL which user should follow to manage subscription" + } + } + } + } + }, + "SubscriptionUpdateRequestBody": { + "description": "The request body for updating a subscription", + "type": "object", + "properties": { + "returnURL": { + "type": "string", + "description": "URL which is used to redirect to the page with ability to update the subscription" + } + } + }, + "SubscriptionUpdateResponseBody": { + "description": "The response body for updating a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "Object with redirect url inside", + "properties": { + "sessionURL": { + "type": "string", + "description": "URL with session URL rediect to" + } + } + } + } + }, + "SubscriptionGetRequestBody": { + "description": "The request body for getting a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + } + } + }, + "SubscriptionGetResponseBody": { + "description": "The response body for getting a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" + } + } + }, + "SubscriptionListRequestBody": { + "description": "The request body for listing subscriptions", + "type": "object", + "properties": { + "customerId": { + "type": "string", + "description": "The Stripe customer id", + "example": "cus_1234567890" + } + } + }, + "SubscriptionListResponseBody": { + "description": "The response body for listing subscriptions", + "type": "object", + "properties": { + "subscriptions": { + "type": "array", + "items": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + } + } + } + }, + "SubscriptionCancelRequestBody": { + "description": "The request body for canceling a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + } + } + }, + "SubscriptionCancelResponseBody": { + "description": "The response body for canceling a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": "abcdefghijklmnopqrstuvwxyz" + } + } + }, + "SubscriptionResumeRequestBody": { + "description": "The request body for resuming a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": "abcdefghijklmnopqrstuvwxyz" + } + } + }, + "SubscriptionResumeResponseBody": { + "description": "The response body for resuming a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + } + } + }, + "APIKeyResponse": { + "description": "The general view for API key in response", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + }, + "createdAt": { + "type": "string", + "description": "The creation date of the API key", + "example": "2000-10-31T01:23:45Z", + "format": "date-time" + }, + "name": { + "type": "string", + "description": "The name of the API key", + "example": "My API Key" + }, + "expiresAt": { + "type": "string", + "description": "The expiration date of the API key", + "example": "2000-10-31T01:23:45Z", + "format": "date-time" + }, + "revoked": { + "type": "boolean", + "description": "The status of the API key", + "example": false + } + } + }, + "APIKeyCreateRequestBody": { + "description": "The request body for creating an API key", + "type": "object", + "properties": { + "expiresAt": { + "type": "string", + "description": "The expiration date of the API key", + "example": "2000-10-31T01:23:45Z", + "format": "date-time" + }, + "name": { + "type": "string", + "description": "The name of the API key", + "example": "My API Key" + } + }, + "required": ["name"] + }, + "APIKeyCreateResponseBody": { + "description": "The response body for creating an API key", + "type": "object", + "schema": { + "ref": "#/components/schemas/APIKeyResponse" + } + }, + "APIKeyCreateUnsuccessfulResponseBody": { + "description": "The response body for an unsuccessful API key creation", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "API key creation unsuccessful" + } + } + }, + "APIKeyUpdateRequestBody": { + "description": "The request body for updating an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + }, + "name": { + "type": "string", + "description": "The name of the API key", + "example": "My API Key" + }, + "expiresAt": { + "type": "string", + "description": "The expiration date of the API key", + "example": "2000-10-31T01:23:45Z", + "format": "date-time" + }, + "revoked": { + "type": "boolean", + "description": "The status of the API key", + "example": false, + "default": false + } + }, + "required": ["apiKey"] + }, + "APIKeyUpdateResponseBody": { + "description": "The response body for an unsuccessful API key update", + "type": "object", + "schema": { + "ref": "#/components/schemas/APIKeyResponse" + } + }, + "APIKeyUpdateUnsuccessfulResponseBody": { + "description": "The response body for an unsuccessful API key update", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "API key update unsuccessful" + } + } + }, + "APIKeyRevokeRequestBody": { + "description": "The request body for revoking an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + } + }, + "required": ["apiKey"] + }, + "APIKeyRevokeResponseBody": { + "description": "The response body for revoking an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + }, + "revoked": { + "type": "boolean", + "description": "The status of the API key", + "example": true + } + }, + "required": ["apiKey"] + }, + "APIKeyRevokeUnsuccessfulResponseBody": { + "description": "The response body for an unsuccessful API key revocation", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "API key revocation unsuccessful" + } + } + }, + "APIKeyListResponseBody": { + "description": "The response body for listing API keys", + "type": "object", + "properties": { + "apiKeys": { + "type": "array", + "items": { + "type": "object", + "schema": { + "ref": "#/components/schemas/APIKeyResponse" + } + } + } + } + }, + "APIKeyGetRequestBody": { + "description": "The request body for getting an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + } + }, + "required": ["apiKey"] + }, + "APIKeyGetResponseBody": { + "description": "The response body for getting an API key", + "type": "object", + "schema": { + "ref": "#/components/schemas/APIKeyResponse" + } + }, + "NotFoundError": { + "description": "The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Not Found Error" + } + } + } + } + } +} diff --git a/src/static/swagger-api.json b/src/static/swagger-api.json index a42f421f..b2cf4b99 100644 --- a/src/static/swagger-api.json +++ b/src/static/swagger-api.json @@ -1,3550 +1,3334 @@ { - "openapi": "3.0.0", - "info": { - "title": "Credential Service API for cheqd network", - "version": "2.0.0", - "description": "API service to create and manage DIDs, Verifiable Credentials, and DID-Linked Resources", - "contact": { - "name": "Cheqd Foundation Limited", - "url": "https://github.com/cheqd/credential-service", - "email": "support-github@cheqd.io" - }, - "license": { - "name": "Apache 2.0", - "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" - } - }, - "tags": [ - { - "name": "Account" - }, - { - "name": "Key" - }, - { - "name": "DID" - }, - { - "name": "Resource" - }, - { - "name": "Credential" - }, - { - "name": "Presentation" - }, - { - "name": "Credential Status" - } - ], - "externalDocs": { - "description": "Credential Service API Documentation", - "url": "https://docs.cheqd.io/identity" - }, - "paths": { - "/account": { - "get": { - "tags": [ - "Account" - ], - "summary": "Fetch custodian-mode client details.", - "description": "This endpoint returns the custodian-mode client details for authenticated users.", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Customer" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/account/idtoken": { - "get": { - "tags": [ - "Account" - ], - "summary": "Fetch IdToken.", - "description": "This endpoint returns IdToken as JWT with list of user roles inside", - "deprecated": true, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "idToken": { - "type": "string" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/account/create": { - "post": { - "tags": [ - "Account" - ], - "summary": "Create an client for an authenticated user.", - "description": "This endpoint creates a client in the custodian-mode for an authenticated user", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/AccountCreateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountCreateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "idToken": { - "type": "string" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/create/unencrypted": { - "post": { - "tags": [ - "Credential Status" - ], - "summary": "Create an unencrypted StatusList2021 credential status list.", - "description": "This endpoint creates an unencrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", - "parameters": [ - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", - "required": true, - "schema": { - "type": "string", - "enum": [ - "revocation", - "suspension" - ] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/create/encrypted": { - "post": { - "tags": [ - "Credential Status" - ], - "summary": "Create an encrypted StatusList2021 credential status list.", - "description": "This endpoint creates an encrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", - "parameters": [ - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", - "required": true, - "schema": { - "type": "string", - "enum": [ - "revocation", - "suspension" - ] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateEncryptedFormRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateEncryptedJsonRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateEncryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/update/unencrypted": { - "post": { - "tags": [ - "Credential Status" - ], - "summary": "Update an existing unencrypted StatusList2021 credential status list.", - "parameters": [ - { - "in": "query", - "name": "statusAction", - "description": "The update action to be performed on the unencrypted status list, can be revoke, suspend or reinstate", - "required": true, - "schema": { - "type": "string", - "enum": [ - "revoke", - "suspend", - "reinstate" - ] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/update/encrypted": { - "post": { - "tags": [ - "Credential Status" - ], - "summary": "Update an existing encrypted StatusList2021 credential status list.", - "parameters": [ - { - "in": "query", - "name": "statusAction", - "description": "The update action to be performed on the encrypted status list, can be revoke, suspend or reinstate", - "required": true, - "schema": { - "type": "string", - "enum": [ - "revoke", - "suspend", - "reinstate" - ] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedFormRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedJsonRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/check": { - "post": { - "tags": [ - "Credential Status" - ], - "summary": "Check a StatusList2021 index for a given Verifiable Credential.", - "description": "This endpoint checks a StatusList2021 index for a given Verifiable Credential and reports whether it is revoked or suspended. It offers a standalone method for checking an index without passing the entire Verifiable Credential or Verifiable Presentation.", - "parameters": [ - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension.", - "required": true, - "schema": { - "type": "string", - "enum": [ - "revocation", - "suspension" - ] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCheckRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCheckRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCheckResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/search": { - "get": { - "tags": [ - "Credential Status" - ], - "summary": "Fetch StatusList2021 DID-Linked Resource based on search criteria.", - "parameters": [ - { - "in": "query", - "name": "did", - "description": "The DID of the issuer of the status list.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension.", - "schema": { - "type": "string", - "enum": [ - "revocation", - "suspension" - ] - } - }, - { - "in": "query", - "name": "statusListName", - "description": "The name of the StatusList2021 DID-Linked Resource.", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusListSearchResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/issue": { - "post": { - "tags": [ - "Credential" - ], - "summary": "Issue a Verifiable Credential", - "description": "This endpoint issues a Verifiable Credential. As input it takes the list of issuerDid, subjectDid, attributes, and other parameters of the credential to be issued.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Credential" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/verify": { - "post": { - "tags": [ - "Credential" - ], - "summary": "Verify a Verifiable Credential.", - "description": "This endpoint verifies a Verifiable Credential passed to it. As input, it can take the VC-JWT as a string or the entire credential itself.", - "operationId": "verify", - "parameters": [ - { - "in": "query", - "name": "verifyStatus", - "description": "If set to `true` the verification will also check the status of the credential. Requires the VC to have a `credentialStatus` property.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "fetchRemoteContexts", - "description": "When dealing with JSON-LD you also MUST provide the proper contexts. Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "allowDeactivatedDid", - "description": "If set to `true` allow to verify credential which based on deactivated DID.", - "schema": { - "type": "boolean", - "default": false - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialVerifyRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialVerifyRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/VerifyCredentialResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/revoke": { - "post": { - "tags": [ - "Credential" - ], - "summary": "Revoke a Verifiable Credential.", - "description": "This endpoint revokes a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself. The StatusList2021 resource should already be setup in the VC and `credentialStatus` property present in the VC.", - "operationId": "revoke", - "parameters": [ - { - "in": "query", - "name": "publish", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RevocationResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/suspend": { - "post": { - "tags": [ - "Credential" - ], - "summary": "Suspend a Verifiable Credential.", - "description": "This endpoint suspends a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself.", - "operationId": "suspend", - "parameters": [ - { - "in": "query", - "name": "publish", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "schema": { - "type": "boolean" - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuspensionResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/reinstate": { - "post": { - "tags": [ - "Credential" - ], - "summary": "Reinstate a suspended Verifiable Credential.", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "operationId": "reinstate", - "parameters": [ - { - "in": "query", - "name": "publish", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "schema": { - "type": "boolean" - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnsuspensionResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/create": { - "post": { - "tags": [ - "DID" - ], - "summary": "Create a DID Document.", - "description": "This endpoint creates a DID and associated DID Document. As input, it can take the DID Document parameters via a form, or the fully-assembled DID Document itself.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidCreateRequestFormBased" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidCreateRequestJson" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/did/update": { - "post": { - "tags": [ - "DID" - ], - "summary": "Update a DID Document.", - "description": "This endpoint updates a DID Document. As an input, it can take JUST the sections/parameters that need to be updated in the DID Document (in this scenario, it fetches the current DID Document and applies the updated section). Alternatively, it take the fully-assembled DID Document with updated sections as well as unchanged sections.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidUpdateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidUpdateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidUpdateResponse" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/import": { - "post": { - "tags": [ - "DID" - ], - "summary": "Import a DID Document.", - "description": "This endpoint imports a decentralized identifier associated with the user's account for custodian-mode clients.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidImportRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidImportRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/did/deactivate/{did}": { - "post": { - "tags": [ - "DID" - ], - "summary": "Deactivate a DID Document.", - "description": "This endpoint deactivates a DID Document by taking the DID identifier as input. Must be called and signed by the DID owner.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier to deactivate.", - "schema": { - "type": "string" - }, - "required": true - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidDeactivateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidDeactivateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeactivatedDidResolution" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/list": { - "get": { - "tags": [ - "DID" - ], - "summary": "Fetch DIDs associated with an account.", - "description": "This endpoint returns the list of DIDs controlled by the account.", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/search/{did}": { - "get": { - "tags": [ - "DID" - ], - "summary": "Resolve a DID Document.", - "description": "Resolve a DID Document by DID identifier. Also supports DID Resolution Queries as defined in the W3C DID Resolution specification.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier to resolve.", - "schema": { - "type": "string" - }, - "required": true, - "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - { - "in": "query", - "name": "metadata", - "description": "Return only metadata of DID Document instead of actual DID Document.", - "schema": { - "type": "boolean" - } - }, - { - "in": "query", - "name": "versionId", - "description": "Unique UUID version identifier of DID Document. Allows for fetching a specific version of the DID Document. See cheqd DID Method Specification for more details.", - "schema": { - "type": "string", - "format": "uuid" - }, - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - { - "in": "query", - "name": "versionTime", - "description": "Returns the closest version of the DID Document *at* or *before* specified time. See DID Resolution handling for `did:cheqd` for more details.", - "schema": { - "type": "string", - "format": "date-time" - }, - "example": "1970-01-01T00:00:00Z" - }, - { - "in": "query", - "name": "transformKeys", - "description": "This directive transforms the Verification Method key format from the version in the DID Document to the specified format chosen below.", - "schema": { - "type": "string", - "enum": [ - "Ed25519VerificationKey2018", - "Ed25519VerificationKey2020", - "JsonWebKey2020" - ] - } - }, - { - "in": "query", - "name": "service", - "description": "Query DID Document for a specific Service Endpoint by Service ID (e.g., `service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`). This will typically redirect to the Service Endpoint based on DID Resolution specification algorithm.", - "schema": { - "type": "string" - }, - "example": "service-1" - }, - { - "in": "query", - "name": "relativeRef", - "description": "Relative reference is a query fragment appended to the Service Endpoint URL. **Must** be used along with the `service` query property above. See DID Resolution specification algorithm for more details.", - "schema": { - "type": "string" - }, - "example": "/path/to/file" - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidResolution" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/key/create": { - "post": { - "tags": [ - "Key" - ], - "summary": "Create an identity key pair.", - "description": "This endpoint creates an identity key pair associated with the user's account for custodian-mode clients.", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/key/import": { - "post": { - "tags": [ - "Key" - ], - "summary": "Import an identity key pair.", - "description": "This endpoint imports an identity key pair associated with the user's account for custodian-mode clients.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/KeyImportRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyImportRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/key/read/{kid}": { - "get": { - "tags": [ - "Key" - ], - "summary": "Fetch an identity key pair.", - "description": "This endpoint fetches an identity key pair's details for a given key ID. Only the user account associated with the custodian-mode client can fetch the key pair.", - "parameters": [ - { - "name": "kid", - "description": "Key ID of the identity key pair to fetch.", - "in": "path", - "schema": { - "type": "string" - }, - "required": true - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/presentation/create": { - "post": { - "tags": [ - "Presentation" - ], - "summary": "!!! WARN. Such endpoint is made mostly for testing purposes and it is not supposed to be used in production !!! Create a Verifiable Presentation from credential(s).", - "description": "This endpoint creates a Verifiable Presentation from credential(s). As input, it can take the credential(s) as a string or the entire credential(s) itself. \n !!! WARN. Such endpoint is made only for testing purposes !!!", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/PresentationCreateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/PresentationCreateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PresentationCreateResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/presentation/verify": { - "post": { - "tags": [ - "Presentation" - ], - "summary": "Verify a Verifiable Presentation generated from credential(s).", - "description": "This endpoint verifies the Verifiable Presentation generated from credential(s). As input, it can take the Verifiable Presentation JWT as a string or the entire Verifiable Presentation itself.", - "parameters": [ - { - "in": "query", - "name": "verifyStatus", - "description": "If set to `true` the verification will also check the status of the presentation. Requires the VP to have a `credentialStatus` property.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "fetchRemoteContexts", - "description": "When dealing with JSON-LD you also MUST provide the proper contexts. * Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "allowDeactivatedDid", - "description": "If set to `true` allow to verify credential which based on deactivated DID.", - "schema": { - "type": "boolean", - "default": false - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/PresentationVerifyRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/PresentationVerifyRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/VerifyPresentationResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/resource/create/{did}": { - "post": { - "tags": [ - "Resource" - ], - "summary": "Create a DID-Linked Resource.", - "description": "This endpoint creates a DID-Linked Resource. As input, it can take the DID identifier and the resource parameters via a form, or the fully-assembled resource itself.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier to link the resource to.", - "schema": { - "type": "string" - }, - "required": true - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CreateResourceRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateResourceRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ResourceMetadata" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/resource/search/{did}": { - "get": { - "tags": [ - "Resource" - ], - "summary": "Get a DID-Linked Resource.", - "description": "This endpoint returns the DID-Linked Resource for a given DID identifier and resource identifier.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier", - "schema": { - "type": "string" - }, - "required": true, - "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - { - "in": "query", - "name": "resourceId", - "description": "Fetch a DID-Linked Resource by Resource ID unique identifier. Since this is a unique identifier, other Resource query parameters are not required. See DID-Linked Resources for more details.", - "schema": { - "type": "string", - "format": "uuid" - }, - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - { - "in": "query", - "name": "resourceName", - "description": "Filter a DID-Linked Resource query by Resource Name. See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "cheqd-issuer-logo" - }, - { - "in": "query", - "name": "resourceType", - "description": "Filter a DID-Linked Resource query by Resource Type. See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "CredentialArtwork" - }, - { - "in": "query", - "name": "resourceVersion", - "description": "Filter a DID-Linked Resource query by Resource Version, which is an optional free-text field used by issuers (e.g., \"v1\", \"Final Version\", \"1st January 1970\" etc). See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "v1" - }, - { - "in": "query", - "name": "resourceVersionTime", - "description": "Filter a DID-Linked Resource query which returns the closest version of the Resource *at* or *before* specified time. See DID-Linked Resources for more details.", - "schema": { - "type": "string", - "format": "date-time" - }, - "example": "1970-01-01T00:00:00Z" - }, - { - "in": "query", - "name": "checksum", - "description": "Request integrity check against a given DID-Linked Resource by providing a SHA-256 checksum hash. See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "dc64474d062ed750a66bad58cb609928de55ed0d81defd231a4a4bf97358e9ed" - }, - { - "in": "query", - "name": "resourceMetadata", - "description": "Return only metadata of DID-Linked Resource instead of actual DID-Linked Resource. Mutually exclusive with some of the other parameters.", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "any": { - "schema": { - "type": "object" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - } - }, - "components": { - "schemas": { - "AlsoKnownAs": { - "type": "object", - "properties": { - "alsoKnownAs": { - "type": "array", - "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", - "items": { - "type": "object", - "properties": { - "uri": { - "type": "string", - "format": "uri", - "description": "URI where the DID-Linked Resource can be fetched from. Can be any type of URI (e.g., DID, HTTPS, IPFS, etc.)" - }, - "description": { - "type": "string", - "description": "Optional description of the URI." - } - } - } - } - } - }, - "CredentialRequest": { - "description": "Input fields for the creating a Verifiable Credential.", - "type": "object", - "additionalProperties": false, - "properties": { - "issuerDid": { - "description": "DID of the Verifiable Credential issuer. This needs to be a `did:cheqd` DID.", - "type": "string", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "subjectDid": { - "description": "DID of the Verifiable Credential holder/subject. This needs to be a `did:key` DID.", - "type": "string", - "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" - }, - "attributes": { - "description": "JSON object containing the attributes to be included in the credential.", - "type": "object", - "example": { - "name": "Bob", - "gender": "male" - } - }, - "@context": { - "description": "Optional properties to be included in the `@context` property of the credential.", - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "https://schema.org/schema.jsonld", - "https://veramo.io/contexts/profile/v1" - ] - }, - "type": { - "description": "Optional properties to be included in the `type` property of the credential.", - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "Person" - ] - }, - "expirationDate": { - "description": "Optional expiration date according to the VC Data Model specification.", - "type": "string", - "format": "date-time", - "example": "2023-06-08T13:49:28.000Z" - }, - "format": { - "description": "Format of the Verifiable Credential. Defaults to VC-JWT.", - "type": "string", - "enum": [ - "jwt", - "jsonld" - ], - "example": "jwt" - }, - "credentialStatus": { - "description": "Optional `credentialStatus` properties for VC revocation or suspension. Takes `statusListName` and `statusListPurpose` as inputs.", - "type": "object", - "required": [ - "statusPurpose", - "statusListName" - ], - "properties": { - "statusPurpose": { - "type": "string", - "enum": [ - "revocation", - "suspension" - ] - }, - "statusListName": { - "type": "string" - }, - "statusListIndex": { - "type": "number" - }, - "statusListVersion": { - "type": "string", - "format": "date-time" - }, - "statusListRangeStart": { - "type": "number" - }, - "statusListRangeEnd": { - "type": "number" - }, - "indexNotIn": { - "type": "number" - } - }, - "example": { - "statusPurpose": "revocation", - "statusListName": "employee-credentials" - } - } - }, - "required": [ - "issuerDid", - "subjectDid", - "attributes" - ], - "example": { - "issuerDid": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "subjectDid": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", - "attributes": { - "gender": "male", - "name": "Bob" - }, - "@context": [ - "https://schema.org" - ], - "type": [ - "Person" - ], - "format": "jwt", - "credentialStatus": { - "statusPurpose": "revocation", - "statusListName": "employee-credentials", - "statusListIndex": 10 - } - } - }, - "Credential": { - "description": "Input fields for revoking/suspending a Verifiable Credential.", - "type": "object", - "additionalProperties": false, - "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "https://www.w3.org/2018/credentials/v1", - "https://schema.org", - "https://veramo.io/contexts/profile/v1" - ] - }, - "type": { - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "VerifiableCredential", - "Person" - ] - }, - "expirationDate": { - "type": "string", - "format": "date-time", - "example": "2023-06-08T13:49:28.000Z" - }, - "issuer": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "DID", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - } - } - }, - "credentialSubject": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "DID", - "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" - } - } - }, - "credentialStatus": { - "type": "object", - "properties": { - "id": { - "type": "string", - "example": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20" - }, - "statusListIndex": { - "type": "number", - "example": 20 - }, - "statusPurpose": { - "type": "string", - "enum": [ - "revocation", - "suspension" - ], - "example": "suspension" - }, - "type": { - "type": "string", - "enum": [ - "StatusList2021Entry" - ] - } - } - }, - "issuanceDate": { - "type": "string", - "format": "date-time", - "example": "2023-06-08T13:49:28.000Z" - }, - "proof": { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "jwt": { - "type": "string" - } - }, - "example": { - "type": "JwtProof2020", - "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg" - } - } - }, - "example": { - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://schema.org", - "https://veramo.io/contexts/profile/v1" - ], - "credentialSubject": { - "gender": "male", - "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", - "name": "Bob" - }, - "credentialStatus": { - "id": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20", - "statusIndex": 20, - "statusPurpose": "suspension", - "type": "StatusList2021Entry" - }, - "issuanceDate": "2023-06-08T13:49:28.000Z", - "issuer": { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "proof": { - "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg", - "type": "JwtProof2020" - }, - "type": [ - "VerifiableCredential", - "Person" - ] - } - }, - "CredentialRevokeRequest": { - "type": "object", - "properties": { - "credential": { - "description": "Verifiable Credential to be revoked as a VC-JWT string or a JSON object.", - "oneOf": [ - { - "type": "object" - }, - { - "type": "string" - } - ] - }, - "symmetricKey": { - "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource. Required if the StatusList2021 DID-Linked Resource is encrypted.", - "type": "string" - } - } - }, - "RevocationResult": { - "properties": { - "revoked": { - "type": "boolean", - "example": true - } - } - }, - "SuspensionResult": { - "properties": { - "suspended": { - "type": "boolean", - "example": true - } - } - }, - "UnsuspensionResult": { - "properties": { - "unsuspended": { - "type": "boolean", - "example": true - } - } - }, - "CredentialVerifyRequest": { - "type": "object", - "properties": { - "credential": { - "description": "Verifiable Credential to be verified as a VC-JWT string or a JSON object.", - "type": "object" - }, - "policies": { - "description": "Custom verification policies to execute when verifying credential.", - "type": "object", - "properties": { - "issuanceDate": { - "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "expirationDate": { - "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "audience": { - "description": "Policy to skip the audience check when set to `false`.", - "type": "boolean", - "default": false - } - } - } - } - }, - "VerifyPresentationResult": { - "type": "object", - "properties": { - "verified": { - "type": "boolean" - }, - "issuer": { - "type": "string" - }, - "signer": { - "type": "object" - }, - "jwt": { - "type": "string" - }, - "verifiableCredential": { - "type": "object" - } - } - }, - "VerifyCredentialResult": { - "type": "object", - "properties": { - "verified": { - "type": "boolean" - }, - "issuer": { - "type": "string" - }, - "signer": { - "type": "object" - }, - "jwt": { - "type": "string" - }, - "verifiableCredential": { - "type": "object" - } - }, - "example": { - "verified": true, - "polices": {}, - "issuer": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "signer": { - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", - "type": "Ed25519VerificationKey2018" - } - } - }, - "PresentationCreateRequest": { - "type": "object", - "required": [ - "credentials" - ], - "properties": { - "credentials": { - "description": "Verifiable Credentials to be used for VP-JWT creation as a VP-JWT strings or a JSON objectsf.", - "type": "array", - "items": { - "type": "object" - } - }, - "holderDid": { - "description": "DID of holder", - "type": "string" - }, - "verifierDid": { - "description": "DID of verifier", - "type": "string" - } - } - }, - "PresentationVerifyRequest": { - "type": "object", - "required": [ - "presentation" - ], - "properties": { - "presentation": { - "description": "Verifiable Presentation to be verified as a VP-JWT string or a JSON object.", - "type": "object" - }, - "verifierDid": { - "description": "Provide an optional verifier DID (also known as 'domain' parameter), if the verifier DID in the presentation is not managed in the wallet.", - "type": "string" - }, - "makeFeePayment": { - "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", - "type": "boolean", - "default": false - }, - "policies": { - "description": "Custom verification policies to execute when verifying presentation.", - "type": "object", - "properties": { - "issuanceDate": { - "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "expirationDate": { - "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "audience": { - "description": "Policy to skip the audience check when set to `false`.", - "type": "boolean", - "default": false - } - } - } - } - }, - "CredentialStatusCreateBody": { - "allOf": [ - { - "type": "object", - "required": [ - "did", - "statusListName" - ], - "properties": { - "did": { - "description": "DID of the StatusList2021 publisher.", - "type": "string", - "format": "uri" - }, - "statusListName": { - "description": "The name of the StatusList2021 DID-Linked Resource to be created.", - "type": "string" - }, - "length": { - "description": "The length of the status list to be created. The default and minimum length is 140000 which is 16kb.", - "type": "integer", - "minimum": 0, - "exclusiveMinimum": true, - "default": 140000 - }, - "encoding": { - "description": "The encoding format of the StatusList2021 DiD-Linked Resource to be created.", - "type": "string", - "default": "base64url", - "enum": [ - "base64url", - "base64", - "hex" - ] - }, - "statusListVersion": { - "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - { - "$ref": "#/components/schemas/AlsoKnownAs" - } - ] - }, - "CredentialStatusCreateUnencryptedRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCreateBody" - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials", - "length": 140000, - "encoding": "base64url" - } - }, - "CredentialStatusUnencryptedResult": { - "type": "object", - "properties": { - "resource": { - "type": "object", - "properties": { - "StatusList2021": { - "type": "object", - "properties": { - "encodedList": { - "type": "string", - "example": "H4sIAAAAAAAAA-3BAQ0AAADCoPdPbQ8HFAAAAAAAAAAAAAAAAAAAAADwaDhDr_xcRAAA" - }, - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "validFrom": { - "type": "string", - "format": "date-time", - "example": "2023-06-26T11:45:19.349Z" - } - } - }, - "metadata": { - "type": "object", - "properties": { - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "encoding": { - "type": "string", - "example": "base64url" - }, - "encrypted": { - "type": "boolean", - "example": false - } - } - } - } - }, - "resourceMetadata": { - "type": "object", - "example": { - "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceName": "cheqd-employee-credentials", - "resourceType": "StatusList2021Revocation", - "mediaType": "application/json", - "resourceVersion": "1.0.0", - "created": "2023-06-26T11:45:20Z", - "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", - "previousVersionId": null, - "nextVersionId": null - } - } - } - }, - "CredentialStatusCreateUnencryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "created": { - "type": "boolean", - "example": true - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" - } - ] - }, - "CredentialStatusEncryptedPaymentConditionsBody": { - "type": "object", - "properties": { - "feePaymentAddress": { - "description": "The cheqd/Cosmos payment address where payments to unlock the encrypted StatusList2021 DID-Linked Resource need to be sent.", - "type": "string", - "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" - }, - "feePaymentAmount": { - "description": "Amount in CHEQ tokens to unlock the encrypted StatusList2021 DID-Linked Resource.", - "type": "number", - "minimum": 0, - "exclusiveMinimum": true, - "default": 20 - }, - "feePaymentWindow": { - "description": "Time window (in minutes) within which the payment to unlock the encrypted StatusList2021 DID-Linked Resource is considered valid.", - "type": "number", - "minimum": 0, - "exclusiveMinimum": true, - "default": 10 - } - } - }, - "CredentialStatusEncryptedPaymentConditionsJson": { - "type": "object", - "properties": { - "paymentConditions": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" - } - ] - } - } - }, - "CredentialStatusCreateEncryptedFormRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCreateBody" - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" - }, - { - "type": "object", - "required": [ - "feePaymentAddress", - "feePaymentAmount", - "feePaymentWindow" - ] - } - ] - }, - "CredentialStatusCreateEncryptedJsonRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCreateBody" - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" - }, - { - "type": "object", - "required": [ - "paymentConditions" - ] - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials-encrypted", - "paymentConditions": [ - { - "feePaymentAddress": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg", - "feePaymentAmount": 20, - "feePaymentWindow": 10 - } - ] - } - }, - "CredentialStatusEncryptedResult": { - "type": "object", - "properties": { - "resource": { - "type": "object", - "properties": { - "StatusList2021": { - "type": "object", - "properties": { - "encodedList": { - "type": "string", - "example": "496fdfbeb745b4db03fcdb40566f9c4c4a1c0f184b31255e641b6e7bdfb9b6946c12be87ca3763be0393c00b67ac1e8737c106b32f46ef59c765754415b5e8cc7c65fccaa3374620430ea476301a5e0dd63340e7a27a68bc627518471f22e4a2" - }, - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "validFrom": { - "type": "string", - "format": "date-time", - "example": "2023-06-26T11:45:19.349Z" - } - } - }, - "metadata": { - "type": "object", - "properties": { - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "encoding": { - "type": "string", - "example": "base64url" - }, - "encrypted": { - "type": "boolean", - "example": true - }, - "encryptedSymmetricKey": { - "type": "string", - "example": "b11182dc524b8181f9a6aef4c4ad0a1c14e40033b9112dffd8d1bcf6cc3b85abc07ded2205ee94068a99f4202502cb0855f322583fa6ce1534d3a05bf36891766ea2c5f90a982b3040680762977d404d758a2370224a239c8279aa7d21e980931c42055b17ca4c7dbffa4782480a8b6279cf989b2f166d5fdb4b2c1b5a63927200000000000000203018dcaba26df45a415bb599218b27ca853a70289d7a3ed3ed0e3730452e8f8d9af91b6e71312565d2c069341f6660ab" - }, - "paymentConditions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "feePaymentAddress": { - "type": "string", - "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" - }, - "feePaymentAmount": { - "type": "string", - "example": "20000000000ncheq" - }, - "intervalInSeconds": { - "type": "number", - "example": 600 - }, - "type": { - "type": "string", - "example": "timelockPayment" - } - } - } - } - } - }, - "resourceMetadata": { - "type": "object", - "example": { - "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceName": "cheqd-revocation-encrypted-1", - "resourceType": "StatusList2021Revocation", - "mediaType": "application/json", - "resourceVersion": "2023-06-26T11:45:19.349Z", - "created": "2023-06-26T11:45:20Z", - "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", - "previousVersionId": null, - "nextVersionId": null - } - }, - "symmetricKey": { - "type": "string", - "example": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" - } - } - } - } - }, - "CredentialStatusCreateEncryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "created": { - "type": "boolean", - "example": true - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedResult" - } - ] - }, - "CredentialStatusUpdateBody": { - "type": "object", - "required": [ - "did", - "statusListName", - "indices" - ], - "properties": { - "did": { - "description": "DID of the StatusList2021 publisher.", - "type": "string", - "format": "uri" - }, - "statusListName": { - "description": "The name of the StatusList2021 DID-Linked Resource to be updated.", - "type": "string" - }, - "indices": { - "description": "List of credential status indices to be updated. The indices must be in the range of the status list.", - "type": "array", - "items": { - "type": "integer", - "minimum": 0, - "exclusiveMinimum": false - } - }, - "statusListVersion": { - "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - "CredentialStatusUpdateUnencryptedRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUpdateBody" - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials", - "indices": [ - 10, - 3199, - 12109, - 130999 - ] - } - }, - "CredentialStatusUpdateUnencryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "updated": { - "type": "boolean", - "example": true - } - } - }, - { - "oneOf": [ - { - "$ref": "#/components/schemas/RevocationResult" - }, - { - "$ref": "#/components/schemas/SuspensionResult" - }, - { - "$ref": "#/components/schemas/UnsuspensionResult" - } - ] - }, - { - "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" - } - ] - }, - "CredentialStatusUpdateEncryptedFormRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUpdateBody" - }, - { - "type": "object", - "required": [ - "symmetricKey" - ], - "properties": { - "symmetricKey": { - "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" - } - ] - }, - "CredentialStatusUpdateEncryptedJsonRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUpdateBody" - }, - { - "type": "object", - "required": [ - "symmetricKey" - ], - "properties": { - "symmetricKey": { - "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials-encrypted", - "indices": [ - 10, - 3199, - 12109, - 130999 - ], - "symmetricKey": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" - } - }, - "CredentialStatusUpdateEncryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "updated": { - "type": "boolean", - "example": true - } - } - }, - { - "oneOf": [ - { - "$ref": "#/components/schemas/RevocationResult" - }, - { - "$ref": "#/components/schemas/SuspensionResult" - }, - { - "$ref": "#/components/schemas/UnsuspensionResult" - } - ] - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedResult" - } - ] - }, - "CredentialStatusCheckRequest": { - "type": "object", - "required": [ - "did", - "statusListName", - "index" - ], - "properties": { - "did": { - "description": "DID of the StatusList2021 publisher.", - "type": "string", - "format": "uri" - }, - "statusListName": { - "description": "The name of the StatusList2021 DID-Linked Resource to be checked.", - "type": "string" - }, - "index": { - "description": "Credential status index to be checked for revocation or suspension.", - "type": "integer", - "minimum": 0, - "exclusiveMinimum": false - }, - "makeFeePayment": { - "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", - "type": "boolean", - "default": true - } - } - }, - "CredentialStatusCheckResult": { - "oneOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCheckRevocationResult" - }, - { - "$ref": "#/components/schemas/CredentialStatusCheckSuspensionResult" - } - ] - }, - "CredentialStatusCheckRevocationResult": { - "type": "object", - "properties": { - "checked": { - "type": "boolean", - "example": true - }, - "revoked": { - "type": "boolean", - "example": false - } - } - }, - "CredentialStatusCheckSuspensionResult": { - "type": "object", - "properties": { - "checked": { - "type": "boolean", - "example": true - }, - "suspended": { - "type": "boolean", - "example": false - } - } - }, - "CredentialStatusListSearchResult": { - "allOf": [ - { - "type": "object", - "properties": { - "found": { - "type": "boolean", - "example": true - } - } - }, - { - "oneOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedResult" - } - ] - } - ] - }, - "KeyImportRequest": { - "type": "object", - "properties": { - "alias": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "Ed25519", - "Secp256k1" - ] - }, - "privateKeyHex": { - "type": "string" - } - } - }, - "KeyResult": { - "type": "object", - "properties": { - "kid": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "Ed25519", - "Secp256k1" - ] - }, - "publicKeyHex": { - "type": "string" - } - } - }, - "DidDocument": { - "description": "This input field contains either a complete DID document, or an incremental change (diff) to a DID document. See Universal DID Registrar specification.", - "type": "object", - "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - } - }, - "id": { - "type": "string" - }, - "controllers": { - "type": "array", - "items": { - "type": "string" - } - }, - "verificationMethod": { - "type": "array", - "items": { - "$ref": "#/components/schemas/VerificationMethod" - } - }, - "service": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "authentication": { - "type": "array", - "items": { - "type": "string" - } - }, - "assertionMethod": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityInvocation": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityDelegation": { - "type": "array", - "items": { - "type": "string" - } - }, - "keyAgreement": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "@context": [ - "https://www.w3.org/ns/did/v1" - ], - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "controller": [ - "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - ], - "verificationMethod": [ - { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "type": "Ed25519VerificationKey2018", - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "publicKeyBase58": "z6MkkVbyHJLLjdjU5B62DaJ4mkdMdUkttf9UqySSkA9bVTeZ" - } - ], - "authentication": [ - "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1" - ], - "service": [ - { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", - "type": "LinkedDomains", - "serviceEndpoint": [ - "https://example.com" - ] - } - ] - } - }, - "DidDocumentWithoutVerificationMethod": { - "type": "object", - "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - } - }, - "id": { - "type": "string" - }, - "controllers": { - "type": "array", - "items": { - "type": "string" - } - }, - "service": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "authentication": { - "type": "array", - "items": { - "type": "string" - } - }, - "assertionMethod": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityInvocation": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityDelegation": { - "type": "array", - "items": { - "type": "string" - } - }, - "keyAgreement": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "@context": [ - "https://www.w3.org/ns/did/v1" - ], - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "controller": [ - "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - ], - "authentication": [ - "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1" - ], - "service": [ - { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", - "type": "LinkedDomains", - "serviceEndpoint": [ - "https://example.com" - ] - } - ] - } - }, - "DidCreateRequestFormBased": { - "type": "object", - "properties": { - "network": { - "description": "Network to create the DID on (testnet or mainnet)", - "type": "string", - "enum": [ - "testnet", - "mainnet" - ] - }, - "identifierFormatType": { - "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", - "type": "string", - "enum": [ - "uuid", - "base58btc" - ] - }, - "verificationMethodType": { - "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", - "type": "string", - "enum": [ - "Ed25519VerificationKey2018", - "JsonWebKey2020", - "Ed25519VerificationKey2020" - ] - }, - "service": { - "description": "It's a list of special objects which are designed to build the actual service. It's almost the same as in DID Core specification, but instead of `id` it utilises `idFragment` field for making the right `id` for each service. !!! WARN. Cause swagger-ui does not handle x-ww-form based arrays correctly, please frame all your services in brackets while using swagger UI. !!!", - "type": "array", - "items": { - "type": "object", - "properties": { - "idFragment": { - "type": "string" - }, - "type": { - "type": "string" - }, - "serviceEndpoint": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "example": [ - { - "idFragment": "service-1", - "type": "LinkedDomains", - "serviceEndpoint": [ - "https://example.com" - ] - } - ] - }, - "key": { - "description": "The unique identifier in hexadecimal public key format used in the verification method to create the DID.", - "type": "string" - }, - "@context": { - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "https://www.w3.org/ns/did/v1" - ] - } - } - }, - "DidCreateRequestJson": { - "type": "object", - "properties": { - "network": { - "description": "Network to create the DID on (testnet or mainnet)", - "type": "string", - "enum": [ - "testnet", - "mainnet" - ] - }, - "identifierFormatType": { - "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", - "type": "string", - "enum": [ - "uuid", - "base58btc" - ] - }, - "assertionMethod": { - "description": "Usually a reference to a Verification Method. An Assertion Method is required to issue JSON-LD credentials. See DID Core specification for more details.", - "type": "boolean", - "default": true - }, - "options": { - "type": "object", - "properties": { - "key": { - "type": "string", - "example": "8255ddadd75695e01f3d98fcec8ccc7861a030b317d4326b0e48a4d579ddc43a" - }, - "verificationMethodType": { - "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", - "type": "string", - "enum": [ - "Ed25519VerificationKey2018", - "JsonWebKey2020", - "Ed25519VerificationKey2020" - ] - } - } - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocumentWithoutVerificationMethod" - } - } - }, - "DidImportRequest": { - "type": "object", - "properties": { - "did": { - "type": "string", - "description": "DID to be imported", - "format": "uri", - "required": true - }, - "keys": { - "type": "array", - "description": "List of keys required to import the DID", - "required": true, - "items": { - "$ref": "#/components/schemas/KeyImportRequest" - } - } - } - }, - "PresentationCreateResult": { - "type": "object", - "properties": { - "vp": { - "type": "object", - "description": "Verifiable Presentation which could be provided to the verifier." - }, - "nbf": { - "type": "integer", - "description": "Unix timestamp of the earliest time that the Verifiable Presentation is valid." - }, - "iss": { - "type": "string", - "description": "DID of the issuer of the Verifiable Presentation. (Here it's supposed to be a holder DID)" - }, - "aud": { - "type": "array", - "items": { - "type": "string" - }, - "description": "DID of the verifier of the Verifiable Presentation." - } - }, - "example": { - "vp": { - "@context": [ - "https://www.w3.org/2018/credentials/v1" - ], - "type": [ - "VerifiablePresentation" - ], - "verifiableCredential": [ - "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc2NoZW1hLm9yZy9zY2hlbWEuanNvbmxkIiwiaHR0cHM6Ly92ZXJhbW8uaW8vY29udGV4dHMvcHJvZmlsZS92MSIsImh0dHBzOi8vdzNpZC5vcmcvdmMtc3RhdHVzLWxpc3QtMjAyMS92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiUGVyc29uIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7Im5hbWUiOiJCb2IiLCJnZW5kZXIiOiJtYWxlIn0sImNyZWRlbnRpYWxTdGF0dXMiOnsiaWQiOiJodHRwczovL3Jlc29sdmVyLmNoZXFkLm5ldC8xLjAvaWRlbnRpZmllcnMvZGlkOmNoZXFkOnRlc3RuZXQ6OTBkNWMxNDEtNzI0Zi00N2FkLTlhZTctYTdjMzNhOWU1NjQzP3Jlc291cmNlTmFtZT1zdXNwZW5zaW9uRW4mcmVzb3VyY2VUeXBlPVN0YXR1c0xpc3QyMDIxU3VzcGVuc2lvbiMxMzMzOCIsInR5cGUiOiJTdGF0dXNMaXN0MjAyMUVudHJ5Iiwic3RhdHVzUHVycG9zZSI6InN1c3BlbnNpb24iLCJzdGF0dXNMaXN0SW5kZXgiOiIxMzMzOCJ9fSwic3ViIjoiZGlkOmtleTp6Nk1raGFYZ0JaRHZvdERrTDUyNTdmYWl6dGlHaUMyUXRLTEdwYm5uRUd0YTJkb0siLCJuYmYiOjE3MDA0NzM0MTYsImlzcyI6ImRpZDpjaGVxZDp0ZXN0bmV0OjkwZDVjMTQxLTcyNGYtNDdhZC05YWU3LWE3YzMzYTllNTY0MyJ9.-14Ril1pZEy2HEEo48gTJr2yOtGxBhUGTFmzVdjAtyhFRsW5zZg9onHt6V9JQ8BaiYBlTkP9GzTnJ-O6hdiyCw" - ] - }, - "nbf": 1700744275, - "iss": "did:cheqd:testnet:4b846d0f-2f6c-4ab6-9fe2-5b8db301c83c", - "aud": [ - "did:cheqd:testnet:8c71e9b6-c5a3-4250-8c58-fa591533cd22" - ] - } - }, - "DidResult": { - "type": "object", - "properties": { - "did": { - "type": "string" - }, - "controllerKeyId": { - "type": "string" - }, - "keys": { - "type": "array", - "items": { - "type": "object" - } - }, - "services": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - } - } - }, - "DidUpdateResponse": { - "type": "object", - "properties": { - "did": { - "type": "string" - }, - "controllerKeyId": { - "type": "string", - "description": "The default key id of which is the key associated with the first verificationMethod" - }, - "keys": { - "type": "array", - "description": "The list of keys associated with the list of verificationMethod's of DIDDocument", - "items": { - "type": "object" - } - }, - "services": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "controllerKeyRefs": { - "type": "array", - "description": "The list of keyRefs which were used for signing the transaction", - "items": { - "type": "string" - } - }, - "controllerKeys": { - "type": "array", - "description": "The list of all possible keys, inlcuding all controller's keys", - "items": { - "type": "string" - } - } - } - }, - "VerificationMethod": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string" - }, - "controller": { - "type": "string" - }, - "publicKeyMultibase": { - "type": "string" - }, - "publicKeyJwk": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "id": "did:cheqd:testnet :7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", - "type": "Ed25519VerificationKey2018" - } - }, - "Service": { - "description": "Communicating or interacting with the DID subject or associated entities via one or more service endpoints. See DID Core specification for more details.", - "type": "object", - "properties": { - "id": { - "description": "DID appended with Service fragment ID (e.g., `#service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`)", - "type": "string", - "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1" - }, - "type": { - "description": "Service type as defined in DID Specification Registries.", - "type": "string", - "example": "LinkedDomains" - }, - "serviceEndpoint": { - "description": "Service endpoint as defined in DID Core Specification.", - "type": "array", - "items": { - "type": "string", - "example": "https://example.com" - } - } - } - }, - "DidUpdateRequest": { - "type": "object", - "properties": { - "did": { - "description": "DID identifier to be updated.", - "type": "string", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "service": { - "type": "array", - "description": "Service section of the DID Document.", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "verificationMethod": { - "type": "array", - "description": "Verification Method section of the DID Document.", - "items": { - "$ref": "#/components/schemas/VerificationMethod" - } - }, - "authentication": { - "description": "Authentication section of the DID Document.", - "type": "array", - "items": { - "type": "string" - } - }, - "publicKeyHexs": { - "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", - "type": "array", - "items": { - "type": "string" - } - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - } - } - }, - "DidDeactivateRequest": { - "type": "object", - "properties": { - "publicKeyHexs": { - "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "CreateResourceRequest": { - "description": "Input fields for DID-Linked Resource creation.", - "type": "object", - "additionalProperties": false, - "required": [ - "name", - "type", - "data", - "encoding" - ], - "properties": { - "data": { - "description": "Encoded string containing the data to be stored in the DID-Linked Resource.", - "type": "string" - }, - "encoding": { - "description": "Encoding format used to encode the data.", - "type": "string", - "enum": [ - "base64url", - "base64", - "hex" - ] - }, - "name": { - "description": "Name of DID-Linked Resource.", - "type": "string" - }, - "type": { - "description": "Type of DID-Linked Resource. This is NOT the same as the media type, which is calculated automatically ledger-side.", - "type": "string" - }, - "alsoKnownAs": { - "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", - "type": "array", - "items": { - "type": "object", - "properties": { - "uri": { - "type": "string" - }, - "description": { - "type": "string" - } - } - } - }, - "version": { - "description": "Optional field to assign a human-readable version in the DID-Linked Resource.", - "type": "string" - }, - "publicKeyHexs": { - "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "data": "SGVsbG8gV29ybGQ=", - "encoding": "base64url", - "name": "ResourceName", - "type": "TextDocument" - } - }, - "ResourceList": { - "type": "object", - "properties": { - "@context": { - "type": "string", - "example": "https://w3id.org/did-resolution/v1" - }, - "contentMetadata": { - "type": "object" - }, - "contentStream": { - "type": "object" - }, - "dereferencingMetadata": { - "$ref": "#/components/schemas/DereferencingMetadata" - } - } - }, - "DereferencingMetadata": { - "type": "object", - "properties": { - "contentType": { - "type": "string", - "example": "application/did+ld+json" - }, - "did": { - "$ref": "#/components/schemas/DidProperties" - }, - "retrieved": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - } - } - }, - "DidResolution": { - "type": "object", - "properties": { - "@context": { - "type": "string", - "example": "https://w3id.org/did-resolution/v1" - }, - "didDidResolutionMetadata": { - "$ref": "#/components/schemas/DidResolutionMetadata" - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - }, - "didDocumentMetadata": { - "$ref": "#/components/schemas/DidDocumentMetadata" - } - } - }, - "DeactivatedDidResolution": { - "type": "object", - "properties": { - "@context": { - "type": "string", - "example": "https://w3id.org/did-resolution/v1" - }, - "didDidResolutionMetadata": { - "$ref": "#/components/schemas/DidResolutionMetadata" - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - }, - "didDocumentMetadata": { - "$ref": "#/components/schemas/DeactivatedDidDocumentMetadata" - } - } - }, - "DidDocumentMetadata": { - "type": "object", - "properties": { - "created": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "deactivated": { - "type": "boolean", - "example": false - }, - "updated": { - "type": "string", - "example": "2021-09-10T12:00:00Z" - }, - "versionId": { - "type": "string", - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - "linkedResourceMetadata": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ResourceMetadata" - } - } - } - }, - "DeactivatedDidDocumentMetadata": { - "type": "object", - "properties": { - "created": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "deactivated": { - "type": "boolean", - "example": true - }, - "updated": { - "type": "string", - "example": "2021-09-10T12:00:00Z" - }, - "versionId": { - "type": "string", - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - "linkedResourceMetadata": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ResourceMetadata" - } - } - } - }, - "ResourceMetadata": { - "type": "object", - "properties": { - "resourceURI": { - "type": "string", - "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47/resources/398cee0a-efac-4643-9f4c-74c48c72a14b" - }, - "resourceCollectionId": { - "type": "string", - "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" - }, - "resourceId": { - "type": "string", - "example": "398cee0a-efac-4643-9f4c-74c48c72a14b" - }, - "resourceName": { - "type": "string", - "example": "cheqd-issuer-logo" - }, - "resourceType": { - "type": "string", - "example": "CredentialArtwork" - }, - "mediaType": { - "type": "string", - "example": "image/png" - }, - "resourceVersion": { - "type": "string", - "example": "1.0" - }, - "checksum": { - "type": "string", - "example": "a95380f460e63ad939541a57aecbfd795fcd37c6d78ee86c885340e33a91b559" - }, - "created": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "nextVersionId": { - "type": "string", - "example": "d4829ac7-4566-478c-a408-b44767eddadc" - }, - "previousVersionId": { - "type": "string", - "example": "ad7a8442-3531-46eb-a024-53953ec6e4ff" - } - } - }, - "DidResolutionMetadata": { - "type": "object", - "properties": { - "contentType": { - "allOf": [ - { - "$ref": "#/components/schemas/ContentType" - } - ], - "example": "application/did+ld+json" - }, - "retrieved": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "did": { - "$ref": "#/components/schemas/DidProperties" - } - } - }, - "ContentType": { - "type": "string", - "enum": [ - "application/did+json", - "application/did+ld+json", - "application/ld+json", - "application/json" - ] - }, - "DidProperties": { - "type": "object", - "properties": { - "didString": { - "type": "string", - "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" - }, - "method": { - "type": "string", - "example": "cheqd" - }, - "methodSpecificId": { - "type": "string", - "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" - } - } - }, - "Customer": { - "type": "object", - "properties": { - "customerId": { - "type": "string", - "example": "6w5drpiiwhhs" - }, - "address": { - "type": "string", - "example": "cheqd1wgsvqwlkmdp60f4dek26ak0sjw6au3ytd3pz7f" - } - } - }, - "AccountCreateRequest": { - "type": "object", - "properties": { - "user": { - "type": "object", - "properties": { - "primaryEmail": { - "type": "string" - } - } - } - } - }, - "InvalidRequest": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "InvalidRequest" - } - } - }, - "InternalError": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Internal Error" - } - } - }, - "UnauthorizedError": { - "description": "Access token is missing or invalid", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Unauthorized Error" - } - } - } - } - } -} \ No newline at end of file + "openapi": "3.0.0", + "info": { + "title": "Credential Service API for cheqd network", + "version": "2.0.0", + "description": "API service to create and manage DIDs, Verifiable Credentials, and DID-Linked Resources", + "contact": { + "name": "Cheqd Foundation Limited", + "url": "https://github.com/cheqd/credential-service", + "email": "support-github@cheqd.io" + }, + "license": { + "name": "Apache 2.0", + "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" + } + }, + "tags": [ + { + "name": "Account" + }, + { + "name": "Key" + }, + { + "name": "DID" + }, + { + "name": "Resource" + }, + { + "name": "Credential" + }, + { + "name": "Presentation" + }, + { + "name": "Credential Status" + } + ], + "externalDocs": { + "description": "Credential Service API Documentation", + "url": "https://docs.cheqd.io/identity" + }, + "paths": { + "/account": { + "get": { + "tags": ["Account"], + "summary": "Fetch custodian-mode client details.", + "description": "This endpoint returns the custodian-mode client details for authenticated users.", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Customer" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/account/idtoken": { + "get": { + "tags": ["Account"], + "summary": "Fetch IdToken.", + "description": "This endpoint returns IdToken as JWT with list of user roles inside", + "deprecated": true, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "idToken": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/account/create": { + "post": { + "tags": ["Account"], + "summary": "Create an client for an authenticated user.", + "description": "This endpoint creates a client in the custodian-mode for an authenticated user", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/AccountCreateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "idToken": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/create/unencrypted": { + "post": { + "tags": ["Credential Status"], + "summary": "Create an unencrypted StatusList2021 credential status list.", + "description": "This endpoint creates an unencrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", + "required": true, + "schema": { + "type": "string", + "enum": ["revocation", "suspension"] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/create/encrypted": { + "post": { + "tags": ["Credential Status"], + "summary": "Create an encrypted StatusList2021 credential status list.", + "description": "This endpoint creates an encrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", + "required": true, + "schema": { + "type": "string", + "enum": ["revocation", "suspension"] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateEncryptedFormRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateEncryptedJsonRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateEncryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/update/unencrypted": { + "post": { + "tags": ["Credential Status"], + "summary": "Update an existing unencrypted StatusList2021 credential status list.", + "parameters": [ + { + "in": "query", + "name": "statusAction", + "description": "The update action to be performed on the unencrypted status list, can be revoke, suspend or reinstate", + "required": true, + "schema": { + "type": "string", + "enum": ["revoke", "suspend", "reinstate"] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/update/encrypted": { + "post": { + "tags": ["Credential Status"], + "summary": "Update an existing encrypted StatusList2021 credential status list.", + "parameters": [ + { + "in": "query", + "name": "statusAction", + "description": "The update action to be performed on the encrypted status list, can be revoke, suspend or reinstate", + "required": true, + "schema": { + "type": "string", + "enum": ["revoke", "suspend", "reinstate"] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedFormRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedJsonRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/check": { + "post": { + "tags": ["Credential Status"], + "summary": "Check a StatusList2021 index for a given Verifiable Credential.", + "description": "This endpoint checks a StatusList2021 index for a given Verifiable Credential and reports whether it is revoked or suspended. It offers a standalone method for checking an index without passing the entire Verifiable Credential or Verifiable Presentation.", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension.", + "required": true, + "schema": { + "type": "string", + "enum": ["revocation", "suspension"] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCheckRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCheckRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCheckResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/search": { + "get": { + "tags": ["Credential Status"], + "summary": "Fetch StatusList2021 DID-Linked Resource based on search criteria.", + "parameters": [ + { + "in": "query", + "name": "did", + "description": "The DID of the issuer of the status list.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension.", + "schema": { + "type": "string", + "enum": ["revocation", "suspension"] + } + }, + { + "in": "query", + "name": "statusListName", + "description": "The name of the StatusList2021 DID-Linked Resource.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusListSearchResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/issue": { + "post": { + "tags": ["Credential"], + "summary": "Issue a Verifiable Credential", + "description": "This endpoint issues a Verifiable Credential. As input it takes the list of issuerDid, subjectDid, attributes, and other parameters of the credential to be issued.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Credential" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/verify": { + "post": { + "tags": ["Credential"], + "summary": "Verify a Verifiable Credential.", + "description": "This endpoint verifies a Verifiable Credential passed to it. As input, it can take the VC-JWT as a string or the entire credential itself.", + "operationId": "verify", + "parameters": [ + { + "in": "query", + "name": "verifyStatus", + "description": "If set to `true` the verification will also check the status of the credential. Requires the VC to have a `credentialStatus` property.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "fetchRemoteContexts", + "description": "When dealing with JSON-LD you also MUST provide the proper contexts. Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "allowDeactivatedDid", + "description": "If set to `true` allow to verify credential which based on deactivated DID.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialVerifyRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialVerifyRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyCredentialResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/revoke": { + "post": { + "tags": ["Credential"], + "summary": "Revoke a Verifiable Credential.", + "description": "This endpoint revokes a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself. The StatusList2021 resource should already be setup in the VC and `credentialStatus` property present in the VC.", + "operationId": "revoke", + "parameters": [ + { + "in": "query", + "name": "publish", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RevocationResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/suspend": { + "post": { + "tags": ["Credential"], + "summary": "Suspend a Verifiable Credential.", + "description": "This endpoint suspends a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself.", + "operationId": "suspend", + "parameters": [ + { + "in": "query", + "name": "publish", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuspensionResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/reinstate": { + "post": { + "tags": ["Credential"], + "summary": "Reinstate a suspended Verifiable Credential.", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "operationId": "reinstate", + "parameters": [ + { + "in": "query", + "name": "publish", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnsuspensionResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/create": { + "post": { + "tags": ["DID"], + "summary": "Create a DID Document.", + "description": "This endpoint creates a DID and associated DID Document. As input, it can take the DID Document parameters via a form, or the fully-assembled DID Document itself.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidCreateRequestFormBased" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidCreateRequestJson" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/did/update": { + "post": { + "tags": ["DID"], + "summary": "Update a DID Document.", + "description": "This endpoint updates a DID Document. As an input, it can take JUST the sections/parameters that need to be updated in the DID Document (in this scenario, it fetches the current DID Document and applies the updated section). Alternatively, it take the fully-assembled DID Document with updated sections as well as unchanged sections.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidUpdateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidUpdateResponse" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/import": { + "post": { + "tags": ["DID"], + "summary": "Import a DID Document.", + "description": "This endpoint imports a decentralized identifier associated with the user's account for custodian-mode clients.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidImportRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidImportRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/did/deactivate/{did}": { + "post": { + "tags": ["DID"], + "summary": "Deactivate a DID Document.", + "description": "This endpoint deactivates a DID Document by taking the DID identifier as input. Must be called and signed by the DID owner.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier to deactivate.", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidDeactivateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidDeactivateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeactivatedDidResolution" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/list": { + "get": { + "tags": ["DID"], + "summary": "Fetch DIDs associated with an account.", + "description": "This endpoint returns the list of DIDs controlled by the account.", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/search/{did}": { + "get": { + "tags": ["DID"], + "summary": "Resolve a DID Document.", + "description": "Resolve a DID Document by DID identifier. Also supports DID Resolution Queries as defined in the W3C DID Resolution specification.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier to resolve.", + "schema": { + "type": "string" + }, + "required": true, + "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + { + "in": "query", + "name": "metadata", + "description": "Return only metadata of DID Document instead of actual DID Document.", + "schema": { + "type": "boolean" + } + }, + { + "in": "query", + "name": "versionId", + "description": "Unique UUID version identifier of DID Document. Allows for fetching a specific version of the DID Document. See cheqd DID Method Specification for more details.", + "schema": { + "type": "string", + "format": "uuid" + }, + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + { + "in": "query", + "name": "versionTime", + "description": "Returns the closest version of the DID Document *at* or *before* specified time. See DID Resolution handling for `did:cheqd` for more details.", + "schema": { + "type": "string", + "format": "date-time" + }, + "example": "1970-01-01T00:00:00Z" + }, + { + "in": "query", + "name": "transformKeys", + "description": "This directive transforms the Verification Method key format from the version in the DID Document to the specified format chosen below.", + "schema": { + "type": "string", + "enum": ["Ed25519VerificationKey2018", "Ed25519VerificationKey2020", "JsonWebKey2020"] + } + }, + { + "in": "query", + "name": "service", + "description": "Query DID Document for a specific Service Endpoint by Service ID (e.g., `service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`). This will typically redirect to the Service Endpoint based on DID Resolution specification algorithm.", + "schema": { + "type": "string" + }, + "example": "service-1" + }, + { + "in": "query", + "name": "relativeRef", + "description": "Relative reference is a query fragment appended to the Service Endpoint URL. **Must** be used along with the `service` query property above. See DID Resolution specification algorithm for more details.", + "schema": { + "type": "string" + }, + "example": "/path/to/file" + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResolution" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/key/create": { + "post": { + "tags": ["Key"], + "summary": "Create an identity key pair.", + "description": "This endpoint creates an identity key pair associated with the user's account for custodian-mode clients.", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/key/import": { + "post": { + "tags": ["Key"], + "summary": "Import an identity key pair.", + "description": "This endpoint imports an identity key pair associated with the user's account for custodian-mode clients.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/KeyImportRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyImportRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/key/read/{kid}": { + "get": { + "tags": ["Key"], + "summary": "Fetch an identity key pair.", + "description": "This endpoint fetches an identity key pair's details for a given key ID. Only the user account associated with the custodian-mode client can fetch the key pair.", + "parameters": [ + { + "name": "kid", + "description": "Key ID of the identity key pair to fetch.", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/presentation/create": { + "post": { + "tags": ["Presentation"], + "summary": "!!! WARN. Such endpoint is made mostly for testing purposes and it is not supposed to be used in production !!! Create a Verifiable Presentation from credential(s).", + "description": "This endpoint creates a Verifiable Presentation from credential(s). As input, it can take the credential(s) as a string or the entire credential(s) itself. \n !!! WARN. Such endpoint is made only for testing purposes !!!", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/PresentationCreateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationCreateResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/presentation/verify": { + "post": { + "tags": ["Presentation"], + "summary": "Verify a Verifiable Presentation generated from credential(s).", + "description": "This endpoint verifies the Verifiable Presentation generated from credential(s). As input, it can take the Verifiable Presentation JWT as a string or the entire Verifiable Presentation itself.", + "parameters": [ + { + "in": "query", + "name": "verifyStatus", + "description": "If set to `true` the verification will also check the status of the presentation. Requires the VP to have a `credentialStatus` property.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "fetchRemoteContexts", + "description": "When dealing with JSON-LD you also MUST provide the proper contexts. * Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "allowDeactivatedDid", + "description": "If set to `true` allow to verify credential which based on deactivated DID.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/PresentationVerifyRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationVerifyRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyPresentationResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/resource/create/{did}": { + "post": { + "tags": ["Resource"], + "summary": "Create a DID-Linked Resource.", + "description": "This endpoint creates a DID-Linked Resource. As input, it can take the DID identifier and the resource parameters via a form, or the fully-assembled resource itself.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier to link the resource to.", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CreateResourceRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateResourceRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceMetadata" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/resource/search/{did}": { + "get": { + "tags": ["Resource"], + "summary": "Get a DID-Linked Resource.", + "description": "This endpoint returns the DID-Linked Resource for a given DID identifier and resource identifier.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier", + "schema": { + "type": "string" + }, + "required": true, + "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + { + "in": "query", + "name": "resourceId", + "description": "Fetch a DID-Linked Resource by Resource ID unique identifier. Since this is a unique identifier, other Resource query parameters are not required. See DID-Linked Resources for more details.", + "schema": { + "type": "string", + "format": "uuid" + }, + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + { + "in": "query", + "name": "resourceName", + "description": "Filter a DID-Linked Resource query by Resource Name. See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "cheqd-issuer-logo" + }, + { + "in": "query", + "name": "resourceType", + "description": "Filter a DID-Linked Resource query by Resource Type. See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "CredentialArtwork" + }, + { + "in": "query", + "name": "resourceVersion", + "description": "Filter a DID-Linked Resource query by Resource Version, which is an optional free-text field used by issuers (e.g., \"v1\", \"Final Version\", \"1st January 1970\" etc). See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "v1" + }, + { + "in": "query", + "name": "resourceVersionTime", + "description": "Filter a DID-Linked Resource query which returns the closest version of the Resource *at* or *before* specified time. See DID-Linked Resources for more details.", + "schema": { + "type": "string", + "format": "date-time" + }, + "example": "1970-01-01T00:00:00Z" + }, + { + "in": "query", + "name": "checksum", + "description": "Request integrity check against a given DID-Linked Resource by providing a SHA-256 checksum hash. See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "dc64474d062ed750a66bad58cb609928de55ed0d81defd231a4a4bf97358e9ed" + }, + { + "in": "query", + "name": "resourceMetadata", + "description": "Return only metadata of DID-Linked Resource instead of actual DID-Linked Resource. Mutually exclusive with some of the other parameters.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "any": { + "schema": { + "type": "object" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + } + }, + "components": { + "schemas": { + "AlsoKnownAs": { + "type": "object", + "properties": { + "alsoKnownAs": { + "type": "array", + "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", + "items": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "format": "uri", + "description": "URI where the DID-Linked Resource can be fetched from. Can be any type of URI (e.g., DID, HTTPS, IPFS, etc.)" + }, + "description": { + "type": "string", + "description": "Optional description of the URI." + } + } + } + } + } + }, + "CredentialRequest": { + "description": "Input fields for the creating a Verifiable Credential.", + "type": "object", + "additionalProperties": false, + "properties": { + "issuerDid": { + "description": "DID of the Verifiable Credential issuer. This needs to be a `did:cheqd` DID.", + "type": "string", + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + "subjectDid": { + "description": "DID of the Verifiable Credential holder/subject. This needs to be a `did:key` DID.", + "type": "string", + "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" + }, + "attributes": { + "description": "JSON object containing the attributes to be included in the credential.", + "type": "object", + "example": { + "name": "Bob", + "gender": "male" + } + }, + "@context": { + "description": "Optional properties to be included in the `@context` property of the credential.", + "type": "array", + "items": { + "type": "string" + }, + "example": ["https://schema.org/schema.jsonld", "https://veramo.io/contexts/profile/v1"] + }, + "type": { + "description": "Optional properties to be included in the `type` property of the credential.", + "type": "array", + "items": { + "type": "string" + }, + "example": ["Person"] + }, + "expirationDate": { + "description": "Optional expiration date according to the VC Data Model specification.", + "type": "string", + "format": "date-time", + "example": "2023-06-08T13:49:28.000Z" + }, + "format": { + "description": "Format of the Verifiable Credential. Defaults to VC-JWT.", + "type": "string", + "enum": ["jwt", "jsonld"], + "example": "jwt" + }, + "credentialStatus": { + "description": "Optional `credentialStatus` properties for VC revocation or suspension. Takes `statusListName` and `statusListPurpose` as inputs.", + "type": "object", + "required": ["statusPurpose", "statusListName"], + "properties": { + "statusPurpose": { + "type": "string", + "enum": ["revocation", "suspension"] + }, + "statusListName": { + "type": "string" + }, + "statusListIndex": { + "type": "number" + }, + "statusListVersion": { + "type": "string", + "format": "date-time" + }, + "statusListRangeStart": { + "type": "number" + }, + "statusListRangeEnd": { + "type": "number" + }, + "indexNotIn": { + "type": "number" + } + }, + "example": { + "statusPurpose": "revocation", + "statusListName": "employee-credentials" + } + } + }, + "required": ["issuerDid", "subjectDid", "attributes"], + "example": { + "issuerDid": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "subjectDid": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", + "attributes": { + "gender": "male", + "name": "Bob" + }, + "@context": ["https://schema.org"], + "type": ["Person"], + "format": "jwt", + "credentialStatus": { + "statusPurpose": "revocation", + "statusListName": "employee-credentials", + "statusListIndex": 10 + } + } + }, + "Credential": { + "description": "Input fields for revoking/suspending a Verifiable Credential.", + "type": "object", + "additionalProperties": false, + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "https://www.w3.org/2018/credentials/v1", + "https://schema.org", + "https://veramo.io/contexts/profile/v1" + ] + }, + "type": { + "type": "array", + "items": { + "type": "string" + }, + "example": ["VerifiableCredential", "Person"] + }, + "expirationDate": { + "type": "string", + "format": "date-time", + "example": "2023-06-08T13:49:28.000Z" + }, + "issuer": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "DID", + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + } + } + }, + "credentialSubject": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "DID", + "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" + } + } + }, + "credentialStatus": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20" + }, + "statusListIndex": { + "type": "number", + "example": 20 + }, + "statusPurpose": { + "type": "string", + "enum": ["revocation", "suspension"], + "example": "suspension" + }, + "type": { + "type": "string", + "enum": ["StatusList2021Entry"] + } + } + }, + "issuanceDate": { + "type": "string", + "format": "date-time", + "example": "2023-06-08T13:49:28.000Z" + }, + "proof": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "jwt": { + "type": "string" + } + }, + "example": { + "type": "JwtProof2020", + "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg" + } + } + }, + "example": { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://schema.org", + "https://veramo.io/contexts/profile/v1" + ], + "credentialSubject": { + "gender": "male", + "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", + "name": "Bob" + }, + "credentialStatus": { + "id": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20", + "statusIndex": 20, + "statusPurpose": "suspension", + "type": "StatusList2021Entry" + }, + "issuanceDate": "2023-06-08T13:49:28.000Z", + "issuer": { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + "proof": { + "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg", + "type": "JwtProof2020" + }, + "type": ["VerifiableCredential", "Person"] + } + }, + "CredentialRevokeRequest": { + "type": "object", + "properties": { + "credential": { + "description": "Verifiable Credential to be revoked as a VC-JWT string or a JSON object.", + "oneOf": [ + { + "type": "object" + }, + { + "type": "string" + } + ] + }, + "symmetricKey": { + "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource. Required if the StatusList2021 DID-Linked Resource is encrypted.", + "type": "string" + } + } + }, + "RevocationResult": { + "properties": { + "revoked": { + "type": "boolean", + "example": true + } + } + }, + "SuspensionResult": { + "properties": { + "suspended": { + "type": "boolean", + "example": true + } + } + }, + "UnsuspensionResult": { + "properties": { + "unsuspended": { + "type": "boolean", + "example": true + } + } + }, + "CredentialVerifyRequest": { + "type": "object", + "properties": { + "credential": { + "description": "Verifiable Credential to be verified as a VC-JWT string or a JSON object.", + "type": "object" + }, + "policies": { + "description": "Custom verification policies to execute when verifying credential.", + "type": "object", + "properties": { + "issuanceDate": { + "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "expirationDate": { + "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "audience": { + "description": "Policy to skip the audience check when set to `false`.", + "type": "boolean", + "default": false + } + } + } + } + }, + "VerifyPresentationResult": { + "type": "object", + "properties": { + "verified": { + "type": "boolean" + }, + "issuer": { + "type": "string" + }, + "signer": { + "type": "object" + }, + "jwt": { + "type": "string" + }, + "verifiableCredential": { + "type": "object" + } + } + }, + "VerifyCredentialResult": { + "type": "object", + "properties": { + "verified": { + "type": "boolean" + }, + "issuer": { + "type": "string" + }, + "signer": { + "type": "object" + }, + "jwt": { + "type": "string" + }, + "verifiableCredential": { + "type": "object" + } + }, + "example": { + "verified": true, + "polices": {}, + "issuer": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "signer": { + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", + "type": "Ed25519VerificationKey2018" + } + } + }, + "PresentationCreateRequest": { + "type": "object", + "required": ["credentials"], + "properties": { + "credentials": { + "description": "Verifiable Credentials to be used for VP-JWT creation as a VP-JWT strings or a JSON objectsf.", + "type": "array", + "items": { + "type": "object" + } + }, + "holderDid": { + "description": "DID of holder", + "type": "string" + }, + "verifierDid": { + "description": "DID of verifier", + "type": "string" + } + } + }, + "PresentationVerifyRequest": { + "type": "object", + "required": ["presentation"], + "properties": { + "presentation": { + "description": "Verifiable Presentation to be verified as a VP-JWT string or a JSON object.", + "type": "object" + }, + "verifierDid": { + "description": "Provide an optional verifier DID (also known as 'domain' parameter), if the verifier DID in the presentation is not managed in the wallet.", + "type": "string" + }, + "makeFeePayment": { + "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", + "type": "boolean", + "default": false + }, + "policies": { + "description": "Custom verification policies to execute when verifying presentation.", + "type": "object", + "properties": { + "issuanceDate": { + "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "expirationDate": { + "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "audience": { + "description": "Policy to skip the audience check when set to `false`.", + "type": "boolean", + "default": false + } + } + } + } + }, + "CredentialStatusCreateBody": { + "allOf": [ + { + "type": "object", + "required": ["did", "statusListName"], + "properties": { + "did": { + "description": "DID of the StatusList2021 publisher.", + "type": "string", + "format": "uri" + }, + "statusListName": { + "description": "The name of the StatusList2021 DID-Linked Resource to be created.", + "type": "string" + }, + "length": { + "description": "The length of the status list to be created. The default and minimum length is 140000 which is 16kb.", + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true, + "default": 140000 + }, + "encoding": { + "description": "The encoding format of the StatusList2021 DiD-Linked Resource to be created.", + "type": "string", + "default": "base64url", + "enum": ["base64url", "base64", "hex"] + }, + "statusListVersion": { + "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/AlsoKnownAs" + } + ] + }, + "CredentialStatusCreateUnencryptedRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCreateBody" + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials", + "length": 140000, + "encoding": "base64url" + } + }, + "CredentialStatusUnencryptedResult": { + "type": "object", + "properties": { + "resource": { + "type": "object", + "properties": { + "StatusList2021": { + "type": "object", + "properties": { + "encodedList": { + "type": "string", + "example": "H4sIAAAAAAAAA-3BAQ0AAADCoPdPbQ8HFAAAAAAAAAAAAAAAAAAAAADwaDhDr_xcRAAA" + }, + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "validFrom": { + "type": "string", + "format": "date-time", + "example": "2023-06-26T11:45:19.349Z" + } + } + }, + "metadata": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "encoding": { + "type": "string", + "example": "base64url" + }, + "encrypted": { + "type": "boolean", + "example": false + } + } + } + } + }, + "resourceMetadata": { + "type": "object", + "example": { + "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceName": "cheqd-employee-credentials", + "resourceType": "StatusList2021Revocation", + "mediaType": "application/json", + "resourceVersion": "1.0.0", + "created": "2023-06-26T11:45:20Z", + "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", + "previousVersionId": null, + "nextVersionId": null + } + } + } + }, + "CredentialStatusCreateUnencryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "created": { + "type": "boolean", + "example": true + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" + } + ] + }, + "CredentialStatusEncryptedPaymentConditionsBody": { + "type": "object", + "properties": { + "feePaymentAddress": { + "description": "The cheqd/Cosmos payment address where payments to unlock the encrypted StatusList2021 DID-Linked Resource need to be sent.", + "type": "string", + "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" + }, + "feePaymentAmount": { + "description": "Amount in CHEQ tokens to unlock the encrypted StatusList2021 DID-Linked Resource.", + "type": "number", + "minimum": 0, + "exclusiveMinimum": true, + "default": 20 + }, + "feePaymentWindow": { + "description": "Time window (in minutes) within which the payment to unlock the encrypted StatusList2021 DID-Linked Resource is considered valid.", + "type": "number", + "minimum": 0, + "exclusiveMinimum": true, + "default": 10 + } + } + }, + "CredentialStatusEncryptedPaymentConditionsJson": { + "type": "object", + "properties": { + "paymentConditions": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" + } + ] + } + } + }, + "CredentialStatusCreateEncryptedFormRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCreateBody" + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" + }, + { + "type": "object", + "required": ["feePaymentAddress", "feePaymentAmount", "feePaymentWindow"] + } + ] + }, + "CredentialStatusCreateEncryptedJsonRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCreateBody" + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" + }, + { + "type": "object", + "required": ["paymentConditions"] + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials-encrypted", + "paymentConditions": [ + { + "feePaymentAddress": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg", + "feePaymentAmount": 20, + "feePaymentWindow": 10 + } + ] + } + }, + "CredentialStatusEncryptedResult": { + "type": "object", + "properties": { + "resource": { + "type": "object", + "properties": { + "StatusList2021": { + "type": "object", + "properties": { + "encodedList": { + "type": "string", + "example": "496fdfbeb745b4db03fcdb40566f9c4c4a1c0f184b31255e641b6e7bdfb9b6946c12be87ca3763be0393c00b67ac1e8737c106b32f46ef59c765754415b5e8cc7c65fccaa3374620430ea476301a5e0dd63340e7a27a68bc627518471f22e4a2" + }, + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "validFrom": { + "type": "string", + "format": "date-time", + "example": "2023-06-26T11:45:19.349Z" + } + } + }, + "metadata": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "encoding": { + "type": "string", + "example": "base64url" + }, + "encrypted": { + "type": "boolean", + "example": true + }, + "encryptedSymmetricKey": { + "type": "string", + "example": "b11182dc524b8181f9a6aef4c4ad0a1c14e40033b9112dffd8d1bcf6cc3b85abc07ded2205ee94068a99f4202502cb0855f322583fa6ce1534d3a05bf36891766ea2c5f90a982b3040680762977d404d758a2370224a239c8279aa7d21e980931c42055b17ca4c7dbffa4782480a8b6279cf989b2f166d5fdb4b2c1b5a63927200000000000000203018dcaba26df45a415bb599218b27ca853a70289d7a3ed3ed0e3730452e8f8d9af91b6e71312565d2c069341f6660ab" + }, + "paymentConditions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "feePaymentAddress": { + "type": "string", + "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" + }, + "feePaymentAmount": { + "type": "string", + "example": "20000000000ncheq" + }, + "intervalInSeconds": { + "type": "number", + "example": 600 + }, + "type": { + "type": "string", + "example": "timelockPayment" + } + } + } + } + } + }, + "resourceMetadata": { + "type": "object", + "example": { + "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceName": "cheqd-revocation-encrypted-1", + "resourceType": "StatusList2021Revocation", + "mediaType": "application/json", + "resourceVersion": "2023-06-26T11:45:19.349Z", + "created": "2023-06-26T11:45:20Z", + "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", + "previousVersionId": null, + "nextVersionId": null + } + }, + "symmetricKey": { + "type": "string", + "example": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" + } + } + } + } + }, + "CredentialStatusCreateEncryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "created": { + "type": "boolean", + "example": true + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedResult" + } + ] + }, + "CredentialStatusUpdateBody": { + "type": "object", + "required": ["did", "statusListName", "indices"], + "properties": { + "did": { + "description": "DID of the StatusList2021 publisher.", + "type": "string", + "format": "uri" + }, + "statusListName": { + "description": "The name of the StatusList2021 DID-Linked Resource to be updated.", + "type": "string" + }, + "indices": { + "description": "List of credential status indices to be updated. The indices must be in the range of the status list.", + "type": "array", + "items": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": false + } + }, + "statusListVersion": { + "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + "CredentialStatusUpdateUnencryptedRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUpdateBody" + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials", + "indices": [10, 3199, 12109, 130999] + } + }, + "CredentialStatusUpdateUnencryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "updated": { + "type": "boolean", + "example": true + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/RevocationResult" + }, + { + "$ref": "#/components/schemas/SuspensionResult" + }, + { + "$ref": "#/components/schemas/UnsuspensionResult" + } + ] + }, + { + "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" + } + ] + }, + "CredentialStatusUpdateEncryptedFormRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUpdateBody" + }, + { + "type": "object", + "required": ["symmetricKey"], + "properties": { + "symmetricKey": { + "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" + } + ] + }, + "CredentialStatusUpdateEncryptedJsonRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUpdateBody" + }, + { + "type": "object", + "required": ["symmetricKey"], + "properties": { + "symmetricKey": { + "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials-encrypted", + "indices": [10, 3199, 12109, 130999], + "symmetricKey": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" + } + }, + "CredentialStatusUpdateEncryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "updated": { + "type": "boolean", + "example": true + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/RevocationResult" + }, + { + "$ref": "#/components/schemas/SuspensionResult" + }, + { + "$ref": "#/components/schemas/UnsuspensionResult" + } + ] + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedResult" + } + ] + }, + "CredentialStatusCheckRequest": { + "type": "object", + "required": ["did", "statusListName", "index"], + "properties": { + "did": { + "description": "DID of the StatusList2021 publisher.", + "type": "string", + "format": "uri" + }, + "statusListName": { + "description": "The name of the StatusList2021 DID-Linked Resource to be checked.", + "type": "string" + }, + "index": { + "description": "Credential status index to be checked for revocation or suspension.", + "type": "integer", + "minimum": 0, + "exclusiveMinimum": false + }, + "makeFeePayment": { + "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", + "type": "boolean", + "default": true + } + } + }, + "CredentialStatusCheckResult": { + "oneOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCheckRevocationResult" + }, + { + "$ref": "#/components/schemas/CredentialStatusCheckSuspensionResult" + } + ] + }, + "CredentialStatusCheckRevocationResult": { + "type": "object", + "properties": { + "checked": { + "type": "boolean", + "example": true + }, + "revoked": { + "type": "boolean", + "example": false + } + } + }, + "CredentialStatusCheckSuspensionResult": { + "type": "object", + "properties": { + "checked": { + "type": "boolean", + "example": true + }, + "suspended": { + "type": "boolean", + "example": false + } + } + }, + "CredentialStatusListSearchResult": { + "allOf": [ + { + "type": "object", + "properties": { + "found": { + "type": "boolean", + "example": true + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedResult" + } + ] + } + ] + }, + "KeyImportRequest": { + "type": "object", + "properties": { + "alias": { + "type": "string" + }, + "type": { + "type": "string", + "enum": ["Ed25519", "Secp256k1"] + }, + "privateKeyHex": { + "type": "string" + } + } + }, + "KeyResult": { + "type": "object", + "properties": { + "kid": { + "type": "string" + }, + "type": { + "type": "string", + "enum": ["Ed25519", "Secp256k1"] + }, + "publicKeyHex": { + "type": "string" + } + } + }, + "DidDocument": { + "description": "This input field contains either a complete DID document, or an incremental change (diff) to a DID document. See Universal DID Registrar specification.", + "type": "object", + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "controllers": { + "type": "array", + "items": { + "type": "string" + } + }, + "verificationMethod": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VerificationMethod" + } + }, + "service": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "authentication": { + "type": "array", + "items": { + "type": "string" + } + }, + "assertionMethod": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityInvocation": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityDelegation": { + "type": "array", + "items": { + "type": "string" + } + }, + "keyAgreement": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "@context": ["https://www.w3.org/ns/did/v1"], + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "controller": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0"], + "verificationMethod": [ + { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "type": "Ed25519VerificationKey2018", + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "publicKeyBase58": "z6MkkVbyHJLLjdjU5B62DaJ4mkdMdUkttf9UqySSkA9bVTeZ" + } + ], + "authentication": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1"], + "service": [ + { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", + "type": "LinkedDomains", + "serviceEndpoint": ["https://example.com"] + } + ] + } + }, + "DidDocumentWithoutVerificationMethod": { + "type": "object", + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "controllers": { + "type": "array", + "items": { + "type": "string" + } + }, + "service": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "authentication": { + "type": "array", + "items": { + "type": "string" + } + }, + "assertionMethod": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityInvocation": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityDelegation": { + "type": "array", + "items": { + "type": "string" + } + }, + "keyAgreement": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "@context": ["https://www.w3.org/ns/did/v1"], + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "controller": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0"], + "authentication": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1"], + "service": [ + { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", + "type": "LinkedDomains", + "serviceEndpoint": ["https://example.com"] + } + ] + } + }, + "DidCreateRequestFormBased": { + "type": "object", + "properties": { + "network": { + "description": "Network to create the DID on (testnet or mainnet)", + "type": "string", + "enum": ["testnet", "mainnet"] + }, + "identifierFormatType": { + "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", + "type": "string", + "enum": ["uuid", "base58btc"] + }, + "verificationMethodType": { + "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", + "type": "string", + "enum": ["Ed25519VerificationKey2018", "JsonWebKey2020", "Ed25519VerificationKey2020"] + }, + "service": { + "description": "It's a list of special objects which are designed to build the actual service. It's almost the same as in DID Core specification, but instead of `id` it utilises `idFragment` field for making the right `id` for each service. !!! WARN. Cause swagger-ui does not handle x-ww-form based arrays correctly, please frame all your services in brackets while using swagger UI. !!!", + "type": "array", + "items": { + "type": "object", + "properties": { + "idFragment": { + "type": "string" + }, + "type": { + "type": "string" + }, + "serviceEndpoint": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "example": [ + { + "idFragment": "service-1", + "type": "LinkedDomains", + "serviceEndpoint": ["https://example.com"] + } + ] + }, + "key": { + "description": "The unique identifier in hexadecimal public key format used in the verification method to create the DID.", + "type": "string" + }, + "@context": { + "type": "array", + "items": { + "type": "string" + }, + "example": ["https://www.w3.org/ns/did/v1"] + } + } + }, + "DidCreateRequestJson": { + "type": "object", + "properties": { + "network": { + "description": "Network to create the DID on (testnet or mainnet)", + "type": "string", + "enum": ["testnet", "mainnet"] + }, + "identifierFormatType": { + "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", + "type": "string", + "enum": ["uuid", "base58btc"] + }, + "assertionMethod": { + "description": "Usually a reference to a Verification Method. An Assertion Method is required to issue JSON-LD credentials. See DID Core specification for more details.", + "type": "boolean", + "default": true + }, + "options": { + "type": "object", + "properties": { + "key": { + "type": "string", + "example": "8255ddadd75695e01f3d98fcec8ccc7861a030b317d4326b0e48a4d579ddc43a" + }, + "verificationMethodType": { + "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", + "type": "string", + "enum": ["Ed25519VerificationKey2018", "JsonWebKey2020", "Ed25519VerificationKey2020"] + } + } + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocumentWithoutVerificationMethod" + } + } + }, + "DidImportRequest": { + "type": "object", + "properties": { + "did": { + "type": "string", + "description": "DID to be imported", + "format": "uri", + "required": true + }, + "keys": { + "type": "array", + "description": "List of keys required to import the DID", + "required": true, + "items": { + "$ref": "#/components/schemas/KeyImportRequest" + } + } + } + }, + "PresentationCreateResult": { + "type": "object", + "properties": { + "vp": { + "type": "object", + "description": "Verifiable Presentation which could be provided to the verifier." + }, + "nbf": { + "type": "integer", + "description": "Unix timestamp of the earliest time that the Verifiable Presentation is valid." + }, + "iss": { + "type": "string", + "description": "DID of the issuer of the Verifiable Presentation. (Here it's supposed to be a holder DID)" + }, + "aud": { + "type": "array", + "items": { + "type": "string" + }, + "description": "DID of the verifier of the Verifiable Presentation." + } + }, + "example": { + "vp": { + "@context": ["https://www.w3.org/2018/credentials/v1"], + "type": ["VerifiablePresentation"], + "verifiableCredential": [ + "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc2NoZW1hLm9yZy9zY2hlbWEuanNvbmxkIiwiaHR0cHM6Ly92ZXJhbW8uaW8vY29udGV4dHMvcHJvZmlsZS92MSIsImh0dHBzOi8vdzNpZC5vcmcvdmMtc3RhdHVzLWxpc3QtMjAyMS92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiUGVyc29uIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7Im5hbWUiOiJCb2IiLCJnZW5kZXIiOiJtYWxlIn0sImNyZWRlbnRpYWxTdGF0dXMiOnsiaWQiOiJodHRwczovL3Jlc29sdmVyLmNoZXFkLm5ldC8xLjAvaWRlbnRpZmllcnMvZGlkOmNoZXFkOnRlc3RuZXQ6OTBkNWMxNDEtNzI0Zi00N2FkLTlhZTctYTdjMzNhOWU1NjQzP3Jlc291cmNlTmFtZT1zdXNwZW5zaW9uRW4mcmVzb3VyY2VUeXBlPVN0YXR1c0xpc3QyMDIxU3VzcGVuc2lvbiMxMzMzOCIsInR5cGUiOiJTdGF0dXNMaXN0MjAyMUVudHJ5Iiwic3RhdHVzUHVycG9zZSI6InN1c3BlbnNpb24iLCJzdGF0dXNMaXN0SW5kZXgiOiIxMzMzOCJ9fSwic3ViIjoiZGlkOmtleTp6Nk1raGFYZ0JaRHZvdERrTDUyNTdmYWl6dGlHaUMyUXRLTEdwYm5uRUd0YTJkb0siLCJuYmYiOjE3MDA0NzM0MTYsImlzcyI6ImRpZDpjaGVxZDp0ZXN0bmV0OjkwZDVjMTQxLTcyNGYtNDdhZC05YWU3LWE3YzMzYTllNTY0MyJ9.-14Ril1pZEy2HEEo48gTJr2yOtGxBhUGTFmzVdjAtyhFRsW5zZg9onHt6V9JQ8BaiYBlTkP9GzTnJ-O6hdiyCw" + ] + }, + "nbf": 1700744275, + "iss": "did:cheqd:testnet:4b846d0f-2f6c-4ab6-9fe2-5b8db301c83c", + "aud": ["did:cheqd:testnet:8c71e9b6-c5a3-4250-8c58-fa591533cd22"] + } + }, + "DidResult": { + "type": "object", + "properties": { + "did": { + "type": "string" + }, + "controllerKeyId": { + "type": "string" + }, + "keys": { + "type": "array", + "items": { + "type": "object" + } + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + } + } + }, + "DidUpdateResponse": { + "type": "object", + "properties": { + "did": { + "type": "string" + }, + "controllerKeyId": { + "type": "string", + "description": "The default key id of which is the key associated with the first verificationMethod" + }, + "keys": { + "type": "array", + "description": "The list of keys associated with the list of verificationMethod's of DIDDocument", + "items": { + "type": "object" + } + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "controllerKeyRefs": { + "type": "array", + "description": "The list of keyRefs which were used for signing the transaction", + "items": { + "type": "string" + } + }, + "controllerKeys": { + "type": "array", + "description": "The list of all possible keys, inlcuding all controller's keys", + "items": { + "type": "string" + } + } + } + }, + "VerificationMethod": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + }, + "controller": { + "type": "string" + }, + "publicKeyMultibase": { + "type": "string" + }, + "publicKeyJwk": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "id": "did:cheqd:testnet :7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", + "type": "Ed25519VerificationKey2018" + } + }, + "Service": { + "description": "Communicating or interacting with the DID subject or associated entities via one or more service endpoints. See DID Core specification for more details.", + "type": "object", + "properties": { + "id": { + "description": "DID appended with Service fragment ID (e.g., `#service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`)", + "type": "string", + "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1" + }, + "type": { + "description": "Service type as defined in DID Specification Registries.", + "type": "string", + "example": "LinkedDomains" + }, + "serviceEndpoint": { + "description": "Service endpoint as defined in DID Core Specification.", + "type": "array", + "items": { + "type": "string", + "example": "https://example.com" + } + } + } + }, + "DidUpdateRequest": { + "type": "object", + "properties": { + "did": { + "description": "DID identifier to be updated.", + "type": "string", + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + "service": { + "type": "array", + "description": "Service section of the DID Document.", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "verificationMethod": { + "type": "array", + "description": "Verification Method section of the DID Document.", + "items": { + "$ref": "#/components/schemas/VerificationMethod" + } + }, + "authentication": { + "description": "Authentication section of the DID Document.", + "type": "array", + "items": { + "type": "string" + } + }, + "publicKeyHexs": { + "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", + "type": "array", + "items": { + "type": "string" + } + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + } + } + }, + "DidDeactivateRequest": { + "type": "object", + "properties": { + "publicKeyHexs": { + "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "CreateResourceRequest": { + "description": "Input fields for DID-Linked Resource creation.", + "type": "object", + "additionalProperties": false, + "required": ["name", "type", "data", "encoding"], + "properties": { + "data": { + "description": "Encoded string containing the data to be stored in the DID-Linked Resource.", + "type": "string" + }, + "encoding": { + "description": "Encoding format used to encode the data.", + "type": "string", + "enum": ["base64url", "base64", "hex"] + }, + "name": { + "description": "Name of DID-Linked Resource.", + "type": "string" + }, + "type": { + "description": "Type of DID-Linked Resource. This is NOT the same as the media type, which is calculated automatically ledger-side.", + "type": "string" + }, + "alsoKnownAs": { + "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", + "type": "array", + "items": { + "type": "object", + "properties": { + "uri": { + "type": "string" + }, + "description": { + "type": "string" + } + } + } + }, + "version": { + "description": "Optional field to assign a human-readable version in the DID-Linked Resource.", + "type": "string" + }, + "publicKeyHexs": { + "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "data": "SGVsbG8gV29ybGQ=", + "encoding": "base64url", + "name": "ResourceName", + "type": "TextDocument" + } + }, + "ResourceList": { + "type": "object", + "properties": { + "@context": { + "type": "string", + "example": "https://w3id.org/did-resolution/v1" + }, + "contentMetadata": { + "type": "object" + }, + "contentStream": { + "type": "object" + }, + "dereferencingMetadata": { + "$ref": "#/components/schemas/DereferencingMetadata" + } + } + }, + "DereferencingMetadata": { + "type": "object", + "properties": { + "contentType": { + "type": "string", + "example": "application/did+ld+json" + }, + "did": { + "$ref": "#/components/schemas/DidProperties" + }, + "retrieved": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + } + } + }, + "DidResolution": { + "type": "object", + "properties": { + "@context": { + "type": "string", + "example": "https://w3id.org/did-resolution/v1" + }, + "didDidResolutionMetadata": { + "$ref": "#/components/schemas/DidResolutionMetadata" + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + }, + "didDocumentMetadata": { + "$ref": "#/components/schemas/DidDocumentMetadata" + } + } + }, + "DeactivatedDidResolution": { + "type": "object", + "properties": { + "@context": { + "type": "string", + "example": "https://w3id.org/did-resolution/v1" + }, + "didDidResolutionMetadata": { + "$ref": "#/components/schemas/DidResolutionMetadata" + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + }, + "didDocumentMetadata": { + "$ref": "#/components/schemas/DeactivatedDidDocumentMetadata" + } + } + }, + "DidDocumentMetadata": { + "type": "object", + "properties": { + "created": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "deactivated": { + "type": "boolean", + "example": false + }, + "updated": { + "type": "string", + "example": "2021-09-10T12:00:00Z" + }, + "versionId": { + "type": "string", + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + "linkedResourceMetadata": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ResourceMetadata" + } + } + } + }, + "DeactivatedDidDocumentMetadata": { + "type": "object", + "properties": { + "created": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "deactivated": { + "type": "boolean", + "example": true + }, + "updated": { + "type": "string", + "example": "2021-09-10T12:00:00Z" + }, + "versionId": { + "type": "string", + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + "linkedResourceMetadata": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ResourceMetadata" + } + } + } + }, + "ResourceMetadata": { + "type": "object", + "properties": { + "resourceURI": { + "type": "string", + "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47/resources/398cee0a-efac-4643-9f4c-74c48c72a14b" + }, + "resourceCollectionId": { + "type": "string", + "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" + }, + "resourceId": { + "type": "string", + "example": "398cee0a-efac-4643-9f4c-74c48c72a14b" + }, + "resourceName": { + "type": "string", + "example": "cheqd-issuer-logo" + }, + "resourceType": { + "type": "string", + "example": "CredentialArtwork" + }, + "mediaType": { + "type": "string", + "example": "image/png" + }, + "resourceVersion": { + "type": "string", + "example": "1.0" + }, + "checksum": { + "type": "string", + "example": "a95380f460e63ad939541a57aecbfd795fcd37c6d78ee86c885340e33a91b559" + }, + "created": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "nextVersionId": { + "type": "string", + "example": "d4829ac7-4566-478c-a408-b44767eddadc" + }, + "previousVersionId": { + "type": "string", + "example": "ad7a8442-3531-46eb-a024-53953ec6e4ff" + } + } + }, + "DidResolutionMetadata": { + "type": "object", + "properties": { + "contentType": { + "allOf": [ + { + "$ref": "#/components/schemas/ContentType" + } + ], + "example": "application/did+ld+json" + }, + "retrieved": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "did": { + "$ref": "#/components/schemas/DidProperties" + } + } + }, + "ContentType": { + "type": "string", + "enum": ["application/did+json", "application/did+ld+json", "application/ld+json", "application/json"] + }, + "DidProperties": { + "type": "object", + "properties": { + "didString": { + "type": "string", + "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" + }, + "method": { + "type": "string", + "example": "cheqd" + }, + "methodSpecificId": { + "type": "string", + "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" + } + } + }, + "Customer": { + "type": "object", + "properties": { + "customerId": { + "type": "string", + "example": "6w5drpiiwhhs" + }, + "address": { + "type": "string", + "example": "cheqd1wgsvqwlkmdp60f4dek26ak0sjw6au3ytd3pz7f" + } + } + }, + "AccountCreateRequest": { + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": { + "primaryEmail": { + "type": "string" + } + } + } + } + }, + "InvalidRequest": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "InvalidRequest" + } + } + }, + "InternalError": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Internal Error" + } + } + }, + "UnauthorizedError": { + "description": "Access token is missing or invalid", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Unauthorized Error" + } + } + } + } + } +} From 4791c0ca5ad513a0b3c6b2a330c7c291a646b707 Mon Sep 17 00:00:00 2001 From: Ankur Banerjee Date: Wed, 17 Apr 2024 11:39:41 +0100 Subject: [PATCH 34/40] npm run build:swagger --- src/static/swagger-admin.json | 2058 +++++----- src/static/swagger-api.json | 6882 +++++++++++++++++---------------- 2 files changed, 4597 insertions(+), 4343 deletions(-) diff --git a/src/static/swagger-admin.json b/src/static/swagger-admin.json index 72021893..f8d03627 100644 --- a/src/static/swagger-admin.json +++ b/src/static/swagger-admin.json @@ -1,1011 +1,1049 @@ { - "openapi": "3.0.0", - "info": { - "title": "Credential Service admin API for cheqd network", - "version": "2.0.0", - "description": "Admin API which handles users subscriptions and payments", - "contact": { - "name": "Cheqd Foundation Limited", - "url": "https://github.com/cheqd/credential-service", - "email": "support-github@cheqd.io" - }, - "license": { - "name": "Apache 2.0", - "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" - } - }, - "tags": [ - { - "name": "Product" - }, - { - "name": "Price" - }, - { - "name": "Subscription" - }, - { - "name": "API Key" - } - ], - "paths": { - "/admin/api-key/create": { - "post": { - "summary": "Create a new API key", - "description": "Create a new API key", - "tags": ["API Key"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyCreateRequestBody" - } - } - } - }, - "responses": { - "201": { - "description": "A new API key has been created", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyCreateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/APIKeyCreateUnsuccessfulResponseBody" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/api-key/update": { - "post": { - "summary": "Update an existing API key", - "description": "Update an existing API key", - "tags": ["API Key"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyUpdateRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The API key has been updated", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyUpdateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/APIKeyUpdateUnsuccessfulResponseBody" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/api-key/revoke": { - "delete": { - "summary": "Revoke an existing API key", - "description": "Revoke an existing API key", - "tags": ["API Key"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyRevokeRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The API key has been revoked", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyRevokeResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/APIKeyRevokeUnsuccessfulResponseBody" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/api-key/list": { - "get": { - "summary": "List all API keys", - "description": "List all API keys", - "tags": ["API Key"], - "responses": { - "200": { - "description": "A list of API keys", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/api-key/get": { - "get": { - "summary": "Get an API key", - "description": "Get an API key. If the API key is not provided, the latest not revoked API key it returns.", - "tags": ["API Key"], - "parameters": [ - { - "name": "apiKey", - "in": "query", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "The API key", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIKeyGetResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/price/list": { - "get": { - "summary": "Get a list of prices", - "description": "Get a list of prices", - "tags": ["Price"], - "parameters": [ - { - "in": "query", - "name": "productId", - "schema": { - "type": "string", - "description": "The product id. If passed - returns filtered by this product list of prices.", - "required": false - } - } - ], - "responses": { - "200": { - "description": "A list of prices", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PriceListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/product/list": { - "get": { - "summary": "Get a list of products", - "description": "Get a list of products which are on a Stripe side", - "tags": ["Product"], - "parameters": [ - { - "in": "query", - "name": "prices", - "schema": { - "type": "boolean", - "description": "If setup to true - returns the list of products with prices inside. Default - true", - "required": false - } - } - ], - "responses": { - "200": { - "description": "A list of products", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/product/get/{productId}": { - "get": { - "summary": "Get a product", - "description": "Get a product by id", - "tags": ["Product"], - "parameters": [ - { - "in": "path", - "name": "productId", - "schema": { - "type": "string", - "description": "The product id which identifies the product in Stripe" - }, - "required": true - }, - { - "in": "query", - "name": "prices", - "schema": { - "type": "boolean", - "description": "If setup to true - returns the product with prices inside. Default - true", - "required": false - } - } - ], - "responses": { - "200": { - "description": "A product", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductGetResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/create": { - "post": { - "summary": "Create a subscription", - "description": "Creates a new subscription for an existing customer", - "tags": ["Subscription"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCreateRequestBody" - } - } - } - }, - "responses": { - "201": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCreateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/update": { - "post": { - "summary": "Update a subscription", - "description": "Updates an existing subscription", - "tags": ["Subscription"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionUpdateRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionUpdateResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/list": { - "get": { - "summary": "Get a list of subscriptions", - "description": "Get a list of subscriptions", - "tags": ["Subscription"], - "parameters": [ - { - "in": "query", - "name": "paymentProviderId", - "schema": { - "type": "string", - "description": "The customer id. If passed - returns filtered by this customer list of subscriptions." - } - } - ], - "responses": { - "200": { - "description": "A list of subscriptions", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionListResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/get": { - "get": { - "summary": "Get a subscription", - "description": "Get a subscription", - "tags": ["Subscription"], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionGetResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/cancel": { - "post": { - "summary": "Cancel a subscription", - "description": "Cancels an existing subscription", - "tags": ["Subscription"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCancelRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionCancelResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/admin/subscription/resume": {}, - "post": { - "summary": "Resume a subscription", - "description": "Resumes an existing subscription", - "tags": ["Subscription"], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionResumeRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubscriptionResumeResponseBody" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "404": { - "$ref": "#/components/schemas/NotFoundError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "components": { - "schemas": { - "PriceListResponseBody": { - "description": "A list of active prcies from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/list)", - "type": "object", - "properties": { - "prices": { - "type": "array", - "items": { - "type": "object", - "description": "A price object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/object)" - } - } - } - }, - "ProductListResponseBody": { - "type": "object", - "properties": { - "products": { - "type": "array", - "items": { - "type": "object", - "description": "A product object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/object)" - } - } - } - }, - "ProductGetResponseBody": { - "description": "A product with or without prices inside. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/retrieve)", - "type": "object" - }, - "InvalidRequest": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "InvalidRequest" - } - } - }, - "InternalError": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Internal Error" - } - } - }, - "UnauthorizedError": { - "description": "Access token is missing or invalid", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Unauthorized Error" - } - } - }, - "SubscriptionCreateRequestBody": { - "description": "The request body for creating a subscription", - "type": "object", - "properties": { - "price": { - "type": "string", - "description": "The price id", - "example": "price_1234567890" - }, - "successURL": { - "type": "string", - "description": "The URL to redirect to after the customer sucessfully completes the checkout", - "example": "https://example.com/success" - }, - "cancelURL": { - "type": "string", - "description": "The URL to redirect to after the customer cancels the checkout", - "example": "https://example.com/cancel" - }, - "quantity": { - "type": "number", - "description": "The quantity of the product", - "example": 1 - }, - "trialPeriodDays": { - "type": "number", - "description": "The number of days the customer has to pay for the product", - "example": 7 - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": "abcdefghijklmnopqrstuvwxyz" - } - } - }, - "SubscriptionCreateResponseBody": { - "description": "The response body for creating a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "An object with link to checkout session. For more information see the [Stripe API documentation](https://docs.stripe.com/api/checkout/sessions/object)", - "properties": { - "sessionURL": { - "type": "string", - "description": "URL which user should follow to manage subscription" - } - } - } - } - }, - "SubscriptionUpdateRequestBody": { - "description": "The request body for updating a subscription", - "type": "object", - "properties": { - "returnURL": { - "type": "string", - "description": "URL which is used to redirect to the page with ability to update the subscription" - } - } - }, - "SubscriptionUpdateResponseBody": { - "description": "The response body for updating a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "Object with redirect url inside", - "properties": { - "sessionURL": { - "type": "string", - "description": "URL with session URL rediect to" - } - } - } - } - }, - "SubscriptionGetRequestBody": { - "description": "The request body for getting a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - } - } - }, - "SubscriptionGetResponseBody": { - "description": "The response body for getting a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" - } - } - }, - "SubscriptionListRequestBody": { - "description": "The request body for listing subscriptions", - "type": "object", - "properties": { - "customerId": { - "type": "string", - "description": "The Stripe customer id", - "example": "cus_1234567890" - } - } - }, - "SubscriptionListResponseBody": { - "description": "The response body for listing subscriptions", - "type": "object", - "properties": { - "subscriptions": { - "type": "array", - "items": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" - } - } - } - }, - "SubscriptionCancelRequestBody": { - "description": "The request body for canceling a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - } - } - }, - "SubscriptionCancelResponseBody": { - "description": "The response body for canceling a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": "abcdefghijklmnopqrstuvwxyz" - } - } - }, - "SubscriptionResumeRequestBody": { - "description": "The request body for resuming a subscription", - "type": "object", - "properties": { - "subscriptionId": { - "type": "string", - "description": "The subscription id", - "example": "sub_1234567890" - }, - "idempotencyKey": { - "type": "string", - "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", - "example": "abcdefghijklmnopqrstuvwxyz" - } - } - }, - "SubscriptionResumeResponseBody": { - "description": "The response body for resuming a subscription", - "type": "object", - "properties": { - "subscription": { - "type": "object", - "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" - } - } - }, - "APIKeyResponse": { - "description": "The general view for API key in response", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz" - }, - "createdAt": { - "type": "string", - "description": "The creation date of the API key", - "example": "2000-10-31T01:23:45Z", - "format": "date-time" - }, - "name": { - "type": "string", - "description": "The name of the API key", - "example": "My API Key" - }, - "expiresAt": { - "type": "string", - "description": "The expiration date of the API key", - "example": "2000-10-31T01:23:45Z", - "format": "date-time" - }, - "revoked": { - "type": "boolean", - "description": "The status of the API key", - "example": false - } - } - }, - "APIKeyCreateRequestBody": { - "description": "The request body for creating an API key", - "type": "object", - "properties": { - "expiresAt": { - "type": "string", - "description": "The expiration date of the API key", - "example": "2000-10-31T01:23:45Z", - "format": "date-time" - }, - "name": { - "type": "string", - "description": "The name of the API key", - "example": "My API Key" - } - }, - "required": ["name"] - }, - "APIKeyCreateResponseBody": { - "description": "The response body for creating an API key", - "type": "object", - "schema": { - "ref": "#/components/schemas/APIKeyResponse" - } - }, - "APIKeyCreateUnsuccessfulResponseBody": { - "description": "The response body for an unsuccessful API key creation", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "API key creation unsuccessful" - } - } - }, - "APIKeyUpdateRequestBody": { - "description": "The request body for updating an API key", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz" - }, - "name": { - "type": "string", - "description": "The name of the API key", - "example": "My API Key" - }, - "expiresAt": { - "type": "string", - "description": "The expiration date of the API key", - "example": "2000-10-31T01:23:45Z", - "format": "date-time" - }, - "revoked": { - "type": "boolean", - "description": "The status of the API key", - "example": false, - "default": false - } - }, - "required": ["apiKey"] - }, - "APIKeyUpdateResponseBody": { - "description": "The response body for an unsuccessful API key update", - "type": "object", - "schema": { - "ref": "#/components/schemas/APIKeyResponse" - } - }, - "APIKeyUpdateUnsuccessfulResponseBody": { - "description": "The response body for an unsuccessful API key update", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "API key update unsuccessful" - } - } - }, - "APIKeyRevokeRequestBody": { - "description": "The request body for revoking an API key", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz" - } - }, - "required": ["apiKey"] - }, - "APIKeyRevokeResponseBody": { - "description": "The response body for revoking an API key", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz" - }, - "revoked": { - "type": "boolean", - "description": "The status of the API key", - "example": true - } - }, - "required": ["apiKey"] - }, - "APIKeyRevokeUnsuccessfulResponseBody": { - "description": "The response body for an unsuccessful API key revocation", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "API key revocation unsuccessful" - } - } - }, - "APIKeyListResponseBody": { - "description": "The response body for listing API keys", - "type": "object", - "properties": { - "apiKeys": { - "type": "array", - "items": { - "type": "object", - "schema": { - "ref": "#/components/schemas/APIKeyResponse" - } - } - } - } - }, - "APIKeyGetRequestBody": { - "description": "The request body for getting an API key", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key", - "example": "abcdefghijklmnopqrstuvwxyz" - } - }, - "required": ["apiKey"] - }, - "APIKeyGetResponseBody": { - "description": "The response body for getting an API key", - "type": "object", - "schema": { - "ref": "#/components/schemas/APIKeyResponse" - } - }, - "NotFoundError": { - "description": "The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Not Found Error" - } - } - } - } - } -} + "openapi": "3.0.0", + "info": { + "title": "Credential Service admin API for cheqd network", + "version": "2.0.0", + "description": "Admin API which handles users subscriptions and payments", + "contact": { + "name": "Cheqd Foundation Limited", + "url": "https://github.com/cheqd/credential-service", + "email": "support-github@cheqd.io" + }, + "license": { + "name": "Apache 2.0", + "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" + } + }, + "tags": [ + { + "name": "Product" + }, + { + "name": "Price" + }, + { + "name": "Subscription" + }, + { + "name": "API Key" + } + ], + "paths": { + "/admin/api-key/create": { + "post": { + "summary": "Create a new API key", + "description": "Create a new API key", + "tags": [ + "API Key" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyCreateRequestBody" + } + } + } + }, + "responses": { + "201": { + "description": "A new API key has been created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyCreateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/APIKeyCreateUnsuccessfulResponseBody" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/api-key/update": { + "post": { + "summary": "Update an existing API key", + "description": "Update an existing API key", + "tags": [ + "API Key" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyUpdateRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The API key has been updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyUpdateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/APIKeyUpdateUnsuccessfulResponseBody" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/api-key/revoke": { + "delete": { + "summary": "Revoke an existing API key", + "description": "Revoke an existing API key", + "tags": [ + "API Key" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyRevokeRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The API key has been revoked", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyRevokeResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/APIKeyRevokeUnsuccessfulResponseBody" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/api-key/list": { + "get": { + "summary": "List all API keys", + "description": "List all API keys", + "tags": [ + "API Key" + ], + "responses": { + "200": { + "description": "A list of API keys", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/api-key/get": { + "get": { + "summary": "Get an API key", + "description": "Get an API key. If the API key is not provided, the latest not revoked API key it returns.", + "tags": [ + "API Key" + ], + "parameters": [ + { + "name": "apiKey", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIKeyGetResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/price/list": { + "get": { + "summary": "Get a list of prices", + "description": "Get a list of prices", + "tags": [ + "Price" + ], + "parameters": [ + { + "in": "query", + "name": "productId", + "schema": { + "type": "string", + "description": "The product id. If passed - returns filtered by this product list of prices.", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A list of prices", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PriceListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/product/list": { + "get": { + "summary": "Get a list of products", + "description": "Get a list of products which are on a Stripe side", + "tags": [ + "Product" + ], + "parameters": [ + { + "in": "query", + "name": "prices", + "schema": { + "type": "boolean", + "description": "If setup to true - returns the list of products with prices inside. Default - true", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A list of products", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProductListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/product/get/{productId}": { + "get": { + "summary": "Get a product", + "description": "Get a product by id", + "tags": [ + "Product" + ], + "parameters": [ + { + "in": "path", + "name": "productId", + "schema": { + "type": "string", + "description": "The product id which identifies the product in Stripe" + }, + "required": true + }, + { + "in": "query", + "name": "prices", + "schema": { + "type": "boolean", + "description": "If setup to true - returns the product with prices inside. Default - true", + "required": false + } + } + ], + "responses": { + "200": { + "description": "A product", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProductGetResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/create": { + "post": { + "summary": "Create a subscription", + "description": "Creates a new subscription for an existing customer", + "tags": [ + "Subscription" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCreateRequestBody" + } + } + } + }, + "responses": { + "201": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCreateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/update": { + "post": { + "summary": "Update a subscription", + "description": "Updates an existing subscription", + "tags": [ + "Subscription" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionUpdateRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionUpdateResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/list": { + "get": { + "summary": "Get a list of subscriptions", + "description": "Get a list of subscriptions", + "tags": [ + "Subscription" + ], + "parameters": [ + { + "in": "query", + "name": "paymentProviderId", + "schema": { + "type": "string", + "description": "The customer id. If passed - returns filtered by this customer list of subscriptions." + } + } + ], + "responses": { + "200": { + "description": "A list of subscriptions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionListResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/get": { + "get": { + "summary": "Get a subscription", + "description": "Get a subscription", + "tags": [ + "Subscription" + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionGetResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/cancel": { + "post": { + "summary": "Cancel a subscription", + "description": "Cancels an existing subscription", + "tags": [ + "Subscription" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCancelRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionCancelResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/admin/subscription/resume": {}, + "post": { + "summary": "Resume a subscription", + "description": "Resumes an existing subscription", + "tags": [ + "Subscription" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionResumeRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionResumeResponseBody" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "404": { + "$ref": "#/components/schemas/NotFoundError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "components": { + "schemas": { + "PriceListResponseBody": { + "description": "A list of active prcies from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/list)", + "type": "object", + "properties": { + "prices": { + "type": "array", + "items": { + "type": "object", + "description": "A price object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/prices/object)" + } + } + } + }, + "ProductListResponseBody": { + "type": "object", + "properties": { + "products": { + "type": "array", + "items": { + "type": "object", + "description": "A product object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/object)" + } + } + } + }, + "ProductGetResponseBody": { + "description": "A product with or without prices inside. For more information see the [Stripe API documentation](https://docs.stripe.com/api/products/retrieve)", + "type": "object" + }, + "InvalidRequest": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "InvalidRequest" + } + } + }, + "InternalError": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Internal Error" + } + } + }, + "UnauthorizedError": { + "description": "Access token is missing or invalid", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Unauthorized Error" + } + } + }, + "SubscriptionCreateRequestBody": { + "description": "The request body for creating a subscription", + "type": "object", + "properties": { + "price": { + "type": "string", + "description": "The price id", + "example": "price_1234567890" + }, + "successURL": { + "type": "string", + "description": "The URL to redirect to after the customer sucessfully completes the checkout", + "example": "https://example.com/success" + }, + "cancelURL": { + "type": "string", + "description": "The URL to redirect to after the customer cancels the checkout", + "example": "https://example.com/cancel" + }, + "quantity": { + "type": "number", + "description": "The quantity of the product", + "example": 1 + }, + "trialPeriodDays": { + "type": "number", + "description": "The number of days the customer has to pay for the product", + "example": 7 + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": "abcdefghijklmnopqrstuvwxyz" + } + } + }, + "SubscriptionCreateResponseBody": { + "description": "The response body for creating a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "An object with link to checkout session. For more information see the [Stripe API documentation](https://docs.stripe.com/api/checkout/sessions/object)", + "properties": { + "sessionURL": { + "type": "string", + "description": "URL which user should follow to manage subscription" + } + } + } + } + }, + "SubscriptionUpdateRequestBody": { + "description": "The request body for updating a subscription", + "type": "object", + "properties": { + "returnURL": { + "type": "string", + "description": "URL which is used to redirect to the page with ability to update the subscription" + } + } + }, + "SubscriptionUpdateResponseBody": { + "description": "The response body for updating a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "Object with redirect url inside", + "properties": { + "sessionURL": { + "type": "string", + "description": "URL with session URL rediect to" + } + } + } + } + }, + "SubscriptionGetRequestBody": { + "description": "The request body for getting a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + } + } + }, + "SubscriptionGetResponseBody": { + "description": "The response body for getting a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object)" + } + } + }, + "SubscriptionListRequestBody": { + "description": "The request body for listing subscriptions", + "type": "object", + "properties": { + "customerId": { + "type": "string", + "description": "The Stripe customer id", + "example": "cus_1234567890" + } + } + }, + "SubscriptionListResponseBody": { + "description": "The response body for listing subscriptions", + "type": "object", + "properties": { + "subscriptions": { + "type": "array", + "items": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + } + } + } + }, + "SubscriptionCancelRequestBody": { + "description": "The request body for canceling a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + } + } + }, + "SubscriptionCancelResponseBody": { + "description": "The response body for canceling a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": "abcdefghijklmnopqrstuvwxyz" + } + } + }, + "SubscriptionResumeRequestBody": { + "description": "The request body for resuming a subscription", + "type": "object", + "properties": { + "subscriptionId": { + "type": "string", + "description": "The subscription id", + "example": "sub_1234567890" + }, + "idempotencyKey": { + "type": "string", + "description": "The idempotency key. It helps to prevent duplicate requests. In case if there was a request with the same idempotency key, the response will be the same as for the first request.", + "example": "abcdefghijklmnopqrstuvwxyz" + } + } + }, + "SubscriptionResumeResponseBody": { + "description": "The response body for resuming a subscription", + "type": "object", + "properties": { + "subscription": { + "type": "object", + "description": "A subscription object from Stripe. For more information see the [Stripe API documentation](https://docs.stripe.com/api/subscriptions/object]" + } + } + }, + "APIKeyResponse": { + "description": "The general view for API key in response", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + }, + "createdAt": { + "type": "string", + "description": "The creation date of the API key", + "example": "2000-10-31T01:23:45Z", + "format": "date-time" + }, + "name": { + "type": "string", + "description": "The name of the API key", + "example": "My API Key" + }, + "expiresAt": { + "type": "string", + "description": "The expiration date of the API key", + "example": "2000-10-31T01:23:45Z", + "format": "date-time" + }, + "revoked": { + "type": "boolean", + "description": "The status of the API key", + "example": false + } + } + }, + "APIKeyCreateRequestBody": { + "description": "The request body for creating an API key", + "type": "object", + "properties": { + "expiresAt": { + "type": "string", + "description": "The expiration date of the API key", + "example": "2000-10-31T01:23:45Z", + "format": "date-time" + }, + "name": { + "type": "string", + "description": "The name of the API key", + "example": "My API Key" + } + }, + "required": [ + "name" + ] + }, + "APIKeyCreateResponseBody": { + "description": "The response body for creating an API key", + "type": "object", + "schema": { + "ref": "#/components/schemas/APIKeyResponse" + } + }, + "APIKeyCreateUnsuccessfulResponseBody": { + "description": "The response body for an unsuccessful API key creation", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "API key creation unsuccessful" + } + } + }, + "APIKeyUpdateRequestBody": { + "description": "The request body for updating an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + }, + "name": { + "type": "string", + "description": "The name of the API key", + "example": "My API Key" + }, + "expiresAt": { + "type": "string", + "description": "The expiration date of the API key", + "example": "2000-10-31T01:23:45Z", + "format": "date-time" + }, + "revoked": { + "type": "boolean", + "description": "The status of the API key", + "example": false, + "default": false + } + }, + "required": [ + "apiKey" + ] + }, + "APIKeyUpdateResponseBody": { + "description": "The response body for an unsuccessful API key update", + "type": "object", + "schema": { + "ref": "#/components/schemas/APIKeyResponse" + } + }, + "APIKeyUpdateUnsuccessfulResponseBody": { + "description": "The response body for an unsuccessful API key update", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "API key update unsuccessful" + } + } + }, + "APIKeyRevokeRequestBody": { + "description": "The request body for revoking an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + } + }, + "required": [ + "apiKey" + ] + }, + "APIKeyRevokeResponseBody": { + "description": "The response body for revoking an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + }, + "revoked": { + "type": "boolean", + "description": "The status of the API key", + "example": true + } + }, + "required": [ + "apiKey" + ] + }, + "APIKeyRevokeUnsuccessfulResponseBody": { + "description": "The response body for an unsuccessful API key revocation", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "API key revocation unsuccessful" + } + } + }, + "APIKeyListResponseBody": { + "description": "The response body for listing API keys", + "type": "object", + "properties": { + "apiKeys": { + "type": "array", + "items": { + "type": "object", + "schema": { + "ref": "#/components/schemas/APIKeyResponse" + } + } + } + } + }, + "APIKeyGetRequestBody": { + "description": "The request body for getting an API key", + "type": "object", + "properties": { + "apiKey": { + "type": "string", + "description": "The API key", + "example": "abcdefghijklmnopqrstuvwxyz" + } + }, + "required": [ + "apiKey" + ] + }, + "APIKeyGetResponseBody": { + "description": "The response body for getting an API key", + "type": "object", + "schema": { + "ref": "#/components/schemas/APIKeyResponse" + } + }, + "NotFoundError": { + "description": "The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Not Found Error" + } + } + } + } + } +} \ No newline at end of file diff --git a/src/static/swagger-api.json b/src/static/swagger-api.json index b2cf4b99..a42f421f 100644 --- a/src/static/swagger-api.json +++ b/src/static/swagger-api.json @@ -1,3334 +1,3550 @@ { - "openapi": "3.0.0", - "info": { - "title": "Credential Service API for cheqd network", - "version": "2.0.0", - "description": "API service to create and manage DIDs, Verifiable Credentials, and DID-Linked Resources", - "contact": { - "name": "Cheqd Foundation Limited", - "url": "https://github.com/cheqd/credential-service", - "email": "support-github@cheqd.io" - }, - "license": { - "name": "Apache 2.0", - "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" - } - }, - "tags": [ - { - "name": "Account" - }, - { - "name": "Key" - }, - { - "name": "DID" - }, - { - "name": "Resource" - }, - { - "name": "Credential" - }, - { - "name": "Presentation" - }, - { - "name": "Credential Status" - } - ], - "externalDocs": { - "description": "Credential Service API Documentation", - "url": "https://docs.cheqd.io/identity" - }, - "paths": { - "/account": { - "get": { - "tags": ["Account"], - "summary": "Fetch custodian-mode client details.", - "description": "This endpoint returns the custodian-mode client details for authenticated users.", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Customer" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/account/idtoken": { - "get": { - "tags": ["Account"], - "summary": "Fetch IdToken.", - "description": "This endpoint returns IdToken as JWT with list of user roles inside", - "deprecated": true, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "idToken": { - "type": "string" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/account/create": { - "post": { - "tags": ["Account"], - "summary": "Create an client for an authenticated user.", - "description": "This endpoint creates a client in the custodian-mode for an authenticated user", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/AccountCreateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/AccountCreateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "idToken": { - "type": "string" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/create/unencrypted": { - "post": { - "tags": ["Credential Status"], - "summary": "Create an unencrypted StatusList2021 credential status list.", - "description": "This endpoint creates an unencrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", - "parameters": [ - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", - "required": true, - "schema": { - "type": "string", - "enum": ["revocation", "suspension"] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/create/encrypted": { - "post": { - "tags": ["Credential Status"], - "summary": "Create an encrypted StatusList2021 credential status list.", - "description": "This endpoint creates an encrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", - "parameters": [ - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", - "required": true, - "schema": { - "type": "string", - "enum": ["revocation", "suspension"] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateEncryptedFormRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateEncryptedJsonRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCreateEncryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/update/unencrypted": { - "post": { - "tags": ["Credential Status"], - "summary": "Update an existing unencrypted StatusList2021 credential status list.", - "parameters": [ - { - "in": "query", - "name": "statusAction", - "description": "The update action to be performed on the unencrypted status list, can be revoke, suspend or reinstate", - "required": true, - "schema": { - "type": "string", - "enum": ["revoke", "suspend", "reinstate"] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/update/encrypted": { - "post": { - "tags": ["Credential Status"], - "summary": "Update an existing encrypted StatusList2021 credential status list.", - "parameters": [ - { - "in": "query", - "name": "statusAction", - "description": "The update action to be performed on the encrypted status list, can be revoke, suspend or reinstate", - "required": true, - "schema": { - "type": "string", - "enum": ["revoke", "suspend", "reinstate"] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedFormRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedJsonRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/check": { - "post": { - "tags": ["Credential Status"], - "summary": "Check a StatusList2021 index for a given Verifiable Credential.", - "description": "This endpoint checks a StatusList2021 index for a given Verifiable Credential and reports whether it is revoked or suspended. It offers a standalone method for checking an index without passing the entire Verifiable Credential or Verifiable Presentation.", - "parameters": [ - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension.", - "required": true, - "schema": { - "type": "string", - "enum": ["revocation", "suspension"] - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCheckRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCheckRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusCheckResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential-status/search": { - "get": { - "tags": ["Credential Status"], - "summary": "Fetch StatusList2021 DID-Linked Resource based on search criteria.", - "parameters": [ - { - "in": "query", - "name": "did", - "description": "The DID of the issuer of the status list.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "statusPurpose", - "description": "The purpose of the status list. Can be either revocation or suspension.", - "schema": { - "type": "string", - "enum": ["revocation", "suspension"] - } - }, - { - "in": "query", - "name": "statusListName", - "description": "The name of the StatusList2021 DID-Linked Resource.", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialStatusListSearchResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/issue": { - "post": { - "tags": ["Credential"], - "summary": "Issue a Verifiable Credential", - "description": "This endpoint issues a Verifiable Credential. As input it takes the list of issuerDid, subjectDid, attributes, and other parameters of the credential to be issued.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Credential" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/verify": { - "post": { - "tags": ["Credential"], - "summary": "Verify a Verifiable Credential.", - "description": "This endpoint verifies a Verifiable Credential passed to it. As input, it can take the VC-JWT as a string or the entire credential itself.", - "operationId": "verify", - "parameters": [ - { - "in": "query", - "name": "verifyStatus", - "description": "If set to `true` the verification will also check the status of the credential. Requires the VC to have a `credentialStatus` property.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "fetchRemoteContexts", - "description": "When dealing with JSON-LD you also MUST provide the proper contexts. Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "allowDeactivatedDid", - "description": "If set to `true` allow to verify credential which based on deactivated DID.", - "schema": { - "type": "boolean", - "default": false - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialVerifyRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialVerifyRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/VerifyCredentialResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/revoke": { - "post": { - "tags": ["Credential"], - "summary": "Revoke a Verifiable Credential.", - "description": "This endpoint revokes a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself. The StatusList2021 resource should already be setup in the VC and `credentialStatus` property present in the VC.", - "operationId": "revoke", - "parameters": [ - { - "in": "query", - "name": "publish", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RevocationResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/suspend": { - "post": { - "tags": ["Credential"], - "summary": "Suspend a Verifiable Credential.", - "description": "This endpoint suspends a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself.", - "operationId": "suspend", - "parameters": [ - { - "in": "query", - "name": "publish", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "schema": { - "type": "boolean" - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuspensionResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/credential/reinstate": { - "post": { - "tags": ["Credential"], - "summary": "Reinstate a suspended Verifiable Credential.", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "operationId": "reinstate", - "parameters": [ - { - "in": "query", - "name": "publish", - "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", - "schema": { - "type": "boolean" - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CredentialRevokeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnsuspensionResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/create": { - "post": { - "tags": ["DID"], - "summary": "Create a DID Document.", - "description": "This endpoint creates a DID and associated DID Document. As input, it can take the DID Document parameters via a form, or the fully-assembled DID Document itself.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidCreateRequestFormBased" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidCreateRequestJson" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/did/update": { - "post": { - "tags": ["DID"], - "summary": "Update a DID Document.", - "description": "This endpoint updates a DID Document. As an input, it can take JUST the sections/parameters that need to be updated in the DID Document (in this scenario, it fetches the current DID Document and applies the updated section). Alternatively, it take the fully-assembled DID Document with updated sections as well as unchanged sections.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidUpdateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidUpdateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidUpdateResponse" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/import": { - "post": { - "tags": ["DID"], - "summary": "Import a DID Document.", - "description": "This endpoint imports a decentralized identifier associated with the user's account for custodian-mode clients.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidImportRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidImportRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/did/deactivate/{did}": { - "post": { - "tags": ["DID"], - "summary": "Deactivate a DID Document.", - "description": "This endpoint deactivates a DID Document by taking the DID identifier as input. Must be called and signed by the DID owner.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier to deactivate.", - "schema": { - "type": "string" - }, - "required": true - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/DidDeactivateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidDeactivateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeactivatedDidResolution" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/list": { - "get": { - "tags": ["DID"], - "summary": "Fetch DIDs associated with an account.", - "description": "This endpoint returns the list of DIDs controlled by the account.", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/did/search/{did}": { - "get": { - "tags": ["DID"], - "summary": "Resolve a DID Document.", - "description": "Resolve a DID Document by DID identifier. Also supports DID Resolution Queries as defined in the W3C DID Resolution specification.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier to resolve.", - "schema": { - "type": "string" - }, - "required": true, - "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - { - "in": "query", - "name": "metadata", - "description": "Return only metadata of DID Document instead of actual DID Document.", - "schema": { - "type": "boolean" - } - }, - { - "in": "query", - "name": "versionId", - "description": "Unique UUID version identifier of DID Document. Allows for fetching a specific version of the DID Document. See cheqd DID Method Specification for more details.", - "schema": { - "type": "string", - "format": "uuid" - }, - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - { - "in": "query", - "name": "versionTime", - "description": "Returns the closest version of the DID Document *at* or *before* specified time. See DID Resolution handling for `did:cheqd` for more details.", - "schema": { - "type": "string", - "format": "date-time" - }, - "example": "1970-01-01T00:00:00Z" - }, - { - "in": "query", - "name": "transformKeys", - "description": "This directive transforms the Verification Method key format from the version in the DID Document to the specified format chosen below.", - "schema": { - "type": "string", - "enum": ["Ed25519VerificationKey2018", "Ed25519VerificationKey2020", "JsonWebKey2020"] - } - }, - { - "in": "query", - "name": "service", - "description": "Query DID Document for a specific Service Endpoint by Service ID (e.g., `service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`). This will typically redirect to the Service Endpoint based on DID Resolution specification algorithm.", - "schema": { - "type": "string" - }, - "example": "service-1" - }, - { - "in": "query", - "name": "relativeRef", - "description": "Relative reference is a query fragment appended to the Service Endpoint URL. **Must** be used along with the `service` query property above. See DID Resolution specification algorithm for more details.", - "schema": { - "type": "string" - }, - "example": "/path/to/file" - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DidResolution" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/key/create": { - "post": { - "tags": ["Key"], - "summary": "Create an identity key pair.", - "description": "This endpoint creates an identity key pair associated with the user's account for custodian-mode clients.", - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/key/import": { - "post": { - "tags": ["Key"], - "summary": "Import an identity key pair.", - "description": "This endpoint imports an identity key pair associated with the user's account for custodian-mode clients.", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/KeyImportRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyImportRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/key/read/{kid}": { - "get": { - "tags": ["Key"], - "summary": "Fetch an identity key pair.", - "description": "This endpoint fetches an identity key pair's details for a given key ID. Only the user account associated with the custodian-mode client can fetch the key pair.", - "parameters": [ - { - "name": "kid", - "description": "Key ID of the identity key pair to fetch.", - "in": "path", - "schema": { - "type": "string" - }, - "required": true - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/KeyResult" - } - } - } - }, - "400": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "InvalidRequest" - } - } - } - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "example": { - "error": "Internal Error" - } - } - } - } - } - } - }, - "/presentation/create": { - "post": { - "tags": ["Presentation"], - "summary": "!!! WARN. Such endpoint is made mostly for testing purposes and it is not supposed to be used in production !!! Create a Verifiable Presentation from credential(s).", - "description": "This endpoint creates a Verifiable Presentation from credential(s). As input, it can take the credential(s) as a string or the entire credential(s) itself. \n !!! WARN. Such endpoint is made only for testing purposes !!!", - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/PresentationCreateRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/PresentationCreateRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PresentationCreateResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/presentation/verify": { - "post": { - "tags": ["Presentation"], - "summary": "Verify a Verifiable Presentation generated from credential(s).", - "description": "This endpoint verifies the Verifiable Presentation generated from credential(s). As input, it can take the Verifiable Presentation JWT as a string or the entire Verifiable Presentation itself.", - "parameters": [ - { - "in": "query", - "name": "verifyStatus", - "description": "If set to `true` the verification will also check the status of the presentation. Requires the VP to have a `credentialStatus` property.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "fetchRemoteContexts", - "description": "When dealing with JSON-LD you also MUST provide the proper contexts. * Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", - "schema": { - "type": "boolean", - "default": false - } - }, - { - "in": "query", - "name": "allowDeactivatedDid", - "description": "If set to `true` allow to verify credential which based on deactivated DID.", - "schema": { - "type": "boolean", - "default": false - } - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/PresentationVerifyRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/PresentationVerifyRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/VerifyPresentationResult" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/resource/create/{did}": { - "post": { - "tags": ["Resource"], - "summary": "Create a DID-Linked Resource.", - "description": "This endpoint creates a DID-Linked Resource. As input, it can take the DID identifier and the resource parameters via a form, or the fully-assembled resource itself.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier to link the resource to.", - "schema": { - "type": "string" - }, - "required": true - } - ], - "requestBody": { - "content": { - "application/x-www-form-urlencoded": { - "schema": { - "$ref": "#/components/schemas/CreateResourceRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateResourceRequest" - } - } - } - }, - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ResourceMetadata" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - }, - "/resource/search/{did}": { - "get": { - "tags": ["Resource"], - "summary": "Get a DID-Linked Resource.", - "description": "This endpoint returns the DID-Linked Resource for a given DID identifier and resource identifier.", - "parameters": [ - { - "in": "path", - "name": "did", - "description": "DID identifier", - "schema": { - "type": "string" - }, - "required": true, - "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - { - "in": "query", - "name": "resourceId", - "description": "Fetch a DID-Linked Resource by Resource ID unique identifier. Since this is a unique identifier, other Resource query parameters are not required. See DID-Linked Resources for more details.", - "schema": { - "type": "string", - "format": "uuid" - }, - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - { - "in": "query", - "name": "resourceName", - "description": "Filter a DID-Linked Resource query by Resource Name. See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "cheqd-issuer-logo" - }, - { - "in": "query", - "name": "resourceType", - "description": "Filter a DID-Linked Resource query by Resource Type. See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "CredentialArtwork" - }, - { - "in": "query", - "name": "resourceVersion", - "description": "Filter a DID-Linked Resource query by Resource Version, which is an optional free-text field used by issuers (e.g., \"v1\", \"Final Version\", \"1st January 1970\" etc). See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "v1" - }, - { - "in": "query", - "name": "resourceVersionTime", - "description": "Filter a DID-Linked Resource query which returns the closest version of the Resource *at* or *before* specified time. See DID-Linked Resources for more details.", - "schema": { - "type": "string", - "format": "date-time" - }, - "example": "1970-01-01T00:00:00Z" - }, - { - "in": "query", - "name": "checksum", - "description": "Request integrity check against a given DID-Linked Resource by providing a SHA-256 checksum hash. See DID-Linked Resources for more details.", - "schema": { - "type": "string" - }, - "example": "dc64474d062ed750a66bad58cb609928de55ed0d81defd231a4a4bf97358e9ed" - }, - { - "in": "query", - "name": "resourceMetadata", - "description": "Return only metadata of DID-Linked Resource instead of actual DID-Linked Resource. Mutually exclusive with some of the other parameters.", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "The request was successful.", - "content": { - "any": { - "schema": { - "type": "object" - } - } - } - }, - "400": { - "$ref": "#/components/schemas/InvalidRequest" - }, - "401": { - "$ref": "#/components/schemas/UnauthorizedError" - }, - "500": { - "$ref": "#/components/schemas/InternalError" - } - } - } - } - }, - "components": { - "schemas": { - "AlsoKnownAs": { - "type": "object", - "properties": { - "alsoKnownAs": { - "type": "array", - "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", - "items": { - "type": "object", - "properties": { - "uri": { - "type": "string", - "format": "uri", - "description": "URI where the DID-Linked Resource can be fetched from. Can be any type of URI (e.g., DID, HTTPS, IPFS, etc.)" - }, - "description": { - "type": "string", - "description": "Optional description of the URI." - } - } - } - } - } - }, - "CredentialRequest": { - "description": "Input fields for the creating a Verifiable Credential.", - "type": "object", - "additionalProperties": false, - "properties": { - "issuerDid": { - "description": "DID of the Verifiable Credential issuer. This needs to be a `did:cheqd` DID.", - "type": "string", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "subjectDid": { - "description": "DID of the Verifiable Credential holder/subject. This needs to be a `did:key` DID.", - "type": "string", - "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" - }, - "attributes": { - "description": "JSON object containing the attributes to be included in the credential.", - "type": "object", - "example": { - "name": "Bob", - "gender": "male" - } - }, - "@context": { - "description": "Optional properties to be included in the `@context` property of the credential.", - "type": "array", - "items": { - "type": "string" - }, - "example": ["https://schema.org/schema.jsonld", "https://veramo.io/contexts/profile/v1"] - }, - "type": { - "description": "Optional properties to be included in the `type` property of the credential.", - "type": "array", - "items": { - "type": "string" - }, - "example": ["Person"] - }, - "expirationDate": { - "description": "Optional expiration date according to the VC Data Model specification.", - "type": "string", - "format": "date-time", - "example": "2023-06-08T13:49:28.000Z" - }, - "format": { - "description": "Format of the Verifiable Credential. Defaults to VC-JWT.", - "type": "string", - "enum": ["jwt", "jsonld"], - "example": "jwt" - }, - "credentialStatus": { - "description": "Optional `credentialStatus` properties for VC revocation or suspension. Takes `statusListName` and `statusListPurpose` as inputs.", - "type": "object", - "required": ["statusPurpose", "statusListName"], - "properties": { - "statusPurpose": { - "type": "string", - "enum": ["revocation", "suspension"] - }, - "statusListName": { - "type": "string" - }, - "statusListIndex": { - "type": "number" - }, - "statusListVersion": { - "type": "string", - "format": "date-time" - }, - "statusListRangeStart": { - "type": "number" - }, - "statusListRangeEnd": { - "type": "number" - }, - "indexNotIn": { - "type": "number" - } - }, - "example": { - "statusPurpose": "revocation", - "statusListName": "employee-credentials" - } - } - }, - "required": ["issuerDid", "subjectDid", "attributes"], - "example": { - "issuerDid": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "subjectDid": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", - "attributes": { - "gender": "male", - "name": "Bob" - }, - "@context": ["https://schema.org"], - "type": ["Person"], - "format": "jwt", - "credentialStatus": { - "statusPurpose": "revocation", - "statusListName": "employee-credentials", - "statusListIndex": 10 - } - } - }, - "Credential": { - "description": "Input fields for revoking/suspending a Verifiable Credential.", - "type": "object", - "additionalProperties": false, - "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - }, - "example": [ - "https://www.w3.org/2018/credentials/v1", - "https://schema.org", - "https://veramo.io/contexts/profile/v1" - ] - }, - "type": { - "type": "array", - "items": { - "type": "string" - }, - "example": ["VerifiableCredential", "Person"] - }, - "expirationDate": { - "type": "string", - "format": "date-time", - "example": "2023-06-08T13:49:28.000Z" - }, - "issuer": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "DID", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - } - } - }, - "credentialSubject": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "DID", - "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" - } - } - }, - "credentialStatus": { - "type": "object", - "properties": { - "id": { - "type": "string", - "example": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20" - }, - "statusListIndex": { - "type": "number", - "example": 20 - }, - "statusPurpose": { - "type": "string", - "enum": ["revocation", "suspension"], - "example": "suspension" - }, - "type": { - "type": "string", - "enum": ["StatusList2021Entry"] - } - } - }, - "issuanceDate": { - "type": "string", - "format": "date-time", - "example": "2023-06-08T13:49:28.000Z" - }, - "proof": { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "jwt": { - "type": "string" - } - }, - "example": { - "type": "JwtProof2020", - "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg" - } - } - }, - "example": { - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://schema.org", - "https://veramo.io/contexts/profile/v1" - ], - "credentialSubject": { - "gender": "male", - "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", - "name": "Bob" - }, - "credentialStatus": { - "id": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20", - "statusIndex": 20, - "statusPurpose": "suspension", - "type": "StatusList2021Entry" - }, - "issuanceDate": "2023-06-08T13:49:28.000Z", - "issuer": { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "proof": { - "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg", - "type": "JwtProof2020" - }, - "type": ["VerifiableCredential", "Person"] - } - }, - "CredentialRevokeRequest": { - "type": "object", - "properties": { - "credential": { - "description": "Verifiable Credential to be revoked as a VC-JWT string or a JSON object.", - "oneOf": [ - { - "type": "object" - }, - { - "type": "string" - } - ] - }, - "symmetricKey": { - "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource. Required if the StatusList2021 DID-Linked Resource is encrypted.", - "type": "string" - } - } - }, - "RevocationResult": { - "properties": { - "revoked": { - "type": "boolean", - "example": true - } - } - }, - "SuspensionResult": { - "properties": { - "suspended": { - "type": "boolean", - "example": true - } - } - }, - "UnsuspensionResult": { - "properties": { - "unsuspended": { - "type": "boolean", - "example": true - } - } - }, - "CredentialVerifyRequest": { - "type": "object", - "properties": { - "credential": { - "description": "Verifiable Credential to be verified as a VC-JWT string or a JSON object.", - "type": "object" - }, - "policies": { - "description": "Custom verification policies to execute when verifying credential.", - "type": "object", - "properties": { - "issuanceDate": { - "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "expirationDate": { - "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "audience": { - "description": "Policy to skip the audience check when set to `false`.", - "type": "boolean", - "default": false - } - } - } - } - }, - "VerifyPresentationResult": { - "type": "object", - "properties": { - "verified": { - "type": "boolean" - }, - "issuer": { - "type": "string" - }, - "signer": { - "type": "object" - }, - "jwt": { - "type": "string" - }, - "verifiableCredential": { - "type": "object" - } - } - }, - "VerifyCredentialResult": { - "type": "object", - "properties": { - "verified": { - "type": "boolean" - }, - "issuer": { - "type": "string" - }, - "signer": { - "type": "object" - }, - "jwt": { - "type": "string" - }, - "verifiableCredential": { - "type": "object" - } - }, - "example": { - "verified": true, - "polices": {}, - "issuer": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "signer": { - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", - "type": "Ed25519VerificationKey2018" - } - } - }, - "PresentationCreateRequest": { - "type": "object", - "required": ["credentials"], - "properties": { - "credentials": { - "description": "Verifiable Credentials to be used for VP-JWT creation as a VP-JWT strings or a JSON objectsf.", - "type": "array", - "items": { - "type": "object" - } - }, - "holderDid": { - "description": "DID of holder", - "type": "string" - }, - "verifierDid": { - "description": "DID of verifier", - "type": "string" - } - } - }, - "PresentationVerifyRequest": { - "type": "object", - "required": ["presentation"], - "properties": { - "presentation": { - "description": "Verifiable Presentation to be verified as a VP-JWT string or a JSON object.", - "type": "object" - }, - "verifierDid": { - "description": "Provide an optional verifier DID (also known as 'domain' parameter), if the verifier DID in the presentation is not managed in the wallet.", - "type": "string" - }, - "makeFeePayment": { - "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", - "type": "boolean", - "default": false - }, - "policies": { - "description": "Custom verification policies to execute when verifying presentation.", - "type": "object", - "properties": { - "issuanceDate": { - "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "expirationDate": { - "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", - "type": "boolean", - "default": true - }, - "audience": { - "description": "Policy to skip the audience check when set to `false`.", - "type": "boolean", - "default": false - } - } - } - } - }, - "CredentialStatusCreateBody": { - "allOf": [ - { - "type": "object", - "required": ["did", "statusListName"], - "properties": { - "did": { - "description": "DID of the StatusList2021 publisher.", - "type": "string", - "format": "uri" - }, - "statusListName": { - "description": "The name of the StatusList2021 DID-Linked Resource to be created.", - "type": "string" - }, - "length": { - "description": "The length of the status list to be created. The default and minimum length is 140000 which is 16kb.", - "type": "integer", - "minimum": 0, - "exclusiveMinimum": true, - "default": 140000 - }, - "encoding": { - "description": "The encoding format of the StatusList2021 DiD-Linked Resource to be created.", - "type": "string", - "default": "base64url", - "enum": ["base64url", "base64", "hex"] - }, - "statusListVersion": { - "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - { - "$ref": "#/components/schemas/AlsoKnownAs" - } - ] - }, - "CredentialStatusCreateUnencryptedRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCreateBody" - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials", - "length": 140000, - "encoding": "base64url" - } - }, - "CredentialStatusUnencryptedResult": { - "type": "object", - "properties": { - "resource": { - "type": "object", - "properties": { - "StatusList2021": { - "type": "object", - "properties": { - "encodedList": { - "type": "string", - "example": "H4sIAAAAAAAAA-3BAQ0AAADCoPdPbQ8HFAAAAAAAAAAAAAAAAAAAAADwaDhDr_xcRAAA" - }, - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "validFrom": { - "type": "string", - "format": "date-time", - "example": "2023-06-26T11:45:19.349Z" - } - } - }, - "metadata": { - "type": "object", - "properties": { - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "encoding": { - "type": "string", - "example": "base64url" - }, - "encrypted": { - "type": "boolean", - "example": false - } - } - } - } - }, - "resourceMetadata": { - "type": "object", - "example": { - "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceName": "cheqd-employee-credentials", - "resourceType": "StatusList2021Revocation", - "mediaType": "application/json", - "resourceVersion": "1.0.0", - "created": "2023-06-26T11:45:20Z", - "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", - "previousVersionId": null, - "nextVersionId": null - } - } - } - }, - "CredentialStatusCreateUnencryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "created": { - "type": "boolean", - "example": true - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" - } - ] - }, - "CredentialStatusEncryptedPaymentConditionsBody": { - "type": "object", - "properties": { - "feePaymentAddress": { - "description": "The cheqd/Cosmos payment address where payments to unlock the encrypted StatusList2021 DID-Linked Resource need to be sent.", - "type": "string", - "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" - }, - "feePaymentAmount": { - "description": "Amount in CHEQ tokens to unlock the encrypted StatusList2021 DID-Linked Resource.", - "type": "number", - "minimum": 0, - "exclusiveMinimum": true, - "default": 20 - }, - "feePaymentWindow": { - "description": "Time window (in minutes) within which the payment to unlock the encrypted StatusList2021 DID-Linked Resource is considered valid.", - "type": "number", - "minimum": 0, - "exclusiveMinimum": true, - "default": 10 - } - } - }, - "CredentialStatusEncryptedPaymentConditionsJson": { - "type": "object", - "properties": { - "paymentConditions": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" - } - ] - } - } - }, - "CredentialStatusCreateEncryptedFormRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCreateBody" - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" - }, - { - "type": "object", - "required": ["feePaymentAddress", "feePaymentAmount", "feePaymentWindow"] - } - ] - }, - "CredentialStatusCreateEncryptedJsonRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCreateBody" - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" - }, - { - "type": "object", - "required": ["paymentConditions"] - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials-encrypted", - "paymentConditions": [ - { - "feePaymentAddress": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg", - "feePaymentAmount": 20, - "feePaymentWindow": 10 - } - ] - } - }, - "CredentialStatusEncryptedResult": { - "type": "object", - "properties": { - "resource": { - "type": "object", - "properties": { - "StatusList2021": { - "type": "object", - "properties": { - "encodedList": { - "type": "string", - "example": "496fdfbeb745b4db03fcdb40566f9c4c4a1c0f184b31255e641b6e7bdfb9b6946c12be87ca3763be0393c00b67ac1e8737c106b32f46ef59c765754415b5e8cc7c65fccaa3374620430ea476301a5e0dd63340e7a27a68bc627518471f22e4a2" - }, - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "validFrom": { - "type": "string", - "format": "date-time", - "example": "2023-06-26T11:45:19.349Z" - } - } - }, - "metadata": { - "type": "object", - "properties": { - "type": { - "type": "string", - "example": "StatusList2021Revocation" - }, - "encoding": { - "type": "string", - "example": "base64url" - }, - "encrypted": { - "type": "boolean", - "example": true - }, - "encryptedSymmetricKey": { - "type": "string", - "example": "b11182dc524b8181f9a6aef4c4ad0a1c14e40033b9112dffd8d1bcf6cc3b85abc07ded2205ee94068a99f4202502cb0855f322583fa6ce1534d3a05bf36891766ea2c5f90a982b3040680762977d404d758a2370224a239c8279aa7d21e980931c42055b17ca4c7dbffa4782480a8b6279cf989b2f166d5fdb4b2c1b5a63927200000000000000203018dcaba26df45a415bb599218b27ca853a70289d7a3ed3ed0e3730452e8f8d9af91b6e71312565d2c069341f6660ab" - }, - "paymentConditions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "feePaymentAddress": { - "type": "string", - "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" - }, - "feePaymentAmount": { - "type": "string", - "example": "20000000000ncheq" - }, - "intervalInSeconds": { - "type": "number", - "example": 600 - }, - "type": { - "type": "string", - "example": "timelockPayment" - } - } - } - } - } - }, - "resourceMetadata": { - "type": "object", - "example": { - "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", - "resourceName": "cheqd-revocation-encrypted-1", - "resourceType": "StatusList2021Revocation", - "mediaType": "application/json", - "resourceVersion": "2023-06-26T11:45:19.349Z", - "created": "2023-06-26T11:45:20Z", - "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", - "previousVersionId": null, - "nextVersionId": null - } - }, - "symmetricKey": { - "type": "string", - "example": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" - } - } - } - } - }, - "CredentialStatusCreateEncryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "created": { - "type": "boolean", - "example": true - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedResult" - } - ] - }, - "CredentialStatusUpdateBody": { - "type": "object", - "required": ["did", "statusListName", "indices"], - "properties": { - "did": { - "description": "DID of the StatusList2021 publisher.", - "type": "string", - "format": "uri" - }, - "statusListName": { - "description": "The name of the StatusList2021 DID-Linked Resource to be updated.", - "type": "string" - }, - "indices": { - "description": "List of credential status indices to be updated. The indices must be in the range of the status list.", - "type": "array", - "items": { - "type": "integer", - "minimum": 0, - "exclusiveMinimum": false - } - }, - "statusListVersion": { - "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - "CredentialStatusUpdateUnencryptedRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUpdateBody" - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials", - "indices": [10, 3199, 12109, 130999] - } - }, - "CredentialStatusUpdateUnencryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "updated": { - "type": "boolean", - "example": true - } - } - }, - { - "oneOf": [ - { - "$ref": "#/components/schemas/RevocationResult" - }, - { - "$ref": "#/components/schemas/SuspensionResult" - }, - { - "$ref": "#/components/schemas/UnsuspensionResult" - } - ] - }, - { - "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" - } - ] - }, - "CredentialStatusUpdateEncryptedFormRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUpdateBody" - }, - { - "type": "object", - "required": ["symmetricKey"], - "properties": { - "symmetricKey": { - "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" - } - ] - }, - "CredentialStatusUpdateEncryptedJsonRequest": { - "allOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUpdateBody" - }, - { - "type": "object", - "required": ["symmetricKey"], - "properties": { - "symmetricKey": { - "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", - "type": "string" - } - } - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" - } - ], - "example": { - "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", - "statusListName": "cheqd-employee-credentials-encrypted", - "indices": [10, 3199, 12109, 130999], - "symmetricKey": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" - } - }, - "CredentialStatusUpdateEncryptedResult": { - "allOf": [ - { - "type": "object", - "properties": { - "updated": { - "type": "boolean", - "example": true - } - } - }, - { - "oneOf": [ - { - "$ref": "#/components/schemas/RevocationResult" - }, - { - "$ref": "#/components/schemas/SuspensionResult" - }, - { - "$ref": "#/components/schemas/UnsuspensionResult" - } - ] - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedResult" - } - ] - }, - "CredentialStatusCheckRequest": { - "type": "object", - "required": ["did", "statusListName", "index"], - "properties": { - "did": { - "description": "DID of the StatusList2021 publisher.", - "type": "string", - "format": "uri" - }, - "statusListName": { - "description": "The name of the StatusList2021 DID-Linked Resource to be checked.", - "type": "string" - }, - "index": { - "description": "Credential status index to be checked for revocation or suspension.", - "type": "integer", - "minimum": 0, - "exclusiveMinimum": false - }, - "makeFeePayment": { - "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", - "type": "boolean", - "default": true - } - } - }, - "CredentialStatusCheckResult": { - "oneOf": [ - { - "$ref": "#/components/schemas/CredentialStatusCheckRevocationResult" - }, - { - "$ref": "#/components/schemas/CredentialStatusCheckSuspensionResult" - } - ] - }, - "CredentialStatusCheckRevocationResult": { - "type": "object", - "properties": { - "checked": { - "type": "boolean", - "example": true - }, - "revoked": { - "type": "boolean", - "example": false - } - } - }, - "CredentialStatusCheckSuspensionResult": { - "type": "object", - "properties": { - "checked": { - "type": "boolean", - "example": true - }, - "suspended": { - "type": "boolean", - "example": false - } - } - }, - "CredentialStatusListSearchResult": { - "allOf": [ - { - "type": "object", - "properties": { - "found": { - "type": "boolean", - "example": true - } - } - }, - { - "oneOf": [ - { - "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" - }, - { - "$ref": "#/components/schemas/CredentialStatusEncryptedResult" - } - ] - } - ] - }, - "KeyImportRequest": { - "type": "object", - "properties": { - "alias": { - "type": "string" - }, - "type": { - "type": "string", - "enum": ["Ed25519", "Secp256k1"] - }, - "privateKeyHex": { - "type": "string" - } - } - }, - "KeyResult": { - "type": "object", - "properties": { - "kid": { - "type": "string" - }, - "type": { - "type": "string", - "enum": ["Ed25519", "Secp256k1"] - }, - "publicKeyHex": { - "type": "string" - } - } - }, - "DidDocument": { - "description": "This input field contains either a complete DID document, or an incremental change (diff) to a DID document. See Universal DID Registrar specification.", - "type": "object", - "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - } - }, - "id": { - "type": "string" - }, - "controllers": { - "type": "array", - "items": { - "type": "string" - } - }, - "verificationMethod": { - "type": "array", - "items": { - "$ref": "#/components/schemas/VerificationMethod" - } - }, - "service": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "authentication": { - "type": "array", - "items": { - "type": "string" - } - }, - "assertionMethod": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityInvocation": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityDelegation": { - "type": "array", - "items": { - "type": "string" - } - }, - "keyAgreement": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "@context": ["https://www.w3.org/ns/did/v1"], - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "controller": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0"], - "verificationMethod": [ - { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "type": "Ed25519VerificationKey2018", - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "publicKeyBase58": "z6MkkVbyHJLLjdjU5B62DaJ4mkdMdUkttf9UqySSkA9bVTeZ" - } - ], - "authentication": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1"], - "service": [ - { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", - "type": "LinkedDomains", - "serviceEndpoint": ["https://example.com"] - } - ] - } - }, - "DidDocumentWithoutVerificationMethod": { - "type": "object", - "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - } - }, - "id": { - "type": "string" - }, - "controllers": { - "type": "array", - "items": { - "type": "string" - } - }, - "service": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "authentication": { - "type": "array", - "items": { - "type": "string" - } - }, - "assertionMethod": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityInvocation": { - "type": "array", - "items": { - "type": "string" - } - }, - "capabilityDelegation": { - "type": "array", - "items": { - "type": "string" - } - }, - "keyAgreement": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "@context": ["https://www.w3.org/ns/did/v1"], - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "controller": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0"], - "authentication": ["did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1"], - "service": [ - { - "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", - "type": "LinkedDomains", - "serviceEndpoint": ["https://example.com"] - } - ] - } - }, - "DidCreateRequestFormBased": { - "type": "object", - "properties": { - "network": { - "description": "Network to create the DID on (testnet or mainnet)", - "type": "string", - "enum": ["testnet", "mainnet"] - }, - "identifierFormatType": { - "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", - "type": "string", - "enum": ["uuid", "base58btc"] - }, - "verificationMethodType": { - "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", - "type": "string", - "enum": ["Ed25519VerificationKey2018", "JsonWebKey2020", "Ed25519VerificationKey2020"] - }, - "service": { - "description": "It's a list of special objects which are designed to build the actual service. It's almost the same as in DID Core specification, but instead of `id` it utilises `idFragment` field for making the right `id` for each service. !!! WARN. Cause swagger-ui does not handle x-ww-form based arrays correctly, please frame all your services in brackets while using swagger UI. !!!", - "type": "array", - "items": { - "type": "object", - "properties": { - "idFragment": { - "type": "string" - }, - "type": { - "type": "string" - }, - "serviceEndpoint": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "example": [ - { - "idFragment": "service-1", - "type": "LinkedDomains", - "serviceEndpoint": ["https://example.com"] - } - ] - }, - "key": { - "description": "The unique identifier in hexadecimal public key format used in the verification method to create the DID.", - "type": "string" - }, - "@context": { - "type": "array", - "items": { - "type": "string" - }, - "example": ["https://www.w3.org/ns/did/v1"] - } - } - }, - "DidCreateRequestJson": { - "type": "object", - "properties": { - "network": { - "description": "Network to create the DID on (testnet or mainnet)", - "type": "string", - "enum": ["testnet", "mainnet"] - }, - "identifierFormatType": { - "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", - "type": "string", - "enum": ["uuid", "base58btc"] - }, - "assertionMethod": { - "description": "Usually a reference to a Verification Method. An Assertion Method is required to issue JSON-LD credentials. See DID Core specification for more details.", - "type": "boolean", - "default": true - }, - "options": { - "type": "object", - "properties": { - "key": { - "type": "string", - "example": "8255ddadd75695e01f3d98fcec8ccc7861a030b317d4326b0e48a4d579ddc43a" - }, - "verificationMethodType": { - "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", - "type": "string", - "enum": ["Ed25519VerificationKey2018", "JsonWebKey2020", "Ed25519VerificationKey2020"] - } - } - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocumentWithoutVerificationMethod" - } - } - }, - "DidImportRequest": { - "type": "object", - "properties": { - "did": { - "type": "string", - "description": "DID to be imported", - "format": "uri", - "required": true - }, - "keys": { - "type": "array", - "description": "List of keys required to import the DID", - "required": true, - "items": { - "$ref": "#/components/schemas/KeyImportRequest" - } - } - } - }, - "PresentationCreateResult": { - "type": "object", - "properties": { - "vp": { - "type": "object", - "description": "Verifiable Presentation which could be provided to the verifier." - }, - "nbf": { - "type": "integer", - "description": "Unix timestamp of the earliest time that the Verifiable Presentation is valid." - }, - "iss": { - "type": "string", - "description": "DID of the issuer of the Verifiable Presentation. (Here it's supposed to be a holder DID)" - }, - "aud": { - "type": "array", - "items": { - "type": "string" - }, - "description": "DID of the verifier of the Verifiable Presentation." - } - }, - "example": { - "vp": { - "@context": ["https://www.w3.org/2018/credentials/v1"], - "type": ["VerifiablePresentation"], - "verifiableCredential": [ - "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc2NoZW1hLm9yZy9zY2hlbWEuanNvbmxkIiwiaHR0cHM6Ly92ZXJhbW8uaW8vY29udGV4dHMvcHJvZmlsZS92MSIsImh0dHBzOi8vdzNpZC5vcmcvdmMtc3RhdHVzLWxpc3QtMjAyMS92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiUGVyc29uIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7Im5hbWUiOiJCb2IiLCJnZW5kZXIiOiJtYWxlIn0sImNyZWRlbnRpYWxTdGF0dXMiOnsiaWQiOiJodHRwczovL3Jlc29sdmVyLmNoZXFkLm5ldC8xLjAvaWRlbnRpZmllcnMvZGlkOmNoZXFkOnRlc3RuZXQ6OTBkNWMxNDEtNzI0Zi00N2FkLTlhZTctYTdjMzNhOWU1NjQzP3Jlc291cmNlTmFtZT1zdXNwZW5zaW9uRW4mcmVzb3VyY2VUeXBlPVN0YXR1c0xpc3QyMDIxU3VzcGVuc2lvbiMxMzMzOCIsInR5cGUiOiJTdGF0dXNMaXN0MjAyMUVudHJ5Iiwic3RhdHVzUHVycG9zZSI6InN1c3BlbnNpb24iLCJzdGF0dXNMaXN0SW5kZXgiOiIxMzMzOCJ9fSwic3ViIjoiZGlkOmtleTp6Nk1raGFYZ0JaRHZvdERrTDUyNTdmYWl6dGlHaUMyUXRLTEdwYm5uRUd0YTJkb0siLCJuYmYiOjE3MDA0NzM0MTYsImlzcyI6ImRpZDpjaGVxZDp0ZXN0bmV0OjkwZDVjMTQxLTcyNGYtNDdhZC05YWU3LWE3YzMzYTllNTY0MyJ9.-14Ril1pZEy2HEEo48gTJr2yOtGxBhUGTFmzVdjAtyhFRsW5zZg9onHt6V9JQ8BaiYBlTkP9GzTnJ-O6hdiyCw" - ] - }, - "nbf": 1700744275, - "iss": "did:cheqd:testnet:4b846d0f-2f6c-4ab6-9fe2-5b8db301c83c", - "aud": ["did:cheqd:testnet:8c71e9b6-c5a3-4250-8c58-fa591533cd22"] - } - }, - "DidResult": { - "type": "object", - "properties": { - "did": { - "type": "string" - }, - "controllerKeyId": { - "type": "string" - }, - "keys": { - "type": "array", - "items": { - "type": "object" - } - }, - "services": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - } - } - }, - "DidUpdateResponse": { - "type": "object", - "properties": { - "did": { - "type": "string" - }, - "controllerKeyId": { - "type": "string", - "description": "The default key id of which is the key associated with the first verificationMethod" - }, - "keys": { - "type": "array", - "description": "The list of keys associated with the list of verificationMethod's of DIDDocument", - "items": { - "type": "object" - } - }, - "services": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "controllerKeyRefs": { - "type": "array", - "description": "The list of keyRefs which were used for signing the transaction", - "items": { - "type": "string" - } - }, - "controllerKeys": { - "type": "array", - "description": "The list of all possible keys, inlcuding all controller's keys", - "items": { - "type": "string" - } - } - } - }, - "VerificationMethod": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string" - }, - "controller": { - "type": "string" - }, - "publicKeyMultibase": { - "type": "string" - }, - "publicKeyJwk": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", - "id": "did:cheqd:testnet :7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", - "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", - "type": "Ed25519VerificationKey2018" - } - }, - "Service": { - "description": "Communicating or interacting with the DID subject or associated entities via one or more service endpoints. See DID Core specification for more details.", - "type": "object", - "properties": { - "id": { - "description": "DID appended with Service fragment ID (e.g., `#service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`)", - "type": "string", - "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1" - }, - "type": { - "description": "Service type as defined in DID Specification Registries.", - "type": "string", - "example": "LinkedDomains" - }, - "serviceEndpoint": { - "description": "Service endpoint as defined in DID Core Specification.", - "type": "array", - "items": { - "type": "string", - "example": "https://example.com" - } - } - } - }, - "DidUpdateRequest": { - "type": "object", - "properties": { - "did": { - "description": "DID identifier to be updated.", - "type": "string", - "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" - }, - "service": { - "type": "array", - "description": "Service section of the DID Document.", - "items": { - "$ref": "#/components/schemas/Service" - } - }, - "verificationMethod": { - "type": "array", - "description": "Verification Method section of the DID Document.", - "items": { - "$ref": "#/components/schemas/VerificationMethod" - } - }, - "authentication": { - "description": "Authentication section of the DID Document.", - "type": "array", - "items": { - "type": "string" - } - }, - "publicKeyHexs": { - "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", - "type": "array", - "items": { - "type": "string" - } - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - } - } - }, - "DidDeactivateRequest": { - "type": "object", - "properties": { - "publicKeyHexs": { - "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "CreateResourceRequest": { - "description": "Input fields for DID-Linked Resource creation.", - "type": "object", - "additionalProperties": false, - "required": ["name", "type", "data", "encoding"], - "properties": { - "data": { - "description": "Encoded string containing the data to be stored in the DID-Linked Resource.", - "type": "string" - }, - "encoding": { - "description": "Encoding format used to encode the data.", - "type": "string", - "enum": ["base64url", "base64", "hex"] - }, - "name": { - "description": "Name of DID-Linked Resource.", - "type": "string" - }, - "type": { - "description": "Type of DID-Linked Resource. This is NOT the same as the media type, which is calculated automatically ledger-side.", - "type": "string" - }, - "alsoKnownAs": { - "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", - "type": "array", - "items": { - "type": "object", - "properties": { - "uri": { - "type": "string" - }, - "description": { - "type": "string" - } - } - } - }, - "version": { - "description": "Optional field to assign a human-readable version in the DID-Linked Resource.", - "type": "string" - }, - "publicKeyHexs": { - "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", - "type": "array", - "items": { - "type": "string" - } - } - }, - "example": { - "data": "SGVsbG8gV29ybGQ=", - "encoding": "base64url", - "name": "ResourceName", - "type": "TextDocument" - } - }, - "ResourceList": { - "type": "object", - "properties": { - "@context": { - "type": "string", - "example": "https://w3id.org/did-resolution/v1" - }, - "contentMetadata": { - "type": "object" - }, - "contentStream": { - "type": "object" - }, - "dereferencingMetadata": { - "$ref": "#/components/schemas/DereferencingMetadata" - } - } - }, - "DereferencingMetadata": { - "type": "object", - "properties": { - "contentType": { - "type": "string", - "example": "application/did+ld+json" - }, - "did": { - "$ref": "#/components/schemas/DidProperties" - }, - "retrieved": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - } - } - }, - "DidResolution": { - "type": "object", - "properties": { - "@context": { - "type": "string", - "example": "https://w3id.org/did-resolution/v1" - }, - "didDidResolutionMetadata": { - "$ref": "#/components/schemas/DidResolutionMetadata" - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - }, - "didDocumentMetadata": { - "$ref": "#/components/schemas/DidDocumentMetadata" - } - } - }, - "DeactivatedDidResolution": { - "type": "object", - "properties": { - "@context": { - "type": "string", - "example": "https://w3id.org/did-resolution/v1" - }, - "didDidResolutionMetadata": { - "$ref": "#/components/schemas/DidResolutionMetadata" - }, - "didDocument": { - "$ref": "#/components/schemas/DidDocument" - }, - "didDocumentMetadata": { - "$ref": "#/components/schemas/DeactivatedDidDocumentMetadata" - } - } - }, - "DidDocumentMetadata": { - "type": "object", - "properties": { - "created": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "deactivated": { - "type": "boolean", - "example": false - }, - "updated": { - "type": "string", - "example": "2021-09-10T12:00:00Z" - }, - "versionId": { - "type": "string", - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - "linkedResourceMetadata": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ResourceMetadata" - } - } - } - }, - "DeactivatedDidDocumentMetadata": { - "type": "object", - "properties": { - "created": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "deactivated": { - "type": "boolean", - "example": true - }, - "updated": { - "type": "string", - "example": "2021-09-10T12:00:00Z" - }, - "versionId": { - "type": "string", - "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" - }, - "linkedResourceMetadata": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ResourceMetadata" - } - } - } - }, - "ResourceMetadata": { - "type": "object", - "properties": { - "resourceURI": { - "type": "string", - "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47/resources/398cee0a-efac-4643-9f4c-74c48c72a14b" - }, - "resourceCollectionId": { - "type": "string", - "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" - }, - "resourceId": { - "type": "string", - "example": "398cee0a-efac-4643-9f4c-74c48c72a14b" - }, - "resourceName": { - "type": "string", - "example": "cheqd-issuer-logo" - }, - "resourceType": { - "type": "string", - "example": "CredentialArtwork" - }, - "mediaType": { - "type": "string", - "example": "image/png" - }, - "resourceVersion": { - "type": "string", - "example": "1.0" - }, - "checksum": { - "type": "string", - "example": "a95380f460e63ad939541a57aecbfd795fcd37c6d78ee86c885340e33a91b559" - }, - "created": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "nextVersionId": { - "type": "string", - "example": "d4829ac7-4566-478c-a408-b44767eddadc" - }, - "previousVersionId": { - "type": "string", - "example": "ad7a8442-3531-46eb-a024-53953ec6e4ff" - } - } - }, - "DidResolutionMetadata": { - "type": "object", - "properties": { - "contentType": { - "allOf": [ - { - "$ref": "#/components/schemas/ContentType" - } - ], - "example": "application/did+ld+json" - }, - "retrieved": { - "type": "string", - "example": "2021-09-01T12:00:00Z" - }, - "did": { - "$ref": "#/components/schemas/DidProperties" - } - } - }, - "ContentType": { - "type": "string", - "enum": ["application/did+json", "application/did+ld+json", "application/ld+json", "application/json"] - }, - "DidProperties": { - "type": "object", - "properties": { - "didString": { - "type": "string", - "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" - }, - "method": { - "type": "string", - "example": "cheqd" - }, - "methodSpecificId": { - "type": "string", - "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" - } - } - }, - "Customer": { - "type": "object", - "properties": { - "customerId": { - "type": "string", - "example": "6w5drpiiwhhs" - }, - "address": { - "type": "string", - "example": "cheqd1wgsvqwlkmdp60f4dek26ak0sjw6au3ytd3pz7f" - } - } - }, - "AccountCreateRequest": { - "type": "object", - "properties": { - "user": { - "type": "object", - "properties": { - "primaryEmail": { - "type": "string" - } - } - } - } - }, - "InvalidRequest": { - "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "InvalidRequest" - } - } - }, - "InternalError": { - "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Internal Error" - } - } - }, - "UnauthorizedError": { - "description": "Access token is missing or invalid", - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "Unauthorized Error" - } - } - } - } - } -} + "openapi": "3.0.0", + "info": { + "title": "Credential Service API for cheqd network", + "version": "2.0.0", + "description": "API service to create and manage DIDs, Verifiable Credentials, and DID-Linked Resources", + "contact": { + "name": "Cheqd Foundation Limited", + "url": "https://github.com/cheqd/credential-service", + "email": "support-github@cheqd.io" + }, + "license": { + "name": "Apache 2.0", + "url": "https://github.com/cheqd/credential-service/blob/main/LICENSE" + } + }, + "tags": [ + { + "name": "Account" + }, + { + "name": "Key" + }, + { + "name": "DID" + }, + { + "name": "Resource" + }, + { + "name": "Credential" + }, + { + "name": "Presentation" + }, + { + "name": "Credential Status" + } + ], + "externalDocs": { + "description": "Credential Service API Documentation", + "url": "https://docs.cheqd.io/identity" + }, + "paths": { + "/account": { + "get": { + "tags": [ + "Account" + ], + "summary": "Fetch custodian-mode client details.", + "description": "This endpoint returns the custodian-mode client details for authenticated users.", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Customer" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/account/idtoken": { + "get": { + "tags": [ + "Account" + ], + "summary": "Fetch IdToken.", + "description": "This endpoint returns IdToken as JWT with list of user roles inside", + "deprecated": true, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "idToken": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/account/create": { + "post": { + "tags": [ + "Account" + ], + "summary": "Create an client for an authenticated user.", + "description": "This endpoint creates a client in the custodian-mode for an authenticated user", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/AccountCreateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "idToken": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/create/unencrypted": { + "post": { + "tags": [ + "Credential Status" + ], + "summary": "Create an unencrypted StatusList2021 credential status list.", + "description": "This endpoint creates an unencrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", + "required": true, + "schema": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateUnencryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/create/encrypted": { + "post": { + "tags": [ + "Credential Status" + ], + "summary": "Create an encrypted StatusList2021 credential status list.", + "description": "This endpoint creates an encrypted StatusList2021 credential status list. The StatusList is published as a DID-Linked Resource on ledger. As input, it can can take input parameters needed to create the status list via a form, or a pre-assembled status list in JSON format. Status lists can be created as either encrypted or unencrypted; and with purpose as either revocation or suspension.", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension. Once this is set, it cannot be changed. A new status list must be created to change the purpose.", + "required": true, + "schema": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateEncryptedFormRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateEncryptedJsonRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCreateEncryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/update/unencrypted": { + "post": { + "tags": [ + "Credential Status" + ], + "summary": "Update an existing unencrypted StatusList2021 credential status list.", + "parameters": [ + { + "in": "query", + "name": "statusAction", + "description": "The update action to be performed on the unencrypted status list, can be revoke, suspend or reinstate", + "required": true, + "schema": { + "type": "string", + "enum": [ + "revoke", + "suspend", + "reinstate" + ] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateUnencryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/update/encrypted": { + "post": { + "tags": [ + "Credential Status" + ], + "summary": "Update an existing encrypted StatusList2021 credential status list.", + "parameters": [ + { + "in": "query", + "name": "statusAction", + "description": "The update action to be performed on the encrypted status list, can be revoke, suspend or reinstate", + "required": true, + "schema": { + "type": "string", + "enum": [ + "revoke", + "suspend", + "reinstate" + ] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedFormRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedJsonRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusUpdateEncryptedResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/check": { + "post": { + "tags": [ + "Credential Status" + ], + "summary": "Check a StatusList2021 index for a given Verifiable Credential.", + "description": "This endpoint checks a StatusList2021 index for a given Verifiable Credential and reports whether it is revoked or suspended. It offers a standalone method for checking an index without passing the entire Verifiable Credential or Verifiable Presentation.", + "parameters": [ + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension.", + "required": true, + "schema": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ] + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCheckRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCheckRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusCheckResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential-status/search": { + "get": { + "tags": [ + "Credential Status" + ], + "summary": "Fetch StatusList2021 DID-Linked Resource based on search criteria.", + "parameters": [ + { + "in": "query", + "name": "did", + "description": "The DID of the issuer of the status list.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "statusPurpose", + "description": "The purpose of the status list. Can be either revocation or suspension.", + "schema": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ] + } + }, + { + "in": "query", + "name": "statusListName", + "description": "The name of the StatusList2021 DID-Linked Resource.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialStatusListSearchResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/issue": { + "post": { + "tags": [ + "Credential" + ], + "summary": "Issue a Verifiable Credential", + "description": "This endpoint issues a Verifiable Credential. As input it takes the list of issuerDid, subjectDid, attributes, and other parameters of the credential to be issued.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Credential" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/verify": { + "post": { + "tags": [ + "Credential" + ], + "summary": "Verify a Verifiable Credential.", + "description": "This endpoint verifies a Verifiable Credential passed to it. As input, it can take the VC-JWT as a string or the entire credential itself.", + "operationId": "verify", + "parameters": [ + { + "in": "query", + "name": "verifyStatus", + "description": "If set to `true` the verification will also check the status of the credential. Requires the VC to have a `credentialStatus` property.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "fetchRemoteContexts", + "description": "When dealing with JSON-LD you also MUST provide the proper contexts. Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "allowDeactivatedDid", + "description": "If set to `true` allow to verify credential which based on deactivated DID.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialVerifyRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialVerifyRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyCredentialResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/revoke": { + "post": { + "tags": [ + "Credential" + ], + "summary": "Revoke a Verifiable Credential.", + "description": "This endpoint revokes a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself. The StatusList2021 resource should already be setup in the VC and `credentialStatus` property present in the VC.", + "operationId": "revoke", + "parameters": [ + { + "in": "query", + "name": "publish", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RevocationResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/suspend": { + "post": { + "tags": [ + "Credential" + ], + "summary": "Suspend a Verifiable Credential.", + "description": "This endpoint suspends a given Verifiable Credential. As input, it can take the VC-JWT as a string or the entire credential itself.", + "operationId": "suspend", + "parameters": [ + { + "in": "query", + "name": "publish", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuspensionResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/credential/reinstate": { + "post": { + "tags": [ + "Credential" + ], + "summary": "Reinstate a suspended Verifiable Credential.", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "operationId": "reinstate", + "parameters": [ + { + "in": "query", + "name": "publish", + "description": "Set whether the StatusList2021 resource should be published to the ledger or not. If set to `false`, the StatusList2021 publisher should manually publish the resource.", + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CredentialRevokeRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnsuspensionResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/create": { + "post": { + "tags": [ + "DID" + ], + "summary": "Create a DID Document.", + "description": "This endpoint creates a DID and associated DID Document. As input, it can take the DID Document parameters via a form, or the fully-assembled DID Document itself.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidCreateRequestFormBased" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidCreateRequestJson" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/did/update": { + "post": { + "tags": [ + "DID" + ], + "summary": "Update a DID Document.", + "description": "This endpoint updates a DID Document. As an input, it can take JUST the sections/parameters that need to be updated in the DID Document (in this scenario, it fetches the current DID Document and applies the updated section). Alternatively, it take the fully-assembled DID Document with updated sections as well as unchanged sections.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidUpdateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidUpdateResponse" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/import": { + "post": { + "tags": [ + "DID" + ], + "summary": "Import a DID Document.", + "description": "This endpoint imports a decentralized identifier associated with the user's account for custodian-mode clients.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidImportRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidImportRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/did/deactivate/{did}": { + "post": { + "tags": [ + "DID" + ], + "summary": "Deactivate a DID Document.", + "description": "This endpoint deactivates a DID Document by taking the DID identifier as input. Must be called and signed by the DID owner.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier to deactivate.", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/DidDeactivateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidDeactivateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeactivatedDidResolution" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/list": { + "get": { + "tags": [ + "DID" + ], + "summary": "Fetch DIDs associated with an account.", + "description": "This endpoint returns the list of DIDs controlled by the account.", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/did/search/{did}": { + "get": { + "tags": [ + "DID" + ], + "summary": "Resolve a DID Document.", + "description": "Resolve a DID Document by DID identifier. Also supports DID Resolution Queries as defined in the W3C DID Resolution specification.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier to resolve.", + "schema": { + "type": "string" + }, + "required": true, + "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + { + "in": "query", + "name": "metadata", + "description": "Return only metadata of DID Document instead of actual DID Document.", + "schema": { + "type": "boolean" + } + }, + { + "in": "query", + "name": "versionId", + "description": "Unique UUID version identifier of DID Document. Allows for fetching a specific version of the DID Document. See cheqd DID Method Specification for more details.", + "schema": { + "type": "string", + "format": "uuid" + }, + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + { + "in": "query", + "name": "versionTime", + "description": "Returns the closest version of the DID Document *at* or *before* specified time. See DID Resolution handling for `did:cheqd` for more details.", + "schema": { + "type": "string", + "format": "date-time" + }, + "example": "1970-01-01T00:00:00Z" + }, + { + "in": "query", + "name": "transformKeys", + "description": "This directive transforms the Verification Method key format from the version in the DID Document to the specified format chosen below.", + "schema": { + "type": "string", + "enum": [ + "Ed25519VerificationKey2018", + "Ed25519VerificationKey2020", + "JsonWebKey2020" + ] + } + }, + { + "in": "query", + "name": "service", + "description": "Query DID Document for a specific Service Endpoint by Service ID (e.g., `service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`). This will typically redirect to the Service Endpoint based on DID Resolution specification algorithm.", + "schema": { + "type": "string" + }, + "example": "service-1" + }, + { + "in": "query", + "name": "relativeRef", + "description": "Relative reference is a query fragment appended to the Service Endpoint URL. **Must** be used along with the `service` query property above. See DID Resolution specification algorithm for more details.", + "schema": { + "type": "string" + }, + "example": "/path/to/file" + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DidResolution" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/key/create": { + "post": { + "tags": [ + "Key" + ], + "summary": "Create an identity key pair.", + "description": "This endpoint creates an identity key pair associated with the user's account for custodian-mode clients.", + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/key/import": { + "post": { + "tags": [ + "Key" + ], + "summary": "Import an identity key pair.", + "description": "This endpoint imports an identity key pair associated with the user's account for custodian-mode clients.", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/KeyImportRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyImportRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/key/read/{kid}": { + "get": { + "tags": [ + "Key" + ], + "summary": "Fetch an identity key pair.", + "description": "This endpoint fetches an identity key pair's details for a given key ID. Only the user account associated with the custodian-mode client can fetch the key pair.", + "parameters": [ + { + "name": "kid", + "description": "Key ID of the identity key pair to fetch.", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeyResult" + } + } + } + }, + "400": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "InvalidRequest" + } + } + } + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "example": { + "error": "Internal Error" + } + } + } + } + } + } + }, + "/presentation/create": { + "post": { + "tags": [ + "Presentation" + ], + "summary": "!!! WARN. Such endpoint is made mostly for testing purposes and it is not supposed to be used in production !!! Create a Verifiable Presentation from credential(s).", + "description": "This endpoint creates a Verifiable Presentation from credential(s). As input, it can take the credential(s) as a string or the entire credential(s) itself. \n !!! WARN. Such endpoint is made only for testing purposes !!!", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/PresentationCreateRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationCreateResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/presentation/verify": { + "post": { + "tags": [ + "Presentation" + ], + "summary": "Verify a Verifiable Presentation generated from credential(s).", + "description": "This endpoint verifies the Verifiable Presentation generated from credential(s). As input, it can take the Verifiable Presentation JWT as a string or the entire Verifiable Presentation itself.", + "parameters": [ + { + "in": "query", + "name": "verifyStatus", + "description": "If set to `true` the verification will also check the status of the presentation. Requires the VP to have a `credentialStatus` property.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "fetchRemoteContexts", + "description": "When dealing with JSON-LD you also MUST provide the proper contexts. * Set this to `true` ONLY if you want the `@context` URLs to be fetched in case they are a custom context.", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "in": "query", + "name": "allowDeactivatedDid", + "description": "If set to `true` allow to verify credential which based on deactivated DID.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/PresentationVerifyRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PresentationVerifyRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyPresentationResult" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/resource/create/{did}": { + "post": { + "tags": [ + "Resource" + ], + "summary": "Create a DID-Linked Resource.", + "description": "This endpoint creates a DID-Linked Resource. As input, it can take the DID identifier and the resource parameters via a form, or the fully-assembled resource itself.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier to link the resource to.", + "schema": { + "type": "string" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/CreateResourceRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateResourceRequest" + } + } + } + }, + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourceMetadata" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + }, + "/resource/search/{did}": { + "get": { + "tags": [ + "Resource" + ], + "summary": "Get a DID-Linked Resource.", + "description": "This endpoint returns the DID-Linked Resource for a given DID identifier and resource identifier.", + "parameters": [ + { + "in": "path", + "name": "did", + "description": "DID identifier", + "schema": { + "type": "string" + }, + "required": true, + "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + { + "in": "query", + "name": "resourceId", + "description": "Fetch a DID-Linked Resource by Resource ID unique identifier. Since this is a unique identifier, other Resource query parameters are not required. See DID-Linked Resources for more details.", + "schema": { + "type": "string", + "format": "uuid" + }, + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + { + "in": "query", + "name": "resourceName", + "description": "Filter a DID-Linked Resource query by Resource Name. See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "cheqd-issuer-logo" + }, + { + "in": "query", + "name": "resourceType", + "description": "Filter a DID-Linked Resource query by Resource Type. See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "CredentialArtwork" + }, + { + "in": "query", + "name": "resourceVersion", + "description": "Filter a DID-Linked Resource query by Resource Version, which is an optional free-text field used by issuers (e.g., \"v1\", \"Final Version\", \"1st January 1970\" etc). See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "v1" + }, + { + "in": "query", + "name": "resourceVersionTime", + "description": "Filter a DID-Linked Resource query which returns the closest version of the Resource *at* or *before* specified time. See DID-Linked Resources for more details.", + "schema": { + "type": "string", + "format": "date-time" + }, + "example": "1970-01-01T00:00:00Z" + }, + { + "in": "query", + "name": "checksum", + "description": "Request integrity check against a given DID-Linked Resource by providing a SHA-256 checksum hash. See DID-Linked Resources for more details.", + "schema": { + "type": "string" + }, + "example": "dc64474d062ed750a66bad58cb609928de55ed0d81defd231a4a4bf97358e9ed" + }, + { + "in": "query", + "name": "resourceMetadata", + "description": "Return only metadata of DID-Linked Resource instead of actual DID-Linked Resource. Mutually exclusive with some of the other parameters.", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "The request was successful.", + "content": { + "any": { + "schema": { + "type": "object" + } + } + } + }, + "400": { + "$ref": "#/components/schemas/InvalidRequest" + }, + "401": { + "$ref": "#/components/schemas/UnauthorizedError" + }, + "500": { + "$ref": "#/components/schemas/InternalError" + } + } + } + } + }, + "components": { + "schemas": { + "AlsoKnownAs": { + "type": "object", + "properties": { + "alsoKnownAs": { + "type": "array", + "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", + "items": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "format": "uri", + "description": "URI where the DID-Linked Resource can be fetched from. Can be any type of URI (e.g., DID, HTTPS, IPFS, etc.)" + }, + "description": { + "type": "string", + "description": "Optional description of the URI." + } + } + } + } + } + }, + "CredentialRequest": { + "description": "Input fields for the creating a Verifiable Credential.", + "type": "object", + "additionalProperties": false, + "properties": { + "issuerDid": { + "description": "DID of the Verifiable Credential issuer. This needs to be a `did:cheqd` DID.", + "type": "string", + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + "subjectDid": { + "description": "DID of the Verifiable Credential holder/subject. This needs to be a `did:key` DID.", + "type": "string", + "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" + }, + "attributes": { + "description": "JSON object containing the attributes to be included in the credential.", + "type": "object", + "example": { + "name": "Bob", + "gender": "male" + } + }, + "@context": { + "description": "Optional properties to be included in the `@context` property of the credential.", + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "https://schema.org/schema.jsonld", + "https://veramo.io/contexts/profile/v1" + ] + }, + "type": { + "description": "Optional properties to be included in the `type` property of the credential.", + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "Person" + ] + }, + "expirationDate": { + "description": "Optional expiration date according to the VC Data Model specification.", + "type": "string", + "format": "date-time", + "example": "2023-06-08T13:49:28.000Z" + }, + "format": { + "description": "Format of the Verifiable Credential. Defaults to VC-JWT.", + "type": "string", + "enum": [ + "jwt", + "jsonld" + ], + "example": "jwt" + }, + "credentialStatus": { + "description": "Optional `credentialStatus` properties for VC revocation or suspension. Takes `statusListName` and `statusListPurpose` as inputs.", + "type": "object", + "required": [ + "statusPurpose", + "statusListName" + ], + "properties": { + "statusPurpose": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ] + }, + "statusListName": { + "type": "string" + }, + "statusListIndex": { + "type": "number" + }, + "statusListVersion": { + "type": "string", + "format": "date-time" + }, + "statusListRangeStart": { + "type": "number" + }, + "statusListRangeEnd": { + "type": "number" + }, + "indexNotIn": { + "type": "number" + } + }, + "example": { + "statusPurpose": "revocation", + "statusListName": "employee-credentials" + } + } + }, + "required": [ + "issuerDid", + "subjectDid", + "attributes" + ], + "example": { + "issuerDid": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "subjectDid": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", + "attributes": { + "gender": "male", + "name": "Bob" + }, + "@context": [ + "https://schema.org" + ], + "type": [ + "Person" + ], + "format": "jwt", + "credentialStatus": { + "statusPurpose": "revocation", + "statusListName": "employee-credentials", + "statusListIndex": 10 + } + } + }, + "Credential": { + "description": "Input fields for revoking/suspending a Verifiable Credential.", + "type": "object", + "additionalProperties": false, + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "https://www.w3.org/2018/credentials/v1", + "https://schema.org", + "https://veramo.io/contexts/profile/v1" + ] + }, + "type": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "VerifiableCredential", + "Person" + ] + }, + "expirationDate": { + "type": "string", + "format": "date-time", + "example": "2023-06-08T13:49:28.000Z" + }, + "issuer": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "DID", + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + } + } + }, + "credentialSubject": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "DID", + "example": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" + } + } + }, + "credentialStatus": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20" + }, + "statusListIndex": { + "type": "number", + "example": 20 + }, + "statusPurpose": { + "type": "string", + "enum": [ + "revocation", + "suspension" + ], + "example": "suspension" + }, + "type": { + "type": "string", + "enum": [ + "StatusList2021Entry" + ] + } + } + }, + "issuanceDate": { + "type": "string", + "format": "date-time", + "example": "2023-06-08T13:49:28.000Z" + }, + "proof": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "jwt": { + "type": "string" + } + }, + "example": { + "type": "JwtProof2020", + "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg" + } + } + }, + "example": { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://schema.org", + "https://veramo.io/contexts/profile/v1" + ], + "credentialSubject": { + "gender": "male", + "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", + "name": "Bob" + }, + "credentialStatus": { + "id": "https://resolver.cheqd.net/1.0/identifiers/did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e?resourceName=cheqd-suspension-1&resourceType=StatusList2021Suspension#20", + "statusIndex": 20, + "statusPurpose": "suspension", + "type": "StatusList2021Entry" + }, + "issuanceDate": "2023-06-08T13:49:28.000Z", + "issuer": { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + "proof": { + "jwt": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkaWQ6Y2hlcWQ6dGVzdG5ldDo3YmY4MWEyMC02MzNjLTRjYzctYmM0YS01YTQ1ODAxMDA1ZTAiLCJuYmYiOjE2ODYyMzIxNjgsInN1YiI6ImRpZDprZXk6ejZNa2hhWGdCWkR2b3REa0w1MjU3ZmFpenRpR2lDMlF0S0xHcGJubkVHdGEyZG9LIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3NjaGVtYS5vcmciLCJodHRwczovL3ZlcmFtby5pby9jb250ZXh0cy9wcm9maWxlL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImdlbmRlciI6Im1hbGUiLCJuYW1lIjoiQm9iIn0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJQZXJzb24iXX19.wMfdR6RtyAZA4eoWya5Aw97wwER2Cm5Guk780Xw8H9fA3sfudIJeLRLboqixpTchqSbYeA7KbuCTAnLgXTD_Cg", + "type": "JwtProof2020" + }, + "type": [ + "VerifiableCredential", + "Person" + ] + } + }, + "CredentialRevokeRequest": { + "type": "object", + "properties": { + "credential": { + "description": "Verifiable Credential to be revoked as a VC-JWT string or a JSON object.", + "oneOf": [ + { + "type": "object" + }, + { + "type": "string" + } + ] + }, + "symmetricKey": { + "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource. Required if the StatusList2021 DID-Linked Resource is encrypted.", + "type": "string" + } + } + }, + "RevocationResult": { + "properties": { + "revoked": { + "type": "boolean", + "example": true + } + } + }, + "SuspensionResult": { + "properties": { + "suspended": { + "type": "boolean", + "example": true + } + } + }, + "UnsuspensionResult": { + "properties": { + "unsuspended": { + "type": "boolean", + "example": true + } + } + }, + "CredentialVerifyRequest": { + "type": "object", + "properties": { + "credential": { + "description": "Verifiable Credential to be verified as a VC-JWT string or a JSON object.", + "type": "object" + }, + "policies": { + "description": "Custom verification policies to execute when verifying credential.", + "type": "object", + "properties": { + "issuanceDate": { + "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "expirationDate": { + "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "audience": { + "description": "Policy to skip the audience check when set to `false`.", + "type": "boolean", + "default": false + } + } + } + } + }, + "VerifyPresentationResult": { + "type": "object", + "properties": { + "verified": { + "type": "boolean" + }, + "issuer": { + "type": "string" + }, + "signer": { + "type": "object" + }, + "jwt": { + "type": "string" + }, + "verifiableCredential": { + "type": "object" + } + } + }, + "VerifyCredentialResult": { + "type": "object", + "properties": { + "verified": { + "type": "boolean" + }, + "issuer": { + "type": "string" + }, + "signer": { + "type": "object" + }, + "jwt": { + "type": "string" + }, + "verifiableCredential": { + "type": "object" + } + }, + "example": { + "verified": true, + "polices": {}, + "issuer": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "signer": { + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", + "type": "Ed25519VerificationKey2018" + } + } + }, + "PresentationCreateRequest": { + "type": "object", + "required": [ + "credentials" + ], + "properties": { + "credentials": { + "description": "Verifiable Credentials to be used for VP-JWT creation as a VP-JWT strings or a JSON objectsf.", + "type": "array", + "items": { + "type": "object" + } + }, + "holderDid": { + "description": "DID of holder", + "type": "string" + }, + "verifierDid": { + "description": "DID of verifier", + "type": "string" + } + } + }, + "PresentationVerifyRequest": { + "type": "object", + "required": [ + "presentation" + ], + "properties": { + "presentation": { + "description": "Verifiable Presentation to be verified as a VP-JWT string or a JSON object.", + "type": "object" + }, + "verifierDid": { + "description": "Provide an optional verifier DID (also known as 'domain' parameter), if the verifier DID in the presentation is not managed in the wallet.", + "type": "string" + }, + "makeFeePayment": { + "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", + "type": "boolean", + "default": false + }, + "policies": { + "description": "Custom verification policies to execute when verifying presentation.", + "type": "object", + "properties": { + "issuanceDate": { + "description": "Policy to skip the `issuanceDate` (`nbf`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "expirationDate": { + "description": "Policy to skip the `expirationDate` (`exp`) timestamp check when set to `false`.", + "type": "boolean", + "default": true + }, + "audience": { + "description": "Policy to skip the audience check when set to `false`.", + "type": "boolean", + "default": false + } + } + } + } + }, + "CredentialStatusCreateBody": { + "allOf": [ + { + "type": "object", + "required": [ + "did", + "statusListName" + ], + "properties": { + "did": { + "description": "DID of the StatusList2021 publisher.", + "type": "string", + "format": "uri" + }, + "statusListName": { + "description": "The name of the StatusList2021 DID-Linked Resource to be created.", + "type": "string" + }, + "length": { + "description": "The length of the status list to be created. The default and minimum length is 140000 which is 16kb.", + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true, + "default": 140000 + }, + "encoding": { + "description": "The encoding format of the StatusList2021 DiD-Linked Resource to be created.", + "type": "string", + "default": "base64url", + "enum": [ + "base64url", + "base64", + "hex" + ] + }, + "statusListVersion": { + "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/AlsoKnownAs" + } + ] + }, + "CredentialStatusCreateUnencryptedRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCreateBody" + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials", + "length": 140000, + "encoding": "base64url" + } + }, + "CredentialStatusUnencryptedResult": { + "type": "object", + "properties": { + "resource": { + "type": "object", + "properties": { + "StatusList2021": { + "type": "object", + "properties": { + "encodedList": { + "type": "string", + "example": "H4sIAAAAAAAAA-3BAQ0AAADCoPdPbQ8HFAAAAAAAAAAAAAAAAAAAAADwaDhDr_xcRAAA" + }, + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "validFrom": { + "type": "string", + "format": "date-time", + "example": "2023-06-26T11:45:19.349Z" + } + } + }, + "metadata": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "encoding": { + "type": "string", + "example": "base64url" + }, + "encrypted": { + "type": "boolean", + "example": false + } + } + } + } + }, + "resourceMetadata": { + "type": "object", + "example": { + "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceName": "cheqd-employee-credentials", + "resourceType": "StatusList2021Revocation", + "mediaType": "application/json", + "resourceVersion": "1.0.0", + "created": "2023-06-26T11:45:20Z", + "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", + "previousVersionId": null, + "nextVersionId": null + } + } + } + }, + "CredentialStatusCreateUnencryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "created": { + "type": "boolean", + "example": true + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" + } + ] + }, + "CredentialStatusEncryptedPaymentConditionsBody": { + "type": "object", + "properties": { + "feePaymentAddress": { + "description": "The cheqd/Cosmos payment address where payments to unlock the encrypted StatusList2021 DID-Linked Resource need to be sent.", + "type": "string", + "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" + }, + "feePaymentAmount": { + "description": "Amount in CHEQ tokens to unlock the encrypted StatusList2021 DID-Linked Resource.", + "type": "number", + "minimum": 0, + "exclusiveMinimum": true, + "default": 20 + }, + "feePaymentWindow": { + "description": "Time window (in minutes) within which the payment to unlock the encrypted StatusList2021 DID-Linked Resource is considered valid.", + "type": "number", + "minimum": 0, + "exclusiveMinimum": true, + "default": 10 + } + } + }, + "CredentialStatusEncryptedPaymentConditionsJson": { + "type": "object", + "properties": { + "paymentConditions": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" + } + ] + } + } + }, + "CredentialStatusCreateEncryptedFormRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCreateBody" + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" + }, + { + "type": "object", + "required": [ + "feePaymentAddress", + "feePaymentAmount", + "feePaymentWindow" + ] + } + ] + }, + "CredentialStatusCreateEncryptedJsonRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCreateBody" + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" + }, + { + "type": "object", + "required": [ + "paymentConditions" + ] + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials-encrypted", + "paymentConditions": [ + { + "feePaymentAddress": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg", + "feePaymentAmount": 20, + "feePaymentWindow": 10 + } + ] + } + }, + "CredentialStatusEncryptedResult": { + "type": "object", + "properties": { + "resource": { + "type": "object", + "properties": { + "StatusList2021": { + "type": "object", + "properties": { + "encodedList": { + "type": "string", + "example": "496fdfbeb745b4db03fcdb40566f9c4c4a1c0f184b31255e641b6e7bdfb9b6946c12be87ca3763be0393c00b67ac1e8737c106b32f46ef59c765754415b5e8cc7c65fccaa3374620430ea476301a5e0dd63340e7a27a68bc627518471f22e4a2" + }, + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "validFrom": { + "type": "string", + "format": "date-time", + "example": "2023-06-26T11:45:19.349Z" + } + } + }, + "metadata": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "StatusList2021Revocation" + }, + "encoding": { + "type": "string", + "example": "base64url" + }, + "encrypted": { + "type": "boolean", + "example": true + }, + "encryptedSymmetricKey": { + "type": "string", + "example": "b11182dc524b8181f9a6aef4c4ad0a1c14e40033b9112dffd8d1bcf6cc3b85abc07ded2205ee94068a99f4202502cb0855f322583fa6ce1534d3a05bf36891766ea2c5f90a982b3040680762977d404d758a2370224a239c8279aa7d21e980931c42055b17ca4c7dbffa4782480a8b6279cf989b2f166d5fdb4b2c1b5a63927200000000000000203018dcaba26df45a415bb599218b27ca853a70289d7a3ed3ed0e3730452e8f8d9af91b6e71312565d2c069341f6660ab" + }, + "paymentConditions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "feePaymentAddress": { + "type": "string", + "example": "cheqd1qs0nhyk868c246defezhz5eymlt0dmajna2csg" + }, + "feePaymentAmount": { + "type": "string", + "example": "20000000000ncheq" + }, + "intervalInSeconds": { + "type": "number", + "example": 600 + }, + "type": { + "type": "string", + "example": "timelockPayment" + } + } + } + } + } + }, + "resourceMetadata": { + "type": "object", + "example": { + "resourceURI": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e/resources/5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceCollectionId": "7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "resourceId": "5945233a-a4b5-422b-b893-eaed5cedd2dc", + "resourceName": "cheqd-revocation-encrypted-1", + "resourceType": "StatusList2021Revocation", + "mediaType": "application/json", + "resourceVersion": "2023-06-26T11:45:19.349Z", + "created": "2023-06-26T11:45:20Z", + "checksum": "909e22e371a41afbb96c330a97752cf7c8856088f1f937f87decbef06cbe9ca2", + "previousVersionId": null, + "nextVersionId": null + } + }, + "symmetricKey": { + "type": "string", + "example": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" + } + } + } + } + }, + "CredentialStatusCreateEncryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "created": { + "type": "boolean", + "example": true + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedResult" + } + ] + }, + "CredentialStatusUpdateBody": { + "type": "object", + "required": [ + "did", + "statusListName", + "indices" + ], + "properties": { + "did": { + "description": "DID of the StatusList2021 publisher.", + "type": "string", + "format": "uri" + }, + "statusListName": { + "description": "The name of the StatusList2021 DID-Linked Resource to be updated.", + "type": "string" + }, + "indices": { + "description": "List of credential status indices to be updated. The indices must be in the range of the status list.", + "type": "array", + "items": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": false + } + }, + "statusListVersion": { + "description": "Optional field to assign a human-readable version in the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + "CredentialStatusUpdateUnencryptedRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUpdateBody" + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials", + "indices": [ + 10, + 3199, + 12109, + 130999 + ] + } + }, + "CredentialStatusUpdateUnencryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "updated": { + "type": "boolean", + "example": true + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/RevocationResult" + }, + { + "$ref": "#/components/schemas/SuspensionResult" + }, + { + "$ref": "#/components/schemas/UnsuspensionResult" + } + ] + }, + { + "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" + } + ] + }, + "CredentialStatusUpdateEncryptedFormRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUpdateBody" + }, + { + "type": "object", + "required": [ + "symmetricKey" + ], + "properties": { + "symmetricKey": { + "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsBody" + } + ] + }, + "CredentialStatusUpdateEncryptedJsonRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUpdateBody" + }, + { + "type": "object", + "required": [ + "symmetricKey" + ], + "properties": { + "symmetricKey": { + "description": "The symmetric key used to encrypt the StatusList2021 DID-Linked Resource.", + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedPaymentConditionsJson" + } + ], + "example": { + "did": "did:cheqd:testnet:7c2b990c-3d05-4ebf-91af-f4f4d0091d2e", + "statusListName": "cheqd-employee-credentials-encrypted", + "indices": [ + 10, + 3199, + 12109, + 130999 + ], + "symmetricKey": "dfe204ee95ae74ea5d74b94c3d8ff782273905b07fbc9f8c3d961c3b43849f18" + } + }, + "CredentialStatusUpdateEncryptedResult": { + "allOf": [ + { + "type": "object", + "properties": { + "updated": { + "type": "boolean", + "example": true + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/RevocationResult" + }, + { + "$ref": "#/components/schemas/SuspensionResult" + }, + { + "$ref": "#/components/schemas/UnsuspensionResult" + } + ] + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedResult" + } + ] + }, + "CredentialStatusCheckRequest": { + "type": "object", + "required": [ + "did", + "statusListName", + "index" + ], + "properties": { + "did": { + "description": "DID of the StatusList2021 publisher.", + "type": "string", + "format": "uri" + }, + "statusListName": { + "description": "The name of the StatusList2021 DID-Linked Resource to be checked.", + "type": "string" + }, + "index": { + "description": "Credential status index to be checked for revocation or suspension.", + "type": "integer", + "minimum": 0, + "exclusiveMinimum": false + }, + "makeFeePayment": { + "description": "Automatically make fee payment (if required) based on payment conditions to unlock encrypted StatusList2021 DID-Linked Resource.", + "type": "boolean", + "default": true + } + } + }, + "CredentialStatusCheckResult": { + "oneOf": [ + { + "$ref": "#/components/schemas/CredentialStatusCheckRevocationResult" + }, + { + "$ref": "#/components/schemas/CredentialStatusCheckSuspensionResult" + } + ] + }, + "CredentialStatusCheckRevocationResult": { + "type": "object", + "properties": { + "checked": { + "type": "boolean", + "example": true + }, + "revoked": { + "type": "boolean", + "example": false + } + } + }, + "CredentialStatusCheckSuspensionResult": { + "type": "object", + "properties": { + "checked": { + "type": "boolean", + "example": true + }, + "suspended": { + "type": "boolean", + "example": false + } + } + }, + "CredentialStatusListSearchResult": { + "allOf": [ + { + "type": "object", + "properties": { + "found": { + "type": "boolean", + "example": true + } + } + }, + { + "oneOf": [ + { + "$ref": "#/components/schemas/CredentialStatusUnencryptedResult" + }, + { + "$ref": "#/components/schemas/CredentialStatusEncryptedResult" + } + ] + } + ] + }, + "KeyImportRequest": { + "type": "object", + "properties": { + "alias": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "Ed25519", + "Secp256k1" + ] + }, + "privateKeyHex": { + "type": "string" + } + } + }, + "KeyResult": { + "type": "object", + "properties": { + "kid": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "Ed25519", + "Secp256k1" + ] + }, + "publicKeyHex": { + "type": "string" + } + } + }, + "DidDocument": { + "description": "This input field contains either a complete DID document, or an incremental change (diff) to a DID document. See Universal DID Registrar specification.", + "type": "object", + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "controllers": { + "type": "array", + "items": { + "type": "string" + } + }, + "verificationMethod": { + "type": "array", + "items": { + "$ref": "#/components/schemas/VerificationMethod" + } + }, + "service": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "authentication": { + "type": "array", + "items": { + "type": "string" + } + }, + "assertionMethod": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityInvocation": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityDelegation": { + "type": "array", + "items": { + "type": "string" + } + }, + "keyAgreement": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "@context": [ + "https://www.w3.org/ns/did/v1" + ], + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "controller": [ + "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + ], + "verificationMethod": [ + { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "type": "Ed25519VerificationKey2018", + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "publicKeyBase58": "z6MkkVbyHJLLjdjU5B62DaJ4mkdMdUkttf9UqySSkA9bVTeZ" + } + ], + "authentication": [ + "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1" + ], + "service": [ + { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", + "type": "LinkedDomains", + "serviceEndpoint": [ + "https://example.com" + ] + } + ] + } + }, + "DidDocumentWithoutVerificationMethod": { + "type": "object", + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "controllers": { + "type": "array", + "items": { + "type": "string" + } + }, + "service": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "authentication": { + "type": "array", + "items": { + "type": "string" + } + }, + "assertionMethod": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityInvocation": { + "type": "array", + "items": { + "type": "string" + } + }, + "capabilityDelegation": { + "type": "array", + "items": { + "type": "string" + } + }, + "keyAgreement": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "@context": [ + "https://www.w3.org/ns/did/v1" + ], + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "controller": [ + "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + ], + "authentication": [ + "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1" + ], + "service": [ + { + "id": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1", + "type": "LinkedDomains", + "serviceEndpoint": [ + "https://example.com" + ] + } + ] + } + }, + "DidCreateRequestFormBased": { + "type": "object", + "properties": { + "network": { + "description": "Network to create the DID on (testnet or mainnet)", + "type": "string", + "enum": [ + "testnet", + "mainnet" + ] + }, + "identifierFormatType": { + "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", + "type": "string", + "enum": [ + "uuid", + "base58btc" + ] + }, + "verificationMethodType": { + "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", + "type": "string", + "enum": [ + "Ed25519VerificationKey2018", + "JsonWebKey2020", + "Ed25519VerificationKey2020" + ] + }, + "service": { + "description": "It's a list of special objects which are designed to build the actual service. It's almost the same as in DID Core specification, but instead of `id` it utilises `idFragment` field for making the right `id` for each service. !!! WARN. Cause swagger-ui does not handle x-ww-form based arrays correctly, please frame all your services in brackets while using swagger UI. !!!", + "type": "array", + "items": { + "type": "object", + "properties": { + "idFragment": { + "type": "string" + }, + "type": { + "type": "string" + }, + "serviceEndpoint": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "example": [ + { + "idFragment": "service-1", + "type": "LinkedDomains", + "serviceEndpoint": [ + "https://example.com" + ] + } + ] + }, + "key": { + "description": "The unique identifier in hexadecimal public key format used in the verification method to create the DID.", + "type": "string" + }, + "@context": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "https://www.w3.org/ns/did/v1" + ] + } + } + }, + "DidCreateRequestJson": { + "type": "object", + "properties": { + "network": { + "description": "Network to create the DID on (testnet or mainnet)", + "type": "string", + "enum": [ + "testnet", + "mainnet" + ] + }, + "identifierFormatType": { + "description": "Algorithm to use for generating the method-specific ID. The two styles supported are UUIDs and Indy-style Base58. See cheqd DID method documentation for more details.", + "type": "string", + "enum": [ + "uuid", + "base58btc" + ] + }, + "assertionMethod": { + "description": "Usually a reference to a Verification Method. An Assertion Method is required to issue JSON-LD credentials. See DID Core specification for more details.", + "type": "boolean", + "default": true + }, + "options": { + "type": "object", + "properties": { + "key": { + "type": "string", + "example": "8255ddadd75695e01f3d98fcec8ccc7861a030b317d4326b0e48a4d579ddc43a" + }, + "verificationMethodType": { + "description": "Type of verification method to use for the DID. See DID Core specification for more details. Only the types listed below are supported.", + "type": "string", + "enum": [ + "Ed25519VerificationKey2018", + "JsonWebKey2020", + "Ed25519VerificationKey2020" + ] + } + } + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocumentWithoutVerificationMethod" + } + } + }, + "DidImportRequest": { + "type": "object", + "properties": { + "did": { + "type": "string", + "description": "DID to be imported", + "format": "uri", + "required": true + }, + "keys": { + "type": "array", + "description": "List of keys required to import the DID", + "required": true, + "items": { + "$ref": "#/components/schemas/KeyImportRequest" + } + } + } + }, + "PresentationCreateResult": { + "type": "object", + "properties": { + "vp": { + "type": "object", + "description": "Verifiable Presentation which could be provided to the verifier." + }, + "nbf": { + "type": "integer", + "description": "Unix timestamp of the earliest time that the Verifiable Presentation is valid." + }, + "iss": { + "type": "string", + "description": "DID of the issuer of the Verifiable Presentation. (Here it's supposed to be a holder DID)" + }, + "aud": { + "type": "array", + "items": { + "type": "string" + }, + "description": "DID of the verifier of the Verifiable Presentation." + } + }, + "example": { + "vp": { + "@context": [ + "https://www.w3.org/2018/credentials/v1" + ], + "type": [ + "VerifiablePresentation" + ], + "verifiableCredential": [ + "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vc2NoZW1hLm9yZy9zY2hlbWEuanNvbmxkIiwiaHR0cHM6Ly92ZXJhbW8uaW8vY29udGV4dHMvcHJvZmlsZS92MSIsImh0dHBzOi8vdzNpZC5vcmcvdmMtc3RhdHVzLWxpc3QtMjAyMS92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiUGVyc29uIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7Im5hbWUiOiJCb2IiLCJnZW5kZXIiOiJtYWxlIn0sImNyZWRlbnRpYWxTdGF0dXMiOnsiaWQiOiJodHRwczovL3Jlc29sdmVyLmNoZXFkLm5ldC8xLjAvaWRlbnRpZmllcnMvZGlkOmNoZXFkOnRlc3RuZXQ6OTBkNWMxNDEtNzI0Zi00N2FkLTlhZTctYTdjMzNhOWU1NjQzP3Jlc291cmNlTmFtZT1zdXNwZW5zaW9uRW4mcmVzb3VyY2VUeXBlPVN0YXR1c0xpc3QyMDIxU3VzcGVuc2lvbiMxMzMzOCIsInR5cGUiOiJTdGF0dXNMaXN0MjAyMUVudHJ5Iiwic3RhdHVzUHVycG9zZSI6InN1c3BlbnNpb24iLCJzdGF0dXNMaXN0SW5kZXgiOiIxMzMzOCJ9fSwic3ViIjoiZGlkOmtleTp6Nk1raGFYZ0JaRHZvdERrTDUyNTdmYWl6dGlHaUMyUXRLTEdwYm5uRUd0YTJkb0siLCJuYmYiOjE3MDA0NzM0MTYsImlzcyI6ImRpZDpjaGVxZDp0ZXN0bmV0OjkwZDVjMTQxLTcyNGYtNDdhZC05YWU3LWE3YzMzYTllNTY0MyJ9.-14Ril1pZEy2HEEo48gTJr2yOtGxBhUGTFmzVdjAtyhFRsW5zZg9onHt6V9JQ8BaiYBlTkP9GzTnJ-O6hdiyCw" + ] + }, + "nbf": 1700744275, + "iss": "did:cheqd:testnet:4b846d0f-2f6c-4ab6-9fe2-5b8db301c83c", + "aud": [ + "did:cheqd:testnet:8c71e9b6-c5a3-4250-8c58-fa591533cd22" + ] + } + }, + "DidResult": { + "type": "object", + "properties": { + "did": { + "type": "string" + }, + "controllerKeyId": { + "type": "string" + }, + "keys": { + "type": "array", + "items": { + "type": "object" + } + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + } + } + }, + "DidUpdateResponse": { + "type": "object", + "properties": { + "did": { + "type": "string" + }, + "controllerKeyId": { + "type": "string", + "description": "The default key id of which is the key associated with the first verificationMethod" + }, + "keys": { + "type": "array", + "description": "The list of keys associated with the list of verificationMethod's of DIDDocument", + "items": { + "type": "object" + } + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "controllerKeyRefs": { + "type": "array", + "description": "The list of keyRefs which were used for signing the transaction", + "items": { + "type": "string" + } + }, + "controllerKeys": { + "type": "array", + "description": "The list of all possible keys, inlcuding all controller's keys", + "items": { + "type": "string" + } + } + } + }, + "VerificationMethod": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + }, + "controller": { + "type": "string" + }, + "publicKeyMultibase": { + "type": "string" + }, + "publicKeyJwk": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "controller": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0", + "id": "did:cheqd:testnet :7bf81a20-633c-4cc7-bc4a-5a45801005e0#key-1", + "publicKeyBase58": "BTJiso1S4iSiReP6wGksSneGfiKHxz9SYcm2KknpqBJt", + "type": "Ed25519VerificationKey2018" + } + }, + "Service": { + "description": "Communicating or interacting with the DID subject or associated entities via one or more service endpoints. See DID Core specification for more details.", + "type": "object", + "properties": { + "id": { + "description": "DID appended with Service fragment ID (e.g., `#service-1` in `did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1`)", + "type": "string", + "example": "did:cheqd:mainnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0#service-1" + }, + "type": { + "description": "Service type as defined in DID Specification Registries.", + "type": "string", + "example": "LinkedDomains" + }, + "serviceEndpoint": { + "description": "Service endpoint as defined in DID Core Specification.", + "type": "array", + "items": { + "type": "string", + "example": "https://example.com" + } + } + } + }, + "DidUpdateRequest": { + "type": "object", + "properties": { + "did": { + "description": "DID identifier to be updated.", + "type": "string", + "example": "did:cheqd:testnet:7bf81a20-633c-4cc7-bc4a-5a45801005e0" + }, + "service": { + "type": "array", + "description": "Service section of the DID Document.", + "items": { + "$ref": "#/components/schemas/Service" + } + }, + "verificationMethod": { + "type": "array", + "description": "Verification Method section of the DID Document.", + "items": { + "$ref": "#/components/schemas/VerificationMethod" + } + }, + "authentication": { + "description": "Authentication section of the DID Document.", + "type": "array", + "items": { + "type": "string" + } + }, + "publicKeyHexs": { + "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", + "type": "array", + "items": { + "type": "string" + } + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + } + } + }, + "DidDeactivateRequest": { + "type": "object", + "properties": { + "publicKeyHexs": { + "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "CreateResourceRequest": { + "description": "Input fields for DID-Linked Resource creation.", + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "type", + "data", + "encoding" + ], + "properties": { + "data": { + "description": "Encoded string containing the data to be stored in the DID-Linked Resource.", + "type": "string" + }, + "encoding": { + "description": "Encoding format used to encode the data.", + "type": "string", + "enum": [ + "base64url", + "base64", + "hex" + ] + }, + "name": { + "description": "Name of DID-Linked Resource.", + "type": "string" + }, + "type": { + "description": "Type of DID-Linked Resource. This is NOT the same as the media type, which is calculated automatically ledger-side.", + "type": "string" + }, + "alsoKnownAs": { + "description": "Optional field to assign a set of alternative URIs where the DID-Linked Resource can be fetched from.", + "type": "array", + "items": { + "type": "object", + "properties": { + "uri": { + "type": "string" + }, + "description": { + "type": "string" + } + } + } + }, + "version": { + "description": "Optional field to assign a human-readable version in the DID-Linked Resource.", + "type": "string" + }, + "publicKeyHexs": { + "description": "List of key references (publicKeys) which will be used for signing the message. The should be in hexadecimal format and placed in the wallet of current user.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "example": { + "data": "SGVsbG8gV29ybGQ=", + "encoding": "base64url", + "name": "ResourceName", + "type": "TextDocument" + } + }, + "ResourceList": { + "type": "object", + "properties": { + "@context": { + "type": "string", + "example": "https://w3id.org/did-resolution/v1" + }, + "contentMetadata": { + "type": "object" + }, + "contentStream": { + "type": "object" + }, + "dereferencingMetadata": { + "$ref": "#/components/schemas/DereferencingMetadata" + } + } + }, + "DereferencingMetadata": { + "type": "object", + "properties": { + "contentType": { + "type": "string", + "example": "application/did+ld+json" + }, + "did": { + "$ref": "#/components/schemas/DidProperties" + }, + "retrieved": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + } + } + }, + "DidResolution": { + "type": "object", + "properties": { + "@context": { + "type": "string", + "example": "https://w3id.org/did-resolution/v1" + }, + "didDidResolutionMetadata": { + "$ref": "#/components/schemas/DidResolutionMetadata" + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + }, + "didDocumentMetadata": { + "$ref": "#/components/schemas/DidDocumentMetadata" + } + } + }, + "DeactivatedDidResolution": { + "type": "object", + "properties": { + "@context": { + "type": "string", + "example": "https://w3id.org/did-resolution/v1" + }, + "didDidResolutionMetadata": { + "$ref": "#/components/schemas/DidResolutionMetadata" + }, + "didDocument": { + "$ref": "#/components/schemas/DidDocument" + }, + "didDocumentMetadata": { + "$ref": "#/components/schemas/DeactivatedDidDocumentMetadata" + } + } + }, + "DidDocumentMetadata": { + "type": "object", + "properties": { + "created": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "deactivated": { + "type": "boolean", + "example": false + }, + "updated": { + "type": "string", + "example": "2021-09-10T12:00:00Z" + }, + "versionId": { + "type": "string", + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + "linkedResourceMetadata": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ResourceMetadata" + } + } + } + }, + "DeactivatedDidDocumentMetadata": { + "type": "object", + "properties": { + "created": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "deactivated": { + "type": "boolean", + "example": true + }, + "updated": { + "type": "string", + "example": "2021-09-10T12:00:00Z" + }, + "versionId": { + "type": "string", + "example": "3ccde6ba-6ba5-56f2-9f4f-8825561a9860" + }, + "linkedResourceMetadata": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ResourceMetadata" + } + } + } + }, + "ResourceMetadata": { + "type": "object", + "properties": { + "resourceURI": { + "type": "string", + "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47/resources/398cee0a-efac-4643-9f4c-74c48c72a14b" + }, + "resourceCollectionId": { + "type": "string", + "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" + }, + "resourceId": { + "type": "string", + "example": "398cee0a-efac-4643-9f4c-74c48c72a14b" + }, + "resourceName": { + "type": "string", + "example": "cheqd-issuer-logo" + }, + "resourceType": { + "type": "string", + "example": "CredentialArtwork" + }, + "mediaType": { + "type": "string", + "example": "image/png" + }, + "resourceVersion": { + "type": "string", + "example": "1.0" + }, + "checksum": { + "type": "string", + "example": "a95380f460e63ad939541a57aecbfd795fcd37c6d78ee86c885340e33a91b559" + }, + "created": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "nextVersionId": { + "type": "string", + "example": "d4829ac7-4566-478c-a408-b44767eddadc" + }, + "previousVersionId": { + "type": "string", + "example": "ad7a8442-3531-46eb-a024-53953ec6e4ff" + } + } + }, + "DidResolutionMetadata": { + "type": "object", + "properties": { + "contentType": { + "allOf": [ + { + "$ref": "#/components/schemas/ContentType" + } + ], + "example": "application/did+ld+json" + }, + "retrieved": { + "type": "string", + "example": "2021-09-01T12:00:00Z" + }, + "did": { + "$ref": "#/components/schemas/DidProperties" + } + } + }, + "ContentType": { + "type": "string", + "enum": [ + "application/did+json", + "application/did+ld+json", + "application/ld+json", + "application/json" + ] + }, + "DidProperties": { + "type": "object", + "properties": { + "didString": { + "type": "string", + "example": "did:cheqd:testnet:55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" + }, + "method": { + "type": "string", + "example": "cheqd" + }, + "methodSpecificId": { + "type": "string", + "example": "55dbc8bf-fba3-4117-855c-1e0dc1d3bb47" + } + } + }, + "Customer": { + "type": "object", + "properties": { + "customerId": { + "type": "string", + "example": "6w5drpiiwhhs" + }, + "address": { + "type": "string", + "example": "cheqd1wgsvqwlkmdp60f4dek26ak0sjw6au3ytd3pz7f" + } + } + }, + "AccountCreateRequest": { + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": { + "primaryEmail": { + "type": "string" + } + } + } + } + }, + "InvalidRequest": { + "description": "A problem with the input fields has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "InvalidRequest" + } + } + }, + "InternalError": { + "description": "An internal error has occurred. Additional state information plus metadata may be available in the response body.", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Internal Error" + } + } + }, + "UnauthorizedError": { + "description": "Access token is missing or invalid", + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Unauthorized Error" + } + } + } + } + } +} \ No newline at end of file From ef9744fb0c86eb798f84edf903aff4dfa0710a8e Mon Sep 17 00:00:00 2001 From: Ankur Banerjee Date: Wed, 17 Apr 2024 11:40:27 +0100 Subject: [PATCH 35/40] Update .prettierignore --- .prettierignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.prettierignore b/.prettierignore index f4743431..313ee4f3 100644 --- a/.prettierignore +++ b/.prettierignore @@ -16,4 +16,5 @@ yarn.lock **/tsconfig.json # Ignore generated files -src/static/swagger.json +src/static/swagger-api.json +src/static/swagger-admin.json From 5458219d02cad260b091c411879412483de76b54 Mon Sep 17 00:00:00 2001 From: Ankur Banerjee Date: Wed, 17 Apr 2024 11:55:15 +0100 Subject: [PATCH 36/40] Rename API_SECRET_KEY_LENGTH to API_KEY_LENGTH --- src/services/admin/api-key.ts | 4 ++-- src/types/constants.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/services/admin/api-key.ts b/src/services/admin/api-key.ts index adc843b7..4ded59a5 100644 --- a/src/services/admin/api-key.ts +++ b/src/services/admin/api-key.ts @@ -9,7 +9,7 @@ import type { CustomerEntity } from '../../database/entities/customer.entity.js' import { APIKeyEntity } from '../../database/entities/api.key.entity.js'; import type { UserEntity } from '../../database/entities/user.entity.js'; import { SecretBox } from '@veramo/kms-local'; -import { API_SECRET_KEY_LENGTH, API_KEY_PREFIX, API_KEY_EXPIRATION } from '../../types/constants.js'; +import { API_KEY_LENGTH, API_KEY_PREFIX, API_KEY_EXPIRATION } from '../../types/constants.js'; import type { APIServiceOptions } from '../../types/portal.js'; dotenv.config(); @@ -170,7 +170,7 @@ export class APIKeyService { // Utils public static generateAPIKey(userId: string): string { - const apiKey = createHmac('sha512', randomBytes(API_SECRET_KEY_LENGTH)).update(userId).digest('hex'); + const apiKey = createHmac('sha512', randomBytes(API_KEY_LENGTH)).update(userId).digest('hex'); return `${API_KEY_PREFIX}_${apiKey}`; } diff --git a/src/types/constants.ts b/src/types/constants.ts index 34c30e24..1a6fa86a 100644 --- a/src/types/constants.ts +++ b/src/types/constants.ts @@ -12,7 +12,7 @@ export const HEADERS = { export const APPLICATION_BASE_URL = process.env.APPLICATION_BASE_URL || 'http://localhost:3000'; export const CORS_ALLOWED_ORIGINS = process.env.CORS_ALLOWED_ORIGINS || APPLICATION_BASE_URL; export const API_KEY_PREFIX = 'caas'; -export const API_SECRET_KEY_LENGTH = 64; +export const API_KEY_LENGTH = 64; export const API_KEY_EXPIRATION = 30; // By default we don't send events to datadog export const ENABLE_DATADOG = process.env.ENABLE_DATADOG === 'true' ? true : false; From b0bae7484951e7f433c76e66a8343f4d839367b4 Mon Sep 17 00:00:00 2001 From: Ankur Banerjee Date: Wed, 17 Apr 2024 12:10:06 +0100 Subject: [PATCH 37/40] Update text --- src/controllers/admin/api-key.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/admin/api-key.ts b/src/controllers/admin/api-key.ts index 3786cc55..ec227700 100644 --- a/src/controllers/admin/api-key.ts +++ b/src/controllers/admin/api-key.ts @@ -199,7 +199,7 @@ export class APIKeyController { ); if (!apiKeyEntity) { return response.status(StatusCodes.NOT_FOUND).json({ - error: "Cannot update API key cause it's not found", + error: "Update failed: API key does not exist", } satisfies APIKeyUpdateUnsuccessfulResponseBody); } From 5be29b56ea4b8138920c694385a9332a28b17b4f Mon Sep 17 00:00:00 2001 From: Ankur Banerjee Date: Wed, 17 Apr 2024 12:13:59 +0100 Subject: [PATCH 38/40] npm update --- package-lock.json | 6018 +++++++++++++++++++++++++-------------------- package.json | 42 +- 2 files changed, 3358 insertions(+), 2702 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7006beb7..181259f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,20 +1,20 @@ { "name": "@cheqd/credential-service", - "version": "2.19.1-develop.1", + "version": "2.20.0-develop.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@cheqd/credential-service", - "version": "2.19.1-develop.1", + "version": "2.20.0-develop.2", "license": "Apache-2.0", "dependencies": { "@cheqd/did-provider-cheqd": "^4.1.0", "@cheqd/sdk": "^4.0.0", "@cheqd/ts-proto": "^3.4.1", - "@cosmjs/amino": "^0.32.2", - "@cosmjs/encoding": "^0.32.2", - "@logto/express": "^2.3.0", + "@cosmjs/amino": "^0.32.3", + "@cosmjs/encoding": "^0.32.3", + "@logto/express": "^2.3.8", "@stablelib/ed25519": "^1.0.3", "@veramo/core": "^5.6.0", "@veramo/credential-ld": "^5.6.0", @@ -26,11 +26,11 @@ "@veramo/key-manager": "^5.6.0", "@veramo/kms-local": "^5.6.0", "@veramo/utils": "^5.6.0", - "@verida/account-node": "^3.0.1", - "@verida/client-ts": "^3.0.2", + "@verida/account-node": "^3.0.2", + "@verida/client-ts": "^3.0.3", "@verida/encryption-utils": "^3.0.0", - "@verida/types": "^3.0.0", - "@verida/vda-did-resolver": "^3.0.1", + "@verida/types": "^3.0.1", + "@verida/vda-did-resolver": "^3.0.2", "bcrypt": "^5.1.1", "bs58": "^5.0.0", "cookie-parser": "^1.4.6", @@ -38,7 +38,7 @@ "cors": "^2.8.5", "cross-env": "^7.0.3", "did-resolver": "^4.1.0", - "dotenv": "^16.4.1", + "dotenv": "^16.4.5", "express": "^4.19.2", "express-session": "^1.18.0", "express-validator": "^7.0.1", @@ -51,15 +51,15 @@ "loglevel": "^1.9.1", "multiformats": "^13.1.0", "node-cache": "^5.1.2", - "pg": "^8.11.3", - "pg-connection-string": "^2.6.2", + "pg": "^8.11.5", + "pg-connection-string": "^2.6.4", "secp256k1": "^5.0.0", "sqlite3": "^5.1.7", - "stripe": "^14.18.0", + "stripe": "^14.25.0", "swagger-ui-dist": "5.10.5", "swagger-ui-express": "^5.0.0", "typeorm": "^0.3.20", - "uint8arrays": "^5.0.2", + "uint8arrays": "^5.0.3", "uri-js": "^4.4.1" }, "devDependencies": { @@ -68,24 +68,24 @@ "@semantic-release/commit-analyzer": "^11.1.0", "@semantic-release/git": "^10.0.1", "@semantic-release/github": "^9.2.6", - "@semantic-release/npm": "^11.0.2", + "@semantic-release/npm": "^11.0.3", "@semantic-release/release-notes-generator": "^12.1.0", "@types/bcrypt": "^5.0.2", "@types/bs58": "^4.0.4", - "@types/cookie-parser": "^1.4.6", + "@types/cookie-parser": "^1.4.7", "@types/cors": "^2.8.17", "@types/debug": "^4.1.12", "@types/express": "^4.17.21", "@types/express-session": "^1.18.0", "@types/helmet": "^4.0.0", "@types/json-stringify-safe": "^5.0.3", - "@types/jsonwebtoken": "^9.0.5", - "@types/node": "^20.11.15", + "@types/jsonwebtoken": "^9.0.6", + "@types/node": "^20.12.7", "@types/secp256k1": "^4.0.6", "@types/swagger-jsdoc": "^6.0.4", "@types/swagger-ui-express": "^4.1.6", "@types/uuid": "^9.0.8", - "@types/validator": "^13.11.8", + "@types/validator": "^13.11.9", "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.62.0", "buffer": "6.0.3", @@ -94,14 +94,14 @@ "eslint-config-prettier": "^9.1.0", "eslint-config-typescript": "^3.0.0", "jest": "^29.7.0", - "prettier": "^3.2.4", - "semantic-release": "^23.0.0", + "prettier": "^3.2.5", + "semantic-release": "^23.0.8", "swagger-jsdoc": "^6.2.8", "ts-jest": "^29.1.2", "ts-loader": "^9.5.1", "ts-node": "^10.9.2", - "typescript": "^5.3.3", - "uint8arrays": "^5.0.2" + "typescript": "^5.4.5", + "uint8arrays": "^5.0.3" }, "engines": { "node": ">=20.0.0" @@ -117,17 +117,17 @@ } }, "node_modules/@adraffy/ens-normalize": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz", - "integrity": "sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==" + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", + "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==" }, "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -212,104 +212,40 @@ "integrity": "sha512-HazVq9zwTVwGmqdwYzu7WyQ6FQVZ7SwET0KKQuKm55jD0IfUpZgN0OPIiZG3zV1iSrVYcN0bdwLRXI/VNCYsUA==" }, "node_modules/@babel/code-frame": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/code-frame/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/code-frame/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/compat-data": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", - "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", + "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", - "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz", + "integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.4", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.9", - "@babel/parser": "^7.23.9", - "@babel/template": "^7.23.9", - "@babel/traverse": "^7.23.9", - "@babel/types": "^7.23.9", + "@babel/helpers": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -333,13 +269,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", - "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", + "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", "dependencies": { - "@babel/types": "^7.23.6", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" }, "engines": { @@ -409,9 +345,9 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.23.10", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.10.tgz", - "integrity": "sha512-2XpP2XhkXzgxecPNEEK8Vz8Asj9aRxt08oKOqtiZoqV2UGZ5T+EkyP9sXQ9nwMxBIG34a7jmasVqoMop7VdPUw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.4.tgz", + "integrity": "sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ==", "optional": true, "peer": true, "dependencies": { @@ -420,7 +356,7 @@ "@babel/helper-function-name": "^7.23.0", "@babel/helper-member-expression-to-functions": "^7.23.0", "@babel/helper-optimise-call-expression": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-replace-supers": "^7.24.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", "semver": "^6.3.1" @@ -471,9 +407,9 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", - "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.1.tgz", + "integrity": "sha512-o7SDgTJuvx5vLKD6SFvkydkSMBvahDKGiNJzG22IZYXhiqoe9efY7zocICBgzHV4IRg5wdgl2nEL/tulKIEIbA==", "optional": true, "peer": true, "dependencies": { @@ -532,11 +468,11 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", "dependencies": { - "@babel/types": "^7.22.15" + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -574,9 +510,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", + "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", "engines": { "node": ">=6.9.0" } @@ -600,14 +536,14 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", - "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz", + "integrity": "sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==", "optional": true, "peer": true, "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-member-expression-to-functions": "^7.23.0", "@babel/helper-optimise-call-expression": "^7.22.5" }, "engines": { @@ -653,9 +589,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", "engines": { "node": ">=6.9.0" } @@ -692,26 +628,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.9.tgz", - "integrity": "sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz", + "integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==", "dependencies": { - "@babel/template": "^7.23.9", - "@babel/traverse": "^7.23.9", - "@babel/types": "^7.23.9" + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" @@ -782,9 +719,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz", - "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", + "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", "bin": { "parser": "bin/babel-parser.js" }, @@ -792,14 +729,31 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.4.tgz", + "integrity": "sha512-qpl6vOOEEzTLLcsuqYYo8yDtrTocmu2xkGvgNebvPjT9DTtfFYGmgDqY+rBYXNlqL4s9qLDn6xkrJv4RxAPiTA==", + "optional": true, + "peer": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.23.3.tgz", - "integrity": "sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.1.tgz", + "integrity": "sha512-y4HqEnkelJIOQGd+3g1bTeKsA5c6qM7eOn7VggGVbBc0y8MLSKHacwcIE2PplNlQSj0PqS9rrXL/nkPVK+kUNg==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -809,15 +763,15 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz", - "integrity": "sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.1.tgz", + "integrity": "sha512-Hj791Ii4ci8HqnaKHAlLNs+zaLXb0EzSDhiAWp5VNlyvCNymYfacs64pxTxbH1znW/NcArSmwpmG9IKE/TUVVQ==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/plugin-transform-optional-chaining": "^7.23.3" + "@babel/plugin-transform-optional-chaining": "^7.24.1" }, "engines": { "node": ">=6.9.0" @@ -827,14 +781,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.7.tgz", - "integrity": "sha512-LlRT7HgaifEpQA1ZgLVOIJZZFVPWN5iReq/7/JixwBtwcoeVGDBD53ZV28rrsLYOZs1Y/EHhA8N/Z6aazHR8cw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.1.tgz", + "integrity": "sha512-m9m/fXsXLiHfwdgydIFnpk+7jlVbnvlK5B2EKiPdLUb6WX654ZaaEWJUjk8TftRbZpK0XibovlLWX4KIZhV6jw==", "optional": true, "peer": true, "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -882,15 +836,15 @@ } }, "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.23.9.tgz", - "integrity": "sha512-hJhBCb0+NnTWybvWq2WpbCYDOcflSbx0t+BYP65e5R9GVnukiDTi+on5bFkk4p7QGuv190H6KfNiV9Knf/3cZA==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.24.1.tgz", + "integrity": "sha512-zPEvzFijn+hRvJuX2Vu3KbEBN39LN3f7tW3MQO2LsIs57B26KU+kUc82BdAktS1VCM6libzh45eKGI65lg0cpA==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.23.9", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-decorators": "^7.23.3" + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-decorators": "^7.24.1" }, "engines": { "node": ">=6.9.0" @@ -900,14 +854,14 @@ } }, "node_modules/@babel/plugin-proposal-export-default-from": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.23.3.tgz", - "integrity": "sha512-Q23MpLZfSGZL1kU7fWqV262q65svLSCIP5kZ/JCW/rKTCm/FrLjpvEd2kfUYMVeHh4QhV/xzyoRAHWrAZJrE3Q==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.24.1.tgz", + "integrity": "sha512-+0hrgGGV3xyYIjOrD/bUZk/iUwOIGuoANfRfVg1cPhYBxF+TIXSEcc42DqzBICmWsnAQ+SfKedY0bj8QD+LuMg==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-export-default-from": "^7.23.3" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-export-default-from": "^7.24.1" }, "engines": { "node": ">=6.9.0" @@ -932,6 +886,24 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", + "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-logical-assignment-operators instead.", + "optional": true, + "peer": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", @@ -1092,13 +1064,13 @@ } }, "node_modules/@babel/plugin-syntax-decorators": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.23.3.tgz", - "integrity": "sha512-cf7Niq4/+/juY67E0PbgH0TDhLQ5J7zS8C/Q5FFx+DWyrRa9sUQdTXkjqKu8zGvuqr7vw1muKiukseihU+PJDA==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.24.1.tgz", + "integrity": "sha512-05RJdO/cCrtVWuAaSn1tS3bH8jbsJa/Y1uD186u6J4C/1mnHFxseeuWpsqr9anvo7TUulev7tm7GDwRV+VuhDw==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1121,13 +1093,13 @@ } }, "node_modules/@babel/plugin-syntax-export-default-from": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.23.3.tgz", - "integrity": "sha512-KeENO5ck1IeZ/l2lFZNy+mpobV3D2Zy5C1YFnWm+YuY5mQiAWc4yAp13dqgguwsBsFVLh4LPCEqCa5qW13N+hw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.24.1.tgz", + "integrity": "sha512-cNXSxv9eTkGUtd0PsNMK8Yx5xeScxfpWOUAxE+ZPAXXEcAMOC3fk7LRdXq5fvpra2pLx2p1YtkAhpUbB2SwaRA==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1148,13 +1120,13 @@ } }, "node_modules/@babel/plugin-syntax-flow": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.23.3.tgz", - "integrity": "sha512-YZiAIpkJAwQXBJLIQbRFayR5c+gJ35Vcz3bg954k7cd73zqjvhacJuL9RbrzPz8qPmZdgqP6EUKwy0PCNhaaPA==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.24.1.tgz", + "integrity": "sha512-sxi2kLTI5DeW5vDtMUsk4mTPwvlUDbjOnoWayhynCwrw4QXRld4QEYwqzY8JmQXaJUtgUuCIurtSRH5sn4c7mA==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1164,13 +1136,13 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz", - "integrity": "sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.1.tgz", + "integrity": "sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1180,13 +1152,13 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.23.3.tgz", - "integrity": "sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.1.tgz", + "integrity": "sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1220,12 +1192,12 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", - "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", + "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", "devOptional": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1338,12 +1310,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", - "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz", + "integrity": "sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==", "devOptional": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1370,13 +1342,13 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz", - "integrity": "sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.1.tgz", + "integrity": "sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1386,14 +1358,14 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.9.tgz", - "integrity": "sha512-8Q3veQEDGe14dTYuwagbRtwxQDnytyg1JFu4/HwEMETeofocrB0U0ejBJIXoeG/t2oXZ8kzCyI0ZZfbT80VFNQ==", + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.3.tgz", + "integrity": "sha512-Qe26CMYVjpQxJ8zxM1340JFNjZaF+ISWpr1Kt/jGo+ZTUzKkfw/pphEWbRCb+lmSM6k/TOgfYLvmbHkUQ0asIg==", "optional": true, "peer": true, "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-remap-async-to-generator": "^7.22.20", "@babel/plugin-syntax-async-generators": "^7.8.4" }, @@ -1405,14 +1377,14 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz", - "integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.1.tgz", + "integrity": "sha512-AawPptitRXp1y0n4ilKcGbRYWfbbzFWz2NqNu7dacYDtFtz0CMjG64b3LQsb3KIgnf4/obcUL78hfaOS7iCUfw==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-module-imports": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-remap-async-to-generator": "^7.22.20" }, "engines": { @@ -1423,13 +1395,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz", - "integrity": "sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.1.tgz", + "integrity": "sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1439,13 +1411,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz", - "integrity": "sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.4.tgz", + "integrity": "sha512-nIFUZIpGKDf9O9ttyRXpHFpKC+X3Y5mtshZONuEUYBomAKoM4y029Jr+uB1bHGPhNmK8YXHevDtKDOLmtRrp6g==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1455,14 +1427,14 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.23.3.tgz", - "integrity": "sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.1.tgz", + "integrity": "sha512-OMLCXi0NqvJfORTaPQBwqLXHhb93wkBKZ4aNwMl6WtehO7ar+cmp+89iPEQPqxAnxsOKTaMcs3POz3rKayJ72g==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1472,14 +1444,14 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.23.4.tgz", - "integrity": "sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.4.tgz", + "integrity": "sha512-B8q7Pz870Hz/q9UgP8InNpY01CSLDSCyqX7zcRuv3FcPl87A2G17lASroHWaCtbdIcbYzOZ7kWmXFKbijMSmFg==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.24.4", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-class-static-block": "^7.14.5" }, "engines": { @@ -1490,9 +1462,9 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.23.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.8.tgz", - "integrity": "sha512-yAYslGsY1bX6Knmg46RjiCiNSwJKv2IUC8qOdYKqMMr0491SXFhcHqOdRDeCRohOOIzwN/90C6mQ9qAKgrP7dg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.1.tgz", + "integrity": "sha512-ZTIe3W7UejJd3/3R4p7ScyyOoafetUShSf4kCqV0O7F/RiHxVj/wRaRnQlrGwflvcehNA8M42HkAiEDYZu2F1Q==", "optional": true, "peer": true, "dependencies": { @@ -1500,8 +1472,8 @@ "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-replace-supers": "^7.24.1", "@babel/helper-split-export-declaration": "^7.22.6", "globals": "^11.1.0" }, @@ -1523,14 +1495,14 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz", - "integrity": "sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.1.tgz", + "integrity": "sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/template": "^7.22.15" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/template": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1540,13 +1512,13 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz", - "integrity": "sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.1.tgz", + "integrity": "sha512-ow8jciWqNxR3RYbSNVuF4U2Jx130nwnBnhRw6N6h1bOejNkABmcI5X5oz29K4alWX7vf1C+o6gtKXikzRKkVdw==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1556,14 +1528,14 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz", - "integrity": "sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.1.tgz", + "integrity": "sha512-p7uUxgSoZwZ2lPNMzUkqCts3xlp8n+o05ikjy7gbtFJSt9gdU88jAmtfmOxHM14noQXBxfgzf2yRWECiNVhTCw==", "optional": true, "peer": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1573,13 +1545,13 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz", - "integrity": "sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.1.tgz", + "integrity": "sha512-msyzuUnvsjsaSaocV6L7ErfNsa5nDWL1XKNnDePLgmz+WdU4w/J8+AxBMrWfi9m4IxfL5sZQKUPQKDQeeAT6lA==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1589,13 +1561,13 @@ } }, "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.23.4.tgz", - "integrity": "sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.1.tgz", + "integrity": "sha512-av2gdSTyXcJVdI+8aFZsCAtR29xJt0S5tas+Ef8NvBNmD1a+N/3ecMLeMBgfcK+xzsjdLDT6oHt+DFPyeqUbDA==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-dynamic-import": "^7.8.3" }, "engines": { @@ -1606,14 +1578,14 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz", - "integrity": "sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.1.tgz", + "integrity": "sha512-U1yX13dVBSwS23DEAqU+Z/PkwE9/m7QQy8Y9/+Tdb8UWYaGNDYwTLi19wqIAiROr8sXVum9A/rtiH5H0boUcTw==", "optional": true, "peer": true, "dependencies": { "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1623,13 +1595,13 @@ } }, "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.4.tgz", - "integrity": "sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.1.tgz", + "integrity": "sha512-Ft38m/KFOyzKw2UaJFkWG9QnHPG/Q/2SkOrRk4pNBPg5IPZ+dOxcmkK5IyuBcxiNPyyYowPGUReyBvrvZs7IlQ==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, "engines": { @@ -1640,14 +1612,14 @@ } }, "node_modules/@babel/plugin-transform-flow-strip-types": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.23.3.tgz", - "integrity": "sha512-26/pQTf9nQSNVJCrLB1IkHUKyPxR+lMrH2QDPG89+Znu9rAMbtrybdbWeE9bb7gzjmE5iXHEY+e0HUwM6Co93Q==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.24.1.tgz", + "integrity": "sha512-iIYPIWt3dUmUKKE10s3W+jsQ3icFkw0JyRVyY1B7G4yK/nngAOHLVx8xlhA6b/Jzl/Y0nis8gjqhqKtRDQqHWQ==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-flow": "^7.23.3" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-flow": "^7.24.1" }, "engines": { "node": ">=6.9.0" @@ -1657,13 +1629,13 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.6.tgz", - "integrity": "sha512-aYH4ytZ0qSuBbpfhuofbg/e96oQ7U2w1Aw/UQmKT+1l39uEhUPoFS3fHevDc1G0OvewyDudfMKY1OulczHzWIw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.1.tgz", + "integrity": "sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" }, "engines": { @@ -1674,15 +1646,15 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz", - "integrity": "sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.1.tgz", + "integrity": "sha512-BXmDZpPlh7jwicKArQASrj8n22/w6iymRnvHYYd2zO30DbE277JO20/7yXJT3QxDPtiQiOxQBbZH4TpivNXIxA==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-function-name": "^7.23.0", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1692,13 +1664,13 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.23.4.tgz", - "integrity": "sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.1.tgz", + "integrity": "sha512-U7RMFmRvoasscrIFy5xA4gIp8iWnWubnKkKuUGJjsuOH7GfbMkB+XZzeslx2kLdEGdOJDamEmCqOks6e8nv8DQ==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-json-strings": "^7.8.3" }, "engines": { @@ -1709,13 +1681,13 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz", - "integrity": "sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.1.tgz", + "integrity": "sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1725,13 +1697,13 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.23.4.tgz", - "integrity": "sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.1.tgz", + "integrity": "sha512-OhN6J4Bpz+hIBqItTeWJujDOfNP+unqv/NJgyhlpSqgBTPm37KkMmZV6SYcOj+pnDbdcl1qRGV/ZiIjX9Iy34w==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, "engines": { @@ -1742,13 +1714,13 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz", - "integrity": "sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.1.tgz", + "integrity": "sha512-4ojai0KysTWXzHseJKa1XPNXKRbuUrhkOPY4rEGeR+7ChlJVKxFa3H3Bz+7tWaGKgJAXUWKOGmltN+u9B3+CVg==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1758,14 +1730,14 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz", - "integrity": "sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.1.tgz", + "integrity": "sha512-lAxNHi4HVtjnHd5Rxg3D5t99Xm6H7b04hUS7EHIXcUl2EV4yl1gWdqZrNzXnSrHveL9qMdbODlLF55mvgjAfaQ==", "optional": true, "peer": true, "dependencies": { "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1775,12 +1747,12 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", - "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz", + "integrity": "sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==", "dependencies": { "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-simple-access": "^7.22.5" }, "engines": { @@ -1791,15 +1763,15 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.9.tgz", - "integrity": "sha512-KDlPRM6sLo4o1FkiSlXoAa8edLXFsKKIda779fbLrvmeuc3itnjCtaO6RrtoaANsIJANj+Vk1zqbZIMhkCAHVw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.1.tgz", + "integrity": "sha512-mqQ3Zh9vFO1Tpmlt8QPnbwGHzNz3lpNEMxQb1kAemn/erstyqw1r9KeOlOfo3y6xAnFEcOv2tSyrXfmMk+/YZA==", "optional": true, "peer": true, "dependencies": { "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-validator-identifier": "^7.22.20" }, "engines": { @@ -1810,14 +1782,14 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz", - "integrity": "sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.1.tgz", + "integrity": "sha512-tuA3lpPj+5ITfcCluy6nWonSL7RvaG0AOTeAuvXqEKS34lnLzXpDb0dcP6K8jD0zWZFNDVly90AGFJPnm4fOYg==", "optional": true, "peer": true, "dependencies": { "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1844,13 +1816,13 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz", - "integrity": "sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.1.tgz", + "integrity": "sha512-/rurytBM34hYy0HKZQyA0nHbQgQNFm4Q/BOc9Hflxi2X3twRof7NaE5W46j4kQitm7SvACVRXsa6N/tSZxvPug==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1860,13 +1832,13 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.4.tgz", - "integrity": "sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.1.tgz", + "integrity": "sha512-iQ+caew8wRrhCikO5DrUYx0mrmdhkaELgFa+7baMcVuhxIkN7oxt06CZ51D65ugIb1UWRQ8oQe+HXAVM6qHFjw==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" }, "engines": { @@ -1877,13 +1849,13 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.23.4.tgz", - "integrity": "sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.1.tgz", + "integrity": "sha512-7GAsGlK4cNL2OExJH1DzmDeKnRv/LXq0eLUSvudrehVA5Rgg4bIrqEUW29FbKMBRT0ztSqisv7kjP+XIC4ZMNw==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-numeric-separator": "^7.10.4" }, "engines": { @@ -1894,17 +1866,16 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz", - "integrity": "sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.1.tgz", + "integrity": "sha512-XjD5f0YqOtebto4HGISLNfiNMTTs6tbkFf2TOqJlYKYmbo+mN9Dnpl4SRoofiziuOWMIyq3sZEUqLo3hLITFEA==", "optional": true, "peer": true, "dependencies": { - "@babel/compat-data": "^7.23.3", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.23.3" + "@babel/plugin-transform-parameters": "^7.24.1" }, "engines": { "node": ">=6.9.0" @@ -1914,14 +1885,14 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz", - "integrity": "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.1.tgz", + "integrity": "sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.20" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-replace-supers": "^7.24.1" }, "engines": { "node": ">=6.9.0" @@ -1931,13 +1902,13 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.23.4.tgz", - "integrity": "sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.1.tgz", + "integrity": "sha512-oBTH7oURV4Y+3EUrf6cWn1OHio3qG/PVwO5J03iSJmBg6m2EhKjkAu/xuaXaYwWW9miYtvbWv4LNf0AmR43LUA==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" }, "engines": { @@ -1948,13 +1919,13 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz", - "integrity": "sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.1.tgz", + "integrity": "sha512-n03wmDt+987qXwAgcBlnUUivrZBPZ8z1plL0YvgQalLm+ZE5BMhGm94jhxXtA1wzv1Cu2aaOv1BM9vbVttrzSg==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, @@ -1966,13 +1937,13 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz", - "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.1.tgz", + "integrity": "sha512-8Jl6V24g+Uw5OGPeWNKrKqXPDw2YDjLc53ojwfMcKwlEoETKU9rU0mHUtcg9JntWI/QYzGAXNWEcVHZ+fR+XXg==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1982,14 +1953,14 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.23.3.tgz", - "integrity": "sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.1.tgz", + "integrity": "sha512-tGvisebwBO5em4PaYNqt4fkw56K2VALsAbAakY0FjTYqJp7gfdrgr7YX76Or8/cpik0W6+tj3rZ0uHU9Oil4tw==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1999,15 +1970,15 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.4.tgz", - "integrity": "sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.1.tgz", + "integrity": "sha512-pTHxDVa0BpUbvAgX3Gat+7cSciXqUcY9j2VZKTbSB6+VQGpNgNO9ailxTGHSXlqOnX1Hcx1Enme2+yv7VqP9bg==", "optional": true, "peer": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-create-class-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, "engines": { @@ -2018,13 +1989,13 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz", - "integrity": "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.1.tgz", + "integrity": "sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2034,13 +2005,13 @@ } }, "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.23.3.tgz", - "integrity": "sha512-GnvhtVfA2OAtzdX58FJxU19rhoGeQzyVndw3GgtdECQvQFXPEZIOVULHVZGAYmOgmqjXpVpfocAbSjh99V/Fqw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.1.tgz", + "integrity": "sha512-mvoQg2f9p2qlpDQRBC7M3c3XTr0k7cp/0+kFKKO/7Gtu0LSw16eKB+Fabe2bDT/UpsyasTBBkAnbdsLrkD5XMw==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2086,13 +2057,13 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz", - "integrity": "sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.24.1.tgz", + "integrity": "sha512-kDJgnPujTmAZ/9q2CN4m2/lRsUUPDvsG3+tSHWUJIzMGTt5U/b/fwWd3RO3n+5mjLrsBrVa5eKFRVSQbi3dF1w==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2102,13 +2073,13 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz", - "integrity": "sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.24.1.tgz", + "integrity": "sha512-1v202n7aUq4uXAieRTKcwPzNyphlCuqHHDcdSNc+vdhoTEZcFMh+L5yZuCmGaIO7bs1nJUNfHB89TZyoL48xNA==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2118,14 +2089,14 @@ } }, "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.23.3.tgz", - "integrity": "sha512-qMFdSS+TUhB7Q/3HVPnEdYJDQIk57jkntAwSuz9xfSE4n+3I+vHYCli3HoHawN1Z3RfCz/y1zXA/JXjG6cVImQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.24.1.tgz", + "integrity": "sha512-+pWEAaDJvSm9aFvJNpLiM2+ktl2Sn2U5DdyiWdZBxmLc6+xGt88dvFqsHiAiDS+8WqUwbDfkKz9jRxK3M0k+kA==", "optional": true, "peer": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2135,13 +2106,13 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz", - "integrity": "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.1.tgz", + "integrity": "sha512-sJwZBCzIBE4t+5Q4IGLaaun5ExVMRY0lYwos/jNecjMrVCygCdph3IKv0tkP5Fc87e/1+bebAmEAGBfnRD+cnw==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-plugin-utils": "^7.24.0", "regenerator-transform": "^0.15.2" }, "engines": { @@ -2152,13 +2123,13 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz", - "integrity": "sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.1.tgz", + "integrity": "sha512-JAclqStUfIwKN15HrsQADFgeZt+wexNQ0uLhuqvqAUFoqPMjEcFCYZBhq0LUdz6dZK/mD+rErhW71fbx8RYElg==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2168,17 +2139,17 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.23.9.tgz", - "integrity": "sha512-A7clW3a0aSjm3ONU9o2HAILSegJCYlEZmOhmBRReVtIpY/Z/p7yIZ+wR41Z+UipwdGuqwtID/V/dOdZXjwi9gQ==", + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.24.3.tgz", + "integrity": "sha512-J0BuRPNlNqlMTRJ72eVptpt9VcInbxO6iP3jaxr+1NPhC0UkKL+6oeX6VXMEYdADnuqmMmsBspt4d5w8Y/TCbQ==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", - "babel-plugin-polyfill-corejs2": "^0.4.8", - "babel-plugin-polyfill-corejs3": "^0.9.0", - "babel-plugin-polyfill-regenerator": "^0.5.5", + "@babel/helper-module-imports": "^7.24.3", + "@babel/helper-plugin-utils": "^7.24.0", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.1", + "babel-plugin-polyfill-regenerator": "^0.6.1", "semver": "^6.3.1" }, "engines": { @@ -2199,13 +2170,13 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz", - "integrity": "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.1.tgz", + "integrity": "sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2215,13 +2186,13 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz", - "integrity": "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.1.tgz", + "integrity": "sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" }, "engines": { @@ -2232,13 +2203,13 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz", - "integrity": "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.1.tgz", + "integrity": "sha512-9v0f1bRXgPVcPrngOQvLXeGNNVLc8UjMVfebo9ka0WF3/7+aVUHmaJVT3sa0XCzEFioPfPHZiOcYG9qOsH63cw==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2248,13 +2219,13 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz", - "integrity": "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.1.tgz", + "integrity": "sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2264,13 +2235,13 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz", - "integrity": "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.1.tgz", + "integrity": "sha512-CBfU4l/A+KruSUoW+vTQthwcAdwuqbpRNB8HQKlZABwHRhsdHZ9fezp4Sn18PeAlYxTNiLMlx4xUBV3AWfg1BA==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2280,16 +2251,16 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.23.6.tgz", - "integrity": "sha512-6cBG5mBvUu4VUD04OHKnYzbuHNP8huDsD3EDqqpIpsswTDoqHCjLoHb6+QgsV1WsT2nipRqCPgxD3LXnEO7XfA==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.24.4.tgz", + "integrity": "sha512-79t3CQ8+oBGk/80SQ8MN3Bs3obf83zJ0YZjDmDaEZN8MqhMI760apl5z6a20kFeMXBwJX99VpKT8CKxEBp5H1g==", "optional": true, "peer": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-create-class-features-plugin": "^7.23.6", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-typescript": "^7.23.3" + "@babel/helper-create-class-features-plugin": "^7.24.4", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-typescript": "^7.24.1" }, "engines": { "node": ">=6.9.0" @@ -2299,13 +2270,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz", - "integrity": "sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.1.tgz", + "integrity": "sha512-RlkVIcWT4TLI96zM660S877E7beKlQw7Ig+wqkKBiWfj0zH5Q4h50q6er4wzZKRNSYpfo6ILJ+hrJAGSX2qcNw==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2315,14 +2286,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.23.3.tgz", - "integrity": "sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.1.tgz", + "integrity": "sha512-Ss4VvlfYV5huWApFsF8/Sq0oXnGO+jB+rijFEFugTd3cwSObUSnUi88djgR5528Csl0uKlrI331kRqe56Ov2Ng==", "optional": true, "peer": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2332,14 +2303,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz", - "integrity": "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.1.tgz", + "integrity": "sha512-2A/94wgZgxfTsiLaQ2E36XAOdcZmGAaEEgVmxQWwZXWkGhvoHbaqXcKnU8zny4ycpu3vNqg0L/PcCiYtHtA13g==", "optional": true, "peer": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2349,14 +2320,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.23.3.tgz", - "integrity": "sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.1.tgz", + "integrity": "sha512-fqj4WuzzS+ukpgerpAoOnMfQXwUHFxXUZUE84oL2Kao2N8uSlvcpnAidKASgsNgzZHBsHWvcm8s9FPWUhAb8fA==", "optional": true, "peer": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -2366,27 +2337,28 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.9.tgz", - "integrity": "sha512-3kBGTNBBk9DQiPoXYS0g0BYlwTQYUTifqgKTjxUwEUkduRT2QOa0FPGBJ+NROQhGyYO5BuTJwGvBnqKDykac6A==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.4.tgz", + "integrity": "sha512-7Kl6cSmYkak0FK/FXjSEnLJ1N9T/WA2RkMhu17gZ/dsxKJUuTYNIylahPTzqpLyJN4WhDif8X0XK1R8Wsguo/A==", "optional": true, "peer": true, "dependencies": { - "@babel/compat-data": "^7.23.5", + "@babel/compat-data": "^7.24.4", "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-validator-option": "^7.23.5", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.7", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.4", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.1", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.23.3", - "@babel/plugin-syntax-import-attributes": "^7.23.3", + "@babel/plugin-syntax-import-assertions": "^7.24.1", + "@babel/plugin-syntax-import-attributes": "^7.24.1", "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", @@ -2398,58 +2370,58 @@ "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.23.3", - "@babel/plugin-transform-async-generator-functions": "^7.23.9", - "@babel/plugin-transform-async-to-generator": "^7.23.3", - "@babel/plugin-transform-block-scoped-functions": "^7.23.3", - "@babel/plugin-transform-block-scoping": "^7.23.4", - "@babel/plugin-transform-class-properties": "^7.23.3", - "@babel/plugin-transform-class-static-block": "^7.23.4", - "@babel/plugin-transform-classes": "^7.23.8", - "@babel/plugin-transform-computed-properties": "^7.23.3", - "@babel/plugin-transform-destructuring": "^7.23.3", - "@babel/plugin-transform-dotall-regex": "^7.23.3", - "@babel/plugin-transform-duplicate-keys": "^7.23.3", - "@babel/plugin-transform-dynamic-import": "^7.23.4", - "@babel/plugin-transform-exponentiation-operator": "^7.23.3", - "@babel/plugin-transform-export-namespace-from": "^7.23.4", - "@babel/plugin-transform-for-of": "^7.23.6", - "@babel/plugin-transform-function-name": "^7.23.3", - "@babel/plugin-transform-json-strings": "^7.23.4", - "@babel/plugin-transform-literals": "^7.23.3", - "@babel/plugin-transform-logical-assignment-operators": "^7.23.4", - "@babel/plugin-transform-member-expression-literals": "^7.23.3", - "@babel/plugin-transform-modules-amd": "^7.23.3", - "@babel/plugin-transform-modules-commonjs": "^7.23.3", - "@babel/plugin-transform-modules-systemjs": "^7.23.9", - "@babel/plugin-transform-modules-umd": "^7.23.3", + "@babel/plugin-transform-arrow-functions": "^7.24.1", + "@babel/plugin-transform-async-generator-functions": "^7.24.3", + "@babel/plugin-transform-async-to-generator": "^7.24.1", + "@babel/plugin-transform-block-scoped-functions": "^7.24.1", + "@babel/plugin-transform-block-scoping": "^7.24.4", + "@babel/plugin-transform-class-properties": "^7.24.1", + "@babel/plugin-transform-class-static-block": "^7.24.4", + "@babel/plugin-transform-classes": "^7.24.1", + "@babel/plugin-transform-computed-properties": "^7.24.1", + "@babel/plugin-transform-destructuring": "^7.24.1", + "@babel/plugin-transform-dotall-regex": "^7.24.1", + "@babel/plugin-transform-duplicate-keys": "^7.24.1", + "@babel/plugin-transform-dynamic-import": "^7.24.1", + "@babel/plugin-transform-exponentiation-operator": "^7.24.1", + "@babel/plugin-transform-export-namespace-from": "^7.24.1", + "@babel/plugin-transform-for-of": "^7.24.1", + "@babel/plugin-transform-function-name": "^7.24.1", + "@babel/plugin-transform-json-strings": "^7.24.1", + "@babel/plugin-transform-literals": "^7.24.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.1", + "@babel/plugin-transform-member-expression-literals": "^7.24.1", + "@babel/plugin-transform-modules-amd": "^7.24.1", + "@babel/plugin-transform-modules-commonjs": "^7.24.1", + "@babel/plugin-transform-modules-systemjs": "^7.24.1", + "@babel/plugin-transform-modules-umd": "^7.24.1", "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", - "@babel/plugin-transform-new-target": "^7.23.3", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.4", - "@babel/plugin-transform-numeric-separator": "^7.23.4", - "@babel/plugin-transform-object-rest-spread": "^7.23.4", - "@babel/plugin-transform-object-super": "^7.23.3", - "@babel/plugin-transform-optional-catch-binding": "^7.23.4", - "@babel/plugin-transform-optional-chaining": "^7.23.4", - "@babel/plugin-transform-parameters": "^7.23.3", - "@babel/plugin-transform-private-methods": "^7.23.3", - "@babel/plugin-transform-private-property-in-object": "^7.23.4", - "@babel/plugin-transform-property-literals": "^7.23.3", - "@babel/plugin-transform-regenerator": "^7.23.3", - "@babel/plugin-transform-reserved-words": "^7.23.3", - "@babel/plugin-transform-shorthand-properties": "^7.23.3", - "@babel/plugin-transform-spread": "^7.23.3", - "@babel/plugin-transform-sticky-regex": "^7.23.3", - "@babel/plugin-transform-template-literals": "^7.23.3", - "@babel/plugin-transform-typeof-symbol": "^7.23.3", - "@babel/plugin-transform-unicode-escapes": "^7.23.3", - "@babel/plugin-transform-unicode-property-regex": "^7.23.3", - "@babel/plugin-transform-unicode-regex": "^7.23.3", - "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", + "@babel/plugin-transform-new-target": "^7.24.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.1", + "@babel/plugin-transform-numeric-separator": "^7.24.1", + "@babel/plugin-transform-object-rest-spread": "^7.24.1", + "@babel/plugin-transform-object-super": "^7.24.1", + "@babel/plugin-transform-optional-catch-binding": "^7.24.1", + "@babel/plugin-transform-optional-chaining": "^7.24.1", + "@babel/plugin-transform-parameters": "^7.24.1", + "@babel/plugin-transform-private-methods": "^7.24.1", + "@babel/plugin-transform-private-property-in-object": "^7.24.1", + "@babel/plugin-transform-property-literals": "^7.24.1", + "@babel/plugin-transform-regenerator": "^7.24.1", + "@babel/plugin-transform-reserved-words": "^7.24.1", + "@babel/plugin-transform-shorthand-properties": "^7.24.1", + "@babel/plugin-transform-spread": "^7.24.1", + "@babel/plugin-transform-sticky-regex": "^7.24.1", + "@babel/plugin-transform-template-literals": "^7.24.1", + "@babel/plugin-transform-typeof-symbol": "^7.24.1", + "@babel/plugin-transform-unicode-escapes": "^7.24.1", + "@babel/plugin-transform-unicode-property-regex": "^7.24.1", + "@babel/plugin-transform-unicode-regex": "^7.24.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.24.1", "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.8", - "babel-plugin-polyfill-corejs3": "^0.9.0", - "babel-plugin-polyfill-regenerator": "^0.5.5", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.4", + "babel-plugin-polyfill-regenerator": "^0.6.1", "core-js-compat": "^3.31.0", "semver": "^6.3.1" }, @@ -2471,15 +2443,15 @@ } }, "node_modules/@babel/preset-flow": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.23.3.tgz", - "integrity": "sha512-7yn6hl8RIv+KNk6iIrGZ+D06VhVY35wLVf23Cz/mMu1zOr7u4MMP4j0nZ9tLf8+4ZFpnib8cFYgB/oYg9hfswA==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.24.1.tgz", + "integrity": "sha512-sWCV2G9pcqZf+JHyv/RyqEIpFypxdCSxWIxQjpdaQxenNog7cN1pr76hg8u0Fz8Qgg0H4ETkGcJnXL8d4j0PPA==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-validator-option": "^7.22.15", - "@babel/plugin-transform-flow-strip-types": "^7.23.3" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-transform-flow-strip-types": "^7.24.1" }, "engines": { "node": ">=6.9.0" @@ -2504,18 +2476,18 @@ } }, "node_modules/@babel/preset-react": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.23.3.tgz", - "integrity": "sha512-tbkHOS9axH6Ysf2OUEqoSZ6T3Fa2SrNH6WTWSPBboxKzdxNc9qOICeLXkNG0ZEwbQ1HY8liwOce4aN/Ceyuq6w==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.24.1.tgz", + "integrity": "sha512-eFa8up2/8cZXLIpkafhaADTXSnl7IsUFCYenRWrARBz0/qZwcT0RBXpys0LJU4+WfPoF2ZG6ew6s2V6izMCwRA==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-validator-option": "^7.22.15", - "@babel/plugin-transform-react-display-name": "^7.23.3", - "@babel/plugin-transform-react-jsx": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-transform-react-display-name": "^7.24.1", + "@babel/plugin-transform-react-jsx": "^7.23.4", "@babel/plugin-transform-react-jsx-development": "^7.22.5", - "@babel/plugin-transform-react-pure-annotations": "^7.23.3" + "@babel/plugin-transform-react-pure-annotations": "^7.24.1" }, "engines": { "node": ">=6.9.0" @@ -2525,17 +2497,17 @@ } }, "node_modules/@babel/preset-typescript": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.23.3.tgz", - "integrity": "sha512-17oIGVlqz6CchO9RFYn5U6ZpWRZIngayYCtrPRSgANSwC2V1Jb+iP74nVxzzXJte8b8BYxrL1yY96xfhTBrNNQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.24.1.tgz", + "integrity": "sha512-1DBaMmRDpuYQBPWD8Pf/WEwCrtgRHxsZnP4mIy9G/X+hFfbI47Q2G4t1Paakld84+qsk2fSsUPMKg71jkoOOaQ==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-validator-option": "^7.22.15", - "@babel/plugin-syntax-jsx": "^7.23.3", - "@babel/plugin-transform-modules-commonjs": "^7.23.3", - "@babel/plugin-transform-typescript": "^7.23.3" + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-syntax-jsx": "^7.24.1", + "@babel/plugin-transform-modules-commonjs": "^7.24.1", + "@babel/plugin-transform-typescript": "^7.24.1" }, "engines": { "node": ">=6.9.0" @@ -2606,9 +2578,9 @@ "peer": true }, "node_modules/@babel/runtime": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", - "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz", + "integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==", "optional": true, "peer": true, "dependencies": { @@ -2619,31 +2591,31 @@ } }, "node_modules/@babel/template": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz", - "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", "dependencies": { "@babel/code-frame": "^7.23.5", - "@babel/parser": "^7.23.9", - "@babel/types": "^7.23.9" + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz", - "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.9", - "@babel/types": "^7.23.9", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -2660,9 +2632,9 @@ } }, "node_modules/@babel/types": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz", - "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", "dependencies": { "@babel/helper-string-parser": "^7.23.4", "@babel/helper-validator-identifier": "^7.22.20", @@ -3094,9 +3066,9 @@ } }, "node_modules/@digitalbazaar/vc-status-list-context": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@digitalbazaar/vc-status-list-context/-/vc-status-list-context-3.0.1.tgz", - "integrity": "sha512-vQsqQXpmSXKNy/C0xxFUOBzz60dHh6oupQam1xRC8IspVC11hYJiX9SAhmbI0ulHvX1R2JfqZaJHZjmAyMZ/aA==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@digitalbazaar/vc-status-list-context/-/vc-status-list-context-3.1.1.tgz", + "integrity": "sha512-cMVtd+EV+4KN2kUG4/vsV74JVsGE6dcpod6zRoFB/AJA2W/sZbJqR44KL3G6P262+GcAECNhtnSsKsTnQ6y8+w==" }, "node_modules/@digitalcredentials/base58-universal": { "version": "1.0.1", @@ -3929,6 +3901,25 @@ "hash.js": "1.1.7" } }, + "node_modules/@ethersproject/signing-key/node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/@ethersproject/signing-key/node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, "node_modules/@ethersproject/solidity": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", @@ -4122,25 +4113,25 @@ } }, "node_modules/@expo/cli": { - "version": "0.17.3", - "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-0.17.3.tgz", - "integrity": "sha512-lIK8igsEQxTh4WuDlcEhE0wAJcDrAyjWDF00phdmwuSCpE5SaEXNlddOXvGxEVKPhUxHZUFo9NbfoQC+JVmkfA==", + "version": "0.17.10", + "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-0.17.10.tgz", + "integrity": "sha512-Jw2wY+lsavP9GRqwwLqF/SvB7w2GZ4sWBMcBKTZ8F0lWjwmLGAUt4WYquf20agdmnY/oZUHvWNkrz/t3SflhnA==", "optional": true, "peer": true, "dependencies": { "@babel/runtime": "^7.20.0", "@expo/code-signing-certificates": "0.0.5", "@expo/config": "~8.5.0", - "@expo/config-plugins": "~7.8.0", + "@expo/config-plugins": "~7.9.0", "@expo/devcert": "^1.0.0", - "@expo/env": "~0.2.0", + "@expo/env": "~0.2.2", "@expo/image-utils": "^0.4.0", "@expo/json-file": "^8.2.37", "@expo/metro-config": "~0.17.0", "@expo/osascript": "^2.0.31", "@expo/package-manager": "^1.1.1", "@expo/plist": "^0.1.0", - "@expo/prebuild-config": "6.7.4", + "@expo/prebuild-config": "6.8.1", "@expo/rudder-sdk-node": "1.1.1", "@expo/spawn-async": "1.5.0", "@expo/xcpretty": "^4.3.0", @@ -4194,6 +4185,7 @@ "send": "^0.18.0", "slugify": "^1.3.4", "source-map-support": "~0.5.21", + "stacktrace-parser": "^0.1.10", "structured-headers": "^0.4.1", "tar": "^6.0.5", "temp-dir": "^2.0.0", @@ -4209,14 +4201,14 @@ } }, "node_modules/@expo/cli/node_modules/@expo/prebuild-config": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-6.7.4.tgz", - "integrity": "sha512-x8EUdCa8DTMZ/dtEXjHAdlP+ljf6oSeSKNzhycXiHhpMSMG9jEhV28ocCwc6cKsjK5GziweEiHwvrj6+vsBlhA==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-6.8.1.tgz", + "integrity": "sha512-ptK9e0dcj1eYlAWV+fG+QkuAWcLAT1AmtEbj++tn7ZjEj8+LkXRM73LCOEGaF0Er8i8ZWNnaVsgGW4vjgP5ZsA==", "optional": true, "peer": true, "dependencies": { "@expo/config": "~8.5.0", - "@expo/config-plugins": "~7.8.0", + "@expo/config-plugins": "~7.9.0", "@expo/config-types": "^50.0.0-alpha.1", "@expo/image-utils": "^0.4.0", "@expo/json-file": "^8.2.37", @@ -4280,9 +4272,9 @@ } }, "node_modules/@expo/cli/node_modules/expo-modules-autolinking": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-1.10.2.tgz", - "integrity": "sha512-OEeoz0+zGx5EJwGtDm9pSywCr+gUCaisZV0mNkK7V3fuRl+EVPBSsI+957JwAc4ZxVps95jy28eLcRRtQ33yVg==", + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-1.10.3.tgz", + "integrity": "sha512-pn4n2Dl4iRh/zUeiChjRIe1C7EqOw1qhccr85viQV7W6l5vgRpY0osE51ij5LKg/kJmGRcJfs12+PwbdTplbKw==", "optional": true, "peer": true, "dependencies": { @@ -4417,6 +4409,13 @@ "node": ">=10" } }, + "node_modules/@expo/cli/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "optional": true, + "peer": true + }, "node_modules/@expo/cli/node_modules/tempy": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.7.1.tgz", @@ -4504,14 +4503,14 @@ } }, "node_modules/@expo/config": { - "version": "8.5.4", - "resolved": "https://registry.npmjs.org/@expo/config/-/config-8.5.4.tgz", - "integrity": "sha512-ggOLJPHGzJSJHVBC1LzwXwR6qUn8Mw7hkc5zEKRIdhFRuIQ6s2FE4eOvP87LrNfDF7eZGa6tJQYsiHSmZKG+8Q==", + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/@expo/config/-/config-8.5.6.tgz", + "integrity": "sha512-wF5awSg6MNn1cb1lIgjnhOn5ov2TEUTnkAVCsOl0QqDwcP+YIerteSFwjn9V52UZvg58L+LKxpCuGbw5IHavbg==", "optional": true, "peer": true, "dependencies": { "@babel/code-frame": "~7.10.4", - "@expo/config-plugins": "~7.8.2", + "@expo/config-plugins": "~7.9.0", "@expo/config-types": "^50.0.0", "@expo/json-file": "^8.2.37", "getenv": "^1.0.0", @@ -4524,9 +4523,9 @@ } }, "node_modules/@expo/config-plugins": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-7.8.4.tgz", - "integrity": "sha512-hv03HYxb/5kX8Gxv/BTI8TLc9L06WzqAfHRRXdbar4zkLcP2oTzvsLEF4/L/TIpD3rsnYa0KU42d0gWRxzPCJg==", + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-7.9.1.tgz", + "integrity": "sha512-ICt6Jed1J0tPYMQrJ8K5Qusgih2I6pZ2PU4VSvxsN3T4n97L13XpYV1vyq1Uc/HMl3UhOwldipmgpEbCfeDqsQ==", "optional": true, "peer": true, "dependencies": { @@ -4591,9 +4590,9 @@ } }, "node_modules/@expo/config-types": { - "version": "50.0.0", - "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-50.0.0.tgz", - "integrity": "sha512-0kkhIwXRT6EdFDwn+zTg9R2MZIAEYGn1MVkyRohAd+C9cXOb5RA8WLQi7vuxKF9m1SMtNAUrf0pO+ENK0+/KSw==", + "version": "50.0.1", + "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-50.0.1.tgz", + "integrity": "sha512-EZHMgzkWRB9SMHO1e9m8s+OMahf92XYTnsCFjxhSfcDrcEoSdFPyJWDJVloHZPMGhxns7Fi2+A+bEVN/hD4NKA==", "optional": true, "peer": true }, @@ -4713,33 +4712,23 @@ } }, "node_modules/@expo/env": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@expo/env/-/env-0.2.1.tgz", - "integrity": "sha512-deZmRS7Dvp18VM8s559dq/ZjPlV1D9vtLoLXwHmCK/JYOvtNptdKsfxcWjI7ewmo6ln2PqgNI9HRI74q6Wk2eA==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@expo/env/-/env-0.2.3.tgz", + "integrity": "sha512-a+uJ/e6MAVxPVVN/HbXU5qxzdqrqDwNQYxCfxtAufgmd5VZj54e5f3TJA3LEEUW3pTSZR8xK0H0EtVN297AZnw==", "optional": true, "peer": true, "dependencies": { "chalk": "^4.0.0", "debug": "^4.3.4", - "dotenv": "~16.0.3", - "dotenv-expand": "~10.0.0", + "dotenv": "~16.4.5", + "dotenv-expand": "~11.0.6", "getenv": "^1.0.0" } }, - "node_modules/@expo/env/node_modules/dotenv": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", - "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", - "optional": true, - "peer": true, - "engines": { - "node": ">=12" - } - }, "node_modules/@expo/fingerprint": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@expo/fingerprint/-/fingerprint-0.6.0.tgz", - "integrity": "sha512-KfpoVRTMwMNJ/Cf5o+Ou8M/Y0EGSTqK+rbi70M2Y0K2qgWNfMJ1gm6sYO9uc8lcTr7YSYM1Rme3dk7QXhpScNA==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@expo/fingerprint/-/fingerprint-0.6.1.tgz", + "integrity": "sha512-ggLn6unI6qowlA1FihdQwPpLn16VJulYkvYAEL50gaqVahfNEglRQMSH2giZzjD0d6xq2/EQuUdFyHaJfyJwOQ==", "optional": true, "peer": true, "dependencies": { @@ -4766,9 +4755,9 @@ } }, "node_modules/@expo/image-utils": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@expo/image-utils/-/image-utils-0.4.1.tgz", - "integrity": "sha512-EZb+VHSmw+a5s2hS9qksTcWylY0FDaIAVufcxoaRS9tHIXLjW5zcKW7Rhj9dSEbZbRVy9yXXdHKa3GQdUQIOFw==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@expo/image-utils/-/image-utils-0.4.2.tgz", + "integrity": "sha512-CxP+1QXgRXsNnmv2FAUA2RWwK6kNBFg4QEmVXn2K9iLoEAI+i+1IQXcUgc+J7nTJl9pO7FIu2gIiEYGYffjLWQ==", "optional": true, "peer": true, "dependencies": { @@ -4892,9 +4881,9 @@ } }, "node_modules/@expo/json-file": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.3.0.tgz", - "integrity": "sha512-yROUeXJXR5goagB8c3muFLCzLmdGOvoPpR5yDNaXrnTp4euNykr9yW0wWhJx4YVRTNOPtGBnEbbJBW+a9q+S6g==", + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.3.1.tgz", + "integrity": "sha512-QIMMaqPvm8EGflp041h27OG8DDgh3RxzkEjEEvHJ9AUImgeieMCGrpDsnGOcPI4TR6MpJpLNAk5rZK4szhEwIQ==", "optional": true, "peer": true, "dependencies": { @@ -4914,9 +4903,9 @@ } }, "node_modules/@expo/metro-config": { - "version": "0.17.3", - "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-0.17.3.tgz", - "integrity": "sha512-YW8ixbaz6yL7/Mg1rJJejiAAVQQKjGY1wXvT2Dh487r/r9/j1yE1YRS/oRY1yItYzbnHvO0p0jMnEGfiFYL3Tg==", + "version": "0.17.7", + "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-0.17.7.tgz", + "integrity": "sha512-3vAdinAjMeRwdhGWWLX6PziZdAPvnyJ6KVYqnJErHHqH0cA6dgAENT3Vq6PEM1H2HgczKr2d5yG9AMgwy848ow==", "optional": true, "peer": true, "dependencies": { @@ -4925,7 +4914,7 @@ "@babel/parser": "^7.20.0", "@babel/types": "^7.20.0", "@expo/config": "~8.5.0", - "@expo/env": "~0.2.0", + "@expo/env": "~0.2.2", "@expo/json-file": "~8.3.0", "@expo/spawn-async": "^1.7.2", "babel-preset-fbjs": "^3.4.0", @@ -5043,6 +5032,13 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/@expo/package-manager/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "optional": true, + "peer": true + }, "node_modules/@expo/package-manager/node_modules/sudo-prompt": { "version": "9.1.1", "resolved": "https://registry.npmjs.org/sudo-prompt/-/sudo-prompt-9.1.1.tgz", @@ -5051,9 +5047,9 @@ "peer": true }, "node_modules/@expo/plist": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.1.0.tgz", - "integrity": "sha512-xWD+8vIFif0wKyuqe3fmnmnSouXYucciZXFzS0ZD5OV9eSAS1RGQI5FaGGJ6zxJ4mpdy/4QzbLdBjnYE5vxA0g==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.1.1.tgz", + "integrity": "sha512-90qbbblHYWR/z0R+HP2t7yRx0IG5AsEL0BqTY/vXcj4emhGhm39Dbwg4BO2t6qfdLljJISzUwEtWWTl1HNHAAg==", "optional": true, "peer": true, "dependencies": { @@ -5218,9 +5214,9 @@ } }, "node_modules/@fastify/busboy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", - "integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", "engines": { "node": ">=14" } @@ -5229,7 +5225,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "optional": true + "devOptional": true }, "node_modules/@graphql-typed-document-node/core": { "version": "3.2.0", @@ -5286,18 +5282,11 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "dev": true }, - "node_modules/@ioredis/commands": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz", - "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==", - "optional": true, - "peer": true - }, "node_modules/@ipld/dag-cbor": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/@ipld/dag-cbor/-/dag-cbor-7.0.3.tgz", @@ -5327,11 +5316,11 @@ "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==" }, "node_modules/@ipld/dag-pb": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@ipld/dag-pb/-/dag-pb-4.0.8.tgz", - "integrity": "sha512-693AqMY2jvhe+w4jSwjnDrbhxIu39gm1H4f6/KD5gG+6VFMM6EXV7vq85BvEf8CRsnA0+auWfA29/S8gbWI0Ew==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@ipld/dag-pb/-/dag-pb-4.1.0.tgz", + "integrity": "sha512-LJU451Drqs5zjFm7jI4Hs3kHlilOqkjcSfPiQgVsZnWaYb2C7YdfhnclrVn/X+ucKejlU9BL3+gXFCZUXkMuCg==", "dependencies": { - "multiformats": "^13.0.0" + "multiformats": "^13.1.0" }, "engines": { "node": ">=16.0.0", @@ -5545,6 +5534,12 @@ "node": ">=8" } }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", @@ -5904,43 +5899,43 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", - "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "devOptional": true, "peer": true, "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, "node_modules/@jridgewell/sourcemap-codec": { @@ -5949,9 +5944,9 @@ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", - "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -6419,14 +6414,6 @@ "tslib": "^2.3.0" } }, - "node_modules/@lit-protocol/contracts-sdk/node_modules/jose": { - "version": "4.15.5", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.5.tgz", - "integrity": "sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, "node_modules/@lit-protocol/contracts-sdk/node_modules/multiformats": { "version": "12.1.3", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-12.1.3.tgz", @@ -6690,14 +6677,6 @@ "tslib": "^2.3.0" } }, - "node_modules/@lit-protocol/core/node_modules/jose": { - "version": "4.15.5", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.5.tgz", - "integrity": "sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, "node_modules/@lit-protocol/core/node_modules/multiformats": { "version": "12.1.3", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-12.1.3.tgz", @@ -7289,14 +7268,6 @@ "tslib": "^2.3.0" } }, - "node_modules/@lit-protocol/lit-node-client-nodejs/node_modules/jose": { - "version": "4.15.5", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.5.tgz", - "integrity": "sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, "node_modules/@lit-protocol/lit-node-client-nodejs/node_modules/multiformats": { "version": "12.1.3", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-12.1.3.tgz", @@ -7890,14 +7861,6 @@ "ieee754": "^1.1.13" } }, - "node_modules/@lit-protocol/lit-node-client/node_modules/jose": { - "version": "4.15.5", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.5.tgz", - "integrity": "sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, "node_modules/@lit-protocol/lit-node-client/node_modules/multiformats": { "version": "12.1.3", "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-12.1.3.tgz", @@ -8335,46 +8298,52 @@ } }, "node_modules/@logto/client": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@logto/client/-/client-2.3.3.tgz", - "integrity": "sha512-iPRGBNQsaKgP1eMMbWZgCp1cFCPzakDipenJ+927+JKQkFxCZYfshjvACSu3XW/vV3dFx2q8ld+B/Nl/Vt202A==", + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/@logto/client/-/client-2.6.6.tgz", + "integrity": "sha512-QT7jMnzEIWHBNrf9/M8p1OErRBbbNZjoekXGji5aZCyUh975hh8+GEBL21HV71FT3H/5Cq4Gf1GzUbAIW3izMA==", "dependencies": { - "@logto/js": "^3.0.2", + "@logto/js": "^4.1.1", "@silverhand/essentials": "^2.8.7", "camelcase-keys": "^7.0.1", - "jose": "^5.0.0" + "jose": "^5.2.2" + } + }, + "node_modules/@logto/client/node_modules/jose": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.2.4.tgz", + "integrity": "sha512-6ScbIk2WWCeXkmzF6bRPmEuaqy1m8SbsRFMa/FLrSCkGIhj8OLVG/IH+XHVmNMx/KUo8cVWEE6oKR4dJ+S0Rkg==", + "funding": { + "url": "https://github.com/sponsors/panva" } }, "node_modules/@logto/express": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@logto/express/-/express-2.3.0.tgz", - "integrity": "sha512-tvbXQdztJ3zpaiJFq38IYMyjxRUpstazYTsVF4eY+blYyTfSVcKOJ+GUOhBLheCo18qdhAzIU/rrOiqdFsPShA==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@logto/express/-/express-2.3.8.tgz", + "integrity": "sha512-uCoxZi4NH6OKFyqs2px+071fdYzVGiMI7B5/mZXeQ1PT6/3LIkYSrXcXioxqTp0YREaqOEbgdn+xhdgY5Pz1Iw==", "dependencies": { - "@logto/node": "^2.3.0" + "@logto/node": "^2.4.7" }, "peerDependencies": { "express": ">=4" } }, "node_modules/@logto/js": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@logto/js/-/js-3.0.2.tgz", - "integrity": "sha512-VfrVoNNPSO1t7J/BKIU+C1G4efbim+FHNn2xvSpvNG22WmLPnsMbx0c8A10pwM58+BpPhVGQTxrvaw06LbpU7Q==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@logto/js/-/js-4.1.1.tgz", + "integrity": "sha512-+RgthBvDw30UojirtAjZeHNfOwDQVURmpjcIBYTIf6afx5F5jJq8b1D/eaFbrCFrmXmatkT2iN7X8kYHui86WQ==", "dependencies": { "@silverhand/essentials": "^2.8.7", - "camelcase-keys": "^7.0.1", - "jose": "^5.0.0" + "camelcase-keys": "^7.0.1" } }, "node_modules/@logto/node": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@logto/node/-/node-2.3.0.tgz", - "integrity": "sha512-i9Qwkrt2wP92JonceD5YUxcJSBaUd/O0+9j38QeAR479sHVqBb+LX5me5f65wjr1d3zXD+whX6aVZt4bIgr1TA==", + "version": "2.4.7", + "resolved": "https://registry.npmjs.org/@logto/node/-/node-2.4.7.tgz", + "integrity": "sha512-AlANeqY1NIt93EBcRzrTmyAVHXOHpszTJK+qe1ok50rmZlTmX2p7yQvrg0/Ehwf/+4Rla5vooAR+HIFMaOmPpQ==", "dependencies": { - "@logto/client": "^2.3.3", + "@logto/client": "^2.6.6", "@silverhand/essentials": "^2.8.7", - "js-base64": "^3.7.4", - "node-fetch": "^2.6.7" + "js-base64": "^3.7.4" } }, "node_modules/@mapbox/node-pre-gyp": { @@ -8407,45 +8376,6 @@ "node": ">= 6.0.0" } }, - "node_modules/@mapbox/node-pre-gyp/node_modules/are-we-there-yet": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", - "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/detect-libc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/gauge": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", - "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.2", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.1", - "object-assign": "^4.1.1", - "signal-exit": "^3.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.2" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@mapbox/node-pre-gyp/node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", @@ -8458,52 +8388,6 @@ "node": ">= 6" } }, - "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/npmlog": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", - "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", - "dependencies": { - "are-we-there-yet": "^2.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^3.0.0", - "set-blocking": "^2.0.0" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/@motionone/animation": { "version": "10.17.0", "resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.17.0.tgz", @@ -8608,11 +8492,11 @@ } }, "node_modules/@noble/curves": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.3.0.tgz", - "integrity": "sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.0.tgz", + "integrity": "sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg==", "dependencies": { - "@noble/hashes": "1.3.3" + "@noble/hashes": "1.4.0" }, "funding": { "url": "https://paulmillr.com/funding/" @@ -8630,9 +8514,9 @@ ] }, "node_modules/@noble/hashes": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", - "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", "engines": { "node": ">= 16" }, @@ -8679,7 +8563,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", - "optional": true, + "devOptional": true, "dependencies": { "@gar/promisify": "^1.0.1", "semver": "^7.3.5" @@ -8690,7 +8574,7 @@ "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", "deprecated": "This functionality has been moved to @npmcli/fs", - "optional": true, + "devOptional": true, "dependencies": { "mkdirp": "^1.0.4", "rimraf": "^3.0.2" @@ -8709,16 +8593,16 @@ } }, "node_modules/@octokit/core": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.1.0.tgz", - "integrity": "sha512-BDa2VAMLSh3otEiaMJ/3Y36GU4qf6GI+VivQ/P41NC6GHcdxpKlqV0ikSZ5gdQsmS3ojXeRx5vasgNTinF0Q4g==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.0.tgz", + "integrity": "sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg==", "dev": true, "dependencies": { "@octokit/auth-token": "^4.0.0", - "@octokit/graphql": "^7.0.0", - "@octokit/request": "^8.0.2", - "@octokit/request-error": "^5.0.0", - "@octokit/types": "^12.0.0", + "@octokit/graphql": "^7.1.0", + "@octokit/request": "^8.3.1", + "@octokit/request-error": "^5.1.0", + "@octokit/types": "^13.0.0", "before-after-hook": "^2.2.0", "universal-user-agent": "^6.0.0" }, @@ -8727,12 +8611,12 @@ } }, "node_modules/@octokit/endpoint": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.4.tgz", - "integrity": "sha512-DWPLtr1Kz3tv8L0UvXTDP1fNwM0S+z6EJpRcvH66orY6Eld4XBMCSYsaWp4xIm61jTWxK68BrR7ibO+vSDnZqw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.5.tgz", + "integrity": "sha512-ekqR4/+PCLkEBF6qgj8WqJfvDq65RH85OAgrtnVp1mSxaXF03u2xW/hUdweGS5654IlC0wkNYC18Z50tSYTAFw==", "dev": true, "dependencies": { - "@octokit/types": "^12.0.0", + "@octokit/types": "^13.1.0", "universal-user-agent": "^6.0.0" }, "engines": { @@ -8740,13 +8624,13 @@ } }, "node_modules/@octokit/graphql": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.0.2.tgz", - "integrity": "sha512-OJ2iGMtj5Tg3s6RaXH22cJcxXRi7Y3EBqbHTBRq+PQAqfaS8f/236fUrWhfSn8P4jovyzqucxme7/vWSSZBX2Q==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.0.tgz", + "integrity": "sha512-r+oZUH7aMFui1ypZnAvZmn0KSqAUgE1/tUXIWaqUCa1758ts/Jio84GZuzsvUkme98kv0WFY8//n0J1Z+vsIsQ==", "dev": true, "dependencies": { - "@octokit/request": "^8.0.1", - "@octokit/types": "^12.0.0", + "@octokit/request": "^8.3.0", + "@octokit/types": "^13.0.0", "universal-user-agent": "^6.0.0" }, "engines": { @@ -8754,24 +8638,39 @@ } }, "node_modules/@octokit/openapi-types": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-19.1.0.tgz", - "integrity": "sha512-6G+ywGClliGQwRsjvqVYpklIfa7oRPA0vyhPQG/1Feh+B+wU0vGH1JiJ5T25d3g1JZYBHzR2qefLi9x8Gt+cpw==", + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.1.0.tgz", + "integrity": "sha512-pGUdSP+eEPfZiQHNkZI0U01HLipxncisdJQB4G//OAmfeO8sqTQ9KRa0KF03TUPCziNsoXUrTg4B2Q1EX++T0Q==", "dev": true }, "node_modules/@octokit/plugin-paginate-rest": { - "version": "9.1.5", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.1.5.tgz", - "integrity": "sha512-WKTQXxK+bu49qzwv4qKbMMRXej1DU2gq017euWyKVudA6MldaSSQuxtz+vGbhxV4CjxpUxjZu6rM2wfc1FiWVg==", + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.1.tgz", + "integrity": "sha512-wfGhE/TAkXZRLjksFXuDZdmGnJQHvtU/joFQdweXUgzo1XwvBCD4o4+75NtFfjfLK5IwLf9vHTfSiU3sLRYpRw==", "dev": true, "dependencies": { - "@octokit/types": "^12.4.0" + "@octokit/types": "^12.6.0" }, "engines": { "node": ">= 18" }, "peerDependencies": { - "@octokit/core": ">=5" + "@octokit/core": "5" + } + }, + "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz", + "integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==", + "dev": true + }, + "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz", + "integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==", + "dev": true, + "dependencies": { + "@octokit/openapi-types": "^20.0.0" } }, "node_modules/@octokit/plugin-retry": { @@ -8791,10 +8690,25 @@ "@octokit/core": ">=5" } }, + "node_modules/@octokit/plugin-retry/node_modules/@octokit/openapi-types": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz", + "integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==", + "dev": true + }, + "node_modules/@octokit/plugin-retry/node_modules/@octokit/types": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz", + "integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==", + "dev": true, + "dependencies": { + "@octokit/openapi-types": "^20.0.0" + } + }, "node_modules/@octokit/plugin-throttling": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-8.1.3.tgz", - "integrity": "sha512-pfyqaqpc0EXh5Cn4HX9lWYsZ4gGbjnSmUILeu4u2gnuM50K/wIk9s1Pxt3lVeVwekmITgN/nJdoh43Ka+vye8A==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-8.2.0.tgz", + "integrity": "sha512-nOpWtLayKFpgqmgD0y3GqXafMFuKcA4tRPZIfu7BArd2lEZeb1988nhWhwx4aZWmjDmUfdgVf7W+Tt4AmvRmMQ==", "dev": true, "dependencies": { "@octokit/types": "^12.2.0", @@ -8807,15 +8721,30 @@ "@octokit/core": "^5.0.0" } }, + "node_modules/@octokit/plugin-throttling/node_modules/@octokit/openapi-types": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz", + "integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==", + "dev": true + }, + "node_modules/@octokit/plugin-throttling/node_modules/@octokit/types": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz", + "integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==", + "dev": true, + "dependencies": { + "@octokit/openapi-types": "^20.0.0" + } + }, "node_modules/@octokit/request": { - "version": "8.1.6", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.1.6.tgz", - "integrity": "sha512-YhPaGml3ncZC1NfXpP3WZ7iliL1ap6tLkAp6MvbK2fTTPytzVUyUesBBogcdMm86uRYO5rHaM1xIWxigWZ17MQ==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.0.tgz", + "integrity": "sha512-9Bb014e+m2TgBeEJGEbdplMVWwPmL1FPtggHQRkV+WVsMggPtEkLKPlcVYm/o8xKLkpJ7B+6N8WfQMtDLX2Dpw==", "dev": true, "dependencies": { - "@octokit/endpoint": "^9.0.0", - "@octokit/request-error": "^5.0.0", - "@octokit/types": "^12.0.0", + "@octokit/endpoint": "^9.0.1", + "@octokit/request-error": "^5.1.0", + "@octokit/types": "^13.1.0", "universal-user-agent": "^6.0.0" }, "engines": { @@ -8823,12 +8752,12 @@ } }, "node_modules/@octokit/request-error": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.0.1.tgz", - "integrity": "sha512-X7pnyTMV7MgtGmiXBwmO6M5kIPrntOXdyKZLigNfQWSEQzVxR4a4vo49vJjTWX70mPndj8KhfT4Dx+2Ng3vnBQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.1.0.tgz", + "integrity": "sha512-GETXfE05J0+7H2STzekpKObFe765O5dlAKUTLNGeH+x47z7JjXHfsHKo5z21D/o/IOZTUEI6nyWyR+bZVP/n5Q==", "dev": true, "dependencies": { - "@octokit/types": "^12.0.0", + "@octokit/types": "^13.1.0", "deprecation": "^2.0.0", "once": "^1.4.0" }, @@ -8837,12 +8766,12 @@ } }, "node_modules/@octokit/types": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.4.0.tgz", - "integrity": "sha512-FLWs/AvZllw/AGVs+nJ+ELCDZZJk+kY0zMen118xhL2zD0s1etIUHm1odgjP7epxYU1ln7SZxEUWYop5bhsdgQ==", + "version": "13.4.1", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.4.1.tgz", + "integrity": "sha512-Y73oOAzRBAUzR/iRAbGULzpNkX8vaxKCqEtg6K74Ff3w9f5apFnWtE/2nade7dMWWW3bS5Kkd6DJS4HF04xreg==", "dev": true, "dependencies": { - "@octokit/openapi-types": "^19.1.0" + "@octokit/openapi-types": "^22.1.0" } }, "node_modules/@parcel/watcher": { @@ -9130,6 +9059,17 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/@parcel/watcher/node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/@parcel/watcher/node_modules/node-addon-api": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.0.tgz", @@ -9160,15 +9100,15 @@ } }, "node_modules/@peculiar/webcrypto": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.5.tgz", - "integrity": "sha512-oDk93QCDGdxFRM8382Zdminzs44dg3M2+E5Np+JWkpqLDyJC9DviMh8F8mEJkYuUcUOGA5jHO5AJJ10MFWdbZw==", + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.6.tgz", + "integrity": "sha512-YBcMfqNSwn3SujUJvAaySy5tlYbYm6tVt9SKoXu8BaTdKGROiJDgPR3TXpZdAKUfklzm3lRapJEAltiMQtBgZg==", "dependencies": { "@peculiar/asn1-schema": "^2.3.8", "@peculiar/json-schema": "^1.1.12", "pvtsutils": "^1.3.5", "tslib": "^2.6.2", - "webcrypto-core": "^1.7.8" + "webcrypto-core": "^1.7.9" }, "engines": { "node": ">=10.12.0" @@ -9294,21 +9234,21 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "node_modules/@react-native-community/cli": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-12.3.2.tgz", - "integrity": "sha512-WgoUWwLDcf/G1Su2COUUVs3RzAwnV/vUTdISSpAUGgSc57mPabaAoUctKTnfYEhCnE3j02k3VtaVPwCAFRO3TQ==", + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-12.3.6.tgz", + "integrity": "sha512-647OSi6xBb8FbwFqX9zsJxOzu685AWtrOUWHfOkbKD+5LOpGORw+GQo0F9rWZnB68rLQyfKUZWJeaD00pGv5fw==", "optional": true, "peer": true, "dependencies": { - "@react-native-community/cli-clean": "12.3.2", - "@react-native-community/cli-config": "12.3.2", - "@react-native-community/cli-debugger-ui": "12.3.2", - "@react-native-community/cli-doctor": "12.3.2", - "@react-native-community/cli-hermes": "12.3.2", - "@react-native-community/cli-plugin-metro": "12.3.2", - "@react-native-community/cli-server-api": "12.3.2", - "@react-native-community/cli-tools": "12.3.2", - "@react-native-community/cli-types": "12.3.2", + "@react-native-community/cli-clean": "12.3.6", + "@react-native-community/cli-config": "12.3.6", + "@react-native-community/cli-debugger-ui": "12.3.6", + "@react-native-community/cli-doctor": "12.3.6", + "@react-native-community/cli-hermes": "12.3.6", + "@react-native-community/cli-plugin-metro": "12.3.6", + "@react-native-community/cli-server-api": "12.3.6", + "@react-native-community/cli-tools": "12.3.6", + "@react-native-community/cli-types": "12.3.6", "chalk": "^4.1.2", "commander": "^9.4.1", "deepmerge": "^4.3.0", @@ -9327,25 +9267,25 @@ } }, "node_modules/@react-native-community/cli-clean": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-12.3.2.tgz", - "integrity": "sha512-90k2hCX0ddSFPT7EN7h5SZj0XZPXP0+y/++v262hssoey3nhurwF57NGWN0XAR0o9BSW7+mBfeInfabzDraO6A==", + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-12.3.6.tgz", + "integrity": "sha512-gUU29ep8xM0BbnZjwz9MyID74KKwutq9x5iv4BCr2im6nly4UMf1B1D+V225wR7VcDGzbgWjaezsJShLLhC5ig==", "optional": true, "peer": true, "dependencies": { - "@react-native-community/cli-tools": "12.3.2", + "@react-native-community/cli-tools": "12.3.6", "chalk": "^4.1.2", "execa": "^5.0.0" } }, "node_modules/@react-native-community/cli-config": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-12.3.2.tgz", - "integrity": "sha512-UUCzDjQgvAVL/57rL7eOuFUhd+d+6qfM7V8uOegQFeFEmSmvUUDLYoXpBa5vAK9JgQtSqMBJ1Shmwao+/oElxQ==", + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-12.3.6.tgz", + "integrity": "sha512-JGWSYQ9EAK6m2v0abXwFLEfsqJ1zkhzZ4CV261QZF9MoUNB6h57a274h1MLQR9mG6Tsh38wBUuNfEPUvS1vYew==", "optional": true, "peer": true, "dependencies": { - "@react-native-community/cli-tools": "12.3.2", + "@react-native-community/cli-tools": "12.3.6", "chalk": "^4.1.2", "cosmiconfig": "^5.1.0", "deepmerge": "^4.3.0", @@ -9354,9 +9294,9 @@ } }, "node_modules/@react-native-community/cli-debugger-ui": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-12.3.2.tgz", - "integrity": "sha512-nSWQUL+51J682DlfcC1bjkUbQbGvHCC25jpqTwHIjmmVjYCX1uHuhPSqQKgPNdvtfOkrkACxczd7kVMmetxY2Q==", + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-12.3.6.tgz", + "integrity": "sha512-SjUKKsx5FmcK9G6Pb6UBFT0s9JexVStK5WInmANw75Hm7YokVvHEgtprQDz2Uvy5znX5g2ujzrkIU//T15KQzA==", "optional": true, "peer": true, "dependencies": { @@ -9364,23 +9304,22 @@ } }, "node_modules/@react-native-community/cli-doctor": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-12.3.2.tgz", - "integrity": "sha512-GrAabdY4qtBX49knHFvEAdLtCjkmndjTeqhYO6BhsbAeKOtspcLT/0WRgdLIaKODRa61ADNB3K5Zm4dU0QrZOg==", + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-12.3.6.tgz", + "integrity": "sha512-fvBDv2lTthfw4WOQKkdTop2PlE9GtfrlNnpjB818MhcdEnPjfQw5YaTUcnNEGsvGomdCs1MVRMgYXXwPSN6OvQ==", "optional": true, "peer": true, "dependencies": { - "@react-native-community/cli-config": "12.3.2", - "@react-native-community/cli-platform-android": "12.3.2", - "@react-native-community/cli-platform-ios": "12.3.2", - "@react-native-community/cli-tools": "12.3.2", + "@react-native-community/cli-config": "12.3.6", + "@react-native-community/cli-platform-android": "12.3.6", + "@react-native-community/cli-platform-ios": "12.3.6", + "@react-native-community/cli-tools": "12.3.6", "chalk": "^4.1.2", "command-exists": "^1.2.8", "deepmerge": "^4.3.0", "envinfo": "^7.10.0", "execa": "^5.0.0", "hermes-profile-transformer": "^0.0.6", - "ip": "^1.1.5", "node-stream-zip": "^1.9.1", "ora": "^5.4.1", "semver": "^7.5.2", @@ -9559,27 +9498,26 @@ } }, "node_modules/@react-native-community/cli-hermes": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-12.3.2.tgz", - "integrity": "sha512-SL6F9O8ghp4ESBFH2YAPLtIN39jdnvGBKnK4FGKpDCjtB3DnUmDsGFlH46S+GGt5M6VzfG2eeKEOKf3pZ6jUzA==", + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-12.3.6.tgz", + "integrity": "sha512-sNGwfOCl8OAIjWCkwuLpP8NZbuO0dhDI/2W7NeOGDzIBsf4/c4MptTrULWtGIH9okVPLSPX0NnRyGQ+mSwWyuQ==", "optional": true, "peer": true, "dependencies": { - "@react-native-community/cli-platform-android": "12.3.2", - "@react-native-community/cli-tools": "12.3.2", + "@react-native-community/cli-platform-android": "12.3.6", + "@react-native-community/cli-tools": "12.3.6", "chalk": "^4.1.2", - "hermes-profile-transformer": "^0.0.6", - "ip": "^1.1.5" + "hermes-profile-transformer": "^0.0.6" } }, "node_modules/@react-native-community/cli-platform-android": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-12.3.2.tgz", - "integrity": "sha512-MZ5nO8yi/N+Fj2i9BJcJ9C/ez+9/Ir7lQt49DWRo9YDmzye66mYLr/P2l/qxsixllbbDi7BXrlLpxaEhMrDopg==", + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-12.3.6.tgz", + "integrity": "sha512-DeDDAB8lHpuGIAPXeeD9Qu2+/wDTFPo99c8uSW49L0hkmZJixzvvvffbGQAYk32H0TmaI7rzvzH+qzu7z3891g==", "optional": true, "peer": true, "dependencies": { - "@react-native-community/cli-tools": "12.3.2", + "@react-native-community/cli-tools": "12.3.6", "chalk": "^4.1.2", "execa": "^5.0.0", "fast-xml-parser": "^4.2.4", @@ -9588,13 +9526,13 @@ } }, "node_modules/@react-native-community/cli-platform-ios": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-12.3.2.tgz", - "integrity": "sha512-OcWEAbkev1IL6SUiQnM6DQdsvfsKZhRZtoBNSj9MfdmwotVZSOEZJ+IjZ1FR9ChvMWayO9ns/o8LgoQxr1ZXeg==", + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-12.3.6.tgz", + "integrity": "sha512-3eZ0jMCkKUO58wzPWlvAPRqezVKm9EPZyaPyHbRPWU8qw7JqkvnRlWIaYDGpjCJgVW4k2hKsEursLtYKb188tg==", "optional": true, "peer": true, "dependencies": { - "@react-native-community/cli-tools": "12.3.2", + "@react-native-community/cli-tools": "12.3.6", "chalk": "^4.1.2", "execa": "^5.0.0", "fast-xml-parser": "^4.0.12", @@ -9736,21 +9674,21 @@ } }, "node_modules/@react-native-community/cli-plugin-metro": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-12.3.2.tgz", - "integrity": "sha512-FpFBwu+d2E7KRhYPTkKvQsWb2/JKsJv+t1tcqgQkn+oByhp+qGyXBobFB8/R3yYvRRDCSDhS+atWTJzk9TjM8g==", + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-12.3.6.tgz", + "integrity": "sha512-3jxSBQt4fkS+KtHCPSyB5auIT+KKIrPCv9Dk14FbvOaEh9erUWEm/5PZWmtboW1z7CYeNbFMeXm9fM2xwtVOpg==", "optional": true, "peer": true }, "node_modules/@react-native-community/cli-server-api": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-12.3.2.tgz", - "integrity": "sha512-iwa7EO9XFA/OjI5pPLLpI/6mFVqv8L73kNck3CNOJIUCCveGXBKK0VMyOkXaf/BYnihgQrXh+x5cxbDbggr7+Q==", + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-12.3.6.tgz", + "integrity": "sha512-80NIMzo8b2W+PL0Jd7NjiJW9mgaT8Y8wsIT/lh6mAvYH7mK0ecDJUYUTAAv79Tbo1iCGPAr3T295DlVtS8s4yQ==", "optional": true, "peer": true, "dependencies": { - "@react-native-community/cli-debugger-ui": "12.3.2", - "@react-native-community/cli-tools": "12.3.2", + "@react-native-community/cli-debugger-ui": "12.3.6", + "@react-native-community/cli-tools": "12.3.6", "compression": "^1.7.1", "connect": "^3.6.5", "errorhandler": "^1.5.1", @@ -9811,9 +9749,9 @@ "peer": true }, "node_modules/@react-native-community/cli-tools": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-12.3.2.tgz", - "integrity": "sha512-nDH7vuEicHI2TI0jac/DjT3fr977iWXRdgVAqPZFFczlbs7A8GQvEdGnZ1G8dqRUmg+kptw0e4hwczAOG89JzQ==", + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-12.3.6.tgz", + "integrity": "sha512-FPEvZn19UTMMXUp/piwKZSh8cMEfO8G3KDtOwo53O347GTcwNrKjgZGtLSPELBX2gr+YlzEft3CoRv2Qmo83fQ==", "optional": true, "peer": true, "dependencies": { @@ -10006,9 +9944,9 @@ "peer": true }, "node_modules/@react-native-community/cli-types": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-12.3.2.tgz", - "integrity": "sha512-9D0UEFqLW8JmS16mjHJxUJWX8E+zJddrHILSH8AJHZ0NNHv4u2DXKdb0wFLMobFxGNxPT+VSOjc60fGvXzWHog==", + "version": "12.3.6", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-12.3.6.tgz", + "integrity": "sha512-xPqTgcUtZowQ8WKOkI9TLGBwH2bGggOC4d2FFaIRST3gTcjrEeGRNeR5aXCzJFIgItIft8sd7p2oKEdy90+01Q==", "optional": true, "peer": true, "dependencies": { @@ -10127,22 +10065,22 @@ } }, "node_modules/@react-native/babel-plugin-codegen": { - "version": "0.73.3", - "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.73.3.tgz", - "integrity": "sha512-+zQrDDbz6lB48LyzFHxNCgXDCBHH+oTRdXAjikRcBUdeG9St9ABbYFLtb799zSxLOrCqFVyXqhJR2vlgLLEbcg==", + "version": "0.75.0-main", + "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.75.0-main.tgz", + "integrity": "sha512-gEl+bl+orntqNA3yGETGeHLNzDnZuQfO074BreX/l80WnZbx00/BJ57IkZ372j6I+gjki+3dYeRQOp82m/sUWQ==", "optional": true, "peer": true, "dependencies": { - "@react-native/codegen": "0.73.2" + "@react-native/codegen": "0.75.0-main" }, "engines": { "node": ">=18" } }, "node_modules/@react-native/babel-preset": { - "version": "0.73.20", - "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.73.20.tgz", - "integrity": "sha512-fU9NqkusbfFq71l4BWQfqqD/lLcLC0MZ++UYgieA3j8lIEppJTLVauv2RwtD2yltBkjebgYEC5Rwvt1l0MUBXw==", + "version": "0.75.0-main", + "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.75.0-main.tgz", + "integrity": "sha512-yTyft0jSbTEfTfDUUfllJqKWLl3rNMiVMFjuWzMigikKAlSwKKUC/DxTEUfMwekFU05TjDyEOtigOTrm2yuoRQ==", "optional": true, "peer": true, "dependencies": { @@ -10150,6 +10088,7 @@ "@babel/plugin-proposal-async-generator-functions": "^7.0.0", "@babel/plugin-proposal-class-properties": "^7.18.0", "@babel/plugin-proposal-export-default-from": "^7.0.0", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.0", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.0", "@babel/plugin-proposal-numeric-separator": "^7.0.0", "@babel/plugin-proposal-object-rest-spread": "^7.20.0", @@ -10185,7 +10124,7 @@ "@babel/plugin-transform-typescript": "^7.5.0", "@babel/plugin-transform-unicode-regex": "^7.0.0", "@babel/template": "^7.0.0", - "@react-native/babel-plugin-codegen": "0.73.3", + "@react-native/babel-plugin-codegen": "0.75.0-main", "babel-plugin-transform-flow-enums": "^0.0.2", "react-refresh": "^0.14.0" }, @@ -10197,15 +10136,15 @@ } }, "node_modules/@react-native/codegen": { - "version": "0.73.2", - "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.73.2.tgz", - "integrity": "sha512-lfy8S7umhE3QLQG5ViC4wg5N1Z+E6RnaeIw8w1voroQsXXGPB72IBozh8dAHR3+ceTxIU0KX3A8OpJI8e1+HpQ==", + "version": "0.75.0-main", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.75.0-main.tgz", + "integrity": "sha512-vcIu7x7o/3xn9UQdOPqA6B/jtxDHB+xTIDlVe7nym+0ua/OIOwYoVscTb0NtHuEjGKO1G5CTWNhl34BFhIs0+g==", "optional": true, "peer": true, "dependencies": { "@babel/parser": "^7.20.0", - "flow-parser": "^0.206.0", "glob": "^7.1.1", + "hermes-parser": "0.20.1", "invariant": "^2.2.4", "jscodeshift": "^0.14.0", "mkdirp": "^0.5.1", @@ -10232,16 +10171,16 @@ } }, "node_modules/@react-native/community-cli-plugin": { - "version": "0.73.14", - "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.73.14.tgz", - "integrity": "sha512-KzIwsTvAJrXPtwhGOSm+OcJH1B8TpY8cS4xxzu/e2qv3a2n4VLePHTPAfco1tmvekV8OHWvvD9JSIX7i2fB1gg==", + "version": "0.73.17", + "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.73.17.tgz", + "integrity": "sha512-F3PXZkcHg+1ARIr6FRQCQiB7ZAA+MQXGmq051metRscoLvgYJwj7dgC8pvgy0kexzUkHu5BNKrZeySzUft3xuQ==", "optional": true, "peer": true, "dependencies": { - "@react-native-community/cli-server-api": "12.3.2", - "@react-native-community/cli-tools": "12.3.2", - "@react-native/dev-middleware": "0.73.7", - "@react-native/metro-babel-transformer": "0.73.14", + "@react-native-community/cli-server-api": "12.3.6", + "@react-native-community/cli-tools": "12.3.6", + "@react-native/dev-middleware": "0.73.8", + "@react-native/metro-babel-transformer": "0.73.15", "chalk": "^4.0.0", "execa": "^5.1.1", "metro": "^0.80.3", @@ -10265,9 +10204,9 @@ } }, "node_modules/@react-native/dev-middleware": { - "version": "0.73.7", - "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.73.7.tgz", - "integrity": "sha512-BZXpn+qKp/dNdr4+TkZxXDttfx8YobDh8MFHsMk9usouLm22pKgFIPkGBV0X8Do4LBkFNPGtrnsKkWk/yuUXKg==", + "version": "0.73.8", + "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.73.8.tgz", + "integrity": "sha512-oph4NamCIxkMfUL/fYtSsE+JbGOnrlawfQ0kKtDQ5xbOjPKotKoXqrs1eGwozNKv7FfQ393stk1by9a6DyASSg==", "optional": true, "peer": true, "dependencies": { @@ -10280,7 +10219,8 @@ "node-fetch": "^2.2.0", "open": "^7.0.3", "serve-static": "^1.13.1", - "temp-dir": "^2.0.0" + "temp-dir": "^2.0.0", + "ws": "^6.2.2" }, "engines": { "node": ">=18" @@ -10320,6 +10260,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@react-native/dev-middleware/node_modules/ws": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", + "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", + "optional": true, + "peer": true, + "dependencies": { + "async-limiter": "~1.0.0" + } + }, "node_modules/@react-native/gradle-plugin": { "version": "0.73.4", "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.73.4.tgz", @@ -10341,14 +10291,14 @@ } }, "node_modules/@react-native/metro-babel-transformer": { - "version": "0.73.14", - "resolved": "https://registry.npmjs.org/@react-native/metro-babel-transformer/-/metro-babel-transformer-0.73.14.tgz", - "integrity": "sha512-5wLeYw/lormpSqYfI9H/geZ/EtPmi+x5qLkEit15Q/70hkzYo/M+aWztUtbOITfgTEOP8d6ybROzoGsqgyZLcw==", + "version": "0.73.15", + "resolved": "https://registry.npmjs.org/@react-native/metro-babel-transformer/-/metro-babel-transformer-0.73.15.tgz", + "integrity": "sha512-LlkSGaXCz+xdxc9819plmpsl4P4gZndoFtpjN3GMBIu6f7TBV0GVbyJAU4GE8fuAWPVSVL5ArOcdkWKSbI1klw==", "optional": true, "peer": true, "dependencies": { "@babel/core": "^7.20.0", - "@react-native/babel-preset": "0.73.20", + "@react-native/babel-preset": "0.73.21", "hermes-parser": "0.15.0", "nullthrows": "^1.1.1" }, @@ -10359,6 +10309,138 @@ "@babel/core": "*" } }, + "node_modules/@react-native/metro-babel-transformer/node_modules/@react-native/babel-plugin-codegen": { + "version": "0.73.4", + "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.73.4.tgz", + "integrity": "sha512-XzRd8MJGo4Zc5KsphDHBYJzS1ryOHg8I2gOZDAUCGcwLFhdyGu1zBNDJYH2GFyDrInn9TzAbRIf3d4O+eltXQQ==", + "optional": true, + "peer": true, + "dependencies": { + "@react-native/codegen": "0.73.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/metro-babel-transformer/node_modules/@react-native/babel-preset": { + "version": "0.73.21", + "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.73.21.tgz", + "integrity": "sha512-WlFttNnySKQMeujN09fRmrdWqh46QyJluM5jdtDNrkl/2Hx6N4XeDUGhABvConeK95OidVO7sFFf7sNebVXogA==", + "optional": true, + "peer": true, + "dependencies": { + "@babel/core": "^7.20.0", + "@babel/plugin-proposal-async-generator-functions": "^7.0.0", + "@babel/plugin-proposal-class-properties": "^7.18.0", + "@babel/plugin-proposal-export-default-from": "^7.0.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.0", + "@babel/plugin-proposal-numeric-separator": "^7.0.0", + "@babel/plugin-proposal-object-rest-spread": "^7.20.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.0.0", + "@babel/plugin-proposal-optional-chaining": "^7.20.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-export-default-from": "^7.0.0", + "@babel/plugin-syntax-flow": "^7.18.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.0.0", + "@babel/plugin-syntax-optional-chaining": "^7.0.0", + "@babel/plugin-transform-arrow-functions": "^7.0.0", + "@babel/plugin-transform-async-to-generator": "^7.20.0", + "@babel/plugin-transform-block-scoping": "^7.0.0", + "@babel/plugin-transform-classes": "^7.0.0", + "@babel/plugin-transform-computed-properties": "^7.0.0", + "@babel/plugin-transform-destructuring": "^7.20.0", + "@babel/plugin-transform-flow-strip-types": "^7.20.0", + "@babel/plugin-transform-function-name": "^7.0.0", + "@babel/plugin-transform-literals": "^7.0.0", + "@babel/plugin-transform-modules-commonjs": "^7.0.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.0.0", + "@babel/plugin-transform-parameters": "^7.0.0", + "@babel/plugin-transform-private-methods": "^7.22.5", + "@babel/plugin-transform-private-property-in-object": "^7.22.11", + "@babel/plugin-transform-react-display-name": "^7.0.0", + "@babel/plugin-transform-react-jsx": "^7.0.0", + "@babel/plugin-transform-react-jsx-self": "^7.0.0", + "@babel/plugin-transform-react-jsx-source": "^7.0.0", + "@babel/plugin-transform-runtime": "^7.0.0", + "@babel/plugin-transform-shorthand-properties": "^7.0.0", + "@babel/plugin-transform-spread": "^7.0.0", + "@babel/plugin-transform-sticky-regex": "^7.0.0", + "@babel/plugin-transform-typescript": "^7.5.0", + "@babel/plugin-transform-unicode-regex": "^7.0.0", + "@babel/template": "^7.0.0", + "@react-native/babel-plugin-codegen": "0.73.4", + "babel-plugin-transform-flow-enums": "^0.0.2", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/@react-native/metro-babel-transformer/node_modules/@react-native/codegen": { + "version": "0.73.3", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.73.3.tgz", + "integrity": "sha512-sxslCAAb8kM06vGy9Jyh4TtvjhcP36k/rvj2QE2Jdhdm61KvfafCATSIsOfc0QvnduWFcpXUPvAVyYwuv7PYDg==", + "optional": true, + "peer": true, + "dependencies": { + "@babel/parser": "^7.20.0", + "flow-parser": "^0.206.0", + "glob": "^7.1.1", + "invariant": "^2.2.4", + "jscodeshift": "^0.14.0", + "mkdirp": "^0.5.1", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@babel/preset-env": "^7.1.6" + } + }, + "node_modules/@react-native/metro-babel-transformer/node_modules/flow-parser": { + "version": "0.206.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.206.0.tgz", + "integrity": "sha512-HVzoK3r6Vsg+lKvlIZzaWNBVai+FXTX1wdYhz/wVlH13tb/gOdLXmlTqy6odmTBhT5UoWUbq0k8263Qhr9d88w==", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/@react-native/metro-babel-transformer/node_modules/hermes-estree": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.15.0.tgz", + "integrity": "sha512-lLYvAd+6BnOqWdnNbP/Q8xfl8LOGw4wVjfrNd9Gt8eoFzhNBRVD95n4l2ksfMVOoxuVyegs85g83KS9QOsxbVQ==", + "optional": true, + "peer": true + }, + "node_modules/@react-native/metro-babel-transformer/node_modules/hermes-parser": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.15.0.tgz", + "integrity": "sha512-Q1uks5rjZlE9RjMMjSUCkGrEIPI5pKJILeCtK1VmTj7U4pf3wVPoo+cxfu+s4cBAPy2JzikIIdCZgBoR6x7U1Q==", + "optional": true, + "peer": true, + "dependencies": { + "hermes-estree": "0.15.0" + } + }, + "node_modules/@react-native/metro-babel-transformer/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "optional": true, + "peer": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, "node_modules/@react-native/normalize-color": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@react-native/normalize-color/-/normalize-color-2.1.0.tgz", @@ -10391,9 +10473,9 @@ } }, "node_modules/@scure/base": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.5.tgz", - "integrity": "sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.6.tgz", + "integrity": "sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g==", "funding": { "url": "https://paulmillr.com/funding/" } @@ -10574,9 +10656,9 @@ } }, "node_modules/@semantic-release/npm": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-11.0.2.tgz", - "integrity": "sha512-owtf3RjyPvRE63iUKZ5/xO4uqjRpVQDUB9+nnXj0xwfIeM9pRl+cG+zGDzdftR4m3f2s4Wyf3SexW+kF5DFtWA==", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-11.0.3.tgz", + "integrity": "sha512-KUsozQGhRBAnoVg4UMZj9ep436VEGwT536/jwSqB7vcEfA6oncCUU7UIYTRdLx7GvTtqn0kBjnkfLVkcnBa2YQ==", "dev": true, "dependencies": { "@semantic-release/error": "^4.0.0", @@ -10586,7 +10668,7 @@ "lodash-es": "^4.17.21", "nerf-dart": "^1.0.0", "normalize-url": "^8.0.0", - "npm": "^10.0.0", + "npm": "^10.5.0", "rc": "^1.2.8", "read-pkg": "^9.0.0", "registry-auth-token": "^5.0.0", @@ -10733,9 +10815,9 @@ } }, "node_modules/@semantic-release/npm/node_modules/npm-run-path": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", - "integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", "dev": true, "dependencies": { "path-key": "^4.0.0" @@ -10874,9 +10956,9 @@ } }, "node_modules/@sindresorhus/merge-streams": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-1.0.0.tgz", - "integrity": "sha512-rUV5WyJrJLoloD4NDN1V1+LDMDWOa4OTsT4yYJwQNpTU6FWxkxHpL7eu4w+DmiH8x/EAM1otkPE1+LaspIbplw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", "dev": true, "engines": { "node": ">=18" @@ -11152,7 +11234,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "optional": true, + "devOptional": true, "engines": { "node": ">= 6" } @@ -11302,14 +11384,6 @@ "node": ">=16" } }, - "node_modules/@transmute/jose-ld/node_modules/jose": { - "version": "4.15.4", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.4.tgz", - "integrity": "sha512-W+oqK4H+r5sITxfxpSU+MMdr/YSWGvgZMQDIsNoBDGGy4i7GBPTtvFKibQzW06n3U3TqHjhvBJsirShsEJ6eeQ==", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, "node_modules/@transmute/json-web-signature": { "version": "0.7.0-unstable.82", "resolved": "https://registry.npmjs.org/@transmute/json-web-signature/-/json-web-signature-0.7.0-unstable.82.tgz", @@ -11469,9 +11543,9 @@ } }, "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", "devOptional": true }, "node_modules/@tsconfig/node12": { @@ -11572,9 +11646,9 @@ } }, "node_modules/@types/cookie-parser": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.6.tgz", - "integrity": "sha512-KoooCrD56qlLskXPLGUiJxOMnv5l/8m7cQD2OxJ73NPMhuSz9PmvwRD6EpjDyKBVrdJDdQ4bQK7JFNHnNmax0w==", + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-Fvuyi354Z+uayxzIGCwYTayFKocfV7TuDYZClCdIP9ckhvAu/ixDtCB6qx2TT0FKjPLf1f3P/J1rgf6lPs64mw==", "dev": true, "dependencies": { "@types/express": "*" @@ -11598,9 +11672,9 @@ } }, "node_modules/@types/eslint": { - "version": "8.56.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz", - "integrity": "sha512-uQDwm1wFHmbBbCZCqAlq6Do9LYwByNZHWzXppSnay9SuwJ+VRbjkbLABer54kcPnMSlG6Fdiy2yaFXm/z9Z5gw==", + "version": "8.56.9", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.9.tgz", + "integrity": "sha512-W4W3KcqzjJ0sHg2vAq9vfml6OhsJ53TcUjUqfzzZf/EChUtwspszj/S0pzMxnfRcO55/iGq47dscXw71Fxc4Zg==", "dev": true, "peer": true, "dependencies": { @@ -11639,9 +11713,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.42", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.42.tgz", - "integrity": "sha512-ckM3jm2bf/MfB3+spLPWYPUH573plBFwpOhqQ2WottxYV85j1HQFlxmnTq57X1yHY9awZPig06hL/cLMgNWHIQ==", + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz", + "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==", "dev": true, "dependencies": { "@types/node": "*", @@ -11720,9 +11794,9 @@ "dev": true }, "node_modules/@types/jsonwebtoken": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.5.tgz", - "integrity": "sha512-VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA==", + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.6.tgz", + "integrity": "sha512-/5hndP5dCjloafCXns6SZyESp3Ldq7YjH3zwzwczYnjxIT0Fqzk5ROSYVGfFyczIue7IUEj8hkvLbPoLQ18vQw==", "dev": true, "dependencies": { "@types/node": "*" @@ -11750,9 +11824,9 @@ "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" }, "node_modules/@types/node": { - "version": "20.11.15", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.15.tgz", - "integrity": "sha512-gscmuADZfvNULx1eyirVbr3kVOVZtpQtzKMCZpeSZcN6MfbkRXAR4s9/gsQ4CzxLHw6EStDtKLNtSDL3vbq05A==", + "version": "20.12.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", + "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", "dependencies": { "undici-types": "~5.26.4" } @@ -11781,9 +11855,9 @@ } }, "node_modules/@types/qs": { - "version": "6.9.11", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz", - "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==", + "version": "6.9.15", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", "dev": true }, "node_modules/@types/range-parser": { @@ -11801,9 +11875,9 @@ } }, "node_modules/@types/semver": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", - "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true }, "node_modules/@types/send": { @@ -11817,14 +11891,14 @@ } }, "node_modules/@types/serve-static": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", - "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", "dev": true, "dependencies": { "@types/http-errors": "*", - "@types/mime": "*", - "@types/node": "*" + "@types/node": "*", + "@types/send": "*" } }, "node_modules/@types/stack-utils": { @@ -11861,9 +11935,9 @@ "dev": true }, "node_modules/@types/validator": { - "version": "13.11.8", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.8.tgz", - "integrity": "sha512-c/hzNDBh7eRF+KbCf+OoZxKbnkpaK/cKp9iLQWqB7muXtM+MtL9SUUH8vCFcLn6dH1Qm05jiexK0ofWY7TfOhQ==", + "version": "13.11.9", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.9.tgz", + "integrity": "sha512-FCTsikRozryfayPuiI46QzH3fnrOoctTjvOYZkho9BTFLCOZ2rgZJHMOVgCOfttjPJcgOx52EpkY0CMfy87MIw==", "dev": true }, "node_modules/@types/yargs": { @@ -12156,7 +12230,6 @@ "node_modules/@veramo-community/lds-ecdsa-secp256k1-recovery2020": { "version": "0.0.8", "resolved": "git+ssh://git@github.com/uport-project/EcdsaSecp256k1RecoverySignature2020.git#ab0db52de6f4e6663ef271a48009ba26e688ef9b", - "license": "Apache-2.0", "dependencies": { "@bitauth/libauth": "^1.19.1", "@digitalcredentials/jsonld": "^5.2.1", @@ -12332,9 +12405,9 @@ "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==" }, "node_modules/@veramo/did-provider-key/node_modules/ethers": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.10.0.tgz", - "integrity": "sha512-nMNwYHzs6V1FR3Y4cdfxSQmNgZsRj1RiTU25JwvnJLmyzw9z3SKxNc2XKDuiXXo/v9ds5Mp9m6HBabgYQQ26tA==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.12.0.tgz", + "integrity": "sha512-zL5NlOTjML239gIvtVJuaSk0N9GQLi1Hom3ZWUszE5lDTQE/IVB62mrPkQ2W1bGcZwVGSLaetQbWNQSvI4rGDQ==", "funding": [ { "type": "individual", @@ -12346,7 +12419,7 @@ } ], "dependencies": { - "@adraffy/ens-normalize": "1.10.0", + "@adraffy/ens-normalize": "1.10.1", "@noble/curves": "1.2.0", "@noble/hashes": "1.3.2", "@types/node": "18.15.13", @@ -12443,9 +12516,9 @@ "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==" }, "node_modules/@veramo/key-manager/node_modules/ethers": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.10.0.tgz", - "integrity": "sha512-nMNwYHzs6V1FR3Y4cdfxSQmNgZsRj1RiTU25JwvnJLmyzw9z3SKxNc2XKDuiXXo/v9ds5Mp9m6HBabgYQQ26tA==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.12.0.tgz", + "integrity": "sha512-zL5NlOTjML239gIvtVJuaSk0N9GQLi1Hom3ZWUszE5lDTQE/IVB62mrPkQ2W1bGcZwVGSLaetQbWNQSvI4rGDQ==", "funding": [ { "type": "individual", @@ -12457,7 +12530,7 @@ } ], "dependencies": { - "@adraffy/ens-normalize": "1.10.0", + "@adraffy/ens-normalize": "1.10.1", "@noble/curves": "1.2.0", "@noble/hashes": "1.3.2", "@types/node": "18.15.13", @@ -12560,9 +12633,9 @@ "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==" }, "node_modules/@veramo/kms-local/node_modules/ethers": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.10.0.tgz", - "integrity": "sha512-nMNwYHzs6V1FR3Y4cdfxSQmNgZsRj1RiTU25JwvnJLmyzw9z3SKxNc2XKDuiXXo/v9ds5Mp9m6HBabgYQQ26tA==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.12.0.tgz", + "integrity": "sha512-zL5NlOTjML239gIvtVJuaSk0N9GQLi1Hom3ZWUszE5lDTQE/IVB62mrPkQ2W1bGcZwVGSLaetQbWNQSvI4rGDQ==", "funding": [ { "type": "individual", @@ -12574,7 +12647,7 @@ } ], "dependencies": { - "@adraffy/ens-normalize": "1.10.0", + "@adraffy/ens-normalize": "1.10.1", "@noble/curves": "1.2.0", "@noble/hashes": "1.3.2", "@types/node": "18.15.13", @@ -12673,9 +12746,9 @@ "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==" }, "node_modules/@veramo/utils/node_modules/ethers": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.10.0.tgz", - "integrity": "sha512-nMNwYHzs6V1FR3Y4cdfxSQmNgZsRj1RiTU25JwvnJLmyzw9z3SKxNc2XKDuiXXo/v9ds5Mp9m6HBabgYQQ26tA==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.12.0.tgz", + "integrity": "sha512-zL5NlOTjML239gIvtVJuaSk0N9GQLi1Hom3ZWUszE5lDTQE/IVB62mrPkQ2W1bGcZwVGSLaetQbWNQSvI4rGDQ==", "funding": [ { "type": "individual", @@ -12687,7 +12760,7 @@ } ], "dependencies": { - "@adraffy/ens-normalize": "1.10.0", + "@adraffy/ens-normalize": "1.10.1", "@noble/curves": "1.2.0", "@noble/hashes": "1.3.2", "@types/node": "18.15.13", @@ -12742,13 +12815,13 @@ } }, "node_modules/@verida/account": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@verida/account/-/account-3.0.1.tgz", - "integrity": "sha512-5i77Hwk4mCSyUZuJQ8iMTsGYeq1rj6wM7mlpiuJLAK8Zj0JJwMP5x8oE5xsd9IWpNQ9xjFv8C6l/lYpe3425uA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@verida/account/-/account-3.0.2.tgz", + "integrity": "sha512-6nN46WCdN/A0W/jfL+5QJGDnfjdVBwAlNJrIaYQt2lw56xaXQV6YYndmKhu+RMvzfF4CWTY6sYl3u4LFiwJ1mw==", "dependencies": { - "@verida/keyring": "^3.0.1", - "@verida/storage-link": "^3.0.1", - "@verida/types": "^3.0.0", + "@verida/keyring": "^3.0.2", + "@verida/storage-link": "^3.0.2", + "@verida/types": "^3.0.1", "did-jwt": "^6.11.0", "did-resolver": "^4.0.1", "lodash": "^4.17.21", @@ -12759,16 +12832,16 @@ } }, "node_modules/@verida/account-node": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@verida/account-node/-/account-node-3.0.1.tgz", - "integrity": "sha512-S6zqCathYR/iRDYZBAa3B3Ze6LkQBdmBuNhWZvcW5KIlGMDwdUpg5N6VXZmhbrBSHUeYJVPdN8eJZWjss+8vLg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@verida/account-node/-/account-node-3.0.2.tgz", + "integrity": "sha512-/dwEfs6KErdwcA7Bet36TuUnbVDT5p6oLwvhG/AAylsseY+hhjy0s6tJmD9uPFTVscKhHeFr5cbkBDGmoUeeqA==", "dependencies": { - "@verida/account": "^3.0.1", - "@verida/did-client": "^3.0.1", - "@verida/did-document": "^3.0.1", + "@verida/account": "^3.0.2", + "@verida/did-client": "^3.0.2", + "@verida/did-document": "^3.0.2", "@verida/encryption-utils": "^3.0.0", - "@verida/keyring": "^3.0.1", - "@verida/types": "^3.0.0", + "@verida/keyring": "^3.0.2", + "@verida/types": "^3.0.1", "axios": "^0.27.2", "did-resolver": "^4.0.1" }, @@ -12833,18 +12906,18 @@ } }, "node_modules/@verida/client-ts": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@verida/client-ts/-/client-ts-3.0.2.tgz", - "integrity": "sha512-nk+hzmis1kMmAUfr8ZwNA4raxOMPrrLxhWqHrwHBvpjtgA8luVV67x2rU6USzNCcJCLEFdjUlFEVJjms5Mahow==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@verida/client-ts/-/client-ts-3.0.3.tgz", + "integrity": "sha512-R7W/3Rb2VWrsdRWwdL5TEnG+vN3t3aRZAXGAqWFZacsYmCfxKcu42Lae0mIWpoaCRQ0p/7HQ4kn1s5s+5u9KeQ==", "dependencies": { - "@verida/account": "^3.0.1", - "@verida/did-client": "^3.0.1", - "@verida/did-document": "^3.0.1", + "@verida/account": "^3.0.2", + "@verida/did-client": "^3.0.2", + "@verida/did-document": "^3.0.2", "@verida/encryption-utils": "^3.0.0", - "@verida/keyring": "^3.0.1", - "@verida/storage-link": "^3.0.1", - "@verida/types": "^3.0.0", - "@verida/vda-name-client": "^3.0.1", + "@verida/keyring": "^3.0.2", + "@verida/storage-link": "^3.0.2", + "@verida/types": "^3.0.1", + "@verida/vda-name-client": "^3.0.2", "ajv": "^8.6.3", "ajv-formats": "^2.1.1", "axios": "^0.21.2", @@ -12928,15 +13001,15 @@ } }, "node_modules/@verida/did-client": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@verida/did-client/-/did-client-3.0.1.tgz", - "integrity": "sha512-eySImxml+HHkWpqSH4fScK/0aHBe9T+SE4SEKSPBLYFoJ8BHtbhw9ZF4dE22IdIciVj08z3PRZfKA5/rCr73PQ==", - "dependencies": { - "@verida/did-document": "^3.0.1", - "@verida/types": "^3.0.0", - "@verida/vda-common": "^3.0.0", - "@verida/vda-did-resolver": "^3.0.1", - "@verida/web3": "^3.0.1", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@verida/did-client/-/did-client-3.0.2.tgz", + "integrity": "sha512-a5hFdck/qmtEXKQLpPK4bzk7/bLofwEA4MF5tUVrHNQe1QAHOzVZJgtSzezRebX01HPUM+xZ6PE0BGKcqEwzzw==", + "dependencies": { + "@verida/did-document": "^3.0.2", + "@verida/types": "^3.0.1", + "@verida/vda-common": "^3.0.1", + "@verida/vda-did-resolver": "^3.0.2", + "@verida/web3": "^3.0.2", "axios": "^0.23.0", "deepcopy": "^2.1.0", "did-resolver": "^4.0.1", @@ -12955,16 +13028,16 @@ } }, "node_modules/@verida/did-document": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@verida/did-document/-/did-document-3.0.1.tgz", - "integrity": "sha512-bqLpGEsmoACrGdnFiulxeoHzOwYyMRKET1L+QXHfAncVUe8UhDeyEmikLD2K2RqpxJN2i5AonKhfhKxdXy+FhA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@verida/did-document/-/did-document-3.0.2.tgz", + "integrity": "sha512-lrVyJxupzcTNpv+ot9HLgPL9OWe6JxrZqiaH4VyI/zMxCOfUJ469YDBicHJfLCU6cbZNsNmM2M5ef7GA6eobyQ==", "dependencies": { "@ethersproject/address": "^5.7.0", "@ethersproject/bignumber": "^5.7.0", "@ethersproject/transactions": "^5.7.0", "@verida/encryption-utils": "^3.0.0", - "@verida/keyring": "^3.0.1", - "@verida/types": "^3.0.0", + "@verida/keyring": "^3.0.2", + "@verida/types": "^3.0.1", "did-resolver": "^4.0.1", "lodash": "^4.17.21" }, @@ -12987,12 +13060,12 @@ } }, "node_modules/@verida/helpers": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@verida/helpers/-/helpers-3.0.1.tgz", - "integrity": "sha512-KJjvyW1AMsaDGxVru1DR2u/QeOmEMk7m2ieoQnrl917ENYIyCzT0qFuqab91a6i8Q99IWKZC5an+tXYCOpQ9RA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@verida/helpers/-/helpers-3.0.2.tgz", + "integrity": "sha512-D1RUQ1aSfLJnsc0TUa8orSolKH9jFYZ4etPPnSuvm2Lp4p9znTYFJnweEEMK2yoVMnCbQosJsXDp0JuwZ6XqUg==", "dependencies": { "@verida/encryption-utils": "^3.0.0", - "@verida/types": "^3.0.0", + "@verida/types": "^3.0.1", "axios": "^1.6.2", "bs58": "^5.0.0", "url": "^0.11.0" @@ -13002,12 +13075,12 @@ } }, "node_modules/@verida/keyring": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@verida/keyring/-/keyring-3.0.1.tgz", - "integrity": "sha512-dmWhAlkT2hz7FIHnMUuYlvvaQL57Ps/JicXdqzhmslNqt7Lez0/o1vqpyJ58ZPnhI/Lv7e0MOEqNnWDb1p3aGw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@verida/keyring/-/keyring-3.0.2.tgz", + "integrity": "sha512-rAZe0vDEeMml8qMQC7iDw+eD/FYWBguz5RkwyD/bAB5xVyxCQnNGqMW7tBk6PlHBbSEKH+xkUaS9WhXBZznfLQ==", "dependencies": { "@verida/encryption-utils": "^3.0.0", - "@verida/types": "^3.0.0", + "@verida/types": "^3.0.1", "ethers": "^5.5.1", "tweetnacl": "^1.0.3", "uuid": "^8.3.2" @@ -13025,14 +13098,14 @@ } }, "node_modules/@verida/storage-link": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@verida/storage-link/-/storage-link-3.0.1.tgz", - "integrity": "sha512-fkerqqb98XvjsilqrE531pLNptGntx9MEOFi28jfu3HWTMWutIZNcT4vLIo2QxxObD/7EG0sZzJGTHmRdHPx5w==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@verida/storage-link/-/storage-link-3.0.2.tgz", + "integrity": "sha512-dUslfVWlPaetpT3PolJVUk/lWKAk0OW4vaant/yrkMtgg4rmiCEPJD8MRSA2l5iVCGd59Jk0fcX8L6FFyInxsQ==", "dependencies": { - "@verida/did-client": "^3.0.1", - "@verida/did-document": "^3.0.1", + "@verida/did-client": "^3.0.2", + "@verida/did-document": "^3.0.2", "@verida/encryption-utils": "^3.0.0", - "@verida/keyring": "^3.0.1", + "@verida/keyring": "^3.0.2", "did-resolver": "^4.0.0", "url-parse": "^1.5.3" }, @@ -13041,9 +13114,9 @@ } }, "node_modules/@verida/types": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@verida/types/-/types-3.0.0.tgz", - "integrity": "sha512-J5psSf9ayqvUVyRBwYWjZ3Zeiomnl/GsHpvn2GA6zwH39QS8bPAvVGHaaq7na+0M1VUysrDEvHFrQ9fSmGAbHw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@verida/types/-/types-3.0.1.tgz", + "integrity": "sha512-YIdX5qP1oU+aY/fqrwrgMAFuH4lz1QuzYxLmYx4olCo5rmnopryu3A8oyE+5CX2qbSOBHp6w0TjvM6Bm4iQZPw==", "dependencies": { "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/bignumber": "^5.7.0", @@ -13058,778 +13131,32 @@ } }, "node_modules/@verida/types/node_modules/@types/node": { - "version": "18.19.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.13.tgz", - "integrity": "sha512-kgnbRDj8ioDyGxoiaXsiu1Ybm/K14ajCgMOkwiqpHrnF7d7QiYRoRqHIpglMMs3DwXinlK4qJ8TZGlj4hfleJg==", + "version": "18.19.31", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.31.tgz", + "integrity": "sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==", "dependencies": { "undici-types": "~5.26.4" } }, "node_modules/@verida/vda-common": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@verida/vda-common/-/vda-common-3.0.0.tgz", - "integrity": "sha512-T24EPcExnbCY1GyQcSThydExaRm2I4Mx38yUE+MkJwnvI7Q1lHNZEacEcDr+jnURAuBsLvp6jIiZAutZdEVdfA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@verida/vda-common/-/vda-common-3.0.1.tgz", + "integrity": "sha512-l6fxtSiOYlTWF1ya9Iy2HothVMAdGiD1AbZ+pfq5K4QrxNzUoijeR+24CBA/8q6XkF+OMSdR0V4sPZ/azgQg8g==", "dependencies": { "@verida/encryption-utils": "^3.0.0", "copyfiles": "^2.4.1", - "ethers": "5.5.1" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/abi": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.5.0.tgz", - "integrity": "sha512-loW7I4AohP5KycATvc0MgujU6JyCHPqHdeoo9z3Nr9xEiNioxa65ccdm1+fsoJhkuhdRtfcL8cfyGamz2AxZ5w==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/address": "^5.5.0", - "@ethersproject/bignumber": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/constants": "^5.5.0", - "@ethersproject/hash": "^5.5.0", - "@ethersproject/keccak256": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/properties": "^5.5.0", - "@ethersproject/strings": "^5.5.0" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/abstract-provider": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.5.1.tgz", - "integrity": "sha512-m+MA/ful6eKbxpr99xUYeRvLkfnlqzrF8SZ46d/xFB1A7ZVknYc/sXJG0RcufF52Qn2jeFj1hhcoQ7IXjNKUqg==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bignumber": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/networks": "^5.5.0", - "@ethersproject/properties": "^5.5.0", - "@ethersproject/transactions": "^5.5.0", - "@ethersproject/web": "^5.5.0" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/abstract-signer": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.5.0.tgz", - "integrity": "sha512-lj//7r250MXVLKI7sVarXAbZXbv9P50lgmJQGr2/is82EwEb8r7HrxsmMqAjTsztMYy7ohrIhGMIml+Gx4D3mA==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abstract-provider": "^5.5.0", - "@ethersproject/bignumber": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/properties": "^5.5.0" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/address": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.5.0.tgz", - "integrity": "sha512-l4Nj0eWlTUh6ro5IbPTgbpT4wRbdH5l8CQf7icF7sb/SI3Nhd9Y9HzhonTSTi6CefI0necIw7LJqQPopPLZyWw==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bignumber": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/keccak256": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/rlp": "^5.5.0" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/base64": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.5.0.tgz", - "integrity": "sha512-tdayUKhU1ljrlHzEWbStXazDpsx4eg1dBXUSI6+mHlYklOXoXF6lZvw8tnD6oVaWfnMxAgRSKROg3cVKtCcppA==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.5.0" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/basex": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.5.0.tgz", - "integrity": "sha512-ZIodwhHpVJ0Y3hUCfUucmxKsWQA5TMnavp5j/UOuDdzZWzJlRmuOjcTMIGgHCYuZmHt36BfiSyQPSRskPxbfaQ==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/properties": "^5.5.0" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/bignumber": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.5.0.tgz", - "integrity": "sha512-6Xytlwvy6Rn3U3gKEc1vP7nR92frHkv6wtVr95LFR3jREXiCPzdWxKQ1cx4JGQBXxcguAwjA8murlYN2TSiEbg==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "bn.js": "^4.11.9" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/bytes": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.5.0.tgz", - "integrity": "sha512-ABvc7BHWhZU9PNM/tANm/Qx4ostPGadAuQzWTr3doklZOhDlmcBqclrQe/ZXUIj3K8wC28oYeuRa+A37tX9kog==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/logger": "^5.5.0" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/constants": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.5.0.tgz", - "integrity": "sha512-2MsRRVChkvMWR+GyMGY4N1sAX9Mt3J9KykCsgUFd/1mwS0UH1qw+Bv9k1UJb3X3YJYFco9H20pjSlOIfCG5HYQ==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bignumber": "^5.5.0" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/contracts": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.5.0.tgz", - "integrity": "sha512-2viY7NzyvJkh+Ug17v7g3/IJC8HqZBDcOjYARZLdzRxrfGlRgmYgl6xPRKVbEzy1dWKw/iv7chDcS83pg6cLxg==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abi": "^5.5.0", - "@ethersproject/abstract-provider": "^5.5.0", - "@ethersproject/abstract-signer": "^5.5.0", - "@ethersproject/address": "^5.5.0", - "@ethersproject/bignumber": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/constants": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/properties": "^5.5.0", - "@ethersproject/transactions": "^5.5.0" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/hash": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.5.0.tgz", - "integrity": "sha512-dnGVpK1WtBjmnp3mUT0PlU2MpapnwWI0PibldQEq1408tQBAbZpPidkWoVVuNMOl/lISO3+4hXZWCL3YV7qzfg==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abstract-signer": "^5.5.0", - "@ethersproject/address": "^5.5.0", - "@ethersproject/bignumber": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/keccak256": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/properties": "^5.5.0", - "@ethersproject/strings": "^5.5.0" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/hdnode": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.5.0.tgz", - "integrity": "sha512-mcSOo9zeUg1L0CoJH7zmxwUG5ggQHU1UrRf8jyTYy6HxdZV+r0PBoL1bxr+JHIPXRzS6u/UW4mEn43y0tmyF8Q==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abstract-signer": "^5.5.0", - "@ethersproject/basex": "^5.5.0", - "@ethersproject/bignumber": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/pbkdf2": "^5.5.0", - "@ethersproject/properties": "^5.5.0", - "@ethersproject/sha2": "^5.5.0", - "@ethersproject/signing-key": "^5.5.0", - "@ethersproject/strings": "^5.5.0", - "@ethersproject/transactions": "^5.5.0", - "@ethersproject/wordlists": "^5.5.0" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/json-wallets": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.5.0.tgz", - "integrity": "sha512-9lA21XQnCdcS72xlBn1jfQdj2A1VUxZzOzi9UkNdnokNKke/9Ya2xA9aIK1SC3PQyBDLt4C+dfps7ULpkvKikQ==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abstract-signer": "^5.5.0", - "@ethersproject/address": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/hdnode": "^5.5.0", - "@ethersproject/keccak256": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/pbkdf2": "^5.5.0", - "@ethersproject/properties": "^5.5.0", - "@ethersproject/random": "^5.5.0", - "@ethersproject/strings": "^5.5.0", - "@ethersproject/transactions": "^5.5.0", - "aes-js": "3.0.0", - "scrypt-js": "3.0.1" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/keccak256": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.5.0.tgz", - "integrity": "sha512-5VoFCTjo2rYbBe1l2f4mccaRFN/4VQEYFwwn04aJV2h7qf4ZvI2wFxUE1XOX+snbwCLRzIeikOqtAoPwMza9kg==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.5.0", - "js-sha3": "0.8.0" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/logger": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.5.0.tgz", - "integrity": "sha512-rIY/6WPm7T8n3qS2vuHTUBPdXHl+rGxWxW5okDfo9J4Z0+gRRZT0msvUdIJkE4/HS29GUMziwGaaKO2bWONBrg==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ] - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/networks": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.5.0.tgz", - "integrity": "sha512-KWfP3xOnJeF89Uf/FCJdV1a2aDJe5XTN2N52p4fcQ34QhDqQFkgQKZ39VGtiqUgHcLI8DfT0l9azC3KFTunqtA==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/logger": "^5.5.0" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/pbkdf2": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.5.0.tgz", - "integrity": "sha512-SaDvQFvXPnz1QGpzr6/HToLifftSXGoXrbpZ6BvoZhmx4bNLHrxDe8MZisuecyOziP1aVEwzC2Hasj+86TgWVg==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/sha2": "^5.5.0" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/properties": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.5.0.tgz", - "integrity": "sha512-l3zRQg3JkD8EL3CPjNK5g7kMx4qSwiR60/uk5IVjd3oq1MZR5qUg40CNOoEJoX5wc3DyY5bt9EbMk86C7x0DNA==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/logger": "^5.5.0" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/providers": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.5.0.tgz", - "integrity": "sha512-xqMbDnS/FPy+J/9mBLKddzyLLAQFjrVff5g00efqxPzcAwXiR+SiCGVy6eJ5iAIirBOATjx7QLhDNPGV+AEQsw==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abstract-provider": "^5.5.0", - "@ethersproject/abstract-signer": "^5.5.0", - "@ethersproject/address": "^5.5.0", - "@ethersproject/basex": "^5.5.0", - "@ethersproject/bignumber": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/constants": "^5.5.0", - "@ethersproject/hash": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/networks": "^5.5.0", - "@ethersproject/properties": "^5.5.0", - "@ethersproject/random": "^5.5.0", - "@ethersproject/rlp": "^5.5.0", - "@ethersproject/sha2": "^5.5.0", - "@ethersproject/strings": "^5.5.0", - "@ethersproject/transactions": "^5.5.0", - "@ethersproject/web": "^5.5.0", - "bech32": "1.1.4", - "ws": "7.4.6" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/random": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.5.0.tgz", - "integrity": "sha512-egGYZwZ/YIFKMHcoBUo8t3a8Hb/TKYX8BCBoLjudVCZh892welR3jOxgOmb48xznc9bTcMm7Tpwc1gHC1PFNFQ==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/logger": "^5.5.0" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/rlp": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.5.0.tgz", - "integrity": "sha512-hLv8XaQ8PTI9g2RHoQGf/WSxBfTB/NudRacbzdxmst5VHAqd1sMibWG7SENzT5Dj3yZ3kJYx+WiRYEcQTAkcYA==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/logger": "^5.5.0" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/sha2": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.5.0.tgz", - "integrity": "sha512-B5UBoglbCiHamRVPLA110J+2uqsifpZaTmid2/7W5rbtYVz6gus6/hSDieIU/6gaKIDcOj12WnOdiymEUHIAOA==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "hash.js": "1.1.7" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/signing-key": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.5.0.tgz", - "integrity": "sha512-5VmseH7qjtNmDdZBswavhotYbWB0bOwKIlOTSlX14rKn5c11QmJwGt4GHeo7NrL/Ycl7uo9AHvEqs5xZgFBTng==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/properties": "^5.5.0", - "bn.js": "^4.11.9", - "elliptic": "6.5.4", - "hash.js": "1.1.7" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/solidity": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.5.0.tgz", - "integrity": "sha512-9NgZs9LhGMj6aCtHXhtmFQ4AN4sth5HuFXVvAQtzmm0jpSCNOTGtrHZJAeYTh7MBjRR8brylWZxBZR9zDStXbw==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bignumber": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/keccak256": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/sha2": "^5.5.0", - "@ethersproject/strings": "^5.5.0" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/strings": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.5.0.tgz", - "integrity": "sha512-9fy3TtF5LrX/wTrBaT8FGE6TDJyVjOvXynXJz5MT5azq+E6D92zuKNx7i29sWW2FjVOaWjAsiZ1ZWznuduTIIQ==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/constants": "^5.5.0", - "@ethersproject/logger": "^5.5.0" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/transactions": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.5.0.tgz", - "integrity": "sha512-9RZYSKX26KfzEd/1eqvv8pLauCKzDTub0Ko4LfIgaERvRuwyaNV78mJs7cpIgZaDl6RJui4o49lHwwCM0526zA==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/address": "^5.5.0", - "@ethersproject/bignumber": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/constants": "^5.5.0", - "@ethersproject/keccak256": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/properties": "^5.5.0", - "@ethersproject/rlp": "^5.5.0", - "@ethersproject/signing-key": "^5.5.0" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/units": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.5.0.tgz", - "integrity": "sha512-7+DpjiZk4v6wrikj+TCyWWa9dXLNU73tSTa7n0TSJDxkYbV3Yf1eRh9ToMLlZtuctNYu9RDNNy2USq3AdqSbag==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bignumber": "^5.5.0", - "@ethersproject/constants": "^5.5.0", - "@ethersproject/logger": "^5.5.0" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/wallet": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.5.0.tgz", - "integrity": "sha512-Mlu13hIctSYaZmUOo7r2PhNSd8eaMPVXe1wxrz4w4FCE4tDYBywDH+bAR1Xz2ADyXGwqYMwstzTrtUVIsKDO0Q==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abstract-provider": "^5.5.0", - "@ethersproject/abstract-signer": "^5.5.0", - "@ethersproject/address": "^5.5.0", - "@ethersproject/bignumber": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/hash": "^5.5.0", - "@ethersproject/hdnode": "^5.5.0", - "@ethersproject/json-wallets": "^5.5.0", - "@ethersproject/keccak256": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/properties": "^5.5.0", - "@ethersproject/random": "^5.5.0", - "@ethersproject/signing-key": "^5.5.0", - "@ethersproject/transactions": "^5.5.0", - "@ethersproject/wordlists": "^5.5.0" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/web": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.5.0.tgz", - "integrity": "sha512-BEgY0eL5oH4mAo37TNYVrFeHsIXLRxggCRG/ksRIxI2X5uj5IsjGmcNiRN/VirQOlBxcUhCgHhaDLG4m6XAVoA==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/base64": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/properties": "^5.5.0", - "@ethersproject/strings": "^5.5.0" - } - }, - "node_modules/@verida/vda-common/node_modules/@ethersproject/wordlists": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.5.0.tgz", - "integrity": "sha512-bL0UTReWDiaQJJYOC9sh/XcRu/9i2jMrzf8VLRmPKx58ckSlOJiohODkECCO50dtLZHcGU6MLXQ4OOrgBwP77Q==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/hash": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/properties": "^5.5.0", - "@ethersproject/strings": "^5.5.0" - } - }, - "node_modules/@verida/vda-common/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, - "node_modules/@verida/vda-common/node_modules/ethers": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.5.1.tgz", - "integrity": "sha512-RodEvUFZI+EmFcE6bwkuJqpCYHazdzeR1nMzg+YWQSmQEsNtfl1KHGfp/FWZYl48bI/g7cgBeP2IlPthjiVngw==", - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abi": "5.5.0", - "@ethersproject/abstract-provider": "5.5.1", - "@ethersproject/abstract-signer": "5.5.0", - "@ethersproject/address": "5.5.0", - "@ethersproject/base64": "5.5.0", - "@ethersproject/basex": "5.5.0", - "@ethersproject/bignumber": "5.5.0", - "@ethersproject/bytes": "5.5.0", - "@ethersproject/constants": "5.5.0", - "@ethersproject/contracts": "5.5.0", - "@ethersproject/hash": "5.5.0", - "@ethersproject/hdnode": "5.5.0", - "@ethersproject/json-wallets": "5.5.0", - "@ethersproject/keccak256": "5.5.0", - "@ethersproject/logger": "5.5.0", - "@ethersproject/networks": "5.5.0", - "@ethersproject/pbkdf2": "5.5.0", - "@ethersproject/properties": "5.5.0", - "@ethersproject/providers": "5.5.0", - "@ethersproject/random": "5.5.0", - "@ethersproject/rlp": "5.5.0", - "@ethersproject/sha2": "5.5.0", - "@ethersproject/signing-key": "5.5.0", - "@ethersproject/solidity": "5.5.0", - "@ethersproject/strings": "5.5.0", - "@ethersproject/transactions": "5.5.0", - "@ethersproject/units": "5.5.0", - "@ethersproject/wallet": "5.5.0", - "@ethersproject/web": "5.5.0", - "@ethersproject/wordlists": "5.5.0" - } - }, - "node_modules/@verida/vda-common/node_modules/js-sha3": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" - }, - "node_modules/@verida/vda-common/node_modules/ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } + "ethers": "5.7.2" } }, "node_modules/@verida/vda-did": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@verida/vda-did/-/vda-did-3.0.1.tgz", - "integrity": "sha512-wgePZNnsVAIfOwk7cDAGCrGyRCgGLyu7PKasonpVs45vTyEVJt74WpAr0m/kLsqUEVPiTSY1jwvuI1A2wE4TqA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@verida/vda-did/-/vda-did-3.0.2.tgz", + "integrity": "sha512-aS881oW9VK4WcmL5cL+cISOMhO974J4a9zZ1AJLzrAjognoJLwXHrSwV65mFS5ihovpTKAdwwITpcUL1UaQAeQ==", "dependencies": { - "@verida/did-document": "^3.0.1", + "@verida/did-document": "^3.0.2", "@verida/encryption-utils": "^3.0.0", - "@verida/types": "^3.0.0", - "@verida/web3": "^3.0.1", + "@verida/types": "^3.0.1", + "@verida/web3": "^3.0.2", "axios": "1.2.0-alpha.1", "ethers": "^5.7.2", "lodash": "^4.17.21" @@ -13839,16 +13166,16 @@ } }, "node_modules/@verida/vda-did-resolver": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@verida/vda-did-resolver/-/vda-did-resolver-3.0.1.tgz", - "integrity": "sha512-dFUPUsb8detiSReN9/ocKm4+pRdOSKPT1ar7owHo0OdELZ8hLX80Y3Nd+1sU9nUn7dYxqmCnPwOZGM42MP3tSQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@verida/vda-did-resolver/-/vda-did-resolver-3.0.2.tgz", + "integrity": "sha512-xW2VQ0YS+9mtkbgPIUokI4Mc3kxLCcD4E8DmRKaTITt5qZ59ezFT+Zpir9svseTRKfW2gpsAjH3kuCvxW8qEIA==", "dependencies": { "@ethersproject/providers": "^5.7.2", - "@verida/did-document": "^3.0.1", + "@verida/did-document": "^3.0.2", "@verida/encryption-utils": "^3.0.0", - "@verida/types": "^3.0.0", - "@verida/vda-common": "^3.0.0", - "@verida/vda-did": "^3.0.1", + "@verida/types": "^3.0.1", + "@verida/vda-common": "^3.0.1", + "@verida/vda-did": "^3.0.2", "axios": "1.2.0-alpha.1", "lodash": "^4.17.21" }, @@ -13877,14 +13204,14 @@ } }, "node_modules/@verida/vda-name-client": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@verida/vda-name-client/-/vda-name-client-3.0.1.tgz", - "integrity": "sha512-HAGro7kQ1hf6oz9gpGJEbHfjQGbUUYZBmjJKSg+wzRM8pKfXnMuN5R4iRVoR6TPpcwoNhbrce4toO4NQybyYAw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@verida/vda-name-client/-/vda-name-client-3.0.2.tgz", + "integrity": "sha512-W8STgdouBmbPvh0yh2SRQ8VxRMIYl+nK4tAxwhYMm8e/Wkw0oJm3o8+RZHedMwtJMyrOTtSp0QCYqovUstw+cg==", "dependencies": { "@ethersproject/providers": "^5.7.2", - "@verida/helpers": "^3.0.1", - "@verida/types": "^3.0.0", - "@verida/web3": "^3.0.1", + "@verida/helpers": "^3.0.2", + "@verida/types": "^3.0.1", + "@verida/web3": "^3.0.2", "axios": "^0.27.2", "ethers": "^5.7.0" } @@ -13899,14 +13226,17 @@ } }, "node_modules/@verida/web3": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@verida/web3/-/web3-3.0.1.tgz", - "integrity": "sha512-XLfwUkG93vh7/4t/cJmtROcu31Gz+7Wj0aCmGE2p3go3iMZzFH03+EmK90xvtQrISbzrmBkxhsThJ1BTbZRiSg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@verida/web3/-/web3-3.0.2.tgz", + "integrity": "sha512-HdDI5Ud10X2v408HtSaSg1+FOZu5vVrlcWD/FYZX9rKZztBjX2wWVc8T+dmcCWJsJSMbXer3Mzo1Q0CQTFZ2wQ==", "dependencies": { - "@verida/types": "^3.0.0", - "@verida/vda-common": "^3.0.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/contracts": "^5.7.0", + "@ethersproject/providers": "^5.7.2", + "@verida/types": "^3.0.1", + "@verida/vda-common": "^3.0.1", "axios": "^1.2.3", - "ethers": "^5.7.0" + "ethers": "^5.7.2" }, "engines": { "node": ">=14.0.0" @@ -14118,19 +13448,14 @@ } }, "node_modules/@walletconnect/logger": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@walletconnect/logger/-/logger-2.0.1.tgz", - "integrity": "sha512-SsTKdsgWm+oDTBeNE/zHxxr5eJfZmE9/5yp/Ku+zJtcTAjELb3DXueWkDXmE9h8uHIbJzIb5wj5lPdzyrjT6hQ==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@walletconnect/logger/-/logger-2.1.2.tgz", + "integrity": "sha512-aAb28I3S6pYXZHQm5ESB+V6rDqIYfsnHaQyzFbwUUBFY4H0OXx/YtTl8lvhUNhMMfb9UxbwEBS253TlXUYJWSw==", "dependencies": { - "pino": "7.11.0", - "tslib": "1.14.1" + "@walletconnect/safe-json": "^1.0.2", + "pino": "7.11.0" } }, - "node_modules/@walletconnect/logger/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, "node_modules/@walletconnect/modal": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/@walletconnect/modal/-/modal-2.6.1.tgz", @@ -14337,9 +13662,9 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@webassemblyjs/ast": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", - "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", "dev": true, "peer": true, "dependencies": { @@ -14362,9 +13687,9 @@ "peer": true }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", - "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", "dev": true, "peer": true }, @@ -14388,16 +13713,16 @@ "peer": true }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", - "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6" + "@webassemblyjs/wasm-gen": "1.12.1" } }, "node_modules/@webassemblyjs/ieee754": { @@ -14428,30 +13753,30 @@ "peer": true }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", - "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6", - "@webassemblyjs/wasm-opt": "1.11.6", - "@webassemblyjs/wasm-parser": "1.11.6", - "@webassemblyjs/wast-printer": "1.11.6" + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", - "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", "@webassemblyjs/ieee754": "1.11.6", "@webassemblyjs/leb128": "1.11.6", @@ -14459,26 +13784,26 @@ } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", - "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6", - "@webassemblyjs/wasm-parser": "1.11.6" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", - "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-api-error": "1.11.6", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", "@webassemblyjs/ieee754": "1.11.6", @@ -14487,13 +13812,13 @@ } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", - "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/ast": "1.12.1", "@xtuc/long": "4.2.2" } }, @@ -14637,9 +13962,9 @@ "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==" }, "node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "dev": true, "dependencies": { "debug": "^4.3.4" @@ -14652,7 +13977,7 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", - "optional": true, + "devOptional": true, "dependencies": { "humanize-ms": "^1.2.1" }, @@ -14795,12 +14120,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/ansicolors": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", - "integrity": "sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==", - "dev": true - }, "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", @@ -14867,23 +14186,21 @@ "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" }, "node_modules/are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "optional": true, + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=10" } }, "node_modules/are-we-there-yet/node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "optional": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -14916,6 +14233,22 @@ "integrity": "sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw==", "dev": true }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "devOptional": true, + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -14936,6 +14269,28 @@ "node": ">=8" } }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "devOptional": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", @@ -15044,11 +14399,11 @@ } }, "node_modules/axios": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", - "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", "dependencies": { - "follow-redirects": "^1.15.4", + "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } @@ -15166,14 +14521,14 @@ } }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.8", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.8.tgz", - "integrity": "sha512-OtIuQfafSzpo/LhnJaykc0R/MMnuLSSVjVYy9mHArIZ9qTCSZ6TpWCuEKZYVoN//t8HqBNScHrOtCrIK5IaGLg==", + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.10.tgz", + "integrity": "sha512-rpIuu//y5OX6jVU+a5BCn1R5RSZYWAl2Nar76iwaOdycqb6JPxediskWFMMl7stfwNJR4b7eiQvh5fB5TEQJTQ==", "optional": true, "peer": true, "dependencies": { "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.5.0", + "@babel/helper-define-polyfill-provider": "^0.6.1", "semver": "^6.3.1" }, "peerDependencies": { @@ -15191,27 +14546,27 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.9.0.tgz", - "integrity": "sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg==", + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz", + "integrity": "sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.5.0", - "core-js-compat": "^3.34.0" + "@babel/helper-define-polyfill-provider": "^0.6.1", + "core-js-compat": "^3.36.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.5.tgz", - "integrity": "sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.1.tgz", + "integrity": "sha512-JfTApdE++cgcTWjsiCQlLyFBMbTUft9ja17saCc93lgV33h4tuCVj7tlvu//qpLwaG+3yEz7/KhahGrUMkVq9g==", "optional": true, "peer": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.5.0" + "@babel/helper-define-polyfill-provider": "^0.6.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -15265,9 +14620,9 @@ } }, "node_modules/babel-preset-expo": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-10.0.1.tgz", - "integrity": "sha512-uWIGmLfbP3dS5+8nesxaW6mQs41d4iP7X82ZwRdisB/wAhKQmuJM9Y1jQe4006uNYkw6Phf2TT03ykLVro7KuQ==", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-10.0.2.tgz", + "integrity": "sha512-hg06qdSTK7MjKmFXSiq6cFoIbI3n3uT8a3NI2EZoISWhu+tedCj4DQduwi+3adFuRuYvAwECI0IYn/5iGh5zWQ==", "optional": true, "peer": true, "dependencies": { @@ -15282,6 +14637,121 @@ "react-refresh": "0.14.0" } }, + "node_modules/babel-preset-expo/node_modules/@react-native/babel-plugin-codegen": { + "version": "0.73.4", + "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.73.4.tgz", + "integrity": "sha512-XzRd8MJGo4Zc5KsphDHBYJzS1ryOHg8I2gOZDAUCGcwLFhdyGu1zBNDJYH2GFyDrInn9TzAbRIf3d4O+eltXQQ==", + "optional": true, + "peer": true, + "dependencies": { + "@react-native/codegen": "0.73.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/babel-preset-expo/node_modules/@react-native/babel-preset": { + "version": "0.73.21", + "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.73.21.tgz", + "integrity": "sha512-WlFttNnySKQMeujN09fRmrdWqh46QyJluM5jdtDNrkl/2Hx6N4XeDUGhABvConeK95OidVO7sFFf7sNebVXogA==", + "optional": true, + "peer": true, + "dependencies": { + "@babel/core": "^7.20.0", + "@babel/plugin-proposal-async-generator-functions": "^7.0.0", + "@babel/plugin-proposal-class-properties": "^7.18.0", + "@babel/plugin-proposal-export-default-from": "^7.0.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.0", + "@babel/plugin-proposal-numeric-separator": "^7.0.0", + "@babel/plugin-proposal-object-rest-spread": "^7.20.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.0.0", + "@babel/plugin-proposal-optional-chaining": "^7.20.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-export-default-from": "^7.0.0", + "@babel/plugin-syntax-flow": "^7.18.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.0.0", + "@babel/plugin-syntax-optional-chaining": "^7.0.0", + "@babel/plugin-transform-arrow-functions": "^7.0.0", + "@babel/plugin-transform-async-to-generator": "^7.20.0", + "@babel/plugin-transform-block-scoping": "^7.0.0", + "@babel/plugin-transform-classes": "^7.0.0", + "@babel/plugin-transform-computed-properties": "^7.0.0", + "@babel/plugin-transform-destructuring": "^7.20.0", + "@babel/plugin-transform-flow-strip-types": "^7.20.0", + "@babel/plugin-transform-function-name": "^7.0.0", + "@babel/plugin-transform-literals": "^7.0.0", + "@babel/plugin-transform-modules-commonjs": "^7.0.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.0.0", + "@babel/plugin-transform-parameters": "^7.0.0", + "@babel/plugin-transform-private-methods": "^7.22.5", + "@babel/plugin-transform-private-property-in-object": "^7.22.11", + "@babel/plugin-transform-react-display-name": "^7.0.0", + "@babel/plugin-transform-react-jsx": "^7.0.0", + "@babel/plugin-transform-react-jsx-self": "^7.0.0", + "@babel/plugin-transform-react-jsx-source": "^7.0.0", + "@babel/plugin-transform-runtime": "^7.0.0", + "@babel/plugin-transform-shorthand-properties": "^7.0.0", + "@babel/plugin-transform-spread": "^7.0.0", + "@babel/plugin-transform-sticky-regex": "^7.0.0", + "@babel/plugin-transform-typescript": "^7.5.0", + "@babel/plugin-transform-unicode-regex": "^7.0.0", + "@babel/template": "^7.0.0", + "@react-native/babel-plugin-codegen": "0.73.4", + "babel-plugin-transform-flow-enums": "^0.0.2", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/babel-preset-expo/node_modules/@react-native/codegen": { + "version": "0.73.3", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.73.3.tgz", + "integrity": "sha512-sxslCAAb8kM06vGy9Jyh4TtvjhcP36k/rvj2QE2Jdhdm61KvfafCATSIsOfc0QvnduWFcpXUPvAVyYwuv7PYDg==", + "optional": true, + "peer": true, + "dependencies": { + "@babel/parser": "^7.20.0", + "flow-parser": "^0.206.0", + "glob": "^7.1.1", + "invariant": "^2.2.4", + "jscodeshift": "^0.14.0", + "mkdirp": "^0.5.1", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@babel/preset-env": "^7.1.6" + } + }, + "node_modules/babel-preset-expo/node_modules/flow-parser": { + "version": "0.206.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.206.0.tgz", + "integrity": "sha512-HVzoK3r6Vsg+lKvlIZzaWNBVai+FXTX1wdYhz/wVlH13tb/gOdLXmlTqy6odmTBhT5UoWUbq0k8263Qhr9d88w==", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/babel-preset-expo/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "optional": true, + "peer": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, "node_modules/babel-preset-fbjs": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/babel-preset-fbjs/-/babel-preset-fbjs-3.4.0.tgz", @@ -15653,9 +15123,9 @@ "integrity": "sha512-+12sHB+Br8HIh6VAMVEG5r3UXCyESIgDW7kzk3BjIXa43DVqVwL7GC5TW3jeh+72dtcH99pPVpw0X8i0jt+/kw==" }, "node_modules/browserslist": { - "version": "4.22.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.3.tgz", - "integrity": "sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", "funding": [ { "type": "opencollective", @@ -15671,8 +15141,8 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001580", - "electron-to-chromium": "^1.4.648", + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", "node-releases": "^2.0.14", "update-browserslist-db": "^1.0.13" }, @@ -15784,20 +15254,11 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, - "node_modules/buffer-writer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", - "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", - "engines": { - "node": ">=4" - } - }, "node_modules/builtins": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", "integrity": "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==", - "optional": true, - "peer": true + "devOptional": true }, "node_modules/bytes": { "version": "3.1.2", @@ -15811,7 +15272,7 @@ "version": "15.3.0", "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", - "optional": true, + "devOptional": true, "dependencies": { "@npmcli/fs": "^1.0.0", "@npmcli/move-file": "^1.0.1", @@ -15933,9 +15394,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001582", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001582.tgz", - "integrity": "sha512-vsJG3V5vgfduaQGVxL53uSX/HUzxyr2eA8xCo36OLal7sRcSZbibJtLeh0qja4sFOr/QQGt4opB4tOy+eOgAxg==", + "version": "1.0.30001610", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001610.tgz", + "integrity": "sha512-QFutAY4NgaelojVMjY63o6XlZyORPaLfyMnsl3HgnWdJUcX6K0oaJymHjH8PT5Gk7sTm8rvC/c5COUQKXqmOMA==", "funding": [ { "type": "opencollective", @@ -15956,19 +15417,6 @@ "resolved": "https://registry.npmjs.org/canonicalize/-/canonicalize-1.0.8.tgz", "integrity": "sha512-0CNTVCLZggSh7bc5VkX5WWPWO+cyZbNd07IHIsSXLia/eAq+r836hgk+8BKoEh7949Mda87VUOitx5OddVj64A==" }, - "node_modules/cardinal": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", - "integrity": "sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==", - "dev": true, - "dependencies": { - "ansicolors": "~0.3.2", - "redeyed": "~2.1.0" - }, - "bin": { - "cdl": "bin/cdl.js" - } - }, "node_modules/cborg": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/cborg/-/cborg-1.10.2.tgz", @@ -16191,9 +15639,9 @@ } }, "node_modules/cli-table3": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", - "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.4.tgz", + "integrity": "sha512-Lm3L0p+/npIQWNIiyF/nAn7T5dnOwR3xNTHXYEBFBFVPXzCVNZ5lqEC/1eo/EVfpDsQ1I+TX4ORPQgp+UI0CRw==", "dev": true, "dependencies": { "string-width": "^4.2.0" @@ -16398,16 +15846,6 @@ "node": ">=6" } }, - "node_modules/cluster-key-slot": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", - "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", - "optional": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -16774,6 +16212,18 @@ "node": ">=16" } }, + "node_modules/convert-hrtime": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/convert-hrtime/-/convert-hrtime-5.0.0.tgz", + "integrity": "sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -16828,13 +16278,13 @@ } }, "node_modules/core-js-compat": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.35.1.tgz", - "integrity": "sha512-sftHa5qUJY3rs9Zht1WEnmkvXputCyDBczPnr7QDgL8n3qrF3CMXY4VPSYtOLLiOUJcah2WNXREd48iOl6mQIw==", + "version": "3.37.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.0.tgz", + "integrity": "sha512-vYq4L+T8aS5UuFg4UwDhc7YNRWVeVZwltad9C/jV3R2LgVOpS9BDr7l/WL6BN0dbV3k1XejPTHqqEzJgsa0frA==", "optional": true, "peer": true, "dependencies": { - "browserslist": "^4.22.2" + "browserslist": "^4.23.0" }, "funding": { "type": "opencollective", @@ -16936,6 +16386,13 @@ "node": ">=4" } }, + "node_modules/cosmiconfig/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "optional": true, + "peer": true + }, "node_modules/cosmjs-types": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/cosmjs-types/-/cosmjs-types-0.9.0.tgz", @@ -17126,7 +16583,6 @@ "node_modules/crypto-pouch": { "version": "4.0.1", "resolved": "git+ssh://git@github.com/tahpot/crypto-pouch.git#7a712691b4404cfefb34ad3f58db1d83b55ed3bf", - "license": "MIT", "dependencies": { "garbados-crypt": "git+https://github.com/tahpot/crypt.git#feature/pbkdf2", "transform-pouch": "^2.0.0" @@ -17185,6 +16641,57 @@ "node": ">= 12" } }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "devOptional": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "devOptional": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "devOptional": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/date-and-time": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-2.4.3.tgz", @@ -17242,9 +16749,9 @@ } }, "node_modules/dedent": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", - "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", "dev": true, "peerDependencies": { "babel-plugin-macros": "^3.1.0" @@ -17584,16 +17091,6 @@ "optional": true, "peer": true }, - "node_modules/denque": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", - "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", - "optional": true, - "peer": true, - "engines": { - "node": ">=0.10" - } - }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -17643,14 +17140,11 @@ "integrity": "sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==" }, "node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "bin": { - "detect-libc": "bin/detect-libc.js" - }, + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", "engines": { - "node": ">=0.10" + "node": ">=8" } }, "node_modules/detect-newline": { @@ -17783,24 +17277,30 @@ } }, "node_modules/dotenv": { - "version": "16.4.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.1.tgz", - "integrity": "sha512-CjA3y+Dr3FyFDOAMnxZEGtnW9KBR2M0JvvUtXNW+dYJL5ROWxP9DUHCwgFqpMk0OXCc0ljhaNTr2w/kutYIcHQ==", + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/motdotla/dotenv?sponsor=1" + "url": "https://dotenvx.com" } }, "node_modules/dotenv-expand": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", - "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", + "version": "11.0.6", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.6.tgz", + "integrity": "sha512-8NHi73otpWsZGBSZwwknTXS5pqMOrk9+Ssrna8xCaxkzEpU9OTf9R5ArQGVw03//Zmk9MOwLPng9WwndvpAJ5g==", "optional": true, "peer": true, + "dependencies": { + "dotenv": "^16.4.4" + }, "engines": { "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" } }, "node_modules/double-ended-queue": { @@ -17881,14 +17381,14 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.653", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.653.tgz", - "integrity": "sha512-wA2A2LQCqnEwQAvwADQq3KpMpNwgAUBnRmrFgRzHnPhbQUFArTR32Ab46f4p0MovDLcg4uqd4nCsN2hTltslpA==" + "version": "1.4.738", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.738.tgz", + "integrity": "sha512-lwKft2CLFztD+vEIpesrOtCrko/TFnEJlHFdRhazU7Y/jx5qc4cqsocfVrBg4So4gGe9lvxnbLIoev47WMpg+A==" }, "node_modules/elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.5.tgz", + "integrity": "sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw==", "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", @@ -17990,9 +17490,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", - "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", + "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -18084,9 +17584,9 @@ } }, "node_modules/env-ci/node_modules/npm-run-path": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", - "integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", "dev": true, "dependencies": { "path-key": "^4.0.0" @@ -18169,9 +17669,9 @@ } }, "node_modules/envinfo": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.0.tgz", - "integrity": "sha512-G9/6xF1FPbIw0TtalAMaVPpiq2aDEuKLXM314jPVAO9r2fo2a4BLqMNkmRS7O/xPPZ+COAhGIz3ETvHEV3eUcg==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.12.0.tgz", + "integrity": "sha512-Iw9rQJBGpJRd3rwXm9ft/JiGoAZmLxxJZELYDQoPRZ4USVhkKtIcNBPw6U+/K2mBpaqM25JSV6Yl4Az9vO2wJg==", "optional": true, "peer": true, "bin": { @@ -18237,6 +17737,66 @@ "node": ">= 0.8" } }, + "node_modules/es-abstract": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "devOptional": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/es-define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", @@ -18257,16 +17817,59 @@ } }, "node_modules/es-module-lexer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", - "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.0.tgz", + "integrity": "sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw==", "dev": true, "peer": true }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "devOptional": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "devOptional": true, + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "devOptional": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "engines": { "node": ">=6" } @@ -18684,25 +18287,25 @@ } }, "node_modules/expo": { - "version": "50.0.4", - "resolved": "https://registry.npmjs.org/expo/-/expo-50.0.4.tgz", - "integrity": "sha512-8QWBvYZyKFd7pHxbtri8/ZITBR19QbrW2IkezAhs3ZOHR2kluSgNfyo9ojAe7GnOnE8hCB6Xe83Dbm0R3Ealhw==", + "version": "50.0.17", + "resolved": "https://registry.npmjs.org/expo/-/expo-50.0.17.tgz", + "integrity": "sha512-eD8Nh10BgVwecU7EVyogx7X314ajxVpJdFwkXhi341AD61S2WPX31NMHW82XGXas6dbDjdbgtaOMo5H/vylB7Q==", "optional": true, "peer": true, "dependencies": { "@babel/runtime": "^7.20.0", - "@expo/cli": "0.17.3", - "@expo/config": "8.5.4", - "@expo/config-plugins": "7.8.4", - "@expo/metro-config": "0.17.3", + "@expo/cli": "0.17.10", + "@expo/config": "8.5.6", + "@expo/config-plugins": "7.9.1", + "@expo/metro-config": "0.17.7", "@expo/vector-icons": "^14.0.0", - "babel-preset-expo": "~10.0.1", + "babel-preset-expo": "~10.0.2", "expo-asset": "~9.0.2", - "expo-file-system": "~16.0.5", - "expo-font": "~11.10.2", + "expo-file-system": "~16.0.9", + "expo-font": "~11.10.3", "expo-keep-awake": "~12.8.2", - "expo-modules-autolinking": "1.10.2", - "expo-modules-core": "1.11.8", + "expo-modules-autolinking": "1.10.3", + "expo-modules-core": "1.11.13", "fbemitter": "^3.0.0", "whatwg-url-without-unicode": "8.0.0-3" }, @@ -18726,9 +18329,9 @@ } }, "node_modules/expo-constants": { - "version": "15.4.5", - "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-15.4.5.tgz", - "integrity": "sha512-1pVVjwk733hbbIjtQcvUFCme540v4gFemdNlaxM2UXKbfRCOh2hzgKN5joHMOysoXQe736TTUrRj7UaZI5Yyhg==", + "version": "15.4.6", + "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-15.4.6.tgz", + "integrity": "sha512-vizE69dww2Vl0PTWWvDmK0Jo2/J+WzdcMZlA05YEnEYofQuhKxTVsiuipf79mSOmFavt4UQYC1UnzptzKyfmiQ==", "optional": true, "peer": true, "dependencies": { @@ -18739,9 +18342,9 @@ } }, "node_modules/expo-file-system": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-16.0.5.tgz", - "integrity": "sha512-JpKMbKfwTaMCbwUwq7MwcSbPR7r+IqZEL3RFam3ClPHDtKLnlEoywREeaDsWjSZb7dS25hG3WqXspfTuugCDvg==", + "version": "16.0.9", + "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-16.0.9.tgz", + "integrity": "sha512-3gRPvKVv7/Y7AdD9eHMIdfg5YbUn2zbwKofjsloTI5sEC57SLUFJtbLvUCz9Pk63DaSQ7WIE1JM0EASyvuPbuw==", "optional": true, "peer": true, "peerDependencies": { @@ -18749,9 +18352,9 @@ } }, "node_modules/expo-font": { - "version": "11.10.2", - "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-11.10.2.tgz", - "integrity": "sha512-AE0Q0LiWiVosQ/jlKUPoWoob7p3GwYM2xmLoUkuopO9RYh9NL1hZKHiMKcWBZyDG8Gww1GtBQwh7ZREST8+jjQ==", + "version": "11.10.3", + "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-11.10.3.tgz", + "integrity": "sha512-q1Td2zUvmLbCA9GV4OG4nLPw5gJuNY1VrPycsnemN1m8XWTzzs8nyECQQqrcBhgulCgcKZZJJ6U0kC2iuSoQHQ==", "optional": true, "peer": true, "dependencies": { @@ -18803,9 +18406,9 @@ } }, "node_modules/expo-modules-core": { - "version": "1.11.8", - "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-1.11.8.tgz", - "integrity": "sha512-rlctE3nCNLCGv3LosGQNaTuwGrr2SyQA+hOgci/0l+VRc0gFNtvl0gskph9C0tnN1jzBeb8rRZQYVj5ih1yxcA==", + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-1.11.13.tgz", + "integrity": "sha512-2H5qrGUvmLzmJNPDOnovH1Pfk5H/S/V0BifBmOQyDc9aUh9LaDwkqnChZGIXv8ZHDW8JRlUW0QqyWxTggkbw1A==", "optional": true, "peer": true, "dependencies": { @@ -18825,9 +18428,9 @@ } }, "node_modules/expo/node_modules/expo-modules-autolinking": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-1.10.2.tgz", - "integrity": "sha512-OEeoz0+zGx5EJwGtDm9pSywCr+gUCaisZV0mNkK7V3fuRl+EVPBSsI+957JwAc4ZxVps95jy28eLcRRtQ33yVg==", + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-1.10.3.tgz", + "integrity": "sha512-pn4n2Dl4iRh/zUeiChjRIe1C7EqOw1qhccr85viQV7W6l5vgRpY0osE51ij5LKg/kJmGRcJfs12+PwbdTplbKw==", "optional": true, "peer": true, "dependencies": { @@ -19052,9 +18655,9 @@ "integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==" }, "node_modules/fast-xml-parser": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.3.4.tgz", - "integrity": "sha512-utnwm92SyozgA3hhH2I8qldf2lBqm6qHOICawRNRFu1qMe3+oqr+GcXjGqTmXTMGE5T4eC03kr/rlh5C1IRdZA==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.3.6.tgz", + "integrity": "sha512-M2SovcRxD4+vC493Uc2GZVcZaj66CCJhWurC4viynVSTvrpErCShNcDz1lAho6n9REQKvL/ll4A4/fw6Y9z8nw==", "funding": [ { "type": "github", @@ -19075,9 +18678,9 @@ } }, "node_modules/fastq": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.0.tgz", - "integrity": "sha512-zGygtijUMT7jnk3h26kUms3BkSDp4IfIKjmnqI2tvx6nuBfiF1UqOxbnLfzdv+apBy+53oaImsKtMw/xYbW+1w==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "devOptional": true, "dependencies": { "reusify": "^1.0.4" @@ -19176,9 +18779,9 @@ "peer": true }, "node_modules/figures": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/figures/-/figures-6.0.1.tgz", - "integrity": "sha512-0oY/olScYD4IhQ8u//gCPA4F3mlTn2dacYmiDm/mbDQvpmLjV4uH+zhsQ5IyXRyvqkvtUkXkNdGvg5OFJTCsuQ==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", "dev": true, "dependencies": { "is-unicode-supported": "^2.0.0" @@ -19429,15 +19032,16 @@ } }, "node_modules/find-versions": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-5.1.0.tgz", - "integrity": "sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-6.0.0.tgz", + "integrity": "sha512-2kCCtc+JvcZ86IGAz3Z2Y0A1baIz9fL31pH/0S1IqZr9Iwnjq8izfPtrCyQKO6TLMPELLsQMre7VDqeIKCsHkA==", "dev": true, "dependencies": { - "semver-regex": "^4.0.5" + "semver-regex": "^4.0.5", + "super-regex": "^1.0.0" }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -19478,9 +19082,9 @@ } }, "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, "node_modules/flow-enums-runtime": { @@ -19491,9 +19095,9 @@ "peer": true }, "node_modules/flow-parser": { - "version": "0.206.0", - "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.206.0.tgz", - "integrity": "sha512-HVzoK3r6Vsg+lKvlIZzaWNBVai+FXTX1wdYhz/wVlH13tb/gOdLXmlTqy6odmTBhT5UoWUbq0k8263Qhr9d88w==", + "version": "0.233.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.233.0.tgz", + "integrity": "sha512-E/mv51GYJfLuRX6fZnw4M52gBxYa8pkHUOgNEZOcQK2RTXS8YXeU5rlalkTcY99UpwbeNVCSUFKaavpOksi/pQ==", "optional": true, "peer": true, "engines": { @@ -19501,9 +19105,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", - "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "funding": [ { "type": "individual", @@ -19681,10 +19285,48 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/function-timeout": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/function-timeout/-/function-timeout-1.0.1.tgz", + "integrity": "sha512-6yPMImFFuaMPNaTMTBuolA8EanHJWF5Vju0NHpObRURT105J6x1Mf2a7J4P7Sqk2xDxv24N5L0RatEhTBhNmdA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "devOptional": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "devOptional": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/garbados-crypt": { "version": "3.0.0-beta", "resolved": "git+ssh://git@github.com/tahpot/crypt.git#80c041d3dd0aead57201eb2c64c07d114f15ff64", - "license": "Apache-2.0", "dependencies": { "pbkdf2": "^3.1.2", "tweetnacl": "^1.0.3", @@ -19695,22 +19337,22 @@ } }, "node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "optional": true, + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", "dependencies": { "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", "string-width": "^4.2.3", "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" + "wide-align": "^1.1.2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=10" } }, "node_modules/generate-password": { @@ -19801,6 +19443,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "devOptional": true, + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/getenv": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/getenv/-/getenv-1.0.0.tgz", @@ -19919,12 +19578,12 @@ } }, "node_modules/globby": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.0.tgz", - "integrity": "sha512-/1WM/LNHRAOH9lZta77uGbq0dAEQM+XjNesWwhlERDVenqothRbnzTrL3/LrIoEPPjeUHC3vrS6TwoyxeHs7MQ==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.1.tgz", + "integrity": "sha512-jOMLD2Z7MAhyG8aJpNOpmziMOP4rPLcc95oQPKXBazW82z+CEgPFBQvEpRUa1KeIMUJo4Wsm+q6uzO/Q/4BksQ==", "dev": true, "dependencies": { - "@sindresorhus/merge-streams": "^1.0.0", + "@sindresorhus/merge-streams": "^2.1.0", "fast-glob": "^3.3.2", "ignore": "^5.2.4", "path-type": "^5.0.0", @@ -20046,6 +19705,15 @@ "uglify-js": "^3.1.4" } }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "devOptional": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -20066,9 +19734,9 @@ } }, "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "engines": { "node": ">= 0.4" }, @@ -20142,9 +19810,9 @@ } }, "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dependencies": { "function-bind": "^1.1.2" }, @@ -20161,20 +19829,20 @@ } }, "node_modules/hermes-estree": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.15.0.tgz", - "integrity": "sha512-lLYvAd+6BnOqWdnNbP/Q8xfl8LOGw4wVjfrNd9Gt8eoFzhNBRVD95n4l2ksfMVOoxuVyegs85g83KS9QOsxbVQ==", + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.20.1.tgz", + "integrity": "sha512-SQpZK4BzR48kuOg0v4pb3EAGNclzIlqMj3Opu/mu7bbAoFw6oig6cEt/RAi0zTFW/iW6Iz9X9ggGuZTAZ/yZHg==", "optional": true, "peer": true }, "node_modules/hermes-parser": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.15.0.tgz", - "integrity": "sha512-Q1uks5rjZlE9RjMMjSUCkGrEIPI5pKJILeCtK1VmTj7U4pf3wVPoo+cxfu+s4cBAPy2JzikIIdCZgBoR6x7U1Q==", + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.20.1.tgz", + "integrity": "sha512-BL5P83cwCogI8D7rrDCgsFY0tdYUtmFP9XaXtl2IQjC+2Xo+4okjfXintlTxcIwl4qeGddEl28Z11kbVIw0aNA==", "optional": true, "peer": true, "dependencies": { - "hermes-estree": "0.15.0" + "hermes-estree": "0.20.1" } }, "node_modules/hermes-profile-transformer": { @@ -20239,8 +19907,7 @@ "version": "3.0.8", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz", "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", - "optional": true, - "peer": true, + "devOptional": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -20258,7 +19925,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "optional": true + "devOptional": true }, "node_modules/http-errors": { "version": "2.0.0", @@ -20276,9 +19943,9 @@ } }, "node_modules/http-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", - "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dev": true, "dependencies": { "agent-base": "^7.1.0", @@ -20303,9 +19970,9 @@ "integrity": "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==" }, "node_modules/https-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", - "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", "dev": true, "dependencies": { "agent-base": "^7.0.2", @@ -20328,7 +19995,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "optional": true, + "devOptional": true, "dependencies": { "ms": "^2.0.0" } @@ -20415,9 +20082,9 @@ } }, "node_modules/import-from-esm": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/import-from-esm/-/import-from-esm-1.3.3.tgz", - "integrity": "sha512-U3Qt/CyfFpTUv6LOP2jRTLYjphH6zg3okMfHbyqRa/W2w6hr8OsJWVggNlR4jxuojQy81TgTJTxgSkyoteRGMQ==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/import-from-esm/-/import-from-esm-1.3.4.tgz", + "integrity": "sha512-7EyUlPFC0HOlBDpUFGfYstsU7XHxZJKAAMzCT8wZ0hMW7b+hG51LIKTDcsgtz8Pu6YC0HqRVbX+rVUtsGMUKvg==", "dev": true, "dependencies": { "debug": "^4.3.4", @@ -20490,7 +20157,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "optional": true + "devOptional": true }, "node_modules/inflight": { "version": "1.0.6", @@ -20584,6 +20251,20 @@ "node": ">=6" } }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "devOptional": true, + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/into-stream": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-7.0.0.tgz", @@ -20609,38 +20290,19 @@ "loose-envify": "^1.0.0" } }, - "node_modules/ioredis": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.3.2.tgz", - "integrity": "sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==", - "optional": true, - "peer": true, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "devOptional": true, "dependencies": { - "@ioredis/commands": "^1.1.1", - "cluster-key-slot": "^1.1.0", - "debug": "^4.3.4", - "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" + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" }, "engines": { - "node": ">=12.22.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/ioredis" + "node": ">= 12" } }, - "node_modules/ip": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", - "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==", - "optional": true, - "peer": true - }, "node_modules/ip-regex": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", @@ -20869,13 +20531,13 @@ } }, "node_modules/ipfs-unixfs": { - "version": "11.1.3", - "resolved": "https://registry.npmjs.org/ipfs-unixfs/-/ipfs-unixfs-11.1.3.tgz", - "integrity": "sha512-sy6Koojwm/EcM8yvDlycRYA89C8wIcLcGTMMpqnCPUtqTCdl+JxsuPNCBgAu7tmO8Nipm7Tv7f0g/erxTGKKRA==", + "version": "11.1.4", + "resolved": "https://registry.npmjs.org/ipfs-unixfs/-/ipfs-unixfs-11.1.4.tgz", + "integrity": "sha512-RE4nyx5qgG2w7JOLj0Y0D7SfAR1ZkEdramNaBx0OSD4DlQ2Y2NORgc4FHfej3Pgy31v+QISDVP1pQJhdv3bUUg==", "dependencies": { "err-code": "^3.0.1", - "protons-runtime": "^5.0.0", - "uint8arraylist": "^2.4.3" + "protons-runtime": "^5.4.0", + "uint8arraylist": "^2.4.8" } }, "node_modules/ipfs-unixfs-importer": { @@ -21007,12 +20669,40 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "devOptional": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "devOptional": true }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "devOptional": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -21024,6 +20714,22 @@ "node": ">=8" } }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "devOptional": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", @@ -21054,6 +20760,36 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "devOptional": true, + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "devOptional": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-directory": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", @@ -21237,7 +20973,19 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "optional": true + "devOptional": true + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "devOptional": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/is-number": { "version": "7.0.0", @@ -21247,6 +20995,21 @@ "node": ">=0.12.0" } }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "devOptional": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-obj": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", @@ -21294,6 +21057,37 @@ "node": ">=0.10.0" } }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "devOptional": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "devOptional": true, + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -21306,6 +21100,36 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "devOptional": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "devOptional": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-text-path": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", @@ -21357,6 +21181,18 @@ "node": ">=0.10.0" } }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "devOptional": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -21464,14 +21300,14 @@ } }, "node_modules/istanbul-lib-instrument": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz", - "integrity": "sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz", + "integrity": "sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==", "dev": true, "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" }, @@ -21493,6 +21329,21 @@ "node": ">=10" } }, + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/istanbul-lib-source-maps": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", @@ -21508,9 +21359,9 @@ } }, "node_modules/istanbul-reports": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", - "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, "dependencies": { "html-escaper": "^2.0.0", @@ -22316,9 +22167,9 @@ } }, "node_modules/joi": { - "version": "17.12.1", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.12.1.tgz", - "integrity": "sha512-vtxmq+Lsc5SlfqotnfVjlViWfOL9nt/avKNbKYizwf6gsCfq9NYY/ceYRMFD8XDdrjJ9abJyScWmhmIiy+XRtQ==", + "version": "17.12.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.12.3.tgz", + "integrity": "sha512-2RRziagf555owrm9IRVtdKynOBeITiDpuZqIpgwqXShPncPKNiRQoiGsl/T8SQdq+8ugRzH2LqY67irr2y/d+g==", "optional": true, "peer": true, "dependencies": { @@ -22337,17 +22188,17 @@ "peer": true }, "node_modules/jose": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/jose/-/jose-5.2.0.tgz", - "integrity": "sha512-oW3PCnvyrcm1HMvGTzqjxxfnEs9EoFOFWi2HsEGhlFVOXxTE3K9GKWVMFoFw06yPUqwpvEWic1BmtUZBI/tIjw==", + "version": "4.15.5", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.5.tgz", + "integrity": "sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==", "funding": { "url": "https://github.com/sponsors/panva" } }, "node_modules/js-base64": { - "version": "3.7.6", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.6.tgz", - "integrity": "sha512-NPrWuHFxFUknr1KqJRDgUQPexQF0uIJWjeT+2KjEePhitQxQEx5EJBG1lVn5/hc8aLycTpXrDOgPQ6Zq+EDiTA==" + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.7.tgz", + "integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==" }, "node_modules/js-sha3": { "version": "0.9.3", @@ -22370,6 +22221,12 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "devOptional": true + }, "node_modules/jsc-android": { "version": "250231.0.0", "resolved": "https://registry.npmjs.org/jsc-android/-/jsc-android-250231.0.0.tgz", @@ -23131,6 +22988,26 @@ "lightningcss-win32-x64-msvc": "1.19.0" } }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.19.0.tgz", + "integrity": "sha512-wIJmFtYX0rXHsXHSr4+sC5clwblEMji7HHQ4Ub1/CznVRxtCFha6JIt5JZaNf8vQrfdZnBxLLC6R8pC818jXqg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/lightningcss-darwin-x64": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.19.0.tgz", @@ -23151,6 +23028,139 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.19.0.tgz", + "integrity": "sha512-P15VXY5682mTXaiDtbnLYQflc8BYb774j2R84FgDLJTN6Qp0ZjWEFyN1SPqyfTj2B2TFjRHRUvQSSZ7qN4Weig==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.19.0.tgz", + "integrity": "sha512-zwXRjWqpev8wqO0sv0M1aM1PpjHz6RVIsBcxKszIG83Befuh4yNysjgHVplF9RTU7eozGe3Ts7r6we1+Qkqsww==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.19.0.tgz", + "integrity": "sha512-vSCKO7SDnZaFN9zEloKSZM5/kC5gbzUjoJQ43BvUpyTFUX7ACs/mDfl2Eq6fdz2+uWhUh7vf92c4EaaP4udEtA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.19.0.tgz", + "integrity": "sha512-0AFQKvVzXf9byrXUq9z0anMGLdZJS+XSDqidyijI5njIwj6MdbvX2UZK/c4FfNmeRa2N/8ngTffoIuOUit5eIQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.19.0.tgz", + "integrity": "sha512-SJoM8CLPt6ECCgSuWe+g0qo8dqQYVcPiW2s19dxkmSI5+Uu1GIRzyKA0b7QqmEXolA+oSJhQqCmJpzjY4CuZAg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.19.0.tgz", + "integrity": "sha512-C+VuUTeSUOAaBZZOPT7Etn/agx/MatzJzGRkeV+zEABmPuntv1zihncsi+AyGmjkkzq3wVedEy7h0/4S84mUtg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss/node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "optional": true, + "peer": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -23316,13 +23326,6 @@ "optional": true, "peer": true }, - "node_modules/lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", - "optional": true, - "peer": true - }, "node_modules/lodash.escaperegexp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", @@ -23339,13 +23342,6 @@ "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" }, - "node_modules/lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", - "optional": true, - "peer": true - }, "node_modules/lodash.isboolean": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", @@ -23700,20 +23696,27 @@ "integrity": "sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA==" }, "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "dependencies": { - "semver": "^7.5.3" + "semver": "^6.0.0" }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -23724,7 +23727,7 @@ "version": "9.1.0", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", - "optional": true, + "devOptional": true, "dependencies": { "agentkeepalive": "^4.1.3", "cacache": "^15.2.0", @@ -23751,7 +23754,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "optional": true, + "devOptional": true, "dependencies": { "debug": "4" }, @@ -23763,7 +23766,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "optional": true, + "devOptional": true, "dependencies": { "@tootallnate/once": "1", "agent-base": "6", @@ -23777,7 +23780,7 @@ "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==", - "optional": true, + "devOptional": true, "dependencies": { "agent-base": "6", "debug": "4" @@ -23807,9 +23810,9 @@ } }, "node_modules/marked": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-11.2.0.tgz", - "integrity": "sha512-HR0m3bvu0jAPYiIvLUUQtdg1g6D247//lvcekpHO1WMvbwDlwSkZAX9Lw4F4YHE1T0HaaNve0tuAWuV1UJ6vtw==", + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.1.tgz", + "integrity": "sha512-Y1/V2yafOcOdWQCX0XpAKXzDakPOpn6U0YLxTJs3cww6VxOzZV1BTOOYWLvH3gX38cq+iLwljHHTnMtlDfg01Q==", "dev": true, "bin": { "marked": "bin/marked.js" @@ -23819,14 +23822,14 @@ } }, "node_modules/marked-terminal": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-6.2.0.tgz", - "integrity": "sha512-ubWhwcBFHnXsjYNsu+Wndpg0zhY4CahSpPlA70PlO0rR9r2sZpkyU+rkCsOWH+KMEkx847UpALON+HWgxowFtw==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-7.0.0.tgz", + "integrity": "sha512-sNEx8nn9Ktcm6pL0TnRz8tnXq/mSS0Q1FRSwJOAqw4lAB4l49UeDf85Gm1n9RPFm5qurCPjwi1StAQT2XExhZw==", "dev": true, "dependencies": { "ansi-escapes": "^6.2.0", - "cardinal": "^2.1.1", "chalk": "^5.3.0", + "cli-highlight": "^2.1.11", "cli-table3": "^0.6.3", "node-emoji": "^2.1.3", "supports-hyperlinks": "^3.0.0" @@ -23835,17 +23838,14 @@ "node": ">=16.0.0" }, "peerDependencies": { - "marked": ">=1 <12" + "marked": ">=1 <13" } }, "node_modules/marked-terminal/node_modules/ansi-escapes": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz", - "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", + "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", "dev": true, - "dependencies": { - "type-fest": "^3.0.0" - }, "engines": { "node": ">=14.16" }, @@ -23865,18 +23865,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/marked-terminal/node_modules/type-fest": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", - "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", - "dev": true, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/marky": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.5.tgz", @@ -24002,9 +23990,9 @@ } }, "node_modules/metro": { - "version": "0.80.5", - "resolved": "https://registry.npmjs.org/metro/-/metro-0.80.5.tgz", - "integrity": "sha512-OE/CGbOgbi8BlTN1QqJgKOBaC27dS0JBQw473JcivrpgVnqIsluROA7AavEaTVUrB9wPUZvoNVDROn5uiM2jfw==", + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro/-/metro-0.80.8.tgz", + "integrity": "sha512-in7S0W11mg+RNmcXw+2d9S3zBGmCARDxIwoXJAmLUQOQoYsRP3cpGzyJtc7WOw8+FXfpgXvceD0u+PZIHXEL7g==", "optional": true, "peer": true, "dependencies": { @@ -24023,24 +24011,24 @@ "denodeify": "^1.2.1", "error-stack-parser": "^2.0.6", "graceful-fs": "^4.2.4", - "hermes-parser": "0.18.2", + "hermes-parser": "0.20.1", "image-size": "^1.0.2", "invariant": "^2.2.4", "jest-worker": "^29.6.3", "jsc-safe-url": "^0.2.2", "lodash.throttle": "^4.1.1", - "metro-babel-transformer": "0.80.5", - "metro-cache": "0.80.5", - "metro-cache-key": "0.80.5", - "metro-config": "0.80.5", - "metro-core": "0.80.5", - "metro-file-map": "0.80.5", - "metro-resolver": "0.80.5", - "metro-runtime": "0.80.5", - "metro-source-map": "0.80.5", - "metro-symbolicate": "0.80.5", - "metro-transform-plugins": "0.80.5", - "metro-transform-worker": "0.80.5", + "metro-babel-transformer": "0.80.8", + "metro-cache": "0.80.8", + "metro-cache-key": "0.80.8", + "metro-config": "0.80.8", + "metro-core": "0.80.8", + "metro-file-map": "0.80.8", + "metro-resolver": "0.80.8", + "metro-runtime": "0.80.8", + "metro-source-map": "0.80.8", + "metro-symbolicate": "0.80.8", + "metro-transform-plugins": "0.80.8", + "metro-transform-worker": "0.80.8", "mime-types": "^2.1.27", "node-fetch": "^2.2.0", "nullthrows": "^1.1.1", @@ -24060,45 +24048,28 @@ } }, "node_modules/metro-babel-transformer": { - "version": "0.80.5", - "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.80.5.tgz", - "integrity": "sha512-sxH6hcWCorhTbk4kaShCWsadzu99WBL4Nvq4m/sDTbp32//iGuxtAnUK+ZV+6IEygr2u9Z0/4XoZ8Sbcl71MpA==", + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.80.8.tgz", + "integrity": "sha512-TTzNwRZb2xxyv4J/+yqgtDAP2qVqH3sahsnFu6Xv4SkLqzrivtlnyUbaeTdJ9JjtADJUEjCbgbFgUVafrXdR9Q==", "optional": true, "peer": true, "dependencies": { "@babel/core": "^7.20.0", - "hermes-parser": "0.18.2", + "hermes-parser": "0.20.1", "nullthrows": "^1.1.1" }, "engines": { "node": ">=18" } }, - "node_modules/metro-babel-transformer/node_modules/hermes-estree": { - "version": "0.18.2", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.18.2.tgz", - "integrity": "sha512-KoLsoWXJ5o81nit1wSyEZnWUGy9cBna9iYMZBR7skKh7okYAYKqQ9/OczwpMHn/cH0hKDyblulGsJ7FknlfVxQ==", - "optional": true, - "peer": true - }, - "node_modules/metro-babel-transformer/node_modules/hermes-parser": { - "version": "0.18.2", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.18.2.tgz", - "integrity": "sha512-1eQfvib+VPpgBZ2zYKQhpuOjw1tH+Emuib6QmjkJWJMhyjM8xnXMvA+76o9LhF0zOAJDZgPfQhg43cyXEyl5Ew==", - "optional": true, - "peer": true, - "dependencies": { - "hermes-estree": "0.18.2" - } - }, "node_modules/metro-cache": { - "version": "0.80.5", - "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.80.5.tgz", - "integrity": "sha512-2u+dQ4PZwmC7eZo9uMBNhQQMig9f+w4QWBZwXCdVy/RYOHM0eObgGdMEOwODo73uxie82T9lWzxr3aZOZ+Nqtw==", + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.80.8.tgz", + "integrity": "sha512-5svz+89wSyLo7BxdiPDlwDTgcB9kwhNMfNhiBZPNQQs1vLFXxOkILwQiV5F2EwYT9DEr6OPZ0hnJkZfRQ8lDYQ==", "optional": true, "peer": true, "dependencies": { - "metro-core": "0.80.5", + "metro-core": "0.80.8", "rimraf": "^3.0.2" }, "engines": { @@ -24106,9 +24077,9 @@ } }, "node_modules/metro-cache-key": { - "version": "0.80.5", - "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.80.5.tgz", - "integrity": "sha512-fr3QLZUarsB3tRbVcmr34kCBsTHk0Sh9JXGvBY/w3b2lbre+Lq5gtgLyFElHPecGF7o4z1eK9r3ubxtScHWcbA==", + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.80.8.tgz", + "integrity": "sha512-qWKzxrLsRQK5m3oH8ePecqCc+7PEhR03cJE6Z6AxAj0idi99dHOSitTmY0dclXVB9vP2tQIAE8uTd8xkYGk8fA==", "optional": true, "peer": true, "engines": { @@ -24116,42 +24087,42 @@ } }, "node_modules/metro-config": { - "version": "0.80.5", - "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.80.5.tgz", - "integrity": "sha512-elqo/lwvF+VjZ1OPyvmW/9hSiGlmcqu+rQvDKw5F5WMX48ZC+ySTD1WcaD7e97pkgAlJHVYqZ98FCjRAYOAFRQ==", + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.80.8.tgz", + "integrity": "sha512-VGQJpfJawtwRzGzGXVUoohpIkB0iPom4DmSbAppKfumdhtLA8uVeEPp2GM61kL9hRvdbMhdWA7T+hZFDlo4mJA==", "optional": true, "peer": true, "dependencies": { "connect": "^3.6.5", "cosmiconfig": "^5.0.5", "jest-validate": "^29.6.3", - "metro": "0.80.5", - "metro-cache": "0.80.5", - "metro-core": "0.80.5", - "metro-runtime": "0.80.5" + "metro": "0.80.8", + "metro-cache": "0.80.8", + "metro-core": "0.80.8", + "metro-runtime": "0.80.8" }, "engines": { "node": ">=18" } }, "node_modules/metro-core": { - "version": "0.80.5", - "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.80.5.tgz", - "integrity": "sha512-vkLuaBhnZxTVpaZO8ZJVEHzjaqSXpOdpAiztSZ+NDaYM6jEFgle3/XIbLW91jTSf2+T8Pj5yB1G7KuOX+BcVwg==", + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.80.8.tgz", + "integrity": "sha512-g6lud55TXeISRTleW6SHuPFZHtYrpwNqbyFIVd9j9Ofrb5IReiHp9Zl8xkAfZQp8v6ZVgyXD7c130QTsCz+vBw==", "optional": true, "peer": true, "dependencies": { "lodash.throttle": "^4.1.1", - "metro-resolver": "0.80.5" + "metro-resolver": "0.80.8" }, "engines": { "node": ">=18" } }, "node_modules/metro-file-map": { - "version": "0.80.5", - "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.80.5.tgz", - "integrity": "sha512-bKCvJ05drjq6QhQxnDUt3I8x7bTcHo3IIKVobEr14BK++nmxFGn/BmFLRzVBlghM6an3gqwpNEYxS5qNc+VKcg==", + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.80.8.tgz", + "integrity": "sha512-eQXMFM9ogTfDs2POq7DT2dnG7rayZcoEgRbHPXvhUWkVwiKkro2ngcBE++ck/7A36Cj5Ljo79SOkYwHaWUDYDw==", "optional": true, "peer": true, "dependencies": { @@ -24191,9 +24162,9 @@ "peer": true }, "node_modules/metro-minify-terser": { - "version": "0.80.5", - "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.80.5.tgz", - "integrity": "sha512-S7oZLLcab6YXUT6jYFX/ZDMN7Fq6xBGGAG8liMFU1UljX6cTcEC2u+UIafYgCLrdVexp/+ClxrIetVPZ5LtL/g==", + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.80.8.tgz", + "integrity": "sha512-y8sUFjVvdeUIINDuW1sejnIjkZfEF+7SmQo0EIpYbWmwh+kq/WMj74yVaBWuqNjirmUp1YNfi3alT67wlbBWBQ==", "optional": true, "peer": true, "dependencies": { @@ -24204,9 +24175,9 @@ } }, "node_modules/metro-resolver": { - "version": "0.80.5", - "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.80.5.tgz", - "integrity": "sha512-haJ/Hveio3zv/Fr4eXVdKzjUeHHDogYok7OpRqPSXGhTXisNXB+sLN7CpcUrCddFRUDLnVaqQOYwhYsFndgUwA==", + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.80.8.tgz", + "integrity": "sha512-JdtoJkP27GGoZ2HJlEsxs+zO7jnDUCRrmwXJozTlIuzLHMRrxgIRRby9fTCbMhaxq+iA9c+wzm3iFb4NhPmLbQ==", "optional": true, "peer": true, "engines": { @@ -24214,9 +24185,9 @@ } }, "node_modules/metro-runtime": { - "version": "0.80.5", - "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.80.5.tgz", - "integrity": "sha512-L0syTWJUdWzfUmKgkScr6fSBVTh6QDr8eKEkRtn40OBd8LPagrJGySBboWSgbyn9eIb4ayW3Y347HxgXBSAjmg==", + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.80.8.tgz", + "integrity": "sha512-2oScjfv6Yb79PelU1+p8SVrCMW9ZjgEiipxq7jMRn8mbbtWzyv3g8Mkwr+KwOoDFI/61hYPUbY8cUnu278+x1g==", "optional": true, "peer": true, "dependencies": { @@ -24227,18 +24198,18 @@ } }, "node_modules/metro-source-map": { - "version": "0.80.5", - "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.80.5.tgz", - "integrity": "sha512-DwSF4l03mKPNqCtyQ6K23I43qzU1BViAXnuH81eYWdHglP+sDlPpY+/7rUahXEo6qXEHXfAJgVoo1sirbXbmsQ==", + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.80.8.tgz", + "integrity": "sha512-+OVISBkPNxjD4eEKhblRpBf463nTMk3KMEeYS8Z4xM/z3qujGJGSsWUGRtH27+c6zElaSGtZFiDMshEb8mMKQg==", "optional": true, "peer": true, "dependencies": { "@babel/traverse": "^7.20.0", "@babel/types": "^7.20.0", "invariant": "^2.2.4", - "metro-symbolicate": "0.80.5", + "metro-symbolicate": "0.80.8", "nullthrows": "^1.1.1", - "ob1": "0.80.5", + "ob1": "0.80.8", "source-map": "^0.5.6", "vlq": "^1.0.0" }, @@ -24257,14 +24228,14 @@ } }, "node_modules/metro-symbolicate": { - "version": "0.80.5", - "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.80.5.tgz", - "integrity": "sha512-IsM4mTYvmo9JvIqwEkCZ5+YeDVPST78Q17ZgljfLdHLSpIivOHp9oVoiwQ/YGbLx0xRHRIS/tKiXueWBnj3UWA==", + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.80.8.tgz", + "integrity": "sha512-nwhYySk79jQhwjL9QmOUo4wS+/0Au9joEryDWw7uj4kz2yvw1uBjwmlql3BprQCBzRdB3fcqOP8kO8Es+vE31g==", "optional": true, "peer": true, "dependencies": { "invariant": "^2.2.4", - "metro-source-map": "0.80.5", + "metro-source-map": "0.80.8", "nullthrows": "^1.1.1", "source-map": "^0.5.6", "through2": "^2.0.1", @@ -24288,9 +24259,9 @@ } }, "node_modules/metro-transform-plugins": { - "version": "0.80.5", - "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.80.5.tgz", - "integrity": "sha512-7IdlTqK/k5+qE3RvIU5QdCJUPk4tHWEqgVuYZu8exeW+s6qOJ66hGIJjXY/P7ccucqF+D4nsbAAW5unkoUdS6g==", + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.80.8.tgz", + "integrity": "sha512-sSu8VPL9Od7w98MftCOkQ1UDeySWbsIAS5I54rW22BVpPnI3fQ42srvqMLaJUQPjLehUanq8St6OMBCBgH/UWw==", "optional": true, "peer": true, "dependencies": { @@ -24305,9 +24276,9 @@ } }, "node_modules/metro-transform-worker": { - "version": "0.80.5", - "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.80.5.tgz", - "integrity": "sha512-Q1oM7hfP+RBgAtzRFBDjPhArELUJF8iRCZ8OidqCpYzQJVGuJZ7InSnIf3hn1JyqiUQwv2f1LXBO78i2rAjzyA==", + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.80.8.tgz", + "integrity": "sha512-+4FG3TQk3BTbNqGkFb2uCaxYTfsbuFOCKMMURbwu0ehCP8ZJuTUramkaNZoATS49NSAkRgUltgmBa4YaKZ5mqw==", "optional": true, "peer": true, "dependencies": { @@ -24315,13 +24286,13 @@ "@babel/generator": "^7.20.0", "@babel/parser": "^7.20.0", "@babel/types": "^7.20.0", - "metro": "0.80.5", - "metro-babel-transformer": "0.80.5", - "metro-cache": "0.80.5", - "metro-cache-key": "0.80.5", - "metro-minify-terser": "0.80.5", - "metro-source-map": "0.80.5", - "metro-transform-plugins": "0.80.5", + "metro": "0.80.8", + "metro-babel-transformer": "0.80.8", + "metro-cache": "0.80.8", + "metro-cache-key": "0.80.8", + "metro-minify-terser": "0.80.8", + "metro-source-map": "0.80.8", + "metro-transform-plugins": "0.80.8", "nullthrows": "^1.1.1" }, "engines": { @@ -24360,23 +24331,6 @@ "ms": "2.0.0" } }, - "node_modules/metro/node_modules/hermes-estree": { - "version": "0.18.2", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.18.2.tgz", - "integrity": "sha512-KoLsoWXJ5o81nit1wSyEZnWUGy9cBna9iYMZBR7skKh7okYAYKqQ9/OczwpMHn/cH0hKDyblulGsJ7FknlfVxQ==", - "optional": true, - "peer": true - }, - "node_modules/metro/node_modules/hermes-parser": { - "version": "0.18.2", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.18.2.tgz", - "integrity": "sha512-1eQfvib+VPpgBZ2zYKQhpuOjw1tH+Emuib6QmjkJWJMhyjM8xnXMvA+76o9LhF0zOAJDZgPfQhg43cyXEyl5Ew==", - "optional": true, - "peer": true, - "dependencies": { - "hermes-estree": "0.18.2" - } - }, "node_modules/metro/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -24544,7 +24498,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "optional": true, + "devOptional": true, "dependencies": { "minipass": "^3.0.0" }, @@ -24556,7 +24510,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", - "optional": true, + "devOptional": true, "dependencies": { "minipass": "^3.1.0", "minipass-sized": "^1.0.3", @@ -24573,7 +24527,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "optional": true, + "devOptional": true, "dependencies": { "minipass": "^3.0.0" }, @@ -24585,7 +24539,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "optional": true, + "devOptional": true, "dependencies": { "minipass": "^3.0.0" }, @@ -24597,7 +24551,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "optional": true, + "devOptional": true, "dependencies": { "minipass": "^3.0.0" }, @@ -24907,9 +24861,9 @@ } }, "node_modules/node-abi": { - "version": "3.54.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.54.0.tgz", - "integrity": "sha512-p7eGEiQil0YUV3ItH4/tBb781L5impVmmx2E9FRKF7d18XXzp4PGT2tdYMFY6wQqgxD0IwNZOiSJ0/K0fSi/OA==", + "version": "3.58.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.58.0.tgz", + "integrity": "sha512-pXY1jnGf5T7b8UNzWzIqf0EkX4bx/w8N2AvwlGnk2SYYA/kzDVPaH0Dh0UG4EwxBB5eKOIZKPr8VAHSHL1DPGg==", "dependencies": { "semver": "^7.3.5" }, @@ -25022,7 +24976,7 @@ "version": "8.4.1", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", - "optional": true, + "devOptional": true, "dependencies": { "env-paths": "^2.2.0", "glob": "^7.1.4", @@ -25052,6 +25006,67 @@ "node-gyp-build-test": "build-test.js" } }, + "node_modules/node-gyp/node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "devOptional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "devOptional": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "devOptional": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "devOptional": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -25166,9 +25181,9 @@ } }, "node_modules/normalize-url": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", - "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz", + "integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==", "dev": true, "engines": { "node": ">=14.16" @@ -25178,9 +25193,9 @@ } }, "node_modules/npm": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/npm/-/npm-10.4.0.tgz", - "integrity": "sha512-RS7Mx0OVfXlOcQLRePuDIYdFCVBPCNapWHplDK+mh7GDdP/Tvor4ocuybRRPSvfcRb2vjRJt1fHCqw3cr8qACQ==", + "version": "10.5.2", + "resolved": "https://registry.npmjs.org/npm/-/npm-10.5.2.tgz", + "integrity": "sha512-cHVG7QEJwJdZyOrK0dKX5uf3R5Fd0E8AcmSES1jLtO52UT1enUKZ96Onw/xwq4CbrTZEnDuu2Vf9kCQh/Sd12w==", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", @@ -25189,6 +25204,7 @@ "@npmcli/map-workspaces", "@npmcli/package-json", "@npmcli/promise-spawn", + "@npmcli/redact", "@npmcli/run-script", "@sigstore/tuf", "abbrev", @@ -25254,32 +25270,40 @@ "write-file-atomic" ], "dev": true, + "workspaces": [ + "docs", + "smoke-tests", + "mock-globals", + "mock-registry", + "workspaces/*" + ], "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/arborist": "^7.2.1", "@npmcli/config": "^8.0.2", "@npmcli/fs": "^3.1.0", - "@npmcli/map-workspaces": "^3.0.4", - "@npmcli/package-json": "^5.0.0", + "@npmcli/map-workspaces": "^3.0.6", + "@npmcli/package-json": "^5.0.2", "@npmcli/promise-spawn": "^7.0.1", + "@npmcli/redact": "^1.1.0", "@npmcli/run-script": "^7.0.4", - "@sigstore/tuf": "^2.3.0", + "@sigstore/tuf": "^2.3.2", "abbrev": "^2.0.0", "archy": "~1.0.0", "cacache": "^18.0.2", "chalk": "^5.3.0", "ci-info": "^4.0.0", "cli-columns": "^4.0.0", - "cli-table3": "^0.6.3", + "cli-table3": "^0.6.4", "columnify": "^1.6.0", "fastest-levenshtein": "^1.0.16", "fs-minipass": "^3.0.3", - "glob": "^10.3.10", + "glob": "^10.3.12", "graceful-fs": "^4.2.11", "hosted-git-info": "^7.0.1", - "ini": "^4.1.1", - "init-package-json": "^6.0.0", - "is-cidr": "^5.0.3", + "ini": "^4.1.2", + "init-package-json": "^6.0.2", + "is-cidr": "^5.0.5", "json-parse-even-better-errors": "^3.0.1", "libnpmaccess": "^8.0.1", "libnpmdiff": "^6.0.3", @@ -25293,11 +25317,11 @@ "libnpmteam": "^6.0.0", "libnpmversion": "^5.0.1", "make-fetch-happen": "^13.0.0", - "minimatch": "^9.0.3", + "minimatch": "^9.0.4", "minipass": "^7.0.4", "minipass-pipeline": "^1.2.4", "ms": "^2.1.2", - "node-gyp": "^10.0.1", + "node-gyp": "^10.1.0", "nopt": "^7.2.0", "normalize-package-data": "^6.0.0", "npm-audit-report": "^5.0.0", @@ -25305,7 +25329,7 @@ "npm-package-arg": "^11.0.1", "npm-pick-manifest": "^9.0.0", "npm-profile": "^9.0.0", - "npm-registry-fetch": "^16.1.0", + "npm-registry-fetch": "^16.2.0", "npm-user-validate": "^2.0.0", "npmlog": "^7.0.1", "p-map": "^4.0.0", @@ -25313,12 +25337,12 @@ "parse-conflict-json": "^3.0.1", "proc-log": "^3.0.0", "qrcode-terminal": "^0.12.0", - "read": "^2.1.0", - "semver": "^7.5.4", - "spdx-expression-parse": "^3.0.1", + "read": "^3.0.1", + "semver": "^7.6.0", + "spdx-expression-parse": "^4.0.0", "ssri": "^10.0.5", "supports-color": "^9.4.0", - "tar": "^6.2.0", + "tar": "^6.2.1", "text-table": "~0.2.0", "tiny-relative-date": "^1.3.0", "treeverse": "^3.0.0", @@ -25338,8 +25362,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-7.0.0.tgz", "integrity": "sha512-xXxr8y5U0kl8dVkz2oK7yZjPBvqM2fwaO5l3Yg13p03v8+E3qQcD0JNhHzjL1vyGgxcKkD0cco+NLR72iuPk3g==", - "optional": true, - "peer": true, + "devOptional": true, "dependencies": { "hosted-git-info": "^3.0.2", "osenv": "^0.1.5", @@ -25351,8 +25374,7 @@ "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "optional": true, - "peer": true, + "devOptional": true, "bin": { "semver": "bin/semver" } @@ -25453,7 +25475,7 @@ "license": "ISC" }, "node_modules/npm/node_modules/@npmcli/agent": { - "version": "2.2.0", + "version": "2.2.2", "dev": true, "inBundle": true, "license": "ISC", @@ -25462,14 +25484,14 @@ "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.1", "lru-cache": "^10.0.1", - "socks-proxy-agent": "^8.0.1" + "socks-proxy-agent": "^8.0.3" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/npm/node_modules/@npmcli/arborist": { - "version": "7.3.1", + "version": "7.4.2", "dev": true, "inBundle": true, "license": "ISC", @@ -25482,7 +25504,8 @@ "@npmcli/name-from-folder": "^2.0.0", "@npmcli/node-gyp": "^3.0.0", "@npmcli/package-json": "^5.0.0", - "@npmcli/query": "^3.0.1", + "@npmcli/query": "^3.1.0", + "@npmcli/redact": "^1.1.0", "@npmcli/run-script": "^7.0.2", "bin-links": "^4.0.1", "cacache": "^18.0.0", @@ -25490,12 +25513,12 @@ "hosted-git-info": "^7.0.1", "json-parse-even-better-errors": "^3.0.0", "json-stringify-nice": "^1.1.4", - "minimatch": "^9.0.0", + "minimatch": "^9.0.4", "nopt": "^7.0.0", "npm-install-checks": "^6.2.0", "npm-package-arg": "^11.0.1", "npm-pick-manifest": "^9.0.0", - "npm-registry-fetch": "^16.0.0", + "npm-registry-fetch": "^16.2.0", "npmlog": "^7.0.1", "pacote": "^17.0.4", "parse-conflict-json": "^3.0.0", @@ -25516,14 +25539,14 @@ } }, "node_modules/npm/node_modules/@npmcli/config": { - "version": "8.1.0", + "version": "8.2.2", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "@npmcli/map-workspaces": "^3.0.2", "ci-info": "^4.0.0", - "ini": "^4.1.0", + "ini": "^4.1.2", "nopt": "^7.0.0", "proc-log": "^3.0.0", "read-package-json-fast": "^3.0.2", @@ -25574,7 +25597,7 @@ } }, "node_modules/npm/node_modules/@npmcli/git": { - "version": "5.0.4", + "version": "5.0.5", "dev": true, "inBundle": true, "license": "ISC", @@ -25609,7 +25632,7 @@ } }, "node_modules/npm/node_modules/@npmcli/map-workspaces": { - "version": "3.0.4", + "version": "3.0.6", "dev": true, "inBundle": true, "license": "ISC", @@ -25657,7 +25680,7 @@ } }, "node_modules/npm/node_modules/@npmcli/package-json": { - "version": "5.0.0", + "version": "5.0.2", "dev": true, "inBundle": true, "license": "ISC", @@ -25687,7 +25710,7 @@ } }, "node_modules/npm/node_modules/@npmcli/query": { - "version": "3.0.1", + "version": "3.1.0", "dev": true, "inBundle": true, "license": "ISC", @@ -25698,6 +25721,15 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/npm/node_modules/@npmcli/redact": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, "node_modules/npm/node_modules/@npmcli/run-script": { "version": "7.0.4", "dev": true, @@ -25725,19 +25757,19 @@ } }, "node_modules/npm/node_modules/@sigstore/bundle": { - "version": "2.1.1", + "version": "2.3.1", "dev": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@sigstore/protobuf-specs": "^0.2.1" + "@sigstore/protobuf-specs": "^0.3.1" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/npm/node_modules/@sigstore/core": { - "version": "0.2.0", + "version": "1.1.0", "dev": true, "inBundle": true, "license": "Apache-2.0", @@ -25746,23 +25778,23 @@ } }, "node_modules/npm/node_modules/@sigstore/protobuf-specs": { - "version": "0.2.1", + "version": "0.3.1", "dev": true, "inBundle": true, "license": "Apache-2.0", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^16.14.0 || >=18.0.0" } }, "node_modules/npm/node_modules/@sigstore/sign": { - "version": "2.2.1", + "version": "2.3.0", "dev": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@sigstore/bundle": "^2.1.1", - "@sigstore/core": "^0.2.0", - "@sigstore/protobuf-specs": "^0.2.1", + "@sigstore/bundle": "^2.3.0", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.1", "make-fetch-happen": "^13.0.0" }, "engines": { @@ -25770,12 +25802,12 @@ } }, "node_modules/npm/node_modules/@sigstore/tuf": { - "version": "2.3.0", + "version": "2.3.2", "dev": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@sigstore/protobuf-specs": "^0.2.1", + "@sigstore/protobuf-specs": "^0.3.0", "tuf-js": "^2.2.0" }, "engines": { @@ -25783,14 +25815,14 @@ } }, "node_modules/npm/node_modules/@sigstore/verify": { - "version": "0.1.0", + "version": "1.2.0", "dev": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@sigstore/bundle": "^2.1.1", - "@sigstore/core": "^0.2.0", - "@sigstore/protobuf-specs": "^0.2.1" + "@sigstore/bundle": "^2.3.1", + "@sigstore/core": "^1.1.0", + "@sigstore/protobuf-specs": "^0.3.1" }, "engines": { "node": "^16.14.0 || >=18.0.0" @@ -25828,7 +25860,7 @@ } }, "node_modules/npm/node_modules/agent-base": { - "version": "7.1.0", + "version": "7.1.1", "dev": true, "inBundle": true, "license": "MIT", @@ -25916,12 +25948,15 @@ } }, "node_modules/npm/node_modules/binary-extensions": { - "version": "2.2.0", + "version": "2.3.0", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/npm/node_modules/brace-expansion": { @@ -25934,7 +25969,7 @@ } }, "node_modules/npm/node_modules/builtins": { - "version": "5.0.1", + "version": "5.1.0", "dev": true, "inBundle": true, "license": "MIT", @@ -26002,7 +26037,7 @@ } }, "node_modules/npm/node_modules/cidr-regex": { - "version": "4.0.3", + "version": "4.0.5", "dev": true, "inBundle": true, "license": "BSD-2-Clause", @@ -26036,7 +26071,7 @@ } }, "node_modules/npm/node_modules/cli-table3": { - "version": "0.6.3", + "version": "0.6.4", "dev": true, "inBundle": true, "license": "MIT", @@ -26197,7 +26232,7 @@ } }, "node_modules/npm/node_modules/diff": { - "version": "5.1.0", + "version": "5.2.0", "dev": true, "inBundle": true, "license": "BSD-3-Clause", @@ -26314,16 +26349,16 @@ } }, "node_modules/npm/node_modules/glob": { - "version": "10.3.10", + "version": "10.3.12", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", + "jackspeak": "^2.3.6", "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -26348,7 +26383,7 @@ "license": "ISC" }, "node_modules/npm/node_modules/hasown": { - "version": "2.0.0", + "version": "2.0.2", "dev": true, "inBundle": true, "license": "MIT", @@ -26378,7 +26413,7 @@ "license": "BSD-2-Clause" }, "node_modules/npm/node_modules/http-proxy-agent": { - "version": "7.0.0", + "version": "7.0.2", "dev": true, "inBundle": true, "license": "MIT", @@ -26391,7 +26426,7 @@ } }, "node_modules/npm/node_modules/https-proxy-agent": { - "version": "7.0.2", + "version": "7.0.4", "dev": true, "inBundle": true, "license": "MIT", @@ -26447,7 +26482,7 @@ } }, "node_modules/npm/node_modules/ini": { - "version": "4.1.1", + "version": "4.1.2", "dev": true, "inBundle": true, "license": "ISC", @@ -26456,15 +26491,15 @@ } }, "node_modules/npm/node_modules/init-package-json": { - "version": "6.0.0", + "version": "6.0.2", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { + "@npmcli/package-json": "^5.0.0", "npm-package-arg": "^11.0.0", "promzard": "^1.0.0", - "read": "^2.0.0", - "read-package-json": "^7.0.0", + "read": "^3.0.1", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4", "validate-npm-package-name": "^5.0.0" @@ -26473,11 +26508,24 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/npm/node_modules/ip": { - "version": "2.0.0", + "node_modules/npm/node_modules/ip-address": { + "version": "9.0.5", "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/npm/node_modules/ip-address/node_modules/sprintf-js": { + "version": "1.1.3", + "dev": true, + "inBundle": true, + "license": "BSD-3-Clause" }, "node_modules/npm/node_modules/ip-regex": { "version": "5.0.0", @@ -26492,12 +26540,12 @@ } }, "node_modules/npm/node_modules/is-cidr": { - "version": "5.0.3", + "version": "5.0.5", "dev": true, "inBundle": true, "license": "BSD-2-Clause", "dependencies": { - "cidr-regex": "4.0.3" + "cidr-regex": "^4.0.4" }, "engines": { "node": ">=14" @@ -26554,6 +26602,12 @@ "@pkgjs/parseargs": "^0.11.0" } }, + "node_modules/npm/node_modules/jsbn": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, "node_modules/npm/node_modules/json-parse-even-better-errors": { "version": "3.0.1", "dev": true, @@ -26594,20 +26648,20 @@ "license": "MIT" }, "node_modules/npm/node_modules/libnpmaccess": { - "version": "8.0.2", + "version": "8.0.3", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "npm-package-arg": "^11.0.1", - "npm-registry-fetch": "^16.0.0" + "npm-registry-fetch": "^16.2.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/npm/node_modules/libnpmdiff": { - "version": "6.0.6", + "version": "6.0.9", "dev": true, "inBundle": true, "license": "ISC", @@ -26615,19 +26669,19 @@ "@npmcli/arborist": "^7.2.1", "@npmcli/disparity-colors": "^3.0.0", "@npmcli/installed-package-contents": "^2.0.2", - "binary-extensions": "^2.2.0", + "binary-extensions": "^2.3.0", "diff": "^5.1.0", - "minimatch": "^9.0.0", + "minimatch": "^9.0.4", "npm-package-arg": "^11.0.1", "pacote": "^17.0.4", - "tar": "^6.2.0" + "tar": "^6.2.1" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/npm/node_modules/libnpmexec": { - "version": "7.0.7", + "version": "7.0.10", "dev": true, "inBundle": true, "license": "ISC", @@ -26639,7 +26693,7 @@ "npmlog": "^7.0.1", "pacote": "^17.0.4", "proc-log": "^3.0.0", - "read": "^2.0.0", + "read": "^3.0.1", "read-package-json-fast": "^3.0.2", "semver": "^7.3.7", "walk-up-path": "^3.0.1" @@ -26649,7 +26703,7 @@ } }, "node_modules/npm/node_modules/libnpmfund": { - "version": "5.0.4", + "version": "5.0.7", "dev": true, "inBundle": true, "license": "ISC", @@ -26661,33 +26715,33 @@ } }, "node_modules/npm/node_modules/libnpmhook": { - "version": "10.0.1", + "version": "10.0.2", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "aproba": "^2.0.0", - "npm-registry-fetch": "^16.0.0" + "npm-registry-fetch": "^16.2.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/npm/node_modules/libnpmorg": { - "version": "6.0.2", + "version": "6.0.3", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "aproba": "^2.0.0", - "npm-registry-fetch": "^16.0.0" + "npm-registry-fetch": "^16.2.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/npm/node_modules/libnpmpack": { - "version": "6.0.6", + "version": "6.0.9", "dev": true, "inBundle": true, "license": "ISC", @@ -26702,7 +26756,7 @@ } }, "node_modules/npm/node_modules/libnpmpublish": { - "version": "9.0.4", + "version": "9.0.5", "dev": true, "inBundle": true, "license": "ISC", @@ -26710,7 +26764,7 @@ "ci-info": "^4.0.0", "normalize-package-data": "^6.0.0", "npm-package-arg": "^11.0.1", - "npm-registry-fetch": "^16.0.0", + "npm-registry-fetch": "^16.2.0", "proc-log": "^3.0.0", "semver": "^7.3.7", "sigstore": "^2.2.0", @@ -26721,25 +26775,25 @@ } }, "node_modules/npm/node_modules/libnpmsearch": { - "version": "7.0.1", + "version": "7.0.2", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "npm-registry-fetch": "^16.0.0" + "npm-registry-fetch": "^16.2.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/npm/node_modules/libnpmteam": { - "version": "6.0.1", + "version": "6.0.2", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "aproba": "^2.0.0", - "npm-registry-fetch": "^16.0.0" + "npm-registry-fetch": "^16.2.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" @@ -26762,7 +26816,7 @@ } }, "node_modules/npm/node_modules/lru-cache": { - "version": "10.1.0", + "version": "10.2.0", "dev": true, "inBundle": true, "license": "ISC", @@ -26793,7 +26847,7 @@ } }, "node_modules/npm/node_modules/minimatch": { - "version": "9.0.3", + "version": "9.0.4", "dev": true, "inBundle": true, "license": "ISC", @@ -27001,7 +27055,7 @@ } }, "node_modules/npm/node_modules/node-gyp": { - "version": "10.0.1", + "version": "10.1.0", "dev": true, "inBundle": true, "license": "MIT", @@ -27152,11 +27206,12 @@ } }, "node_modules/npm/node_modules/npm-registry-fetch": { - "version": "16.1.0", + "version": "16.2.0", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { + "@npmcli/redact": "^1.1.0", "make-fetch-happen": "^13.0.0", "minipass": "^7.0.2", "minipass-fetch": "^3.0.0", @@ -27264,12 +27319,12 @@ } }, "node_modules/npm/node_modules/path-scurry": { - "version": "1.10.1", + "version": "1.10.2", "dev": true, "inBundle": true, "license": "BlueOak-1.0.0", "dependencies": { - "lru-cache": "^9.1.1 || ^10.0.0", + "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { @@ -27280,7 +27335,7 @@ } }, "node_modules/npm/node_modules/postcss-selector-parser": { - "version": "6.0.15", + "version": "6.0.16", "dev": true, "inBundle": true, "license": "MIT", @@ -27339,12 +27394,12 @@ } }, "node_modules/npm/node_modules/promzard": { - "version": "1.0.0", + "version": "1.0.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "read": "^2.0.0" + "read": "^3.0.1" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -27359,12 +27414,12 @@ } }, "node_modules/npm/node_modules/read": { - "version": "2.1.0", + "version": "3.0.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "mute-stream": "~1.0.0" + "mute-stream": "^1.0.0" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -27424,7 +27479,7 @@ "optional": true }, "node_modules/npm/node_modules/semver": { - "version": "7.5.4", + "version": "7.6.0", "dev": true, "inBundle": true, "license": "ISC", @@ -27490,17 +27545,17 @@ } }, "node_modules/npm/node_modules/sigstore": { - "version": "2.2.0", + "version": "2.3.0", "dev": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@sigstore/bundle": "^2.1.1", - "@sigstore/core": "^0.2.0", - "@sigstore/protobuf-specs": "^0.2.1", - "@sigstore/sign": "^2.2.1", - "@sigstore/tuf": "^2.3.0", - "@sigstore/verify": "^0.1.0" + "@sigstore/bundle": "^2.3.1", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.1", + "@sigstore/sign": "^2.3.0", + "@sigstore/tuf": "^2.3.1", + "@sigstore/verify": "^1.2.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" @@ -27517,26 +27572,26 @@ } }, "node_modules/npm/node_modules/socks": { - "version": "2.7.1", + "version": "2.8.3", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { - "ip": "^2.0.0", + "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" }, "engines": { - "node": ">= 10.13.0", + "node": ">= 10.0.0", "npm": ">= 3.0.0" } }, "node_modules/npm/node_modules/socks-proxy-agent": { - "version": "8.0.2", + "version": "8.0.3", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { - "agent-base": "^7.0.2", + "agent-base": "^7.1.1", "debug": "^4.3.4", "socks": "^2.7.1" }, @@ -27554,14 +27609,24 @@ "spdx-license-ids": "^3.0.0" } }, + "node_modules/npm/node_modules/spdx-correct/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, "node_modules/npm/node_modules/spdx-exceptions": { - "version": "2.3.0", + "version": "2.5.0", "dev": true, "inBundle": true, "license": "CC-BY-3.0" }, "node_modules/npm/node_modules/spdx-expression-parse": { - "version": "3.0.1", + "version": "4.0.0", "dev": true, "inBundle": true, "license": "MIT", @@ -27571,7 +27636,7 @@ } }, "node_modules/npm/node_modules/spdx-license-ids": { - "version": "3.0.16", + "version": "3.0.17", "dev": true, "inBundle": true, "license": "CC0-1.0" @@ -27655,7 +27720,7 @@ } }, "node_modules/npm/node_modules/tar": { - "version": "6.2.0", + "version": "6.2.1", "dev": true, "inBundle": true, "license": "ISC", @@ -27779,6 +27844,16 @@ "spdx-expression-parse": "^3.0.0" } }, + "node_modules/npm/node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, "node_modules/npm/node_modules/validate-npm-package-name": { "version": "5.0.0", "dev": true, @@ -27959,18 +28034,14 @@ "license": "ISC" }, "node_modules/npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "optional": true, + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", "dependencies": { - "are-we-there-yet": "^3.0.0", + "are-we-there-yet": "^2.0.0", "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", + "gauge": "^3.0.0", "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/nullthrows": { @@ -27981,9 +28052,9 @@ "peer": true }, "node_modules/ob1": { - "version": "0.80.5", - "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.80.5.tgz", - "integrity": "sha512-zYDMnnNrFi/1Tqh0vo3PE4p97Tpl9/4MP2k2ECvkbLOZzQuAYZJLTUYVLZb7hJhbhjT+JJxAwBGS8iu5hCSd1w==", + "version": "0.80.8", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.80.8.tgz", + "integrity": "sha512-QHJQk/lXMmAW8I7AIM3in1MSlwe1umR72Chhi8B7Xnq6mzjhBKkA6Fy/zAhQnGkA4S912EPCEvTij5yh+EQTAA==", "optional": true, "peer": true, "engines": { @@ -28014,6 +28085,24 @@ "node": ">= 0.4" } }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "devOptional": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/ofetch": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.3.4.tgz", @@ -28241,8 +28330,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", - "optional": true, - "peer": true, + "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -28251,8 +28339,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "optional": true, - "peer": true, + "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -28261,8 +28348,7 @@ "version": "0.1.5", "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "optional": true, - "peer": true, + "devOptional": true, "dependencies": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" @@ -28313,9 +28399,9 @@ } }, "node_modules/p-filter/node_modules/p-map": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.1.tgz", - "integrity": "sha512-2wnaR0XL/FDOj+TgpDuRb2KTjLnu3Fma6b1ZUwGY7LcqenMcvP/YFpjpbPKY6WVGsbuJZRuoUz8iPrt8ORnAFw==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.2.tgz", + "integrity": "sha512-z4cYYMMdKHzw4O5UkWJImbZynVIo0lSGTXc7bzB1e/rrDqkgGUNysK/o4bTr+0+xKvvLoTyGqYC4Fgljy9qe1Q==", "dev": true, "engines": { "node": ">=18" @@ -28377,7 +28463,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "optional": true, + "devOptional": true, "dependencies": { "aggregate-error": "^3.0.0" }, @@ -28405,11 +28491,6 @@ "node": ">=6" } }, - "node_modules/packet-reader": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", - "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" - }, "node_modules/pako": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", @@ -28531,11 +28612,11 @@ "devOptional": true }, "node_modules/path-scurry": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", - "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", + "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", "dependencies": { - "lru-cache": "^9.1.1 || ^10.0.0", + "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { @@ -28608,15 +28689,13 @@ } }, "node_modules/pg": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz", - "integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==", - "dependencies": { - "buffer-writer": "2.0.0", - "packet-reader": "1.0.0", - "pg-connection-string": "^2.6.2", - "pg-pool": "^3.6.1", - "pg-protocol": "^1.6.0", + "version": "8.11.5", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.5.tgz", + "integrity": "sha512-jqgNHSKL5cbDjFlHyYsCXmQDrfIX/3RsNwYqpd4N0Kt8niLuNoRNH+aazv6cOd43gPh9Y4DjQCtb+X0MH0Hvnw==", + "dependencies": { + "pg-connection-string": "^2.6.4", + "pg-pool": "^3.6.2", + "pg-protocol": "^1.6.1", "pg-types": "^2.1.0", "pgpass": "1.x" }, @@ -28642,9 +28721,9 @@ "optional": true }, "node_modules/pg-connection-string": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", - "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==" + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.4.tgz", + "integrity": "sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==" }, "node_modules/pg-int8": { "version": "1.0.1", @@ -28655,17 +28734,17 @@ } }, "node_modules/pg-pool": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz", - "integrity": "sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.2.tgz", + "integrity": "sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==", "peerDependencies": { "pg": ">=8.0" } }, "node_modules/pg-protocol": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", - "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.1.tgz", + "integrity": "sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==" }, "node_modules/pg-types": { "version": "2.2.0", @@ -29013,9 +29092,9 @@ } }, "node_modules/postcss": { - "version": "8.4.33", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", - "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", "funding": [ { "type": "opencollective", @@ -29035,7 +29114,7 @@ "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "source-map-js": "^1.2.0" }, "engines": { "node": "^10 || ^12 || >=14" @@ -29333,9 +29412,9 @@ } }, "node_modules/prebuild-install": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", - "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", + "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", @@ -29357,14 +29436,6 @@ "node": ">=10" } }, - "node_modules/prebuild-install/node_modules/detect-libc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", - "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", - "engines": { - "node": ">=8" - } - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -29375,9 +29446,9 @@ } }, "node_modules/prettier": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.4.tgz", - "integrity": "sha512-FWu1oLHKCrtpO1ypU6J0SbK2d9Ckwysq6bHj/uaCP26DxrPpppCLQRGVuqAxSTvhF00AcvDRyYrLNW7ocBhFFQ==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -29470,13 +29541,13 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "optional": true + "devOptional": true }, "node_modules/promise-retry": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "optional": true, + "devOptional": true, "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" @@ -29489,7 +29560,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "optional": true + "devOptional": true }, "node_modules/prompts": { "version": "2.4.2", @@ -29553,9 +29624,9 @@ } }, "node_modules/protons-runtime": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-5.3.0.tgz", - "integrity": "sha512-RySXxx+jvz4mi/rr2VsnvgWvC6dFP2pVyWpVRFYb/jxmwih862ZjXJLUkjd+nOtXBx0Lwk2xeuY2f2fmd3FT9w==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-5.4.0.tgz", + "integrity": "sha512-XfA++W/WlQOSyjUyuF5lgYBfXZUEMP01Oh1C2dSwZAlF2e/ZrMRPfWonXj6BGM+o8Xciv7w0tsRMKYwYEuQvaw==", "dependencies": { "uint8-varint": "^2.0.2", "uint8arraylist": "^2.4.3", @@ -29612,9 +29683,9 @@ } }, "node_modules/pure-rand": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", - "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", "dev": true, "funding": [ { @@ -29664,8 +29735,7 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.11.0.tgz", "integrity": "sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ==", - "optional": true, - "peer": true, + "devOptional": true, "bin": { "qrcode-terminal": "bin/qrcode-terminal.js" } @@ -30014,19 +30084,19 @@ "devOptional": true }, "node_modules/react-native": { - "version": "0.73.3", - "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.73.3.tgz", - "integrity": "sha512-RSQDtT2DNUcmB4IgmW9NhRb5wqvXFl6DI2NEJmt0ps2OrVHpoA8Tkq+lkFOA/fvPscJKtFKEHFBDSR5UHR3PUw==", + "version": "0.73.6", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.73.6.tgz", + "integrity": "sha512-oqmZe8D2/VolIzSPZw+oUd6j/bEmeRHwsLn1xLA5wllEYsZ5zNuMsDus235ONOnCRwexqof/J3aztyQswSmiaA==", "optional": true, "peer": true, "dependencies": { "@jest/create-cache-key-function": "^29.6.3", - "@react-native-community/cli": "12.3.2", - "@react-native-community/cli-platform-android": "12.3.2", - "@react-native-community/cli-platform-ios": "12.3.2", + "@react-native-community/cli": "12.3.6", + "@react-native-community/cli-platform-android": "12.3.6", + "@react-native-community/cli-platform-ios": "12.3.6", "@react-native/assets-registry": "0.73.1", - "@react-native/codegen": "0.73.2", - "@react-native/community-cli-plugin": "0.73.14", + "@react-native/codegen": "0.73.3", + "@react-native/community-cli-plugin": "0.73.17", "@react-native/gradle-plugin": "0.73.4", "@react-native/js-polyfills": "0.73.1", "@react-native/normalize-colors": "0.73.2", @@ -30106,6 +30176,28 @@ "node": ">= 10.14.2" } }, + "node_modules/react-native/node_modules/@react-native/codegen": { + "version": "0.73.3", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.73.3.tgz", + "integrity": "sha512-sxslCAAb8kM06vGy9Jyh4TtvjhcP36k/rvj2QE2Jdhdm61KvfafCATSIsOfc0QvnduWFcpXUPvAVyYwuv7PYDg==", + "optional": true, + "peer": true, + "dependencies": { + "@babel/parser": "^7.20.0", + "flow-parser": "^0.206.0", + "glob": "^7.1.1", + "invariant": "^2.2.4", + "jscodeshift": "^0.14.0", + "mkdirp": "^0.5.1", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@babel/preset-env": "^7.1.6" + } + }, "node_modules/react-native/node_modules/@types/yargs": { "version": "15.0.19", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.19.tgz", @@ -30131,6 +30223,16 @@ "node": ">=12" } }, + "node_modules/react-native/node_modules/flow-parser": { + "version": "0.206.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.206.0.tgz", + "integrity": "sha512-HVzoK3r6Vsg+lKvlIZzaWNBVai+FXTX1wdYhz/wVlH13tb/gOdLXmlTqy6odmTBhT5UoWUbq0k8263Qhr9d88w==", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/react-native/node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", @@ -30237,6 +30339,35 @@ "react": "^16.0.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/read-package-up": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz", + "integrity": "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==", + "dev": true, + "dependencies": { + "find-up-simple": "^1.0.0", + "read-pkg": "^9.0.0", + "type-fest": "^4.6.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-package-up/node_modules/type-fest": { + "version": "4.15.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.15.0.tgz", + "integrity": "sha512-tB9lu0pQpX5KJq54g+oHOLumOx+pMep4RaM6liXh2PKmVRFF+/vAtUP0ZaJ0kOySfVNjF6doBWPHhBhISKdlIA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/read-pkg": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", @@ -30275,9 +30406,9 @@ } }, "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "4.10.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.10.2.tgz", - "integrity": "sha512-anpAG63wSpdEbLwOqH8L84urkL6PiVIov3EMmgIhhThevh9aiMQov+6Btx0wldNcvm4wV+e2/Rt1QdDwKHFbHw==", + "version": "4.15.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.15.0.tgz", + "integrity": "sha512-tB9lu0pQpX5KJq54g+oHOLumOx+pMep4RaM6liXh2PKmVRFF+/vAtUP0ZaJ0kOySfVNjF6doBWPHhBhISKdlIA==", "dev": true, "engines": { "node": ">=16" @@ -30304,9 +30435,9 @@ } }, "node_modules/read-pkg/node_modules/type-fest": { - "version": "4.10.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.10.2.tgz", - "integrity": "sha512-anpAG63wSpdEbLwOqH8L84urkL6PiVIov3EMmgIhhThevh9aiMQov+6Btx0wldNcvm4wV+e2/Rt1QdDwKHFbHw==", + "version": "4.15.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.15.0.tgz", + "integrity": "sha512-tB9lu0pQpX5KJq54g+oHOLumOx+pMep4RaM6liXh2PKmVRFF+/vAtUP0ZaJ0kOySfVNjF6doBWPHhBhISKdlIA==", "dev": true, "engines": { "node": ">=16" @@ -30428,42 +30559,10 @@ "ms": "^2.1.1" } }, - "node_modules/redeyed": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz", - "integrity": "sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==", - "dev": true, - "dependencies": { - "esprima": "~4.0.0" - } - }, - "node_modules/redis-errors": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", - "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", - "optional": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/redis-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", - "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", - "optional": true, - "peer": true, - "dependencies": { - "redis-errors": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/reflect-metadata": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.1.tgz", - "integrity": "sha512-i5lLI6iw9AU3Uu4szRNPPEkomnkjRTaVt9hy/bn5g/oSzekBSMeLZblcjP74AW0vBabqERLLIrz+gR8QYR54Tw==" + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==" }, "node_modules/regenerate": { "version": "1.4.2", @@ -30502,6 +30601,24 @@ "@babel/runtime": "^7.8.4" } }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "devOptional": true, + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/regexpu-core": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", @@ -30715,7 +30832,7 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "optional": true, + "devOptional": true, "engines": { "node": ">= 4" } @@ -30776,6 +30893,30 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "devOptional": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "devOptional": true + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -30802,6 +30943,23 @@ "optional": true, "peer": true }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "devOptional": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safe-stable-stringify": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", @@ -30915,35 +31073,35 @@ } }, "node_modules/semantic-release": { - "version": "23.0.0", - "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-23.0.0.tgz", - "integrity": "sha512-Jz7jEWO2igTtske112gC4PPE2whCMVrsgxUPG3/SZI7VE357suIUZFlJd1Yu0g2I6RPc2HxNEfUg7KhmDTjwqg==", + "version": "23.0.8", + "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-23.0.8.tgz", + "integrity": "sha512-yZkuWcTTfh5h/DrR4Q4QvJSARJdb6wjwn/sN0qKMYEkvwaVFek8YWfrgtL8oWaRdl0fLte0Y1wWMzLbwoaII1g==", "dev": true, "dependencies": { - "@semantic-release/commit-analyzer": "^11.0.0", + "@semantic-release/commit-analyzer": "^12.0.0", "@semantic-release/error": "^4.0.0", - "@semantic-release/github": "^9.0.0", - "@semantic-release/npm": "^11.0.0", - "@semantic-release/release-notes-generator": "^12.0.0", + "@semantic-release/github": "^10.0.0", + "@semantic-release/npm": "^12.0.0", + "@semantic-release/release-notes-generator": "^13.0.0", "aggregate-error": "^5.0.0", "cosmiconfig": "^9.0.0", "debug": "^4.0.0", "env-ci": "^11.0.0", "execa": "^8.0.0", "figures": "^6.0.0", - "find-versions": "^5.1.0", + "find-versions": "^6.0.0", "get-stream": "^6.0.0", "git-log-parser": "^1.2.0", "hook-std": "^3.0.0", "hosted-git-info": "^7.0.0", "import-from-esm": "^1.3.1", "lodash-es": "^4.17.21", - "marked": "^11.0.0", - "marked-terminal": "^6.0.0", + "marked": "^12.0.0", + "marked-terminal": "^7.0.0", "micromatch": "^4.0.2", "p-each-series": "^3.0.0", "p-reduce": "^3.0.0", - "read-pkg-up": "^11.0.0", + "read-package-up": "^11.0.0", "resolve-from": "^5.0.0", "semver": "^7.3.2", "semver-diff": "^4.0.0", @@ -30957,6 +31115,156 @@ "node": ">=20.8.1" } }, + "node_modules/semantic-release/node_modules/@octokit/auth-token": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-5.1.1.tgz", + "integrity": "sha512-rh3G3wDO8J9wSjfI436JUKzHIxq8NaiL0tVeB2aXmG6p/9859aUOAjA9pmSPNGGZxfwmaJ9ozOJImuNVJdpvbA==", + "dev": true, + "engines": { + "node": ">= 18" + } + }, + "node_modules/semantic-release/node_modules/@octokit/core": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-6.1.2.tgz", + "integrity": "sha512-hEb7Ma4cGJGEUNOAVmyfdB/3WirWMg5hDuNFVejGEDFqupeOysLc2sG6HJxY2etBp5YQu5Wtxwi020jS9xlUwg==", + "dev": true, + "dependencies": { + "@octokit/auth-token": "^5.0.0", + "@octokit/graphql": "^8.0.0", + "@octokit/request": "^9.0.0", + "@octokit/request-error": "^6.0.1", + "@octokit/types": "^13.0.0", + "before-after-hook": "^3.0.2", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/semantic-release/node_modules/@octokit/endpoint": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.1.tgz", + "integrity": "sha512-JYjh5rMOwXMJyUpj028cu0Gbp7qe/ihxfJMLc8VZBMMqSwLgOxDI1911gV4Enl1QSavAQNJcwmwBF9M0VvLh6Q==", + "dev": true, + "dependencies": { + "@octokit/types": "^13.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/semantic-release/node_modules/@octokit/graphql": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-8.1.1.tgz", + "integrity": "sha512-ukiRmuHTi6ebQx/HFRCXKbDlOh/7xEV6QUXaE7MJEKGNAncGI/STSbOkl12qVXZrfZdpXctx5O9X1AIaebiDBg==", + "dev": true, + "dependencies": { + "@octokit/request": "^9.0.0", + "@octokit/types": "^13.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/semantic-release/node_modules/@octokit/plugin-paginate-rest": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.1.1.tgz", + "integrity": "sha512-joUIZu9TupD4pRXLmWShD1Ur/oxYf/bJjYcnaopmGTReNrmWwcW7DUGSrWOjoTeihnlDig+a79m8koiafc4XQw==", + "dev": true, + "dependencies": { + "@octokit/types": "^13.4.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/semantic-release/node_modules/@octokit/plugin-retry": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-7.1.0.tgz", + "integrity": "sha512-6mc4xNtT6eoDBGrJJn0sFALUmIba2f7Wx+G8XV9GkBLcyX5PogBdx2mDMW5yPPqSD/y23tYagkjOLX9sT7O6jA==", + "dev": true, + "dependencies": { + "@octokit/request-error": "^6.0.0", + "@octokit/types": "^13.0.0", + "bottleneck": "^2.15.3" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/semantic-release/node_modules/@octokit/plugin-throttling": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-9.2.0.tgz", + "integrity": "sha512-zHZSZCC7wk3HbK3ZCuvc3iPrnFGoYIVJsJAY4l8ilsVu4fqPfe7BP7QLZ1A641yttLWqgy2oID3ETD3Z1036Gw==", + "dev": true, + "dependencies": { + "@octokit/types": "^13.0.0", + "bottleneck": "^2.15.3" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "^6.0.0" + } + }, + "node_modules/semantic-release/node_modules/@octokit/request": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.1.1.tgz", + "integrity": "sha512-pyAguc0p+f+GbQho0uNetNQMmLG1e80WjkIaqqgUkihqUp0boRU6nKItXO4VWnr+nbZiLGEyy4TeKRwqaLvYgw==", + "dev": true, + "dependencies": { + "@octokit/endpoint": "^10.0.0", + "@octokit/request-error": "^6.0.1", + "@octokit/types": "^13.1.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/semantic-release/node_modules/@octokit/request-error": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.1.tgz", + "integrity": "sha512-1mw1gqT3fR/WFvnoVpY/zUM2o/XkMs/2AszUUG9I69xn0JFLv6PGkPhNk5lbfvROs79wiS0bqiJNxfCZcRJJdg==", + "dev": true, + "dependencies": { + "@octokit/types": "^13.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/semantic-release/node_modules/@semantic-release/commit-analyzer": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-12.0.0.tgz", + "integrity": "sha512-qG+md5gdes+xa8zP7lIo1fWE17zRdO8yMCaxh9lyL65TQleoSv8WHHOqRURfghTytUh+NpkSyBprQ5hrkxOKVQ==", + "dev": true, + "dependencies": { + "conventional-changelog-angular": "^7.0.0", + "conventional-commits-filter": "^4.0.0", + "conventional-commits-parser": "^5.0.0", + "debug": "^4.0.0", + "import-from-esm": "^1.0.3", + "lodash-es": "^4.17.21", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=20.8.1" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, "node_modules/semantic-release/node_modules/@semantic-release/error": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-4.0.0.tgz", @@ -30966,6 +31274,99 @@ "node": ">=18" } }, + "node_modules/semantic-release/node_modules/@semantic-release/github": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-10.0.3.tgz", + "integrity": "sha512-nSJQboKrG4xBn7hHpRMrK8lt5DgqJg50ZMz9UbrsfTxuRk55XVoQEadbGZ2L9M0xZAC6hkuwkDhQJKqfPU35Fw==", + "dev": true, + "dependencies": { + "@octokit/core": "^6.0.0", + "@octokit/plugin-paginate-rest": "^11.0.0", + "@octokit/plugin-retry": "^7.0.0", + "@octokit/plugin-throttling": "^9.0.0", + "@semantic-release/error": "^4.0.0", + "aggregate-error": "^5.0.0", + "debug": "^4.3.4", + "dir-glob": "^3.0.1", + "globby": "^14.0.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "issue-parser": "^7.0.0", + "lodash-es": "^4.17.21", + "mime": "^4.0.0", + "p-filter": "^4.0.0", + "url-join": "^5.0.0" + }, + "engines": { + "node": ">=20.8.1" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, + "node_modules/semantic-release/node_modules/@semantic-release/npm": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-12.0.0.tgz", + "integrity": "sha512-72TVYQCH9NvVsO/y13eF8vE4bNnfls518+4KcFwJUKi7AtA/ZXoNgSg9gTTfw5eMZMkiH0izUrpGXgZE/cSQhA==", + "dev": true, + "dependencies": { + "@semantic-release/error": "^4.0.0", + "aggregate-error": "^5.0.0", + "execa": "^8.0.0", + "fs-extra": "^11.0.0", + "lodash-es": "^4.17.21", + "nerf-dart": "^1.0.0", + "normalize-url": "^8.0.0", + "npm": "^10.5.0", + "rc": "^1.2.8", + "read-pkg": "^9.0.0", + "registry-auth-token": "^5.0.0", + "semver": "^7.1.2", + "tempy": "^3.0.0" + }, + "engines": { + "node": ">=20.8.1" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, + "node_modules/semantic-release/node_modules/@semantic-release/release-notes-generator": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-13.0.0.tgz", + "integrity": "sha512-LEeZWb340keMYuREMyxrODPXJJ0JOL8D/mCl74B4LdzbxhtXV2LrPN2QBEcGJrlQhoqLO0RhxQb6masHytKw+A==", + "dev": true, + "dependencies": { + "conventional-changelog-angular": "^7.0.0", + "conventional-changelog-writer": "^7.0.0", + "conventional-commits-filter": "^4.0.0", + "conventional-commits-parser": "^5.0.0", + "debug": "^4.0.0", + "get-stream": "^7.0.0", + "import-from-esm": "^1.0.3", + "into-stream": "^7.0.0", + "lodash-es": "^4.17.21", + "read-pkg-up": "^11.0.0" + }, + "engines": { + "node": ">=20.8.1" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, + "node_modules/semantic-release/node_modules/@semantic-release/release-notes-generator/node_modules/get-stream": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-7.0.1.tgz", + "integrity": "sha512-3M8C1EOFN6r8AMUhwUAACIoXZJEOufDU5+0gFFN5uNs6XYOralD2Pqkl7m046va6x77FwposWXbAhPPIOus7mQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/semantic-release/node_modules/aggregate-error": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-5.0.0.tgz", @@ -30982,6 +31383,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/semantic-release/node_modules/before-after-hook": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-3.0.2.tgz", + "integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==", + "dev": true + }, "node_modules/semantic-release/node_modules/clean-stack": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-5.2.0.tgz", @@ -31141,6 +31548,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/semantic-release/node_modules/issue-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-7.0.0.tgz", + "integrity": "sha512-jgAw78HO3gs9UrKqJNQvfDj9Ouy8Mhu40fbEJ8yXff4MW8+/Fcn9iFjyWUQ6SKbX8ipPk3X5A3AyfYHRu6uVLw==", + "dev": true, + "dependencies": { + "lodash.capitalize": "^4.2.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.uniqby": "^4.7.0" + }, + "engines": { + "node": "^18.17 || >=20.6.1" + } + }, "node_modules/semantic-release/node_modules/lru-cache": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", @@ -31163,9 +31586,9 @@ } }, "node_modules/semantic-release/node_modules/npm-run-path": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", - "integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", "dev": true, "dependencies": { "path-key": "^4.0.0" @@ -31249,6 +31672,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/semantic-release/node_modules/universal-user-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz", + "integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==", + "dev": true + }, "node_modules/semantic-release/node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", @@ -31268,9 +31697,9 @@ } }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -31430,6 +31859,21 @@ "node": ">= 0.4" } }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "devOptional": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -31493,13 +31937,17 @@ } }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -31682,11 +32130,11 @@ "devOptional": true }, "node_modules/siwe": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/siwe/-/siwe-2.1.4.tgz", - "integrity": "sha512-Dke1Qqa3mgiLm3vjqw/+SQ7dl8WV/Pfk3AlQBF94cBFydTYhztngqYrikzE3X5UTsJ6565dfVbQptszsuYZNYg==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/siwe/-/siwe-2.3.1.tgz", + "integrity": "sha512-CkQu/g1tAOUL4e9s4qRQ3drb02bNaCtSUT3grQhTIfAZb0h0W9LtFrYSQQYgvoGUuQn2Zp9Nm2FTH/FNFO78AA==", "dependencies": { - "@spruceid/siwe-parser": "*", + "@spruceid/siwe-parser": "^2.1.1", "@stablelib/random": "^1.0.1", "uri-js": "^4.4.1", "valid-url": "^1.0.9" @@ -31722,6 +32170,17 @@ "npm": ">=7.0.0" } }, + "node_modules/siwe/node_modules/@spruceid/siwe-parser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@spruceid/siwe-parser/-/siwe-parser-2.1.1.tgz", + "integrity": "sha512-AqaR/pJeSooqlW0Xw6zZByk6yfoORCaJOugY18I+k7GerLCMgPqiqAeKDtxFhdB2Ov/GdQKp6dDuIFG/AtAx9A==", + "dependencies": { + "@noble/hashes": "^1.1.2", + "apg-js": "^4.1.1", + "uri-js": "^4.4.1", + "valid-url": "^1.0.9" + } + }, "node_modules/skin-tone": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", @@ -31805,23 +32264,23 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "optional": true, + "devOptional": true, "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" } }, "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", - "optional": true, + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "devOptional": true, "dependencies": { - "ip": "^2.0.0", + "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" }, "engines": { - "node": ">= 10.13.0", + "node": ">= 10.0.0", "npm": ">= 3.0.0" } }, @@ -31829,7 +32288,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", - "optional": true, + "devOptional": true, "dependencies": { "agent-base": "^6.0.2", "debug": "^4.3.3", @@ -31843,7 +32302,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "optional": true, + "devOptional": true, "dependencies": { "debug": "4" }, @@ -31851,12 +32310,6 @@ "node": ">= 6.0.0" } }, - "node_modules/socks/node_modules/ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", - "optional": true - }, "node_modules/sonic-boom": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-2.8.0.tgz", @@ -31874,9 +32327,9 @@ } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", "optional": true, "peer": true, "engines": { @@ -31919,9 +32372,9 @@ } }, "node_modules/spdx-exceptions": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.4.0.tgz", - "integrity": "sha512-hcjppoJ68fhxA/cjbN4T8N6uCUejN8yFw69ttpqtBeCbF3u13n7mb31NB9jKwGTTWWnt9IbRA/mf1FprYS8wfw==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", "dev": true }, "node_modules/spdx-expression-parse": { @@ -31935,9 +32388,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", - "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", + "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", "dev": true }, "node_modules/split": { @@ -31970,9 +32423,9 @@ } }, "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", "devOptional": true }, "node_modules/sqlite3": { @@ -32010,7 +32463,7 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", - "optional": true, + "devOptional": true, "dependencies": { "minipass": "^3.1.1" }, @@ -32069,13 +32522,6 @@ "node": ">=8" } }, - "node_modules/standard-as-callback": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", - "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==", - "optional": true, - "peer": true - }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -32204,6 +32650,55 @@ "node": ">=8" } }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "devOptional": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "devOptional": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "devOptional": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -32268,9 +32763,9 @@ } }, "node_modules/stripe": { - "version": "14.18.0", - "resolved": "https://registry.npmjs.org/stripe/-/stripe-14.18.0.tgz", - "integrity": "sha512-yLqKPqYgGJbMxrQiE4+i2i00ZVA2NRIZbZ1rejzj5XR3F3Uc+1iy9QE133knZudhVGMw367b8vTpB8D9pYMETw==", + "version": "14.25.0", + "resolved": "https://registry.npmjs.org/stripe/-/stripe-14.25.0.tgz", + "integrity": "sha512-wQS3GNMofCXwH8TSje8E1SE8zr6ODiGtHQgPtO95p9Mb4FhKC9jvXR2NUTpZ9ZINlckJcFidCmaTFV4P6vsb9g==", "dependencies": { "@types/node": ">=8.1.0", "qs": "^6.11.0" @@ -32370,6 +32865,22 @@ "optional": true, "peer": true }, + "node_modules/super-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/super-regex/-/super-regex-1.0.0.tgz", + "integrity": "sha512-CY8u7DtbvucKuquCmOFEKhr9Besln7n9uN8eFbwcoGYWXOMW07u2o8njWaiXt11ylS3qoGF55pILjRmPlbodyg==", + "dev": true, + "dependencies": { + "function-timeout": "^1.0.1", + "time-span": "^5.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -32524,9 +33035,9 @@ } }, "node_modules/tar": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", - "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -32743,9 +33254,9 @@ } }, "node_modules/terser": { - "version": "5.27.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.27.0.tgz", - "integrity": "sha512-bi1HRwVRskAjheeYl291n3JC4GgO/Ty4z1nVs5AAsmonJulGxpSektecnNedrwK9C7vpvVtcX3cw00VSLt7U2A==", + "version": "5.30.3", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.3.tgz", + "integrity": "sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA==", "devOptional": true, "peer": true, "dependencies": { @@ -32915,6 +33426,21 @@ "xtend": "~4.0.1" } }, + "node_modules/time-span": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/time-span/-/time-span-5.1.0.tgz", + "integrity": "sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==", + "dev": true, + "dependencies": { + "convert-hrtime": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/timeout-abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/timeout-abort-controller/-/timeout-abort-controller-3.0.0.tgz", @@ -33021,10 +33547,15 @@ } }, "node_modules/traverse": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.8.tgz", - "integrity": "sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA==", + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.9.tgz", + "integrity": "sha512-7bBrcF+/LQzSgFmT0X5YclVqQxtv7TDJ1f8Wj7ibBu/U6BMLeOpUxuZjV7rMc44UtKxlnMFigdhFAIszSX1DMg==", "devOptional": true, + "dependencies": { + "gopd": "^1.0.1", + "typedarray.prototype.slice": "^1.0.3", + "which-typed-array": "^1.1.15" + }, "engines": { "node": ">= 0.4" }, @@ -33250,6 +33781,99 @@ "node": ">= 0.6" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "devOptional": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "devOptional": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "devOptional": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "devOptional": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedarray.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typedarray.prototype.slice/-/typedarray.prototype.slice-1.0.3.tgz", + "integrity": "sha512-8WbVAQAUlENo1q3c3zZYuy5k9VzBQvp8AX9WOtbvyWlLM1v5JaSRmjubLjzHF4JFtptjH/5c/i95yaElvcjC0A==", + "devOptional": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-errors": "^1.3.0", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-offset": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typeforce": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz", @@ -33382,15 +34006,15 @@ } }, "node_modules/typeorm/node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", + "jackspeak": "^2.3.6", "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -33403,9 +34027,9 @@ } }, "node_modules/typeorm/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -33456,9 +34080,9 @@ } }, "node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "devOptional": true, "bin": { "tsc": "bin/tsc", @@ -33539,22 +34163,37 @@ } }, "node_modules/uint8arrays": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-5.0.2.tgz", - "integrity": "sha512-S0GaeR+orZt7LaqzTRs4ZP8QqzAauJ+0d4xvP2lJTA99jIkKsE2FgDs4tGF/K/z5O9I/2W5Yvrh7IuqNeYH+0Q==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-5.0.3.tgz", + "integrity": "sha512-6LBuKji28kHjgPJMkQ6GDaBb1lRwIhyOYq6pDGwYMoDPfImE9SkuYENVmR0yu9yGgs2clHUSY9fKDukR+AXfqQ==", "dependencies": { "multiformats": "^13.0.0" } }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "devOptional": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/uncrypto": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==" }, "node_modules/undici": { - "version": "5.28.2", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.2.tgz", - "integrity": "sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w==", + "version": "5.28.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", + "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", "dependencies": { "@fastify/busboy": "^2.0.0" }, @@ -33659,7 +34298,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "optional": true, + "devOptional": true, "dependencies": { "unique-slug": "^2.0.0" } @@ -33668,7 +34307,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "optional": true, + "devOptional": true, "dependencies": { "imurmurhash": "^0.1.4" } @@ -33888,11 +34527,11 @@ "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" }, "node_modules/url/node_modules/qs": { - "version": "6.11.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", - "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "version": "6.12.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.1.tgz", + "integrity": "sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -33985,8 +34624,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", "integrity": "sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==", - "optional": true, - "peer": true, + "devOptional": true, "dependencies": { "builtins": "^1.0.3" } @@ -34062,9 +34700,9 @@ } }, "node_modules/watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", + "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", "dev": true, "peer": true, "dependencies": { @@ -34086,9 +34724,9 @@ } }, "node_modules/web-streams-polyfill": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.2.tgz", - "integrity": "sha512-3pRGuxRF5gpuZc0W+EpwQRmCD7gRqcDOMt688KmdlDAgAyaB1XlN0zq2njfDNm44XVdIouE7pZ6GzbdyH47uIQ==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", "engines": { "node": ">= 8" } @@ -34099,9 +34737,9 @@ "integrity": "sha512-c0rhqNcHXRkY/ogGDJQxZ9Im9D19hDihbzSQJrsioex+KnFgmMzBiy57Z1EjkhX/+OjyBpclDCzz2ITtjokFmg==" }, "node_modules/webcrypto-core": { - "version": "1.7.8", - "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.8.tgz", - "integrity": "sha512-eBR98r9nQXTqXt/yDRtInszPMjTaSAMJAFDg2AHsgrnczawT1asx9YNBX6k5p+MekbPF4+s/UJJrr88zsTqkSg==", + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.9.tgz", + "integrity": "sha512-FE+a4PPkOmBbgNDIyRmcHhgXn+2ClRl3JzJdDu/P4+B8y81LqKe6RAsI9b3lAOHe1T1BMkSjsRHTYRikImZnVA==", "dependencies": { "@peculiar/asn1-schema": "^2.3.8", "@peculiar/json-schema": "^1.1.12", @@ -34121,27 +34759,27 @@ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/webpack": { - "version": "5.90.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.0.tgz", - "integrity": "sha512-bdmyXRCXeeNIePv6R6tGPyy20aUobw4Zy8r0LUS2EWO+U+Ke/gYDgsCh7bl5rB6jPpr4r0SZa6dPxBxLooDT3w==", + "version": "5.91.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.91.0.tgz", + "integrity": "sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==", "dev": true, "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.5", - "@webassemblyjs/ast": "^1.11.5", - "@webassemblyjs/wasm-edit": "^1.11.5", - "@webassemblyjs/wasm-parser": "^1.11.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", "acorn": "^8.7.1", "acorn-import-assertions": "^1.9.0", "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.15.0", + "enhanced-resolve": "^5.16.0", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", + "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", @@ -34149,7 +34787,7 @@ "schema-utils": "^3.2.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.3.10", - "watchpack": "^2.4.0", + "watchpack": "^2.4.1", "webpack-sources": "^3.2.3" }, "bin": { @@ -34258,6 +34896,22 @@ "node": ">= 8" } }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "devOptional": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/which-module": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", @@ -34344,8 +34998,7 @@ "version": "2.4.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", - "optional": true, - "peer": true, + "devOptional": true, "dependencies": { "graceful-fs": "^4.1.11", "imurmurhash": "^0.1.4", @@ -34474,11 +35127,14 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yaml": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", - "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", + "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", "optional": true, "peer": true, + "bin": { + "yaml": "bin.mjs" + }, "engines": { "node": ">= 14" } diff --git a/package.json b/package.json index 963ecb99..11e50f51 100644 --- a/package.json +++ b/package.json @@ -55,9 +55,9 @@ "@cheqd/did-provider-cheqd": "^4.1.0", "@cheqd/sdk": "^4.0.0", "@cheqd/ts-proto": "^3.4.1", - "@cosmjs/amino": "^0.32.2", - "@cosmjs/encoding": "^0.32.2", - "@logto/express": "^2.3.0", + "@cosmjs/amino": "^0.32.3", + "@cosmjs/encoding": "^0.32.3", + "@logto/express": "^2.3.8", "@stablelib/ed25519": "^1.0.3", "@veramo/core": "^5.6.0", "@veramo/credential-ld": "^5.6.0", @@ -69,11 +69,11 @@ "@veramo/key-manager": "^5.6.0", "@veramo/kms-local": "^5.6.0", "@veramo/utils": "^5.6.0", - "@verida/account-node": "^3.0.1", - "@verida/client-ts": "^3.0.2", + "@verida/account-node": "^3.0.2", + "@verida/client-ts": "^3.0.3", "@verida/encryption-utils": "^3.0.0", - "@verida/types": "^3.0.0", - "@verida/vda-did-resolver": "^3.0.1", + "@verida/types": "^3.0.1", + "@verida/vda-did-resolver": "^3.0.2", "bcrypt": "^5.1.1", "bs58": "^5.0.0", "cookie-parser": "^1.4.6", @@ -81,7 +81,7 @@ "cors": "^2.8.5", "cross-env": "^7.0.3", "did-resolver": "^4.1.0", - "dotenv": "^16.4.1", + "dotenv": "^16.4.5", "express": "^4.19.2", "express-session": "^1.18.0", "express-validator": "^7.0.1", @@ -94,15 +94,15 @@ "loglevel": "^1.9.1", "multiformats": "^13.1.0", "node-cache": "^5.1.2", - "pg": "^8.11.3", - "pg-connection-string": "^2.6.2", + "pg": "^8.11.5", + "pg-connection-string": "^2.6.4", "secp256k1": "^5.0.0", "sqlite3": "^5.1.7", - "stripe": "^14.18.0", + "stripe": "^14.25.0", "swagger-ui-dist": "5.10.5", "swagger-ui-express": "^5.0.0", "typeorm": "^0.3.20", - "uint8arrays": "^5.0.2", + "uint8arrays": "^5.0.3", "uri-js": "^4.4.1" }, "devDependencies": { @@ -111,24 +111,24 @@ "@semantic-release/commit-analyzer": "^11.1.0", "@semantic-release/git": "^10.0.1", "@semantic-release/github": "^9.2.6", - "@semantic-release/npm": "^11.0.2", + "@semantic-release/npm": "^11.0.3", "@semantic-release/release-notes-generator": "^12.1.0", "@types/bcrypt": "^5.0.2", "@types/bs58": "^4.0.4", - "@types/cookie-parser": "^1.4.6", + "@types/cookie-parser": "^1.4.7", "@types/cors": "^2.8.17", "@types/debug": "^4.1.12", "@types/express": "^4.17.21", "@types/express-session": "^1.18.0", "@types/helmet": "^4.0.0", "@types/json-stringify-safe": "^5.0.3", - "@types/jsonwebtoken": "^9.0.5", - "@types/node": "^20.11.15", + "@types/jsonwebtoken": "^9.0.6", + "@types/node": "^20.12.7", "@types/secp256k1": "^4.0.6", "@types/swagger-jsdoc": "^6.0.4", "@types/swagger-ui-express": "^4.1.6", "@types/uuid": "^9.0.8", - "@types/validator": "^13.11.8", + "@types/validator": "^13.11.9", "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.62.0", "buffer": "6.0.3", @@ -137,14 +137,14 @@ "eslint-config-prettier": "^9.1.0", "eslint-config-typescript": "^3.0.0", "jest": "^29.7.0", - "prettier": "^3.2.4", - "semantic-release": "^23.0.0", + "prettier": "^3.2.5", + "semantic-release": "^23.0.8", "swagger-jsdoc": "^6.2.8", "ts-jest": "^29.1.2", "ts-loader": "^9.5.1", "ts-node": "^10.9.2", - "typescript": "^5.3.3", - "uint8arrays": "^5.0.2" + "typescript": "^5.4.5", + "uint8arrays": "^5.0.3" }, "publishConfig": { "registry": "https://registry.npmjs.org/", From 95b8b07d8175bc1cbc7b9527d9e0b2a816055d13 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Wed, 17 Apr 2024 14:19:29 +0200 Subject: [PATCH 39/40] Move to UTC time comparing --- src/controllers/admin/api-key.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/controllers/admin/api-key.ts b/src/controllers/admin/api-key.ts index ec227700..ba1df4ad 100644 --- a/src/controllers/admin/api-key.ts +++ b/src/controllers/admin/api-key.ts @@ -34,7 +34,8 @@ export class APIKeyController { .toDate() .withMessage('Invalid date format') .custom((value) => { - if (value < new Date()) { + const current = new Date(); + if (value < new Date(current.toISOString())) { throw new Error('expiresAt must be in the future'); } return true; @@ -63,7 +64,8 @@ export class APIKeyController { .toDate() .withMessage('Invalid date format') .custom((value) => { - if (value < new Date()) { + const current = new Date(); + if (value < new Date(current.toISOString())) { throw new Error('expiresAt must be in the future'); } return true; From ec42e7ef6f6e676b0f7afa3a4d3603865909ec4a Mon Sep 17 00:00:00 2001 From: Ankur Banerjee Date: Wed, 17 Apr 2024 13:39:21 +0100 Subject: [PATCH 40/40] npm run format --- src/controllers/admin/api-key.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/admin/api-key.ts b/src/controllers/admin/api-key.ts index ba1df4ad..9f8c76e2 100644 --- a/src/controllers/admin/api-key.ts +++ b/src/controllers/admin/api-key.ts @@ -201,7 +201,7 @@ export class APIKeyController { ); if (!apiKeyEntity) { return response.status(StatusCodes.NOT_FOUND).json({ - error: "Update failed: API key does not exist", + error: 'Update failed: API key does not exist', } satisfies APIKeyUpdateUnsuccessfulResponseBody); }