wip more stuff

This commit is contained in:
itsMapleLeaf
2022-10-02 17:57:49 -05:00
parent dc6239e598
commit b6f244aaa0
8 changed files with 315 additions and 117 deletions

View File

@@ -10,14 +10,14 @@ export class AsyncQueue {
private items: QueueItem[] = []
private running = false
add<T>(callback: AsyncCallback<T>): Promise<Awaited<T>> {
append<T>(callback: AsyncCallback<T>): Promise<Awaited<T>> {
return new Promise((resolve, reject) => {
this.items.push({ callback, resolve: resolve as any, reject })
void this.runQueue()
void this.run()
})
}
private async runQueue() {
private async run() {
if (this.running) return
this.running = true

View File

@@ -0,0 +1,21 @@
{
"name": "@reacord/playground",
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "tsx watch src/main.tsx"
},
"dependencies": {
"@reacord/helpers": "workspace:*",
"discord.js": "^14.1.2",
"dotenv": "^16.0.1",
"ora": "^6.1.2",
"react": "^18.2.0"
},
"devDependencies": {
"@types/node": "*",
"@types/react": "^18.0.16",
"tsx": "^3.8.0",
"typescript": "^4.7.4"
}
}

View File

@@ -0,0 +1,54 @@
import { raise } from "@reacord/helpers/raise"
import { Client, GatewayIntentBits } from "discord.js"
import * as dotenv from "dotenv"
import { join } from "node:path"
import { fileURLToPath } from "node:url"
import { oraPromise } from "ora"
import React from "react"
import { Button, ReacordClient } from "../../reacord/src/main"
dotenv.config({
path: join(fileURLToPath(import.meta.url), "../../../../.env"),
override: true,
})
const token = process.env.TEST_BOT_TOKEN ?? raise("TEST_BOT_TOKEN not defined")
const client = new Client({ intents: [GatewayIntentBits.Guilds] })
const reacord = new ReacordClient({ token })
client.once("ready", async (client) => {
try {
await oraPromise(
client.application.commands.create({
name: "counter",
description: "counts things",
}),
"Registering commands",
)
} catch (error) {
console.error("Failed to register commands:", error)
}
})
client.on("interactionCreate", async (interaction) => {
if (
interaction.isChatInputCommand() &&
interaction.commandName === "counter"
) {
reacord.reply(interaction, <Counter />)
// reacord.reply(interaction, "test3").render("test4")
}
})
await oraPromise(client.login(token), "Logging in")
function Counter() {
const [count, setCount] = React.useState(0)
return (
<>
count: {count}
<Button label="+" onClick={() => setCount(count + 1)} />
</>
)
}

View File

@@ -0,0 +1,3 @@
{
"extends": "../../tsconfig.base.json"
}

View File

@@ -2,14 +2,21 @@ import type { APIInteraction, Client } from "discord.js"
import {
GatewayDispatchEvents,
GatewayIntentBits,
InteractionResponseType,
InteractionType,
Routes,
} from "discord.js"
import * as React from "react"
import { createDiscordClient } from "./create-discord-client"
import type { ReacordInstance } from "./reacord-instance"
import { ReacordInstancePrivate } from "./reacord-instance"
import { InstanceProvider } from "./react/instance-context"
import { Renderer } from "./renderer"
import type { Renderer } from "./renderer"
import {
ChannelMessageRenderer,
EphemeralInteractionReplyRenderer,
InteractionReplyRenderer,
} from "./renderer"
/**
* @category Core
@@ -65,10 +72,28 @@ export class ReacordClient {
this.discordClientPromise
.then((client) => {
// we listen to the websocket message instead of the normal "interactionCreate" event,
// so that we can pass a library-agnostic APIInteraction object to the user's component callbacks
// the DJS MessageComponentInteraction doesn't have the raw data on it (as of writing this)
client.ws.on(
GatewayDispatchEvents.InteractionCreate,
(interaction: APIInteraction) => {
async (interaction: APIInteraction) => {
if (interaction.type !== InteractionType.MessageComponent) return
// handling a component interaction may not always result in a re-render,
// and in the case that it doesn't, discord will incorrectly show "interaction failed",
// so here, we'll just always defer an update just in case
//
// we _can_ be a little smarter and check to see if an update happened before deferring,
// but I can figure that out later
//
// or we can make the user defer themselves if they don't update,
// but that's bad UX probably
await client.rest.post(
Routes.interactionCallback(interaction.id, interaction.token),
{ body: { type: InteractionResponseType.DeferredMessageUpdate } },
)
for (const instance of this.instances) {
instance.handleInteraction(interaction, this)
}
@@ -88,7 +113,7 @@ export class ReacordClient {
reply(interaction: InteractionInfo, initialContent?: React.ReactNode) {
return this.createInstance(
new InteractionReplyRenderer(interaction),
new InteractionReplyRenderer(interaction, this.discordClientPromise),
initialContent,
)
}
@@ -98,7 +123,10 @@ export class ReacordClient {
initialContent?: React.ReactNode,
) {
return this.createInstance(
new EphemeralInteractionReplyRenderer(interaction),
new EphemeralInteractionReplyRenderer(
interaction,
this.discordClientPromise,
),
initialContent,
)
}
@@ -132,11 +160,11 @@ export class ReacordClient {
},
deactivate: () => {
this.removeInstance(instance)
renderer.deactivate().catch(console.error)
renderer.deactivate()
},
destroy: () => {
this.removeInstance(instance)
renderer.destroy().catch(console.error)
renderer.destroy()
},
}

View File

@@ -50,35 +50,23 @@ export class ReacordInstancePrivate {
readonly tree = new Node({})
private latestTree?: Node
constructor(private readonly renderer: Renderer) {}
constructor(readonly renderer: Renderer) {}
render(content: React.ReactNode) {
reconciler.updateContainer(content, this.container)
}
async update(tree: Node) {
try {
await this.renderer.update(tree)
this.latestTree = tree
} catch (error) {
console.error(error)
}
update(tree: Node) {
this.renderer.update(tree)
this.latestTree = tree
}
async deactivate() {
try {
await this.renderer.deactivate()
} catch (error) {
console.error(error)
}
deactivate() {
this.renderer.deactivate()
}
async destroy() {
try {
await this.renderer.destroy()
} catch (error) {
console.error(error)
}
destroy() {
this.renderer.destroy()
}
handleInteraction(
@@ -87,6 +75,8 @@ export class ReacordInstancePrivate {
) {
if (!this.latestTree) return
this.renderer.onComponentInteraction(interaction)
const baseEvent: ComponentEvent = {
reply: (content) => client.reply(interaction, content),
ephemeralReply: (content) => client.ephemeralReply(interaction, content),
@@ -102,7 +92,7 @@ export class ReacordInstancePrivate {
...baseEvent,
interaction: interaction as APIMessageComponentButtonInteraction,
})
break
return
}
}
}
@@ -124,6 +114,7 @@ export class ReacordInstancePrivate {
if (interaction.data.values[0]) {
node.props.onChangeValue?.(interaction.data.values[0], event)
}
return
}
}
}

View File

@@ -1,15 +1,22 @@
import { AsyncQueue } from "@reacord/helpers/async-queue.js"
import type { Client, Message } from "discord.js"
import { TextChannel } from "discord.js"
import type { MessageUpdatePayload } from "./make-message-update-payload.js"
import { makeMessageUpdatePayload } from "./make-message-update-payload.js"
import type { Node } from "./node.js"
import type { InteractionInfo } from "./reacord-client.js"
import { AsyncQueue } from "@reacord/helpers/async-queue"
import type {
Client,
Message,
RESTPostAPIInteractionFollowupResult,
Snowflake,
} from "discord.js"
import { InteractionResponseType, Routes, TextChannel } from "discord.js"
import type { MessageUpdatePayload } from "./make-message-update-payload"
import { makeMessageUpdatePayload } from "./make-message-update-payload"
import type { Node } from "./node"
import type { InteractionInfo } from "./reacord-client"
export abstract class Renderer {
private readonly queue = new AsyncQueue()
private active = true
private destroyPromise?: Promise<void>
private componentInteraction?: InteractionInfo
private readonly queue = new AsyncQueue()
constructor(protected readonly clientPromise: Promise<Client<true>>) {}
protected abstract handleUpdate(payload: MessageUpdatePayload): Promise<void>
protected abstract handleDestroy(): Promise<void>
@@ -17,59 +24,97 @@ export abstract class Renderer {
update(tree: Node) {
const payload = makeMessageUpdatePayload(tree)
return this.queue.add(async () => {
if (!this.active) return
await this.handleUpdate(payload)
})
this.queue
.append(async () => {
if (!this.active) return
if (this.componentInteraction) {
await this.updateInteractionMessage(
this.componentInteraction,
payload,
)
this.componentInteraction = undefined
return
}
await this.handleUpdate(payload)
})
.catch(console.error)
}
destroy() {
if (this.destroyPromise) return this.destroyPromise
if (!this.active) return
this.active = false
const promise = this.queue.add(() => this.handleDestroy())
// if it failed, we'll want to try again
promise.catch((error) => {
console.error("Failed to destroy message:", error)
this.destroyPromise = undefined
})
return (this.destroyPromise = promise)
this.queue.append(() => this.handleDestroy()).catch(console.error)
}
deactivate() {
return this.queue.add(async () => {
if (!this.active) return
this.queue
.append(async () => {
await this.handleDeactivate()
this.active = false
})
.catch(console.error)
}
await this.handleDeactivate()
onComponentInteraction(info: InteractionInfo) {
this.componentInteraction = info
// set active to false *after* running deactivation,
// so that other queued operations run first,
// and we can show the correct deactivated state
this.active = false
// a component update might not happen in response to this interaction,
// so we'll defer it after a timeout if it's not handled by then
setTimeout(() => {
this.queue
.append(() => {
if (!this.componentInteraction) return
const info = this.componentInteraction
this.componentInteraction = undefined
return this.deferMessageUpdate(info)
})
.catch(console.error)
}, 500)
}
private async updateInteractionMessage(
{ id, token }: InteractionInfo,
payload: MessageUpdatePayload,
) {
const client = await this.clientPromise
await client.rest.post(Routes.interactionCallback(id, token), {
body: {
type: InteractionResponseType.UpdateMessage,
data: payload,
},
})
}
private async deferMessageUpdate({ id, token }: InteractionInfo) {
const client = await this.clientPromise
await client.rest.post(Routes.interactionCallback(id, token), {
body: { type: InteractionResponseType.DeferredMessageUpdate },
})
}
}
export class ChannelMessageRenderer extends Renderer {
private channel: TextChannel | undefined
private message: Message | undefined
private channel?: TextChannel
private message?: Message
constructor(
private readonly channelId: string,
private readonly clientPromise: Promise<Client<true>>,
clientPromise: Promise<Client<true>>,
) {
super()
super(clientPromise)
}
override async handleUpdate(payload: MessageUpdatePayload): Promise<void> {
if (this.message) {
await this.message.edit(payload)
} else {
const channel = await this.getChannel()
this.message = await channel.send(payload)
return
}
const channel = await this.getChannel()
this.message = await channel.send(payload)
}
override async handleDestroy(): Promise<void> {
@@ -101,14 +146,80 @@ export class ChannelMessageRenderer extends Renderer {
}
export class InteractionReplyRenderer extends Renderer {
constructor(private readonly interaction: InteractionInfo) {
super()
private messageCreated = false
constructor(
private interaction: InteractionInfo,
clientPromise: Promise<Client<true>>,
) {
super(clientPromise)
}
handleUpdate(payload: MessageUpdatePayload): Promise<void> {
async handleUpdate(payload: MessageUpdatePayload): Promise<void> {
const client = await this.clientPromise
if (!this.messageCreated) {
await client.rest.post(
Routes.interactionCallback(this.interaction.id, this.interaction.token),
{
body: {
type: InteractionResponseType.ChannelMessageWithSource,
data: payload,
},
},
)
this.messageCreated = true
} else {
await client.rest.patch(
Routes.webhookMessage(
client.application.id,
this.interaction.token,
"@original",
),
{ body: payload },
)
}
}
handleDestroy(): Promise<void> {
throw new Error("Method not implemented.")
}
handleDeactivate(): Promise<void> {
throw new Error("Method not implemented.")
}
}
export class InteractionFollowUpRenderer extends Renderer {
private messageId?: Snowflake
constructor(
readonly interaction: InteractionInfo,
clientPromise: Promise<Client<true>>,
) {
super(clientPromise)
}
async handleUpdate(payload: MessageUpdatePayload): Promise<void> {
const client = await this.clientPromise
if (!this.messageId) {
const response = (await client.rest.post(
Routes.webhookMessage(client.application.id, this.interaction.token),
{ body: payload },
)) as RESTPostAPIInteractionFollowupResult
this.messageId = response.id
} else {
await client.rest.patch(
Routes.webhookMessage(
client.application.id,
this.interaction.token,
this.messageId,
),
{ body: payload },
)
}
}
handleDestroy(): Promise<void> {
throw new Error("Method not implemented.")
}
@@ -119,8 +230,11 @@ export class InteractionReplyRenderer extends Renderer {
}
export class EphemeralInteractionReplyRenderer extends Renderer {
constructor(private readonly interaction: InteractionInfo) {
super()
constructor(
private readonly interaction: InteractionInfo,
clientPromise: Promise<Client<true>>,
) {
super(clientPromise)
}
handleUpdate(payload: MessageUpdatePayload): Promise<void> {

75
pnpm-lock.yaml generated
View File

@@ -43,6 +43,29 @@ importers:
lodash-es: 4.17.21
type-fest: 2.18.0
packages/playground:
specifiers:
'@reacord/helpers': workspace:*
'@types/node': '*'
'@types/react': ^18.0.16
discord.js: ^14.1.2
dotenv: ^16.0.1
ora: ^6.1.2
react: ^18.2.0
tsx: ^3.8.0
typescript: ^4.7.4
dependencies:
'@reacord/helpers': link:../helpers
discord.js: 14.1.2
dotenv: 16.0.1
ora: 6.1.2
react: 18.2.0
devDependencies:
'@types/node': 18.6.4
'@types/react': 18.0.16
tsx: 3.8.0
typescript: 4.7.4
packages/reacord:
specifiers:
'@reacord/helpers': workspace:*
@@ -1654,12 +1677,10 @@ packages:
fast-deep-equal: 3.1.3
ts-mixer: 6.0.1
tslib: 2.4.0
dev: true
/@discordjs/collection/1.0.1:
resolution: {integrity: sha512-5V/wswzR3r2RVYXLxxg4TvrAnBhVCNgHTXhC+OUtLoriJ072rPMHo+Iw1SS1vrCckp8Es40XM411+WkNRPaXFw==}
engines: {node: '>=16.9.0'}
dev: true
/@discordjs/rest/1.0.1:
resolution: {integrity: sha512-w08CTKVzzYYvKxEjXKOs9AdS7KQ1J502TrPfF8eCZ2lF6AfKuMP/32YgDakiwIyYTDjEQS/v0nKLSFcncHRMtg==}
@@ -1672,7 +1693,6 @@ packages:
file-type: 17.1.6
tslib: 2.4.0
undici: 5.8.1
dev: true
/@esbuild-kit/cjs-loader/2.3.2:
resolution: {integrity: sha512-3UIFKrGfq2d2R2A/SpJaeHTP5z3nrOnVMxE+cNpOuuW+Lotm0Sfbc9lVHCjcxaxgcx0MKI7g2FvxvWlylzDRKg==}
@@ -2263,7 +2283,6 @@ packages:
/@sapphire/async-queue/1.3.2:
resolution: {integrity: sha512-rUpMLATsoAMnlN3gecAcr9Ecnw1vG7zi5Xr+IX22YzRzi1k9PF9vKzoT8RuEJbiIszjcimu3rveqUnvwDopz8g==}
engines: {node: '>=v14.0.0', npm: '>=7.0.0'}
dev: true
/@sapphire/shapeshift/3.5.1:
resolution: {integrity: sha512-7JFsW5IglyOIUQI1eE0g6h06D/Far6HqpcowRScgCiLSqTf3hhkPWCWotVTtVycnDCMYIwPeaw6IEPBomKC8pA==}
@@ -2271,12 +2290,10 @@ packages:
dependencies:
fast-deep-equal: 3.1.3
lodash.uniqwith: 4.5.0
dev: true
/@sapphire/snowflake/3.2.2:
resolution: {integrity: sha512-ula2O0kpSZtX9rKXNeQMrHwNd7E4jPDJYUXmEGTFdMRfyfMw+FPyh04oKMjAiDuOi64bYgVkOV3MjK+loImFhQ==}
engines: {node: '>=v14.0.0', npm: '>=7.0.0'}
dev: true
/@sideway/address/4.1.4:
resolution: {integrity: sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==}
@@ -2354,7 +2371,6 @@ packages:
/@tokenizer/token/0.3.0:
resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==}
dev: true
/@tootallnate/once/1.1.2:
resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==}
@@ -2562,6 +2578,14 @@ packages:
'@types/scheduler': 0.16.2
csstype: 3.1.0
/@types/react/18.0.16:
resolution: {integrity: sha512-3vX1dzVucqc2nhXtzyaParTIIRZeNbisRqLE7QdeLomVybEyeiuAouzZXgz71P+2kbJOqj3dy0fzoATg2I06GQ==}
dependencies:
'@types/prop-types': 15.7.5
'@types/scheduler': 0.16.2
csstype: 3.1.0
dev: true
/@types/responselike/1.0.0:
resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==}
dependencies:
@@ -2603,7 +2627,6 @@ packages:
resolution: {integrity: sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==}
dependencies:
'@types/node': 18.6.4
dev: true
/@types/yauzl/2.10.0:
resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==}
@@ -2882,7 +2905,6 @@ packages:
/ansi-regex/6.0.1:
resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
engines: {node: '>=12'}
dev: true
/ansi-styles/3.2.1:
resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
@@ -3226,7 +3248,6 @@ packages:
/base64-js/1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
dev: true
/basic-auth/2.0.1:
resolution: {integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==}
@@ -3280,7 +3301,6 @@ packages:
buffer: 6.0.3
inherits: 2.0.4
readable-stream: 3.6.0
dev: true
/blob-util/2.0.2:
resolution: {integrity: sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==}
@@ -3402,7 +3422,6 @@ packages:
dependencies:
base64-js: 1.5.1
ieee754: 1.2.1
dev: true
/builtin-modules/3.3.0:
resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
@@ -3595,7 +3614,6 @@ packages:
/chalk/5.0.1:
resolution: {integrity: sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==}
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
dev: true
/character-entities-html4/2.1.0:
resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==}
@@ -3699,12 +3717,10 @@ packages:
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dependencies:
restore-cursor: 4.0.0
dev: true
/cli-spinners/2.7.0:
resolution: {integrity: sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==}
engines: {node: '>=6'}
dev: true
/cli-table3/0.6.2:
resolution: {integrity: sha512-QyavHCaIC80cMivimWu4aWHilIpiDpfm3hGmqAmXVL1UsnbLuBSMd21hTX6VY4ZSDSM73ESLeF8TOYId3rBTbw==}
@@ -3767,7 +3783,6 @@ packages:
/clone/1.0.4:
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
engines: {node: '>=0.8'}
dev: true
/clsx/1.2.1:
resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==}
@@ -4254,7 +4269,6 @@ packages:
resolution: {integrity: sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==}
dependencies:
clone: 1.0.4
dev: true
/defer-to-connect/2.0.1:
resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==}
@@ -4370,7 +4384,6 @@ packages:
/discord-api-types/0.36.3:
resolution: {integrity: sha512-bz/NDyG0KBo/tY14vSkrwQ/n3HKPf87a0WFW/1M9+tXYK+vp5Z5EksawfCWo2zkAc6o7CClc0eff1Pjrqznlwg==}
dev: true
/discord-api-types/0.37.1:
resolution: {integrity: sha512-mePTvycgxnXh1wZO2BTj0mVKsxX69tuc1Zgf4A7dZDGX/HT/geb/26ZLIVqBU9BREJbySuDQlluyIjwZFQj3qw==}
@@ -4394,7 +4407,6 @@ packages:
transitivePeerDependencies:
- bufferutil
- utf-8-validate
dev: true
/dlv/1.1.3:
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
@@ -4427,7 +4439,6 @@ packages:
/dotenv/16.0.1:
resolution: {integrity: sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==}
engines: {node: '>=12'}
dev: true
/duplexify/3.7.1:
resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==}
@@ -5267,7 +5278,6 @@ packages:
/fast-deep-equal/3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
dev: true
/fast-glob/3.2.11:
resolution: {integrity: sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==}
@@ -5341,7 +5351,6 @@ packages:
readable-web-to-node-stream: 3.0.2
strtok3: 7.0.0
token-types: 5.0.1
dev: true
/file-uri-to-path/1.0.0:
resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
@@ -6117,7 +6126,6 @@ packages:
/ieee754/1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
dev: true
/ignore-by-default/1.0.1:
resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==}
@@ -6458,7 +6466,6 @@ packages:
/is-interactive/2.0.0:
resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==}
engines: {node: '>=12'}
dev: true
/is-js-type/2.0.0:
resolution: {integrity: sha512-Aj13l47+uyTjlQNHtXBV8Cji3jb037vxwMWCgopRR8h6xocgBGW3qG8qGlIOEmbXQtkKShKuBM9e8AA1OeQ+xw==}
@@ -6631,7 +6638,6 @@ packages:
/is-unicode-supported/1.2.0:
resolution: {integrity: sha512-wH+U77omcRzevfIG8dDhTS0V9zZyweakfD01FULl97+0EHiJTTZtJqxPSkIIo/SDPv/i07k/C9jAPY+jwLLeUQ==}
engines: {node: '>=12'}
dev: true
/is-weakref/1.0.2:
resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
@@ -7054,7 +7060,6 @@ packages:
/lodash.snakecase/4.1.1:
resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==}
dev: true
/lodash.sortby/4.7.0:
resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==}
@@ -7066,7 +7071,6 @@ packages:
/lodash.uniqwith/4.5.0:
resolution: {integrity: sha512-7lYL8bLopMoy4CTICbxygAUq6CdRJ36vFc80DucPueUee+d5NBRxz3FdT9Pes/HEx5mPoT9jwnsEJWz1N7uq7Q==}
dev: true
/lodash/4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
@@ -7086,7 +7090,6 @@ packages:
dependencies:
chalk: 5.0.1
is-unicode-supported: 1.2.0
dev: true
/log-update/4.0.0:
resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==}
@@ -7680,7 +7683,6 @@ packages:
/mimic-fn/2.1.0:
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
engines: {node: '>=6'}
dev: true
/mimic-fn/4.0.0:
resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
@@ -8111,7 +8113,6 @@ packages:
engines: {node: '>=6'}
dependencies:
mimic-fn: 2.1.0
dev: true
/onetime/6.0.0:
resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
@@ -8181,7 +8182,6 @@ packages:
log-symbols: 5.1.0
strip-ansi: 7.0.1
wcwidth: 1.0.1
dev: true
/os-name/5.0.1:
resolution: {integrity: sha512-0EQpaHUHq7olp2/YFUr+0vZi9tMpDTblHGz+Ch5RntKxiRXOAY0JOz1UlxhSjMSksHvkm13eD6elJj3M8Ht/kw==}
@@ -8465,7 +8465,6 @@ packages:
/peek-readable/5.0.0:
resolution: {integrity: sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==}
engines: {node: '>=14.16'}
dev: true
/peek-stream/1.1.3:
resolution: {integrity: sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA==}
@@ -9068,14 +9067,12 @@ packages:
inherits: 2.0.4
string_decoder: 1.3.0
util-deprecate: 1.0.2
dev: true
/readable-web-to-node-stream/3.0.2:
resolution: {integrity: sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==}
engines: {node: '>=8'}
dependencies:
readable-stream: 3.6.0
dev: true
/readdirp/3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
@@ -9376,7 +9373,6 @@ packages:
dependencies:
onetime: 5.1.2
signal-exit: 3.0.7
dev: true
/ret/0.1.15:
resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==}
@@ -9645,7 +9641,6 @@ packages:
/signal-exit/3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
dev: true
/simple-update-notifier/1.0.7:
resolution: {integrity: sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew==}
@@ -9980,7 +9975,6 @@ packages:
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
dependencies:
safe-buffer: 5.2.1
dev: true
/stringify-entities/4.0.3:
resolution: {integrity: sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g==}
@@ -10001,7 +9995,6 @@ packages:
engines: {node: '>=12'}
dependencies:
ansi-regex: 6.0.1
dev: true
/strip-bom-string/1.0.0:
resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==}
@@ -10046,7 +10039,6 @@ packages:
dependencies:
'@tokenizer/token': 0.3.0
peek-readable: 5.0.0
dev: true
/style-to-object/0.3.0:
resolution: {integrity: sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==}
@@ -10281,7 +10273,6 @@ packages:
dependencies:
'@tokenizer/token': 0.3.0
ieee754: 1.2.1
dev: true
/toml/3.0.0:
resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==}
@@ -10337,7 +10328,6 @@ packages:
/ts-mixer/6.0.1:
resolution: {integrity: sha512-hvE+ZYXuINrx6Ei6D6hz+PTim0Uf++dYbK9FFifLNwQj+RwKquhQpn868yZsCtJYiclZF1u8l6WZxxKi+vv7Rg==}
dev: true
/ts-morph/15.1.0:
resolution: {integrity: sha512-RBsGE2sDzUXFTnv8Ba22QfeuKbgvAGJFuTN7HfmIRUkgT/NaVLfDM/8OFm2NlFkGlWEXdpW5OaFIp1jvqdDuOg==}
@@ -10542,7 +10532,6 @@ packages:
/undici/5.8.1:
resolution: {integrity: sha512-iDRmWX4Zar/4A/t+1LrKQRm102zw2l9Wgat3LtTlTn8ykvMZmAmpq9tjyHEigx18FsY7IfATvyN3xSw9BDz0eA==}
engines: {node: '>=12.18'}
dev: true
/unicode-canonical-property-names-ecmascript/2.0.0:
resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==}
@@ -10979,7 +10968,6 @@ packages:
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
dependencies:
defaults: 1.0.3
dev: true
/web-encoding/1.1.5:
resolution: {integrity: sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==}
@@ -11161,7 +11149,6 @@ packages:
optional: true
utf-8-validate:
optional: true
dev: true
/xdg-basedir/5.1.0:
resolution: {integrity: sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==}