everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
89 lines (87 loc) • 3.16 kB
JavaScript
const require_client = require('../../apps/upload/src/client.cjs');
let node_path = require("node:path");
let node_fs_promises = require("node:fs/promises");
//#region src/services/deploy/storage.ts
async function walkDist(dir, baseDir) {
const entries = await (0, node_fs_promises.readdir)(dir, { withFileTypes: true });
const files = [];
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
const fullPath = (0, node_path.join)(dir, entry.name);
if (entry.isDirectory()) {
files.push(...await walkDist(fullPath, baseDir));
continue;
}
if (!(await (0, node_fs_promises.stat)(fullPath)).isFile()) continue;
files.push({
path: (0, node_path.relative)(baseDir, fullPath).split(node_path.sep).join("/"),
bytes: new Uint8Array(await (0, node_fs_promises.readFile)(fullPath))
});
}
return files;
}
async function collectDistFiles(distDir) {
return walkDist(distDir, distDir);
}
async function uploadBundle(input) {
return await require_client.createUploadClient({
origin: input.origin,
apiKey: input.apiKey,
fetchImpl: input.fetchImpl
}).uploadBundle({
account: input.account,
gateway: input.gateway,
workspace: input.workspace,
files: input.files.map((file) => ({
path: file.path,
contentBase64: Buffer.from(file.bytes).toString("base64")
}))
});
}
/** Per-request file-count cap for `uploadWorkspaceDist`: each file costs the
* server a stat+put round trip against object storage, so request count — not
* byte size — is what keeps a batch inside the CDN proxy's response timeout. */
const DEFAULT_MAX_FILES_PER_REQUEST = 100;
async function uploadWorkspaceDist(input) {
const maxRequestBytes = input.maxRequestBytes ?? (Number(process.env.BOS_MAX_BUNDLE_UPLOAD_BYTES) || 67108864);
const maxFilesPerRequest = input.maxFilesPerRequest ?? 100;
const merged = {
stored: 0,
totalBytes: 0,
integrity: {}
};
let batch = [];
let batchBytes = 0;
const overheadPerFile = (file) => Math.ceil(file.bytes.byteLength / 3) * 4 + file.path.length + 64;
const flush = async () => {
if (batch.length === 0) return;
const result = await uploadBundle({
origin: input.origin,
apiKey: input.apiKey,
account: input.account,
gateway: input.gateway,
workspace: input.workspace,
files: batch
});
merged.stored += result.stored;
merged.totalBytes += result.totalBytes;
merged.unchanged = (merged.unchanged ?? 0) + (result.unchanged ?? 0);
Object.assign(merged.integrity, result.integrity);
merged.storage = result.storage;
batch = [];
batchBytes = 0;
};
for (const file of input.files) {
const cost = overheadPerFile(file);
if (cost > maxRequestBytes) throw new Error(`[publish] ${input.workspace}/${file.path} (${file.bytes.byteLength} bytes) exceeds the per-request upload ceiling`);
if (batchBytes + cost > maxRequestBytes || batch.length >= maxFilesPerRequest) await flush();
batch.push(file);
batchBytes += cost;
}
await flush();
return merged;
}
//#endregion
exports.collectDistFiles = collectDistFiles;
exports.uploadBundle = uploadBundle;
exports.uploadWorkspaceDist = uploadWorkspaceDist;
//# sourceMappingURL=storage.cjs.map