mirror of
https://github.com/MetaFam/TheGame.git
synced 2026-04-24 03:00:09 -04:00
* beginning ESM transition: Ceramic libraries, Next.js, & TypeScript configuration 🇭🇰 * updating Chakra, React, & Next image `import`s 👔 * upgrading `@types/react`, import extensions for Node, & b64 SVG to PNG ⛹🏿♀️ * fixing relative import names & upddating @types packages 📻 * removoing WYSIWYG editor, draft-js, & updating express ⛹🏿♀️ * updating OpenSea 🚲 * ¡@metafam/utils is building! 📰 * ¡Discord bot is building! 👘 * ¡backend is building! 🛩 * fixed everything but Ceramic DID update 🏍 * switching to DID:PKH 📦 * fixing "only one child allowed" error 🙇🏿♀️ * importing `React` as required by tsc's `isolatedModules` 🇲🇰 * disabling testing rather than taking the time to fix jest ⚜ * removing set `types` from `tsconfig` to fix compilation error 🥦 * printing tests disabled warning, hopefully 🙀 * setting file to be copied to the new resolver 👁️🗨️ * "paths-resolver" not "paths-resolve" 🦴 * switching back to relative paths rather than trying to fix `paths` ⏳ * `yarn backend:dev` not working, testing GitHub build 🎺 * removing design system build & fixing some images ✊🏿 * fixed "expected function got string" error & trying to address undefined HTMLElement 🐡 * fixing @emotion/react tree shaking by making external 🏏 * including eslint config in Dockerfile 🌾 * fixing more images 🎯 * updating DIDs & switching back to an updated DID:3 ❇ * switching to w3s.link gateway & fixing early termination of storage endpoint 🔭 * switching back to ipfs.io gateway b/c w3s.link serves SVGs as application/xml which are CORB blocked 🥾 * fixing node config name in eslint ignore & shortening some paths 🧰 * fixing ts-node not handling project references 🥁
88 lines
2.4 KiB
TypeScript
88 lines
2.4 KiB
TypeScript
import Busboy from 'busboy';
|
|
import { CONFIG } from 'config';
|
|
import * as fs from 'fs';
|
|
import { mkdtemp, rmdir, unlink } from 'fs/promises';
|
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
|
import * as os from 'os';
|
|
import * as path from 'path';
|
|
import { Readable } from 'stream';
|
|
import { Web3Storage } from 'web3.storage';
|
|
|
|
export const handler: (
|
|
req: NextApiRequest,
|
|
res: NextApiResponse<Record<string, string>>,
|
|
) => Promise<void> = async (
|
|
req: NextApiRequest,
|
|
res: NextApiResponse<Record<string, string>>,
|
|
) => {
|
|
const upload = new Promise<Record<string, string>>((resolve, reject) => {
|
|
const storage = new Web3Storage({ token: CONFIG.web3StorageToken });
|
|
const busboy = Busboy({ headers: req.headers });
|
|
const files: { field: string; name: string }[] = [];
|
|
|
|
busboy.on(
|
|
'file',
|
|
async (fieldname: string, file: Readable, { filename }) => {
|
|
const field = path.basename(fieldname);
|
|
const name = path.join(
|
|
await mkdtemp(path.join(os.tmpdir(), `${field}-`)),
|
|
filename,
|
|
);
|
|
files.push({ field, name });
|
|
file.pipe(fs.createWriteStream(name));
|
|
},
|
|
);
|
|
|
|
busboy.on('finish', async () => {
|
|
try {
|
|
if (files.length === 0) {
|
|
throw new Error('No files uploaded.');
|
|
}
|
|
|
|
const tmpFiles = files.map(({ field, name }) => ({
|
|
name: `${field}/${path.basename(name)}`,
|
|
stream: () =>
|
|
fs.createReadStream(name) as unknown as ReadableStream<string>,
|
|
}));
|
|
const cid = await storage.put(tmpFiles);
|
|
|
|
await Promise.all(
|
|
files.map(async ({ name }) => {
|
|
await unlink(name);
|
|
await rmdir(path.dirname(name));
|
|
}),
|
|
);
|
|
|
|
const uploadedFiles = Object.fromEntries(
|
|
files.map(({ field, name }) => {
|
|
const filename = path.basename(name);
|
|
return [field, `${cid}/${field}/${filename}`];
|
|
}),
|
|
);
|
|
|
|
resolve(uploadedFiles);
|
|
} catch (err) {
|
|
reject((err as Error).message);
|
|
}
|
|
});
|
|
|
|
req.pipe(busboy);
|
|
});
|
|
|
|
try {
|
|
const uploaded = await upload;
|
|
res.status(201).json(uploaded);
|
|
} catch (err) {
|
|
console.error('error uploading to web3.storage', err);
|
|
res.status(500).json({ error: (err as Error).message });
|
|
}
|
|
};
|
|
|
|
export default handler;
|
|
|
|
export const config = {
|
|
api: {
|
|
bodyParser: false,
|
|
},
|
|
};
|