storyblok 4.17.11 → 4.18.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 CHANGED
@@ -715,6 +715,7 @@ const API_ACTIONS = {
715
715
  push_asset_update: "Failed to update asset",
716
716
  pull_asset_internal_tags: "Failed to pull asset internal tags",
717
717
  push_asset_internal_tag: "Failed to push asset internal tag",
718
+ transfer_asset: "Failed to transfer asset",
718
719
  pull_datasources: "Failed to pull datasources",
719
720
  push_datasource: "Failed to push datasource",
720
721
  update_datasource: "Failed to update datasource",
@@ -980,6 +981,17 @@ function toError(maybeError) {
980
981
  return new Error(String(maybeError));
981
982
  }
982
983
  }
984
+ function getResponseStatus(maybeError) {
985
+ const error = toError(maybeError);
986
+ if (!("response" in error)) {
987
+ return void 0;
988
+ }
989
+ const { response } = error;
990
+ if (!response || typeof response !== "object" || !("status" in response)) {
991
+ return void 0;
992
+ }
993
+ return typeof response.status === "number" ? response.status : void 0;
994
+ }
983
995
  function handleVerboseError(error) {
984
996
  if (error instanceof CommandError || error instanceof APIError || error instanceof FileSystemError) {
985
997
  const errorDetails = "getInfo" in error ? error.getInfo() : {};
@@ -1984,8 +1996,9 @@ const getUser = async (token, region) => {
1984
1996
  throwOnError: true
1985
1997
  });
1986
1998
  return data?.user;
1987
- } catch (error) {
1988
- const status = error?.response?.status;
1999
+ } catch (maybeError) {
2000
+ const error = toError(maybeError);
2001
+ const status = getResponseStatus(maybeError);
1989
2002
  const customMessage = status === 401 ? `The token provided ${chalk.bold(maskToken(token))} is invalid.
1990
2003
  Please make sure you are using the correct token and try again.` : void 0;
1991
2004
  handleAPIError("get_user", error, customMessage);
@@ -7291,6 +7304,41 @@ const createAsset = async (asset, fileBuffer, { spaceId }) => {
7291
7304
  handleAPIError("push_asset_create", toError(maybeError));
7292
7305
  }
7293
7306
  };
7307
+ const transferAsset = async (spaceId, assetId, folderId) => {
7308
+ try {
7309
+ const { data } = await getMapiClient().assets.convertToShared(assetId, {
7310
+ path: { space_id: Number(spaceId) },
7311
+ query: { target_asset_folder_id: folderId },
7312
+ throwOnError: true
7313
+ });
7314
+ return data;
7315
+ } catch (maybeError) {
7316
+ const error = toError(maybeError);
7317
+ const status = getResponseStatus(maybeError);
7318
+ handleAPIError(
7319
+ "transfer_asset",
7320
+ error,
7321
+ status === 403 ? `Not authorized to transfer into folder ${folderId}. Make sure it exists in the global asset library and that this space has write access to it.` : void 0
7322
+ );
7323
+ }
7324
+ };
7325
+ const transferAssets = async (spaceId, assetIds, folderId, callbacks = {}) => {
7326
+ const lock = createPipelineBackpressureLock();
7327
+ return Promise.all(assetIds.map(async (assetId) => {
7328
+ await lock.acquire();
7329
+ try {
7330
+ const asset = await transferAsset(spaceId, assetId, folderId);
7331
+ callbacks.onSuccess?.({ assetId, filename: asset.filename });
7332
+ return { assetId, status: "transferred", filename: asset.filename };
7333
+ } catch (maybeError) {
7334
+ const error = toError(maybeError);
7335
+ callbacks.onError?.(error, assetId);
7336
+ return { assetId, status: "failed", reason: error.message };
7337
+ } finally {
7338
+ lock.release();
7339
+ }
7340
+ }));
7341
+ };
7294
7342
 
