UNPKG

@strapi/data-transfer

Version:

Data transfer capabilities for Strapi

152 lines (148 loc) 6.07 kB
'use strict'; var path = require('path'); var stream = require('stream'); var fs = require('fs-extra'); function getFileStream(filepath, strapi, isLocal = false) { if (isLocal) { // Todo: handle errors return fs.createReadStream(filepath); } const readableStream = new stream.PassThrough(); // fetch the image from remote url and stream it strapi.fetch(filepath).then((res)=>{ if (res.status !== 200) { readableStream.emit('error', new Error(`Request failed with status code ${res.status}`)); return; } if (res.body) { // pipe the image data stream.Readable.fromWeb(res.body).pipe(readableStream); } else { readableStream.emit('error', new Error('Empty data found for file')); } }).catch((error)=>{ readableStream.emit('error', error); }); return readableStream; } function getFileStatsForTransfer(filepath, strapi, isLocal = false) { if (isLocal) { return fs.stat(filepath); } return new Promise((resolve, reject)=>{ strapi.fetch(filepath).then((res)=>{ if (res.status !== 200) { reject(new Error(`Request failed with status code ${res.status}`)); return; } const contentLength = res.headers.get('content-length'); const stats = { size: contentLength ? parseInt(contentLength, 10) : 0 }; resolve(stats); }).catch((error)=>{ reject(error); }); }); } async function signUploadFileForTransfer(strapi, file) { const { provider } = strapi.plugins.upload; const { provider: providerName } = strapi.config.get('plugin.upload'); const isPrivate = await provider.isPrivate(); if (file?.provider === providerName && isPrivate) { const signUrl = async (f)=>{ const signedUrl = await provider.getSignedUrl(f); f.url = signedUrl.url; }; await signUrl(file); if (file.formats) { for (const format of Object.keys(file.formats)){ await signUrl(file.formats[format]); } } } } const missingAssetWarningMessage = (file, filepath, format)=>{ const formatPart = format ? ` (format: ${format})` : ''; return `[Data transfer] Media item ${file.id} (hash: ${file.hash}) exists in database but no corresponding file was found to transfer${formatPart}. Path: ${filepath}`; }; /** * Generate and consume assets streams in order to stream each file individually */ const createAssetsStream = (strapi, options = {})=>{ const warnMissingAsset = (message)=>{ strapi.log.warn(message); options.onWarning?.(message); }; const generator = async function*() { const stream = strapi.db.queryBuilder('plugin::upload.file')// Create a query builder instance (default type is 'select') // Fetch all columns .select('*')// Get a readable stream .stream(); for await (const file of stream){ const isLocalProvider = file.provider === 'local'; if (!isLocalProvider) { await signUploadFileForTransfer(strapi, file); } const filepath = isLocalProvider ? path.join(strapi.dirs.static.public, file.url) : file.url; let stats; try { stats = await getFileStatsForTransfer(filepath, strapi, isLocalProvider); } catch (err) { const code = err && typeof err === 'object' && 'code' in err ? err.code : undefined; if (code === 'ENOENT') { warnMissingAsset(missingAssetWarningMessage(file, filepath)); continue; } throw err; } const stream = getFileStream(filepath, strapi, isLocalProvider); yield { metadata: file, filepath, filename: file.hash + file.ext, stream, stats: { size: stats.size } }; if (file.formats) { for (const format of Object.keys(file.formats)){ const fileFormat = file.formats[format]; const fileFormatFilepath = isLocalProvider ? path.join(strapi.dirs.static.public, fileFormat.url) : fileFormat.url; let fileFormatStats; try { fileFormatStats = await getFileStatsForTransfer(fileFormatFilepath, strapi, isLocalProvider); } catch (err) { const code = err && typeof err === 'object' && 'code' in err ? err.code : undefined; if (code === 'ENOENT') { warnMissingAsset(missingAssetWarningMessage(file, fileFormatFilepath, format)); continue; } throw err; } const fileFormatStream = getFileStream(fileFormatFilepath, strapi, isLocalProvider); const metadata = { ...fileFormat, type: format, id: file.id, mainHash: file.hash }; yield { metadata, filepath: fileFormatFilepath, filename: fileFormat.hash + fileFormat.ext, stream: fileFormatStream, stats: { size: fileFormatStats.size } }; } } } }; return stream.Duplex.from(generator()); }; exports.createAssetsStream = createAssetsStream; exports.getFileStatsForTransfer = getFileStatsForTransfer; exports.signUploadFileForTransfer = signUploadFileForTransfer; //# sourceMappingURL=assets.js.map