From fb1290dacfbc8497e17851d812aaf438009dbc95 Mon Sep 17 00:00:00 2001 From: xHyroM Date: Sun, 9 Apr 2023 13:23:41 +0200 Subject: [PATCH] feat: redis api client, serialization --- apps/redis-api/scripts/build.mjs | 4 +- packages/bot/package.json | 1 + packages/bot/src/commands/setup.ts | 72 +- packages/bot/src/components/setup.ts | 138 ++-- packages/bot/src/index.ts | 12 +- packages/bot/src/modals/setup.ts | 115 ++- packages/bot/src/structs/Command.ts | 2 +- packages/bot/src/structs/Component.ts | 2 +- packages/bot/src/structs/Modal.ts | 2 +- .../src/structs/contexts/ComponentContext.ts | 7 +- packages/bot/src/structs/contexts/Context.ts | 4 + .../bot/src/structs/contexts/ModalContext.ts | 7 +- packages/bot/src/{registers.ts => things.ts} | 6 + packages/bot/src/types.d.ts | 2 + packages/bot/src/utils/returnRoleLpe.ts | 38 +- packages/bot/src/utils/verify.ts | 2 + packages/redis-api-client/LICENSE | 21 + packages/redis-api-client/README.md | 1 + packages/redis-api-client/package.json | 14 + packages/redis-api-client/scripts/build.mjs | 38 + packages/redis-api-client/src/index.ts | 70 ++ packages/redis-api-client/tsconfig.json | 15 + packages/serialize/LICENSE | 215 +----- packages/serialize/README.md | 2 +- packages/serialize/package.json | 8 +- packages/serialize/scripts/build.mjs | 4 +- packages/serialize/src/BitBuffer.ts | 93 --- packages/serialize/src/BitSerializer.ts | 42 -- packages/serialize/src/custom-id.ts | 42 -- packages/serialize/src/index.ts | 46 +- packages/serialize/src/serializers.ts | 352 ---------- packages/serialize/src/utils.ts | 18 - pnpm-lock.yaml | 657 +++++++++++++++--- test.txt | 0 34 files changed, 1035 insertions(+), 1017 deletions(-) rename packages/bot/src/{registers.ts => things.ts} (72%) create mode 100644 packages/redis-api-client/LICENSE create mode 100644 packages/redis-api-client/README.md create mode 100644 packages/redis-api-client/package.json create mode 100644 packages/redis-api-client/scripts/build.mjs create mode 100644 packages/redis-api-client/src/index.ts create mode 100644 packages/redis-api-client/tsconfig.json delete mode 100644 packages/serialize/src/BitBuffer.ts delete mode 100644 packages/serialize/src/BitSerializer.ts delete mode 100644 packages/serialize/src/custom-id.ts delete mode 100644 packages/serialize/src/serializers.ts delete mode 100644 packages/serialize/src/utils.ts create mode 100644 test.txt diff --git a/apps/redis-api/scripts/build.mjs b/apps/redis-api/scripts/build.mjs index fb155f6..cba84cb 100644 --- a/apps/redis-api/scripts/build.mjs +++ b/apps/redis-api/scripts/build.mjs @@ -39,11 +39,11 @@ Promise.all([ }), ]) .catch((err) => { - console.error("Builders failed to build"); + console.error("Redis api failed to build"); console.error(err.message); }) .then(() => { console.log( - watch ? "Waiting for your changes..." : "Builders has been built", + watch ? "Waiting for your changes..." : "Redis api has been built", ); }); diff --git a/packages/bot/package.json b/packages/bot/package.json index dd76474..9af5472 100644 --- a/packages/bot/package.json +++ b/packages/bot/package.json @@ -23,6 +23,7 @@ "dependencies": { "builders": "workspace:*", "serialize": "workspace:*", + "redis-api-client": "workspace:*", "discord-api-types": "^0.37.37" } } diff --git a/packages/bot/src/commands/setup.ts b/packages/bot/src/commands/setup.ts index 6a1a5ef..82e98d8 100644 --- a/packages/bot/src/commands/setup.ts +++ b/packages/bot/src/commands/setup.ts @@ -1,39 +1,61 @@ import { Command } from "../structs/Command"; import { + APIRole, ChannelType, - InteractionResponseType, MessageFlags, + RouteBases, + Routes, } from "discord-api-types/v10"; import { ActionRowBuilder, ChannelSelectMenuBuilder } from "builders"; -import { serializers } from "serialize"; +import { REDIS } from "../things"; +import { encodeToHex } from "serialize"; // Part 1 ## select channel new Command({ name: "setup", - acknowledge: false, + flags: MessageFlags.Ephemeral, run: async (ctx) => { - return ctx.respond({ - type: InteractionResponseType.ChannelMessageWithSource, - data: { - content: "Select the channel to which the panel will be sent.", - components: [ - new ActionRowBuilder() - .addComponents( - new ChannelSelectMenuBuilder() - .setCustomId( - serializers.genericObject.encodeCustomId({ - type: "setup:part-channel", - }), - ) - .addChannelTypes( - ChannelType.GuildAnnouncement, - ChannelType.GuildText, - ), - ) - .toJSON(), - ], - flags: MessageFlags.Ephemeral, - }, + if (!ctx.guildId) + return await ctx.editReply({ + content: "Guild not found.", + }); + + // Delete the data if it exists + await REDIS.del(`roles-bot-setup:${ctx.guildId}`); + + const roles = (await ( + await fetch(`${RouteBases.api}${Routes.guildRoles(ctx.guildId)}`, { + headers: { + Authorization: `Bot ${ctx.env.token}`, + }, + }) + ).json()) as APIRole[]; + + await REDIS.setex( + `roles-bot-setup-roles:${ctx.guildId}`, + encodeToHex( + roles.map((r) => ({ + id: r.id, + name: r.name, + })), + ), + 3600, + ); + + await ctx.editReply({ + content: "Select the channel to which the panel will be sent.", + components: [ + new ActionRowBuilder() + .addComponents( + new ChannelSelectMenuBuilder() + .setCustomId("setup:part-channel") + .addChannelTypes( + ChannelType.GuildAnnouncement, + ChannelType.GuildText, + ), + ) + .toJSON(), + ], }); }, }); diff --git a/packages/bot/src/components/setup.ts b/packages/bot/src/components/setup.ts index 71b2c2d..00fc396 100644 --- a/packages/bot/src/components/setup.ts +++ b/packages/bot/src/components/setup.ts @@ -12,17 +12,32 @@ import { MessageFlags, TextInputStyle, } from "discord-api-types/v10"; -import { serializers } from "serialize"; import returnRoleLpe from "../utils/returnRoleLpe"; +import { REDIS } from "../things"; +import { encodeToHex, decodeFromString } from "serialize"; // Part 2 Channels ## select button/dropdowns new Component({ id: "setup:part-channel", flags: MessageFlags.Ephemeral, run: async (ctx) => { + if (!ctx.interaction.guild_id) + return await ctx.editReply({ + content: "Guild not found.", + }); + const interaction = ctx.interaction as APIMessageComponentSelectMenuInteraction; - const channelId = interaction.data.values[0]; + + const data = { + channelId: interaction.data.values[0], + }; + + await REDIS.setex( + `roles-bot-setup:${interaction.guild_id}`, + encodeToHex(data), + 600, + ); await ctx.editReply({ content: @@ -32,27 +47,11 @@ new Component({ .addComponents( new ButtonBuilder() .setLabel("Buttons") - .setCustomId( - serializers.genericObject.encodeCustomId({ - type: "setup:part-selecting", - data: { - channelId, - selecting: 1, - }, - }), - ) + .setCustomId("setup:part-selecting:buttons") .setStyle(ButtonStyle.Primary), new ButtonBuilder() .setLabel("Dropdowns") - .setCustomId( - serializers.genericObject.encodeCustomId({ - type: "setup:part-selecting", - data: { - channelId, - selecting: 2, - }, - }), - ) + .setCustomId("setup:part-selecting:dropdowns") .setStyle(ButtonStyle.Primary), ) .toJSON(), @@ -66,7 +65,25 @@ new Component({ id: "setup:part-selecting", flags: MessageFlags.Ephemeral, run: async (ctx) => { - const data = ctx.decodedId.data; + if (!ctx.interaction.guild_id) + return await ctx.editReply({ content: "Guild not found." }); + + const rawData = await REDIS.get( + `roles-bot-setup:${ctx.interaction.guild_id}`, + ); + if (!rawData) + return await ctx.editReply({ + content: "Data not found. Try running setup again.", + }); + + const data = decodeFromString(rawData); + data.selecting = ctx.interaction.data.custom_id.split(":")[2]; + + await REDIS.setex( + `roles-bot-setup:${ctx.interaction.guild_id}`, + encodeToHex(data), + 600, + ); await ctx.editReply({ content: "Select the roles that will be available in the menu.", @@ -74,12 +91,7 @@ new Component({ new ActionRowBuilder() .addComponents( new RoleSelectMenuBuilder() - .setCustomId( - serializers.genericObject.encodeCustomId({ - type: "setup:part-roles", - data, - }), - ) + .setCustomId("setup:part-roles") .setPlaceholder("Select roles") .setMinValues(1) .setMaxValues(25), @@ -94,23 +106,41 @@ new Component({ new Component({ id: "setup:part-roles", acknowledge: false, - run: (ctx) => { - const previousData = ctx.decodedId.data; + run: async (ctx) => { + if (!ctx.interaction.guild_id) + return await ctx.editReply({ content: "Guild not found." }); + const interaction = ctx.interaction as APIMessageComponentSelectMenuInteraction; - const rawRoleIds = - (previousData.rawRoleIds as string[]) ?? interaction.data.values; - const data = { ...previousData, rawRoleIds }; + const rawData = await REDIS.get( + `roles-bot-setup:${ctx.interaction.guild_id}`, + ); + if (!rawData) + return ctx.respond({ + type: InteractionResponseType.ChannelMessageWithSource, + data: { + content: "Data not found. Try running setup again.", + flags: MessageFlags.Ephemeral, + }, + }); + + const data = decodeFromString(rawData); + const rawRoleIds = (data.rawRoleIds as string[]) ?? interaction.data.values; + + data.rawRoleIds = rawRoleIds; + + await REDIS.setex( + `roles-bot-setup:${ctx.interaction.guild_id}`, + encodeToHex(data), + 600, + ); return rawRoleIds.length > 0 - ? returnRoleLpe(data, ctx, rawRoleIds[0]) + ? returnRoleLpe(ctx, rawRoleIds[0]) : ctx.returnModal({ title: "Message Preview", - custom_id: serializers.genericObject.encodeCustomId({ - type: "setup:part-messageContent", - data, - }), + custom_id: "setup:part-messageContent", components: [ new ActionRowBuilder() .addComponents( @@ -166,30 +196,38 @@ new Component({ id: "setup:part-sendAs", acknowledge: false, run: async (ctx) => { - const channelId = ctx.decodedId.data.channelId; - const selecting = - ctx.decodedId.data.selecting === 1 ? "buttons" : "dropdowns"; - const roleIds = ctx.decodedId.data.roleIds as { - label: string; - placeholder: string; - emoji: string; - }[]; - const message = ctx.decodedId.data.message; - const sendAs = ctx.decodedId.data.sendAs === 1 ? "webhook" : "bot"; + if (!ctx.interaction.guild_id) + return await ctx.editReply({ content: "Guild not found." }); - console.log(channelId, roleIds, message, sendAs); + const rawData = await REDIS.get( + `roles-bot-setup:${ctx.interaction.guild_id}`, + ); + if (!rawData) + return ctx.respond({ + type: InteractionResponseType.ChannelMessageWithSource, + data: { + content: "Data not found. Try running setup again.", + flags: MessageFlags.Ephemeral, + }, + }); + + const data = decodeFromString(rawData); + console.log(data); + + // delete data + await REDIS.del(`roles-bot-setup:${ctx.guildId}`); // TODO: finish sending const actionRow = new ActionRowBuilder(); - switch (selecting) { + /*switch (selecting) { case "buttons": { // TOOD: finish } case "dropdowns": { // TODO: finish } - } + }*/ return ctx.respond({ type: InteractionResponseType.ChannelMessageWithSource, diff --git a/packages/bot/src/index.ts b/packages/bot/src/index.ts index fc043af..42f0ef8 100644 --- a/packages/bot/src/index.ts +++ b/packages/bot/src/index.ts @@ -10,7 +10,7 @@ import { InteractionResponseType, InteractionType, } from "discord-api-types/v10"; -import { COMMANDS, COMPONENTS, MODALS } from "./registers"; +import { COMMANDS, COMPONENTS, MODALS, REDIS, setRedis } from "./things"; import { verify } from "./utils/verify"; import respond from "./utils/respond"; import { CommandContext } from "./structs/contexts/CommandContext"; @@ -20,6 +20,8 @@ import { Env } from "./types"; export default { fetch: async (request: Request, env: Env) => { + if (!REDIS) setRedis(env.redisApiClientKey, env.redisApiClientHost); + if ( !request.headers.get("X-Signature-Ed25519") || !request.headers.get("X-Signature-Timestamp") @@ -66,7 +68,9 @@ export default { } case InteractionType.ModalSubmit: { const context = new ModalContext(interaction, env); - const modal = MODALS.find((md) => md.id === context.decodedId.type); + const modal = MODALS.find((md) => + context.interaction.data.custom_id.startsWith(md.id), + ); if (!modal) return new Response("Unknown modal", { status: 404 }); @@ -88,8 +92,8 @@ export default { } case InteractionType.MessageComponent: { const context = new ComponentContext(interaction, env); - const component = COMPONENTS.find( - (cmp) => cmp.id === context.decodedId.type, + const component = COMPONENTS.find((cmp) => + context.interaction.data.custom_id.startsWith(cmp.id), ); if (!component) diff --git a/packages/bot/src/modals/setup.ts b/packages/bot/src/modals/setup.ts index 6b10d91..67d040c 100644 --- a/packages/bot/src/modals/setup.ts +++ b/packages/bot/src/modals/setup.ts @@ -5,16 +5,24 @@ import { } from "discord-api-types/v10"; import { Modal } from "../structs/Modal"; import { ActionRowBuilder, ButtonBuilder } from "builders"; -import { serializers } from "serialize"; +import { encodeToHex, decodeFromString } from "serialize"; +import { REDIS } from "../things"; // Part 5 Roles ## add label, placeholder, emoji OR message content new Modal({ id: "setup:part-roles-lpe", - acknowledge: false, run: async (ctx) => { - const previousData = ctx.decodedId.data; - const rawRoleIds = previousData.rawRoleIds as string[]; - const roleIds = (previousData.roleIds ?? []) as { + const rawData = await REDIS.get( + `roles-bot-setup:${ctx.interaction.guild_id}`, + ); + if (!rawData) + return await ctx.editReply({ + content: "Data not found. Try running setup again.", + }); + + const data = decodeFromString(rawData); + const rawRoleIds = data.rawRoleIds as string[]; + const roleIds = (data.roleIds ?? []) as { label: string; placeholder: string; emoji: string; @@ -27,34 +35,29 @@ new Modal({ roleIds.push({ label, placeholder, emoji }); rawRoleIds.shift(); - previousData.rawRoleIds = rawRoleIds; - const data = { ...previousData, roleIds }; + data.rawRoleIds = rawRoleIds; - return ctx.respond({ - type: InteractionResponseType.ChannelMessageWithSource, - data: { - content: - rawRoleIds.length > 0 - ? "Click the button to set the label, placeholder and emoji for next role." - : "Click the button to set message content or embed.", - components: [ - new ActionRowBuilder() - .addComponents( - new ButtonBuilder() - .setLabel( - rawRoleIds.length > 0 ? "Next Role" : "Message Content", - ) - .setCustomId( - serializers.genericObject.encodeCustomId({ - type: "setup:part-roles", - data, - }), - ) - .setStyle(ButtonStyle.Primary), - ) - .toJSON(), - ], - }, + await REDIS.setex( + `roles-bot-setup:${ctx.interaction.guild_id}`, + encodeToHex(data), + 600, + ); + + return await ctx.editReply({ + content: + rawRoleIds.length > 0 + ? "Click the button to set the label, placeholder and emoji for next role." + : "Click the button to set message content or embed.", + components: [ + new ActionRowBuilder() + .addComponents( + new ButtonBuilder() + .setLabel(rawRoleIds.length > 0 ? "Next Role" : "Message Content") + .setCustomId("setup:part-roles") + .setStyle(ButtonStyle.Primary), + ) + .toJSON(), + ], }); }, }); @@ -64,15 +67,22 @@ new Modal({ id: "setup:part-messageContent", flags: MessageFlags.Ephemeral, run: async (ctx) => { - const previousData = ctx.decodedId.data; + const rawData = await REDIS.get( + `roles-bot-setup:${ctx.interaction.guild_id}`, + ); + if (!rawData) + return await ctx.editReply({ + content: "Data not found. Try running setup again.", + }); + + const data = decodeFromString(rawData); + const content = ctx.interaction.data.components[0].components[0].value; const embedTitle = ctx.interaction.data.components[1].components[0].value; const embedDescription = ctx.interaction.data.components[2].components[0].value; const embedColor = ctx.interaction.data.components[3].components[0].value; - console.log("asd"); - if (!content && !embedTitle && !embedDescription) { await ctx.editReply({ content: "You must provide a message content or embed.", @@ -82,14 +92,15 @@ new Modal({ return; } - const data = { - ...previousData, - message: { content, embedTitle, embedDescription, embedColor }, - }; + data.message = { content, embedTitle, embedDescription, embedColor }; - console.log("edit"); + await REDIS.setex( + `roles-bot-setup:${ctx.interaction.guild_id}`, + encodeToHex(data), + 600, + ); - const o = await ctx.editReply({ + await ctx.editReply({ content: "Choose whether you want to send the message as a webhook or as a bot.", components: [ @@ -97,33 +108,15 @@ new Modal({ .addComponents( new ButtonBuilder() .setLabel("Webhook") - .setCustomId( - serializers.genericObject.encodeCustomId({ - type: "setup:part-sendAs", - data: { - ...data, - sendAs: 1, - }, - }), - ) + .setCustomId("setup:part-sendAs:webhook") .setStyle(ButtonStyle.Primary), new ButtonBuilder() .setLabel("Bot") - .setCustomId( - serializers.genericObject.encodeCustomId({ - type: "setup:part-sendAs", - data: { - ...data, - sendAs: 2, - }, - }), - ) + .setCustomId("setup:part-sendAs:bot") .setStyle(ButtonStyle.Primary), ) .toJSON(), ], }); - - console.log(data); }, }); diff --git a/packages/bot/src/structs/Command.ts b/packages/bot/src/structs/Command.ts index f014dff..ac0a2ec 100644 --- a/packages/bot/src/structs/Command.ts +++ b/packages/bot/src/structs/Command.ts @@ -1,5 +1,5 @@ import { MessageFlags } from "discord-api-types/v10"; -import { registerCommand } from "../registers"; +import { registerCommand } from "../things"; import { CommandContext } from "./contexts/CommandContext"; interface CommandOptions { diff --git a/packages/bot/src/structs/Component.ts b/packages/bot/src/structs/Component.ts index c6eb902..5e888bd 100644 --- a/packages/bot/src/structs/Component.ts +++ b/packages/bot/src/structs/Component.ts @@ -1,5 +1,5 @@ import { MessageFlags } from "discord-api-types/v10"; -import { registerComponent } from "../registers"; +import { registerComponent } from "../things"; import { ComponentContext } from "./contexts/ComponentContext"; interface ComponentOptions { diff --git a/packages/bot/src/structs/Modal.ts b/packages/bot/src/structs/Modal.ts index 807b65d..b1dc45a 100644 --- a/packages/bot/src/structs/Modal.ts +++ b/packages/bot/src/structs/Modal.ts @@ -1,5 +1,5 @@ import { MessageFlags } from "discord-api-types/v10"; -import { registerModal } from "../registers"; +import { registerModal } from "../things"; import { ModalContext } from "./contexts/ModalContext"; interface ModalOptions { diff --git a/packages/bot/src/structs/contexts/ComponentContext.ts b/packages/bot/src/structs/contexts/ComponentContext.ts index c2cd82e..77e8b9d 100644 --- a/packages/bot/src/structs/contexts/ComponentContext.ts +++ b/packages/bot/src/structs/contexts/ComponentContext.ts @@ -1,18 +1,13 @@ import { APIMessageComponentInteraction } from "discord-api-types/v10"; -import { DeclaredId, Env } from "../../types"; -import { serializers } from "serialize"; +import { Env } from "../../types"; import { Context } from "./Context"; export class ComponentContext extends Context { - public decodedId: DeclaredId; public interaction: APIMessageComponentInteraction; constructor(interaction: APIMessageComponentInteraction, env: Env) { super(interaction, env); - this.decodedId = serializers.genericObject.decodeCustomId( - interaction.data.custom_id, - ) as DeclaredId; this.interaction = interaction; } } diff --git a/packages/bot/src/structs/contexts/Context.ts b/packages/bot/src/structs/contexts/Context.ts index a05f2be..3f1d8eb 100644 --- a/packages/bot/src/structs/contexts/Context.ts +++ b/packages/bot/src/structs/contexts/Context.ts @@ -18,6 +18,10 @@ export class Context { this.env = env; } + get guildId() { + return this.interaction.guild_id; + } + public respond = respond; public async editReply(content: APIInteractionResponseCallbackData) { diff --git a/packages/bot/src/structs/contexts/ModalContext.ts b/packages/bot/src/structs/contexts/ModalContext.ts index 2851933..124ce68 100644 --- a/packages/bot/src/structs/contexts/ModalContext.ts +++ b/packages/bot/src/structs/contexts/ModalContext.ts @@ -1,18 +1,13 @@ import { APIModalSubmitInteraction } from "discord-api-types/v10"; -import { DeclaredId, Env } from "../../types"; -import { serializers } from "serialize"; import { Context } from "./Context"; +import { Env } from "../../types"; export class ModalContext extends Context { - public decodedId: DeclaredId; public interaction: APIModalSubmitInteraction; constructor(interaction: APIModalSubmitInteraction, env: Env) { super(interaction, env); - this.decodedId = serializers.genericObject.decodeCustomId( - interaction.data.custom_id, - ) as DeclaredId; this.interaction = interaction; } } diff --git a/packages/bot/src/registers.ts b/packages/bot/src/things.ts similarity index 72% rename from packages/bot/src/registers.ts rename to packages/bot/src/things.ts index f80ae55..dbc53b3 100644 --- a/packages/bot/src/registers.ts +++ b/packages/bot/src/things.ts @@ -1,3 +1,4 @@ +import { RedisAPIClient } from "redis-api-client"; import { Command } from "./structs/Command"; import { Component } from "./structs/Component"; import { Modal } from "./structs/Modal"; @@ -5,6 +6,11 @@ import { Modal } from "./structs/Modal"; export const COMMANDS: Command[] = []; export const COMPONENTS: Component[] = []; export const MODALS: Modal[] = []; +export let REDIS: RedisAPIClient; + +export const setRedis = (apiKey: string, host: string) => { + REDIS = new RedisAPIClient(apiKey, host); +}; export const registerCommand = (command: Command) => { COMMANDS.push(command); diff --git a/packages/bot/src/types.d.ts b/packages/bot/src/types.d.ts index a09ff66..861973d 100644 --- a/packages/bot/src/types.d.ts +++ b/packages/bot/src/types.d.ts @@ -18,4 +18,6 @@ declare type DeclaredId = Record< declare interface Env { publicKey: string; token: string; + redisApiClientKey: string; + redisApiClientHost: string; } diff --git a/packages/bot/src/utils/returnRoleLpe.ts b/packages/bot/src/utils/returnRoleLpe.ts index 9e7c34f..cbbf78f 100644 --- a/packages/bot/src/utils/returnRoleLpe.ts +++ b/packages/bot/src/utils/returnRoleLpe.ts @@ -1,19 +1,33 @@ -import { Generic, serializers } from "serialize"; import { Context } from "../structs/contexts/Context"; import { ActionRowBuilder, TextInputBuilder } from "builders"; -import { TextInputStyle } from "discord-api-types/v10"; +import { + APIRole, + InteractionResponseType, + MessageFlags, + TextInputStyle, +} from "discord-api-types/v10"; +import { REDIS } from "../things"; +import { decodeFromString } from "serialize"; + +export default async function (ctx: Context, rawRole: string) { + const rolesRaw = await REDIS.get(`roles-bot-setup-roles:${ctx.guildId}`); + if (!rolesRaw) + return ctx.respond({ + type: InteractionResponseType.ChannelMessageWithSource, + data: { + content: + "Something went wrong. Please try again.\nIf this problem persists, please contact [Support Server](https://discord.gg/kFPKmEKeMS/).", + flags: MessageFlags.Ephemeral, + }, + }); + + const roles = decodeFromString(rolesRaw) as Partial[]; + + const roleName = roles?.find((r) => r.id === rawRole)?.name; -export default function ( - data: Record, - ctx: Context, - rawRole: string, -) { return ctx.returnModal({ - title: `Role Setup ${rawRole}`, - custom_id: serializers.genericObject.encodeCustomId({ - type: "setup:part-roles-lpe", - data, - }), + title: `${roleName?.slice(0, 39)} Role`, + custom_id: "setup:part-roles-lpe", components: [ new ActionRowBuilder() .addComponents( diff --git a/packages/bot/src/utils/verify.ts b/packages/bot/src/utils/verify.ts index 1c7f77e..bf2adff 100644 --- a/packages/bot/src/utils/verify.ts +++ b/packages/bot/src/utils/verify.ts @@ -2,6 +2,8 @@ "use strict"; +import type { Env } from "../types"; + function hex2bin(hex: string) { const buf = new Uint8Array(Math.ceil(hex.length / 2)); for (let i = 0; i < buf.length; i++) { diff --git a/packages/redis-api-client/LICENSE b/packages/redis-api-client/LICENSE new file mode 100644 index 0000000..92b249a --- /dev/null +++ b/packages/redis-api-client/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Jozef Steinhübl + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/redis-api-client/README.md b/packages/redis-api-client/README.md new file mode 100644 index 0000000..0296dc2 --- /dev/null +++ b/packages/redis-api-client/README.md @@ -0,0 +1 @@ +Client for [Redis API](../../apps/redis-api/) diff --git a/packages/redis-api-client/package.json b/packages/redis-api-client/package.json new file mode 100644 index 0000000..9e65dab --- /dev/null +++ b/packages/redis-api-client/package.json @@ -0,0 +1,14 @@ +{ + "name": "redis-api-client", + "version": "0.0.1", + "author": "xHyroM", + "main": "dist/index.mjs", + "types": "dist/index.d.ts", + "scripts": { + "build": "node scripts/build.mjs && tsc -p tsconfig.json" + }, + "devDependencies": { + "esbuild": "^0.15.11", + "typescript": "^4.8.4" + } +} diff --git a/packages/redis-api-client/scripts/build.mjs b/packages/redis-api-client/scripts/build.mjs new file mode 100644 index 0000000..0e93181 --- /dev/null +++ b/packages/redis-api-client/scripts/build.mjs @@ -0,0 +1,38 @@ +import esbuild from "esbuild"; +import { rmSync, existsSync } from "node:fs"; +import { join } from "node:path"; +import { fileURLToPath } from "node:url"; + +const __dirname = fileURLToPath(new URL(".", import.meta.url)); + +if (existsSync(join(__dirname, "..", "dist"))) + rmSync(join(__dirname, "..", "dist"), { recursive: true }); + +const watch = process.argv.includes("--watch"); +const dev = process.argv.includes("--dev"); + +Promise.all([ + esbuild.build({ + bundle: true, + logLevel: "info", + format: "esm", + mainFields: ["browser", "module", "main"], + platform: "neutral", + target: "es2020", + entryPoints: ["./src/index.ts"], + outfile: "./dist/index.mjs", + sourcemap: dev, + charset: "utf8", + minify: !dev, + watch: watch, + }), +]) + .catch((err) => { + console.error("Builders failed to build"); + console.error(err.message); + }) + .then(() => { + console.log( + watch ? "Waiting for your changes..." : "Builders has been built", + ); + }); diff --git a/packages/redis-api-client/src/index.ts b/packages/redis-api-client/src/index.ts new file mode 100644 index 0000000..07534c5 --- /dev/null +++ b/packages/redis-api-client/src/index.ts @@ -0,0 +1,70 @@ +export class RedisAPIClient { + private apiKey: string; + private host: string; + + constructor(apiKey: string, host: string) { + this.apiKey = apiKey; + this.host = host; + } + + public async get(key: string): Promise { + const url = `${this.host}/get?key=${key}`; + const response = await fetch(url, { + headers: { + Authorization: this.apiKey, + }, + }); + + return response.text(); + } + + public async set(key: string, value: string): Promise { + const url = `${this.host}/set`; + const response = await fetch(url, { + method: "POST", + headers: { + Authorization: this.apiKey, + "Content-Type": "application/json", + }, + body: JSON.stringify({ + key, + value, + }), + }); + + return response.text(); + } + + public async setex( + key: string, + value: string, + seconds: number, + ): Promise { + const url = `${this.host}/setex`; + const response = await fetch(url, { + method: "POST", + headers: { + Authorization: this.apiKey, + "Content-Type": "application/json", + }, + body: JSON.stringify({ + key, + value, + seconds, + }), + }); + + return response.text(); + } + + public async del(key: string): Promise { + const url = `${this.host}/del?key=${key}`; + const response = await fetch(url, { + headers: { + Authorization: this.apiKey, + }, + }); + + return response.text(); + } +} diff --git a/packages/redis-api-client/tsconfig.json b/packages/redis-api-client/tsconfig.json new file mode 100644 index 0000000..05f250f --- /dev/null +++ b/packages/redis-api-client/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "rootDir": "src", + "outDir": "dist", + "target": "ESNext", + "lib": ["ESNext", "WebWorker"], + "module": "ESNext", + "strict": true, + "moduleResolution": "node", + "skipLibCheck": true, + "esModuleInterop": true, + "declaration": true, + "emitDeclarationOnly": true + } +} diff --git a/packages/serialize/LICENSE b/packages/serialize/LICENSE index 5adfeda..92b249a 100644 --- a/packages/serialize/LICENSE +++ b/packages/serialize/LICENSE @@ -1,202 +1,21 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ +MIT License - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +Copyright (c) 2023 Jozef Steinhübl - 1. Definitions. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2021-2022 Dave Caruso - Copyright 2021-2022 CRBT Team - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/serialize/README.md b/packages/serialize/README.md index 1c68b91..09a1d02 100644 --- a/packages/serialize/README.md +++ b/packages/serialize/README.md @@ -1 +1 @@ -[https://github.com/CRBT-Team/Purplet/blob/main/packages/serialize](https://github.com/CRBT-Team/Purplet/blob/main/packages/serialize) +Simple serialization using MessagePack Lite diff --git a/packages/serialize/package.json b/packages/serialize/package.json index 0d240bc..08a9aae 100644 --- a/packages/serialize/package.json +++ b/packages/serialize/package.json @@ -4,13 +4,17 @@ "main": "dist/index.mjs", "types": "dist/index.d.ts", "scripts": { - "build": "node scripts/build.mjs && tsc -p tsconfig.json" + "build": "node scripts/build.mjs && tsc -p tsconfig.json", + "test": "ava" }, "devDependencies": { + "@types/msgpack-lite": "^0.1.8", + "ava": "^5.2.0", "esbuild": "^0.15.11", + "fast-deep-equal": "^3.1.3", "typescript": "^4.8.4" }, "dependencies": { - "@paperdave/utils": "^1.6.1" + "msgpack-lite": "^0.1.26" } } diff --git a/packages/serialize/scripts/build.mjs b/packages/serialize/scripts/build.mjs index 0e93181..b1afb2b 100644 --- a/packages/serialize/scripts/build.mjs +++ b/packages/serialize/scripts/build.mjs @@ -28,11 +28,11 @@ Promise.all([ }), ]) .catch((err) => { - console.error("Builders failed to build"); + console.error("Serialize failed to build"); console.error(err.message); }) .then(() => { console.log( - watch ? "Waiting for your changes..." : "Builders has been built", + watch ? "Waiting for your changes..." : "Serialize has been built", ); }); diff --git a/packages/serialize/src/BitBuffer.ts b/packages/serialize/src/BitBuffer.ts deleted file mode 100644 index 4226aba..0000000 --- a/packages/serialize/src/BitBuffer.ts +++ /dev/null @@ -1,93 +0,0 @@ -export class BitBuffer { - private array: Uint8Array; - private byteIndex = 0; - private bitIndex = 0; - - get index() { - return this.byteIndex * 8 + this.bitIndex; - } - - set index(value: number) { - this.byteIndex = Math.floor(value / 8); - this.bitIndex = value % 8; - } - - get buffer() { - return this.array.buffer; - } - - set buffer(v: ArrayBufferLike) { - this.array = new Uint8Array(v); - } - - constructor( - input: Uint8Array | ArrayBufferLike | ArrayLike | number = 256, - ) { - this.array = new Uint8Array( - input instanceof Uint8Array ? input.buffer : (input as ArrayBufferLike), - ); - } - - seek(index: number) { - this.index = index; - return this; - } - - read(length = 1) { - let result = 0; - for (let i = 0; i < length; i++) { - const bit = (this.array[this.byteIndex] >> this.bitIndex) & 1; - result |= bit << i; - this.bitIndex++; - if (this.bitIndex >= 8) { - this.bitIndex = 0; - this.byteIndex++; - } - } - return result; - } - - write(value: number, length = 1) { - for (let i = 0; i < length; i++) { - const bit = (value >> i) & 1; - this.array[this.byteIndex] |= bit << this.bitIndex; - this.bitIndex++; - if (this.bitIndex >= 8) { - this.bitIndex = 0; - this.byteIndex++; - } - } - return this; - } - - readBI(length = 1) { - let result = 0n; - for (let i = 0n; i < length; i++) { - const bit = (this.array[this.byteIndex] >> this.bitIndex) & 1; - if (bit) { - result |= 1n << i; - } - this.bitIndex++; - if (this.bitIndex >= 8) { - this.bitIndex = 0; - this.byteIndex++; - } - } - return result; - } - - writeBI(value: bigint, length = 1) { - for (let i = 0n; i < length; i++) { - const bit = (value >> i) & 1n; - if (bit) { - this.array[this.byteIndex] |= 1 << this.bitIndex; - } - this.bitIndex++; - if (this.bitIndex >= 8) { - this.bitIndex = 0; - this.byteIndex++; - } - } - return this; - } -} diff --git a/packages/serialize/src/BitSerializer.ts b/packages/serialize/src/BitSerializer.ts deleted file mode 100644 index 5b8f263..0000000 --- a/packages/serialize/src/BitSerializer.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { BitBuffer } from "./BitBuffer"; -import { decodeCustomId, encodeCustomId } from "./custom-id"; - -export interface BitSerializerOptions { - write(value: T, buffer: BitBuffer): void; - read(buffer: BitBuffer): T; - check?(value: unknown): value is T; -} - -export class BitSerializer { - constructor(private options: BitSerializerOptions) {} - - write(value: T, buffer: BitBuffer): void { - this.options.write(value, buffer); - } - - read(buffer: BitBuffer): T { - return this.options.read(buffer); - } - - check(value: unknown): value is T { - return this.options.check?.(value) ?? true; - } - - encode(value: T, bufferLength = 256) { - const buffer = new BitBuffer(bufferLength); - this.options.write(value, buffer); - return new Uint8Array(buffer.buffer.slice(0, Math.ceil(buffer.index / 8))); - } - - decode(value: Uint8Array): T { - return this.options.read(new BitBuffer(value)); - } - - encodeCustomId(value: T, bufferLength = 256) { - return encodeCustomId(this.encode(value, bufferLength)); - } - - decodeCustomId(value: string): T { - return this.decode(decodeCustomId(value)); - } -} diff --git a/packages/serialize/src/custom-id.ts b/packages/serialize/src/custom-id.ts deleted file mode 100644 index 6ae8148..0000000 --- a/packages/serialize/src/custom-id.ts +++ /dev/null @@ -1,42 +0,0 @@ -// using all unicode characters from range 0 to 0x10FFFF, encode two and a half bytes per character -// This is essentially "base1114111" -export function encodeCustomId(data: Uint8Array) { - let output = ""; - for (let i = 0; i < data.length; i += 5) { - const one = data[i]; - const two = data[i + 1]; - const three = data[i + 2]; - const four = data[i + 3]; - const five = data[i + 4]; - - // byte one contains one + two + the least significant bits of three - const codePoint1 = (one << 12) | (two << 4) | (three & 0b1111); - // byte two contains four + five + the most significant bits of three - const codePoint2 = (four << 12) | (five << 4) | (three >> 4); - - output += - String.fromCodePoint(codePoint1) + String.fromCodePoint(codePoint2); - } - - return output; -} - -export function decodeCustomId(data: string) { - const codePoints = [...data]; - const output = new Uint8Array(Math.ceil(codePoints.length * 2.5)); - let j = 0; - - for (let i = 0; i < codePoints.length; i += 2, j += 5) { - // rome-ignore lint/style/noNonNullAssertion: - const codePoint1 = codePoints[i].codePointAt(0)!; - // rome-ignore lint/style/noNonNullAssertion: - const codePoint2 = codePoints[i + 1].codePointAt(0)!; - - output[j] = (codePoint1 >>> 12) & 0xff; - output[j + 1] = (codePoint1 >>> 4) & 0xff; - output[j + 2] = (codePoint1 & 0xf) | ((codePoint2 & 0xf) << 4); - output[j + 3] = (codePoint2 >>> 12) & 0xff; - output[j + 4] = (codePoint2 >>> 4) & 0xff; - } - return output; -} diff --git a/packages/serialize/src/index.ts b/packages/serialize/src/index.ts index 6faa6de..9144fdc 100644 --- a/packages/serialize/src/index.ts +++ b/packages/serialize/src/index.ts @@ -1,5 +1,41 @@ -export { BitSerializer, type BitSerializerOptions } from "./BitSerializer"; -export * as serializers from "./serializers"; -export { BitBuffer } from "./BitBuffer"; -export { type Generic } from "./utils"; -export { decodeCustomId, encodeCustomId } from "./custom-id"; +import msgPack from "msgpack-lite"; + +export const encode = (data: Generic) => msgPack.encode(data); +export const decode = (data: Buffer) => msgPack.decode(data); + +export const encodeToHex = (data: Generic) => + buffer_to_hex(msgPack.encode(data)); +export const decodeFromString = (data: string) => + msgPack.decode(hex_to_buffer(data)); + +function buffer_to_hex(buffer: Buffer) { + return Array.prototype.map + .call(buffer, function (val) { + let hex = val.toString(16).toUpperCase(); + if (val < 16) hex = `0${hex}`; + return hex; + }) + .join(" "); +} + +function hex_to_buffer(string: string) { + return string + .split(/\s+/) + .filter(function (chr) { + return chr !== ""; + }) + .map(function (chr) { + return parseInt(chr, 16); + }); +} + +export type Generic = + | string + | number + | boolean + | bigint + | Date + | null + | undefined + | Generic[] + | { [key: string]: Generic }; diff --git a/packages/serialize/src/serializers.ts b/packages/serialize/src/serializers.ts deleted file mode 100644 index d118615..0000000 --- a/packages/serialize/src/serializers.ts +++ /dev/null @@ -1,352 +0,0 @@ -import type { Dict } from "@paperdave/utils"; -import type { BitBuffer } from "./BitBuffer"; -import { BitSerializer } from "./BitSerializer"; -import type { Generic } from "./utils"; -import { fillArray } from "./utils"; - -/** Creates a serializer that does not read/write any data, but instead return a predefined constant. */ -export function constant(input: T): BitSerializer { - return new BitSerializer({ - read: () => input, - write: () => {}, - check(value): value is T { - return value === input; - }, - }); -} - -const nullSerializer = constant(null); - -/** Serializer for a boolean value. */ -export const boolean = new BitSerializer({ - read(buffer) { - return buffer.read() === 1; - }, - write(value, buffer) { - buffer.write(value ? 1 : 0); - }, - check(value): value is boolean { - return typeof value === "boolean"; - }, -}); - -/** Creates a serializer for unsigned integers, at the given precision. */ -function unsignedInt(bits: number) { - return new BitSerializer({ - read(buffer) { - return buffer.read(bits); - }, - write(value, buffer) { - buffer.write(value, bits); - }, - check(value): value is number { - return ( - typeof value === "number" && - Math.floor(value) === value && - value >= 0 && - value < 1 << bits - ); - }, - }); -} - -/** Creates a serializer for signed integers, at the given precision. */ -function signedInt(bits: number) { - const signBit = -1 << (bits - 1); - return new BitSerializer({ - read(buffer) { - const value = buffer.read(bits); - const sign = buffer.read(); - return value + (sign ? signBit : 0); - }, - write(value, buffer) { - const sign = value < 0; - if (sign) { - value += signBit; - } - buffer.write(value, bits); - buffer.write(sign ? 1 : 0); - }, - check(value): value is number { - return ( - typeof value === "number" && - Math.floor(value) === value && - value >= -(1 << (bits - 1)) && - value < 1 << (bits - 1) - ); - }, - }); -} - -/** Creates a serializer for unsigned BigInts, at the given precision. */ -function unsignedBigInt(bits: number) { - return new BitSerializer({ - read(buffer) { - return buffer.readBI(bits); - }, - write(value, buffer) { - buffer.writeBI(value, bits); - }, - check(value): value is bigint { - return typeof value === "bigint" && value >= 0; - }, - }); -} - -/** Creates a serializer for unsigned floats, at the given precision. */ -function signedBigInt(bits: number) { - const signBit = -1n << (BigInt(bits) - 1n); - return new BitSerializer({ - read(buffer: BitBuffer) { - const value = buffer.readBI(bits); - const sign = buffer.readBI(); - return value + (sign ? signBit : 0n); - }, - write(value, buffer) { - const sign = value < 0; - if (sign) { - value += signBit; - } - buffer.writeBI(value, bits); - buffer.write(sign ? 1 : 0); - }, - check(value): value is bigint { - return typeof value === "bigint"; - }, - }); -} - -/* Serializer for 8-bit unsigned integers. 0 <= n <= 255. */ -export const u8 = unsignedInt(8); -/* Serializer for 16-bit unsigned integers. 0 <= n <= 65535. */ -export const u16 = unsignedInt(16); -/* Serializer for 32-bit unsigned integers. 0 <= n <= 4294967295. */ -export const u32 = unsignedInt(32); -/* Serializer for 8-bit signed integers. -128 <= n <= 127. */ -export const s8 = signedInt(8); -/* Serializer for 16-bit signed integers. -32768 <= n <= 32767. */ -export const s16 = signedInt(16); -/* Serializer for 32-bit signed integers. -2147483648 <= n <= 2147483647. */ -export const s32 = signedInt(32); - -/* Serializer for 8-bit unsigned BigInts. 0n <= n <= 255n. */ -export const u8bi = unsignedBigInt(8); -/* Serializer for 16-bit unsigned BigInts. 0n <= n <= 65535n. */ -export const u16bi = unsignedBigInt(16); -/* Serializer for 32-bit unsigned BigInts. 0n <= n <= 4294967295n. */ -export const u32bi = unsignedBigInt(32); -/* Serializer for 64-bit unsigned BigInts. 0n <= n <= 18446744073709551615n. */ -export const u64bi = unsignedBigInt(64); -/* Serializer for 128-bit unsigned BigInts. 0n <= n <= (39 digits). */ -export const u128bi = unsignedBigInt(128); -/* Serializer for 8-bit signed BigInts. -128n <= n <= 127n. */ -export const s8bi = signedBigInt(8); -/* Serializer for 16-bit signed BigInts. -32768n <= n <= 32767n. */ -export const s16bi = signedBigInt(16); -/* Serializer for 32-bit signed BigInts. -2147483648n <= n <= 2147483647n. */ -export const s32bi = signedBigInt(32); -/* Serializer for 64-bit signed BigInts. -9223372036854775808n <= n <= 9223372036854775807n. */ -export const s64bi = signedBigInt(64); -/* Serializer for 128-bit signed BigInts. -170141183460469231731687303715884105728n <= n <= 170141183460469231731687303715884105727n. */ -export const s128bi = signedBigInt(128); - -/* Serializer for Discord snowflakes, which are u64bi strings. If you have a bigint value, use the `u64bi` serializer instead. */ -export const snowflake = new BitSerializer({ - read(buffer) { - return buffer.readBI(64).toString(); - }, - write(value, buffer) { - buffer.writeBI(BigInt(value), 64); - }, - check(value): value is string { - return typeof value === "string" && /^[0-9]{18,20}$/.test(value); - }, -}); - -/** Serializer for a JavaScript number (IEEE-754/float64) value. */ -export const float = new BitSerializer({ - read(buffer) { - return new Float64Array( - new Uint8Array(fillArray(8, () => buffer.read(8))).buffer, - )[0]; - }, - write(value, buffer) { - const view = new Uint8Array(new Float64Array([value]).buffer); - for (let i = 0; i < 8; i++) { - buffer.write(view[i], 8); - } - }, - check(value): value is number { - return typeof value === "number"; - }, -}); - -/** Serializer for a `Date` value. */ -export const date = new BitSerializer({ - read(buffer) { - return new Date(Number(buffer.readBI(52))); - }, - write(value, buffer) { - buffer.writeBI(BigInt(value.getTime()), 52); - }, - check(value): value is Date { - return value instanceof Date; - }, -}); - -/** Serializer for a string value. Uses a length + content approach, so it does not support lengths above 255. */ -export const string = new BitSerializer({ - read(buffer) { - const length = buffer.read(8); - const bytes = fillArray(length, () => buffer.read(8)); - return new TextDecoder().decode(new Uint8Array(bytes)); - }, - write(value, buffer) { - const bytes = new TextEncoder().encode(value); - if (bytes.length > 255) { - throw new Error( - "String serializer does not support strings over 255 bytes.", - ); - } - buffer.write(bytes.length, 8); - bytes.forEach((byte) => buffer.write(byte, 8)); - }, - check(value): value is string { - return typeof value === "string"; - }, -}); - -/** - * Creates a serializer for an array of values. Uses a length + content approach, so it does not - * support lengths above 255. - */ -export function arrayOf(serializer: BitSerializer) { - return new BitSerializer({ - read(buffer) { - const length = buffer.read(8); - const array = []; - for (let i = 0; i < length; i++) { - array.push(serializer.read(buffer)); - } - return array; - }, - write(value, buffer) { - buffer.write(value.length, 8); - value.forEach((item) => serializer.write(item, buffer)); - }, - // rome-ignore lint/suspicious/noExplicitAny: - check(value): value is any[] { - return ( - Array.isArray(value) && value.every((item) => serializer.check(item)) - ); - }, - }); -} - -/** Creates a serializer out of two other serializers. Uses one bit to tell them apart. */ -export function or(a: BitSerializer, b: BitSerializer) { - return new BitSerializer({ - read(buffer) { - return buffer.read() ? a.read(buffer) : b.read(buffer); - }, - write(value, buffer) { - const isA = a.check(value); - buffer.write(isA ? 1 : 0, 1); - if (isA) { - a.write(value, buffer); - } else { - b.write(value, buffer); - } - }, - check(value): value is A | B { - return a.check(value) || b.check(value); - }, - }); -} - -/** Serializer for numbers, using an extra bit to allow a short s16 when possible, otherwise float64. */ -export const number = or(s16, float); - -export function nullable(serializer: BitSerializer) { - return or(serializer, nullSerializer); -} - -export function object>( - definition: { - [K in keyof T]: BitSerializer; - }, -): BitSerializer { - const keys = Object.keys(definition).sort(); - return new BitSerializer({ - read(buffer) { - const obj = {} as T; - keys.forEach((key) => { - // rome-ignore lint/suspicious/noExplicitAny: - (obj as any)[key] = definition[key].read(buffer) as any; - }); - return obj; - }, - write(value, buffer) { - keys.forEach((key) => { - // rome-ignore lint/suspicious/noExplicitAny: - definition[key].write(value[key] as any, buffer); - }); - }, - check(value): value is T { - return ( - typeof value === "object" && - // rome-ignore lint/suspicious/noExplicitAny: - keys.every((key) => definition[key].check((value as any)[key])) - ); - }, - }); -} - -/** Serializer for an object of `generic` values. */ -export const genericObject = new BitSerializer>({ - read(buffer) { - const obj: Dict = {}; - let key: string = string.read(buffer); - while (key !== "") { - obj[key] = generic.read(buffer); - key = string.read(buffer); - } - return obj; - }, - write(value, buffer) { - Object.keys(value).forEach((key) => { - string.write(key, buffer); - generic.write(value[key], buffer); - }); - string.write("", buffer); - }, - check(value): value is Record { - return ( - value != null && - typeof value === "object" && - Object.keys(value).every( - // rome-ignore lint/suspicious/noExplicitAny: - (key) => string.check(key) && generic.check((value as any)[key]), - ) - ); - }, -}); - -export const genericArray = { - __proto__: BitSerializer.prototype, -} as unknown as BitSerializer; - -/** - * Serializer for the `generic` type, which is all JSON-compatible types, but also including Dates, - * undefined, and bigints up to 128 bits. Discord snowflakes have special treatment here as well, to - * reduce the number of serialized bytes from ~19 to 4 per snowflake. - */ -export const generic: BitSerializer = or( - or(or(snowflake, string), or(constant(null), constant(undefined))), - or( - or(or(or(date, s128bi), boolean), or(genericArray, genericObject)), - number, - ), -); - -Object.assign(genericArray, arrayOf(generic)); diff --git a/packages/serialize/src/utils.ts b/packages/serialize/src/utils.ts deleted file mode 100644 index b7cca8e..0000000 --- a/packages/serialize/src/utils.ts +++ /dev/null @@ -1,18 +0,0 @@ -export function fillArray(length: number, cb: (index: number) => T): T[] { - const arr = new Array(length); - for (let i = 0; i < length; i++) { - arr[i] = cb(i); - } - return arr; -} - -export type Generic = - | string - | number - | boolean - | bigint - | Date - | null - | undefined - | Generic[] - | { [key: string]: Generic }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a64212a..8a033fe 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,57 +8,7 @@ importers: specifier: ^12.0.0 version: 12.0.0 - packages/bot: - dependencies: - builders: - specifier: workspace:* - version: link:../builders - discord-api-types: - specifier: ^0.37.37 - version: 0.37.37 - serialize: - specifier: workspace:* - version: link:../serialize - devDependencies: - '@cloudflare/workers-types': - specifier: ^3.17.0 - version: 3.17.0 - '@types/jest': - specifier: ^29.1.2 - version: 29.1.2 - esbuild: - specifier: ^0.15.11 - version: 0.15.11 - eslint: - specifier: ^8.25.0 - version: 8.25.0 - jest: - specifier: ^29.2.0 - version: 29.2.0 - miniflare: - specifier: ^2.10.0 - version: 2.10.0 - typescript: - specifier: ^4.8.4 - version: 4.8.4 - - packages/builders: - dependencies: - '@discordjs/util': - specifier: ^0.2.0 - version: 0.2.0 - discord-api-types: - specifier: ^0.37.37 - version: 0.37.37 - devDependencies: - esbuild: - specifier: ^0.15.11 - version: 0.15.18 - typescript: - specifier: ^4.8.4 - version: 4.8.4 - - packages/redis-api: + apps/redis-api: dependencies: dotenv: specifier: ^16.0.3 @@ -77,20 +27,7 @@ importers: specifier: ^4.8.4 version: 4.8.4 - packages/serialize: - dependencies: - '@paperdave/utils': - specifier: ^1.6.1 - version: 1.6.1 - devDependencies: - esbuild: - specifier: ^0.15.11 - version: 0.15.11 - typescript: - specifier: ^4.8.4 - version: 4.8.4 - - packages/website: + apps/website: dependencies: '@astrojs/prefetch': specifier: ^0.2.1 @@ -142,6 +79,90 @@ importers: specifier: ^0.2.6 version: 0.2.6(prettier-plugin-astro@0.8.0)(prettier@2.8.7) + packages/bot: + dependencies: + builders: + specifier: workspace:* + version: link:../builders + discord-api-types: + specifier: ^0.37.37 + version: 0.37.37 + redis-api-client: + specifier: workspace:* + version: link:../redis-api-client + serialize: + specifier: workspace:* + version: link:../serialize + devDependencies: + '@cloudflare/workers-types': + specifier: ^3.17.0 + version: 3.17.0 + '@types/jest': + specifier: ^29.1.2 + version: 29.1.2 + esbuild: + specifier: ^0.15.11 + version: 0.15.11 + eslint: + specifier: ^8.25.0 + version: 8.25.0 + jest: + specifier: ^29.2.0 + version: 29.2.0 + miniflare: + specifier: ^2.10.0 + version: 2.10.0 + typescript: + specifier: ^4.8.4 + version: 4.8.4 + + packages/builders: + dependencies: + '@discordjs/util': + specifier: ^0.2.0 + version: 0.2.0 + discord-api-types: + specifier: ^0.37.37 + version: 0.37.37 + devDependencies: + esbuild: + specifier: ^0.15.11 + version: 0.15.18 + typescript: + specifier: ^4.8.4 + version: 4.8.4 + + packages/redis-api-client: + devDependencies: + esbuild: + specifier: ^0.15.11 + version: 0.15.11 + typescript: + specifier: ^4.8.4 + version: 4.8.4 + + packages/serialize: + dependencies: + msgpack-lite: + specifier: ^0.1.26 + version: 0.1.26 + devDependencies: + '@types/msgpack-lite': + specifier: ^0.1.8 + version: 0.1.8 + ava: + specifier: ^5.2.0 + version: 5.2.0 + esbuild: + specifier: ^0.15.11 + version: 0.15.11 + fast-deep-equal: + specifier: ^3.1.3 + version: 3.1.3 + typescript: + specifier: ^4.8.4 + version: 4.8.4 + packages: /@ampproject/remapping@2.2.0: @@ -1373,14 +1394,6 @@ packages: '@nodelib/fs.scandir': 2.1.5 fastq: 1.15.0 - /@paperdave/utils@1.6.1: - resolution: {integrity: sha512-LA9itR/tlnqztz3Scz/fFpQOaQMBrCylEoC5yM2cweUnvxRypCAOkB9TR9EcTI8sx7TlhpzFOFGCzTL5FnWBtQ==} - engines: {bun: '>=0.1.9', node: '>=16'} - dependencies: - utility-types: 3.10.0 - yaml: 2.2.1 - dev: false - /@pkgr/utils@2.3.1: resolution: {integrity: sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} @@ -1592,6 +1605,12 @@ packages: resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} dev: false + /@types/msgpack-lite@0.1.8: + resolution: {integrity: sha512-3qIhe8MH1kGcXnB5YuY6W0lLb9LEcWrhanDYfw0zKdXAv+CNKG0+6To1X8dqVyrxKb3FeAgJBJS5RdFwBQteVg==} + dependencies: + '@types/node': 18.15.11 + dev: true + /@types/nlcst@1.0.0: resolution: {integrity: sha512-3TGCfOcy8R8mMQ4CNSNOe3PG66HttvjcLzCoOpvXvDtfWOTi+uT/rxeOKm/qEwbM4SNe1O/PjdiBK2YcTjU4OQ==} dependencies: @@ -1683,11 +1702,24 @@ packages: acorn: 8.8.2 dev: true + /acorn-walk@8.2.0: + resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} + engines: {node: '>=0.4.0'} + dev: true + /acorn@8.8.2: resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} engines: {node: '>=0.4.0'} hasBin: true + /aggregate-error@4.0.1: + resolution: {integrity: sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==} + engines: {node: '>=12'} + dependencies: + clean-stack: 4.2.0 + indent-string: 5.0.0 + dev: true + /ajv-formats@2.1.1(ajv@8.12.0): resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependencies: @@ -1737,7 +1769,6 @@ packages: /ansi-regex@6.0.1: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} engines: {node: '>=12'} - dev: false /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} @@ -1759,7 +1790,6 @@ packages: /ansi-styles@6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} - dev: false /any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} @@ -1789,6 +1819,11 @@ packages: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} dev: true + /array-find-index@1.0.2: + resolution: {integrity: sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==} + engines: {node: '>=0.10.0'} + dev: true + /array-iterate@2.0.1: resolution: {integrity: sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==} dev: false @@ -1798,6 +1833,16 @@ packages: engines: {node: '>=8'} dev: true + /arrgv@1.0.2: + resolution: {integrity: sha512-a4eg4yhp7mmruZDQFqVMlxNRFGi/i1r87pt8SDHy0/I8PqSXoUTlWZRdAZo0VXgvEARcujbtTk8kiZRi1uDGRw==} + engines: {node: '>=8.0.0'} + dev: true + + /arrify@3.0.0: + resolution: {integrity: sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==} + engines: {node: '>=12'} + dev: true + /astro-compress@1.1.35: resolution: {integrity: sha512-K6BK+iMbejXeUS1eAjoQhRh4geEutFrGkgCkeTAthf1XeRzPrWvtNPA7RjJBXWR8aNJtjryxyW02z3pE+4RNow==} dependencies: @@ -1927,6 +1972,65 @@ packages: postcss: 8.4.21 postcss-value-parser: 4.2.0 + /ava@5.2.0: + resolution: {integrity: sha512-W8yxFXJr/P68JP55eMpQIa6AiXhCX3VeuajM8nolyWNExcMDD6rnIWKTjw0B/+GkFHBIaN6Jd0LtcMThcoqVfg==} + engines: {node: '>=14.19 <15 || >=16.15 <17 || >=18'} + hasBin: true + peerDependencies: + '@ava/typescript': '*' + peerDependenciesMeta: + '@ava/typescript': + optional: true + dependencies: + acorn: 8.8.2 + acorn-walk: 8.2.0 + ansi-styles: 6.2.1 + arrgv: 1.0.2 + arrify: 3.0.0 + callsites: 4.0.0 + cbor: 8.1.0 + chalk: 5.2.0 + chokidar: 3.5.3 + chunkd: 2.0.1 + ci-info: 3.8.0 + ci-parallel-vars: 1.0.1 + clean-yaml-object: 0.1.0 + cli-truncate: 3.1.0 + code-excerpt: 4.0.0 + common-path-prefix: 3.0.0 + concordance: 5.0.4 + currently-unhandled: 0.4.1 + debug: 4.3.4 + del: 7.0.0 + emittery: 1.0.1 + figures: 5.0.0 + globby: 13.1.3 + ignore-by-default: 2.1.0 + indent-string: 5.0.0 + is-error: 2.2.2 + is-plain-object: 5.0.0 + is-promise: 4.0.0 + matcher: 5.0.0 + mem: 9.0.2 + ms: 2.1.3 + p-event: 5.0.1 + p-map: 5.5.0 + picomatch: 2.3.1 + pkg-conf: 4.0.0 + plur: 5.1.0 + pretty-ms: 8.0.0 + resolve-cwd: 3.0.0 + slash: 3.0.0 + stack-utils: 2.0.6 + strip-ansi: 7.0.1 + supertap: 3.0.1 + temp-dir: 3.0.0 + write-file-atomic: 5.0.0 + yargs: 17.7.1 + transitivePeerDependencies: + - supports-color + dev: true + /avvio@8.2.1: resolution: {integrity: sha512-TAlMYvOuwGyLK3PfBb5WKBXZmXz2fVCgv23d6zZFdle/q3gPjmxBaeuC0pY0Dzs5PWMSgfqqEZkrye19GlDTgw==} dependencies: @@ -2023,7 +2127,6 @@ packages: /binary-extensions@2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} - dev: false /bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -2041,6 +2144,10 @@ packages: readable-stream: 3.6.2 dev: false + /blueimp-md5@2.19.0: + resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==} + dev: true + /boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -2120,6 +2227,11 @@ packages: engines: {node: '>=6'} dev: true + /callsites@4.0.0: + resolution: {integrity: sha512-y3jRROutgpKdz5vzEhWM34TidDU8vkJppF8dszITeb1PQmSqV3DTxyV8G/lyO/DNvtE1YTedehmw9MPZsCBHxQ==} + engines: {node: '>=12.20'} + dev: true + /camel-case@4.1.2: resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} dependencies: @@ -2153,6 +2265,13 @@ packages: /caniuse-lite@1.0.30001473: resolution: {integrity: sha512-ewDad7+D2vlyy+E4UJuVfiBsU69IL+8oVmTuZnH5Q6CIUbxNfI50uVpRHbUPDD6SUaN2o0Lh4DhTrvLG/Tn1yg==} + /cbor@8.1.0: + resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} + engines: {node: '>=12.19'} + dependencies: + nofilter: 3.1.0 + dev: true + /ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} dev: false @@ -2175,7 +2294,6 @@ packages: /chalk@5.2.0: resolution: {integrity: sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - dev: false /char-regex@1.0.2: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} @@ -2207,16 +2325,23 @@ packages: readdirp: 3.6.0 optionalDependencies: fsevents: 2.3.2 - dev: false /chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} dev: false + /chunkd@2.0.1: + resolution: {integrity: sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==} + dev: true + /ci-info@3.8.0: resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} engines: {node: '>=8'} + /ci-parallel-vars@1.0.1: + resolution: {integrity: sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==} + dev: true + /cjs-module-lexer@1.2.2: resolution: {integrity: sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==} dev: true @@ -2228,6 +2353,18 @@ packages: source-map: 0.6.1 dev: false + /clean-stack@4.2.0: + resolution: {integrity: sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==} + engines: {node: '>=12'} + dependencies: + escape-string-regexp: 5.0.0 + dev: true + + /clean-yaml-object@0.1.0: + resolution: {integrity: sha512-3yONmlN9CSAkzNwnRCiJQ7Q2xK5mWuEfL3PuTZcAUzhObbXsfsnMptJzXwz93nc5zn9V9TwCVMmV7w4xsm43dw==} + engines: {node: '>=0.10.0'} + dev: true + /cli-boxes@3.0.0: resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} engines: {node: '>=10'} @@ -2245,6 +2382,14 @@ packages: engines: {node: '>=6'} dev: false + /cli-truncate@3.1.0: + resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + slice-ansi: 5.0.0 + string-width: 5.1.2 + dev: true + /cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -2269,6 +2414,13 @@ packages: engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} dev: true + /code-excerpt@4.0.0: + resolution: {integrity: sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + convert-to-spaces: 2.0.1 + dev: true + /collect-v8-coverage@1.0.1: resolution: {integrity: sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==} dev: true @@ -2335,9 +2487,27 @@ packages: resolution: {integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==} dev: false + /common-path-prefix@3.0.0: + resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} + dev: true + /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + /concordance@5.0.4: + resolution: {integrity: sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==} + engines: {node: '>=10.18.0 <11 || >=12.14.0 <13 || >=14'} + dependencies: + date-time: 3.1.0 + esutils: 2.0.3 + fast-diff: 1.2.0 + js-string-escape: 1.0.1 + lodash: 4.17.21 + md5-hex: 3.0.1 + semver: 7.3.8 + well-known-symbols: 2.0.0 + dev: true + /convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} @@ -2345,6 +2515,11 @@ packages: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} dev: true + /convert-to-spaces@2.0.1: + resolution: {integrity: sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + /cookie@0.4.2: resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} engines: {node: '>= 0.6'} @@ -2497,11 +2672,25 @@ packages: dependencies: css-tree: 2.2.1 + /currently-unhandled@0.4.1: + resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==} + engines: {node: '>=0.10.0'} + dependencies: + array-find-index: 1.0.2 + dev: true + /data-uri-to-buffer@4.0.1: resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} engines: {node: '>= 12'} dev: false + /date-time@3.1.0: + resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==} + engines: {node: '>=6'} + dependencies: + time-zone: 1.0.0 + dev: true + /debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -2558,6 +2747,20 @@ packages: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} engines: {node: '>=8'} + /del@7.0.0: + resolution: {integrity: sha512-tQbV/4u5WVB8HMJr08pgw0b6nG4RGt/tj+7Numvq+zqcvUFeMaIWWOUFltiU+6go8BSO2/ogsB4EasDaj0y68Q==} + engines: {node: '>=14.16'} + dependencies: + globby: 13.1.3 + graceful-fs: 4.2.11 + is-glob: 4.0.3 + is-path-cwd: 3.0.0 + is-path-inside: 4.0.0 + p-map: 5.5.0 + rimraf: 3.0.2 + slash: 4.0.0 + dev: true + /denque@2.1.0: resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} engines: {node: '>=0.10'} @@ -2688,7 +2891,6 @@ packages: /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - dev: false /electron-to-chromium@1.4.348: resolution: {integrity: sha512-gM7TdwuG3amns/1rlgxMbeeyNoBFPa+4Uu0c7FeROWh4qWmvSOnvcslKmWy51ggLKZ2n/F/4i2HJ+PVNxH9uCQ==} @@ -2698,6 +2900,11 @@ packages: engines: {node: '>=12'} dev: true + /emittery@1.0.1: + resolution: {integrity: sha512-2ID6FdrMD9KDLldGesP6317G78K7km/kMcwItRtVFva7I/cSEOIaLpewaUb+YLXVwdAp3Ctfxh/V5zIl1sj7dQ==} + engines: {node: '>=14.16'} + dev: true + /emmet@2.4.1: resolution: {integrity: sha512-8rZn/3b0WRT21UeGjQ+bzUqg3up6xBKqRjeWRZA1mrzHokNf4brqPx88XQ53+s9lK2p/pWI2VlTIu1S59OwDtA==} dependencies: @@ -2710,7 +2917,6 @@ packages: /emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - dev: false /end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} @@ -3186,7 +3392,6 @@ packages: /escape-string-regexp@5.0.0: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} engines: {node: '>=12'} - dev: false /eslint-scope@7.1.1: resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==} @@ -3307,6 +3512,10 @@ packages: engines: {node: '>=0.10.0'} dev: true + /event-lite@0.1.3: + resolution: {integrity: sha512-8qz9nOz5VeD2z96elrEKD2U433+L3DWdUdDkOINLGOJvx1GsMBbMn0aCeu28y8/e85A6mCigBiFlYMnTBEGlSw==} + dev: false + /event-target-shim@5.0.1: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} @@ -3389,6 +3598,10 @@ packages: /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + /fast-diff@1.2.0: + resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==} + dev: true + /fast-glob@3.2.12: resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==} engines: {node: '>=8.6.0'} @@ -3474,6 +3687,14 @@ packages: web-streams-polyfill: 3.2.1 dev: false + /figures@5.0.0: + resolution: {integrity: sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==} + engines: {node: '>=14'} + dependencies: + escape-string-regexp: 5.0.0 + is-unicode-supported: 1.3.0 + dev: true + /file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -3522,6 +3743,14 @@ packages: locate-path: 6.0.0 path-exists: 4.0.0 + /find-up@6.3.0: + resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + locate-path: 7.2.0 + path-exists: 5.0.0 + dev: true + /find-yarn-workspace-root2@1.2.16: resolution: {integrity: sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==} dependencies: @@ -3663,6 +3892,17 @@ packages: slash: 3.0.0 dev: true + /globby@13.1.3: + resolution: {integrity: sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + dir-glob: 3.0.1 + fast-glob: 3.2.12 + ignore: 5.2.4 + merge2: 1.4.1 + slash: 4.0.0 + dev: true + /globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} @@ -3825,6 +4065,11 @@ packages: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} dev: false + /ignore-by-default@2.1.0: + resolution: {integrity: sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==} + engines: {node: '>=10 <11 || >=12 <13 || >=14'} + dev: true + /ignore@5.2.4: resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} engines: {node: '>= 4'} @@ -3856,6 +4101,11 @@ packages: engines: {node: '>=0.8.19'} dev: true + /indent-string@5.0.0: + resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} + engines: {node: '>=12'} + dev: true + /inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} dependencies: @@ -3869,6 +4119,10 @@ packages: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} dev: false + /int64-buffer@0.1.10: + resolution: {integrity: sha512-v7cSY1J8ydZ0GyjUHqF+1bshJ6cnEVLo9EnjB8p+4HDRPZc9N5jjmvUV7NvEsqQOKyH0pmIBFWXVQbiS0+OBbA==} + dev: false + /ioredis@5.3.1: resolution: {integrity: sha512-C+IBcMysM6v52pTLItYMeV4Hz7uriGtoJdz7SSBDX6u+zwSYGirLdQh3L7t/OItWITcw3gTFMjJReYUwS4zihg==} engines: {node: '>=12.22.0'} @@ -3891,6 +4145,11 @@ packages: engines: {node: '>= 0.10'} dev: false + /irregular-plurals@3.5.0: + resolution: {integrity: sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==} + engines: {node: '>=8'} + dev: true + /is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} dev: true @@ -3904,7 +4163,6 @@ packages: engines: {node: '>=8'} dependencies: binary-extensions: 2.2.0 - dev: false /is-buffer@2.0.5: resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} @@ -3927,6 +4185,10 @@ packages: hasBin: true dev: false + /is-error@2.2.2: + resolution: {integrity: sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==} + dev: true + /is-extendable@0.1.1: resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} engines: {node: '>=0.10.0'} @@ -3940,6 +4202,11 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + /is-fullwidth-code-point@4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + dev: true + /is-generator-fn@2.1.0: resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} engines: {node: '>=6'} @@ -3960,11 +4227,30 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + /is-path-cwd@3.0.0: + resolution: {integrity: sha512-kyiNFFLU0Ampr6SDZitD/DwUo4Zs1nSdnygUBqsu3LooL00Qvb5j+UnvApUn/TTj1J3OuE6BTdQ5rudKmU2ZaA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /is-path-inside@4.0.0: + resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==} + engines: {node: '>=12'} + dev: true + /is-plain-obj@4.1.0: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} dev: false + /is-plain-object@5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + dev: true + + /is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + dev: true + /is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} @@ -3977,7 +4263,6 @@ packages: /is-unicode-supported@1.3.0: resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} engines: {node: '>=12'} - dev: false /is-wsl@2.2.0: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} @@ -3985,6 +4270,10 @@ packages: dependencies: is-docker: 2.2.1 + /isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + dev: false + /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -4452,6 +4741,11 @@ packages: resolution: {integrity: sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==} dev: true + /js-string-escape@1.0.1: + resolution: {integrity: sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==} + engines: {node: '>= 0.8'} + dev: true + /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -4544,6 +4838,11 @@ packages: /lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + /load-json-file@7.0.1: + resolution: {integrity: sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + /load-yaml-file@0.2.0: resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==} engines: {node: '>=6'} @@ -4566,6 +4865,13 @@ packages: dependencies: p-locate: 5.0.0 + /locate-path@7.2.0: + resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + p-locate: 6.0.0 + dev: true + /lodash.castarray@4.4.0: resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==} dev: false @@ -4593,6 +4899,10 @@ packages: resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} dev: true + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: true + /log-symbols@5.1.0: resolution: {integrity: sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==} engines: {node: '>=12'} @@ -4642,10 +4952,31 @@ packages: tmpl: 1.0.5 dev: true + /map-age-cleaner@0.1.3: + resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==} + engines: {node: '>=6'} + dependencies: + p-defer: 1.0.0 + dev: true + /markdown-table@3.0.3: resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==} dev: false + /matcher@5.0.0: + resolution: {integrity: sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + escape-string-regexp: 5.0.0 + dev: true + + /md5-hex@3.0.1: + resolution: {integrity: sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==} + engines: {node: '>=8'} + dependencies: + blueimp-md5: 2.19.0 + dev: true + /mdast-util-definitions@5.1.2: resolution: {integrity: sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==} dependencies: @@ -4787,6 +5118,14 @@ packages: /mdn-data@2.0.30: resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} + /mem@9.0.2: + resolution: {integrity: sha512-F2t4YIv9XQUBHt6AOJ0y7lSmP1+cY7Fm1DRh9GClTGzKST7UWLMx6ly9WZdLH/G/ppM5RL4MlQfRT71ri9t19A==} + engines: {node: '>=12.20'} + dependencies: + map-age-cleaner: 0.1.3 + mimic-fn: 4.0.0 + dev: true + /merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -5132,6 +5471,20 @@ packages: /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + dev: true + + /msgpack-lite@0.1.26: + resolution: {integrity: sha512-SZ2IxeqZ1oRFGo0xFGbvBJWMp3yLIY9rlIJyxy8CGrwZn1f0ZK4r6jV/AM1r0FZMDUkWkglOk/eeKIL9g77Nxw==} + hasBin: true + dependencies: + event-lite: 0.1.3 + ieee754: 1.2.1 + int64-buffer: 0.1.10 + isarray: 1.0.0 + dev: false + /mustache@4.2.0: resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} hasBin: true @@ -5208,6 +5561,11 @@ packages: /node-releases@2.0.10: resolution: {integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==} + /nofilter@3.1.0: + resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} + engines: {node: '>=12.19'} + dev: true + /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -5309,6 +5667,18 @@ packages: wcwidth: 1.0.1 dev: false + /p-defer@1.0.0: + resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==} + engines: {node: '>=4'} + dev: true + + /p-event@5.0.1: + resolution: {integrity: sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + p-timeout: 5.1.0 + dev: true + /p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -5321,6 +5691,13 @@ packages: dependencies: yocto-queue: 0.1.0 + /p-limit@4.0.0: + resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + yocto-queue: 1.0.0 + dev: true + /p-locate@4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} @@ -5333,6 +5710,25 @@ packages: dependencies: p-limit: 3.1.0 + /p-locate@6.0.0: + resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + p-limit: 4.0.0 + dev: true + + /p-map@5.5.0: + resolution: {integrity: sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==} + engines: {node: '>=12'} + dependencies: + aggregate-error: 4.0.1 + dev: true + + /p-timeout@5.1.0: + resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==} + engines: {node: '>=12'} + dev: true + /p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} @@ -5369,6 +5765,11 @@ packages: unist-util-visit-children: 2.0.2 dev: false + /parse-ms@3.0.0: + resolution: {integrity: sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==} + engines: {node: '>=12'} + dev: true + /parse-package-name@1.0.0: resolution: {integrity: sha512-kBeTUtcj+SkyfaW4+KBe0HtsloBJ/mKTPoxpVdA57GZiPerREsUWJOhVj9anXweFiJkm5y8FG1sxFZkZ0SN6wg==} dev: true @@ -5388,6 +5789,11 @@ packages: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} + /path-exists@5.0.0: + resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + /path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} @@ -5461,12 +5867,27 @@ packages: resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==} engines: {node: '>= 6'} + /pkg-conf@4.0.0: + resolution: {integrity: sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + find-up: 6.3.0 + load-json-file: 7.0.1 + dev: true + /pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} dependencies: find-up: 4.1.0 + /plur@5.1.0: + resolution: {integrity: sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + irregular-plurals: 3.5.0 + dev: true + /postcss-calc@8.2.4(postcss@8.4.21): resolution: {integrity: sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==} peerDependencies: @@ -5964,6 +6385,13 @@ packages: react-is: 18.2.0 dev: true + /pretty-ms@8.0.0: + resolution: {integrity: sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==} + engines: {node: '>=14.16'} + dependencies: + parse-ms: 3.0.0 + dev: true + /prismjs@1.29.0: resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==} engines: {node: '>=6'} @@ -6068,7 +6496,6 @@ packages: engines: {node: '>=8.10.0'} dependencies: picomatch: 2.3.1 - dev: false /real-require@0.2.0: resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} @@ -6375,6 +6802,13 @@ packages: dependencies: lru-cache: 6.0.0 + /serialize-error@7.0.1: + resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} + engines: {node: '>=10'} + dependencies: + type-fest: 0.13.1 + dev: true + /server-destroy@1.0.1: resolution: {integrity: sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==} dev: false @@ -6458,7 +6892,14 @@ packages: /slash@4.0.0: resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} engines: {node: '>=12'} - dev: false + + /slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + dev: true /sonic-boom@3.3.0: resolution: {integrity: sha512-LYxp34KlZ1a2Jb8ZQgFCK3niIHzibdwtwNUWKg0qQRzsDoJ3Gfgkf8KdBTFU3SkejDEIlWwnSnpVdOZIhFMl/g==} @@ -6558,7 +6999,6 @@ packages: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 strip-ansi: 7.0.1 - dev: false /string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} @@ -6584,7 +7024,6 @@ packages: engines: {node: '>=12'} dependencies: ansi-regex: 6.0.1 - dev: false /strip-bom-string@1.0.0: resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==} @@ -6648,6 +7087,16 @@ packages: dependencies: s.color: 0.0.15 + /supertap@3.0.1: + resolution: {integrity: sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + indent-string: 5.0.0 + js-yaml: 3.14.1 + serialize-error: 7.0.1 + strip-ansi: 7.0.1 + dev: true + /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -6765,6 +7214,11 @@ packages: readable-stream: 3.6.2 dev: false + /temp-dir@3.0.0: + resolution: {integrity: sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==} + engines: {node: '>=14.16'} + dev: true + /terser@5.16.5: resolution: {integrity: sha512-qcwfg4+RZa3YvlFh0qjifnzBHjKGNbtDo9yivMqMFDy9Q6FSaQWSB/j1xKhsoUFJIqDOM3TsN6D5xbrMrFcHbg==} engines: {node: '>=10'} @@ -6813,6 +7267,11 @@ packages: engines: {node: '>=6'} dev: false + /time-zone@1.0.0: + resolution: {integrity: sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==} + engines: {node: '>=4'} + dev: true + /tiny-glob@0.2.9: resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} dependencies: @@ -6893,7 +7352,6 @@ packages: /type-fest@0.13.1: resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} engines: {node: '>=10'} - dev: false /type-fest@0.20.2: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} @@ -7015,11 +7473,6 @@ packages: /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - /utility-types@3.10.0: - resolution: {integrity: sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==} - engines: {node: '>= 4'} - dev: false - /uvu@0.5.6: resolution: {integrity: sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==} engines: {node: '>=8'} @@ -7203,6 +7656,11 @@ packages: engines: {node: '>= 8'} dev: false + /well-known-symbols@2.0.0: + resolution: {integrity: sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==} + engines: {node: '>=6'} + dev: true + /which-pm-runs@1.1.0: resolution: {integrity: sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==} engines: {node: '>=4'} @@ -7264,6 +7722,14 @@ packages: signal-exit: 3.0.7 dev: true + /write-file-atomic@5.0.0: + resolution: {integrity: sha512-R7NYMnHSlV42K54lwY9lvW6MnSm1HSJqZL3xiSgi9E7//FYaI74r2G0rd+/X6VAMkHEdzxQaU5HUOXWUz5kA/w==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + imurmurhash: 0.1.4 + signal-exit: 3.0.7 + dev: true + /ws@8.13.0: resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} engines: {node: '>=10.0.0'} @@ -7319,6 +7785,11 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + /yocto-queue@1.0.0: + resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} + engines: {node: '>=12.20'} + dev: true + /youch@2.2.2: resolution: {integrity: sha512-/FaCeG3GkuJwaMR34GHVg0l8jCbafZLHiFowSjqLlqhC6OMyf2tPJBu8UirF7/NI9X/R5ai4QfEKUCOxMAGxZQ==} dependencies: diff --git a/test.txt b/test.txt new file mode 100644 index 0000000..e69de29