From 77b67fbd0485e0067ef1017327152ad18c7b71cf Mon Sep 17 00:00:00 2001 From: Darcy Ye Date: Wed, 20 Mar 2024 18:48:16 +0800 Subject: [PATCH] refactor(core): add cloud-only API prune for API docs --- .../core/src/routes/logto-config.openapi.json | 44 ++++++++++++++++ packages/core/src/routes/swagger/index.ts | 6 ++- .../core/src/routes/swagger/utils/general.ts | 51 +++++++++++++++++++ 3 files changed, 100 insertions(+), 1 deletion(-) diff --git a/packages/core/src/routes/logto-config.openapi.json b/packages/core/src/routes/logto-config.openapi.json index 64fd081b7..320e32379 100644 --- a/packages/core/src/routes/logto-config.openapi.json +++ b/packages/core/src/routes/logto-config.openapi.json @@ -188,6 +188,50 @@ } } } + }, + "/api/configs/jwt-customizer/test": { + "post": { + "tags": ["cloud-only"], + "summary": "Test JWT customizer", + "description": "Test the JWT customizer script with the given sample context and sample token payload.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "properties": { + "tokenType": { + "description": "The token type to test the JWT customizer for." + }, + "payload": { + "properties": { + "script": { + "description": "The code snippet of the JWT customizer." + }, + "envVars": { + "description": "The environment variables for the JWT customizer." + }, + "contextSample": { + "description": "The sample context for the JWT customizer script testing purpose." + }, + "tokenSample": { + "description": "The sample token payload for the JWT customizer script testing purpose." + } + } + } + } + } + } + } + }, + "responses": { + "200": { + "description": "The result of the JWT customizer script testing." + }, + "400": { + "description": "The request body is invalid." + } + } + } } } } diff --git a/packages/core/src/routes/swagger/index.ts b/packages/core/src/routes/swagger/index.ts index 97b5a1099..118547103 100644 --- a/packages/core/src/routes/swagger/index.ts +++ b/packages/core/src/routes/swagger/index.ts @@ -24,6 +24,7 @@ import { buildTag, findSupplementFiles, normalizePath, + pruneSupplementPaths, validateSupplement, validateSwaggerDocument, } from './utils/general.js'; @@ -192,12 +193,15 @@ export default function swaggerRoutes JSON.parse(await fs.readFile(path, 'utf8')) as Record ) ); + const supplementDocuments = rawSupplementDocuments.map((document) => + pruneSupplementPaths(document) + ); const baseDocument: OpenAPIV3.Document = { openapi: '3.0.1', diff --git a/packages/core/src/routes/swagger/utils/general.ts b/packages/core/src/routes/swagger/utils/general.ts index 850ebc082..6e04c905c 100644 --- a/packages/core/src/routes/swagger/utils/general.ts +++ b/packages/core/src/routes/swagger/utils/general.ts @@ -6,6 +6,7 @@ import { isKeyInObject, type Optional } from '@silverhand/essentials'; import { OpenAPIV3 } from 'openapi-types'; import { z } from 'zod'; +import { EnvSet } from '#src/env-set/index.js'; import { consoleLog } from '#src/utils/console.js'; const capitalize = (value: string) => value.charAt(0).toUpperCase() + value.slice(1); @@ -201,3 +202,53 @@ export const validateSwaggerDocument = (document: OpenAPIV3.Document) => { } } }; + +/** + * Some path are only available in the cloud version, so we need to prune them out in the OSS. + */ +export const pruneSupplementPaths = (supplement: Record) => { + if (EnvSet.values.isCloud) { + return supplement; + } + + // eslint-disable-next-line no-restricted-syntax + const supplementName = ((supplement.tags ?? []) as OpenAPIV3.TagObject[])[0]?.name; + + if (!supplementName) { + return supplement; + } + + if (!supplement.paths) { + return supplement; + } + + // eslint-disable-next-line no-restricted-syntax + const supplementPaths = supplement.paths as OpenAPIV3.PathsObject; + + if (Object.entries(supplement.paths).length === 0) { + return supplement; + } + + // eslint-disable-next-line no-restricted-syntax + const newPaths = Object.fromEntries( + Object.entries(supplementPaths) + .map(([path, pathBody]) => [ + path, + Object.fromEntries( + // eslint-disable-next-line no-restricted-syntax + Object.entries(pathBody as OpenAPIV3.PathItemObject).filter( + ([_, operationBody]) => + // eslint-disable-next-line no-restricted-syntax + !((operationBody as OpenAPIV3.OperationObject).tags ?? []).includes('cloud-only') + ) + ), + ]) + // eslint-disable-next-line no-restricted-syntax + .filter(([_, pathBody]) => Object.entries(pathBody as OpenAPIV3.PathItemObject).length > 0) + ) as OpenAPIV3.PathsObject; + + return { + ...supplement, + paths: newPaths, + }; +};