storyblok 4.16.0 → 4.16.2

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/README.md CHANGED
@@ -99,7 +99,7 @@ Then you can set breakpoints directly to the typescript files and the debugger w
99
99
 
100
100
  For help, discussion about best practices, or any other conversation that would benefit from being searchable:
101
101
 
102
- - [Discuss Storyblok on Github Discussions](https://github.com/storyblok/storyblok/discussions)
102
+ - [Discuss Storyblok on GitHub Discussions](https://github.com/storyblok/storyblok/discussions)
103
103
 
104
104
  For community support, chatting with other users, please visit:
105
105
 
@@ -114,7 +114,7 @@ For bugs or feature requests, please [submit an issue](https://github.com/storyb
114
114
 
115
115
  ### I can't share my company project code
116
116
 
117
- We understand that you might not be able to share your company's project code. Please provide a minimal reproducible example that demonstrates the issue by using tools like [Stackblitz](https://stackblitz.com) or a link to a Github Repo lease make sure you include a README file with the instructions to build and run the project, important not to include any access token, password or personal information of any kind.
117
+ We understand that you might not be able to share your company's project code. Please provide a minimal reproducible example that demonstrates the issue by using tools like [Stackblitz](https://stackblitz.com) or a link to a GitHub repo. Please make sure you include a README file with the instructions to build and run the project, important not to include any access token, password or personal information of any kind.
118
118
 
119
119
  ### I only have a question
120
120
 
@@ -122,7 +122,7 @@ If you have a question, please ask in the [Discuss Storyblok on Discord](https:/
122
122
 
123
123
  ## Contributing
124
124
 
125
- If you're interested in contributing to Storyblok CLI, please read our [contributing docs](https://github.com/storyblok/.github/blob/main/contributing.md) before submitting a pull request.
125
+ If you're interested in contributing to Storyblok CLI, please read our [contributing docs](../../CONTRIBUTING.md) before submitting a pull request.
126
126
 
127
127
  ## License
128
128
 
package/dist/index.mjs CHANGED
@@ -3995,6 +3995,8 @@ generateCmd$1.action(async (componentName, options, command) => {
3995
3995
  }
3996
3996
  });
3997
3997
 
3998
+ const normalizeFullSlug = (slug) => slug.replace(/\/$/, "");
3999
+
3998
4000
  const fetchStories = async (spaceId, params) => {
3999
4001
  try {
4000
4002
  const client = getMapiClient();
@@ -4096,9 +4098,15 @@ const prefetchTargetStories = async (spaceId, options) => {
4096
4098
  options?.onTotal?.(total);
4097
4099
  }
4098
4100
  for (const story of response.stories) {
4099
- const ref = { id: story.id, uuid: story.uuid };
4101
+ const ref = { id: story.id, uuid: story.uuid, is_folder: story.is_folder };
4100
4102
  if (story.full_slug) {
4101
- result.bySlug.set(story.full_slug, ref);
4103
+ const key = normalizeFullSlug(story.full_slug);
4104
+ const existing = result.bySlug.get(key);
4105
+ if (existing) {
4106
+ existing.push(ref);
4107
+ } else {
4108
+ result.bySlug.set(key, [ref]);
4109
+ }
4102
4110
  }
4103
4111
  result.byId.set(story.id, ref);
4104
4112
  }
@@ -5994,16 +6002,17 @@ const generateCmd = typesCommand.command("generate").description("Generate types
5994
6002
  ).option("--sf, --separate-files", "Generate one .d.ts file per component instead of a single combined file").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").option("-s, --space <space>", "space ID").option("-p, --path <path>", "path for file storage");
5995
6003
  generateCmd.action(async (options, command) => {
5996
6004
  konsola.title(`${commands.TYPES}`, colorPalette.TYPES, "Generating types...");
5997
- const { space, path, verbose } = command.optsWithGlobals();
6005
+ const { space, path, verbose, suffix, filename, separateFiles } = command.optsWithGlobals();
5998
6006
  const spinner = new Spinner({
5999
- verbose: !isVitest
6007
+ verbose
6000
6008
  });
6001
6009
  try {
6002
6010
  spinner.start(`Generating types...`);
6003
6011
  const componentsData = await readComponentsFiles({
6004
6012
  from: space,
6005
6013
  path,
6006
- suffix: options.suffix,
6014
+ separateFiles,
6015
+ suffix,
6007
6016
  verbose
6008
6017
  });
6009
6018
  let dataSourceData;
@@ -6011,7 +6020,8 @@ generateCmd.action(async (options, command) => {
6011
6020
  dataSourceData = await readDatasourcesFiles({
6012
6021
  from: space,
6013
6022
  path,
6014
- suffix: options.suffix,
6023
+ separateFiles,
6024
+ suffix,
6015
6025
  verbose
6016
6026
  });
6017
6027
  } catch (error) {
@@ -6029,18 +6039,17 @@ generateCmd.action(async (options, command) => {
6029
6039
  ...dataSourceData
6030
6040
  };
6031
6041
  const typedefData = await generateTypes(spaceDataWithComponentsAndDatasources, {
6032
- ...options,
6033
- path
6042
+ ...options
6034
6043
  });
6035
6044
  if (typedefData) {
6036
6045
  await saveTypesToComponentsFile(space, typedefData, {
6037
- filename: options.filename,
6046
+ filename,
6038
6047
  path,
6039
- separateFiles: options.separateFiles
6048
+ separateFiles
6040
6049
  });
6041
6050
  }
6042
6051
  spinner.succeed();
6043
- if (options.separateFiles && options.filename) {
6052
+ if (separateFiles && filename) {
6044
6053
  konsola.warn(`The --filename option is ignored when using --separate-files`);
6045
6054
  }
6046
6055
  konsola.ok(`Successfully generated types for space ${space}`, true);
@@ -8216,87 +8225,172 @@ const mapReferencesStream = ({
8216
8225
  }
8217
8226
  });
8218
8227
  };
8219
- const makeCreateStoryAPITransport = ({ spaceId }) => async (localStory) => {
8220
- const { id: _id, uuid: _uuid, parent_id: _parentId, is_startpage: _isStartpage, content, ...newStoryData } = localStory;
8221
- if (!localStory.is_folder && !content?.component) {
8222
- throw new Error(`Story "${localStory.slug}" is missing a content type (content.component). Every story must define a content field with a valid component.`);
8223
- }
8224
- const remoteStory = await createStory(spaceId, {
8225
- story: {
8226
- ...newStoryData,
8227
- ...content?.component ? { content: { _uid: "", component: "__migration_artifact__" } } : {}
8228
- },
8229
- publish: 0
8230
- });
8231
- if (!remoteStory) {
8232
- throw new Error("No response!");
8233
- }
8234
- return remoteStory;
8235
- };
8236
- const makeAppendToManifestFSTransport = ({ manifestFile }) => async (localStory, remoteStory) => {
8228
+ const makeAppendToManifestFSTransport = ({ manifestFile }) => async (entry, remoteStory) => {
8237
8229
  const createdAt = (/* @__PURE__ */ new Date()).toISOString();
8238
8230
  await appendToFile(manifestFile, JSON.stringify({
8239
- old_id: localStory.uuid,
8231
+ old_id: entry.uuid,
8240
8232
  new_id: remoteStory.uuid,
8241
8233
  created_at: createdAt
8242
8234
  }));
8243
8235
  await appendToFile(manifestFile, JSON.stringify({
8244
- old_id: localStory.id,
8236
+ old_id: entry.id,
8245
8237
  new_id: remoteStory.id,
8246
8238
  created_at: createdAt
8247
8239
  }));
8248
8240
  };
8249
- const createStoryPlaceholderStream = ({
8241
+ const scanLocalStoryIndex = async ({
8242
+ directoryPath,
8243
+ setTotalStories,
8244
+ onIncrement,
8245
+ onError
8246
+ }) => {
8247
+ const files = (await readDirectory(directoryPath)).filter((f) => extname(f) === ".json");
8248
+ setTotalStories?.(files.length);
8249
+ const entries = [];
8250
+ for (const file of files) {
8251
+ try {
8252
+ const filePath = join(directoryPath, file);
8253
+ const fileContent = await readFile$1(filePath, "utf-8");
8254
+ const story = JSON.parse(fileContent);
8255
+ entries.push({
8256
+ filename: file,
8257
+ id: story.id,
8258
+ uuid: story.uuid ?? "",
8259
+ slug: story.slug ?? "",
8260
+ name: story.name ?? "",
8261
+ full_slug: story.full_slug ?? "",
8262
+ is_folder: story.is_folder ?? false,
8263
+ is_startpage: story.is_startpage === true,
8264
+ parent_id: story.parent_id ?? null,
8265
+ component: story.content?.component
8266
+ });
8267
+ } catch (maybeError) {
8268
+ onError?.(toError(maybeError), file);
8269
+ } finally {
8270
+ onIncrement?.();
8271
+ }
8272
+ }
8273
+ return entries;
8274
+ };
8275
+ const groupStoriesByDepth = (entries) => {
8276
+ const depthMap = /* @__PURE__ */ new Map();
8277
+ for (const entry of entries) {
8278
+ const slug = normalizeFullSlug(entry.full_slug || "");
8279
+ const depth = slug === "" ? 0 : slug.split("/").length - 1;
8280
+ if (!depthMap.has(depth)) {
8281
+ depthMap.set(depth, []);
8282
+ }
8283
+ depthMap.get(depth).push(entry);
8284
+ }
8285
+ const maxDepth = depthMap.size > 0 ? Math.max(...depthMap.keys()) : 0;
8286
+ const levels = [];
8287
+ for (let d = 0; d <= maxDepth; d++) {
8288
+ const level = depthMap.get(d);
8289
+ if (!level || level.length === 0) {
8290
+ continue;
8291
+ }
8292
+ level.sort((a, b) => {
8293
+ if (a.is_folder && !b.is_folder) {
8294
+ return -1;
8295
+ }
8296
+ if (!a.is_folder && b.is_folder) {
8297
+ return 1;
8298
+ }
8299
+ return 0;
8300
+ });
8301
+ levels.push(level);
8302
+ }
8303
+ return levels;
8304
+ };
8305
+ const findSlugMatch = ({
8306
+ entry,
8307
+ existingTargetStories,
8308
+ claimedRemoteIds
8309
+ }) => {
8310
+ const normalizedSlug = entry.full_slug ? normalizeFullSlug(entry.full_slug) : void 0;
8311
+ const slugCandidates = normalizedSlug ? existingTargetStories.bySlug.get(normalizedSlug) : void 0;
8312
+ if (!slugCandidates) {
8313
+ return void 0;
8314
+ }
8315
+ const unclaimed = slugCandidates.filter((ref) => !claimedRemoteIds.has(ref.id));
8316
+ return unclaimed.find((ref) => ref.is_folder === entry.is_folder) ?? unclaimed[0];
8317
+ };
8318
+ const createStoriesForLevel = async ({
8319
+ level,
8320
+ spaceId,
8250
8321
  maps,
8251
8322
  existingTargetStories,
8323
+ claimedRemoteIds,
8252
8324
  isCrossSpace,
8253
- transports,
8254
- onIncrement,
8325
+ dryRun,
8326
+ appendToManifest,
8255
8327
  onStorySuccess,
8256
8328
  onStorySkipped,
8257
8329
  onStoryError
8258
8330
  }) => {
8259
- const processing = /* @__PURE__ */ new Set();
8260
- return new Writable({
8261
- objectMode: true,
8262
- async write(localStory, _encoding, callback) {
8263
- await apiConcurrencyLock.acquire();
8264
- const task = (async () => {
8265
- try {
8266
- const mappedStoryId = maps.stories?.get(localStory.id);
8267
- const mappedRemoteStory = mappedStoryId ? existingTargetStories.byId.get(Number(mappedStoryId)) : void 0;
8268
- if (mappedRemoteStory) {
8269
- onStorySkipped?.(localStory, mappedRemoteStory);
8270
- return;
8271
- }
8272
- const existingBySlug = localStory.full_slug ? existingTargetStories.bySlug.get(localStory.full_slug) : void 0;
8273
- if (existingBySlug) {
8274
- const isMatchConfirmed = isCrossSpace || existingBySlug.uuid === localStory.uuid;
8275
- if (isMatchConfirmed) {
8276
- await transports.appendStoryManifest(localStory, existingBySlug);
8277
- onStorySkipped?.(localStory, existingBySlug);
8278
- return;
8279
- }
8280
- }
8281
- const newRemoteStory = await transports.createStory(localStory);
8282
- await transports.appendStoryManifest(localStory, newRemoteStory);
8283
- onStorySuccess?.(localStory, newRemoteStory);
8284
- } catch (maybeError) {
8285
- onStoryError?.(toError(maybeError), localStory);
8331
+ const processEntry = async (entry) => {
8332
+ await apiConcurrencyLock.acquire();
8333
+ try {
8334
+ const mappedStoryId = maps.stories?.get(entry.id);
8335
+ const mappedRemoteStory = mappedStoryId ? existingTargetStories.byId.get(Number(mappedStoryId)) : void 0;
8336
+ if (mappedRemoteStory) {
8337
+ claimedRemoteIds.add(mappedRemoteStory.id);
8338
+ onStorySkipped?.(entry, mappedRemoteStory, "matched by manifest mapping from a previous push");
8339
+ return;
8340
+ }
8341
+ const match = findSlugMatch({ entry, existingTargetStories, claimedRemoteIds });
8342
+ if (match) {
8343
+ const isMatchConfirmed = isCrossSpace || match.uuid === entry.uuid;
8344
+ if (isMatchConfirmed) {
8345
+ claimedRemoteIds.add(match.id);
8346
+ await appendToManifest(entry, match);
8347
+ onStorySkipped?.(entry, match, "matched by slug in target space");
8348
+ return;
8286
8349
  }
8287
- })();
8288
- processing.add(task);
8289
- task.finally(() => {
8290
- onIncrement?.();
8291
- apiConcurrencyLock.release();
8292
- processing.delete(task);
8350
+ }
8351
+ if (!entry.is_folder && !entry.component) {
8352
+ throw new Error(`Story "${entry.slug}" (${entry.filename}) is missing a content type (content.component). Every story must define a content field with a valid component.`);
8353
+ }
8354
+ const resolvedParentId = entry.parent_id != null ? maps.stories?.get(entry.parent_id) : void 0;
8355
+ if (dryRun) {
8356
+ const fakeRemote = { id: entry.id, uuid: entry.uuid };
8357
+ onStorySuccess?.(entry, fakeRemote);
8358
+ return;
8359
+ }
8360
+ const remoteStory = await createStory(spaceId, {
8361
+ story: {
8362
+ slug: entry.slug,
8363
+ name: entry.name,
8364
+ is_folder: entry.is_folder,
8365
+ ...resolvedParentId != null ? { parent_id: Number(resolvedParentId) } : {},
8366
+ ...entry.is_startpage && resolvedParentId != null ? { is_startpage: true } : {},
8367
+ ...entry.component ? { content: { _uid: "", component: entry.component } } : {}
8368
+ },
8369
+ publish: 0
8293
8370
  });
8294
- callback();
8295
- },
8296
- final(callback) {
8297
- Promise.all(processing).finally(() => callback());
8371
+ if (!remoteStory) {
8372
+ throw new Error("No response!");
8373
+ }
8374
+ await appendToManifest(entry, remoteStory);
8375
+ onStorySuccess?.(entry, remoteStory);
8376
+ } catch (maybeError) {
8377
+ onStoryError?.(toError(maybeError), entry);
8378
+ } finally {
8379
+ apiConcurrencyLock.release();
8298
8380
  }
8299
- });
8381
+ };
8382
+ const folders = level.filter((e) => e.is_folder);
8383
+ const nonFolders = level.filter((e) => !e.is_folder);
8384
+ const folderTasks = [];
8385
+ for (const entry of folders) {
8386
+ folderTasks.push(processEntry(entry));
8387
+ }
8388
+ await Promise.all(folderTasks);
8389
+ const storyTasks = [];
8390
+ for (const entry of nonFolders) {
8391
+ storyTasks.push(processEntry(entry));
8392
+ }
8393
+ await Promise.all(storyTasks);
8300
8394
  };
8301
8395
  const makeWriteStoryFSTransport = ({ directoryPath }) => async (story) => {
8302
8396
  await saveToFile(resolve(directoryPath, getStoryFilename(story)), JSON.stringify(story, null, 2));
@@ -8306,15 +8400,25 @@ const makeWriteStoryAPITransport = ({ spaceId, publish }) => (mappedLocalStory)
8306
8400
  story: mappedLocalStory,
8307
8401
  publish: publish ?? (isStoryPublishedWithoutChanges(mappedLocalStory) ? 1 : 0)
8308
8402
  });
8309
- const makeCleanupStoryFSTransport = ({ directoryPath, maps }) => async (mappedStory) => {
8310
- const mapEntry = maps.stories?.entries().find(([_, v]) => v === mappedStory.uuid);
8311
- const originalUuid = mapEntry?.[0] && typeof mapEntry?.[0] === "string" ? mapEntry?.[0] : mappedStory.uuid;
8312
- const storyFilename = getStoryFilename({
8313
- slug: mappedStory.slug,
8314
- uuid: originalUuid
8315
- });
8316
- const storyFilePath = resolve(directoryPath, storyFilename);
8317
- await unlink(storyFilePath);
8403
+ const makeCleanupStoryFSTransport = ({ directoryPath, maps }) => {
8404
+ const reverseUuidMap = /* @__PURE__ */ new Map();
8405
+ if (maps.stories) {
8406
+ for (const [key, value] of maps.stories.entries()) {
8407
+ if (typeof key === "string") {
8408
+ reverseUuidMap.set(value, key);
8409
+ }
8410
+ }
8411
+ }
8412
+ return async (mappedStory) => {
8413
+ const uuid = mappedStory.uuid ?? "";
8414
+ const originalUuid = reverseUuidMap.get(uuid) ?? uuid;
8415
+ const storyFilename = getStoryFilename({
8416
+ slug: mappedStory.slug,
8417
+ uuid: originalUuid
8418
+ });
8419
+ const storyFilePath = resolve(directoryPath, storyFilename);
8420
+ await unlink(storyFilePath);
8421
+ };
8318
8422
  };
8319
8423
  const writeStoryStream = ({
8320
8424
  transports,
@@ -8921,75 +9025,80 @@ pushCmd.action(async (options, command) => {
8921
9025
  });
8922
9026
  fetchProgress.stop();
8923
9027
  const storiesDirectoryPath = resolveCommandPath(directories.stories, fromSpace, basePath);
9028
+ const scanProgress = ui.createProgressBar({ title: "Scanning Stories...".padEnd(21) });
9029
+ const storyIndex = await scanLocalStoryIndex({
9030
+ directoryPath: storiesDirectoryPath,
9031
+ setTotalStories(total) {
9032
+ scanProgress.setTotal(total);
9033
+ },
9034
+ onIncrement() {
9035
+ scanProgress.increment();
9036
+ },
9037
+ onError(error, filename) {
9038
+ summary.creationResults.failed += 1;
9039
+ handleError(error, verbose, { storyFile: filename });
9040
+ }
9041
+ });
9042
+ const levels = groupStoriesByDepth(storyIndex);
9043
+ scanProgress.stop();
8924
9044
  const creationProgress = ui.createProgressBar({ title: "Creating Stories...".padEnd(21) });
8925
9045
  const processProgress = ui.createProgressBar({ title: "Processing Stories...".padEnd(21) });
8926
9046
  const updateProgress = ui.createProgressBar({ title: "Updating Stories...".padEnd(21) });
8927
- await pipeline$1(
8928
- // Read local stories from `.json` files.
8929
- readLocalStoriesStream({
8930
- directoryPath: storiesDirectoryPath,
8931
- setTotalStories(total) {
8932
- summary.creationResults.total = total;
8933
- summary.processResults.total = total;
8934
- summary.updateResults.total = total;
8935
- creationProgress.setTotal(total);
8936
- processProgress.setTotal(total);
8937
- updateProgress.setTotal(total);
8938
- },
8939
- onStoryError(error, filename) {
8940
- summary.creationResults.failed += 1;
8941
- summary.processResults.total -= 1;
8942
- summary.updateResults.total -= 1;
8943
- processProgress.setTotal(summary.processResults.total);
8944
- updateProgress.setTotal(summary.updateResults.total);
8945
- creationProgress.increment();
8946
- handleError(error, verbose, { storyFile: filename });
8947
- }
8948
- }),
8949
- // Create remote stories.
8950
- createStoryPlaceholderStream({
9047
+ const totalStories = storyIndex.length + summary.creationResults.failed;
9048
+ summary.creationResults.total = totalStories;
9049
+ summary.processResults.total = totalStories;
9050
+ summary.updateResults.total = totalStories;
9051
+ creationProgress.setTotal(totalStories);
9052
+ processProgress.setTotal(totalStories);
9053
+ updateProgress.setTotal(totalStories);
9054
+ const appendToManifest = options.dryRun ? (() => Promise.resolve()) : makeAppendToManifestFSTransport({ manifestFile });
9055
+ const claimedRemoteIds = /* @__PURE__ */ new Set();
9056
+ for (const level of levels) {
9057
+ await createStoriesForLevel({
9058
+ level,
9059
+ spaceId: space,
8951
9060
  maps,
8952
9061
  existingTargetStories,
9062
+ claimedRemoteIds,
8953
9063
  isCrossSpace: fromSpace !== space,
8954
- transports: {
8955
- createStory: options.dryRun ? async (story) => story : makeCreateStoryAPITransport({
8956
- spaceId: space
8957
- }),
8958
- appendStoryManifest: options.dryRun ? () => Promise.resolve() : makeAppendToManifestFSTransport({
8959
- manifestFile
8960
- })
8961
- },
8962
- onStorySuccess(localStory, remoteStory) {
8963
- if (!localStory.uuid || !remoteStory.uuid) {
9064
+ dryRun: options.dryRun ?? false,
9065
+ appendToManifest,
9066
+ onStorySuccess(entry, remoteStory) {
9067
+ if (!entry.uuid || !remoteStory.uuid) {
8964
9068
  throw new Error("Invalid story provided!");
8965
9069
  }
8966
- maps.stories.set(localStory.id, remoteStory.id);
8967
- maps.stories.set(localStory.uuid, remoteStory.uuid);
9070
+ maps.stories.set(entry.id, remoteStory.id);
9071
+ maps.stories.set(entry.uuid, remoteStory.uuid);
8968
9072
  logger.info("Created story", { storyId: remoteStory.uuid });
8969
9073
  summary.creationResults.succeeded += 1;
9074
+ creationProgress.increment();
8970
9075
  },
8971
- onStorySkipped(localStory, remoteStory) {
8972
- if (!localStory.uuid || !remoteStory.uuid) {
9076
+ onStorySkipped(entry, remoteStory, reason) {
9077
+ if (!entry.uuid || !remoteStory.uuid) {
8973
9078
  throw new Error("Invalid story provided!");
8974
9079
  }
8975
- maps.stories.set(localStory.id, remoteStory.id);
8976
- maps.stories.set(localStory.uuid, remoteStory.uuid);
8977
- logger.info("Skipped creating story", { storyId: localStory.uuid });
9080
+ maps.stories.set(entry.id, remoteStory.id);
9081
+ maps.stories.set(entry.uuid, remoteStory.uuid);
9082
+ logger.info(`Skipped creating story: ${reason}`, { storyId: entry.uuid });
8978
9083
  summary.creationResults.skipped += 1;
9084
+ creationProgress.increment();
8979
9085
  },
8980
- onStoryError(error, localStory) {
9086
+ onStoryError(error, entry) {
8981
9087
  summary.creationResults.failed += 1;
8982
9088
  summary.processResults.total -= 1;
8983
9089
  summary.updateResults.total -= 1;
8984
9090
  processProgress.setTotal(summary.processResults.total);
8985
9091
  updateProgress.setTotal(summary.updateResults.total);
8986
- handleError(error, verbose, { storyId: localStory?.uuid });
8987
- },
8988
- onIncrement() {
8989
9092
  creationProgress.increment();
9093
+ handleError(error, verbose, { storyId: entry?.uuid });
8990
9094
  }
8991
- })
8992
- );
9095
+ });
9096
+ }
9097
+ if (summary.creationResults.failed > 0) {
9098
+ const message = `${summary.creationResults.failed} ${summary.creationResults.failed === 1 ? "story" : "stories"} failed to create. References to these stories will be left unmapped.`;
9099
+ ui.warn(message);
9100
+ logger.warn(message);
9101
+ }
8993
9102
  await pipeline$1(
8994
9103
  // Read local stories from `.json` files.
8995
9104
  readLocalStoriesStream({