From f6ec0065074474f8b05862845e882f9d5d1048e4 Mon Sep 17 00:00:00 2001 From: Christian Fehmer Date: Thu, 8 Aug 2024 15:10:26 +0200 Subject: [PATCH] impr: use tsrest for psa endpoints (@fehmer) (#5712) !nuf --- backend/__tests__/api/controllers/psa.spec.ts | 64 +++++++++ backend/__tests__/utils/misc.spec.ts | 3 + backend/package.json | 3 +- backend/redocly.yaml | 2 +- backend/scripts/openapi.ts | 5 + backend/src/api/controllers/psa.ts | 10 +- backend/src/api/routes/index.ts | 2 +- backend/src/api/routes/psas.ts | 19 +-- backend/src/dal/psa.ts | 4 +- .../src/documentation/internal-swagger.json | 18 --- backend/src/utils/misc.ts | 1 + frontend/src/ts/ape/endpoints/index.ts | 2 - frontend/src/ts/ape/endpoints/psas.ts | 13 -- frontend/src/ts/ape/index.ts | 3 +- frontend/src/ts/elements/psa.ts | 4 +- packages/contracts/src/index.ts | 2 + packages/contracts/src/psas.ts | 37 +++++ packages/contracts/src/schemas/api.ts | 5 +- packages/contracts/src/schemas/psas.ts | 11 ++ packages/shared-types/src/index.ts | 8 -- pnpm-lock.yaml | 136 +++++++++++++++++- 21 files changed, 289 insertions(+), 63 deletions(-) create mode 100644 backend/__tests__/api/controllers/psa.spec.ts delete mode 100644 frontend/src/ts/ape/endpoints/psas.ts create mode 100644 packages/contracts/src/psas.ts create mode 100644 packages/contracts/src/schemas/psas.ts diff --git a/backend/__tests__/api/controllers/psa.spec.ts b/backend/__tests__/api/controllers/psa.spec.ts new file mode 100644 index 000000000..edc3631b0 --- /dev/null +++ b/backend/__tests__/api/controllers/psa.spec.ts @@ -0,0 +1,64 @@ +import request from "supertest"; +import app from "../../../src/app"; +import * as PsaDal from "../../../src/dal/psa"; +import { ObjectId } from "mongodb"; +const mockApp = request(app); + +describe("Psa Controller", () => { + describe("get psa", () => { + const getPsaMock = vi.spyOn(PsaDal, "get"); + + afterEach(() => { + getPsaMock.mockReset(); + }); + + it("get psas without authorization", async () => { + //GIVEN + const psaOne: PsaDal.DBPSA = { + _id: new ObjectId(), + message: "test2", + date: 1000, + level: 1, + sticky: true, + }; + const psaTwo: PsaDal.DBPSA = { + _id: new ObjectId(), + message: "test2", + date: 2000, + level: 2, + sticky: false, + }; + getPsaMock.mockResolvedValue([psaOne, psaTwo]); + + //WHEN + const { body } = await mockApp.get("/psas").expect(200); + + //THEN + expect(body).toEqual({ + message: "PSAs retrieved", + data: [ + { + _id: psaOne._id.toHexString(), + date: 1000, + level: 1, + message: "test2", + sticky: true, + }, + { + _id: psaTwo._id.toHexString(), + date: 2000, + level: 2, + message: "test2", + sticky: false, + }, + ], + }); + }); + it("get psas with authorization", async () => { + await mockApp + .get("/psas") + .set("authorization", `Uid 123456789`) + .expect(200); + }); + }); +}); diff --git a/backend/__tests__/utils/misc.spec.ts b/backend/__tests__/utils/misc.spec.ts index 71c32cad5..a379e0fb0 100644 --- a/backend/__tests__/utils/misc.spec.ts +++ b/backend/__tests__/utils/misc.spec.ts @@ -649,5 +649,8 @@ describe("Misc Utils", () => { }, ]); }); + it("handles undefined", () => { + expect(misc.replaceObjectIds(undefined as any)).toBeUndefined(); + }); }); }); diff --git a/backend/package.json b/backend/package.json index 7a36cc306..d668b5ef5 100644 --- a/backend/package.json +++ b/backend/package.json @@ -16,7 +16,7 @@ "knip": "knip", "docker-db-only": "docker compose -f docker/compose.db-only.yml up", "docker": "docker compose -f docker/compose.yml up", - "gen-docs": "tsx scripts/openapi.ts dist/static/api/openapi.json && redocly build-docs -o dist/static/api/internal.html internal@v2 && redocly bundle -o dist/static/api/public.json public-filter && redocly build-docs -o dist/static/api/public.html public@v2" + "gen-docs": "tsx scripts/openapi.ts dist/static/api/openapi.json && openapi-recursive-tagging dist/static/api/openapi.json dist/static/api/openapi-tagged.json && redocly build-docs -o dist/static/api/internal.html internal@v2 && redocly bundle -o dist/static/api/public.json public-filter && redocly build-docs -o dist/static/api/public.html public@v2" }, "engines": { "node": "20.16.0" @@ -90,6 +90,7 @@ "eslint": "8.57.0", "eslint-watch": "8.0.0", "ioredis-mock": "7.4.0", + "openapi-recursive-tagging": "0.0.6", "readline-sync": "1.4.10", "supertest": "6.2.3", "tsx": "4.16.2", diff --git a/backend/redocly.yaml b/backend/redocly.yaml index 7bacf646a..1898e3891 100644 --- a/backend/redocly.yaml +++ b/backend/redocly.yaml @@ -5,7 +5,7 @@ apis: internal@v2: root: dist/static/api/openapi.json public-filter: - root: dist/static/api/openapi.json + root: dist/static/api/openapi-tagged.json decorators: filter-in: property: x-public diff --git a/backend/scripts/openapi.ts b/backend/scripts/openapi.ts index 75317f4c8..4b444caa1 100644 --- a/backend/scripts/openapi.ts +++ b/backend/scripts/openapi.ts @@ -66,6 +66,11 @@ export function getOpenApi(): OpenAPIObject { description: "Ape keys provide access to certain API endpoints.", "x-displayName": "Ape Keys", }, + { + name: "psas", + description: "Public service announcements.", + "x-displayName": "PSAs", + }, { name: "admin", description: diff --git a/backend/src/api/controllers/psa.ts b/backend/src/api/controllers/psa.ts index 18a3e31b9..721527eef 100644 --- a/backend/src/api/controllers/psa.ts +++ b/backend/src/api/controllers/psa.ts @@ -1,7 +1,11 @@ +import { GetPsaResponse } from "@monkeytype/contracts/psas"; import * as PsaDAL from "../../dal/psa"; -import { MonkeyResponse } from "../../utils/monkey-response"; +import { MonkeyResponse2 } from "../../utils/monkey-response"; +import { replaceObjectIds } from "../../utils/misc"; -export async function getPsas(): Promise { +export async function getPsas( + _req: MonkeyTypes.Request2 +): Promise { const data = await PsaDAL.get(); - return new MonkeyResponse("PSAs retrieved", data); + return new MonkeyResponse2("PSAs retrieved", replaceObjectIds(data)); } diff --git a/backend/src/api/routes/index.ts b/backend/src/api/routes/index.ts index 6f3b22b6c..c64ee8cfd 100644 --- a/backend/src/api/routes/index.ts +++ b/backend/src/api/routes/index.ts @@ -43,7 +43,6 @@ const APP_START_TIME = Date.now(); const API_ROUTE_MAP = { "/users": users, "/results": results, - "/psas": psas, "/public": publicStats, "/leaderboards": leaderboards, "/quotes": quotes, @@ -57,6 +56,7 @@ const router = s.router(contract, { apeKeys, configs, presets, + psas, }); export function addApiRoutes(app: Application): void { diff --git a/backend/src/api/routes/psas.ts b/backend/src/api/routes/psas.ts index 6fbbd6759..4a283009a 100644 --- a/backend/src/api/routes/psas.ts +++ b/backend/src/api/routes/psas.ts @@ -1,10 +1,13 @@ -import { Router } from "express"; -import * as PsaController from "../controllers/psa"; +import { psasContract } from "@monkeytype/contracts/psas"; +import { initServer } from "@ts-rest/express"; import * as RateLimit from "../../middlewares/rate-limit"; -import { asyncHandler } from "../../middlewares/utility"; +import * as PsaController from "../controllers/psa"; +import { callController } from "../ts-rest-adapter"; -const router = Router(); - -router.get("/", RateLimit.psaGet, asyncHandler(PsaController.getPsas)); - -export default router; +const s = initServer(); +export default s.router(psasContract, { + get: { + middleware: [RateLimit.psaGet], + handler: async (r) => callController(PsaController.getPsas)(r), + }, +}); diff --git a/backend/src/dal/psa.ts b/backend/src/dal/psa.ts index a343c49dd..904c30b8a 100644 --- a/backend/src/dal/psa.ts +++ b/backend/src/dal/psa.ts @@ -1,7 +1,7 @@ -import { PSA } from "@monkeytype/shared-types"; +import { PSA } from "@monkeytype/contracts/schemas/psas"; import * as db from "../init/db"; -type DBPSA = MonkeyTypes.WithObjectId; +export type DBPSA = MonkeyTypes.WithObjectId; export async function get(): Promise { return await db.collection("psa").find().toArray(); diff --git a/backend/src/documentation/internal-swagger.json b/backend/src/documentation/internal-swagger.json index d19a4fc74..a999ae0da 100644 --- a/backend/src/documentation/internal-swagger.json +++ b/backend/src/documentation/internal-swagger.json @@ -23,10 +23,6 @@ "name": "users", "description": "User data and related operations" }, - { - "name": "psas", - "description": "Public service announcements" - }, { "name": "leaderboards", "description": "Leaderboard data" @@ -416,20 +412,6 @@ } } }, - "/psas": { - "get": { - "tags": ["psas"], - "summary": "Gets the latest public service announcements", - "responses": { - "default": { - "description": "", - "schema": { - "$ref": "#/definitions/Response" - } - } - } - } - }, "/leaderboards": { "get": { "tags": ["leaderboards"], diff --git a/backend/src/utils/misc.ts b/backend/src/utils/misc.ts index 5b91628d2..26e83cf77 100644 --- a/backend/src/utils/misc.ts +++ b/backend/src/utils/misc.ts @@ -331,5 +331,6 @@ export function replaceObjectId( export function replaceObjectIds( data: T[] ): (T & { _id: string })[] { + if (data === undefined) return data; return data.map((it) => replaceObjectId(it)); } diff --git a/frontend/src/ts/ape/endpoints/index.ts b/frontend/src/ts/ape/endpoints/index.ts index 5b7b849fe..2dae7057b 100644 --- a/frontend/src/ts/ape/endpoints/index.ts +++ b/frontend/src/ts/ape/endpoints/index.ts @@ -1,5 +1,4 @@ import Leaderboards from "./leaderboards"; -import Psas from "./psas"; import Quotes from "./quotes"; import Results from "./results"; import Users from "./users"; @@ -9,7 +8,6 @@ import Dev from "./dev"; export default { Leaderboards, - Psas, Public, Quotes, Results, diff --git a/frontend/src/ts/ape/endpoints/psas.ts b/frontend/src/ts/ape/endpoints/psas.ts deleted file mode 100644 index 6477a7878..000000000 --- a/frontend/src/ts/ape/endpoints/psas.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { PSA } from "@monkeytype/shared-types"; - -const BASE_PATH = "/psas"; - -export default class Psas { - constructor(private httpClient: Ape.HttpClient) { - this.httpClient = httpClient; - } - - async get(): Ape.EndpointResponse { - return await this.httpClient.get(BASE_PATH); - } -} diff --git a/frontend/src/ts/ape/index.ts b/frontend/src/ts/ape/index.ts index 137a08871..6bebc1c3c 100644 --- a/frontend/src/ts/ape/index.ts +++ b/frontend/src/ts/ape/index.ts @@ -5,6 +5,7 @@ import { buildClient } from "./adapters/ts-rest-adapter"; import { configsContract } from "@monkeytype/contracts/configs"; import { presetsContract } from "@monkeytype/contracts/presets"; import { apeKeysContract } from "@monkeytype/contracts/ape-keys"; +import { psasContract } from "@monkeytype/contracts/psas"; const API_PATH = ""; const BASE_URL = envConfig.backendUrl; @@ -17,7 +18,7 @@ const Ape = { users: new endpoints.Users(httpClient), configs: buildClient(configsContract, BASE_URL, 10_000), results: new endpoints.Results(httpClient), - psas: new endpoints.Psas(httpClient), + psas: buildClient(psasContract, BASE_URL, 10_000), quotes: new endpoints.Quotes(httpClient), leaderboards: new endpoints.Leaderboards(httpClient), presets: buildClient(presetsContract, BASE_URL, 10_000), diff --git a/frontend/src/ts/elements/psa.ts b/frontend/src/ts/elements/psa.ts index c6c8acae9..324e2a863 100644 --- a/frontend/src/ts/elements/psa.ts +++ b/frontend/src/ts/elements/psa.ts @@ -4,7 +4,7 @@ import { secondsToString } from "../utils/date-and-time"; import * as Notifications from "./notifications"; import { format } from "date-fns/format"; import * as Alerts from "./alerts"; -import { PSA } from "@monkeytype/shared-types"; +import { PSA } from "@monkeytype/contracts/schemas/psas"; function clearMemory(): void { window.localStorage.setItem("confirmedPSAs", JSON.stringify([])); @@ -61,7 +61,7 @@ async function getLatest(): Promise { } else if (response.status !== 200) { return null; } - return response.data; + return response.body.data; } export async function show(): Promise { diff --git a/packages/contracts/src/index.ts b/packages/contracts/src/index.ts index 533e4a3d2..e7f383639 100644 --- a/packages/contracts/src/index.ts +++ b/packages/contracts/src/index.ts @@ -3,6 +3,7 @@ import { adminContract } from "./admin"; import { apeKeysContract } from "./ape-keys"; import { configsContract } from "./configs"; import { presetsContract } from "./presets"; +import { psasContract } from "./psas"; const c = initContract(); @@ -11,4 +12,5 @@ export const contract = c.router({ apeKeys: apeKeysContract, configs: configsContract, presets: presetsContract, + psas: psasContract, }); diff --git a/packages/contracts/src/psas.ts b/packages/contracts/src/psas.ts new file mode 100644 index 000000000..25e2f3226 --- /dev/null +++ b/packages/contracts/src/psas.ts @@ -0,0 +1,37 @@ +import { initContract } from "@ts-rest/core"; +import { z } from "zod"; +import { PSASchema } from "./schemas/psas"; + +import { + CommonResponses, + EndpointMetadata, + responseWithData, +} from "./schemas/api"; +export const GetPsaResponseSchema = responseWithData(z.array(PSASchema)); +export type GetPsaResponse = z.infer; + +const c = initContract(); +export const psasContract = c.router( + { + get: { + summary: "get psas", + description: "Get list of public service announcements", + method: "GET", + path: "/", + responses: { + 200: GetPsaResponseSchema, + }, + }, + }, + { + pathPrefix: "/psas", + strictStatusCodes: true, + metadata: { + openApiTags: "psas", + authenticationOptions: { + isPublic: true, + }, + } as EndpointMetadata, + commonResponses: CommonResponses, + } +); diff --git a/packages/contracts/src/schemas/api.ts b/packages/contracts/src/schemas/api.ts index 37d3b6d2e..f90e47dbd 100644 --- a/packages/contracts/src/schemas/api.ts +++ b/packages/contracts/src/schemas/api.ts @@ -1,6 +1,6 @@ import { z, ZodSchema } from "zod"; -export type OpenApiTag = "configs" | "presets" | "ape-keys" | "admin"; +export type OpenApiTag = "configs" | "presets" | "ape-keys" | "admin" | "psas"; export type EndpointMetadata = { /** Authentication options, by default a bearer token is required. */ @@ -74,4 +74,7 @@ export const CommonResponses = { 422: MonkeyValidationErrorSchema.describe("Request validation failed"), 429: MonkeyClientError.describe("Rate limit exceeded"), 500: MonkeyServerError.describe("Generic server error"), + 503: MonkeyServerError.describe( + "Endpoint disabled or server is under maintenance" + ), }; diff --git a/packages/contracts/src/schemas/psas.ts b/packages/contracts/src/schemas/psas.ts new file mode 100644 index 000000000..2ec6d074a --- /dev/null +++ b/packages/contracts/src/schemas/psas.ts @@ -0,0 +1,11 @@ +import { z } from "zod"; +import { IdSchema } from "./util"; + +export const PSASchema = z.object({ + _id: IdSchema, + message: z.string(), + date: z.number().int().min(0).optional(), + level: z.number().int().optional(), + sticky: z.boolean().optional(), +}); +export type PSA = z.infer; diff --git a/packages/shared-types/src/index.ts b/packages/shared-types/src/index.ts index 695c637b4..fe8d50ea6 100644 --- a/packages/shared-types/src/index.ts +++ b/packages/shared-types/src/index.ts @@ -301,14 +301,6 @@ export type ResultFilters = { } & Record; }; -export type PSA = { - _id: string; - message: string; - sticky?: boolean; - level?: number; - date?: number; -}; - export type SpeedHistogram = { [key: string]: number; }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2eb2832a2..cea3e4b34 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -264,6 +264,9 @@ importers: ioredis-mock: specifier: 7.4.0 version: 7.4.0(ioredis@4.28.5) + openapi-recursive-tagging: + specifier: 0.0.6 + version: 0.0.6 readline-sync: specifier: 1.4.10 version: 1.4.10 @@ -2844,6 +2847,10 @@ packages: resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==} engines: {node: '>=0.10.0'} + ansi-regex@4.1.1: + resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==} + engines: {node: '>=6'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -3449,6 +3456,9 @@ packages: cliui@3.2.0: resolution: {integrity: sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==} + cliui@5.0.0: + resolution: {integrity: sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==} + cliui@7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} @@ -4189,6 +4199,9 @@ packages: electron-to-chromium@1.5.5: resolution: {integrity: sha512-QR7/A7ZkMS8tZuoftC/jfqNkZLQO779SSW3YuZHP4eXpj3EffGLFcB/Xu9AAZQzLccTiCV+EmUo3ha4mQ9wnlA==} + emoji-regex@7.0.3: + resolution: {integrity: sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==} + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -4665,6 +4678,10 @@ packages: resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} engines: {node: '>=4'} + find-up@3.0.0: + resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} + engines: {node: '>=6'} + find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -5504,6 +5521,10 @@ packages: resolution: {integrity: sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==} engines: {node: '>=0.10.0'} + is-fullwidth-code-point@2.0.0: + resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} + engines: {node: '>=4'} + is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} @@ -6028,6 +6049,10 @@ packages: resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} engines: {node: '>=4'} + locate-path@3.0.0: + resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} + engines: {node: '>=6'} + locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -6989,6 +7014,10 @@ packages: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} + openapi-recursive-tagging@0.0.6: + resolution: {integrity: sha512-ZtHR0jHeIMTuyeenbee7j0fK58Uf9ZMFGTXv3abQvsdjImfdEXfmmNlMNgpW27DmoomOgwwpGNGldUUQd0oJ4g==} + hasBin: true + openapi-sampler@1.5.1: resolution: {integrity: sha512-tIWIrZUKNAsbqf3bd9U1oH6JEXo8LNYuDlXw26By67EygpjT+ArFnsxxyTMjFWRfbqo5ozkvgSQDK69Gd8CddA==} @@ -7041,6 +7070,10 @@ packages: resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} engines: {node: '>=4'} + p-locate@3.0.0: + resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} + engines: {node: '>=6'} + p-locate@4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} @@ -7764,6 +7797,9 @@ packages: require-main-filename@1.0.1: resolution: {integrity: sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==} + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + requirejs-config-file@4.0.0: resolution: {integrity: sha512-jnIre8cbWOyvr8a5F2KuqBnY+SDA4NXr/hzEZJG79Mxm2WiFQz2dzhC8ibtPJS7zkmBEl1mxSwp5HhC1W4qpxw==} engines: {node: '>=10.13.0'} @@ -8300,6 +8336,10 @@ packages: resolution: {integrity: sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==} engines: {node: '>=0.10.0'} + string-width@3.1.0: + resolution: {integrity: sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==} + engines: {node: '>=6'} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -8340,6 +8380,10 @@ packages: resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} engines: {node: '>=0.10.0'} + strip-ansi@5.2.0: + resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==} + engines: {node: '>=6'} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -9292,6 +9336,9 @@ packages: which-module@1.0.0: resolution: {integrity: sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==} + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + which-pm-runs@1.1.0: resolution: {integrity: sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==} engines: {node: '>=4'} @@ -9397,6 +9444,10 @@ packages: resolution: {integrity: sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==} engines: {node: '>=0.10.0'} + wrap-ansi@5.1.0: + resolution: {integrity: sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==} + engines: {node: '>=6'} + wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} @@ -9438,6 +9489,9 @@ packages: y18n@3.2.2: resolution: {integrity: sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==} + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -9460,6 +9514,9 @@ packages: engines: {node: '>= 14'} hasBin: true + yargs-parser@15.0.3: + resolution: {integrity: sha512-/MVEVjTXy/cGAjdtQf8dW3V9b97bPN7rNn8ETj6BmAQL7ibC7O1Q9SPJbGjgh3SlwoBNXMzj/ZGIj8mBgl12YA==} + yargs-parser@20.2.9: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} engines: {node: '>=10'} @@ -9471,6 +9528,9 @@ packages: yargs-parser@5.0.1: resolution: {integrity: sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==} + yargs@14.2.3: + resolution: {integrity: sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==} + yargs@16.2.0: resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} engines: {node: '>=10'} @@ -12174,6 +12234,8 @@ snapshots: ansi-regex@2.1.1: {} + ansi-regex@4.1.1: {} + ansi-regex@5.0.1: {} ansi-regex@6.0.1: {} @@ -12887,6 +12949,12 @@ snapshots: strip-ansi: 3.0.1 wrap-ansi: 2.1.0 + cliui@5.0.0: + dependencies: + string-width: 3.1.0 + strip-ansi: 5.2.0 + wrap-ansi: 5.1.0 + cliui@7.0.4: dependencies: string-width: 4.2.3 @@ -13651,6 +13719,8 @@ snapshots: electron-to-chromium@1.5.5: {} + emoji-regex@7.0.3: {} + emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} @@ -14464,6 +14534,10 @@ snapshots: dependencies: locate-path: 2.0.0 + find-up@3.0.0: + dependencies: + locate-path: 3.0.0 + find-up@4.1.0: dependencies: locate-path: 5.0.0 @@ -15594,6 +15668,8 @@ snapshots: dependencies: number-is-nan: 1.0.1 + is-fullwidth-code-point@2.0.0: {} + is-fullwidth-code-point@3.0.0: {} is-fullwidth-code-point@4.0.0: {} @@ -16132,6 +16208,11 @@ snapshots: p-locate: 2.0.0 path-exists: 3.0.0 + locate-path@3.0.0: + dependencies: + p-locate: 3.0.0 + path-exists: 3.0.0 + locate-path@5.0.0: dependencies: p-locate: 4.1.0 @@ -17206,7 +17287,7 @@ snapshots: oas-kit-common: 1.0.8 reftools: 1.1.9 yaml: 1.10.2 - yargs: 17.0.1 + yargs: 17.7.2 oas-schema-walker@1.1.5: {} @@ -17348,6 +17429,12 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 + openapi-recursive-tagging@0.0.6: + dependencies: + reftools: 1.1.9 + yaml: 1.10.2 + yargs: 14.2.3 + openapi-sampler@1.5.1: dependencies: '@types/json-schema': 7.0.15 @@ -17414,6 +17501,10 @@ snapshots: dependencies: p-limit: 1.3.0 + p-locate@3.0.0: + dependencies: + p-limit: 2.3.0 + p-locate@4.1.0: dependencies: p-limit: 2.3.0 @@ -18203,6 +18294,8 @@ snapshots: require-main-filename@1.0.1: {} + require-main-filename@2.0.0: {} + requirejs-config-file@4.0.0: dependencies: esprima: 4.0.1 @@ -18789,6 +18882,12 @@ snapshots: is-fullwidth-code-point: 1.0.0 strip-ansi: 3.0.1 + string-width@3.1.0: + dependencies: + emoji-regex: 7.0.3 + is-fullwidth-code-point: 2.0.0 + strip-ansi: 5.2.0 + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -18855,6 +18954,10 @@ snapshots: dependencies: ansi-regex: 2.1.1 + strip-ansi@5.2.0: + dependencies: + ansi-regex: 4.1.1 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -19037,7 +19140,7 @@ snapshots: oas-validator: 5.0.8 reftools: 1.1.9 yaml: 1.10.2 - yargs: 17.0.1 + yargs: 17.7.2 transitivePeerDependencies: - encoding @@ -19924,6 +20027,8 @@ snapshots: which-module@1.0.0: {} + which-module@2.0.1: {} + which-pm-runs@1.1.0: {} which-typed-array@1.1.15: @@ -20105,6 +20210,12 @@ snapshots: string-width: 1.0.2 strip-ansi: 3.0.1 + wrap-ansi@5.1.0: + dependencies: + ansi-styles: 3.2.1 + string-width: 3.1.0 + strip-ansi: 5.2.0 + wrap-ansi@6.2.0: dependencies: ansi-styles: 4.3.0 @@ -20140,6 +20251,8 @@ snapshots: y18n@3.2.2: {} + y18n@4.0.3: {} + y18n@5.0.8: {} yallist@3.1.1: {} @@ -20152,6 +20265,11 @@ snapshots: yaml@2.5.0: {} + yargs-parser@15.0.3: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + yargs-parser@20.2.9: {} yargs-parser@21.1.1: {} @@ -20161,6 +20279,20 @@ snapshots: camelcase: 3.0.0 object.assign: 4.1.5 + yargs@14.2.3: + dependencies: + cliui: 5.0.0 + decamelize: 1.2.0 + find-up: 3.0.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 3.1.0 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 15.0.3 + yargs@16.2.0: dependencies: cliui: 7.0.4