storyblok 4.3.3 → 4.4.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
@@ -62,6 +62,13 @@ const regionsDomain = {
62
62
  ca: "api-ca.storyblok.com",
63
63
  ap: "api-ap.storyblok.com"
64
64
  };
65
+ const managementApiRegions = {
66
+ eu: "mapi.storyblok.com",
67
+ us: "api-us.storyblok.com",
68
+ cn: "app.storyblokchina.cn",
69
+ ca: "api-ca.storyblok.com",
70
+ ap: "api-ap.storyblok.com"
71
+ };
65
72
  const appDomains = {
66
73
  eu: "app.storyblok.com",
67
74
  us: "app-us.storyblok.com",
@@ -532,7 +539,7 @@ function getProgram() {
532
539
 
533
540
  const API_VERSION = "v1";
534
541
  const getStoryblokUrl = (region = "eu") => {
535
- return `https://${regionsDomain[region]}/${API_VERSION}`;
542
+ return `https://${managementApiRegions[region]}/${API_VERSION}`;
536
543
  };
537
544
 
538
545
  const loginWithToken = async (token, region) => {
@@ -723,7 +730,7 @@ function createSession() {
723
730
  async function persistCredentials(region) {
724
731
  if (state.isLoggedIn && state.login && state.password && state.region) {
725
732
  await addCredentials({
726
- machineName: regionsDomain[region] || "api.storyblok.com",
733
+ machineName: regionsDomain[region] || "mapi.storyblok.com",
727
734
  login: state.login,
728
735
  password: state.password,
729
736
  region: state.region
@@ -1003,6 +1010,7 @@ const getUser = async (token, region) => {
1003
1010
  const program$f = getProgram();
1004
1011
  program$f.command(commands.USER).description("Get the current user").action(async () => {
1005
1012
  konsola.title(`${commands.USER}`, colorPalette.USER);
1013
+ const verbose = program$f.opts().verbose;
1006
1014
  const { state, initializeSession } = session();
1007
1015
  await initializeSession();
1008
1016
  if (!requireAuthentication(state)) {
@@ -1018,6 +1026,9 @@ program$f.command(commands.USER).description("Get the current user").action(asyn
1018
1026
  }
1019
1027
  const { user } = await getUser(password, region);
1020
1028
  spinner.succeed();
1029
+ if (verbose) {
1030
+ konsola.info(JSON.stringify(user, null, 2));
1031
+ }
1021
1032
  konsola.ok(`Hi ${chalk.bold(user.friendly_name)}, you are currently logged in with ${chalk.hex(colorPalette.PRIMARY)(user.email)} on ${chalk.bold(region)} region`, true);
1022
1033
  } catch (error) {
1023
1034
  spinner.failed();
@@ -2838,18 +2849,21 @@ const fetchStories = async (space, params) => {
2838
2849
  const allStories = [];
2839
2850
  let currentPage = 1;
2840
2851
  let hasMorePages = true;
2852
+ const perPage = 100;
2841
2853
  while (hasMorePages) {
2842
2854
  const { filter_query, ...restParams } = params || {};
2843
2855
  const regularParams = new URLSearchParams({
2844
- ...objectToStringParams({ ...restParams, per_page: 100 }),
2856
+ ...objectToStringParams({ ...restParams, per_page: perPage }),
2845
2857
  ...currentPage > 1 && { page: currentPage.toString() }
2846
2858
  }).toString();
2847
2859
  const queryString = filter_query ? `${regularParams ? `${regularParams}&` : ""}${filter_query}` : regularParams;
2848
2860
  const endpoint = `spaces/${space}/stories${queryString ? `?${queryString}` : ""}`;
2849
2861
  const { data } = await client.get(endpoint, {});
2850
2862
  allStories.push(...data.stories);
2851
- const totalPages = Math.ceil(data.total / data.per_page);
2852
- hasMorePages = currentPage < totalPages;
2863
+ hasMorePages = data.stories.length === perPage && data.stories.length > 0;
2864
+ if (data.stories.length < perPage) {
2865
+ break;
2866
+ }
2853
2867
  currentPage++;
2854
2868
  }
2855
2869
  return allStories;
@@ -4668,7 +4682,12 @@ STORYBLOK_DELIVERY_API_TOKEN=${accessToken}
4668
4682
  };
4669
4683
  const generateSpaceUrl = (spaceId, region) => {
4670
4684
  const domain = appDomains[region];
4671
- return `https://${domain}/#/me/spaces/${spaceId}/dashboard`;
4685
+ const utmParams = new URLSearchParams({
4686
+ utm_source: "storyblok-cli",
4687
+ utm_medium: "cli",
4688
+ utm_campaign: "create"
4689
+ });
4690
+ return `https://${domain}/#/me/spaces/${spaceId}/dashboard?${utmParams.toString()}`;
4672
4691
  };
4673
4692
  const openSpaceInBrowser = async (spaceId, region) => {
4674
4693
  try {
@@ -4688,7 +4707,7 @@ const extractPortFromTopics = (topics) => {
4688
4707
  }
4689
4708
  return "3000";
4690
4709
  };
4691
- const repositoryToBlueprint = (repo) => {
4710
+ const repositoryToTemplate = (repo) => {
4692
4711
  const technology = repo.name.replace("blueprint-core-", "");
4693
4712
  const port = extractPortFromTopics(repo.topics || []);
4694
4713
  return {
@@ -4709,7 +4728,7 @@ const fetchBlueprintRepositories = async () => {
4709
4728
  order: "desc",
4710
4729
  per_page: 100
4711
4730
  });
4712
- const blueprints = data.items.filter((repo) => repo.name.startsWith("blueprint-core-")).map(repositoryToBlueprint).sort((a, b) => a.name.localeCompare(b.name));
4731
+ const blueprints = data.items.filter((repo) => repo.name.startsWith("blueprint-core-")).map(repositoryToTemplate).sort((a, b) => a.name.localeCompare(b.name));
4713
4732
  return blueprints;
4714
4733
  } catch (error) {
4715
4734
  handleAPIError("fetch_blueprints", error, "Failed to fetch blueprints from GitHub");
@@ -4729,10 +4748,17 @@ const createSpace = async (space) => {
4729
4748
  };
4730
4749
 
4731
4750
  const program$1 = getProgram();
4732
- program$1.command(`${commands.CREATE} [project-path]`).alias("c").description(`Scaffold a new project using Storyblok`).option("-b, --blueprint <blueprint>", "technology starter blueprint").option("--skip-space", "skip space creation").action(async (projectPath, options) => {
4751
+ program$1.command(`${commands.CREATE} [project-path]`).alias("c").description(`Scaffold a new project using Storyblok`).option("-t, --template <template>", "technology starter template").option("-b, --blueprint <blueprint>", "[DEPRECATED] use --template instead").option("--skip-space", "skip space creation").action(async (projectPath, options) => {
4733
4752
  konsola.title(`${commands.CREATE}`, colorPalette.CREATE);
4734
4753
  const verbose = program$1.opts().verbose;
4735
- const { blueprint } = options;
4754
+ const { template, blueprint } = options;
4755
+ let selectedTemplate = template;
4756
+ if (blueprint && !template) {
4757
+ konsola.warn(`The --blueprint flag is deprecated. Please use --template instead.`);
4758
+ selectedTemplate = blueprint;
4759
+ } else if (blueprint && template) {
4760
+ konsola.warn(`Both --blueprint and --template provided. Using --template and ignoring --blueprint.`);
4761
+ }
4736
4762
  const { state, initializeSession } = session();
4737
4763
  await initializeSession();
4738
4764
  if (!requireAuthentication(state, verbose)) {
@@ -4749,33 +4775,42 @@ program$1.command(`${commands.CREATE} [project-path]`).alias("c").description(`S
4749
4775
  const spinnerSpace = new Spinner({
4750
4776
  verbose: !isVitest
4751
4777
  });
4778
+ let userData;
4752
4779
  try {
4753
- spinnerBlueprints.start("Fetching starter blueprints...");
4754
- const blueprints = await fetchBlueprintRepositories();
4755
- spinnerBlueprints.succeed("Starter blueprints fetched successfully");
4756
- if (!blueprints) {
4780
+ const { user } = await getUser(password, region);
4781
+ userData = user;
4782
+ } catch (error) {
4783
+ konsola.error("Failed to fetch user info. Please login again.", error);
4784
+ konsola.br();
4785
+ return;
4786
+ }
4787
+ try {
4788
+ spinnerBlueprints.start("Fetching starter templates...");
4789
+ const templates = await fetchBlueprintRepositories();
4790
+ spinnerBlueprints.succeed("Starter templates fetched successfully");
4791
+ if (!templates) {
4757
4792
  spinnerBlueprints.failed();
4758
- konsola.warn("No starter blueprints found. Please contact support@storyblok.com");
4793
+ konsola.warn("No starter templates found. Please contact support@storyblok.com");
4759
4794
  konsola.br();
4760
4795
  return;
4761
4796
  }
4762
- let technologyBlueprint = blueprint;
4763
- if (blueprint) {
4764
- const validBlueprints = blueprints;
4765
- const isValidBlueprint = validBlueprints.find((bp) => bp.value === blueprint);
4766
- if (!isValidBlueprint) {
4767
- const validOptions = validBlueprints.map((bp) => bp.value).join(", ");
4768
- konsola.warn(`Invalid blueprint "${chalk.hex(colorPalette.CREATE)(blueprint)}". Valid options are: ${chalk.hex(colorPalette.CREATE)(validOptions)}`);
4797
+ let technologyTemplate = selectedTemplate;
4798
+ if (selectedTemplate) {
4799
+ const validTemplates = templates;
4800
+ const isValidTemplate = validTemplates.find((bp) => bp.value === selectedTemplate);
4801
+ if (!isValidTemplate) {
4802
+ const validOptions = validTemplates.map((bp) => bp.value).join(", ");
4803
+ konsola.warn(`Invalid template "${chalk.hex(colorPalette.CREATE)(selectedTemplate)}". Valid options are: ${chalk.hex(colorPalette.CREATE)(validOptions)}`);
4769
4804
  konsola.br();
4770
- technologyBlueprint = void 0;
4805
+ technologyTemplate = void 0;
4771
4806
  }
4772
4807
  }
4773
- if (!technologyBlueprint) {
4774
- technologyBlueprint = await select({
4808
+ if (!technologyTemplate) {
4809
+ technologyTemplate = await select({
4775
4810
  message: "Please select the technology you would like to use:",
4776
- choices: blueprints.map((blueprint2) => ({
4777
- name: blueprint2.name,
4778
- value: blueprint2.value
4811
+ choices: templates.map((template2) => ({
4812
+ name: template2.name,
4813
+ value: template2.value
4779
4814
  }))
4780
4815
  });
4781
4816
  }
@@ -4783,7 +4818,7 @@ program$1.command(`${commands.CREATE} [project-path]`).alias("c").description(`S
4783
4818
  if (!projectPath) {
4784
4819
  finalProjectPath = await input({
4785
4820
  message: "What is the path for your project?",
4786
- default: `./my-${technologyBlueprint}-project`,
4821
+ default: `./my-${technologyTemplate}-project`,
4787
4822
  validate: (value) => {
4788
4823
  if (!value.trim()) {
4789
4824
  return "Project path is required";
@@ -4800,19 +4835,50 @@ program$1.command(`${commands.CREATE} [project-path]`).alias("c").description(`S
4800
4835
  const targetDirectory = path.dirname(resolvedPath);
4801
4836
  const projectName = path.basename(resolvedPath);
4802
4837
  konsola.br();
4803
- konsola.info(`Scaffolding your project using the ${chalk.hex(colorPalette.CREATE)(technologyBlueprint)} blueprint...`);
4804
- await generateProject(technologyBlueprint, projectName, targetDirectory);
4838
+ konsola.info(`Scaffolding your project using the ${chalk.hex(colorPalette.CREATE)(technologyTemplate)} template...`);
4839
+ await generateProject(technologyTemplate, projectName, targetDirectory);
4805
4840
  konsola.ok(`Project ${chalk.hex(colorPalette.PRIMARY)(projectName)} created successfully in ${chalk.hex(colorPalette.PRIMARY)(finalProjectPath)}`, true);
4806
4841
  let createdSpace;
4842
+ const choices = [
4843
+ { name: "My personal account", value: "personal" }
4844
+ ];
4845
+ if (userData.has_org) {
4846
+ choices.push({ name: `Organization (${userData.org.name})`, value: "org" });
4847
+ }
4848
+ if (userData.has_partner) {
4849
+ choices.push({ name: "Partner Portal", value: "partner" });
4850
+ }
4851
+ let whereToCreateSpace = "personal";
4852
+ if (region === "eu" && (userData.has_partner || userData.has_org)) {
4853
+ whereToCreateSpace = await select({
4854
+ message: `Where would you like to create this space?`,
4855
+ choices
4856
+ });
4857
+ }
4858
+ if (region !== "eu" && userData.has_org) {
4859
+ whereToCreateSpace = "org";
4860
+ }
4861
+ if (region !== "eu" && !userData.has_org) {
4862
+ konsola.warn(`Space creation in this region is limited to Enterprise accounts. If you're part of an organization, please ensure you have the required permissions. For more information about Enterprise access, contact our Sales Team.`);
4863
+ konsola.br();
4864
+ return;
4865
+ }
4807
4866
  if (!options.skipSpace) {
4808
4867
  try {
4809
4868
  spinnerSpace.start(`Creating space "${toHumanReadable(projectName)}"`);
4810
- const selectedBlueprint = blueprints.find((bp) => bp.value === technologyBlueprint);
4869
+ const selectedBlueprint = templates.find((bp) => bp.value === technologyTemplate);
4811
4870
  const blueprintDomain = selectedBlueprint?.location || "https://localhost:3000/";
4812
- createdSpace = await createSpace({
4871
+ const spaceToCreate = {
4813
4872
  name: toHumanReadable(projectName),
4814
4873
  domain: blueprintDomain
4815
- });
4874
+ };
4875
+ if (whereToCreateSpace === "org") {
4876
+ spaceToCreate.org = userData.org;
4877
+ spaceToCreate.in_org = true;
4878
+ } else if (whereToCreateSpace === "partner") {
4879
+ spaceToCreate.assign_partner = true;
4880
+ }
4881
+ createdSpace = await createSpace(spaceToCreate);
4816
4882
  spinnerSpace.succeed(`Space "${chalk.hex(colorPalette.PRIMARY)(toHumanReadable(projectName))}" created successfully`);
4817
4883
  } catch (error) {
4818
4884
  spinnerSpace.failed();
@@ -4841,9 +4907,15 @@ program$1.command(`${commands.CREATE} [project-path]`).alias("c").description(`S
4841
4907
  }
4842
4908
  }
4843
4909
  konsola.br();
4844
- konsola.ok(`Your ${chalk.hex(colorPalette.PRIMARY)(technologyBlueprint)} project is ready \u{1F389} !`);
4910
+ konsola.ok(`Your ${chalk.hex(colorPalette.PRIMARY)(technologyTemplate)} project is ready \u{1F389} !`);
4845
4911
  if (createdSpace?.first_token) {
4846
- konsola.ok(`Storyblok space created, preview url and .env configured automatically`);
4912
+ if (whereToCreateSpace === "org") {
4913
+ konsola.ok(`Storyblok space created in organization ${chalk.hex(colorPalette.PRIMARY)(userData.org.name)}, preview url and .env configured automatically. You can now open your space in the browser at ${chalk.hex(colorPalette.PRIMARY)(generateSpaceUrl(createdSpace.id, region))}`);
4914
+ } else if (whereToCreateSpace === "partner") {
4915
+ konsola.ok(`Storyblok space created in partner portal, preview url and .env configured automatically. You can now open your space in the browser at ${chalk.hex(colorPalette.PRIMARY)(generateSpaceUrl(createdSpace.id, region))}`);
4916
+ } else {
4917
+ konsola.ok(`Storyblok space created, preview url and .env configured automatically. You can now open your space in the browser at ${chalk.hex(colorPalette.PRIMARY)(generateSpaceUrl(createdSpace.id, region))}`);
4918
+ }
4847
4919
  }
4848
4920
  konsola.br();
4849
4921
  konsola.info(`Next steps:
@@ -4860,7 +4932,7 @@ program$1.command(`${commands.CREATE} [project-path]`).alias("c").description(`S
4860
4932
  konsola.br();
4861
4933
  });
4862
4934
 
4863
- const version = "4.3.3";
4935
+ const version = "4.4.0";
4864
4936
  const pkg = {
4865
4937
  version: version};
4866
4938