mirror of
https://github.com/logto-io/logto.git
synced 2024-12-30 20:33:54 -05:00
refactor: filter whole supplement document if needed (#6085)
This commit is contained in:
parent
6dd487269d
commit
097dfcac89
4 changed files with 29 additions and 21 deletions
|
@ -3,12 +3,12 @@
|
|||
{
|
||||
"name": "Organization applications",
|
||||
"description": "Manage organization - application relationships. An application can be associated with one or more organizations in order to get access to the organization resources.\n\nCurrently, only machine-to-machine applications can be associated with organizations."
|
||||
}
|
||||
},
|
||||
{ "name": "Dev feature" }
|
||||
],
|
||||
"paths": {
|
||||
"/api/organizations/{id}/applications": {
|
||||
"get": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Get organization applications",
|
||||
"description": "Get applications associated with the organization.",
|
||||
"responses": {
|
||||
|
@ -18,7 +18,6 @@
|
|||
}
|
||||
},
|
||||
"post": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Add organization application",
|
||||
"description": "Add an application to the organization.",
|
||||
"requestBody": {
|
||||
|
@ -44,7 +43,6 @@
|
|||
}
|
||||
},
|
||||
"put": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Replace organization applications",
|
||||
"description": "Replace all applications associated with the organization with the given data.",
|
||||
"requestBody": {
|
||||
|
@ -72,7 +70,6 @@
|
|||
},
|
||||
"/api/organizations/{id}/applications/{applicationId}": {
|
||||
"delete": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Remove organization application",
|
||||
"description": "Remove an application from the organization.",
|
||||
"responses": {
|
||||
|
@ -84,7 +81,6 @@
|
|||
},
|
||||
"/api/organizations/{id}/applications/{applicationId}/roles": {
|
||||
"get": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Get organization application roles",
|
||||
"description": "Get roles associated with the application in the organization.",
|
||||
"responses": {
|
||||
|
@ -94,7 +90,6 @@
|
|||
}
|
||||
},
|
||||
"post": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Add organization application role",
|
||||
"description": "Add a role to the application in the organization.",
|
||||
"requestBody": {
|
||||
|
@ -120,7 +115,6 @@
|
|||
}
|
||||
},
|
||||
"put": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Replace organization application roles",
|
||||
"description": "Replace all roles associated with the application in the organization with the given data.",
|
||||
"requestBody": {
|
||||
|
@ -148,7 +142,6 @@
|
|||
},
|
||||
"/api/organizations/{id}/applications/{applicationId}/roles/{organizationRoleId}": {
|
||||
"delete": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Remove organization application role",
|
||||
"description": "Remove a role from the application in the organization.",
|
||||
"responses": {
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
{
|
||||
"name": "Security",
|
||||
"description": "Security related endpoints."
|
||||
}
|
||||
},
|
||||
{ "name": "Dev feature" }
|
||||
],
|
||||
"paths": {
|
||||
"/api/security/subject-tokens": {
|
||||
"post": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Create a new subject token.",
|
||||
"description": "Create a new subject token for the use of impersonating the user.",
|
||||
"requestBody": {
|
||||
|
|
|
@ -2,7 +2,7 @@ import fs from 'node:fs/promises';
|
|||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import { httpCodeToMessage } from '@logto/core-kit';
|
||||
import { condString, conditionalArray, deduplicate } from '@silverhand/essentials';
|
||||
import { condArray, condString, conditionalArray, deduplicate } from '@silverhand/essentials';
|
||||
import deepmerge from 'deepmerge';
|
||||
import { findUp } from 'find-up';
|
||||
import type { IMiddleware } from 'koa-router';
|
||||
|
@ -23,6 +23,7 @@ import type { AnonymousRouter } from '../types.js';
|
|||
|
||||
import {
|
||||
buildTag,
|
||||
devFeatureTag,
|
||||
findSupplementFiles,
|
||||
normalizePath,
|
||||
removeUnnecessaryOperations,
|
||||
|
@ -134,11 +135,13 @@ const identifiableEntityNames = Object.freeze([
|
|||
]);
|
||||
|
||||
/** Additional tags that cannot be inferred from the path. */
|
||||
const additionalTags = Object.freeze([
|
||||
'Organization applications',
|
||||
'Organization users',
|
||||
'Security',
|
||||
]);
|
||||
const additionalTags = Object.freeze(
|
||||
condArray<string>(
|
||||
EnvSet.values.isDevFeaturesEnabled && 'Organization applications',
|
||||
EnvSet.values.isDevFeaturesEnabled && 'Security',
|
||||
'Organization users'
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Attach the `/swagger.json` route which returns the generated OpenAPI document for the
|
||||
|
@ -201,7 +204,7 @@ export default function swaggerRoutes<T extends AnonymousRouter, R extends Route
|
|||
assertThat(routesDirectory, new Error('Cannot find routes directory.'));
|
||||
|
||||
const supplementPaths = await findSupplementFiles(routesDirectory);
|
||||
const supplementDocuments = await Promise.all(
|
||||
const allSupplementDocuments = await Promise.all(
|
||||
supplementPaths.map(async (path) =>
|
||||
removeUnnecessaryOperations(
|
||||
// eslint-disable-next-line no-restricted-syntax -- trust the type here as we'll validate it later
|
||||
|
@ -210,6 +213,13 @@ export default function swaggerRoutes<T extends AnonymousRouter, R extends Route
|
|||
)
|
||||
);
|
||||
|
||||
// Filter out supplement documents that are for dev features when dev features are disabled.
|
||||
const supplementDocuments = allSupplementDocuments.filter(
|
||||
(supplement) =>
|
||||
EnvSet.values.isDevFeaturesEnabled ||
|
||||
!supplement.tags?.find((tag) => tag?.name === devFeatureTag)
|
||||
);
|
||||
|
||||
const baseDocument: OpenAPIV3.Document = {
|
||||
openapi: '3.0.1',
|
||||
servers: [
|
||||
|
|
|
@ -15,7 +15,9 @@ const capitalize = (value: string) => value.charAt(0).toUpperCase() + value.slic
|
|||
/** The tag name used in the supplement document to indicate that the operation is cloud only. */
|
||||
const cloudOnlyTag = 'Cloud only';
|
||||
/** The tag name is used in the supplement document to indicate that the corresponding API operation is a dev feature. */
|
||||
const devFeatureTag = 'Dev feature';
|
||||
export const devFeatureTag = 'Dev feature';
|
||||
|
||||
const reservedTags = new Set([cloudOnlyTag, devFeatureTag]);
|
||||
|
||||
/**
|
||||
* Get the root component name from the given absolute path.
|
||||
|
@ -145,7 +147,7 @@ export const validateSupplement = (
|
|||
const originalTags = new Set(original.tags?.map((tag) => tag.name));
|
||||
|
||||
for (const { name } of supplementTags) {
|
||||
if (!originalTags.has(name)) {
|
||||
if (!reservedTags.has(name) && !originalTags.has(name)) {
|
||||
throw new TypeError(
|
||||
`Supplement document contains extra tag \`${name}\`. If you want to add a new tag, please add it to the \`additionalTags\` array in the main swagger route file.`
|
||||
);
|
||||
|
@ -213,7 +215,10 @@ export const validateSwaggerDocument = (document: OpenAPIV3.Document) => {
|
|||
}
|
||||
|
||||
for (const tag of document.tags ?? []) {
|
||||
assert(tag.description, `Tag \`${tag.name}\` must have a description.`);
|
||||
assert(
|
||||
reservedTags.has(tag.name) || tag.description,
|
||||
`Tag \`${tag.name}\` must have a description.`
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue