From 63cfffd05eaf20da3dd8e844c4e800db19878049 Mon Sep 17 00:00:00 2001 From: Dev Singh Date: Mon, 6 Jan 2025 17:37:01 +0000 Subject: [PATCH 1/9] add group modification route with protected groups support --- src/api/functions/entraId.ts | 126 ++++++++++++++++++++++++++++++++--- src/api/routes/iam.ts | 112 ++++++++++++++++++++++++++++++- src/common/config.ts | 17 +++-- src/common/errors/index.ts | 22 ++++++ src/common/types/iam.ts | 27 +++++++- 5 files changed, 284 insertions(+), 20 deletions(-) diff --git a/src/api/functions/entraId.ts b/src/api/functions/entraId.ts index 7a764ac5..a4994cca 100644 --- a/src/api/functions/entraId.ts +++ b/src/api/functions/entraId.ts @@ -1,20 +1,17 @@ import { genericConfig } from "../../common/config.js"; import { + EntraGroupError, EntraInvitationError, InternalServerError, } from "../../common/errors/index.js"; import { getSecretValue } from "../plugins/auth.js"; import { ConfidentialClientApplication } from "@azure/msal-node"; import { getItemFromCache, insertItemIntoCache } from "./cache.js"; +import { + EntraGroupActions, + EntraInvitationResponse, +} from "../../common/types/iam.js"; -interface EntraInvitationResponse { - status: number; - data?: Record; - error?: { - message: string; - code?: string; - }; -} export async function getEntraIdToken( clientId: string, scopes: string[] = ["https://graph.microsoft.com/.default"], @@ -76,6 +73,7 @@ export async function getEntraIdToken( /** * Adds a user to the tenant by sending an invitation to their email + * @param token - Entra ID token authorized to take this action. * @param email - The email address of the user to invite * @throws {InternalServerError} If the invitation fails * @returns {Promise} True if the invitation was successful @@ -123,3 +121,115 @@ export async function addToTenant(token: string, email: string) { }); } } + +/** + * Resolves an email address to an OID using Microsoft Graph API. + * @param token - Entra ID token authorized to perform this action. + * @param email - The email address to resolve. + * @throws {Error} If the resolution fails. + * @returns {Promise} The OID of the user. + */ +export async function resolveEmailToOid( + token: string, + email: string, +): Promise { + email = email.toLowerCase().replace(/\s/g, ""); + + const url = `https://graph.microsoft.com/v1.0/users?$filter=mail eq '${email}'`; + + const response = await fetch(url, { + method: "GET", + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json", + }, + }); + + if (!response.ok) { + const errorData = (await response.json()) as { + error?: { message?: string }; + }; + throw new Error(errorData?.error?.message ?? response.statusText); + } + + const data = (await response.json()) as { + value: { id: string }[]; + }; + + if (!data.value || data.value.length === 0) { + throw new Error(`No user found with email: ${email}`); + } + + return data.value[0].id; +} + +/** + * Adds or removes a user from an Entra ID group. + * @param token - Entra ID token authorized to take this action. + * @param email - The email address of the user to add or remove. + * @param group - The group ID to take action on. + * @param action - Whether to add or remove the user from the group. + * @throws {EntraGroupError} If the group action fails. + * @returns {Promise} True if the action was successful. + */ +export async function modifyGroup( + token: string, + email: string, + group: string, + action: EntraGroupActions, +): Promise { + email = email.toLowerCase().replace(/\s/g, ""); + if (!email.endsWith("@illinois.edu")) { + throw new EntraGroupError({ + group, + message: "User's domain must be illinois.edu to be added to the group.", + }); + } + + try { + const oid = await resolveEmailToOid(token, email); + const methodMapper = { + [EntraGroupActions.ADD]: "POST", + [EntraGroupActions.REMOVE]: "DELETE", + }; + + const urlMapper = { + [EntraGroupActions.ADD]: `https://graph.microsoft.com/v1.0/groups/${group}/members/$ref`, + [EntraGroupActions.REMOVE]: `https://graph.microsoft.com/v1.0/groups/${group}/members/${oid}/$ref`, + }; + const url = urlMapper[action]; + const body = { + "@odata.id": `https://graph.microsoft.com/v1.0/directoryObjects/${oid}`, + }; + + const response = await fetch(url, { + method: methodMapper[action], + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json", + }, + body: JSON.stringify(body), + }); + + if (!response.ok) { + const errorData = (await response.json()) as { + error?: { message?: string }; + }; + throw new EntraGroupError({ + message: errorData?.error?.message ?? response.statusText, + group, + }); + } + + return true; + } catch (error) { + if (error instanceof EntraGroupError) { + throw error; + } + + throw new EntraGroupError({ + message: error instanceof Error ? error.message : String(error), + group, + }); + } +} diff --git a/src/api/routes/iam.ts b/src/api/routes/iam.ts index ddd3e064..5201ce2e 100644 --- a/src/api/routes/iam.ts +++ b/src/api/routes/iam.ts @@ -1,11 +1,16 @@ import { FastifyPluginAsync } from "fastify"; import { AppRoles } from "../../common/roles.js"; import { zodToJsonSchema } from "zod-to-json-schema"; -import { addToTenant, getEntraIdToken } from "../functions/entraId.js"; +import { + addToTenant, + getEntraIdToken, + modifyGroup, +} from "../functions/entraId.js"; import { BaseError, DatabaseFetchError, DatabaseInsertError, + EntraGroupError, EntraInvitationError, InternalServerError, NotFoundError, @@ -22,7 +27,10 @@ import { invitePostRequestSchema, GroupMappingCreatePostRequest, groupMappingCreatePostSchema, - invitePostResponseSchema, + entraActionResponseSchema, + groupModificationPatchSchema, + GroupModificationPatchRequest, + EntraGroupActions, } from "../../common/types/iam.js"; const dynamoClient = new DynamoDBClient({ @@ -134,7 +142,7 @@ const iamRoutes: FastifyPluginAsync = async (fastify, _options) => { "/inviteUsers", { schema: { - response: { 200: zodToJsonSchema(invitePostResponseSchema) }, + response: { 200: zodToJsonSchema(entraActionResponseSchema) }, }, preValidation: async (request, reply) => { await fastify.zodValidateBody(request, reply, invitePostRequestSchema); @@ -176,6 +184,104 @@ const iamRoutes: FastifyPluginAsync = async (fastify, _options) => { reply.status(202).send(response); }, ); + fastify.patch<{ + Body: GroupModificationPatchRequest; + Querystring: { groupId: string }; + }>( + "/groupMembership/:groupId", + { + schema: { + querystring: { + type: "object", + properties: { + groupId: { + type: "string", + }, + }, + }, + }, + preValidation: async (request, reply) => { + await fastify.zodValidateBody( + request, + reply, + groupModificationPatchSchema, + ); + }, + onRequest: async (request, reply) => { + await fastify.authorize(request, reply, [AppRoles.IAM_ADMIN]); + }, + }, + async (request, reply) => { + const groupId = (request.params as Record).groupId; + if (!groupId || groupId === "") { + throw new NotFoundError({ + endpointName: request.url, + }); + } + if (genericConfig.ProtectedEntraIDGroups.includes(groupId)) { + throw new EntraGroupError({ + code: 403, + message: + "This group is protected and may not be modified by this service. You must log into Entra ID directly to modify this group.", + group: groupId, + }); + } + const entraIdToken = await getEntraIdToken( + fastify.environmentConfig.AadValidClientId, + ); + const addResults = await Promise.allSettled( + request.body.add.map((email) => + modifyGroup(entraIdToken, email, groupId, EntraGroupActions.ADD), + ), + ); + const removeResults = await Promise.allSettled( + request.body.remove.map((email) => + modifyGroup(entraIdToken, email, groupId, EntraGroupActions.REMOVE), + ), + ); + const response: Record[]> = { + success: [], + failure: [], + }; + for (let i = 0; i < addResults.length; i++) { + const result = addResults[i]; + if (result.status === "fulfilled") { + response.success.push({ email: request.body.add[i] }); + } else { + if (result.reason instanceof EntraGroupError) { + response.failure.push({ + email: request.body.add[i], + message: result.reason.message, + }); + } else { + response.failure.push({ + email: request.body.add[i], + message: "An unknown error occurred.", + }); + } + } + } + for (let i = 0; i < removeResults.length; i++) { + const result = removeResults[i]; + if (result.status === "fulfilled") { + response.success.push({ email: request.body.remove[i] }); + } else { + if (result.reason instanceof EntraGroupError) { + response.failure.push({ + email: request.body.add[i], + message: result.reason.message, + }); + } else { + response.failure.push({ + email: request.body.add[i], + message: "An unknown error occurred.", + }); + } + } + } + reply.status(202).send(response); + }, + ); }; export default iamRoutes; diff --git a/src/common/config.ts b/src/common/config.ts index 55dd384b..77857fe6 100644 --- a/src/common/config.ts +++ b/src/common/config.ts @@ -30,12 +30,17 @@ type GenericConfigType = { TicketMetadataTableName: string; MerchStoreMetadataTableName: string; IAMTablePrefix: string; + ProtectedEntraIDGroups: string[]; // these groups are too privileged to be modified via this portal and must be modified directly in Entra ID. }; type EnvironmentConfigType = { [env in RunEnvironment]: ConfigType; }; +export const infraChairsGroupId = "48591dbc-cdcb-4544-9f63-e6b92b067e33"; +export const officersGroupId = "ff49e948-4587-416b-8224-65147540d5fc"; +export const execCouncilGroupId = "ad81254b-4eeb-4c96-8191-3acdce9194b1"; + const genericConfig: GenericConfigType = { EventsDynamoTableName: "infra-core-api-events", CacheDynamoTableName: "infra-core-api-cache", @@ -48,12 +53,13 @@ const genericConfig: GenericConfigType = { TicketPurchasesTableName: "infra-events-tickets", TicketMetadataTableName: "infra-events-ticketing-metadata", IAMTablePrefix: "infra-core-api-iam", + ProtectedEntraIDGroups: [infraChairsGroupId, officersGroupId], } as const; const environmentConfig: EnvironmentConfigType = { dev: { GroupRoleMapping: { - "48591dbc-cdcb-4544-9f63-e6b92b067e33": allAppRoles, // Infra Chairs + [infraChairsGroupId]: allAppRoles, // Infra Chairs "940e4f9e-6891-4e28-9e29-148798495cdb": allAppRoles, // ACM Infra Team "f8dfc4cf-456b-4da3-9053-f7fdeda5d5d6": allAppRoles, // Infra Leads "0": allAppRoles, // Dummy Group for development only @@ -76,12 +82,9 @@ const environmentConfig: EnvironmentConfigType = { }, prod: { GroupRoleMapping: { - "48591dbc-cdcb-4544-9f63-e6b92b067e33": allAppRoles, // Infra Chairs - "ff49e948-4587-416b-8224-65147540d5fc": allAppRoles, // Officers - "ad81254b-4eeb-4c96-8191-3acdce9194b1": [ - AppRoles.EVENTS_MANAGER, - AppRoles.IAM_INVITE_ONLY, - ], // Exec + [infraChairsGroupId]: allAppRoles, // Infra Chairs + [officersGroupId]: allAppRoles, // Officers + [execCouncilGroupId]: [AppRoles.EVENTS_MANAGER, AppRoles.IAM_INVITE_ONLY], // Exec }, UserRoleMapping: { "jlevine4@illinois.edu": allAppRoles, diff --git a/src/common/errors/index.ts b/src/common/errors/index.ts index 43a29fc8..632669f4 100644 --- a/src/common/errors/index.ts +++ b/src/common/errors/index.ts @@ -179,3 +179,25 @@ export class NotSupportedError extends BaseError<"NotSupportedError"> { }); } } + +export class EntraGroupError extends BaseError<"EntraGroupError"> { + group: string; + constructor({ + code, + message, + group, + }: { + code?: number; + message?: string; + group: string; + }) { + super({ + name: "EntraGroupError", + id: 308, + message: + message || `Could not modify the group membership for group ${group}.`, + httpStatusCode: code || 500, + }); + this.group = group; + } +} diff --git a/src/common/types/iam.ts b/src/common/types/iam.ts index 8a499e98..a4dd331c 100644 --- a/src/common/types/iam.ts +++ b/src/common/types/iam.ts @@ -1,6 +1,20 @@ import { AppRoles } from "../roles.js"; import { z } from "zod"; +export enum EntraGroupActions { + ADD, + REMOVE, +} + +export interface EntraInvitationResponse { + status: number; + data?: Record; + error?: { + message: string; + code?: string; + }; +} + export const invitePostRequestSchema = z.object({ emails: z.array(z.string()), }); @@ -20,11 +34,20 @@ export type GroupMappingCreatePostRequest = z.infer< typeof groupMappingCreatePostSchema >; -export const invitePostResponseSchema = z.object({ +export const entraActionResponseSchema = z.object({ success: z.array(z.object({ email: z.string() })).optional(), failure: z .array(z.object({ email: z.string(), message: z.string() })) .optional(), }); -export type InvitePostResponse = z.infer; +export type EntraActionResponse = z.infer; + +export const groupModificationPatchSchema = z.object({ + add: z.array(z.string()), + remove: z.array(z.string()), +}); + +export type GroupModificationPatchRequest = z.infer< + typeof groupModificationPatchSchema +>; From 17ad20c621cd7688ca821bf6dc6efda46a77e51d Mon Sep 17 00:00:00 2001 From: Dev Singh Date: Mon, 6 Jan 2025 17:45:45 +0000 Subject: [PATCH 2/9] modify endpoint names; add listing group membership route --- src/api/functions/entraId.ts | 57 ++++++++++++++++++++++++++++++++++++ src/api/routes/iam.ts | 46 +++++++++++++++++++++++++++-- 2 files changed, 101 insertions(+), 2 deletions(-) diff --git a/src/api/functions/entraId.ts b/src/api/functions/entraId.ts index a4994cca..189c9a6a 100644 --- a/src/api/functions/entraId.ts +++ b/src/api/functions/entraId.ts @@ -233,3 +233,60 @@ export async function modifyGroup( }); } } + +/** + * Lists all members of an Entra ID group. + * @param token - Entra ID token authorized to take this action. + * @param group - The group ID to fetch members for. + * @throws {EntraGroupError} If the group action fails. + * @returns {Promise>} List of members with name and email. + */ +export async function listGroupMembers( + token: string, + group: string, +): Promise> { + try { + const url = `https://graph.microsoft.com/v1.0/groups/${group}/members`; + const response = await fetch(url, { + method: "GET", + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json", + }, + }); + + if (!response.ok) { + const errorData = (await response.json()) as { + error?: { message?: string }; + }; + throw new EntraGroupError({ + message: errorData?.error?.message ?? response.statusText, + group, + }); + } + + const data = (await response.json()) as { + value: Array<{ + displayName?: string; + mail?: string; + }>; + }; + + // Map the response to the desired format + const members = data.value.map((member) => ({ + name: member.displayName ?? "", + email: member.mail ?? "", + })); + + return members; + } catch (error) { + if (error instanceof EntraGroupError) { + throw error; + } + + throw new EntraGroupError({ + message: error instanceof Error ? error.message : String(error), + group, + }); + } +} diff --git a/src/api/routes/iam.ts b/src/api/routes/iam.ts index 5201ce2e..64b73369 100644 --- a/src/api/routes/iam.ts +++ b/src/api/routes/iam.ts @@ -4,6 +4,7 @@ import { zodToJsonSchema } from "zod-to-json-schema"; import { addToTenant, getEntraIdToken, + listGroupMembers, modifyGroup, } from "../functions/entraId.js"; import { @@ -188,7 +189,7 @@ const iamRoutes: FastifyPluginAsync = async (fastify, _options) => { Body: GroupModificationPatchRequest; Querystring: { groupId: string }; }>( - "/groupMembership/:groupId", + "/groups/:groupId", { schema: { querystring: { @@ -222,7 +223,7 @@ const iamRoutes: FastifyPluginAsync = async (fastify, _options) => { throw new EntraGroupError({ code: 403, message: - "This group is protected and may not be modified by this service. You must log into Entra ID directly to modify this group.", + "This group is protected and cannot be modified by this service. You must log into Entra ID directly to modify this group.", group: groupId, }); } @@ -282,6 +283,47 @@ const iamRoutes: FastifyPluginAsync = async (fastify, _options) => { reply.status(202).send(response); }, ); + fastify.get<{ + Querystring: { groupId: string }; + }>( + "/groups/:groupId", + { + schema: { + querystring: { + type: "object", + properties: { + groupId: { + type: "string", + }, + }, + }, + }, + onRequest: async (request, reply) => { + await fastify.authorize(request, reply, [AppRoles.IAM_ADMIN]); + }, + }, + async (request, reply) => { + const groupId = (request.params as Record).groupId; + if (!groupId || groupId === "") { + throw new NotFoundError({ + endpointName: request.url, + }); + } + if (genericConfig.ProtectedEntraIDGroups.includes(groupId)) { + throw new EntraGroupError({ + code: 403, + message: + "This group is protected and cannot be read by this service. You must log into Entra ID directly to read this group.", + group: groupId, + }); + } + const entraIdToken = await getEntraIdToken( + fastify.environmentConfig.AadValidClientId, + ); + const response = await listGroupMembers(entraIdToken, groupId); + reply.status(200).send(response); + }, + ); }; export default iamRoutes; From a4d879f69fb084ad0f7b96792fb300081d59cad1 Mon Sep 17 00:00:00 2001 From: Dev Singh Date: Mon, 6 Jan 2025 18:04:00 +0000 Subject: [PATCH 3/9] fix response types --- src/api/routes/iam.ts | 4 +++- src/common/types/iam.ts | 11 +++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/api/routes/iam.ts b/src/api/routes/iam.ts index 64b73369..2bb207af 100644 --- a/src/api/routes/iam.ts +++ b/src/api/routes/iam.ts @@ -32,6 +32,7 @@ import { groupModificationPatchSchema, GroupModificationPatchRequest, EntraGroupActions, + entraGroupMembershipListResponse, } from "../../common/types/iam.js"; const dynamoClient = new DynamoDBClient({ @@ -143,7 +144,7 @@ const iamRoutes: FastifyPluginAsync = async (fastify, _options) => { "/inviteUsers", { schema: { - response: { 200: zodToJsonSchema(entraActionResponseSchema) }, + response: { 202: zodToJsonSchema(entraActionResponseSchema) }, }, preValidation: async (request, reply) => { await fastify.zodValidateBody(request, reply, invitePostRequestSchema); @@ -289,6 +290,7 @@ const iamRoutes: FastifyPluginAsync = async (fastify, _options) => { "/groups/:groupId", { schema: { + response: { 200: zodToJsonSchema(entraGroupMembershipListResponse) }, querystring: { type: "object", properties: { diff --git a/src/common/types/iam.ts b/src/common/types/iam.ts index a4dd331c..c7699881 100644 --- a/src/common/types/iam.ts +++ b/src/common/types/iam.ts @@ -51,3 +51,14 @@ export const groupModificationPatchSchema = z.object({ export type GroupModificationPatchRequest = z.infer< typeof groupModificationPatchSchema >; + +export const entraGroupMembershipListResponse = z.array( + z.object({ + name: z.string(), + email: z.string(), + }), +); + +export type GroupMemberGetResponse = z.infer< + typeof entraGroupMembershipListResponse +>; From 9ca4515b843740f522e89321ea4fb5bc969e926b Mon Sep 17 00:00:00 2001 From: Dev Singh Date: Mon, 6 Jan 2025 18:07:34 +0000 Subject: [PATCH 4/9] basic unit tests --- tests/unit/entraGroupManagement.test.ts | 171 ++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 tests/unit/entraGroupManagement.test.ts diff --git a/tests/unit/entraGroupManagement.test.ts b/tests/unit/entraGroupManagement.test.ts new file mode 100644 index 00000000..c8389654 --- /dev/null +++ b/tests/unit/entraGroupManagement.test.ts @@ -0,0 +1,171 @@ +import { afterAll, expect, test, beforeEach, vi } from "vitest"; +import { mockClient } from "aws-sdk-client-mock"; +import init from "../../src/api/index.js"; +import { createJwt } from "./auth.test.js"; +import supertest from "supertest"; +import { describe } from "node:test"; +import { + GetSecretValueCommand, + SecretsManagerClient, +} from "@aws-sdk/client-secrets-manager"; +import { EntraGroupError } from "../../src/common/errors/index.js"; + +// Mock required dependencies - their real impl's are defined in the beforeEach section. +vi.mock("../../src/api/functions/entraId.js", () => { + return { + ...vi.importActual("../../src/api/functions/entraId.js"), + getEntraIdToken: vi.fn().mockImplementation(async () => { + return ""; + }), + modifyGroup: vi.fn().mockImplementation(async () => { + return ""; + }), + resolveEmailToOid: vi.fn().mockImplementation(async () => { + return ""; + }), + listGroupMembers: vi.fn().mockImplementation(async () => { + return ""; + }), + }; +}); + +import { + modifyGroup, + listGroupMembers, + getEntraIdToken, + resolveEmailToOid, +} from "../../src/api/functions/entraId.js"; +import { EntraGroupActions } from "../../src/common/types/iam.js"; + +const smMock = mockClient(SecretsManagerClient); +const app = await init(); + +describe("Test Modify Group and List Group Routes", () => { + beforeEach(() => { + vi.resetAllMocks(); + smMock.on(GetSecretValueCommand).resolves({ + SecretString: JSON.stringify({ jwt_key: "test_jwt_key" }), + }); + }); + + test("Modify group: Add and remove members", async () => { + const testJwt = createJwt(); + await app.ready(); + + const response = await supertest(app.server) + .patch("/api/v1/iam/groups/test-group-id") + .set("authorization", `Bearer ${testJwt}`) + .send({ + add: ["validuser1@illinois.edu"], + remove: ["validuser2@illinois.edu"], + }); + + expect(response.statusCode).toBe(202); + expect(modifyGroup).toHaveBeenCalledTimes(2); + expect(modifyGroup).toHaveBeenNthCalledWith( + 1, + "ey.test.token", + "validuser1@illinois.edu", + "test-group-id", + EntraGroupActions.ADD, + ); + expect(modifyGroup).toHaveBeenNthCalledWith( + 2, + "ey.test.token", + "validuser2@illinois.edu", + "test-group-id", + EntraGroupActions.REMOVE, + ); + expect(response.body.success).toEqual([ + { email: "validuser1@illinois.edu" }, + { email: "validuser2@illinois.edu" }, + ]); + expect(response.body.failure).toEqual([]); + }); + + test("Modify group: Fail for invalid email domain", async () => { + const testJwt = createJwt(); + await app.ready(); + + const response = await supertest(app.server) + .patch("/api/v1/iam/groups/test-group-id") + .set("authorization", `Bearer ${testJwt}`) + .send({ + add: ["invaliduser@example.com"], + remove: [], + }); + + expect(response.statusCode).toBe(202); + expect(modifyGroup).toHaveBeenCalledTimes(1); + expect(response.body.success).toEqual([]); + expect(response.body.failure).toEqual([ + { + email: "invaliduser@example.com", + message: + "User's domain must be illinois.edu to be added or removed from the group.", + }, + ]); + }); + + test("List group members: Happy path", async () => { + const testJwt = createJwt(); + await app.ready(); + + const response = await supertest(app.server) + .get("/api/v1/iam/groups/test-group-id") + .set("authorization", `Bearer ${testJwt}`); + + expect(response.statusCode).toBe(200); + expect(listGroupMembers).toHaveBeenCalledWith( + "ey.test.token", + "test-group-id", + ); + expect(response.body).toEqual([ + { name: "John Doe", email: "john.doe@illinois.edu" }, + { name: "Jane Doe", email: "jane.doe@illinois.edu" }, + ]); + }); + + afterAll(async () => { + await app.close(); + }); + beforeEach(() => { + vi.resetAllMocks(); + vi.useFakeTimers(); + (getEntraIdToken as any).mockImplementation(async () => { + return "ey.test.token"; + }); + (modifyGroup as any).mockImplementation( + async (_token, email, group, _action) => { + if (!email.endsWith("@illinois.edu")) { + throw new EntraGroupError({ + code: 400, + message: + "User's domain must be illinois.edu to be added or removed from the group.", + group, + }); + } + return true; + }, + ); + (resolveEmailToOid as any).mockImplementation(async (_token, email) => { + if (email === "invaliduser@example.com") { + throw new Error("User not found"); + } + return "mocked-oid"; + }); + (listGroupMembers as any).mockImplementation(async (_token, group) => { + if (group === "nonexistent-group-id") { + throw new EntraGroupError({ + code: 404, + message: "Group not found.", + group, + }); + } + return [ + { name: "John Doe", email: "john.doe@illinois.edu" }, + { name: "Jane Doe", email: "jane.doe@illinois.edu" }, + ]; + }); + }); +}); From 0b7efcbbed0d76c6f7528d76c2ab4d5d454cba79 Mon Sep 17 00:00:00 2001 From: Dev Singh Date: Mon, 6 Jan 2025 18:54:34 +0000 Subject: [PATCH 5/9] test ui --- .github/workflows/deploy-dev.yml | 2 +- .github/workflows/deploy-prod.yml | 10 +- src/ui/pages/iam/GroupMemberManagement.tsx | 280 +++++++++++++++++++++ src/ui/pages/iam/ManageIam.page.tsx | 38 +++ src/ui/tsconfig.json | 26 +- src/ui/vite.config.mjs | 4 +- 6 files changed, 346 insertions(+), 14 deletions(-) create mode 100644 src/ui/pages/iam/GroupMemberManagement.tsx diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml index 10a6b5c0..dc9b3e18 100644 --- a/.github/workflows/deploy-dev.yml +++ b/.github/workflows/deploy-dev.yml @@ -85,7 +85,7 @@ jobs: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} projectName: management-ui-dev - directory: dist/ui/ + directory: dist_ui/ gitHubToken: ${{ secrets.GITHUB_TOKEN }} branch: main test: diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml index 862efd45..41bdeebd 100644 --- a/.github/workflows/deploy-prod.yml +++ b/.github/workflows/deploy-prod.yml @@ -85,7 +85,7 @@ jobs: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} projectName: management-ui-dev - directory: dist/ui/ + directory: dist_ui/ gitHubToken: ${{ secrets.GITHUB_TOKEN }} test: runs-on: ubuntu-latest @@ -103,7 +103,7 @@ jobs: node-version: 20.x - uses: actions/checkout@v4 env: - HUSKY: "0" + HUSKY: "0" - name: Set up Python 3.11 for testing uses: actions/setup-python@v5 with: @@ -126,7 +126,7 @@ jobs: node-version: 20.x - uses: actions/checkout@v4 env: - HUSKY: "0" + HUSKY: "0" - uses: aws-actions/setup-sam@v2 with: use-installer: true @@ -171,7 +171,7 @@ jobs: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} projectName: management-ui-prod - directory: dist/ui/ + directory: dist_ui/ gitHubToken: ${{ secrets.GITHUB_TOKEN }} branch: main health-check-prod: @@ -189,6 +189,6 @@ jobs: node-version: 20.x - uses: actions/checkout@v4 env: - HUSKY: "0" + HUSKY: "0" - name: Call the health check script run: make prod_health_check diff --git a/src/ui/pages/iam/GroupMemberManagement.tsx b/src/ui/pages/iam/GroupMemberManagement.tsx new file mode 100644 index 00000000..b2e24d60 --- /dev/null +++ b/src/ui/pages/iam/GroupMemberManagement.tsx @@ -0,0 +1,280 @@ +import React, { useState, useEffect } from 'react'; +import { + Box, + Button, + Text, + TextInput, + Group, + Modal, + List, + ListItem, + Alert, + ActionIcon, + ScrollArea, + Badge, +} from '@mantine/core'; +import { IconTrash, IconCheck, IconX } from '@tabler/icons-react'; +import { notifications } from '@mantine/notifications'; +import { GroupMemberGetResponse, EntraActionResponse } from '@common/types/iam'; + +interface GroupMemberManagementProps { + fetchMembers: () => Promise; + updateMembers: (toAdd: string[], toRemove: string[]) => Promise; +} + +export const GroupMemberManagement: React.FC = ({ + fetchMembers, + updateMembers, +}) => { + const [members, setMembers] = useState([]); + const [toAdd, setToAdd] = useState([]); + const [toRemove, setToRemove] = useState([]); + const [results, setResults] = useState< + { email: string; status: 'success' | 'failure'; message?: string }[] + >([]); + const [email, setEmail] = useState(''); + const [isLoading, setIsLoading] = useState(false); + const [confirmationModal, setConfirmationModal] = useState(false); + const [errorModal, setErrorModal] = useState<{ open: boolean; email: string; message: string }>({ + open: false, + email: '', + message: '', + }); + + useEffect(() => { + const loadMembers = async () => { + try { + const memberList = await fetchMembers(); + setMembers(memberList); + } catch (error) { + notifications.show({ + title: 'Error', + message: 'Failed to retrieve members.', + color: 'red', + }); + } + }; + loadMembers(); + }, [fetchMembers]); + + const handleAddMember = () => { + if (email && !members.some((member) => member.email === email) && !toAdd.includes(email)) { + setToAdd((prev) => [...prev, email]); + setEmail(''); + } + }; + + const handleRemoveMember = (email: string) => { + if (!toRemove.includes(email)) { + setToRemove((prev) => [...prev, email]); + } + }; + + const handleSaveChanges = async () => { + setIsLoading(true); + const newResults: { email: string; status: 'success' | 'failure'; message?: string }[] = []; + + try { + const response = await updateMembers(toAdd, toRemove); + response.success?.forEach(({ email }) => { + newResults.push({ email, status: 'success' }); + }); + response.failure?.forEach(({ email, message }) => { + newResults.push({ email, status: 'failure', message }); + }); + setResults(newResults); + setToAdd([]); + setToRemove([]); + } catch (error) { + notifications.show({ + title: 'Error', + message: 'An error occurred while saving changes.', + color: 'red', + }); + } finally { + setIsLoading(false); + } + }; + + const handleViewErrorDetails = (email: string, message: string) => { + setErrorModal({ open: true, email, message }); + }; + + return ( + + + Group Member Management + + + {/* Member List */} + + + Current Members + + + + {members.map((member) => ( + + + {member.email} + handleRemoveMember(member.email)} + > + + + + + ))} + + + + + {/* Add Member */} + + setEmail(event.currentTarget.value)} + placeholder="Enter email to add" + disabled={isLoading} + /> + + + + {/* Save Changes Button */} + + + {/* Confirmation Modal */} + setConfirmationModal(false)} + title="Confirm Changes" + size="md" + > + + {toAdd.length > 0 && ( + + + Members to Add: + + + + {toAdd.map((email) => ( + + {email} + + ))} + + + + )} + {toRemove.length > 0 && ( + + + Members to Remove: + + + + {toRemove.map((email) => ( + + {email} + + ))} + + + + )} + + + + + + + + {/* Results */} + {results.length > 0 && ( + + + Results + + + {results.map(({ email, status, message }) => ( + + + {email} + + + {status === 'success' ? 'Success' : 'Failure'} + + {status === 'failure' && ( + + )} + + + + ))} + + + )} + + {/* Error Modal */} + setErrorModal({ open: false, email: '', message: '' })} + title="Error Details" + > + + + Email: + + + {errorModal.email} + + + Error Message: + + + {errorModal.message} + + + + + + {/* Notifications for Feedback */} + {isLoading && ( + + Please wait while the changes are being processed. + + )} + + ); +}; + +export default GroupMemberManagement; diff --git a/src/ui/pages/iam/ManageIam.page.tsx b/src/ui/pages/iam/ManageIam.page.tsx index f2db494d..a26eed45 100644 --- a/src/ui/pages/iam/ManageIam.page.tsx +++ b/src/ui/pages/iam/ManageIam.page.tsx @@ -4,6 +4,13 @@ import { AuthGuard } from '@ui/components/AuthGuard'; import { useApi } from '@ui/util/api'; import { AppRoles } from '@common/roles'; import UserInvitePanel from './UserInvitePanel'; +import GroupMemberManagement from './GroupMemberManagement'; +import { execCouncilGroupId } from '@common/config'; +import { + EntraActionResponse, + GroupMemberGetResponse, + GroupModificationPatchRequest, +} from '@common/types/iam'; export const ManageIamPage = () => { const api = useApi('core'); @@ -26,6 +33,36 @@ export const ManageIamPage = () => { } }; + const getExecMembers = async () => { + try { + const response = await api.get(`/api/v1/iam/groups/${execCouncilGroupId}`); + return response.data as GroupMemberGetResponse; + } catch (error: any) { + console.error('Failed to get users:', error); + return []; + } + }; + + const updateExecMembers = async (toAdd: string[], toRemove: string[]) => { + const allMembers = toAdd.concat(toRemove); + try { + const response = await api.patch(`/api/v1/iam/groups/${execCouncilGroupId}`, { + remove: toRemove, + add: toAdd, + } as GroupModificationPatchRequest); + return response.data as EntraActionResponse; + } catch (error: any) { + console.error('Failed to get users:', error); + return { + success: [], + failure: allMembers.map((email) => ({ + email, + message: error.message || 'Failed to modify group member', + })), + }; + } + }; + return ( { Manage Authentication + {/* For future panels, make sure to add an auth guard if not every IAM role can see it. */} diff --git a/src/ui/tsconfig.json b/src/ui/tsconfig.json index dfb3fec2..ade8e55d 100644 --- a/src/ui/tsconfig.json +++ b/src/ui/tsconfig.json @@ -1,10 +1,18 @@ { "compilerOptions": { - "types": ["node", "@testing-library/jest-dom", "vitest/globals"], + "types": [ + "node", + "@testing-library/jest-dom", + "vitest/globals" + ], "target": "ESNext", - "outDir": "../../dist/ui", + "outDir": "../../dist_ui", "useDefineForClassFields": true, - "lib": ["DOM", "DOM.Iterable", "ESNext"], + "lib": [ + "DOM", + "DOM.Iterable", + "ESNext" + ], "allowJs": false, "skipLibCheck": true, "esModuleInterop": false, @@ -18,9 +26,15 @@ "noEmit": true, "jsx": "react-jsx", "paths": { - "@ui/*": ["./*"], - "@common/*": ["../common/*"] + "@ui/*": [ + "./*" + ], + "@common/*": [ + "../common/*" + ] }, }, - "include": ["./**/*"], + "include": [ + "./**/*" + ], } diff --git a/src/ui/vite.config.mjs b/src/ui/vite.config.mjs index 68302222..e47cc647 100644 --- a/src/ui/vite.config.mjs +++ b/src/ui/vite.config.mjs @@ -26,7 +26,7 @@ export default defineConfig({ historyApiFallback: true, }, build: { - outDir: "../../dist/ui", + outDir: '../../dist_ui', emptyOutDir: true, rollupOptions: { output: { @@ -39,4 +39,4 @@ export default defineConfig({ }, }, }, -}); \ No newline at end of file +}); From 5bf387194060d83f36d6eb1f6e2be4fbe895b3e5 Mon Sep 17 00:00:00 2001 From: Dev Singh Date: Mon, 6 Jan 2025 18:58:04 +0000 Subject: [PATCH 6/9] fix build dir --- .gitignore | 3 +- src/ui/pages/iam/GroupMemberManagement.tsx | 81 +--------------------- src/ui/pages/iam/UserInvitePanel.tsx | 6 +- src/ui/vite.config.mjs | 8 +-- 4 files changed, 9 insertions(+), 89 deletions(-) diff --git a/.gitignore b/.gitignore index 4461ec84..8a4bd7ae 100644 --- a/.gitignore +++ b/.gitignore @@ -133,6 +133,7 @@ dist .aws-sam/ build/ dist/ +dist_ui/ *.pyc -__pycache__ \ No newline at end of file +__pycache__ diff --git a/src/ui/pages/iam/GroupMemberManagement.tsx b/src/ui/pages/iam/GroupMemberManagement.tsx index b2e24d60..d41f26c2 100644 --- a/src/ui/pages/iam/GroupMemberManagement.tsx +++ b/src/ui/pages/iam/GroupMemberManagement.tsx @@ -115,7 +115,7 @@ export const GroupMemberManagement: React.FC = ({ {members.map((member) => ( - + {member.email} = ({ - {/* Add Member */} - - setEmail(event.currentTarget.value)} - placeholder="Enter email to add" - disabled={isLoading} - /> - - - {/* Save Changes Button */} @@ -209,70 +196,6 @@ export const GroupMemberManagement: React.FC = ({ - - {/* Results */} - {results.length > 0 && ( - - - Results - - - {results.map(({ email, status, message }) => ( - - - {email} - - - {status === 'success' ? 'Success' : 'Failure'} - - {status === 'failure' && ( - - )} - - - - ))} - - - )} - - {/* Error Modal */} - setErrorModal({ open: false, email: '', message: '' })} - title="Error Details" - > - - - Email: - - - {errorModal.email} - - - Error Message: - - - {errorModal.message} - - - - - - {/* Notifications for Feedback */} - {isLoading && ( - - Please wait while the changes are being processed. - - )} ); }; diff --git a/src/ui/pages/iam/UserInvitePanel.tsx b/src/ui/pages/iam/UserInvitePanel.tsx index 6313ceda..084d355a 100644 --- a/src/ui/pages/iam/UserInvitePanel.tsx +++ b/src/ui/pages/iam/UserInvitePanel.tsx @@ -1,10 +1,10 @@ import { Box, Button, Textarea, Text, Modal, Alert, Group, List, ListItem } from '@mantine/core'; import { IconAlertCircle, IconCircleCheck } from '@tabler/icons-react'; import React, { useState } from 'react'; -import { InvitePostResponse } from '@common/types/iam'; +import { EntraActionResponse } from '@common/types/iam'; interface UserInvitePanelProps { - onSubmit: (emails: string[]) => Promise; + onSubmit: (emails: string[]) => Promise; } interface ErrorModalState { @@ -16,7 +16,7 @@ interface ErrorModalState { export const UserInvitePanel: React.FC = ({ onSubmit }) => { const [emails, setEmails] = useState(''); const [isSubmitting, setIsSubmitting] = useState(false); - const [results, setResults] = useState(null); + const [results, setResults] = useState(null); const [errorModal, setErrorModal] = useState({ open: false, email: '', diff --git a/src/ui/vite.config.mjs b/src/ui/vite.config.mjs index e47cc647..4968fc89 100644 --- a/src/ui/vite.config.mjs +++ b/src/ui/vite.config.mjs @@ -1,15 +1,11 @@ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import tsconfigPaths from 'vite-tsconfig-paths'; -import 'dotenv/config' +import 'dotenv/config'; import path from 'path'; - export default defineConfig({ - plugins: [ - react(), - tsconfigPaths(), - ], + plugins: [react(), tsconfigPaths()], resolve: { preserveSymlinks: true, alias: { From c58ce327adc3fc27a1f21b24bac42dd53d7db2a7 Mon Sep 17 00:00:00 2001 From: Dev Singh Date: Mon, 6 Jan 2025 19:33:47 +0000 Subject: [PATCH 7/9] enable better preview --- src/ui/package.json | 5 +- yarn.lock | 732 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 644 insertions(+), 93 deletions(-) diff --git a/src/ui/package.json b/src/ui/package.json index 25f77749..a76e5a6f 100644 --- a/src/ui/package.json +++ b/src/ui/package.json @@ -6,7 +6,7 @@ "dev": "cross-env VITE_RUN_ENVIRONMENT=local-dev vite", "dev:aws": "cross-env VITE_RUN_ENVIRONMENT=dev vite", "build": "tsc && vite build", - "preview": "vite preview", + "preview": "cross-env VITE_RUN_ENVIRONMENT=local-dev yarn build && cross-env VITE_RUN_ENVIRONMENT=local-dev serve -l 5173 -s ../../dist_ui/", "typecheck": "tsc --noEmit", "lint": " eslint . --ext .ts,.tsx --cache", "prettier": "prettier --check \"**/*.{ts,tsx}\"", @@ -17,7 +17,7 @@ "storybook": "storybook dev -p 6006", "storybook:build": "storybook build" }, -"dependencies": { + "dependencies": { "@azure/msal-browser": "^3.20.0", "@azure/msal-react": "^2.0.22", "@mantine/core": "^7.12.0", @@ -75,6 +75,7 @@ "postcss-simple-vars": "^7.0.1", "prettier": "^3.3.3", "prop-types": "^15.8.1", + "serve": "^14.2.4", "storybook": "^8.2.8", "storybook-dark-mode": "^4.0.2", "stylelint": "^16.8.1", diff --git a/yarn.lock b/yarn.lock index f2e1aec0..4d407953 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1414,6 +1414,21 @@ resolved "https://registry.yarnpkg.com/@mantine/store/-/store-7.15.2.tgz#90fb34f257a4a7514747a035eee76c41055128d6" integrity sha512-8ZVRr6D/8GEu2VmUVU447w4H+hl9dwefl//GpSGI2vKxXBqlud5X9PJQkSwi5J7I5FAxvlG5dr/zCxC3r3nsIQ== +"@mapbox/node-pre-gyp@^1.0.0": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz#417db42b7f5323d79e93b34a6d7a2a12c0df43fa" + integrity sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ== + dependencies: + detect-libc "^2.0.0" + https-proxy-agent "^5.0.0" + make-dir "^3.1.0" + node-fetch "^2.6.7" + nopt "^5.0.0" + npmlog "^5.0.1" + rimraf "^3.0.2" + semver "^7.3.5" + tar "^6.1.11" + "@mdx-js/react@^3.0.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-3.1.0.tgz#c4522e335b3897b9a845db1dbdd2f966ae8fb0ed" @@ -1421,72 +1436,6 @@ dependencies: "@types/mdx" "^2.0.0" -"@napi-rs/canvas-android-arm64@0.1.65": - version "0.1.65" - resolved "https://registry.yarnpkg.com/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.65.tgz#b42f2a2f67cb32ad6669e53561987d58384e791f" - integrity sha512-ZYwqFYEKcT5Zr8lbiaJNJj/poLaeK2TncolY914r+gD2TJNeP7ZqvE7A2SX/1C9MB4E3DQEwm3YhL3WEf0x3MQ== - -"@napi-rs/canvas-darwin-arm64@0.1.65": - version "0.1.65" - resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.65.tgz#8b1a8c2495816f640c1c0299e717de722b961608" - integrity sha512-Pg1pfiJEyDIsX+V0QaJPRWvXbw5zmWAk3bivFCvt/5pwZb37/sT6E/RqPHT9NnqpDyKW6SriwY9ypjljysUA1Q== - -"@napi-rs/canvas-darwin-x64@0.1.65": - version "0.1.65" - resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.65.tgz#c34da0605c6220ec4e42bbf4dd2ae594c19a4048" - integrity sha512-3Tr+/HjdJN7Z/VKIcsxV2DvDIibZCExgfYTgljCkUSFuoI7iNkOE6Dc1Q6j212EB9PeO8KmfrViBqHYT6IwWkA== - -"@napi-rs/canvas-linux-arm-gnueabihf@0.1.65": - version "0.1.65" - resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.65.tgz#83b618fe762190bbbfdb66e636f6de0ea940c0ec" - integrity sha512-3KP+dYObH7CVkZMZWwk1WX9jRjL+EKdQtD43H8MOI+illf+dwqLlecdQ4d9bQRIxELKJ8dyPWY4fOp/Ngufrdg== - -"@napi-rs/canvas-linux-arm64-gnu@0.1.65": - version "0.1.65" - resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.65.tgz#b267573eea3209c76d69c69f8fd040407720167d" - integrity sha512-Ka3StKz7Dq7kjTF3nNJCq43UN/VlANS7qGE3dWkn1d+tQNsCRy/wRmyt1TUFzIjRqcTFMQNRbgYq84+53UBA0A== - -"@napi-rs/canvas-linux-arm64-musl@0.1.65": - version "0.1.65" - resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.65.tgz#36896b8166f6e8752c0142c6114cb64cf235a649" - integrity sha512-O4xMASm2JrmqYoiDyxVWi+z5C14H+oVEag2rZ5iIA67dhWqYZB+iO7wCFpBYRj31JPBR29FOsu6X9zL+DwBFdw== - -"@napi-rs/canvas-linux-riscv64-gnu@0.1.65": - version "0.1.65" - resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.65.tgz#ab5059fae49769ccf726e8ded103f15e0a39e16c" - integrity sha512-dblWDaA59ZU8bPbkfM+riSke7sFbNZ70LEevUdI5rgiFEUzYUQlU34gSBzemTACj5rCWt1BYeu0GfkLSjNMBSw== - -"@napi-rs/canvas-linux-x64-gnu@0.1.65": - version "0.1.65" - resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.65.tgz#767b023c9d7d9d09be06afdfe37ed0549b5b7a6c" - integrity sha512-wsp+atutw13OJXGU3DDkdngtBDoEg01IuK5xMe0L6VFPV8maGkh17CXze078OD5QJOc6kFyw3DDscMLOPF8+oA== - -"@napi-rs/canvas-linux-x64-musl@0.1.65": - version "0.1.65" - resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.65.tgz#9551edca5b5f0e7abfe7d5fea97b1ce25aeed4ca" - integrity sha512-odX+nN+IozWzhdj31INcHz3Iy9+EckNw+VqsZcaUxZOTu7/3FmktRNI6aC1qe5minZNv1m05YOS1FVf7fvmjlA== - -"@napi-rs/canvas-win32-x64-msvc@0.1.65": - version "0.1.65" - resolved "https://registry.yarnpkg.com/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.65.tgz#86b9209267a20df2c0044b650feb9abc8c85be3d" - integrity sha512-RZQX3luWnlNWgdMnLMQ1hyfQraeAn9lnxWWVCHuUM4tAWEV8UDdeb7cMwmJW7eyt8kAosmjeHt3cylQMHOxGFg== - -"@napi-rs/canvas@^0.1.65": - version "0.1.65" - resolved "https://registry.yarnpkg.com/@napi-rs/canvas/-/canvas-0.1.65.tgz#ef97a41b83aa03ae37862e789d124ec80eaf5b33" - integrity sha512-YcFhXQcp+b2d38zFOJNbpyPHnIL7KAEkhJQ+UeeKI5IpE9B8Cpf/M6RiHPQXSsSqnYbrfFylnW49dyh2oeSblQ== - optionalDependencies: - "@napi-rs/canvas-android-arm64" "0.1.65" - "@napi-rs/canvas-darwin-arm64" "0.1.65" - "@napi-rs/canvas-darwin-x64" "0.1.65" - "@napi-rs/canvas-linux-arm-gnueabihf" "0.1.65" - "@napi-rs/canvas-linux-arm64-gnu" "0.1.65" - "@napi-rs/canvas-linux-arm64-musl" "0.1.65" - "@napi-rs/canvas-linux-riscv64-gnu" "0.1.65" - "@napi-rs/canvas-linux-x64-gnu" "0.1.65" - "@napi-rs/canvas-linux-x64-musl" "0.1.65" - "@napi-rs/canvas-win32-x64-msvc" "0.1.65" - "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -2887,6 +2836,11 @@ resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== +"@zeit/schemas@2.36.0": + version "2.36.0" + resolved "https://registry.yarnpkg.com/@zeit/schemas/-/schemas-2.36.0.tgz#7a1b53f4091e18d0b404873ea3e3c83589c765f2" + integrity sha512-7kjMwcChYEzMKjeex9ZFXkt1AyNov9R5HZtjBKVsmVpw7pa7ZtlCGvCBC2vnnXctaYN+aRI61HjIqeetZW5ROg== + "@zxing/browser@0.0.7": version "0.0.7" resolved "https://registry.yarnpkg.com/@zxing/browser/-/browser-0.0.7.tgz#5fa7680a867b660f48d3288fdf63e0174ad531c7" @@ -2908,6 +2862,11 @@ resolved "https://registry.yarnpkg.com/@zxing/text-encoding/-/text-encoding-0.9.0.tgz#fb50ffabc6c7c66a0c96b4c03e3d9be74864b70b" integrity sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA== +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + abstract-cache@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/abstract-cache/-/abstract-cache-1.0.1.tgz#136151becf5c32e0ea27f78728d073d8fe07932a" @@ -2922,6 +2881,14 @@ abstract-logging@^2.0.1: resolved "https://registry.yarnpkg.com/abstract-logging/-/abstract-logging-2.0.1.tgz#6b0c371df212db7129b57d2e7fcf282b8bf1c839" integrity sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA== +accepts@~1.3.5: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + acorn-jsx@^5.2.0, acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -2937,6 +2904,13 @@ acorn@^8.14.0, acorn@^8.9.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + agent-base@^7.1.0, agent-base@^7.1.2: version "7.1.3" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.3.tgz#29435eb821bc4194633a5b89e5bc4703bafc25a1" @@ -2949,6 +2923,16 @@ ajv-formats@^3.0.1: dependencies: ajv "^8.0.0" +ajv@8.12.0: + version "8.12.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" + integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -2969,6 +2953,13 @@ ajv@^8.0.0, ajv@^8.0.1, ajv@^8.12.0: json-schema-traverse "^1.0.0" require-from-string "^2.0.2" +ansi-align@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59" + integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w== + dependencies: + string-width "^4.1.0" + ansi-escapes@^4.2.1: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" @@ -2986,6 +2977,11 @@ ansi-regex@^5.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +ansi-regex@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== + ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -3005,6 +3001,34 @@ ansi-styles@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + +"aproba@^1.0.3 || ^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" + integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== + +arch@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" + integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== + +are-we-there-yet@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" + integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== + dependencies: + delegates "^1.0.0" + readable-stream "^3.6.0" + +arg@5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c" + integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg== + argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -3286,6 +3310,20 @@ bowser@^2.11.0: resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f" integrity sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA== +boxen@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-7.0.0.tgz#9e5f8c26e716793fc96edcf7cf754cdf5e3fbf32" + integrity sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg== + dependencies: + ansi-align "^3.0.1" + camelcase "^7.0.0" + chalk "^5.0.1" + cli-boxes "^3.0.0" + string-width "^5.1.2" + type-fest "^2.13.0" + widest-line "^4.0.1" + wrap-ansi "^8.0.1" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -3328,6 +3366,11 @@ buffer-equal-constant-time@1.0.1: resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== + cac@^6.7.14: version "6.7.14" resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" @@ -3369,11 +3412,25 @@ camelcase-css@^2.0.1: resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== +camelcase@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-7.0.1.tgz#f02e50af9fd7782bc8b88a3558c32fd3a388f048" + integrity sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw== + caniuse-lite@^1.0.30001688: version "1.0.30001690" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz#f2d15e3aaf8e18f76b2b8c1481abde063b8104c8" integrity sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w== +canvas@^2.11.2: + version "2.11.2" + resolved "https://registry.yarnpkg.com/canvas/-/canvas-2.11.2.tgz#553d87b1e0228c7ac0fc72887c3adbac4abbd860" + integrity sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw== + dependencies: + "@mapbox/node-pre-gyp" "^1.0.0" + nan "^2.17.0" + simple-get "^3.0.3" + caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" @@ -3390,6 +3447,18 @@ chai@^5.1.1, chai@^5.1.2: loupe "^3.1.0" pathval "^2.0.0" +chalk-template@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/chalk-template/-/chalk-template-0.4.0.tgz#692c034d0ed62436b9062c1707fadcd0f753204b" + integrity sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg== + dependencies: + chalk "^4.1.2" + +chalk@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.0.1.tgz#ca57d71e82bb534a296df63bbacc4a1c22b2a4b6" + integrity sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w== + chalk@^2.1.0: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -3415,6 +3484,11 @@ chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^5.0.1: + version "5.4.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.4.1.tgz#1b48bf0963ec158dce2aacf69c093ae2dd2092d8" + integrity sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w== + chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" @@ -3425,6 +3499,16 @@ check-error@^2.1.1: resolved "https://registry.yarnpkg.com/check-error/-/check-error-2.1.1.tgz#87eb876ae71ee388fa0471fe423f494be1d96ccc" integrity sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw== +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + +cli-boxes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-3.0.0.tgz#71a10c716feeba005e4504f36329ef0b17cf3145" + integrity sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g== + cli-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" @@ -3437,6 +3521,15 @@ cli-width@^3.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== +clipboardy@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-3.0.0.tgz#f3876247404d334c9ed01b6f269c11d09a5e3092" + integrity sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg== + dependencies: + arch "^2.2.0" + execa "^5.1.1" + is-wsl "^2.2.0" + cliui@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" @@ -3485,6 +3578,11 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-support@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + colord@^2.9.3: version "2.9.3" resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43" @@ -3517,6 +3615,26 @@ component-emitter@^1.3.0: resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.1.tgz#ef1d5796f7d93f135ee6fb684340b26403c97d17" integrity sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ== +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -3540,6 +3658,16 @@ confusing-browser-globals@^1.0.10: resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz#ae40e9b57cdd3915408a2805ebd3a5585608dc81" integrity sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA== +console-control-strings@^1.0.0, console-control-strings@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== + +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + integrity sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA== + convert-source-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" @@ -3588,7 +3716,7 @@ cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.1, cross-spawn@^7.0.2: +cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== @@ -3684,6 +3812,13 @@ dayjs@^1.11.12: resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.7: version "4.4.0" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" @@ -3703,6 +3838,13 @@ decimal.js@^10.4.3: resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== +decompress-response@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-4.2.1.tgz#414023cc7a302da25ce2ec82d0d5238ccafd8986" + integrity sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw== + dependencies: + mimic-response "^2.0.0" + deep-eql@^5.0.1: version "5.0.2" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341" @@ -3732,6 +3874,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" @@ -3765,11 +3912,21 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== + dequal@^2.0.2, dequal@^2.0.3: version "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.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700" + integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw== + 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" @@ -3864,6 +4021,11 @@ dunder-proto@^1.0.0, dunder-proto@^1.0.1: es-errors "^1.3.0" gopd "^1.2.0" +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -4543,6 +4705,21 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +execa@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + expect-type@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/expect-type/-/expect-type-1.1.0.tgz#a146e414250d13dfc49eafcfd1344a4060fa4c75" @@ -4845,6 +5022,13 @@ forwarded@0.2.0: resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -4882,6 +5066,21 @@ functions-have-names@^1.2.3: resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== +gauge@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395" + integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== + dependencies: + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.2" + console-control-strings "^1.0.0" + has-unicode "^2.0.1" + object-assign "^4.1.1" + signal-exit "^3.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.2" + gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -4921,6 +5120,11 @@ get-proto@^1.0.0, get-proto@^1.0.1: dunder-proto "^1.0.1" es-object-atoms "^1.0.0" +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + get-symbol-description@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.1.0.tgz#7bdd54e0befe8ffc9f3b4e203220d9f1e881b6ee" @@ -5109,6 +5313,11 @@ has-tostringtag@^1.0.2: dependencies: has-symbols "^1.0.3" +has-unicode@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== + hasown@^2.0.0, hasown@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" @@ -5155,6 +5364,14 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" +https-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== + dependencies: + agent-base "6" + debug "4" + https-proxy-agent@^7.0.5: version "7.0.6" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz#da8dfeac7da130b05c2ba4b59c9b6cd66611a6b9" @@ -5163,6 +5380,11 @@ https-proxy-agent@^7.0.5: agent-base "^7.1.2" debug "4" +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + husky@^9.1.4: version "9.1.7" resolved "https://registry.yarnpkg.com/husky/-/husky-9.1.7.tgz#d46a38035d101b46a70456a850ff4201344c0b2d" @@ -5242,7 +5464,7 @@ inherits@2, inherits@^2.0.3: 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== @@ -5440,6 +5662,11 @@ is-plain-object@^5.0.0: resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== +is-port-reachable@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-port-reachable/-/is-port-reachable-4.0.0.tgz#dac044091ef15319c8ab2f34604d8794181f8c2d" + integrity sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig== + is-potential-custom-element-name@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" @@ -5467,6 +5694,11 @@ is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.4: dependencies: call-bound "^1.0.3" +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + is-string@^1.0.7, is-string@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.1.1.tgz#92ea3f3d5c5b6e039ca8677e5ac8d07ea773cbb9" @@ -5955,6 +6187,13 @@ make-cancellable-promise@^1.3.1: resolved "https://registry.yarnpkg.com/make-cancellable-promise/-/make-cancellable-promise-1.3.2.tgz#993c8c8b79cff13c74fa93de0bd8a17fe66685c1" integrity sha512-GCXh3bq/WuMbS+Ky4JBPW1hYTOU+znU+Q5m9Pu+pI8EoUqIHk9+tviOKC6/qhHh8C4/As3tzJ69IF32kdz85ww== +make-dir@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + make-event-props@^1.6.0: version "1.6.2" resolved "https://registry.yarnpkg.com/make-event-props/-/make-event-props-1.6.2.tgz#c8e0e48eb28b9b808730de38359f6341de7ec5a2" @@ -6009,6 +6248,11 @@ merge-refs@^1.3.0: resolved "https://registry.yarnpkg.com/merge-refs/-/merge-refs-1.3.0.tgz#65d7f8c5058917b9d1fc204ae4b9a727614d0119" integrity sha512-nqXPXbso+1dcKDpPCXvwZyJILz+vSLqGGOnDrYHQYE+B8n9JTCekVLC65AfCpR4ggVyA/45Y0iR9LDyS2iI+zA== +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" @@ -6032,7 +6276,24 @@ mime-db@1.52.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@~2.1.19: +"mime-db@>= 1.43.0 < 2": + version "1.53.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.53.0.tgz#3cb63cd820fc29896d9d4e8c32ab4fcd74ccb447" + integrity sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg== + +mime-db@~1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" + integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ== + +mime-types@2.1.18: + version "2.1.18" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" + integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ== + dependencies: + mime-db "~1.33.0" + +mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -6049,12 +6310,17 @@ 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@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43" + integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA== + 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" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== -minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@3.1.2, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -6073,6 +6339,26 @@ minimist@^1.2.0, minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== +minipass@^3.0.0: + version "3.3.6" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" + integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== + dependencies: + yallist "^4.0.0" + +minipass@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" + integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== + +minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + mkdirp@^0.5.1: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" @@ -6080,6 +6366,11 @@ mkdirp@^0.5.1: dependencies: minimist "^1.2.6" +mkdirp@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + mnemonist@0.38.3: version "0.38.3" resolved "https://registry.yarnpkg.com/mnemonist/-/mnemonist-0.38.3.tgz#35ec79c1c1f4357cfda2fe264659c2775ccd7d9d" @@ -6111,6 +6402,11 @@ mrmime@^2.0.0: resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-2.0.0.tgz#151082a6e06e59a9a39b46b3e14d5cfe92b3abb4" integrity sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw== +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" @@ -6121,6 +6417,11 @@ mute-stream@0.0.8: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== +nan@^2.17.0: + version "2.22.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.22.0.tgz#31bc433fc33213c97bad36404bb68063de604de3" + integrity sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw== + nanoid@^3.3.7: version "3.3.8" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf" @@ -6131,6 +6432,11 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -6154,6 +6460,13 @@ nmtree@^1.0.6: dependencies: commander "^2.11.0" +node-fetch@^2.6.7: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + node-ical@^0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/node-ical/-/node-ical-0.18.0.tgz#919ab65f43cdfebb4ac9a1c2acca2b5e62cc003f" @@ -6169,11 +6482,35 @@ node-releases@^2.0.19: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== +nopt@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" + integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== + dependencies: + abbrev "1" + normalize-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +npmlog@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" + integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== + dependencies: + are-we-there-yet "^2.0.0" + console-control-strings "^1.1.0" + gauge "^3.0.0" + set-blocking "^2.0.0" + nwsapi@^2.2.12: version "2.2.16" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.16.tgz#177760bba02c351df1d2644e220c31dfec8cdb43" @@ -6272,14 +6609,19 @@ on-exit-leak-free@^2.1.0: resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz#fed195c9ebddb7d9e4c3842f93f281ac8dadd3b8" integrity sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA== -once@^1.3.0, once@^1.4.0: +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" -onetime@^5.1.0: +onetime@^5.1.0, onetime@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== @@ -6381,12 +6723,17 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== +path-is-inside@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w== + path-key@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== -path-key@^3.1.0: +path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== @@ -6396,6 +6743,11 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-to-regexp@3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-3.3.0.tgz#f7f31d32e8518c2660862b644414b6d5c63a611b" + integrity sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw== + path-to-regexp@^8.1.0: version "8.2.0" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-8.2.0.tgz#73990cc29e57a3ff2a0d914095156df5db79e8b4" @@ -6406,6 +6758,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@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" @@ -6416,12 +6773,13 @@ pathval@^2.0.0: resolved "https://registry.yarnpkg.com/pathval/-/pathval-2.0.0.tgz#7e2550b422601d4f6b8e26f1301bc8f15a741a25" integrity sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA== -pdfjs-dist@4.8.69, pdfjs-dist@^4.5.136, pdfjs-dist@^4.6.82, pdfjs-dist@^4.8.69: - version "4.10.38" - resolved "https://registry.yarnpkg.com/pdfjs-dist/-/pdfjs-dist-4.10.38.tgz#3ee698003790dc266cc8b55c0e662ccb9ae18f53" - integrity sha512-/Y3fcFrXEAsMjJXeL9J8+ZG9U01LbuWaYypvDW2ycW1jL269L3js3DVBjDJ0Up9Np1uqDXsDrRihHANhZOlwdQ== +pdfjs-dist@4.5.136, pdfjs-dist@4.8.69, pdfjs-dist@^4.5.136, pdfjs-dist@^4.6.82: + version "4.5.136" + resolved "https://registry.yarnpkg.com/pdfjs-dist/-/pdfjs-dist-4.5.136.tgz#4c6f67252d4e23212f43b36537a142171ebfb1ca" + integrity sha512-V1BALcAN/FmxBEShLxoP73PlQZAZtzlaNfRbRhJrKvXzjLC5VaIlBAQUJuWP8iaYUmIdmdLHmt3E2TBglxOm3w== optionalDependencies: - "@napi-rs/canvas" "^0.1.65" + canvas "^2.11.2" + path2d "^0.2.1" performance-now@^2.1.0: version "2.1.0" @@ -6688,6 +7046,21 @@ random-bytes@~1.0.0: resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b" integrity sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ== +range-parser@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + integrity sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A== + +rc@^1.0.1, rc@^1.1.6: + 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.2.2" resolved "https://registry.yarnpkg.com/react-docgen-typescript/-/react-docgen-typescript-2.2.2.tgz#4611055e569edc071204aadb20e1c93e1ab1659c" @@ -6836,6 +7209,15 @@ react-transition-group@4.4.5: dependencies: loose-envify "^1.1.0" +readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + real-require@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/real-require/-/real-require-0.2.0.tgz#209632dea1810be2ae063a6ac084fee7e33fba78" @@ -6896,6 +7278,21 @@ regexpp@^2.0.1: resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== +registry-auth-token@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20" + integrity sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ== + dependencies: + rc "^1.1.6" + safe-buffer "^5.0.1" + +registry-url@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" + integrity sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA== + dependencies: + rc "^1.0.1" + request@^2.88.2: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" @@ -7091,7 +7488,12 @@ safe-array-concat@^1.1.3: has-symbols "^1.1.0" isarray "^2.0.5" -safe-buffer@^5.0.1, safe-buffer@^5.1.2: +safe-buffer@5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -7154,16 +7556,51 @@ semver@^5.5.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@^6.1.2, semver@^6.3.0, semver@^6.3.1: +semver@^6.0.0, semver@^6.1.2, semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.5.4, semver@^7.6.0, semver@^7.6.2, semver@^7.6.3: +semver@^7.3.5, semver@^7.5.4, semver@^7.6.0, semver@^7.6.2, semver@^7.6.3: version "7.6.3" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== +serve-handler@6.1.6: + version "6.1.6" + resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.6.tgz#50803c1d3e947cd4a341d617f8209b22bd76cfa1" + integrity sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ== + dependencies: + bytes "3.0.0" + content-disposition "0.5.2" + mime-types "2.1.18" + minimatch "3.1.2" + path-is-inside "1.0.2" + path-to-regexp "3.3.0" + range-parser "1.2.0" + +serve@^14.2.4: + version "14.2.4" + resolved "https://registry.yarnpkg.com/serve/-/serve-14.2.4.tgz#ba4c425c3c965f496703762e808f34b913f42fb0" + integrity sha512-qy1S34PJ/fcY8gjVGszDB3EXiPSk5FKhUa7tQe0UPRddxRidc2V6cNHPNewbE1D7MAkgLuWEt3Vw56vYy73tzQ== + dependencies: + "@zeit/schemas" "2.36.0" + ajv "8.12.0" + arg "5.0.2" + boxen "7.0.0" + chalk "5.0.1" + chalk-template "0.4.0" + clipboardy "3.0.0" + compression "1.7.4" + is-port-reachable "4.0.0" + serve-handler "6.1.6" + update-check "1.5.4" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + set-cookie-parser@^2.6.0: version "2.7.1" resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz#3016f150072202dfbe90fadee053573cc89d2943" @@ -7274,7 +7711,7 @@ siginfo@^2.0.0: resolved "https://registry.yarnpkg.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30" integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g== -signal-exit@^3.0.2: +signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -7284,6 +7721,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@^3.0.3: + version "3.1.1" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.1.1.tgz#cc7ba77cfbe761036fbfce3d021af25fc5584d55" + integrity sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA== + dependencies: + decompress-response "^4.2.0" + once "^1.3.1" + simple-concat "^1.0.0" + sinon@^18.0.1: version "18.0.1" resolved "https://registry.yarnpkg.com/sinon/-/sinon-18.0.1.tgz#464334cdfea2cddc5eda9a4ea7e2e3f0c7a91c5e" @@ -7419,6 +7870,15 @@ storybook@^8.2.8: dependencies: "@storybook/core" "8.4.7" +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" @@ -7428,14 +7888,14 @@ string-width@^3.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" string.prototype.includes@^2.0.1: version "2.0.1" @@ -7505,6 +7965,13 @@ string.prototype.trimstart@^1.0.8: define-properties "^1.2.1" es-object-atoms "^1.0.0" +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" @@ -7519,11 +7986,23 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + strip-indent@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" @@ -7543,6 +8022,11 @@ strip-json-comments@^3.0.1, strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +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== + strnum@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db" @@ -7761,6 +8245,18 @@ tapable@^2.2.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== +tar@^6.1.11: + version "6.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" + integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^5.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -7865,6 +8361,11 @@ tr46@^5.0.0: dependencies: punycode "^2.3.1" +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + tree-kill@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" @@ -7985,7 +8486,7 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -type-fest@^2.19.0: +type-fest@^2.13.0, type-fest@^2.19.0: version "2.19.0" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== @@ -8102,6 +8603,14 @@ update-browserslist-db@^1.1.1: escalade "^3.2.0" picocolors "^1.1.0" +update-check@1.5.4: + version "1.5.4" + resolved "https://registry.yarnpkg.com/update-check/-/update-check-1.5.4.tgz#5b508e259558f1ad7dbc8b4b0457d4c9d28c8743" + integrity sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ== + dependencies: + registry-auth-token "3.3.2" + registry-url "3.1.0" + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -8149,7 +8658,7 @@ use-sidecar@^1.1.2: detect-node-es "^1.1.0" tslib "^2.0.0" -util-deprecate@^1.0.2: +util-deprecate@^1.0.1, util-deprecate@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== @@ -8190,6 +8699,11 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz#cdada8bec61e15865f05d097c5f4fd30e94dc128" integrity sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw== +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + verror@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" @@ -8270,6 +8784,11 @@ warning@^4.0.0: dependencies: loose-envify "^1.0.0" +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + webidl-conversions@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" @@ -8300,6 +8819,14 @@ whatwg-url@^14.0.0: tr46 "^5.0.0" webidl-conversions "^7.0.0" +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + which-boxed-primitive@^1.0.2, which-boxed-primitive@^1.1.0, which-boxed-primitive@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz#d76ec27df7fa165f18d5808374a5fe23c29b176e" @@ -8374,6 +8901,20 @@ why-is-node-running@^2.3.0: siginfo "^2.0.0" stackback "0.0.2" +wide-align@^1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" + integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== + dependencies: + string-width "^1.0.2 || 2 || 3 || 4" + +widest-line@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-4.0.1.tgz#a0fc673aaba1ea6f0a0d35b3c2795c9a9cc2ebf2" + integrity sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig== + dependencies: + string-width "^5.0.1" + word-wrap@^1.2.5, word-wrap@~1.2.3: version "1.2.5" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" @@ -8388,6 +8929,15 @@ wrap-ansi@^7.0.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^8.0.1: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" From b4a35a26a8c04113bb3cf7982b708c6e5837b10a Mon Sep 17 00:00:00 2001 From: Dev Singh Date: Mon, 6 Jan 2025 19:53:06 +0000 Subject: [PATCH 8/9] add panel --- src/ui/pages/iam/GroupMemberManagement.tsx | 142 +++++++++++++-------- src/ui/pages/iam/ManageIam.page.tsx | 7 +- 2 files changed, 94 insertions(+), 55 deletions(-) diff --git a/src/ui/pages/iam/GroupMemberManagement.tsx b/src/ui/pages/iam/GroupMemberManagement.tsx index d41f26c2..7b33d215 100644 --- a/src/ui/pages/iam/GroupMemberManagement.tsx +++ b/src/ui/pages/iam/GroupMemberManagement.tsx @@ -8,12 +8,11 @@ import { Modal, List, ListItem, - Alert, - ActionIcon, ScrollArea, Badge, + ActionIcon, } from '@mantine/core'; -import { IconTrash, IconCheck, IconX } from '@tabler/icons-react'; +import { IconTrash, IconUserPlus } from '@tabler/icons-react'; import { notifications } from '@mantine/notifications'; import { GroupMemberGetResponse, EntraActionResponse } from '@common/types/iam'; @@ -29,17 +28,9 @@ export const GroupMemberManagement: React.FC = ({ const [members, setMembers] = useState([]); const [toAdd, setToAdd] = useState([]); const [toRemove, setToRemove] = useState([]); - const [results, setResults] = useState< - { email: string; status: 'success' | 'failure'; message?: string }[] - >([]); - const [email, setEmail] = useState(''); - const [isLoading, setIsLoading] = useState(false); - const [confirmationModal, setConfirmationModal] = useState(false); - const [errorModal, setErrorModal] = useState<{ open: boolean; email: string; message: string }>({ - open: false, - email: '', - message: '', - }); + const [email, setEmail] = useState(''); + const [isLoading, setIsLoading] = useState(false); + const [confirmationModal, setConfirmationModal] = useState(false); useEffect(() => { const loadMembers = async () => { @@ -61,9 +52,14 @@ export const GroupMemberManagement: React.FC = ({ if (email && !members.some((member) => member.email === email) && !toAdd.includes(email)) { setToAdd((prev) => [...prev, email]); setEmail(''); + } else { + notifications.show({ + title: 'Invalid Input', + message: 'Email is missing or the user already exists.', + color: 'orange', + }); } }; - const handleRemoveMember = (email: string) => { if (!toRemove.includes(email)) { setToRemove((prev) => [...prev, email]); @@ -72,23 +68,27 @@ export const GroupMemberManagement: React.FC = ({ const handleSaveChanges = async () => { setIsLoading(true); - const newResults: { email: string; status: 'success' | 'failure'; message?: string }[] = []; - try { const response = await updateMembers(toAdd, toRemove); - response.success?.forEach(({ email }) => { - newResults.push({ email, status: 'success' }); - }); - response.failure?.forEach(({ email, message }) => { - newResults.push({ email, status: 'failure', message }); + if (response.success) { + setMembers((prev) => + prev + .filter((member) => !toRemove.includes(member.email)) + .concat(toAdd.map((email) => ({ name: '', email }))) + ); + setToAdd([]); + setToRemove([]); + } + + notifications.show({ + title: 'Success', + message: 'Changes saved successfully!', + color: 'green', }); - setResults(newResults); - setToAdd([]); - setToRemove([]); } catch (error) { notifications.show({ title: 'Error', - message: 'An error occurred while saving changes.', + message: 'Failed to save changes.', color: 'red', }); } finally { @@ -96,14 +96,10 @@ export const GroupMemberManagement: React.FC = ({ } }; - const handleViewErrorDetails = (email: string, message: string) => { - setErrorModal({ open: true, email, message }); - }; - return ( - Group Member Management + Exec Group Management {/* Member List */} @@ -111,12 +107,21 @@ export const GroupMemberManagement: React.FC = ({ Current Members - - + + {members.map((member) => ( - {member.email} + + + {member.name} ({member.email}) + + {toRemove.includes(member.email) && ( + + Queued for removal + + )} + = ({ ))} + {toAdd.map((member) => ( + + + + {member} + + Queued for addition + + + + + ))} + {/* Add Member */} + + setEmail(e.currentTarget.value)} + placeholder="Enter email" + label="Add Member" + /> + + + {/* Save Changes Button */}