From c6d100fa7901dfbf535f787332c317bb22ce957e Mon Sep 17 00:00:00 2001 From: Alex Layton Date: Tue, 2 Aug 2022 14:22:31 -0400 Subject: [PATCH] refactor(well-known): fastify & prom metrics --- .vscode/launch.json | 19 +- charts/oada/templates/configmap.yaml | 1 + oada/.yarnrc.yml | 1 + oada/libs/lib-prom/src/index.ts | 2 +- oada/services/http-handler/src/config.ts | 6 + oada/services/http-handler/src/server.ts | 10 +- oada/services/http-handler/src/types.d.ts | 16 ++ oada/services/well-known/package.json | 14 +- oada/services/well-known/src/config.ts | 28 +-- oada/services/well-known/src/index.ts | 243 ++++++++-------------- oada/services/well-known/src/types.d.ts | 31 +++ oada/yarn.lock | 121 ++++++++++- 12 files changed, 305 insertions(+), 187 deletions(-) create mode 100644 oada/services/well-known/src/types.d.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index a750d0a5..388d2726 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -52,6 +52,22 @@ "localRoot": "${workspaceFolder}/oada/", "remoteRoot": "/oada/" }, + { + "name": "k8s: Attach to well-known", + "presentation": { + "group": "k8s" + }, + "type": "cloudcode.kubernetes", + "request": "attach", + "language": "Node", + "debugPort": "inspect", + "podSelector": { + "app.kubernetes.io/name": "well-known" + }, + "smartStep": true, + "localRoot": "${workspaceFolder}/oada/", + "remoteRoot": "/oada/" + }, { "type": "node", "request": "attach", @@ -69,7 +85,8 @@ "configurations": [ "k8s: Attach to http-handler", "k8s: Attach to write-handler", - "k8s: Attach to auth" + "k8s: Attach to auth", + "k8s: Attach to well-known" ], "presentation": { "group": "k8s", diff --git a/charts/oada/templates/configmap.yaml b/charts/oada/templates/configmap.yaml index a45e61f4..515c3a03 100644 --- a/charts/oada/templates/configmap.yaml +++ b/charts/oada/templates/configmap.yaml @@ -38,6 +38,7 @@ data: {{ if eq (include "oada.kafka.deploy" .) "true" -}} KAFKA_BROKERS: {{ include "oada.kafka.brokers" . }} {{- end }} + WELLKNOWN_SUBSERVICES: http://auth-{{ .Release.Name }} {{ if .Values.global.development -}} NODE_ENV: development NODE_TLS_REJECT_UNAUTHORIZED: '0' diff --git a/oada/.yarnrc.yml b/oada/.yarnrc.yml index 3d47ef09..e3cf92c8 100644 --- a/oada/.yarnrc.yml +++ b/oada/.yarnrc.yml @@ -21,6 +21,7 @@ packageExtensions: "@oada/well-known-json@*": peerDependencies: "@types/express": "*" + fastify: "*" express@*: peerDependencies: ejs: "*" diff --git a/oada/libs/lib-prom/src/index.ts b/oada/libs/lib-prom/src/index.ts index f4dd178d..19272ef4 100644 --- a/oada/libs/lib-prom/src/index.ts +++ b/oada/libs/lib-prom/src/index.ts @@ -1,6 +1,6 @@ /** * @license - * Copyright 2017-2021 Open Ag Data Alliance + * Copyright 2022 Open Ag Data Alliance * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/oada/services/http-handler/src/config.ts b/oada/services/http-handler/src/config.ts index 496e1a89..e2ea3082 100644 --- a/oada/services/http-handler/src/config.ts +++ b/oada/services/http-handler/src/config.ts @@ -18,6 +18,12 @@ import libConfig from '@oada/lib-config'; export const { config, schema } = await libConfig({ + 'trustProxy': { + format: Array, + default: ['uniquelocal'], + env: 'TRUST_PROXY', + arg: 'trust-proxy', + }, 'server': { port: { format: 'port', diff --git a/oada/services/http-handler/src/server.ts b/oada/services/http-handler/src/server.ts index 6c505318..5f94bf63 100644 --- a/oada/services/http-handler/src/server.ts +++ b/oada/services/http-handler/src/server.ts @@ -17,6 +17,8 @@ import { mixins, pino } from '@oada/pino-debug'; +import { config } from './config.js'; + import { KafkaError } from '@oada/lib-kafka'; import { nstats } from '@oada/lib-prom'; @@ -24,7 +26,6 @@ import { plugin as formats } from '@oada/formats-server'; import tokenLookup, { TokenResponse } from './tokenLookup.js'; import authorizations from './authorizations.js'; -import { config } from './config.js'; import resources from './resources.js'; import users from './users.js'; import websockets from './websockets.js'; @@ -86,8 +87,10 @@ mixins.push(() => ({ reqId: requestContext.get('id'), })); +const trustProxy = config.get('trustProxy'); // eslint-disable-next-line new-cap export const fastify = Fastify({ + trustProxy, logger: { ...logger, // HACK: fastify overrides existing serializers. This circumvents that... @@ -137,12 +140,13 @@ if (process.env.NODE_ENV !== 'production') { }); } +const port = config.get('server.port'); export async function start(): Promise { await fastify.listen({ - port: config.get('server.port'), + port, host: '::', }); - fastify.log.info('OADA Server started on port %d', config.get('server.port')); + fastify.log.info('OADA Server started on port %d', port); } declare module '@fastify/request-context' { diff --git a/oada/services/http-handler/src/types.d.ts b/oada/services/http-handler/src/types.d.ts index 98c0c959..ab2dbea4 100644 --- a/oada/services/http-handler/src/types.d.ts +++ b/oada/services/http-handler/src/types.d.ts @@ -24,3 +24,19 @@ declare module 'es-main' { declare module 'assert' { function internal(value: unknown, message?: string | Error): asserts value; } + +declare module 'nstats' { + import type { Server as HTTPServer } from 'node:http'; + + import type { Plugin } from 'fastify-plugin'; + import type { Server as WSServer } from 'ws'; + + export interface NStats { + fastify(): Plugin; + toPrometheus(): string; + } + + function nstats(ws?: WSServer, http?: HTTPServer, semver?: string): NStats; + + export = nstats; +} diff --git a/oada/services/well-known/package.json b/oada/services/well-known/package.json index 3520658d..c49c5642 100644 --- a/oada/services/well-known/package.json +++ b/oada/services/well-known/package.json @@ -28,23 +28,23 @@ "test": "echo \"Error: no test specified\" && exit 1" }, "dependencies": { - "@oada/error": "^2.0.1", + "@fastify/accepts": "^4.0.0", + "@fastify/cors": "^8.0.0", + "@fastify/helmet": "^9.1.0", "@oada/formats-server": "^3.1.1", "@oada/lib-config": "^3.5.1", "@oada/lib-prom": "workspace:^", "@oada/pino-debug": "^3.5.1", - "@oada/well-known-json": "^2.0.1", - "axios": "^0.27.2", - "cors": "^2.8.5", + "@oada/well-known-json": "^4.0.0", "debug": "^4.3.4", - "express": "^4.18.1", - "helmet": "^5.1.1", + "fastify": "^4.3.0", + "got": "^12.3.0", "tslib": "^2.4.0" }, "devDependencies": { "@types/cors": "^2.8.12", "@types/debug": "^4.1.7", - "@types/express": "^4.17.13" + "fastify-plugin": "^4.0.0" }, "volta": { "node": "18.5.0" diff --git a/oada/services/well-known/src/config.ts b/oada/services/well-known/src/config.ts index 32b417d9..a244e9e1 100644 --- a/oada/services/well-known/src/config.ts +++ b/oada/services/well-known/src/config.ts @@ -18,13 +18,13 @@ import libConfig from '@oada/lib-config'; export const { config, schema } = await libConfig({ + trustProxy: { + format: Array, + default: ['uniquelocal'], + env: 'TRUST_PROXY', + arg: 'trust-proxy', + }, wellKnown: { - 'forceProtocol': { - doc: 'use this to force https prefixes on URLs. Useful when behind a proxy.', - format: ['https', 'http'], - nullable: true, - default: null, - }, 'server': { port: { format: 'port', @@ -66,11 +66,15 @@ export const { config, schema } = await libConfig({ }, 'mergeSubServices': { format: Array, - default: [] as Array<{ - resource: string; - base: string; - addPrefix?: string; - }>, + default: [] as Array< + | { + base: string; + addPrefix?: string; + } + | string + >, + env: 'WELLKNOWN_SUBSERVICES', + arg: 'wellknown-subservices', }, 'oada-configuration': { format: Object, @@ -100,7 +104,7 @@ if (!config.get('wellKnown.oada-configuration.oada_base_uri')) { config.set( 'wellKnown.wellKnown.server.oada-configuration.oada_base_uri', `${server.mode}//${server.domain}${server.port ? `:${server.port}` : ''}${ - server.path_prefix ? server.path_prefix : '' + server.path_prefix ?? '' }` ); } diff --git a/oada/services/well-known/src/index.ts b/oada/services/well-known/src/index.ts index f539d256..b845e944 100644 --- a/oada/services/well-known/src/index.ts +++ b/oada/services/well-known/src/index.ts @@ -23,194 +23,133 @@ // internal requests to every internal service to retrieve the // latest well-known documents. +import { pino } from '@oada/pino-debug'; + import { config } from './config.js'; -import '@oada/lib-prom'; +import { nstats } from '@oada/lib-prom'; -import type { ServerOptions } from 'node:http'; -import https from 'node:https'; +import got from 'got'; -import axios from 'axios'; -import cors from 'cors'; -import debuglib from 'debug'; -import express from 'express'; -import helmet from 'helmet'; +import Fastify from 'fastify'; +import accepts from '@fastify/accepts'; +import cors from '@fastify/cors'; +import helmet from '@fastify/helmet'; -import { Codes, OADAError, middleware } from '@oada/error'; -import { middleware as formats } from '@oada/formats-server'; +import { plugin as formats } from '@oada/formats-server'; import wkj from '@oada/well-known-json'; -// Setup the loggers: -const log = { - error: debuglib('well-known:error'), - info: debuglib('well-known:info'), - trace: debuglib('well-known:trace'), -}; - -log.info('-------------------------------------------------------------'); -log.info('Starting server for ./well-known/oada-configuration...'); - -// Setup express: -const app = express(); +const trustProxy = config.get('trustProxy'); +// eslint-disable-next-line new-cap +const fastify = Fastify({ + trustProxy, + logger: pino(), +}); -app.use(helmet() as (...arguments_: unknown[]) => void); +fastify.log.info('Starting server for ./well-known/oada-configuration...'); -// ----------------------------------------------------------------- -// Log all requests before anything else gets them for debugging: -app.use((request, _response, next) => { - log.info('Received request: %s %s', request.method, request.url); - // Log.trace('req.headers = ', req.headers); - // log.trace('req.body = ', req.body); - next(); +await fastify.register(helmet, { + crossOriginResourcePolicy: { + policy: 'cross-origin', + }, }); -// ---------------------------------------------------------- +await fastify.register(accepts); + // Turn on CORS for all domains, allow the necessary headers -app.use( - cors({ - exposedHeaders: ['x-oada-rev', 'location'], - }) -); -app.options('*', cors() as (...arguments_: unknown[]) => void); +await fastify.register(cors, { + strictPreflight: false, + exposedHeaders: [ + 'x-oada-rev', + 'x-oada-path-leftover', + 'location', + 'content-location', + ], +}); +/* // TODO: Less gross fix for Content-Types? app.get('/.well-known/oada-configuration', (_, response, next) => { response.type('application/vnd.oada.oada-configuration.1+json'); next(); }); -app.get('/.well-known/oada-configuration', formats({})); - -// --------------------------------------------------- -// Configure the top-level OADA well-known handler middleware -const options: { forceProtocol?: string } = {}; -if (config.get('wellKnown.forceProtocol')) { - // Set to 'https' to force to https. Useful when behind another proxy. - options.forceProtocol = config.get('wellKnown.forceProtocol') ?? undefined; -} - -const wellKnownHandler = wkj.middleware( - { +*/ +await fastify.register(formats); + +const wellKnownOptions = { + resources: { 'oada-configuration': config.get('wellKnown.oada-configuration'), 'openid-configuration': config.get('wellKnown.openid-configuration'), }, - options -); +}; -// ------------------------------------------ -// Retrieve /.well-known/ from sub-services, -// replacing domains and paths as needed -app.use(async (request, _response, next) => { - try { - // Parse out the '/.well-known' part of the URL, like - // '/.well-known/oada-configuration' or '/.well-known/openid-configuration' - // - // /.well-known/oada-configuration - const whichdoc = request.url.replace(/^.*(\/.well-known\/.*$)/, '$1'); - // Oada-configuration - const resource = whichdoc.replace(/^\/.well-known\/(.*)$/, '$1'); - const subservices = config.get('wellKnown.mergeSubServices'); - if (Array.isArray(subservices)) { - await Promise.all( - subservices.map(async (s) => { - // If this subservice doesn't support this resource - // (oada-configuration vs. openid-configuration), move on... - if (s.resource !== resource) { - log.trace( - 'Requested resource %s, ' + - 'but this subservice entry (%o) is not for that resource.' + - 'Skipping...', - resource, - s - ); - return; - } +const subservices = new Set( + config + .get('wellKnown.mergeSubServices') + .map((s) => (typeof s === 'string' ? s : `${s.base}${s.addPrefix ?? ''}`)) +); - log.trace( +await fastify.register( + async (app) => { + app.addHook('preSerialization', async (request, _reply, payload) => { + // Parse out the '/.well-known' part of the URL, like + // '/.well-known/oada-configuration' or '/.well-known/openid-configuration' + // + // /.well-known/oada-configuration + const whichdoc = request.url.replace(/^.*(\/.well-known\/.*$)/, '$1'); + // Oada-configuration + const resource = whichdoc.replace(/^\/.well-known\/(.*)$/, '$1'); + + // Reverse-proxy + const proxy = got.extend({ + headers: { + 'X-Forwarded-Host': request.hostname, + 'X-Forwarded-Proto': request.protocol, + 'X-Forwarded-For': [...(request.ips ?? []), request.ip], + }, + }); + const rest = await Promise.all( + Array.from(subservices, async (s) => { + request.log.trace( 'Resource (%s) matches subservice entry (%o), retrieving', resource, s ); // Request this resource from the subservice: - const url = s.base + whichdoc; - log.trace('Requesting subservice URL: %s', url); + const url = s + whichdoc; + request.log.trace('Requesting subservice URL: %s', url); try { - const result = await axios.get(url); - if (result?.status !== 200) { - log.trace( - '%s does not exist for subservice %s', - whichdoc, - s.base - ); - return; - } - - log.trace('Merging %s for subservice %s', whichdoc, s.base); - // The wkj handler library puts the servername for the sub-service - // on the URLs instead of the proxy's name. - // Replace the subservice name with "./" - // so this top-level wkj handler will replace properly: - const pfx = s.addPrefix ?? ''; - const body = Object.fromEntries( - Object.entries(result.data).map(([key, value]) => [ - key, - typeof value === 'string' - ? value.replace(/^https?:\/\/[^/]+\//, `./${pfx}`) - : value, - ]) - ); - - wellKnownHandler.addResource(s.resource, body); - log.trace('Merged into %s: %O', whichdoc, body); - - // If failed to return, or json didn't parse: + const body = await proxy.get(url).json(); + request.log.trace({ whichdoc, body }, 'Merging in'); + return body; } catch (error: unknown) { - log.error({ error }, `The subservice URL ${url} failed`); + // If failed to return, or json didn't parse: + request.log.error({ error }, `The subservice URL ${url} failed`); + return null; } }) ); - } - } finally { - // No matter whether we throw or not, let request continue: - next(); + // eslint-disable-next-line @typescript-eslint/ban-types + return Object.assign(payload as object, ...rest) as unknown; + }); + + // Include well_known_handler AFTER the subservices check so that + // express does the check prior to the well-known handler responding. + await fastify.register(wkj.plugin, wellKnownOptions); } -}); + // { prefix: '/.well-known' } +); -// Include well_known_handler AFTER the subservices check so that -// express does the check prior to the well-known handler responding. -app.use(wellKnownHandler); +const stats = nstats(); +const plugin = stats.fastify(); +plugin[Symbol.for('plugin-meta')].fastify = '>=3.0.0'; +await fastify.register(plugin); -// -------------------------------------------------- -// Default handler for top-level routes not found: -app.use((request) => { - throw new OADAError(`Route not found: ${request.url}`, Codes.NotFound); +const port = config.get('wellKnown.server.port'); +await fastify.listen({ + port, + host: '::', }); -// --------------------------------------------------- -// Use OADA middleware to catch errors and respond -app.use(middleware(log.error)); - -app.set('port', config.get('wellKnown.server.port')); - -// --------------------------------------------------- -// In oada/server, the proxy provides the https for us, -// but this service could also have its own certs and run https -if (config.get('wellKnown.server.mode') === 'https') { - const s = https.createServer( - config.get('wellKnown.server.certs') as ServerOptions, - app - ); - s.listen(app.get('port'), () => { - log.info( - 'OADA Well-Known service started on port %d [https]', - app.get('port') - ); - }); - - // ------------------------------------------------------- - // Otherwise, just plain-old HTTP server -} else { - app.listen(app.get('port'), () => { - log.info('OADA well-known server started on port %d', app.get('port')); - }); -} +fastify.log.info('OADA well-known server started on port %d', port); diff --git a/oada/services/well-known/src/types.d.ts b/oada/services/well-known/src/types.d.ts new file mode 100644 index 00000000..97b757e6 --- /dev/null +++ b/oada/services/well-known/src/types.d.ts @@ -0,0 +1,31 @@ +/** + * Copyright 2022 Open Ag Data Alliance + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +declare module 'nstats' { + import type { Server as HTTPServer } from 'node:http'; + + import type { Plugin } from 'fastify-plugin'; + import type { Server as WSServer } from 'ws'; + + export interface NStats { + fastify(): Plugin; + toPrometheus(): string; + } + + function nstats(ws?: WSServer, http?: HTTPServer, semver?: string): NStats; + + export = nstats; +} diff --git a/oada/yarn.lock b/oada/yarn.lock index ce5e9ef6..cf9d341b 100644 --- a/oada/yarn.lock +++ b/oada/yarn.lock @@ -1059,24 +1059,39 @@ __metadata: languageName: node linkType: hard +"@oada/well-known-json@npm:^4.0.0": + version: 4.0.0 + resolution: "@oada/well-known-json@npm:4.0.0" + dependencies: + "@fastify/cors": ^8.0.0 + allow-methods: ^4.1.1 + cors: ^2.8.5 + fastify-plugin: ^4.0.0 + object-assign: ^4.1.1 + tslib: ^2.4.0 + urijs: ^1.19.11 + checksum: f020a4822cae9448411a7cb09215b7b990383531c0faed88b9cd8c28b89263142542bd03983f1e8630c107e40a6efbc790a379def9c12a040e40860b058ddd9c + languageName: node + linkType: hard + "@oada/well-known@workspace:services/well-known": version: 0.0.0-use.local resolution: "@oada/well-known@workspace:services/well-known" dependencies: - "@oada/error": ^2.0.1 + "@fastify/accepts": ^4.0.0 + "@fastify/cors": ^8.0.0 + "@fastify/helmet": ^9.1.0 "@oada/formats-server": ^3.1.1 "@oada/lib-config": ^3.5.1 "@oada/lib-prom": "workspace:^" "@oada/pino-debug": ^3.5.1 - "@oada/well-known-json": ^2.0.1 + "@oada/well-known-json": ^4.0.0 "@types/cors": ^2.8.12 "@types/debug": ^4.1.7 - "@types/express": ^4.17.13 - axios: ^0.27.2 - cors: ^2.8.5 debug: ^4.3.4 - express: ^4.18.1 - helmet: ^5.1.1 + fastify: ^4.3.0 + fastify-plugin: ^4.0.0 + got: ^12.3.0 tslib: ^2.4.0 languageName: unknown linkType: soft @@ -1114,6 +1129,13 @@ __metadata: languageName: node linkType: hard +"@sindresorhus/is@npm:^5.2.0": + version: 5.3.0 + resolution: "@sindresorhus/is@npm:5.3.0" + checksum: b31cebabcdece3d5322de2a4dbc8c0f004e04147a00f2606787bcaf5655ad4b1954f6727fc6914c524009b2b9a2cc01c42835b55f651ce69fd2a0083b60bb852 + languageName: node + linkType: hard + "@szmarczak/http-timer@npm:^4.0.5": version: 4.0.6 resolution: "@szmarczak/http-timer@npm:4.0.6" @@ -1123,6 +1145,15 @@ __metadata: languageName: node linkType: hard +"@szmarczak/http-timer@npm:^5.0.1": + version: 5.0.1 + resolution: "@szmarczak/http-timer@npm:5.0.1" + dependencies: + defer-to-connect: ^2.0.1 + checksum: fc9cb993e808806692e4a3337c90ece0ec00c89f4b67e3652a356b89730da98bc824273a6d67ca84d5f33cd85f317dcd5ce39d8cc0a2f060145a608a7cb8ce92 + languageName: node + linkType: hard + "@tokenizer/token@npm:^0.3.0": version: 0.3.0 resolution: "@tokenizer/token@npm:0.3.0" @@ -1214,7 +1245,7 @@ __metadata: languageName: node linkType: hard -"@types/cacheable-request@npm:^6.0.1": +"@types/cacheable-request@npm:^6.0.1, @types/cacheable-request@npm:^6.0.2": version: 6.0.2 resolution: "@types/cacheable-request@npm:6.0.2" dependencies: @@ -2119,6 +2150,15 @@ __metadata: languageName: node linkType: hard +"allow-methods@npm:^4.1.1": + version: 4.1.1 + resolution: "allow-methods@npm:4.1.1" + dependencies: + http-errors: ^2.0.0 + checksum: 912b5ddc700cdf5dae302ff04945fac837880a5eda8268beffcf8d8318b46af79d8cdd73a10a65276c3b50a9eb67b8987502fe2da14767f8467ce7169cc2f685 + languageName: node + linkType: hard + "already@npm:^2.2.1": version: 2.2.1 resolution: "already@npm:2.2.1" @@ -2761,6 +2801,13 @@ __metadata: languageName: node linkType: hard +"cacheable-lookup@npm:^6.0.4": + version: 6.0.4 + resolution: "cacheable-lookup@npm:6.0.4" + checksum: 7aea70f5ea081aed12bf54fc165b9f80b580b0d210c85d55cc8fed2beaa9027fd321c1939c65dad945fe9eb207cea45442e01a48b5aa57542e125b716f022b6d + languageName: node + linkType: hard + "cacheable-request@npm:^7.0.2": version: 7.0.2 resolution: "cacheable-request@npm:7.0.2" @@ -3559,7 +3606,7 @@ __metadata: languageName: node linkType: hard -"defer-to-connect@npm:^2.0.0": +"defer-to-connect@npm:^2.0.0, defer-to-connect@npm:^2.0.1": version: 2.0.1 resolution: "defer-to-connect@npm:2.0.1" checksum: 8a9b50d2f25446c0bfefb55a48e90afd58f85b21bcf78e9207cd7b804354f6409032a1705c2491686e202e64fc05f147aa5aa45f9aa82627563f045937f5791b @@ -4791,7 +4838,7 @@ __metadata: languageName: node linkType: hard -"fastify@npm:4.3.0": +"fastify@npm:4.3.0, fastify@npm:^4.3.0": version: 4.3.0 resolution: "fastify@npm:4.3.0" dependencies: @@ -5050,6 +5097,13 @@ __metadata: languageName: node linkType: hard +"form-data-encoder@npm:^2.0.1": + version: 2.0.1 + resolution: "form-data-encoder@npm:2.0.1" + checksum: 66a8dd84d7fcbab5fdaec9382f29e26a12b625d491ddfd267c7c7b0bf5b41b142c51826d4b89155fa975c09ea32b67000b6d01074410d57d6a7adee7405754c0 + languageName: node + linkType: hard + "form-data@npm:^4.0.0": version: 4.0.0 resolution: "form-data@npm:4.0.0" @@ -5361,6 +5415,27 @@ __metadata: languageName: node linkType: hard +"got@npm:^12.3.0": + version: 12.3.0 + resolution: "got@npm:12.3.0" + dependencies: + "@sindresorhus/is": ^5.2.0 + "@szmarczak/http-timer": ^5.0.1 + "@types/cacheable-request": ^6.0.2 + "@types/responselike": ^1.0.0 + cacheable-lookup: ^6.0.4 + cacheable-request: ^7.0.2 + decompress-response: ^6.0.0 + form-data-encoder: ^2.0.1 + get-stream: ^6.0.1 + http2-wrapper: ^2.1.10 + lowercase-keys: ^3.0.0 + p-cancelable: ^3.0.0 + responselike: ^2.0.0 + checksum: 3f2ec7a17d7fdd259a668888eb5ee6e6b7794ec466f1a7d3170697306e4838350515495c60879a3b4d6b228d2a42749fd43941bd876748671b9c04e37a7e34b5 + languageName: node + linkType: hard + "graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6": version: 4.2.10 resolution: "graceful-fs@npm:4.2.10" @@ -5539,6 +5614,16 @@ __metadata: languageName: node linkType: hard +"http2-wrapper@npm:^2.1.10": + version: 2.1.11 + resolution: "http2-wrapper@npm:2.1.11" + dependencies: + quick-lru: ^5.1.1 + resolve-alpn: ^1.2.0 + checksum: 5da05aa2c77226ac9cc82c616383f59c8f31b79897b02ecbe44b09714be1fca1f21bb184e672a669ca2830eefea4edac5f07e71c00cb5a8c5afec8e5a20cfaf7 + languageName: node + linkType: hard + "https-proxy-agent@npm:^5.0.0": version: 5.0.1 resolution: "https-proxy-agent@npm:5.0.1" @@ -6579,6 +6664,13 @@ __metadata: languageName: node linkType: hard +"lowercase-keys@npm:^3.0.0": + version: 3.0.0 + resolution: "lowercase-keys@npm:3.0.0" + checksum: 67a3f81409af969bc0c4ca0e76cd7d16adb1e25aa1c197229587eaf8671275c8c067cd421795dbca4c81be0098e4c426a086a05e30de8a9c587b7a13c0c7ccc5 + languageName: node + linkType: hard + "lru-cache@npm:^6.0.0": version: 6.0.0 resolution: "lru-cache@npm:6.0.0" @@ -7470,6 +7562,13 @@ __metadata: languageName: node linkType: hard +"p-cancelable@npm:^3.0.0": + version: 3.0.0 + resolution: "p-cancelable@npm:3.0.0" + checksum: 2b5ae34218f9c2cf7a7c18e5d9a726ef9b165ef07e6c959f6738371509e747334b5f78f3bcdeb03d8a12dcb978faf641fd87eb21486ed7d36fb823b8ddef3219 + languageName: node + linkType: hard + "p-defer@npm:^1.0.0": version: 1.0.0 resolution: "p-defer@npm:1.0.0" @@ -8393,7 +8492,7 @@ __metadata: languageName: node linkType: hard -"resolve-alpn@npm:^1.0.0, resolve-alpn@npm:^1.2.1": +"resolve-alpn@npm:^1.0.0, resolve-alpn@npm:^1.2.0, resolve-alpn@npm:^1.2.1": version: 1.2.1 resolution: "resolve-alpn@npm:1.2.1" checksum: f558071fcb2c60b04054c99aebd572a2af97ef64128d59bef7ab73bd50d896a222a056de40ffc545b633d99b304c259ea9d0c06830d5c867c34f0bfa60b8eae0