SHA256
UI: добавить вложения Arweave в каналы
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
const DEFAULT_ARWEAVE_GATEWAY = 'https://arweave.net';
|
||||
const WINSTON_PER_AR = 1_000_000_000_000n;
|
||||
const MAX_AVATAR_SOURCE_BYTES = 10 * 1024 * 1024;
|
||||
const MAX_ARWEAVE_ATTACHMENT_METADATA_BYTES = 50 * 1024 * 1024;
|
||||
const MAX_AVATAR_SIDE_PX = 768;
|
||||
const AVATAR_QUALITY = 0.86;
|
||||
const TX_ID_RE = /^[A-Za-z0-9_-]{43}$/;
|
||||
@@ -268,12 +269,42 @@ export async function prepareAvatarImageFile(file) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function uploadArweaveFile({ gateway, jwk, file, tags = [] }) {
|
||||
export async function loadArweaveFileMetadata({ gateway, txId, maxBytes = MAX_ARWEAVE_ATTACHMENT_METADATA_BYTES } = {}) {
|
||||
const url = buildArweaveDataUrl({ gateway, txId });
|
||||
const limit = Math.max(1, Number(maxBytes || MAX_ARWEAVE_ATTACHMENT_METADATA_BYTES));
|
||||
const response = await fetch(url, { method: 'GET', cache: 'no-store' });
|
||||
if (!response.ok) {
|
||||
throw new Error(`Не удалось скачать файл Arweave (${response.status} ${response.statusText})`);
|
||||
}
|
||||
|
||||
const lengthHeader = String(response.headers.get('content-length') || '').trim();
|
||||
const declaredSize = Number(lengthHeader);
|
||||
if (Number.isFinite(declaredSize) && declaredSize > limit) {
|
||||
throw new Error(`Файл слишком большой для локальной проверки. Максимум ${Math.round(limit / 1024 / 1024)} MB.`);
|
||||
}
|
||||
|
||||
const buffer = await response.arrayBuffer();
|
||||
if (buffer.byteLength > limit) {
|
||||
throw new Error(`Файл слишком большой для локальной проверки. Максимум ${Math.round(limit / 1024 / 1024)} MB.`);
|
||||
}
|
||||
|
||||
const cleanType = String(response.headers.get('content-type') || '').split(';')[0].trim();
|
||||
const sha256Hex = await sha256HexFromArrayBuffer(buffer);
|
||||
return {
|
||||
txId: String(txId || '').trim(),
|
||||
sizeBytes: buffer.byteLength,
|
||||
sha256Hex,
|
||||
contentType: cleanType,
|
||||
gateway: normalizeGateway(gateway),
|
||||
};
|
||||
}
|
||||
|
||||
export async function uploadArweaveFile({ gateway, jwk, file, tags = [], shineType = 'avatar' }) {
|
||||
if (!jwk || typeof jwk !== 'object') {
|
||||
throw new Error('Arweave-кошелёк не инициализирован.');
|
||||
}
|
||||
if (!(file instanceof File)) {
|
||||
throw new Error('Выберите файл изображения.');
|
||||
throw new Error('Выберите файл.');
|
||||
}
|
||||
|
||||
const normalizedGateway = normalizeGateway(gateway);
|
||||
@@ -287,14 +318,13 @@ export async function uploadArweaveFile({ gateway, jwk, file, tags = [] }) {
|
||||
const tx = await arweave.createTransaction({ data }, jwk);
|
||||
tx.addTag('Content-Type', String(file.type || 'application/octet-stream'));
|
||||
tx.addTag('App-Name', 'SHiNE');
|
||||
tx.addTag('SHiNE-Type', 'avatar');
|
||||
tx.addTag('SHiNE-Type', String(shineType || 'file'));
|
||||
const extraTags = Array.isArray(tags) ? tags : [];
|
||||
const profileLoginTag = extraTags.find((item) => String(item?.name || '').trim() === 'SHiNE-Profile-Login');
|
||||
const profileLogin = String(profileLoginTag?.value || '').trim();
|
||||
if (!profileLogin) {
|
||||
throw new Error('Не указан логин профиля для тега SHiNE-Profile-Login');
|
||||
}
|
||||
tx.addTag('SHiNE-Profile-Login', profileLogin);
|
||||
extraTags.forEach((item) => {
|
||||
const name = String(item?.name || '').trim();
|
||||
const value = String(item?.value || '').trim();
|
||||
if (name && value) tx.addTag(name, value);
|
||||
});
|
||||
|
||||
await arweave.transactions.sign(tx, jwk);
|
||||
const postResult = await arweave.transactions.post(tx);
|
||||
|
||||
Reference in New Issue
Block a user