mirror of
https://github.com/MetaFam/TheGame.git
synced 2026-04-24 03:00:09 -04:00
@@ -55,7 +55,7 @@ import { errorHandler } from 'utils/errorHandler';
|
||||
import { getImageDimensions } from 'utils/imageHelpers';
|
||||
import { isEmpty } from 'utils/objectHelpers';
|
||||
import { hasuraToComposeDBProfile } from 'utils/playerHelpers';
|
||||
import { directUpload } from 'utils/uploadHelpers';
|
||||
import { uploadFiles } from 'utils/uploadHelpers';
|
||||
|
||||
import { ConnectToProgress } from './ConnectToProgress';
|
||||
import { EditAvatarImage } from './Player/Profile/EditAvatarImage';
|
||||
@@ -174,6 +174,8 @@ export const EditProfileModal: React.FC<EditProfileModalProps> = ({
|
||||
return null;
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
|
||||
const changedInputs = Object.fromEntries(
|
||||
Object.entries(inputs).filter(([key]) => !isHasuraImageField(key)),
|
||||
);
|
||||
@@ -183,32 +185,51 @@ export const EditProfileModal: React.FC<EditProfileModalProps> = ({
|
||||
hasuraImageFields.map((field) => [field, null]),
|
||||
) as Record<HasuraImageFieldKey, Maybe<ComposeDBImageMetadata>>;
|
||||
|
||||
const toType = (key: string) => {
|
||||
const match = key.match(/^(.+?)(Image)?(URL)$/i);
|
||||
const [name] = match?.slice(1) ?? ['unknown'];
|
||||
return name;
|
||||
};
|
||||
|
||||
if (Object.keys(pickedFiles).length > 0) {
|
||||
setStatus('Uploading images to web3.storage…');
|
||||
|
||||
const rootCID = await directUpload(Object.values(pickedFiles));
|
||||
// Upload all the files to /api/storage
|
||||
Object.entries(pickedFiles).forEach(([key, file]) => {
|
||||
formData.append(toType(key), file);
|
||||
});
|
||||
const response = await uploadFiles(formData);
|
||||
|
||||
await Promise.all(
|
||||
Object.entries(pickedFileDataURLs).map(async ([key, val]) => {
|
||||
setStatus('Calculating image metadata…');
|
||||
const file = pickedFiles[key as HasuraImageFieldKey];
|
||||
if (!file) {
|
||||
throw new Error(`No \`file\` for "${key}".`);
|
||||
const tKey = toType(key);
|
||||
if (!response[tKey]) {
|
||||
toast({
|
||||
title: 'Error Saving Image',
|
||||
description: `Uploaded "${tKey}" & didn't get a response back.`,
|
||||
status: 'warning',
|
||||
isClosable: true,
|
||||
duration: 8000,
|
||||
});
|
||||
} else {
|
||||
setStatus('Calculating image metadata…');
|
||||
const mime = getMimeType(val);
|
||||
const file = pickedFiles[key as HasuraImageFieldKey];
|
||||
|
||||
const imageMetadata = {
|
||||
url: `ipfs://${response[tKey]}`,
|
||||
mimeType: mime,
|
||||
size: file?.size,
|
||||
} as ComposeDBImageMetadata;
|
||||
|
||||
const { width, height } = await getImageDimensions(val);
|
||||
if (width && height) {
|
||||
imageMetadata.width = width;
|
||||
imageMetadata.height = height;
|
||||
}
|
||||
|
||||
profileImages[key as HasuraImageFieldKey] = imageMetadata;
|
||||
}
|
||||
|
||||
const imageMetadata = {
|
||||
url: `ipfs://${rootCID}/${file.name}`,
|
||||
mimeType: getMimeType(val),
|
||||
size: file.size,
|
||||
} as ComposeDBImageMetadata;
|
||||
|
||||
const { width, height } = await getImageDimensions(val);
|
||||
if (width && height) {
|
||||
imageMetadata.width = width;
|
||||
imageMetadata.height = height;
|
||||
}
|
||||
|
||||
profileImages[key as HasuraImageFieldKey] = imageMetadata;
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -26,8 +26,6 @@ export const CONFIG = {
|
||||
process.env.NEXT_PUBLIC_CERAMIC_NETWORK || 'mainnet' || 'testnet-clay',
|
||||
googleDataAPIKey: process.env.NEXT_PUBLIC_YOUTUBE_API_KEY,
|
||||
web3StorageToken: process.env.WEB3_STORAGE_TOKEN,
|
||||
web3StorageKey: process.env.WEB3_STORAGE_KEY,
|
||||
web3StorageProof: process.env.WEB3_STORAGE_PROOF,
|
||||
openseaAPIKey: process.env.OPENSEA_API_KEY,
|
||||
alchemyAPIKey: process.env.NEXT_PUBLIC_ALCHEMY_API_KEY,
|
||||
mainnetRPC: process.env.NEXT_PUBLIC_MAINNET_RPC || 'https://eth.llamarpc.com',
|
||||
|
||||
@@ -23,20 +23,15 @@
|
||||
"@honeybadger-io/js": "^4.3.1",
|
||||
"@honeybadger-io/react": "^4.4.1",
|
||||
"@honeybadger-io/webpack": "^4.3.1",
|
||||
"@ipld/car": "^5.2.6",
|
||||
"@ipld/dag-ucan": "^3.4.0",
|
||||
"@metafam/ds": "0.2.0",
|
||||
"@metafam/utils": "1.0.1",
|
||||
"@orbisclub/orbis-sdk": "^0.4.40",
|
||||
"@quest-chains/sdk": "0.2.9",
|
||||
"@react-spring/web": "9.4.3",
|
||||
"@types/luxon": "^3.3.2",
|
||||
"@ucanto/core": "^9.0.1",
|
||||
"@ucanto/principal": "^9.0.0",
|
||||
"@urql/exchange-retry": "^1.2.0",
|
||||
"@userback/react": "^0.1.4",
|
||||
"@walletconnect/web3-provider": "1.7.3",
|
||||
"@web3-storage/w3up-client": "^12.0.0",
|
||||
"busboy": "1.6.0",
|
||||
"chakra-ui-markdown-renderer": "^4.1.0",
|
||||
"cids": "^1.1.9",
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
import { CarReader } from '@ipld/car';
|
||||
import * as DID from '@ipld/dag-ucan/did';
|
||||
import * as Delegation from '@ucanto/core/delegation';
|
||||
import type { Block } from '@ucanto/interface';
|
||||
import * as Signer from '@ucanto/principal/ed25519';
|
||||
import * as Client from '@web3-storage/w3up-client';
|
||||
import { CONFIG } from 'config';
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
|
||||
async function w3sDelegation(did: string) {
|
||||
if (!CONFIG.web3StorageKey) {
|
||||
throw new Error('$WEB3_STORAGE_KEY is not set.');
|
||||
}
|
||||
const principal = Signer.parse(CONFIG.web3StorageKey);
|
||||
const client = await Client.create({ principal });
|
||||
|
||||
if (!CONFIG.web3StorageProof) {
|
||||
throw new Error('$WEB3_STORAGE_PROOF is not set.');
|
||||
}
|
||||
const proof = await parseProof(CONFIG.web3StorageProof);
|
||||
const space = await client.addSpace(proof);
|
||||
await client.setCurrentSpace(space.did());
|
||||
|
||||
const audience = DID.parse(did);
|
||||
const abilities = ['store/add', 'upload/add'];
|
||||
const expiration = Math.floor(Date.now() / 1000) + 60 * 60 * 24; // 24 hours from now
|
||||
const delegation = await client.createDelegation(audience, abilities, {
|
||||
expiration,
|
||||
});
|
||||
|
||||
const archive = await delegation.archive();
|
||||
return archive.ok;
|
||||
}
|
||||
|
||||
/** @param {string} data Base64 encoded CAR file */
|
||||
async function parseProof(proof: string) {
|
||||
const blocks = [];
|
||||
const reader = await CarReader.fromBytes(Buffer.from(proof, 'base64'));
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for await (const block of reader.blocks()) {
|
||||
blocks.push(block as Block<unknown, number, number, 1>);
|
||||
}
|
||||
return Delegation.importDAG(blocks);
|
||||
}
|
||||
|
||||
export const handler: (
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse<Record<string, string>>,
|
||||
) => Promise<void> = async (
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse<Record<string, string>>,
|
||||
) => {
|
||||
try {
|
||||
const { did } = req.body;
|
||||
if (!did) {
|
||||
throw new Error('Missing `did` in request body.');
|
||||
}
|
||||
const ucan = await w3sDelegation(did);
|
||||
if (!ucan) {
|
||||
throw new Error(`No UCAN generated for "${did}".`);
|
||||
}
|
||||
res.status(201).json({ ucan: ucan.toString() });
|
||||
} catch (error) {
|
||||
console.error({ 'error generating W3S UCAN': error });
|
||||
res.status(500).json({ error: (error as Error).message });
|
||||
}
|
||||
};
|
||||
|
||||
export default handler;
|
||||
@@ -1,6 +1,3 @@
|
||||
import * as Delegation from '@ucanto/core/delegation';
|
||||
import * as Client from '@web3-storage/w3up-client';
|
||||
|
||||
export const uploadFile = async (file: File): Promise<string> => {
|
||||
const formData = new FormData();
|
||||
formData.append('ipfsHash', file);
|
||||
@@ -32,25 +29,3 @@ export const uploadFiles = async (formData: FormData) => {
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
export const directUpload = async (files: Array<File>) => {
|
||||
const client = await Client.create();
|
||||
|
||||
const response = await fetch('/api/w3s-delegation', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ did: client.did().toString() }),
|
||||
});
|
||||
const raw = await response.arrayBuffer();
|
||||
const delegation = await Delegation.extract(new Uint8Array(raw));
|
||||
if (!delegation.ok) {
|
||||
throw new Error('Failed to extract delegation', {
|
||||
cause: delegation.error,
|
||||
});
|
||||
}
|
||||
|
||||
const space = await client.addSpace(delegation.ok);
|
||||
client.setCurrentSpace(space.did());
|
||||
|
||||
return client.uploadDirectory(files);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user