diff --git a/src/api/functions/linkry.ts b/src/api/functions/linkry.ts index 67e0e604..a368258e 100644 --- a/src/api/functions/linkry.ts +++ b/src/api/functions/linkry.ts @@ -5,7 +5,7 @@ import { } from "@aws-sdk/client-dynamodb"; import { unmarshall } from "@aws-sdk/util-dynamodb"; import { LinkryGroupUUIDToGroupNameMap } from "common/config.js"; -import { LinkRecord } from "common/types/linkry.js"; +import { LinkRecord, OrgLinkRecord } from "common/types/linkry.js"; import { FastifyRequest } from "fastify"; export async function fetchLinkEntry( @@ -72,6 +72,40 @@ export async function fetchOwnerRecords( }); } +export async function fetchOrgRecords( + orgId: string, + tableName: string, + dynamoClient: DynamoDBClient, +) { + const fetchAllOwnerRecords = new QueryCommand({ + TableName: tableName, + IndexName: "AccessIndex", + KeyConditionExpression: "#access = :accessVal", + ExpressionAttributeNames: { + "#access": "access", + }, + ExpressionAttributeValues: { + ":accessVal": { S: `OWNER#${orgId}` }, + }, + ScanIndexForward: false, + }); + + const result = await dynamoClient.send(fetchAllOwnerRecords); + + // Process the results + return (result.Items || []).map((item) => { + const unmarshalledItem = unmarshall(item); + + // Strip '#' from access field + if (unmarshalledItem.access) { + unmarshalledItem.access = + unmarshalledItem.access.split("#")[1] || unmarshalledItem.access; + } + + return unmarshalledItem as OrgLinkRecord; + }); +} + export function extractUniqueSlugs(records: LinkRecord[]) { return Array.from( new Set(records.filter((item) => item.slug).map((item) => item.slug)), diff --git a/src/api/routes/linkry.ts b/src/api/routes/linkry.ts index cd1829f6..8161183e 100644 --- a/src/api/routes/linkry.ts +++ b/src/api/routes/linkry.ts @@ -15,11 +15,19 @@ import { TransactWriteItemsCommand, TransactWriteItem, TransactionCanceledException, + PutItemCommand, + PutItemCommandInput, + ConditionalCheckFailedException, } from "@aws-sdk/client-dynamodb"; import { genericConfig } from "../../common/config.js"; import { marshall, unmarshall } from "@aws-sdk/util-dynamodb"; import rateLimiter from "api/plugins/rateLimiter.js"; -import { createRequest, linkrySlug } from "common/types/linkry.js"; +import { + createOrgLinkRequest, + createRequest, + linkrySlug, + orgLinkRecord, +} from "common/types/linkry.js"; import { extractUniqueSlugs, fetchOwnerRecords, @@ -28,12 +36,18 @@ import { getDelegatedLinks, fetchLinkEntry, getAllLinks, + fetchOrgRecords, } from "api/functions/linkry.js"; import { intersection } from "api/plugins/auth.js"; -import { createAuditLogEntry } from "api/functions/auditLog.js"; +import { + buildAuditLogTransactPut, + createAuditLogEntry, +} from "api/functions/auditLog.js"; import { Modules } from "common/modules.js"; import { FastifyZodOpenApiTypeProvider } from "fastify-zod-openapi"; import { withRoles, withTags } from "api/components/index.js"; +import { AllOrganizationNameList, Organizations } from "@acm-uiuc/js-shared"; +import { authorizeByOrgRoleOrSchema } from "api/functions/authorization.js"; type OwnerRecord = { slug: string; @@ -43,6 +57,15 @@ type OwnerRecord = { createdAt: string; }; +type OrgRecord = { + slug: string; + redirect: string; + access: string; + updatedAt: string; + createdAt: string; + lastModifiedBy: string; +}; + type AccessRecord = { slug: string; access: string; @@ -587,6 +610,279 @@ const linkryRoutes: FastifyPluginAsync = async (fastify, _options) => { reply.code(204).send(); }, ); + + fastify.withTypeProvider().post( + "/orgs/:orgId/redir", + { + schema: withRoles( + [AppRoles.AT_LEAST_ONE_ORG_MANAGER, AppRoles.LINKS_ADMIN], + withTags(["Linkry"], { + body: createOrgLinkRequest, + params: z.object({ + orgId: z.enum(Object.keys(Organizations)).meta({ + description: "ACM @ UIUC unique organization ID.", + examples: ["A01"], + }), + }), + summary: "Create a short link for a specific org", + response: { + 201: { + description: "The short link was modified.", + content: { + "application/json": { + schema: z.null(), + }, + }, + }, + }, + }), + ), + preValidation: async (request, reply) => { + const routeAlreadyExists = fastify.hasRoute({ + url: `/${request.params.orgId}#${request.body.slug}`, + method: "GET", + }); + + if (routeAlreadyExists) { + throw new ValidationError({ + message: `Slug ${request.params.orgId}#${request.body.slug} is reserved by the system.`, + }); + } + }, + onRequest: async (request, reply) => { + await authorizeByOrgRoleOrSchema(fastify, request, reply, { + validRoles: [ + { org: Organizations[request.params.orgId].name, role: "LEAD" }, + ], + }); + }, + }, + async (request, reply) => { + const { slug, redirect } = request.body; + const tableName = genericConfig.LinkryDynamoTableName; + const realSlug = `${request.params.orgId}#${slug}`; + const currentRecord = await fetchLinkEntry( + realSlug, + tableName, + fastify.dynamoClient, + ); + + try { + const mode = currentRecord ? "modify" : "create"; + request.log.info(`Operating in ${mode} mode.`); + const currentUpdatedAt = + currentRecord && currentRecord.updatedAt + ? currentRecord.updatedAt + : null; + const currentCreatedAt = + currentRecord && currentRecord.createdAt + ? currentRecord.createdAt + : null; + + const creationTime: Date = new Date(); + const newUpdatedAt = creationTime.toISOString(); + const newCreatedAt = currentCreatedAt || newUpdatedAt; + + const ownerRecord: OrgRecord = { + slug: realSlug, + redirect, + access: `OWNER#${request.params.orgId}`, // org records are owned by the org + updatedAt: newUpdatedAt, + createdAt: newCreatedAt, + lastModifiedBy: request.username!, + }; + + // Add the OWNER record with a condition check to ensure it hasn't been modified + const ownerPutParams: PutItemCommandInput = { + TableName: genericConfig.LinkryDynamoTableName, + Item: marshall(ownerRecord, { removeUndefinedValues: true }), + ...(mode === "modify" + ? { + ConditionExpression: "updatedAt = :updatedAt", + ExpressionAttributeValues: marshall({ + ":updatedAt": currentUpdatedAt, + }), + } + : {}), + }; + + await fastify.dynamoClient.send(new PutItemCommand(ownerPutParams)); + } catch (e) { + fastify.log.error(e); + if (e instanceof ConditionalCheckFailedException) { + throw new ValidationError({ + message: + "The record was modified by another process. Please try again.", + }); + } + + if (e instanceof BaseError) { + throw e; + } + + throw new DatabaseInsertError({ + message: "Failed to save data to DynamoDB.", + }); + } + await createAuditLogEntry({ + dynamoClient: fastify.dynamoClient, + entry: { + module: Modules.LINKRY, + actor: request.username!, + target: `${Organizations[request.params.orgId].name}/${request.body.slug}`, + message: `Created redirect to "${request.body.redirect}"`, + }, + }); + const newResourceUrl = `${request.url}/slug/${request.body.slug}`; + return reply.status(201).headers({ location: newResourceUrl }).send(); + }, + ); + fastify.withTypeProvider().get( + "/orgs/:orgId/redir", + { + schema: withRoles( + [AppRoles.AT_LEAST_ONE_ORG_MANAGER, AppRoles.LINKS_ADMIN], + withTags(["Linkry"], { + params: z.object({ + orgId: z.enum(Object.keys(Organizations)).meta({ + description: "ACM @ UIUC organization ID.", + examples: ["A01"], + }), + }), + summary: "Retrieve short link for a specific org", + response: { + 200: { + description: "The short links were retrieved.", + content: { + "application/json": { + schema: z.array(orgLinkRecord), + }, + }, + }, + }, + }), + ), + onRequest: async (request, reply) => { + await authorizeByOrgRoleOrSchema(fastify, request, reply, { + validRoles: [ + { org: Organizations[request.params.orgId].name, role: "LEAD" }, + ], + }); + }, + }, + async (request, reply) => { + let orgRecords; + try { + orgRecords = await fetchOrgRecords( + request.params.orgId, + genericConfig.LinkryDynamoTableName, + fastify.dynamoClient, + ); + } catch (e) { + if (e instanceof BaseError) { + throw e; + } + request.log.error(e); + throw new DatabaseFetchError({ + message: "Failed to get links for org.", + }); + } + return reply.status(200).send(orgRecords); + }, + ); + fastify.withTypeProvider().delete( + "/orgs/:orgId/redir/:slug", + { + schema: withRoles( + [AppRoles.AT_LEAST_ONE_ORG_MANAGER, AppRoles.LINKS_ADMIN], + withTags(["Linkry"], { + params: z.object({ + orgId: z.enum(Object.keys(Organizations)).meta({ + description: "ACM @ UIUC organization ID.", + examples: ["A01"], + }), + slug: linkrySlug, + }), + summary: "Delete a short link for a specific org", + response: { + 204: { + description: "The short links was deleted.", + content: { + "application/json": { + schema: z.null(), + }, + }, + }, + }, + }), + ), + onRequest: async (request, reply) => { + await authorizeByOrgRoleOrSchema(fastify, request, reply, { + validRoles: [ + { org: Organizations[request.params.orgId].name, role: "LEAD" }, + ], + }); + }, + }, + async (request, reply) => { + const realSlug = `${request.params.orgId}#${request.params.slug}`; + try { + const tableName = genericConfig.LinkryDynamoTableName; + const currentRecord = await fetchLinkEntry( + realSlug, + tableName, + fastify.dynamoClient, + ); + if (!currentRecord) { + throw new NotFoundError({ endpointName: request.url }); + } + } catch (e) { + if (e instanceof BaseError) { + throw e; + } + request.log.error(e); + throw new DatabaseFetchError({ + message: "Failed to get link.", + }); + } + const logStatement = buildAuditLogTransactPut({ + entry: { + module: Modules.LINKRY, + actor: request.username!, + target: `${Organizations[request.params.orgId].name}/${request.params.slug}`, + message: `Deleted short link redirect.`, + }, + }); + const TransactItems: TransactWriteItem[] = [ + ...(logStatement ? [logStatement] : []), + { + Delete: { + TableName: genericConfig.LinkryDynamoTableName, + Key: { + slug: { S: realSlug }, + access: { S: `OWNER#${request.params.orgId}` }, + }, + }, + }, + ]; + + try { + await fastify.dynamoClient.send( + new TransactWriteItemsCommand({ TransactItems }), + ); + } catch (e) { + fastify.log.error(e); + if (e instanceof BaseError) { + throw e; + } + + throw new DatabaseDeleteError({ + message: "Failed to delete data from DynamoDB.", + }); + } + return reply.status(204).send(); + }, + ); }; fastify.register(limitedRoutes); }; diff --git a/src/common/types/linkry.ts b/src/common/types/linkry.ts index 5d8c448b..38bcb98c 100644 --- a/src/common/types/linkry.ts +++ b/src/common/types/linkry.ts @@ -23,21 +23,31 @@ export const createRequest = z.object({ slug: linkrySlug.refine((url) => !url.includes('#'), { message: "Slug must not contain a hashtag" }), - orgId: z.optional(OrgUniqueId), access: linkryAccessList, redirect: z.url().min(1).meta({ description: "Full URL to redirect to when the short URL is visited.", example: "https://google.com" }) }); +export const createOrgLinkRequest = createRequest.omit({ access: true }); + export const linkRecord = z.object({ access: linkryAccessList, slug: linkrySlug, createdAt: z.iso.datetime(), updatedAt: z.iso.datetime(), redirect: z.url(), - owner: z.string().min(1) + owner: z.string().min(1), +}); + +export const orgLinkRecord = z.object({ + slug: linkrySlug, + lastModifiedBy: z.string().min(1), + createdAt: z.iso.datetime(), + updatedAt: z.iso.datetime(), + redirect: z.url(), }); export type LinkRecord = z.infer; +export type OrgLinkRecord = z.infer; export const getLinksResponse = z.object({ ownedLinks: z.array(linkRecord), diff --git a/src/linkryEdgeFunction/index.ts b/src/linkryEdgeFunction/index.ts index 72ce5ad9..9cc4fc33 100644 --- a/src/linkryEdgeFunction/index.ts +++ b/src/linkryEdgeFunction/index.ts @@ -1,3 +1,4 @@ +import { Organizations } from "@acm-uiuc/js-shared"; import { DynamoDBClient, QueryCommand, @@ -14,6 +15,38 @@ const DYNAMODB_TABLE = "infra-core-api-linkry"; const FALLBACK_URL = process.env.FALLBACK_URL || "https://acm.illinois.edu/404"; const DEFAULT_URL = process.env.DEFAULT_URL || "https://www.acm.illinois.edu"; const CACHE_TTL = "30"; // seconds to hold response in PoP +const BASE_DOMAINS = [".acm.illinois.edu", ".aws.qa.acmuiuc.org", ".acm.gg"]; + +const entries = Object.entries(Organizations); +const shortToOrgCodeMapper: Record = {}; +for (const item of entries) { + shortToOrgCodeMapper[item[1].shortcode] = item[0]; +} + +function getSlugToQuery(path: string, host: string): string { + let cleanedHost = host.toLowerCase(); + + for (const domain of BASE_DOMAINS) { + if (cleanedHost.endsWith(domain)) { + cleanedHost = cleanedHost.substring( + 0, + cleanedHost.length - domain.length, + ); + break; + } + } + + const hostParts = cleanedHost.split("."); + + if (hostParts.length > 1 && host !== "acm") { + const short = hostParts[0]; + if (shortToOrgCodeMapper[short]) { + return `${shortToOrgCodeMapper[short]}#${path}`; + } + } + + return path; +} /** * Determine which DynamoDB replica to use based on Lambda execution region @@ -50,8 +83,9 @@ export const handler = async ( ): Promise => { const request = event.Records[0].cf.request; const path = request.uri.replace(/^\/+/, ""); - - console.log(`Processing path: ${path}`); + const host = request.headers.host?.[0]?.value || ""; + const slugToQuery = getSlugToQuery(path, host); + console.log(`Host: ${host}, Path: ${path}, Querying Slug: ${slugToQuery}`); if (!path) { return { @@ -73,7 +107,7 @@ export const handler = async ( KeyConditionExpression: "slug = :slug AND begins_with(access, :owner_prefix)", ExpressionAttributeValues: { - ":slug": { S: path }, + ":slug": { S: slugToQuery }, ":owner_prefix": { S: "OWNER#" }, }, ProjectionExpression: "redirect", diff --git a/src/linkryEdgeFunction/package.json b/src/linkryEdgeFunction/package.json index 23ca956e..2fffdc2c 100644 --- a/src/linkryEdgeFunction/package.json +++ b/src/linkryEdgeFunction/package.json @@ -15,10 +15,11 @@ "devDependencies": { "@types/aws-lambda": "^8.10.138", "@types/node": "^24.3.0", - "typescript": "^5.9.2", - "esbuild": "^0.25.12" + "esbuild": "^0.25.12", + "typescript": "^5.9.2" }, "dependencies": { + "@acm-uiuc/js-shared": "^3.2.1", "@aws-sdk/client-dynamodb": "^3.922.0" } -} \ No newline at end of file +} diff --git a/terraform/envs/prod/variables.tf b/terraform/envs/prod/variables.tf index 772402b3..7c1a28fe 100644 --- a/terraform/envs/prod/variables.tf +++ b/terraform/envs/prod/variables.tf @@ -27,7 +27,7 @@ variable "CoreCertificateArn" { // For acm.gg we need a seperate cert for Linkry variable "LinkryCertificateArn" { type = string - default = "arn:aws:acm:us-east-1:298118738376:certificate/aa58a5e8-49eb-44fb-b118-ab0a7ecd2054" + default = "arn:aws:acm:us-east-1:298118738376:certificate/2b6a2570-53a5-42c6-ba73-3822e6b9691d" } variable "EmailDomain" { diff --git a/terraform/envs/qa/main.tf b/terraform/envs/qa/main.tf index 1dcad1a7..cd9e81fc 100644 --- a/terraform/envs/qa/main.tf +++ b/terraform/envs/qa/main.tf @@ -207,6 +207,19 @@ resource "aws_route53_record" "linkry" { evaluate_target_health = false } } + +resource "aws_route53_record" "linkry_wildcard" { + for_each = toset(["A", "AAAA"]) + zone_id = "Z04502822NVIA85WM2SML" + type = each.key + name = "*.${var.LinkryPublicDomain}" + alias { + name = module.frontend.linkry_cloudfront_domain_name + zone_id = "Z2FDTNDATAQYW2" + evaluate_target_health = false + } +} + resource "aws_lambda_event_source_mapping" "queue_consumer" { region = "us-east-2" depends_on = [module.lambdas, module.sqs_queues] diff --git a/terraform/envs/qa/variables.tf b/terraform/envs/qa/variables.tf index f5a3fddf..c846844b 100644 --- a/terraform/envs/qa/variables.tf +++ b/terraform/envs/qa/variables.tf @@ -16,7 +16,7 @@ variable "CoreCertificateArn" { variable "LinkryCertificateArn" { type = string - default = "arn:aws:acm:us-east-1:427040638965:certificate/63ccdf0b-d2b5-44f0-b589-eceffb935c23" + default = "arn:aws:acm:us-east-1:427040638965:certificate/1aecf0c6-a204-440f-ad0b-fc9157ad93a9" } variable "CorePublicDomain" { diff --git a/terraform/modules/frontend/main.tf b/terraform/modules/frontend/main.tf index ab8e6e52..37c64d3a 100644 --- a/terraform/modules/frontend/main.tf +++ b/terraform/modules/frontend/main.tf @@ -486,7 +486,10 @@ resource "aws_cloudfront_distribution" "linkry_cloudfront_distribution" { origin_ssl_protocols = ["TLSv1", "TLSv1.1", "TLSv1.2"] } } - aliases = var.LinkryPublicDomains + aliases = concat( + tolist(var.LinkryPublicDomains), + [for domain in var.LinkryPublicDomains : "*.${domain}"] + ) enabled = true is_ipv6_enabled = true default_cache_behavior { diff --git a/tests/live/linrky.test.ts b/tests/live/linkry.test.ts similarity index 69% rename from tests/live/linrky.test.ts rename to tests/live/linkry.test.ts index c51cb68d..90aff0db 100644 --- a/tests/live/linrky.test.ts +++ b/tests/live/linkry.test.ts @@ -2,6 +2,7 @@ import { describe, expect, test } from "vitest"; import { getBaseEndpoint, makeRandomString } from "./utils.js"; const baseEndpoint = getBaseEndpoint("go"); +const baseEndpointInfra = getBaseEndpoint("infra.go"); describe("Linkry live tests", async () => { test("Linkry health check", async () => { @@ -10,6 +11,12 @@ describe("Linkry live tests", async () => { expect(response.redirected).toBe(true); expect(response.url).toBe("https://www.google.com/"); }); + test("Org-scoped linkry health check", async () => { + const response = await fetch(`${baseEndpointInfra}/healthz`); + expect(response.status).toBe(200); + expect(response.redirected).toBe(true); + expect(response.url).toBe("https://www.google.com/"); + }); test("Linkry 404 redirect", async () => { const response = await fetch(`${baseEndpoint}/${makeRandomString(16)}`); expect(response.status).toBe(200); diff --git a/tests/live/tickets.test.ts b/tests/live/tickets.test.ts index 06fb0f7b..c0795b79 100644 --- a/tests/live/tickets.test.ts +++ b/tests/live/tickets.test.ts @@ -30,25 +30,26 @@ describe("Tickets live API tests", async () => { expect(Array.isArray(responseBody["merch"])).toBe(true); expect(Array.isArray(responseBody["tickets"])).toBe(true); }); - test( - "Test that getting user purchases succeeds", - { timeout: 10000 }, - async () => { - const response = await fetch( - `${baseEndpoint}/api/v1/tickets/purchases/acm@illinois.edu`, - { - method: "GET", - headers: { - Authorization: `Bearer ${token}`, - }, - }, - ); - expect(response.status).toBe(200); - const responseBody = await response.json(); - expect(responseBody).toHaveProperty("merch"); - expect(responseBody).toHaveProperty("tickets"); - expect(Array.isArray(responseBody["merch"])).toBe(true); - expect(Array.isArray(responseBody["tickets"])).toBe(true); - }, - ); + // TODO: write this test for the new UIN-based lookup + // test( + // "Test that getting user purchases succeeds", + // { timeout: 10000 }, + // async () => { + // const response = await fetch( + // `${baseEndpoint}/api/v1/tickets/purchases/acm@illinois.edu`, + // { + // method: "GET", + // headers: { + // Authorization: `Bearer ${token}`, + // }, + // }, + // ); + // expect(response.status).toBe(200); + // const responseBody = await response.json(); + // expect(responseBody).toHaveProperty("merch"); + // expect(responseBody).toHaveProperty("tickets"); + // expect(Array.isArray(responseBody["merch"])).toBe(true); + // expect(Array.isArray(responseBody["tickets"])).toBe(true); + // }, + // ); }); diff --git a/tests/live/utils.ts b/tests/live/utils.ts index 4e50c762..9a3688b6 100644 --- a/tests/live/utils.ts +++ b/tests/live/utils.ts @@ -72,7 +72,7 @@ export async function createJwt( return token; } -type Service = "core" | "go" | "ical"; +type Service = "core" | "go" | "ical" | "infra.go"; export function getBaseEndpoint(service?: Service) { const base = process.env.CORE_BASE_URL ?? "https://core.aws.qa.acmuiuc.org"; diff --git a/yarn.lock b/yarn.lock index 39f4a1e6..b572b07a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1989,7 +1989,7 @@ resolved "https://registry.yarnpkg.com/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.81.tgz#e76784880f26d48f4863d73c9891c53f161ffe6e" integrity sha512-57ryVbhm/z7RE9/UVcS7mrLPdlayLesy+9U0Uf6epCoeSGrs99tfieCcgZWFbIgmByQ1AZnNtFI2N6huqDLlWQ== -"@napi-rs/canvas@^0.1.65": +"@napi-rs/canvas@^0.1.65", "@napi-rs/canvas@^0.1.80", "@napi-rs/canvas@^0.1.81": version "0.1.81" resolved "https://registry.yarnpkg.com/@napi-rs/canvas/-/canvas-0.1.81.tgz#4cb1556171a64480e52d2a3766aa5413bfc4a9b1" integrity sha512-ReCjd5SYI/UKx/olaQLC4GtN6wUQGjlgHXs1lvUvWGXfBMR3Fxnik3cL+OxKN5ithNdoU0/GlCrdKcQDFh2XKQ== @@ -4575,7 +4575,7 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== -bl@^4.0.2: +bl@^4.0.2, bl@^4.0.3: version "4.1.0" resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== @@ -4716,6 +4716,14 @@ caniuse-lite@^1.0.30001726: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001726.tgz#a15bd87d5a4bf01f6b6f70ae7c97fdfd28b5ae47" integrity sha512-VQAUIUzBiZ/UnlM28fSp2CRF3ivUn1BWEvxMcVTNwpw91Py1pGbPIyIKtd+tzct9C3ouceCVdGAXxZOpZAsgdw== +canvas@^3.0.0-rc2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/canvas/-/canvas-3.2.0.tgz#877c51aabdb99cbb5b2b378138a6cdd681e9d390" + integrity sha512-jk0GxrLtUEmW/TmFsk2WghvgHe8B0pxGilqCL21y8lHkPUGa6FTsnCNtHPOzT8O3y+N+m3espawV80bbBlgfTA== + dependencies: + node-addon-api "^7.0.0" + prebuild-install "^7.1.3" + chai@^5.1.1, chai@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/chai/-/chai-5.2.0.tgz#1358ee106763624114addf84ab02697e411c9c05" @@ -4777,6 +4785,11 @@ chokidar@^3.5.2, chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + cli-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" @@ -5094,6 +5107,13 @@ decimal.js@^10.5.0: resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.5.0.tgz#0f371c7cf6c4898ce0afb09836db73cd82010f22" integrity sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw== +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" + deep-eql@^5.0.1: version "5.0.2" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341" @@ -5123,6 +5143,11 @@ deep-equal@^2.0.5: which-collection "^1.0.1" which-typed-array "^1.1.13" +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + deep-is@^0.1.3, deep-is@~0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" @@ -5176,6 +5201,11 @@ dequal@^2.0.2, dequal@^2.0.3: resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== +detect-libc@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.1.2.tgz#689c5dcdc1900ef5583a4cb9f6d7b473742074ad" + integrity sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ== + detect-node-es@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" @@ -5997,6 +6027,11 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +expand-template@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" + integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== + expect-type@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/expect-type/-/expect-type-1.2.1.tgz#af76d8b357cf5fa76c41c09dafb79c549e75f71f" @@ -6338,6 +6373,11 @@ formidable@^3.5.4: dezalgo "^1.0.4" once "^1.4.0" +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + fs-extra@^10.0.1: version "10.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" @@ -6444,6 +6484,11 @@ get-tsconfig@^4.10.1, get-tsconfig@^4.7.5: dependencies: resolve-pkg-maps "^1.0.0" +github-from-package@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" + integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw== + glob-parent@^5.0.0, glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" @@ -6796,7 +6841,7 @@ inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, i resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -ini@^1.3.5: +ini@^1.3.5, ini@~1.3.0: version "1.3.8" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== @@ -7776,6 +7821,11 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== + min-indent@^1.0.0, min-indent@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" @@ -7802,7 +7852,7 @@ minimatch@^9.0.4: dependencies: brace-expansion "^2.0.1" -minimist@^1.1.0, minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: +minimist@^1.1.0, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -7812,6 +7862,11 @@ minimist@^1.1.0, minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== +mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== + mkdirp@^0.5.1: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" @@ -7897,6 +7952,11 @@ nanoid@^3.3.11: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== +napi-build-utils@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-2.0.0.tgz#13c22c0187fcfccce1461844136372a47ddc027e" + integrity sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA== + napi-postinstall@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/napi-postinstall/-/napi-postinstall-0.3.0.tgz#888e51d1fb500e86dcf6ace1baccdbb377e654ce" @@ -7928,6 +7988,18 @@ nise@^6.0.0: just-extend "^6.2.0" path-to-regexp "^8.1.0" +node-abi@^3.3.0: + version "3.80.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.80.0.tgz#d7390951f27caa129cceeec01e1c20fc9f07581c" + integrity sha512-LyPuZJcI9HVwzXK1GPxWNzrr+vr8Hp/3UqlmWxxh8p54U1ZbclOqbSog9lWHaCX+dBaiGi6n/hIX+mKu74GmPA== + dependencies: + semver "^7.3.5" + +node-addon-api@^7.0.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558" + integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ== + node-addon-api@^8.5.0: version "8.5.0" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-8.5.0.tgz#c91b2d7682fa457d2e1c388150f0dff9aafb8f3f" @@ -8313,6 +8385,11 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +path2d@^0.2.1: + version "0.2.2" + resolved "https://registry.yarnpkg.com/path2d/-/path2d-0.2.2.tgz#cc85d61ed7827e7863a2ee36713d4b5315a3d85d" + integrity sha512-+vnG6S4dYcYxZd+CZxzXCNKdELYZSKfohrk98yajCo1PtRoDgCTrrwOvK1GT0UoAdVszagDVllQc0U1vaX4NUQ== + pathe@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716" @@ -8323,13 +8400,35 @@ pathval@^2.0.0: resolved "https://registry.yarnpkg.com/pathval/-/pathval-2.0.1.tgz#8855c5a2899af072d6ac05d11e46045ad0dc605d" integrity sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ== -pdfjs-dist@4.8.69, pdfjs-dist@5.4.296, pdfjs-dist@^4.6.82, pdfjs-dist@^4.8.69, pdfjs-dist@^5.4.394: +pdfjs-dist@4.8.69: + version "4.8.69" + resolved "https://registry.yarnpkg.com/pdfjs-dist/-/pdfjs-dist-4.8.69.tgz#61ea5d66863d49b40e5eacbd4070341175bdda2e" + integrity sha512-IHZsA4T7YElCKNNXtiLgqScw4zPd3pG9do8UrznC757gMd7UPeHSL2qwNNMJo4r79fl8oj1Xx+1nh2YkzdMpLQ== + optionalDependencies: + canvas "^3.0.0-rc2" + path2d "^0.2.1" + +pdfjs-dist@5.4.296: + version "5.4.296" + resolved "https://registry.yarnpkg.com/pdfjs-dist/-/pdfjs-dist-5.4.296.tgz#b1aa7ded8828f29537bc7cc99c1343c8b3a5d2d6" + integrity sha512-DlOzet0HO7OEnmUmB6wWGJrrdvbyJKftI1bhMitK7O2N8W2gc757yyYBbINy9IDafXAV9wmKr9t7xsTaNKRG5Q== + optionalDependencies: + "@napi-rs/canvas" "^0.1.80" + +pdfjs-dist@^4.6.82: version "4.10.38" resolved "https://registry.yarnpkg.com/pdfjs-dist/-/pdfjs-dist-4.10.38.tgz#3ee698003790dc266cc8b55c0e662ccb9ae18f53" integrity sha512-/Y3fcFrXEAsMjJXeL9J8+ZG9U01LbuWaYypvDW2ycW1jL269L3js3DVBjDJ0Up9Np1uqDXsDrRihHANhZOlwdQ== optionalDependencies: "@napi-rs/canvas" "^0.1.65" +pdfjs-dist@^5.4.394: + version "5.4.394" + resolved "https://registry.yarnpkg.com/pdfjs-dist/-/pdfjs-dist-5.4.394.tgz#48697151afce097132673883a55bede103ded6e4" + integrity sha512-9ariAYGqUJzx+V/1W4jHyiyCep6IZALmDzoaTLZ6VNu8q9LWi1/ukhzHgE2Xsx96AZi0mbZuK4/ttIbqSbLypg== + optionalDependencies: + "@napi-rs/canvas" "^0.1.81" + picocolors@1.1.1, picocolors@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" @@ -8525,6 +8624,24 @@ postcss@^8.3.11, postcss@^8.5.3, postcss@^8.5.6: picocolors "^1.1.1" source-map-js "^1.2.1" +prebuild-install@^7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.3.tgz#d630abad2b147443f20a212917beae68b8092eec" + integrity sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug== + dependencies: + detect-libc "^2.0.0" + expand-template "^2.0.3" + github-from-package "0.0.0" + minimist "^1.2.3" + mkdirp-classic "^0.5.3" + napi-build-utils "^2.0.0" + node-abi "^3.3.0" + pump "^3.0.0" + rc "^1.2.7" + simple-get "^4.0.0" + tar-fs "^2.0.0" + tunnel-agent "^0.6.0" + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -8649,6 +8766,16 @@ raw-body@^3.0.0: iconv-lite "0.6.3" unpipe "1.0.0" +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + react-docgen-typescript@^2.2.2: version "2.4.0" resolved "https://registry.yarnpkg.com/react-docgen-typescript/-/react-docgen-typescript-2.4.0.tgz#033428b4a6a639d050ac8baf2a5195c596521713" @@ -9179,7 +9306,7 @@ semver@^6.1.2, semver@^6.3.0, semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.2, semver@^7.7.1: +semver@^7.3.5, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.2, semver@^7.7.1: version "7.7.3" resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946" integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q== @@ -9314,6 +9441,20 @@ signal-exit@^4.0.1: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== +simple-concat@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" + integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== + +simple-get@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-4.0.1.tgz#4a39db549287c979d352112fa03fd99fd6bc3543" + integrity sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA== + dependencies: + decompress-response "^6.0.0" + once "^1.3.1" + simple-concat "^1.0.0" + simple-update-notifier@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz#d70b92bdab7d6d90dfd73931195a30b6e3d7cebb" @@ -9649,6 +9790,11 @@ strip-json-comments@^5.0.2: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-5.0.2.tgz#14a76abd63b84a6d2419d14f26a0281d0cf6ea46" integrity sha512-4X2FR3UwhNUE9G49aIsJW5hRRR3GXGTBTZRMfv568O60ojM8HcWjV/VxAxCDW3SUND33O6ZY66ZuRcdkj73q2g== +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== + strip-literal@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-literal/-/strip-literal-3.0.0.tgz#ce9c452a91a0af2876ed1ae4e583539a353df3fc" @@ -9860,6 +10006,27 @@ table@^6.9.0: string-width "^4.2.3" strip-ansi "^6.0.1" +tar-fs@^2.0.0: + version "2.1.4" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.4.tgz#800824dbf4ef06ded9afea4acafe71c67c76b930" + integrity sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ== + dependencies: + chownr "^1.1.1" + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^2.1.4" + +tar-stream@^2.1.4: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + dependencies: + bl "^4.0.3" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + test-exclude@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-7.0.1.tgz#20b3ba4906ac20994e275bbcafd68d510264c2a2" @@ -10063,6 +10230,13 @@ tsx@^4.20.4: optionalDependencies: fsevents "~2.3.3" +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== + dependencies: + safe-buffer "^5.0.1" + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"