storyblok 4.6.4 → 4.6.6

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
@@ -856,7 +856,7 @@ const loginStrategy = {
856
856
  short: "Email"
857
857
  },
858
858
  {
859
- name: "With Token (SSO)",
859
+ name: "With Token (Personal Access Token \u2013 works also for SSO accounts)",
860
860
  value: "login-with-token",
861
861
  short: "Token"
862
862
  }
@@ -915,8 +915,13 @@ program$i.command(commands.LOGIN).description("Login to the Storyblok CLI").opti
915
915
  try {
916
916
  const strategy = await select(loginStrategy);
917
917
  if (strategy === "login-with-token") {
918
+ konsola.info([
919
+ "\u{1F511} You can use a Personal Access Token to log in.",
920
+ "This works for all accounts, including SSO accounts.",
921
+ `Generate one in your Storyblok account settings: ${chalk.underline.blue("https://app.storyblok.com/#/me/account?tab=token")}`
922
+ ].join("\n"));
918
923
  const userToken = await password({
919
- message: "Please enter your token:",
924
+ message: "Please enter your Personal Access Token:",
920
925
  validate: (value) => {
921
926
  return value.length > 0;
922
927
  }
@@ -3074,7 +3079,8 @@ function applyMigrationToAllBlocks(content, migrationFunction, targetComponent)
3074
3079
  migratedContent = migrationFunction({ ...content });
3075
3080
  processed = true;
3076
3081
  }
3077
- for (const key of Object.keys(content)) {
3082
+ const uniqueKeys = /* @__PURE__ */ new Set([...Object.keys(content), ...Object.keys(migratedContent || {})]);
3083
+ for (const key of uniqueKeys) {
3078
3084
  if (migratedContent) {
3079
3085
  if (!(key in migratedContent)) {
3080
3086
  delete content[key];
@@ -3102,7 +3108,7 @@ async function saveRollbackData({
3102
3108
  path,
3103
3109
  story,
3104
3110
  migrationTimestamp,
3105
- migrationFile
3111
+ migrationNames
3106
3112
  }) {
3107
3113
  const rollbackData = {
3108
3114
  storyId: story.id,
@@ -3110,7 +3116,9 @@ async function saveRollbackData({
3110
3116
  content: story.content
3111
3117
  };
3112
3118
  const rollbacksPath = resolvePath(path, `migrations/${space}/rollbacks`);
3113
- const rollbackFileName = `${migrationFile.replace(".js", "")}.${migrationTimestamp}.jsonl`;
3119
+ const componentNames = migrationNames.map((n) => getComponentNameFromFilename(n));
3120
+ const rollbackName = [...new Set(componentNames)].join("~");
3121
+ const rollbackFileName = `${rollbackName}.${migrationTimestamp}.jsonl`;
3114
3122
  const rollbackFilePath = join(rollbacksPath, rollbackFileName);
3115
3123
  await appendToFile(
3116
3124
  rollbackFilePath,
@@ -3168,67 +3176,71 @@ class MigrationStream extends Transform {
3168
3176
  callback(error);
3169
3177
  }
3170
3178
  }
3171
- async processStory(story) {
3172
- if (!story.content) {
3173
- for (const migrationFile of this.options.migrationFiles) {
3174
- this.results.failed.push({
3175
- storyId: story.id,
3176
- migrationName: migrationFile.name,
3177
- error: new Error("Story content is missing")
3178
- });
3179
- }
3180
- return [];
3179
+ async getOrLoadMigrationFunction(migrationFile) {
3180
+ if (this.migrationFunctions.has(migrationFile.name)) {
3181
+ return this.migrationFunctions.get(migrationFile.name);
3181
3182
  }
3183
+ const migrationFunction = await getMigrationFunction(
3184
+ migrationFile.name,
3185
+ this.options.space,
3186
+ this.options.path
3187
+ );
3188
+ this.migrationFunctions.set(migrationFile.name, migrationFunction);
3189
+ return migrationFunction;
3190
+ }
3191
+ async processStory(story) {
3182
3192
  const relevantMigrations = this.options.componentName ? this.options.migrationFiles.filter((file) => {
3183
3193
  const targetComponent = getComponentNameFromFilename(file.name);
3184
3194
  return targetComponent.split(".")[0] === this.options.componentName;
3185
3195
  }) : this.options.migrationFiles;
3196
+ if (!story.content) {
3197
+ this.results.failed.push({
3198
+ storyId: story.id,
3199
+ migrationNames: relevantMigrations.map((m) => m.name),
3200
+ error: new Error("Story content is missing")
3201
+ });
3202
+ return [];
3203
+ }
3186
3204
  const successfulResults = [];
3187
- for (const migrationFile of relevantMigrations) {
3188
- const result = await this.applyMigrationToStory(story, migrationFile);
3189
- if (result) {
3190
- successfulResults.push(result);
3191
- }
3205
+ const result = await this.applyMigrationsToStory(story, relevantMigrations);
3206
+ if (result) {
3207
+ successfulResults.push(result);
3192
3208
  }
3193
3209
  return successfulResults;
3194
3210
  }
3195
- async applyMigrationToStory(story, migrationFile) {
3211
+ async applyMigrationsToStory(story, migrationFiles) {
3212
+ const migrationNames = migrationFiles.map((f) => f.name);
3196
3213
  try {
3197
- let migrationFunction = this.migrationFunctions.get(migrationFile.name);
3198
- if (!migrationFunction) {
3199
- migrationFunction = await getMigrationFunction(
3200
- migrationFile.name,
3201
- this.options.space,
3202
- this.options.path
3203
- );
3204
- this.migrationFunctions.set(migrationFile.name, migrationFunction);
3205
- }
3206
- if (!migrationFunction) {
3207
- this.results.failed.push({
3208
- storyId: story.id,
3209
- migrationName: migrationFile.name,
3210
- error: new Error(`Failed to load migration function from file "${migrationFile.name}"`)
3211
- });
3212
- return null;
3213
- }
3214
- await saveRollbackData({
3215
- space: this.options.space,
3216
- path: this.options.path,
3217
- story: { id: story.id, name: story.name || "", content: story.content },
3218
- migrationTimestamp: this.timestamp,
3219
- migrationFile: migrationFile.name
3220
- });
3221
3214
  const storyContent = structuredClone(story.content);
3222
3215
  const originalContentHash = hash(storyContent);
3223
- const targetComponent = this.options.componentName || getComponentNameFromFilename(migrationFile.name);
3224
- const processed = applyMigrationToAllBlocks(storyContent, migrationFunction, targetComponent);
3216
+ let processed = false;
3217
+ for (const migrationFile of migrationFiles) {
3218
+ const migrationFunction = await this.getOrLoadMigrationFunction(migrationFile);
3219
+ if (!migrationFunction) {
3220
+ this.results.failed.push({
3221
+ storyId: story.id,
3222
+ migrationNames,
3223
+ error: new Error(`Failed to load migration function from file "${migrationFile.name}"`)
3224
+ });
3225
+ return null;
3226
+ }
3227
+ const targetComponent = this.options.componentName || getComponentNameFromFilename(migrationFile.name);
3228
+ processed = applyMigrationToAllBlocks(storyContent, migrationFunction, targetComponent);
3229
+ }
3225
3230
  const newContentHash = hash(storyContent);
3226
3231
  const contentChanged = originalContentHash !== newContentHash;
3227
3232
  if (processed && contentChanged) {
3233
+ await saveRollbackData({
3234
+ space: this.options.space,
3235
+ path: this.options.path,
3236
+ story: { id: story.id, name: story.name || "", content: story.content },
3237
+ migrationTimestamp: this.timestamp,
3238
+ migrationNames
3239
+ });
3228
3240
  this.results.successful.push({
3229
3241
  storyId: story.id,
3230
3242
  name: story.name,
3231
- migrationName: migrationFile.name,
3243
+ migrationNames,
3232
3244
  content: storyContent
3233
3245
  });
3234
3246
  return {
@@ -3240,24 +3252,28 @@ class MigrationStream extends Transform {
3240
3252
  this.results.skipped.push({
3241
3253
  storyId: story.id,
3242
3254
  name: story.name,
3243
- migrationName: migrationFile.name,
3255
+ migrationNames,
3244
3256
  reason: "No changes detected after migration"
3245
3257
  });
3246
3258
  return null;
3247
3259
  } else {
3248
- const baseComponent = targetComponent.split(".")[0];
3260
+ const reason = migrationFiles.map((migrationFile) => {
3261
+ const targetComponent = this.options.componentName || getComponentNameFromFilename(migrationFile.name);
3262
+ const baseComponent = targetComponent.split(".")[0];
3263
+ return baseComponent === this.options.componentName ? `No matching components found for ${migrationFile.name}` : `Different component target ${migrationFile.name}`;
3264
+ }).join("\n");
3249
3265
  this.results.skipped.push({
3250
3266
  storyId: story.id,
3251
3267
  name: story.name,
3252
- migrationName: migrationFile.name,
3253
- reason: baseComponent === this.options.componentName ? "No matching components found" : "Different component target"
3268
+ migrationNames,
3269
+ reason
3254
3270
  });
3255
3271
  return null;
3256
3272
  }
3257
3273
  } catch (error) {
3258
3274
  this.results.failed.push({
3259
3275
  storyId: story.id,
3260
- migrationName: migrationFile.name,
3276
+ migrationNames,
3261
3277
  error
3262
3278
  });
3263
3279
  return null;
@@ -3355,8 +3371,9 @@ class UpdateStream extends Writable {
3355
3371
  } else if (this.options.publish === "all") {
3356
3372
  payload.publish = 1;
3357
3373
  }
3358
- const updatedStory = await updateStory(this.options.space, storyId, payload);
3359
- if (updatedStory) {
3374
+ const updatedStory = !this.options.dryRun && await updateStory(this.options.space, storyId, payload);
3375
+ const isStoryUpdated = Boolean(updatedStory);
3376
+ if (isStoryUpdated || this.options.dryRun) {
3360
3377
  this.results.successful.push({ storyId, name: storyName });
3361
3378
  this.results.totalProcessed++;
3362
3379
  this.options.onProgress?.(this.results.totalProcessed);
@@ -3415,6 +3432,10 @@ class UpdateStream extends Writable {
3415
3432
  const program$8 = getProgram();
3416
3433
  migrationsCommand.command("run [componentName]").description("Run migrations").option("--fi, --filter <filter>", "glob filter to apply to the components before pushing").option("-d, --dry-run", "Preview changes without applying them to Storyblok").option("-q, --query <query>", 'Filter stories by content attributes using Storyblok filter query syntax. Example: --query="[highlighted][in]=true"').option("--starts-with <path>", 'Filter stories by path. Example: --starts-with="/en/blog/"').option("--publish <publish>", "Options for publication mode: all | published | published-with-changes").action(async (componentName, options) => {
3417
3434
  konsola.title(`${commands.MIGRATIONS}`, colorPalette.MIGRATIONS, componentName ? `Running migrations for component ${componentName}...` : "Running migrations...");
3435
+ if (options.dryRun) {
3436
+ konsola.warn(`DRY RUN MODE ENABLED: No changes will be made.
3437
+ `);
3438
+ }
3418
3439
  const verbose = program$8.opts().verbose;
3419
3440
  const { filter, dryRun = false, query, startsWith, publish } = options;
3420
3441
  const { space, path } = migrationsCommand.opts();
@@ -4001,6 +4022,7 @@ const storyblokSchemas = /* @__PURE__ */ new Map([
4001
4022
  ]);
4002
4023
 
4003
4024
  const STORY_TYPE = "ISbStoryData";
4025
+ const DEFAULT_COMPONENT_FILENAME = "storyblok-components";
4004
4026
  const DEFAULT_TYPEDEFS_HEADER = [
4005
4027
  "// This file was generated by the storyblok CLI.",
4006
4028
  "// DO NOT MODIFY THIS FILE BY HAND."
@@ -4263,8 +4285,8 @@ const generateTypes = async (spaceData, options = {
4263
4285
  handleError(error);
4264
4286
  }
4265
4287
  };
4266
- const saveTypesToFile = async (space, typedefString, options) => {
4267
- const { filename = "storyblok-components", path } = options;
4288
+ const saveTypesToComponentsFile = async (space, typedefString, options) => {
4289
+ const { filename = DEFAULT_COMPONENT_FILENAME, path } = options;
4268
4290
  const resolvedPath = path ? resolve(process.cwd(), path, "types", space) : resolvePath(path, `types/${space}`);
4269
4291
  try {
4270
4292
  await saveToFile(join(resolvedPath, `${filename}.d.ts`), typedefString);
@@ -4273,7 +4295,7 @@ const saveTypesToFile = async (space, typedefString, options) => {
4273
4295
  }
4274
4296
  };
4275
4297
  const generateStoryblokTypes = async (options = {}) => {
4276
- const { filename = "storyblok", path } = options;
4298
+ const { path } = options;
4277
4299
  try {
4278
4300
  const storyblokTypesPath = resolve(__dirname, "./index.d.ts");
4279
4301
  const storyblokTypesContent = readFileSync(storyblokTypesPath, "utf-8");
@@ -4284,7 +4306,7 @@ const generateStoryblokTypes = async (options = {}) => {
4284
4306
  storyblokTypesContent
4285
4307
  ].join("\n");
4286
4308
  const resolvedPath = path ? resolve(process.cwd(), path, "types") : resolvePath(path, "types");
4287
- await saveToFile(join(resolvedPath, `${filename}.d.ts`), typeDefs);
4309
+ await saveToFile(join(resolvedPath, `storyblok.d.ts`), typeDefs);
4288
4310
  return true;
4289
4311
  } catch (error) {
4290
4312
  handleFileSystemError("read", error);
@@ -4293,7 +4315,10 @@ const generateStoryblokTypes = async (options = {}) => {
4293
4315
  };
4294
4316
 
4295
4317
  const program$5 = getProgram();
4296
- typesCommand.command("generate").description("Generate types d.ts for your component schemas").option("--sf, --separate-files", "").option("--strict", "strict mode, no loose typing").option("--type-prefix <prefix>", "prefix to be prepended to all generated component type names").option("--type-suffix <suffix>", "suffix to be appended to all generated component type names").option("--suffix <suffix>", "Components suffix").option("--custom-fields-parser <path>", "Path to the parser file for Custom Field Types").option("--compiler-options <options>", "path to the compiler options from json-schema-to-typescript").action(async (options) => {
4318
+ typesCommand.command("generate").description("Generate types d.ts for your component schemas").option("--sf, --separate-files", "Generate one .d.ts file per component instead of a single combined file").option(
4319
+ "--filename <name>",
4320
+ "Base file name for all component types when generating a single declarations file (e.g. components.d.ts). Ignored when using --separate-files."
4321
+ ).option("--strict", "strict mode, no loose typing").option("--type-prefix <prefix>", "prefix to be prepended to all generated component type names").option("--type-suffix <suffix>", "suffix to be appended to all generated component type names").option("--suffix <suffix>", "Components suffix").option("--custom-fields-parser <path>", "Path to the parser file for Custom Field Types").option("--compiler-options <options>", "path to the compiler options from json-schema-to-typescript").action(async (options) => {
4297
4322
  konsola.title(`${commands.TYPES}`, colorPalette.TYPES, "Generating types...");
4298
4323
  const verbose = program$5.opts().verbose;
4299
4324
  const { space, path } = typesCommand.opts();
@@ -4308,7 +4333,6 @@ typesCommand.command("generate").description("Generate types d.ts for your compo
4308
4333
  path
4309
4334
  });
4310
4335
  await generateStoryblokTypes({
4311
- ...options,
4312
4336
  path
4313
4337
  });
4314
4338
  const spaceDataWithDatasources = {
@@ -4320,8 +4344,8 @@ typesCommand.command("generate").description("Generate types d.ts for your compo
4320
4344
  path
4321
4345
  });
4322
4346
  if (typedefString) {
4323
- await saveTypesToFile(space, typedefString, {
4324
- ...options,
4347
+ await saveTypesToComponentsFile(space, typedefString, {
4348
+ filename: options.filename,
4325
4349
  path
4326
4350
  });
4327
4351
  }
@@ -5157,7 +5181,7 @@ program$1.command(`${commands.CREATE} [project-path]`).alias("c").description(`S
5157
5181
  konsola.br();
5158
5182
  });
5159
5183
 
5160
- const version = "4.6.4";
5184
+ const version = "4.6.6";
5161
5185
  const pkg = {
5162
5186
  version: version};
5163
5187