mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-03-24 11:03:17 -04:00
feat: require JSDoc in new api (#50429)
Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
@@ -169,6 +169,29 @@
|
||||
"rules": {
|
||||
"filenames-simple/naming-convention": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["**/api/src/**/*.ts"],
|
||||
"plugins": ["jsdoc"],
|
||||
"extends": ["plugin:jsdoc/recommended-typescript-error"],
|
||||
"rules": {
|
||||
"jsdoc/require-jsdoc": [
|
||||
"error",
|
||||
{
|
||||
"require": {
|
||||
"ArrowFunctionExpression": true,
|
||||
"ClassDeclaration": true,
|
||||
"ClassExpression": true,
|
||||
"FunctionDeclaration": true,
|
||||
"FunctionExpression": true,
|
||||
"MethodDefinition": true
|
||||
},
|
||||
"publicOnly": true
|
||||
}
|
||||
],
|
||||
"jsdoc/require-description-complete-sentence": "warn",
|
||||
"jsdoc/tag-lines": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -69,7 +69,8 @@
|
||||
"start": "FREECODECAMP_NODE_ENV=production node dist/server.js",
|
||||
"test": "jest --force-exit",
|
||||
"prisma": "dotenv -e ../.env prisma",
|
||||
"postinstall": "prisma generate"
|
||||
"postinstall": "prisma generate",
|
||||
"lint": "cd .. && eslint api/src --max-warnings 0"
|
||||
},
|
||||
"version": "0.0.1"
|
||||
}
|
||||
|
||||
@@ -77,6 +77,13 @@ ajv.addFormat('objectid', {
|
||||
validate: (str: string) => isObjectID(str)
|
||||
});
|
||||
|
||||
/**
|
||||
* Top-level wrapper to instantiate the API server. This is where all middleware and
|
||||
* routes should be mounted.
|
||||
*
|
||||
* @param options The options to pass to the Fastify constructor.
|
||||
* @returns The instantiated Fastify server, with TypeBox.
|
||||
*/
|
||||
export const build = async (
|
||||
options: FastifyHttpOptions<RawServerDefault, FastifyBaseLogger> = {}
|
||||
): Promise<FastifyInstanceWithTypeProvider> => {
|
||||
|
||||
@@ -3,6 +3,13 @@ import type { NextFunction, NextHandleFunction } from '@fastify/middie';
|
||||
type MiddieRequest = Parameters<NextHandleFunction>[0];
|
||||
type MiddieResponse = Parameters<NextHandleFunction>[1];
|
||||
|
||||
/**
|
||||
* Test middleware used to log request and response data?
|
||||
*
|
||||
* @param req The request payload.
|
||||
* @param res The response to be sent back to the request.
|
||||
* @param next Callback function to indicate that the middleware logic is complete.
|
||||
*/
|
||||
export function testMiddleware(
|
||||
req: MiddieRequest,
|
||||
res: MiddieResponse,
|
||||
|
||||
@@ -47,6 +47,15 @@ const findOrCreateUser = async (fastify: FastifyInstance, email: string) => {
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Route handler for development login. This is only used in local
|
||||
* development, and bypasses Auth0, authenticating as the development
|
||||
* user.
|
||||
*
|
||||
* @param fastify The Fastify instance.
|
||||
* @param _options Fastify options I guess?
|
||||
* @param done Callback to signal that the logic has completed.
|
||||
*/
|
||||
export const devLoginCallback: FastifyPluginCallback = (
|
||||
fastify,
|
||||
_options,
|
||||
@@ -64,6 +73,13 @@ export const devLoginCallback: FastifyPluginCallback = (
|
||||
done();
|
||||
};
|
||||
|
||||
/**
|
||||
* Route handler for Auth0 authentication.
|
||||
*
|
||||
* @param fastify The Fastify instance.
|
||||
* @param _options Fastify options I guess?
|
||||
* @param done Callback to signal that the logic has completed.
|
||||
*/
|
||||
export const auth0Routes: FastifyPluginCallback = (fastify, _options, done) => {
|
||||
fastify.addHook('onRequest', fastify.authenticate);
|
||||
|
||||
|
||||
@@ -11,6 +11,13 @@ import {
|
||||
updateProject
|
||||
} from './helpers/challenge-helpers';
|
||||
|
||||
/**
|
||||
* Plugin for the challenge submission endpoints.
|
||||
*
|
||||
* @param fastify The Fastify instance.
|
||||
* @param _options Options passed to the plugin via `fastify.register(plugin, options)`.
|
||||
* @param done The callback to signal that the plugin is ready.
|
||||
*/
|
||||
export const challengeRoutes: FastifyPluginCallbackTypebox = (
|
||||
fastify,
|
||||
_options,
|
||||
|
||||
@@ -10,6 +10,18 @@ export const endpoints: Endpoints = [
|
||||
['/account', 'GET']
|
||||
];
|
||||
|
||||
/**
|
||||
* Plugin for the deprecated endpoints. Instantiates a Fastify route for each
|
||||
* endpoint, returning a 410 status code and a message indicating that the user
|
||||
* should reload the app.
|
||||
*
|
||||
* These endpoints remain active until we can confirm that no requests are being
|
||||
* made to them.
|
||||
*
|
||||
* @param fastify The Fastify instance.
|
||||
* @param _options Fastify options I guess?
|
||||
* @param done Callback to signal that the logic has completed.
|
||||
*/
|
||||
export const deprecatedEndpoints: FastifyPluginCallbackTypebox = (
|
||||
fastify,
|
||||
_options,
|
||||
|
||||
@@ -8,6 +8,15 @@ export const unsubscribeEndpoints: Endpoint[] = [
|
||||
['/unsubscribe/:email', 'GET']
|
||||
];
|
||||
|
||||
/**
|
||||
* Plugin for the deprecated unsubscribe endpoints. Each route returns a 302
|
||||
* redirect to the referer with a message explaining how to unsubscribe.
|
||||
*
|
||||
* @param fastify The Fastify instance.
|
||||
* @param _options Options passed to the plugin via `fastify.register(plugin,
|
||||
* options)`.
|
||||
* @param done The callback to signal that the plugin is ready.
|
||||
*/
|
||||
export const unsubscribeDeprecated: FastifyPluginCallbackTypebox = (
|
||||
fastify,
|
||||
_options,
|
||||
|
||||
@@ -3,6 +3,13 @@ import {
|
||||
type FastifyPluginCallbackTypebox
|
||||
} from '@fastify/type-provider-typebox';
|
||||
|
||||
/**
|
||||
* Plugin for the donation endpoints.
|
||||
*
|
||||
* @param fastify The Fastify instance.
|
||||
* @param _options Options passed to the plugin via `fastify.register(plugin, options)`.
|
||||
* @param done The callback to signal that the plugin is ready.
|
||||
*/
|
||||
export const donateRoutes: FastifyPluginCallbackTypebox = (
|
||||
fastify,
|
||||
_options,
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
import type { Prisma } from '@prisma/client';
|
||||
import type { ProgressTimestamp } from '../../utils/progress';
|
||||
|
||||
/**
|
||||
* Confirm that a user can submit a CodeRoad project.
|
||||
*
|
||||
* @param id The id of the project.
|
||||
* @param param The challenges the user has completed.
|
||||
* @param param.partiallyCompletedChallenges The partially completed challenges.
|
||||
* @param param.completedChallenges The completed challenges.
|
||||
* @returns A boolean indicating if the user can submit the project.
|
||||
*/
|
||||
export const canSubmitCodeRoadCertProject = (
|
||||
id: string | undefined,
|
||||
{
|
||||
@@ -16,6 +25,12 @@ export const canSubmitCodeRoadCertProject = (
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the Prisma query to update a project.
|
||||
* @param id The id of the project.
|
||||
* @param newChallenge The challenge corresponding to the project.
|
||||
* @returns A Prisma query to update the project.
|
||||
*/
|
||||
export const updateProject = (
|
||||
id: string,
|
||||
newChallenge: Prisma.CompletedChallengeUpdateInput
|
||||
@@ -26,6 +41,13 @@ export const updateProject = (
|
||||
partiallyCompletedChallenges: { deleteMany: { where: { id } } }
|
||||
});
|
||||
|
||||
/**
|
||||
* Create the Prisma query to create a project.
|
||||
* @param id The id of the project.
|
||||
* @param newChallenge The challenge corresponding to the project.
|
||||
* @param progressTimestamps The user's current progress timestamps.
|
||||
* @returns A Prisma query to update the project.
|
||||
*/
|
||||
export const createProject = (
|
||||
id: string,
|
||||
newChallenge: Prisma.CompletedChallengeCreateInput,
|
||||
|
||||
@@ -5,6 +5,12 @@ import { isValidUsername } from '../../../utils/validate';
|
||||
import { blocklistedUsernames } from '../../../config/constants.js';
|
||||
import { schemas } from '../schemas';
|
||||
|
||||
/**
|
||||
* Validate an image url.
|
||||
*
|
||||
* @param picture The url to check.
|
||||
* @returns Whether the url is a picture with a valid protocol.
|
||||
*/
|
||||
export const isPictureWithProtocol = (picture?: string): boolean => {
|
||||
if (!picture) return false;
|
||||
try {
|
||||
@@ -15,6 +21,13 @@ export const isPictureWithProtocol = (picture?: string): boolean => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Plugin for all endpoints related to user settings.
|
||||
*
|
||||
* @param fastify The Fastify instance.
|
||||
* @param _options Fastify options I guess?
|
||||
* @param done Callback to signal that the logic has completed.
|
||||
*/
|
||||
export const settingRoutes: FastifyPluginCallbackTypebox = (
|
||||
fastify,
|
||||
_options,
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
import { type FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox';
|
||||
|
||||
/**
|
||||
* Plugin for the health check endpoint.
|
||||
*
|
||||
* @param fastify The Fastify instance.
|
||||
* @param _options Options passed to the plugin via `fastify.register(plugin,
|
||||
* options)`.
|
||||
* @param done The callback to signal that the plugin is ready.
|
||||
*/
|
||||
export const statusRoute: FastifyPluginCallbackTypebox = (
|
||||
fastify,
|
||||
_options,
|
||||
|
||||
@@ -24,6 +24,14 @@ const nanoid = customAlphabet(
|
||||
64
|
||||
);
|
||||
|
||||
/**
|
||||
* Wrapper for endpoints related to user account management,
|
||||
* such as account deletion.
|
||||
*
|
||||
* @param fastify The Fastify instance.
|
||||
* @param _options Fastify options I guess?
|
||||
* @param done Callback to signal that the logic has completed.
|
||||
*/
|
||||
export const userRoutes: FastifyPluginCallbackTypebox = (
|
||||
fastify,
|
||||
_options,
|
||||
|
||||
@@ -65,6 +65,18 @@ type CompletedChallenge = {
|
||||
files?: CompletedChallengeFile[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to update a user's challenge data. Used in challenge
|
||||
* submission endpoints.
|
||||
*
|
||||
* @deprecated Create specific functions for each submission endpoint.
|
||||
* @param fastify The Fastify instance.
|
||||
* @param user The existing user record.
|
||||
* @param challengeId The id of the submitted challenge.
|
||||
* @param _completedChallenge The challenge submission.
|
||||
* @param timezone The user's timezone.
|
||||
* @returns Information about the update.
|
||||
*/
|
||||
export async function updateUserChallengeData(
|
||||
fastify: FastifyInstance,
|
||||
user: user,
|
||||
|
||||
@@ -9,7 +9,12 @@ export type FormattedError = {
|
||||
| 'You have to complete the project before you can submit a URL.';
|
||||
};
|
||||
|
||||
// This only formats invalid challenge submission for now.
|
||||
/**
|
||||
* Format invalid challenge submission errors.
|
||||
*
|
||||
* @param errors An array of validation errors.
|
||||
* @returns Formatted errors that can be used in the response.
|
||||
*/
|
||||
export const formatValidationError = (
|
||||
errors: ErrorObject[]
|
||||
): FormattedError => {
|
||||
|
||||
@@ -20,6 +20,10 @@ interface CurriculumProps {
|
||||
blocks: Record<string, Block>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the challenges from the curriculum.
|
||||
* @returns An array of challenges.
|
||||
*/
|
||||
export function getChallenges() {
|
||||
const superBlockKeys = Object.values(SuperBlocks);
|
||||
const typedCurriculum: Curriculum = curriculum as Curriculum;
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import { randomBytes, createHash } from 'crypto';
|
||||
|
||||
/**
|
||||
* Utility to encode a buffer to a base64 URI.
|
||||
*
|
||||
* @param buf The buffer to encode.
|
||||
* @returns The encoded string.
|
||||
*/
|
||||
export function base64URLEncode(buf: Buffer): string {
|
||||
return buf
|
||||
.toString('base64')
|
||||
|
||||
@@ -9,6 +9,12 @@ type NoNullProperties<T> = {
|
||||
[P in keyof T]: NullToUndefined<T[P]>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a Twitter handle or URL to a URL.
|
||||
*
|
||||
* @param handleOrUrl Twitter handle or URL.
|
||||
* @returns Twitter URL.
|
||||
*/
|
||||
export const normalizeTwitter = (
|
||||
handleOrUrl: string | null
|
||||
): string | undefined => {
|
||||
@@ -23,6 +29,12 @@ export const normalizeTwitter = (
|
||||
return url ?? handleOrUrl;
|
||||
};
|
||||
|
||||
/**
|
||||
* Ensure that the user's profile UI settings are valid.
|
||||
*
|
||||
* @param maybeProfileUI A null or the user's profile UI settings.
|
||||
* @returns The input with nulls removed or a default value if there is no input.
|
||||
*/
|
||||
export const normalizeProfileUI = (
|
||||
maybeProfileUI: ProfileUI | null
|
||||
): NoNullProperties<ProfileUI> => {
|
||||
@@ -42,6 +54,12 @@ export const normalizeProfileUI = (
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove all the null properties from an object.
|
||||
*
|
||||
* @param obj Any object.
|
||||
* @returns The input with nulls removed.
|
||||
*/
|
||||
export const removeNulls = <T extends Record<string, unknown>>(
|
||||
obj: T
|
||||
): NoNullProperties<T> =>
|
||||
@@ -65,6 +83,12 @@ type NormalizedChallenge = {
|
||||
solution?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove all the null properties from a CompletedChallenge array.
|
||||
*
|
||||
* @param completedChallenges The CompletedChallenge array.
|
||||
* @returns The input with nulls removed.
|
||||
*/
|
||||
export const normalizeChallenges = (
|
||||
completedChallenges: CompletedChallenge[]
|
||||
): NormalizedChallenge[] => {
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
export type ProgressTimestamp = number | { timestamp: number } | null;
|
||||
|
||||
/**
|
||||
* Converts a ProgressTimestamp array to a object with keys based on the timestamps.
|
||||
*
|
||||
* @param progressTimestamps The ProgressTimestamp array.
|
||||
* @returns The object with keys based on the timestamps.
|
||||
*/
|
||||
export const getCalendar = (
|
||||
progressTimestamps: ProgressTimestamp[] | null
|
||||
): Record<string, 1> => {
|
||||
@@ -17,6 +23,12 @@ export const getCalendar = (
|
||||
return calendar;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a ProgressTimestamp array to an integer number of points.
|
||||
*
|
||||
* @param progressTimestamps The ProgressTimestamp array.
|
||||
* @returns The number of points.
|
||||
*/
|
||||
export const getPoints = (
|
||||
progressTimestamps: ProgressTimestamp[] | null
|
||||
): number => {
|
||||
|
||||
@@ -2,6 +2,12 @@ import jwt from 'jsonwebtoken';
|
||||
|
||||
import { JWT_SECRET } from './env';
|
||||
|
||||
/**
|
||||
* Encode an id into a JWT (the naming suggests it's a user token, but it's the
|
||||
* id of the UserToken document).
|
||||
* @param userToken A token id to encode.
|
||||
* @returns An encoded object with the userToken property.
|
||||
*/
|
||||
export function encodeUserToken(userToken: string): string {
|
||||
return jwt.sign({ userToken }, JWT_SECRET);
|
||||
}
|
||||
|
||||
@@ -2,5 +2,11 @@ import { ObjectId } from 'mongodb';
|
||||
|
||||
// This is trivial, but makes it simple to refactor if we swap monogodb for
|
||||
// bson, say.
|
||||
|
||||
/**
|
||||
* Checks if a string is a valid MongoDB ObjectID.
|
||||
* @param id A string to check.
|
||||
* @returns A boolean indicating if the string is a valid MongoDB ObjectID.
|
||||
*/
|
||||
export const isObjectID = (id?: string): boolean =>
|
||||
id ? ObjectId.isValid(id) : false;
|
||||
|
||||
@@ -130,6 +130,7 @@
|
||||
"eslint-plugin-filenames-simple": "0.8.0",
|
||||
"eslint-plugin-import": "2.28.0",
|
||||
"eslint-plugin-jest-dom": "3.9.4",
|
||||
"eslint-plugin-jsdoc": "44.2.4",
|
||||
"eslint-plugin-jsx-a11y": "6.7.1",
|
||||
"eslint-plugin-no-only-tests": "2.6.0",
|
||||
"eslint-plugin-react": "7.33.1",
|
||||
|
||||
58
pnpm-lock.yaml
generated
58
pnpm-lock.yaml
generated
@@ -99,6 +99,9 @@ importers:
|
||||
eslint-plugin-jest-dom:
|
||||
specifier: 3.9.4
|
||||
version: 3.9.4(eslint@8.46.0)
|
||||
eslint-plugin-jsdoc:
|
||||
specifier: 44.2.4
|
||||
version: 44.2.4(eslint@8.46.0)
|
||||
eslint-plugin-jsx-a11y:
|
||||
specifier: 6.7.1
|
||||
version: 6.7.1(eslint@8.46.0)
|
||||
@@ -6859,6 +6862,15 @@ packages:
|
||||
transitivePeerDependencies:
|
||||
- typescript
|
||||
|
||||
/@es-joy/jsdoccomment@0.39.4:
|
||||
resolution: {integrity: sha512-Jvw915fjqQct445+yron7Dufix9A+m9j1fCJYlCo1FWlRvTxa3pjJelxdSTdaLWcTwRU6vbL+NYjO4YuNIS5Qg==}
|
||||
engines: {node: '>=16'}
|
||||
dependencies:
|
||||
comment-parser: 1.3.1
|
||||
esquery: 1.5.0
|
||||
jsdoc-type-pratt-parser: 4.0.0
|
||||
dev: true
|
||||
|
||||
/@eslint-community/eslint-utils@4.4.0(eslint@8.46.0):
|
||||
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
@@ -12358,6 +12370,11 @@ packages:
|
||||
resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==}
|
||||
dev: false
|
||||
|
||||
/are-docs-informative@0.0.2:
|
||||
resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==}
|
||||
engines: {node: '>=14'}
|
||||
dev: true
|
||||
|
||||
/are-we-there-yet@2.0.0:
|
||||
resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -15245,6 +15262,11 @@ packages:
|
||||
engines: {node: ^12.20.0 || >=14}
|
||||
dev: true
|
||||
|
||||
/comment-parser@1.3.1:
|
||||
resolution: {integrity: sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
dev: true
|
||||
|
||||
/common-path-prefix@3.0.0:
|
||||
resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==}
|
||||
|
||||
@@ -17814,6 +17836,25 @@ packages:
|
||||
- typescript
|
||||
dev: false
|
||||
|
||||
/eslint-plugin-jsdoc@44.2.4(eslint@8.46.0):
|
||||
resolution: {integrity: sha512-/EMMxCyRh1SywhCb66gAqoGX4Yv6Xzc4bsSkF1AiY2o2+bQmGMQ05QZ5+JjHbdFTPDZY9pfn+DsSNP0a5yQpIg==}
|
||||
engines: {node: '>=16'}
|
||||
peerDependencies:
|
||||
eslint: ^7.0.0 || ^8.0.0
|
||||
dependencies:
|
||||
'@es-joy/jsdoccomment': 0.39.4
|
||||
are-docs-informative: 0.0.2
|
||||
comment-parser: 1.3.1
|
||||
debug: 4.3.4(supports-color@8.1.1)
|
||||
escape-string-regexp: 4.0.0
|
||||
eslint: 8.46.0
|
||||
esquery: 1.5.0
|
||||
semver: 7.5.3
|
||||
spdx-expression-parse: 3.0.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/eslint-plugin-jsx-a11y@6.7.1(eslint@7.32.0):
|
||||
resolution: {integrity: sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==}
|
||||
engines: {node: '>=4.0'}
|
||||
@@ -21072,13 +21113,23 @@ packages:
|
||||
dependencies:
|
||||
'@types/express': 4.17.17
|
||||
'@types/http-proxy': 1.17.10
|
||||
http-proxy: 1.18.1(debug@3.2.7)
|
||||
http-proxy: 1.18.1
|
||||
is-glob: 4.0.3
|
||||
is-plain-obj: 3.0.0
|
||||
micromatch: 4.0.5
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
|
||||
/http-proxy@1.18.1:
|
||||
resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==}
|
||||
engines: {node: '>=8.0.0'}
|
||||
dependencies:
|
||||
eventemitter3: 4.0.7
|
||||
follow-redirects: 1.15.2(debug@4.3.4)
|
||||
requires-port: 1.0.0
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
|
||||
/http-proxy@1.18.1(debug@3.2.7):
|
||||
resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==}
|
||||
engines: {node: '>=8.0.0'}
|
||||
@@ -23342,6 +23393,11 @@ packages:
|
||||
/jsbn@0.1.1:
|
||||
resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==}
|
||||
|
||||
/jsdoc-type-pratt-parser@4.0.0:
|
||||
resolution: {integrity: sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
dev: true
|
||||
|
||||
/jsdom@16.7.0:
|
||||
resolution: {integrity: sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
Reference in New Issue
Block a user