storyblok 4.20.0 → 4.21.0
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/index.mjs +103 -21
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/dist/index.mjs
CHANGED
|
@@ -714,6 +714,7 @@ const API_ACTIONS = {
|
|
|
714
714
|
update_story: "Failed to update story",
|
|
715
715
|
pull_asset: "Failed to pull asset",
|
|
716
716
|
pull_assets: "Failed to pull assets",
|
|
717
|
+
transfer_enumerate_assets: "Failed to enumerate assets for transfer",
|
|
717
718
|
pull_asset_folder: "Failed to pull asset folder",
|
|
718
719
|
pull_asset_folders: "Failed to pull asset folders",
|
|
719
720
|
push_asset_folder: "Failed to push asset folder",
|
|
@@ -7476,6 +7477,27 @@ const fetchAssets = async ({ spaceId, params }) => {
|
|
|
7476
7477
|
handleAPIError("pull_assets", toError(maybeError));
|
|
7477
7478
|
}
|
|
7478
7479
|
};
|
|
7480
|
+
const fetchAllSpaceAssetIds = async (spaceId, params) => {
|
|
7481
|
+
try {
|
|
7482
|
+
const client = getMapiClient();
|
|
7483
|
+
const assets = await fetchAllPages(
|
|
7484
|
+
(page) => client.assets.list({
|
|
7485
|
+
path: { space_id: Number(spaceId) },
|
|
7486
|
+
query: { ...params, page, per_page: 100 },
|
|
7487
|
+
throwOnError: true
|
|
7488
|
+
}),
|
|
7489
|
+
(data) => data?.assets ?? []
|
|
7490
|
+
);
|
|
7491
|
+
return assets.reduce((ids, asset) => {
|
|
7492
|
+
if (typeof asset?.id === "number") {
|
|
7493
|
+
ids.push(asset.id);
|
|
7494
|
+
}
|
|
7495
|
+
return ids;
|
|
7496
|
+
}, []);
|
|
7497
|
+
} catch (maybeError) {
|
|
7498
|
+
handleAPIError("transfer_enumerate_assets", toError(maybeError));
|
|
7499
|
+
}
|
|
7500
|
+
};
|
|
7479
7501
|
const fetchAssetInternalTagsByName = async (spaceId) => {
|
|
7480
7502
|
try {
|
|
7481
7503
|
const client = getMapiClient();
|
|
@@ -7651,22 +7673,32 @@ const transferAsset = async (spaceId, assetId, folderId) => {
|
|
|
7651
7673
|
);
|
|
7652
7674
|
}
|
|
7653
7675
|
};
|
|
7676
|
+
const TRANSFER_CHUNK_SIZE = 500;
|
|
7654
7677
|
const transferAssets = async (spaceId, assetIds, folderId, callbacks = {}) => {
|
|
7655
7678
|
const lock = createPipelineBackpressureLock();
|
|
7656
|
-
|
|
7657
|
-
|
|
7658
|
-
|
|
7659
|
-
|
|
7660
|
-
|
|
7661
|
-
|
|
7662
|
-
|
|
7663
|
-
|
|
7664
|
-
|
|
7665
|
-
|
|
7666
|
-
|
|
7667
|
-
|
|
7668
|
-
|
|
7669
|
-
|
|
7679
|
+
const results = [];
|
|
7680
|
+
let completed = 0;
|
|
7681
|
+
for (let start = 0; start < assetIds.length; start += TRANSFER_CHUNK_SIZE) {
|
|
7682
|
+
const chunk = assetIds.slice(start, start + TRANSFER_CHUNK_SIZE);
|
|
7683
|
+
const chunkResults = await Promise.all(chunk.map(async (assetId) => {
|
|
7684
|
+
await lock.acquire();
|
|
7685
|
+
try {
|
|
7686
|
+
const asset = await transferAsset(spaceId, assetId, folderId);
|
|
7687
|
+
callbacks.onSuccess?.({ assetId, filename: asset.filename });
|
|
7688
|
+
return { assetId, status: "transferred", filename: asset.filename };
|
|
7689
|
+
} catch (maybeError) {
|
|
7690
|
+
const error = toError(maybeError);
|
|
7691
|
+
callbacks.onError?.(error, assetId);
|
|
7692
|
+
return { assetId, status: "failed", reason: error.message };
|
|
7693
|
+
} finally {
|
|
7694
|
+
lock.release();
|
|
7695
|
+
completed += 1;
|
|
7696
|
+
callbacks.onProgress?.(completed, assetIds.length);
|
|
7697
|
+
}
|
|
7698
|
+
}));
|
|
7699
|
+
results.push(...chunkResults);
|
|
7700
|
+
}
|
|
7701
|
+
return results;
|
|
7670
7702
|
};
|
|
7671
7703
|
const fetchSharedAssets = async ({ spaceId, libraryId, params }) => {
|
|
7672
7704
|
try {
|
|
@@ -10174,7 +10206,7 @@ pushCmd$1.action(async (assetInput, options, command) => {
|
|
|
10174
10206
|
}
|
|
10175
10207
|
});
|
|
10176
10208
|
|
|
10177
|
-
const transferCmd = assetsCommand.command("transfer
|
|
10209
|
+
const transferCmd = assetsCommand.command("transfer [asset-id...]").option("-s, --space <space>", "space ID").option("--folder-id <folderId>", "destination asset folder ID in the shared library").option("--all", "Transfer every asset in the space to the shared library").option("-q, --query <query>", 'Transfer every asset in the space matching a Storyblok filter query. Example: --query="search=my-file.jpg&with_tags=tag1,tag2"').option("-d, --dry-run", "Preview changes without applying them to Storyblok").description(`Transfer space assets into the organization's shared asset library.`);
|
|
10178
10210
|
transferCmd.action(async (assetIds, options, command) => {
|
|
10179
10211
|
const ui = getUI();
|
|
10180
10212
|
const logger = getLogger();
|
|
@@ -10203,12 +10235,43 @@ transferCmd.action(async (assetIds, options, command) => {
|
|
|
10203
10235
|
process.exitCode = 2;
|
|
10204
10236
|
return;
|
|
10205
10237
|
}
|
|
10206
|
-
|
|
10207
|
-
|
|
10208
|
-
|
|
10238
|
+
if (options.all && options.query) {
|
|
10239
|
+
handleError(new CommandError(`Cannot combine --all with --query. Use --all to transfer every asset, or --query to transfer a filtered subset.`), verbose);
|
|
10240
|
+
process.exitCode = 2;
|
|
10241
|
+
return;
|
|
10242
|
+
}
|
|
10243
|
+
const bulk = Boolean(options.all || options.query);
|
|
10244
|
+
if (bulk && assetIds.length > 0) {
|
|
10245
|
+
handleError(new CommandError(`Cannot combine explicit asset IDs with --all or --query.`), verbose);
|
|
10209
10246
|
process.exitCode = 2;
|
|
10210
10247
|
return;
|
|
10211
10248
|
}
|
|
10249
|
+
let ids;
|
|
10250
|
+
if (bulk) {
|
|
10251
|
+
const params = options.query ? Object.fromEntries(new URLSearchParams(options.query)) : void 0;
|
|
10252
|
+
logger.info("Enumerating space assets", { space, query: options.query });
|
|
10253
|
+
try {
|
|
10254
|
+
ids = await fetchAllSpaceAssetIds(space, params);
|
|
10255
|
+
} catch (maybeError) {
|
|
10256
|
+
handleError(toError(maybeError), verbose);
|
|
10257
|
+
process.exitCode = 2;
|
|
10258
|
+
return;
|
|
10259
|
+
}
|
|
10260
|
+
logger.info("Enumerated space assets", { count: ids.length });
|
|
10261
|
+
if (ids.length === 0) {
|
|
10262
|
+
ui.info(options.query ? `No assets in space ${space} match the query. Nothing to transfer.` : `No assets found in space ${space}. Nothing to transfer.`);
|
|
10263
|
+
logger.info("Transferring assets finished (no assets found)");
|
|
10264
|
+
process.exitCode = 0;
|
|
10265
|
+
return;
|
|
10266
|
+
}
|
|
10267
|
+
} else {
|
|
10268
|
+
ids = assetIds.map((id) => Number(id)).filter((id) => !Number.isNaN(id));
|
|
10269
|
+
if (ids.length === 0) {
|
|
10270
|
+
handleError(new CommandError(`Please provide at least one valid asset ID, or use --all.`), verbose);
|
|
10271
|
+
process.exitCode = 2;
|
|
10272
|
+
return;
|
|
10273
|
+
}
|
|
10274
|
+
}
|
|
10212
10275
|
if (options.dryRun) {
|
|
10213
10276
|
const summary2 = { total: ids.length, succeeded: 0, failed: 0 };
|
|
10214
10277
|
ui.info(`Transfer plan: ${ids.length} asset(s) to folder ${folderId}`);
|
|
@@ -10219,14 +10282,33 @@ transferCmd.action(async (assetIds, options, command) => {
|
|
|
10219
10282
|
process.exitCode = 0;
|
|
10220
10283
|
return;
|
|
10221
10284
|
}
|
|
10285
|
+
const progress = ui.createProgressBar({ title: "Transferring assets..." });
|
|
10286
|
+
progress.setTotal(ids.length);
|
|
10222
10287
|
const results = await transferAssets(space, ids, folderId, {
|
|
10223
10288
|
onSuccess: ({ assetId, filename }) => logger.info("Transferred asset", { assetId, filename }),
|
|
10224
|
-
onError: (error, assetId) => logOnlyError(error, { assetId })
|
|
10289
|
+
onError: (error, assetId) => logOnlyError(error, { assetId }),
|
|
10290
|
+
onProgress: () => progress.increment()
|
|
10225
10291
|
});
|
|
10292
|
+
ui.stopAllProgressBars();
|
|
10226
10293
|
const succeeded = results.filter((result) => result.status === "transferred").length;
|
|
10227
10294
|
const summary = { total: results.length, succeeded, failed: results.length - succeeded };
|
|
10228
|
-
ui.info(`Transfer results: ${summary.
|
|
10229
|
-
|
|
10295
|
+
ui.info(`Transfer results: ${summary.succeeded} transferred, ${summary.failed} failed (of ${summary.total}).`);
|
|
10296
|
+
if (summary.failed > 0) {
|
|
10297
|
+
const countsByReason = /* @__PURE__ */ new Map();
|
|
10298
|
+
for (const result of results) {
|
|
10299
|
+
if (result.status === "failed") {
|
|
10300
|
+
const reason = result.reason ?? "Unknown error";
|
|
10301
|
+
countsByReason.set(reason, (countsByReason.get(reason) ?? 0) + 1);
|
|
10302
|
+
}
|
|
10303
|
+
}
|
|
10304
|
+
const byReason = [...countsByReason.entries()].sort((a, b) => b[1] - a[1]);
|
|
10305
|
+
const MAX_REASONS = 10;
|
|
10306
|
+
const lines = byReason.slice(0, MAX_REASONS).map(([reason, count]) => `\u2717 ${reason} (${count})`);
|
|
10307
|
+
if (byReason.length > MAX_REASONS) {
|
|
10308
|
+
lines.push(`\u2026 and ${byReason.length - MAX_REASONS} more failure reason(s)`);
|
|
10309
|
+
}
|
|
10310
|
+
ui.list(lines);
|
|
10311
|
+
}
|
|
10230
10312
|
reporter.addSummary("transferResults", summary);
|
|
10231
10313
|
reporter.finalize();
|
|
10232
10314
|
logger.info("Transferring assets finished", { summary });
|