@onexapis/cli 1.1.50 → 1.1.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +113 -3
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +113 -3
- package/dist/cli.mjs.map +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -4668,6 +4668,18 @@ var MIME_MAP = {
|
|
|
4668
4668
|
".json": "application/json"
|
|
4669
4669
|
};
|
|
4670
4670
|
var HASH_LEN = 8;
|
|
4671
|
+
var VIDEO_EXTENSIONS = [
|
|
4672
|
+
".mp4",
|
|
4673
|
+
".webm",
|
|
4674
|
+
".ogg",
|
|
4675
|
+
".mov",
|
|
4676
|
+
".avi",
|
|
4677
|
+
".mkv"
|
|
4678
|
+
];
|
|
4679
|
+
function isVideoAsset(filePath) {
|
|
4680
|
+
const lower = filePath.toLowerCase();
|
|
4681
|
+
return VIDEO_EXTENSIONS.some((ext) => lower.endsWith(ext));
|
|
4682
|
+
}
|
|
4671
4683
|
function mimeFor(filename) {
|
|
4672
4684
|
const ext = path9__default.default.extname(filename).toLowerCase();
|
|
4673
4685
|
return MIME_MAP[ext] || "application/octet-stream";
|
|
@@ -4869,8 +4881,30 @@ Or use the --bump flag:
|
|
|
4869
4881
|
);
|
|
4870
4882
|
process.exit(1);
|
|
4871
4883
|
}
|
|
4884
|
+
const videoAssets = assetEntries.filter((a) => isVideoAsset(a.originalPath));
|
|
4885
|
+
const regularAssets = assetEntries.filter(
|
|
4886
|
+
(a) => !isVideoAsset(a.originalPath)
|
|
4887
|
+
);
|
|
4888
|
+
const videoUrls = {};
|
|
4889
|
+
if (videoAssets.length > 0) {
|
|
4890
|
+
logger.startSpinner(`Uploading ${videoAssets.length} video(s)...`);
|
|
4891
|
+
try {
|
|
4892
|
+
for (const video of videoAssets) {
|
|
4893
|
+
const url = await uploadVideoMultipart(apiUrl, themeId, video);
|
|
4894
|
+
videoUrls[video.originalPath] = url;
|
|
4895
|
+
}
|
|
4896
|
+
logger.stopSpinner(true, `Uploaded ${videoAssets.length} video(s)`);
|
|
4897
|
+
} catch (error) {
|
|
4898
|
+
logger.stopSpinner(false, "Video upload failed");
|
|
4899
|
+
logger.error(error instanceof Error ? error.message : "Upload error");
|
|
4900
|
+
process.exit(1);
|
|
4901
|
+
}
|
|
4902
|
+
}
|
|
4872
4903
|
try {
|
|
4873
|
-
const assetMap = buildAssetMap(
|
|
4904
|
+
const assetMap = buildAssetMap(regularAssets);
|
|
4905
|
+
for (const [originalPath, url] of Object.entries(videoUrls)) {
|
|
4906
|
+
assetMap[originalPath] = url;
|
|
4907
|
+
}
|
|
4874
4908
|
const assetMapPath = path9__default.default.join(distDir, "asset-map.json");
|
|
4875
4909
|
await fs__default.default.writeFile(assetMapPath, JSON.stringify(assetMap, null, 2));
|
|
4876
4910
|
} catch (error) {
|
|
@@ -4891,7 +4925,7 @@ Or use the --bump flag:
|
|
|
4891
4925
|
method: "POST",
|
|
4892
4926
|
body: JSON.stringify({
|
|
4893
4927
|
version: version2,
|
|
4894
|
-
assets:
|
|
4928
|
+
assets: regularAssets.map((a) => ({
|
|
4895
4929
|
path: a.hashedPath,
|
|
4896
4930
|
hash: a.hash,
|
|
4897
4931
|
size: a.size,
|
|
@@ -4925,7 +4959,7 @@ Or use the --bump flag:
|
|
|
4925
4959
|
if (assetUploads.length > 0) {
|
|
4926
4960
|
logger.startSpinner(`Uploading ${assetUploads.length} asset(s) to S3...`);
|
|
4927
4961
|
const CONCURRENCY = 8;
|
|
4928
|
-
const byHashedPath = new Map(
|
|
4962
|
+
const byHashedPath = new Map(regularAssets.map((a) => [a.hashedPath, a]));
|
|
4929
4963
|
const queue = [...assetUploads];
|
|
4930
4964
|
let uploaded = 0;
|
|
4931
4965
|
let failed = 0;
|
|
@@ -5081,6 +5115,82 @@ Or use the --bump flag:
|
|
|
5081
5115
|
logger.newLine();
|
|
5082
5116
|
logger.success(`\u2713 Theme "${themeId}" v${version2} published!`);
|
|
5083
5117
|
}
|
|
5118
|
+
async function uploadVideoMultipart(apiUrl, themeId, video) {
|
|
5119
|
+
const fileName = path9__default.default.basename(video.originalPath);
|
|
5120
|
+
const initRes = await authenticatedFetch(
|
|
5121
|
+
`${apiUrl}/media/videos/multipart/init`,
|
|
5122
|
+
{
|
|
5123
|
+
method: "POST",
|
|
5124
|
+
body: JSON.stringify({
|
|
5125
|
+
file_name: fileName,
|
|
5126
|
+
content_type: video.contentType,
|
|
5127
|
+
file_size: video.size,
|
|
5128
|
+
prefix: `themes/${themeId}/assets`
|
|
5129
|
+
})
|
|
5130
|
+
}
|
|
5131
|
+
);
|
|
5132
|
+
const initData = await initRes.json();
|
|
5133
|
+
const initBody = initData.statusCode ? initData.body : initData;
|
|
5134
|
+
if (!initRes.ok || !initBody.upload_id) {
|
|
5135
|
+
throw new Error(
|
|
5136
|
+
`Init multipart failed for ${fileName}: ${initBody.error || initRes.status}`
|
|
5137
|
+
);
|
|
5138
|
+
}
|
|
5139
|
+
const { upload_id, file_key, chunk_size, chunk_urls } = initBody;
|
|
5140
|
+
const fileBuffer = await fs__default.default.promises.readFile(video.absPath);
|
|
5141
|
+
const CHUNK_CONCURRENCY = 4;
|
|
5142
|
+
const queue = [...chunk_urls];
|
|
5143
|
+
const parts = [];
|
|
5144
|
+
async function chunkWorker() {
|
|
5145
|
+
while (queue.length > 0) {
|
|
5146
|
+
const chunk = queue.shift();
|
|
5147
|
+
if (!chunk) break;
|
|
5148
|
+
const start = (chunk.part_number - 1) * chunk_size;
|
|
5149
|
+
const end = Math.min(start + chunk_size, fileBuffer.length);
|
|
5150
|
+
const body = fileBuffer.subarray(start, end);
|
|
5151
|
+
const res = await fetch(chunk.upload_url, { method: "PUT", body });
|
|
5152
|
+
if (!res.ok) {
|
|
5153
|
+
throw new Error(
|
|
5154
|
+
`Chunk ${chunk.part_number} upload failed: HTTP ${res.status}`
|
|
5155
|
+
);
|
|
5156
|
+
}
|
|
5157
|
+
const etag = res.headers.get("etag") || res.headers.get("ETag");
|
|
5158
|
+
if (!etag) {
|
|
5159
|
+
throw new Error(`Chunk ${chunk.part_number}: missing ETag header`);
|
|
5160
|
+
}
|
|
5161
|
+
parts.push({ part_number: chunk.part_number, etag });
|
|
5162
|
+
}
|
|
5163
|
+
}
|
|
5164
|
+
await Promise.all(
|
|
5165
|
+
Array.from(
|
|
5166
|
+
{ length: Math.min(CHUNK_CONCURRENCY, chunk_urls.length) },
|
|
5167
|
+
() => chunkWorker()
|
|
5168
|
+
)
|
|
5169
|
+
);
|
|
5170
|
+
parts.sort((a, b) => a.part_number - b.part_number);
|
|
5171
|
+
const completeRes = await authenticatedFetch(
|
|
5172
|
+
`${apiUrl}/media/videos/multipart/complete`,
|
|
5173
|
+
{
|
|
5174
|
+
method: "POST",
|
|
5175
|
+
body: JSON.stringify({ upload_id, file_key, parts })
|
|
5176
|
+
}
|
|
5177
|
+
);
|
|
5178
|
+
const completeData = await completeRes.json();
|
|
5179
|
+
const completeBody = completeData.statusCode ? completeData.body : completeData;
|
|
5180
|
+
if (!completeRes.ok || !completeBody.url) {
|
|
5181
|
+
try {
|
|
5182
|
+
await authenticatedFetch(`${apiUrl}/media/videos/multipart/abort`, {
|
|
5183
|
+
method: "POST",
|
|
5184
|
+
body: JSON.stringify({ upload_id, file_key })
|
|
5185
|
+
});
|
|
5186
|
+
} catch {
|
|
5187
|
+
}
|
|
5188
|
+
throw new Error(
|
|
5189
|
+
`Complete multipart failed for ${fileName}: ${completeBody.error || completeRes.status}`
|
|
5190
|
+
);
|
|
5191
|
+
}
|
|
5192
|
+
return completeBody.url;
|
|
5193
|
+
}
|
|
5084
5194
|
async function createZip(sourceDir, outputPath, exclude) {
|
|
5085
5195
|
const archiver2 = (await import('archiver')).default;
|
|
5086
5196
|
const { createWriteStream } = await import('fs');
|