mirror of
https://github.com/captbaritone/webamp.git
synced 2026-01-23 02:15:01 +00:00
Bluesky bot
This commit is contained in:
parent
3c882550e3
commit
e5ed88c8ec
7 changed files with 330 additions and 6 deletions
|
|
@ -35,6 +35,7 @@ import { setHashesForSkin } from "./skinHash";
|
|||
import * as S3 from "./s3";
|
||||
import { generateDescription } from "./services/openAi";
|
||||
import KeyValue from "./data/KeyValue";
|
||||
import { postToBluesky } from "./tasks/bluesky";
|
||||
|
||||
async function withHandler(
|
||||
cb: (handler: DiscordEventHandler) => Promise<void>
|
||||
|
|
@ -81,21 +82,30 @@ program
|
|||
.argument("[md5]", "md5 of the skin to share")
|
||||
.option("-t, --twitter", "Share on Twitter")
|
||||
.option("-i, --instagram", "Share on Instagram")
|
||||
.option("-b, --bluesky", "Share on Bluesky")
|
||||
.option("-m, --mastodon", "Share on Mastodon")
|
||||
.action(async (md5, { twitter, instagram, mastodon }) => {
|
||||
if (!twitter && !instagram && !mastodon) {
|
||||
throw new Error("Expected at least one of --twitter or --instagram");
|
||||
}
|
||||
.action(async (md5, { twitter, instagram, mastodon, bluesky }) => {
|
||||
await withDiscordClient(async (client) => {
|
||||
if (twitter) {
|
||||
await tweet(client, md5);
|
||||
return;
|
||||
}
|
||||
if (instagram) {
|
||||
await insta(client, md5);
|
||||
return;
|
||||
}
|
||||
if (mastodon) {
|
||||
await postToMastodon(client, md5);
|
||||
return;
|
||||
}
|
||||
if (bluesky) {
|
||||
await postToBluesky(client, md5);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
"Expected at least one of --twitter, --instagram, --mastodon, --bluesky"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ export const INSTAGRAM_ACCOUNT_ID = env("INSTAGRAM_ACCOUNT_ID");
|
|||
// Used for session encryption
|
||||
export const SECRET = env("SECRET");
|
||||
export const NODE_ENV = env("NODE_ENV") || "production";
|
||||
export const BLUESKY_PASSWORD = env("BLUESKY_PASSWORD");
|
||||
export const BLUESKY_USERNAME = env("BLUESKY_USERNAME");
|
||||
|
||||
function env(key: string): string {
|
||||
const value = process.env[key];
|
||||
|
|
|
|||
|
|
@ -144,6 +144,17 @@ export async function markAsPostedToMastodon(
|
|||
);
|
||||
}
|
||||
|
||||
export async function markAsPostedToBlueSky(
|
||||
md5: string,
|
||||
postId: string,
|
||||
url: string
|
||||
): Promise<void> {
|
||||
await knex("bluesky_posts").insert(
|
||||
{ skin_md5: md5, post_id: postId, url },
|
||||
[]
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Also path actor
|
||||
export async function markAsNSFW(ctx: UserContext, md5: string): Promise<void> {
|
||||
const index = { objectID: md5, nsfw: true };
|
||||
|
|
@ -550,6 +561,31 @@ export async function getSkinToPostToMastodon(): Promise<string | null> {
|
|||
return skin.md5;
|
||||
}
|
||||
|
||||
export async function getSkinToPostToBluesky(): Promise<string | null> {
|
||||
// TODO: This does not account for skins that have been both approved and rejected
|
||||
const postables = await knex("skins")
|
||||
.leftJoin("skin_reviews", "skin_reviews.skin_md5", "=", "skins.md5")
|
||||
.leftJoin("bluesky_posts", "bluesky_posts.skin_md5", "=", "skins.md5")
|
||||
.leftJoin("tweets", "tweets.skin_md5", "=", "skins.md5")
|
||||
.leftJoin("refreshes", "refreshes.skin_md5", "=", "skins.md5")
|
||||
.where({
|
||||
"bluesky_posts.id": null,
|
||||
skin_type: 1,
|
||||
"skin_reviews.review": "APPROVED",
|
||||
"refreshes.error": null,
|
||||
})
|
||||
.where("likes", ">", 10)
|
||||
.groupBy("skins.md5")
|
||||
.orderByRaw("random()")
|
||||
.limit(1);
|
||||
|
||||
const skin = postables[0];
|
||||
if (skin == null) {
|
||||
return null;
|
||||
}
|
||||
return skin.md5;
|
||||
}
|
||||
|
||||
export async function getUnreviewedSkinCount(): Promise<number> {
|
||||
const rows = await knex("skins")
|
||||
.where({ skin_type: 1 })
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
import * as Knex from "knex";
|
||||
|
||||
export async function up(knex: Knex): Promise<any> {
|
||||
await knex.raw(
|
||||
`CREATE TABLE "bluesky_posts" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
"skin_md5" TEXT NOT NULL,
|
||||
post_id text NOT NULL UNIQUE,
|
||||
url text NOT NULL UNIQUE
|
||||
);`
|
||||
);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<any> {
|
||||
await knex.raw(`DROP TABLE "bluesky_posts"`);
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@atproto/api": "^0.17.2",
|
||||
"@next/third-parties": "^15.3.3",
|
||||
"@sentry/node": "^5.27.3",
|
||||
"@sentry/tracing": "^5.27.3",
|
||||
|
|
|
|||
173
packages/skin-database/tasks/bluesky.ts
Normal file
173
packages/skin-database/tasks/bluesky.ts
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
import * as Skins from "../data/skins";
|
||||
import {
|
||||
AppBskyEmbedImages,
|
||||
AppBskyFeedPost,
|
||||
AtpAgent,
|
||||
BlobRef,
|
||||
RichText,
|
||||
} from "@atproto/api";
|
||||
import {
|
||||
TWEET_BOT_CHANNEL_ID,
|
||||
BLUESKY_USERNAME,
|
||||
BLUESKY_PASSWORD,
|
||||
} from "../config";
|
||||
import { Client } from "discord.js";
|
||||
import sharp from "sharp";
|
||||
import SkinModel from "../data/SkinModel";
|
||||
import UserContext from "../data/UserContext";
|
||||
import { withBufferAsTempFile } from "../utils";
|
||||
import fs from "fs";
|
||||
|
||||
const agent = new AtpAgent({ service: "https://bsky.social" });
|
||||
|
||||
export async function postToBluesky(
|
||||
discordClient: Client,
|
||||
md5: string | null
|
||||
): Promise<void> {
|
||||
if (md5 == null) {
|
||||
md5 = await Skins.getSkinToPostToBluesky();
|
||||
}
|
||||
if (md5 == null) {
|
||||
console.error("No skins to post to Bluesky");
|
||||
return;
|
||||
}
|
||||
const url = await post(md5);
|
||||
|
||||
console.log("Going to post to discord");
|
||||
const tweetBotChannel = await discordClient.channels.fetch(
|
||||
TWEET_BOT_CHANNEL_ID
|
||||
);
|
||||
// @ts-ignore
|
||||
await tweetBotChannel.send(url);
|
||||
console.log("Posted to discord");
|
||||
}
|
||||
|
||||
async function post(md5: string): Promise<string> {
|
||||
const ctx = new UserContext();
|
||||
const skin = await SkinModel.fromMd5Assert(ctx, md5);
|
||||
const screenshot = await Skins.getScreenshotBuffer(md5);
|
||||
const { width, height } = await sharp(screenshot).metadata();
|
||||
|
||||
const image = await sharp(screenshot)
|
||||
.resize(width * 2, height * 2, {
|
||||
kernel: sharp.kernel.nearest,
|
||||
})
|
||||
.toBuffer();
|
||||
|
||||
const name = await skin.getFileName();
|
||||
const url = skin.getMuseumUrl();
|
||||
const screenshotFileName = await skin.getScreenshotFileName();
|
||||
|
||||
const status = `${name}\n`; // TODO: Should we add hashtags?
|
||||
|
||||
await agent.login({
|
||||
identifier: BLUESKY_USERNAME!,
|
||||
password: BLUESKY_PASSWORD!,
|
||||
});
|
||||
|
||||
const blob = await withBufferAsTempFile(
|
||||
image,
|
||||
screenshotFileName,
|
||||
async (filePath) => {
|
||||
return uploadImageFromFilePath(agent, filePath);
|
||||
}
|
||||
);
|
||||
|
||||
const postData = await buildPost(
|
||||
agent,
|
||||
status,
|
||||
buildImageEmbed(blob, width * 2, height * 2)
|
||||
);
|
||||
const postResp = await agent.post(postData);
|
||||
console.log(postResp);
|
||||
|
||||
const postId = postResp.cid;
|
||||
const postUrl = postResp.uri;
|
||||
|
||||
await Skins.markAsPostedToBlueSky(md5, postId, postUrl);
|
||||
|
||||
const prefix = "Try on the ";
|
||||
const suffix = "Winamp Skin Museum";
|
||||
|
||||
agent.post({
|
||||
text: prefix + suffix,
|
||||
createdAt: new Date().toISOString(),
|
||||
facets: [
|
||||
{
|
||||
$type: "app.bsky.richtext.facet",
|
||||
index: {
|
||||
byteStart: prefix.length,
|
||||
byteEnd: prefix.length + suffix.length,
|
||||
},
|
||||
features: [
|
||||
{
|
||||
$type: "app.bsky.richtext.facet#link",
|
||||
uri: url,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
reply: {
|
||||
root: postResp,
|
||||
parent: postResp,
|
||||
},
|
||||
$type: "app.bsky.feed.post",
|
||||
});
|
||||
|
||||
// return permalink;
|
||||
return postUrl;
|
||||
}
|
||||
|
||||
/** Build the embed data for an image. */
|
||||
function buildImageEmbed(
|
||||
imgBlob: BlobRef,
|
||||
width: number,
|
||||
height: number
|
||||
): AppBskyEmbedImages.Main {
|
||||
const image = {
|
||||
image: imgBlob,
|
||||
aspectRatio: { width, height },
|
||||
alt: "",
|
||||
};
|
||||
return {
|
||||
$type: "app.bsky.embed.images",
|
||||
images: [image],
|
||||
};
|
||||
}
|
||||
|
||||
/** Build the post data for an image. */
|
||||
async function buildPost(
|
||||
agent: AtpAgent,
|
||||
rawText: string,
|
||||
imageEmbed: AppBskyEmbedImages.Main
|
||||
): Promise<AppBskyFeedPost.Record> {
|
||||
const rt = new RichText({ text: rawText });
|
||||
await rt.detectFacets(agent);
|
||||
const { text, facets } = rt;
|
||||
return {
|
||||
text,
|
||||
facets,
|
||||
$type: "app.bsky.feed.post",
|
||||
createdAt: new Date().toISOString(),
|
||||
embed: {
|
||||
$type: "app.bsky.embed.recordWithMedia",
|
||||
...imageEmbed,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/** Upload an image from a URL to Bluesky. */
|
||||
async function uploadImageFromFilePath(
|
||||
agent: AtpAgent,
|
||||
filePath: string
|
||||
): Promise<BlobRef> {
|
||||
const imageBuff = fs.readFileSync(filePath);
|
||||
const imgU8 = new Uint8Array(imageBuff);
|
||||
|
||||
const dstResp = await agent.uploadBlob(imgU8);
|
||||
if (!dstResp.success) {
|
||||
console.log(dstResp);
|
||||
throw new Error("Failed to upload image");
|
||||
}
|
||||
return dstResp.data.blob;
|
||||
}
|
||||
90
pnpm-lock.yaml
generated
90
pnpm-lock.yaml
generated
|
|
@ -124,6 +124,9 @@ importers:
|
|||
|
||||
packages/skin-database:
|
||||
dependencies:
|
||||
'@atproto/api':
|
||||
specifier: ^0.17.2
|
||||
version: 0.17.2
|
||||
'@next/third-parties':
|
||||
specifier: ^15.3.3
|
||||
version: 15.3.3(next@15.3.3(@babel/core@7.27.4)(babel-plugin-macros@3.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)
|
||||
|
|
@ -198,7 +201,7 @@ importers:
|
|||
version: 2.7.0(encoding@0.1.13)
|
||||
openai:
|
||||
specifier: ^4.68.0
|
||||
version: 4.68.0(encoding@0.1.13)
|
||||
version: 4.68.0(encoding@0.1.13)(zod@3.25.76)
|
||||
polygon-clipping:
|
||||
specifier: ^0.15.3
|
||||
version: 0.15.7
|
||||
|
|
@ -786,6 +789,21 @@ packages:
|
|||
'@assemblyscript/loader@0.17.14':
|
||||
resolution: {integrity: sha512-+PVTOfla/0XMLRTQLJFPg4u40XcdTfon6GGea70hBGi8Pd7ZymIXyVUR+vK8wt5Jb4MVKTKPIz43Myyebw5mZA==}
|
||||
|
||||
'@atproto/api@0.17.2':
|
||||
resolution: {integrity: sha512-luRY9YPaRQFpm3v7a1bTOaekQ/KPCG3gb0jVyaOtfMXDSfIZJh9lr9MtmGPdEp7AvfE8urkngZ+V/p8Ial3z2g==}
|
||||
|
||||
'@atproto/common-web@0.4.3':
|
||||
resolution: {integrity: sha512-nRDINmSe4VycJzPo6fP/hEltBcULFxt9Kw7fQk6405FyAWZiTluYHlXOnU7GkQfeUK44OENG1qFTBcmCJ7e8pg==}
|
||||
|
||||
'@atproto/lexicon@0.5.1':
|
||||
resolution: {integrity: sha512-y8AEtYmfgVl4fqFxqXAeGvhesiGkxiy3CWoJIfsFDDdTlZUC8DFnZrYhcqkIop3OlCkkljvpSJi1hbeC1tbi8A==}
|
||||
|
||||
'@atproto/syntax@0.4.1':
|
||||
resolution: {integrity: sha512-CJdImtLAiFO+0z3BWTtxwk6aY5w4t8orHTMVJgkf++QRJWTxPbIFko/0hrkADB7n2EruDxDSeAgfUGehpH6ngw==}
|
||||
|
||||
'@atproto/xrpc@0.7.5':
|
||||
resolution: {integrity: sha512-MUYNn5d2hv8yVegRL0ccHvTHAVj5JSnW07bkbiaz96UH45lvYNRVwt44z+yYVnb0/mvBzyD3/ZQ55TRGt7fHkA==}
|
||||
|
||||
'@babel/code-frame@7.27.1':
|
||||
resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
|
@ -4663,6 +4681,9 @@ packages:
|
|||
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
await-lock@2.2.2:
|
||||
resolution: {integrity: sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==}
|
||||
|
||||
aws-sdk@2.1592.0:
|
||||
resolution: {integrity: sha512-iwmS46jOEHMNodfrpNBJ5eHwjKAY05t/xYV2cp+KyzMX2yGgt2/EtWWnlcoMGBKR31qKTsjMj5ZPouC9/VeDOA==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
|
|
@ -8204,6 +8225,9 @@ packages:
|
|||
isexe@2.0.0:
|
||||
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
|
||||
|
||||
iso-datestring-validator@2.2.2:
|
||||
resolution: {integrity: sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==}
|
||||
|
||||
isobject@2.1.0:
|
||||
resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
|
@ -9500,6 +9524,9 @@ packages:
|
|||
resolution: {integrity: sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==}
|
||||
hasBin: true
|
||||
|
||||
multiformats@9.9.0:
|
||||
resolution: {integrity: sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==}
|
||||
|
||||
multipipe@0.1.2:
|
||||
resolution: {integrity: sha512-7ZxrUybYv9NonoXgwoOqtStIu18D1c3eFZj27hqgf5kBrBF8Q+tE8V0MW8dKM5QLkQPh1JhhbKgHLY9kifov4Q==}
|
||||
|
||||
|
|
@ -12514,6 +12541,10 @@ packages:
|
|||
tinyqueue@1.2.3:
|
||||
resolution: {integrity: sha512-Qz9RgWuO9l8lT+Y9xvbzhPT2efIUIFd69N7eF7tJ9lnQl0iLj1M7peK7IoUGZL9DJHw9XftqLreccfxcQgYLxA==}
|
||||
|
||||
tlds@1.260.0:
|
||||
resolution: {integrity: sha512-78+28EWBhCEE7qlyaHA9OR3IPvbCLiDh3Ckla593TksfFc9vfTsgvH7eS+dr3o9qr31gwGbogcI16yN91PoRjQ==}
|
||||
hasBin: true
|
||||
|
||||
tmp@0.0.33:
|
||||
resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==}
|
||||
engines: {node: '>=0.6.0'}
|
||||
|
|
@ -12827,6 +12858,9 @@ packages:
|
|||
resolution: {integrity: sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
uint8arrays@3.0.0:
|
||||
resolution: {integrity: sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==}
|
||||
|
||||
unbox-primitive@1.0.2:
|
||||
resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
|
||||
|
||||
|
|
@ -13548,6 +13582,9 @@ packages:
|
|||
zod@3.22.4:
|
||||
resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==}
|
||||
|
||||
zod@3.25.76:
|
||||
resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
|
||||
|
||||
zwitch@2.0.4:
|
||||
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
|
||||
|
||||
|
|
@ -13746,6 +13783,39 @@ snapshots:
|
|||
|
||||
'@assemblyscript/loader@0.17.14': {}
|
||||
|
||||
'@atproto/api@0.17.2':
|
||||
dependencies:
|
||||
'@atproto/common-web': 0.4.3
|
||||
'@atproto/lexicon': 0.5.1
|
||||
'@atproto/syntax': 0.4.1
|
||||
'@atproto/xrpc': 0.7.5
|
||||
await-lock: 2.2.2
|
||||
multiformats: 9.9.0
|
||||
tlds: 1.260.0
|
||||
zod: 3.25.76
|
||||
|
||||
'@atproto/common-web@0.4.3':
|
||||
dependencies:
|
||||
graphemer: 1.4.0
|
||||
multiformats: 9.9.0
|
||||
uint8arrays: 3.0.0
|
||||
zod: 3.25.76
|
||||
|
||||
'@atproto/lexicon@0.5.1':
|
||||
dependencies:
|
||||
'@atproto/common-web': 0.4.3
|
||||
'@atproto/syntax': 0.4.1
|
||||
iso-datestring-validator: 2.2.2
|
||||
multiformats: 9.9.0
|
||||
zod: 3.25.76
|
||||
|
||||
'@atproto/syntax@0.4.1': {}
|
||||
|
||||
'@atproto/xrpc@0.7.5':
|
||||
dependencies:
|
||||
'@atproto/lexicon': 0.5.1
|
||||
zod: 3.25.76
|
||||
|
||||
'@babel/code-frame@7.27.1':
|
||||
dependencies:
|
||||
'@babel/helper-validator-identifier': 7.27.1
|
||||
|
|
@ -18518,6 +18588,8 @@ snapshots:
|
|||
dependencies:
|
||||
possible-typed-array-names: 1.0.0
|
||||
|
||||
await-lock@2.2.2: {}
|
||||
|
||||
aws-sdk@2.1592.0:
|
||||
dependencies:
|
||||
buffer: 4.9.2
|
||||
|
|
@ -22832,6 +22904,8 @@ snapshots:
|
|||
|
||||
isexe@2.0.0: {}
|
||||
|
||||
iso-datestring-validator@2.2.2: {}
|
||||
|
||||
isobject@2.1.0:
|
||||
dependencies:
|
||||
isarray: 1.0.0
|
||||
|
|
@ -24903,6 +24977,8 @@ snapshots:
|
|||
dns-packet: 5.6.1
|
||||
thunky: 1.1.0
|
||||
|
||||
multiformats@9.9.0: {}
|
||||
|
||||
multipipe@0.1.2:
|
||||
dependencies:
|
||||
duplexer2: 0.0.2
|
||||
|
|
@ -25339,7 +25415,7 @@ snapshots:
|
|||
is-docker: 2.2.1
|
||||
is-wsl: 2.2.0
|
||||
|
||||
openai@4.68.0(encoding@0.1.13):
|
||||
openai@4.68.0(encoding@0.1.13)(zod@3.25.76):
|
||||
dependencies:
|
||||
'@types/node': 18.19.56
|
||||
'@types/node-fetch': 2.6.11
|
||||
|
|
@ -25348,6 +25424,8 @@ snapshots:
|
|||
form-data-encoder: 1.7.2
|
||||
formdata-node: 4.4.1
|
||||
node-fetch: 2.7.0(encoding@0.1.13)
|
||||
optionalDependencies:
|
||||
zod: 3.25.76
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
|
||||
|
|
@ -28430,6 +28508,8 @@ snapshots:
|
|||
|
||||
tinyqueue@1.2.3: {}
|
||||
|
||||
tlds@1.260.0: {}
|
||||
|
||||
tmp@0.0.33:
|
||||
dependencies:
|
||||
os-tmpdir: 1.0.2
|
||||
|
|
@ -28759,6 +28839,10 @@ snapshots:
|
|||
|
||||
uint8array-extras@1.4.0: {}
|
||||
|
||||
uint8arrays@3.0.0:
|
||||
dependencies:
|
||||
multiformats: 9.9.0
|
||||
|
||||
unbox-primitive@1.0.2:
|
||||
dependencies:
|
||||
call-bind: 1.0.7
|
||||
|
|
@ -29668,4 +29752,6 @@ snapshots:
|
|||
|
||||
zod@3.22.4: {}
|
||||
|
||||
zod@3.25.76: {}
|
||||
|
||||
zwitch@2.0.4: {}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue