0
Fork 0
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:
Gao Sun 2024-06-23 10:33:28 +08:00 committed by GitHub
parent 6dd487269d
commit 097dfcac89
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 29 additions and 21 deletions

View file

@ -3,12 +3,12 @@
{ {
"name": "Organization applications", "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." "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": { "paths": {
"/api/organizations/{id}/applications": { "/api/organizations/{id}/applications": {
"get": { "get": {
"tags": ["Dev feature"],
"summary": "Get organization applications", "summary": "Get organization applications",
"description": "Get applications associated with the organization.", "description": "Get applications associated with the organization.",
"responses": { "responses": {
@ -18,7 +18,6 @@
} }
}, },
"post": { "post": {
"tags": ["Dev feature"],
"summary": "Add organization application", "summary": "Add organization application",
"description": "Add an application to the organization.", "description": "Add an application to the organization.",
"requestBody": { "requestBody": {
@ -44,7 +43,6 @@
} }
}, },
"put": { "put": {
"tags": ["Dev feature"],
"summary": "Replace organization applications", "summary": "Replace organization applications",
"description": "Replace all applications associated with the organization with the given data.", "description": "Replace all applications associated with the organization with the given data.",
"requestBody": { "requestBody": {
@ -72,7 +70,6 @@
}, },
"/api/organizations/{id}/applications/{applicationId}": { "/api/organizations/{id}/applications/{applicationId}": {
"delete": { "delete": {
"tags": ["Dev feature"],
"summary": "Remove organization application", "summary": "Remove organization application",
"description": "Remove an application from the organization.", "description": "Remove an application from the organization.",
"responses": { "responses": {
@ -84,7 +81,6 @@
}, },
"/api/organizations/{id}/applications/{applicationId}/roles": { "/api/organizations/{id}/applications/{applicationId}/roles": {
"get": { "get": {
"tags": ["Dev feature"],
"summary": "Get organization application roles", "summary": "Get organization application roles",
"description": "Get roles associated with the application in the organization.", "description": "Get roles associated with the application in the organization.",
"responses": { "responses": {
@ -94,7 +90,6 @@
} }
}, },
"post": { "post": {
"tags": ["Dev feature"],
"summary": "Add organization application role", "summary": "Add organization application role",
"description": "Add a role to the application in the organization.", "description": "Add a role to the application in the organization.",
"requestBody": { "requestBody": {
@ -120,7 +115,6 @@
} }
}, },
"put": { "put": {
"tags": ["Dev feature"],
"summary": "Replace organization application roles", "summary": "Replace organization application roles",
"description": "Replace all roles associated with the application in the organization with the given data.", "description": "Replace all roles associated with the application in the organization with the given data.",
"requestBody": { "requestBody": {
@ -148,7 +142,6 @@
}, },
"/api/organizations/{id}/applications/{applicationId}/roles/{organizationRoleId}": { "/api/organizations/{id}/applications/{applicationId}/roles/{organizationRoleId}": {
"delete": { "delete": {
"tags": ["Dev feature"],
"summary": "Remove organization application role", "summary": "Remove organization application role",
"description": "Remove a role from the application in the organization.", "description": "Remove a role from the application in the organization.",
"responses": { "responses": {

View file

@ -3,12 +3,12 @@
{ {
"name": "Security", "name": "Security",
"description": "Security related endpoints." "description": "Security related endpoints."
} },
{ "name": "Dev feature" }
], ],
"paths": { "paths": {
"/api/security/subject-tokens": { "/api/security/subject-tokens": {
"post": { "post": {
"tags": ["Dev feature"],
"summary": "Create a new subject token.", "summary": "Create a new subject token.",
"description": "Create a new subject token for the use of impersonating the user.", "description": "Create a new subject token for the use of impersonating the user.",
"requestBody": { "requestBody": {

View file

@ -2,7 +2,7 @@ import fs from 'node:fs/promises';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
import { httpCodeToMessage } from '@logto/core-kit'; 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 deepmerge from 'deepmerge';
import { findUp } from 'find-up'; import { findUp } from 'find-up';
import type { IMiddleware } from 'koa-router'; import type { IMiddleware } from 'koa-router';
@ -23,6 +23,7 @@ import type { AnonymousRouter } from '../types.js';
import { import {
buildTag, buildTag,
devFeatureTag,
findSupplementFiles, findSupplementFiles,
normalizePath, normalizePath,
removeUnnecessaryOperations, removeUnnecessaryOperations,
@ -134,11 +135,13 @@ const identifiableEntityNames = Object.freeze([
]); ]);
/** Additional tags that cannot be inferred from the path. */ /** Additional tags that cannot be inferred from the path. */
const additionalTags = Object.freeze([ const additionalTags = Object.freeze(
'Organization applications', condArray<string>(
'Organization users', EnvSet.values.isDevFeaturesEnabled && 'Organization applications',
'Security', EnvSet.values.isDevFeaturesEnabled && 'Security',
]); 'Organization users'
)
);
/** /**
* Attach the `/swagger.json` route which returns the generated OpenAPI document for the * 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.')); assertThat(routesDirectory, new Error('Cannot find routes directory.'));
const supplementPaths = await findSupplementFiles(routesDirectory); const supplementPaths = await findSupplementFiles(routesDirectory);
const supplementDocuments = await Promise.all( const allSupplementDocuments = await Promise.all(
supplementPaths.map(async (path) => supplementPaths.map(async (path) =>
removeUnnecessaryOperations( removeUnnecessaryOperations(
// eslint-disable-next-line no-restricted-syntax -- trust the type here as we'll validate it later // 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 = { const baseDocument: OpenAPIV3.Document = {
openapi: '3.0.1', openapi: '3.0.1',
servers: [ servers: [

View file

@ -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. */ /** The tag name used in the supplement document to indicate that the operation is cloud only. */
const cloudOnlyTag = '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. */ /** 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. * 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)); const originalTags = new Set(original.tags?.map((tag) => tag.name));
for (const { name } of supplementTags) { for (const { name } of supplementTags) {
if (!originalTags.has(name)) { if (!reservedTags.has(name) && !originalTags.has(name)) {
throw new TypeError( 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.` `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 ?? []) { 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.`
);
} }
} }
}; };