7295
7343
  const parseAssetData = (raw) => {
7296
7344
  if (!raw) {
@@ -9169,6 +9217,65 @@ pushCmd$1.action(async (assetInput, options, command) => {
9169
9217
  }
9170
9218
  });
9171
9219
 
9220
+ const transferCmd = assetsCommand.command("transfer <asset-id...>").option("-s, --space <space>", "space ID").option("--folder-id <folderId>", "destination asset folder ID in the global library").option("-d, --dry-run", "Preview changes without applying them to Storyblok").description(`Transfer space assets into the organization's global asset library.`);
9221
+ transferCmd.action(async (assetIds, options, command) => {
9222
+ const ui = getUI();
9223
+ const logger = getLogger();
9224
+ const reporter = getReporter();
9225
+ ui.title(`${commands.ASSETS}`, colorPalette.ASSETS, "Transferring assets...");
9226
+ logger.info("Transferring assets started");
9227
+ if (options.dryRun) {
9228
+ ui.warn(`DRY RUN MODE ENABLED: No changes will be made.
9229
+ `);
9230
+ logger.warn("Dry run mode enabled");
9231
+ }
9232
+ const { space, verbose } = command.optsWithGlobals();
9233
+ const { state } = session();
9234
+ if (!requireAuthentication(state, verbose)) {
9235
+ process.exitCode = 2;
9236
+ return;
9237
+ }
9238
+ if (!space) {
9239
+ handleError(new CommandError(`Please provide the space as argument --space YOUR_SPACE_ID.`), verbose);
9240
+ process.exitCode = 2;
9241
+ return;
9242
+ }
9243
+ const folderId = Number(options.folderId);
9244
+ if (!options.folderId || !Number.isFinite(folderId) || folderId <= 0) {
9245
+ handleError(new CommandError(`Please provide a destination folder with --folder-id YOUR_FOLDER_ID.`), verbose);
9246
+ process.exitCode = 2;
9247
+ return;
9248
+ }
9249
+ const ids = assetIds.map((id) => Number(id)).filter((id) => !Number.isNaN(id));
9250
+ if (ids.length === 0) {
9251
+ handleError(new CommandError(`Please provide at least one valid asset ID.`), verbose);
9252
+ process.exitCode = 2;
9253
+ return;
9254
+ }
9255
+ if (options.dryRun) {
9256
+ const summary2 = { total: ids.length, succeeded: 0, failed: 0 };
9257
+ ui.info(`Transfer plan: ${ids.length} asset(s) to folder ${folderId}`);
9258
+ ui.list(ids.map((id) => `${id} -> folder ${folderId}`));
9259
+ reporter.addSummary("transferResults", summary2);
9260
+ reporter.finalize();
9261
+ logger.info("Transferring assets finished (dry run)", { summary: summary2 });
9262
+ process.exitCode = 0;
9263
+ return;
9264
+ }
9265
+ const results = await transferAssets(space, ids, folderId, {
9266
+ onSuccess: ({ assetId, filename }) => logger.info("Transferred asset", { assetId, filename }),
9267
+ onError: (error, assetId) => logOnlyError(error, { assetId })
9268
+ });
9269
+ const succeeded = results.filter((result) => result.status === "transferred").length;
9270
+ const summary = { total: results.length, succeeded, failed: results.length - succeeded };
9271
+ ui.info(`Transfer results: ${summary.total} processed, ${summary.failed} failed`);
9272
+ ui.list(results.map((result) => result.status === "transferred" ? `${result.assetId} \u2713 transferred -> ${result.filename}` : `${result.assetId} \u2717 failed: ${result.reason}`));
9273
+ reporter.addSummary("transferResults", summary);
9274
+ reporter.finalize();
9275
+ logger.info("Transferring assets finished", { summary });
9276
+ process.exitCode = summary.failed > 0 ? 1 : 0;
9277
+ });
9278
+
9172
9279
  const program$1 = getProgram();
9173
9280
  const storiesCommand = program$1.command(commands.STORIES).description(`Manage your space's stories`);
9174
9281