storyblok 4.6.14 → 4.7.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
@@ -4041,6 +4041,7 @@ const DEFAULT_TYPEDEFS_HEADER = [
4041
4041
  "// This file was generated by the storyblok CLI.",
4042
4042
  "// DO NOT MODIFY THIS FILE BY HAND."
4043
4043
  ];
4044
+ const getDatasourceTypeTitle = (slug) => `${toPascalCase(slug)}DataSource`;
4044
4045
  const getPropertyTypeAnnotation = (property, prefix, suffix) => {
4045
4046
  if (Array.from(storyblokSchemas.keys()).includes(property.type)) {
4046
4047
  return { type: property.type };
@@ -4149,6 +4150,13 @@ const getComponentPropertiesTypeAnnotations = async (component, options, spaceDa
4149
4150
  const componentType = toPascalCase(propertyType);
4150
4151
  propertyTypeAnnotation[key].tsType = `Storyblok${componentType}`;
4151
4152
  }
4153
+ if (spaceData.datasources.length > 0 && schema.source === "internal" && schema?.datasource_slug) {
4154
+ const datasourceExists = spaceData.datasources.some((ds) => ds.slug === schema.datasource_slug);
4155
+ if (datasourceExists) {
4156
+ const type = getDatasourceTypeTitle(schema.datasource_slug);
4157
+ propertyTypeAnnotation[key].tsType = propertyType === "options" ? `${type}[]` : type;
4158
+ }
4159
+ }
4152
4160
  if (propertyType === "multilink") {
4153
4161
  const excludedLinktypes = [
4154
4162
  ...!schema.email_link_type ? ['{ linktype?: "email" }'] : [],
@@ -4222,6 +4230,7 @@ const generateTypes = async (spaceData, options = {
4222
4230
  try {
4223
4231
  const typeDefs = [...DEFAULT_TYPEDEFS_HEADER];
4224
4232
  const storyblokPropertyTypes = /* @__PURE__ */ new Set();
4233
+ const contentTypeBloks = /* @__PURE__ */ new Set();
4225
4234
  let customFieldsParser;
4226
4235
  let compilerOptions;
4227
4236
  if (options.customFieldsParser) {
@@ -4230,8 +4239,11 @@ const generateTypes = async (spaceData, options = {
4230
4239
  if (options.compilerOptions) {
4231
4240
  compilerOptions = await loadCompilerOptions(options.compilerOptions);
4232
4241
  }
4233
- const schemas = await Promise.all(spaceData.components.map(async (component) => {
4242
+ const componentsSchema = spaceData.components.map(async (component) => {
4234
4243
  const type = getComponentType(component.name, options);
4244
+ if (component.is_root) {
4245
+ contentTypeBloks.add(type);
4246
+ }
4235
4247
  const componentPropertiesTypeAnnotations = await getComponentPropertiesTypeAnnotations(component, options, spaceData, customFieldsParser);
4236
4248
  const requiredFields = Object.entries(component?.schema || {}).reduce(
4237
4249
  (acc, [key, value]) => {
@@ -4270,7 +4282,35 @@ const generateTypes = async (spaceData, options = {
4270
4282
  }
4271
4283
  };
4272
4284
  return componentSchema;
4273
- }));
4285
+ });
4286
+ const resolvedComponentsSchema = await Promise.all(componentsSchema);
4287
+ const datasourcesSchema = spaceData.datasources.map(async (datasource) => {
4288
+ const allComponentTypes = resolvedComponentsSchema.map((schema) => schema.title);
4289
+ const enumValues = datasource.entries?.filter((d) => d.value).map((d) => d.value);
4290
+ const type = getDatasourceTypeTitle(datasource.slug);
4291
+ if (allComponentTypes.includes(type)) {
4292
+ console.warn(`Warning: Datasource type "${type}" conflicts with existing component type`);
4293
+ }
4294
+ const datasourceSchema = {
4295
+ $id: `#/${datasource.slug}`,
4296
+ title: type,
4297
+ type: "string",
4298
+ enum: enumValues
4299
+ };
4300
+ return datasourceSchema;
4301
+ });
4302
+ const resolvedDatasourcesSchema = await Promise.all(datasourcesSchema);
4303
+ const contentTypeSchema = {
4304
+ $id: `#/ContentType`,
4305
+ title: "ContentType",
4306
+ type: "string",
4307
+ tsType: contentTypeBloks.size > 0 ? `${Array.from(contentTypeBloks).join(" | ")}` : "never"
4308
+ };
4309
+ const schemas = [
4310
+ ...resolvedComponentsSchema,
4311
+ ...resolvedDatasourcesSchema,
4312
+ contentTypeSchema
4313
+ ];
4274
4314
  const result = await Promise.all(schemas.map(async (schema) => {
4275
4315
  return await compile(schema, schema.title || schema.$id.replace("#/", ""), {
4276
4316
  additionalProperties: !options.strict,
@@ -4328,6 +4368,160 @@ const generateStoryblokTypes = async (options = {}) => {
4328
4368
  }
4329
4369
  };
4330
4370
 
4371
+ const pushDatasource = async (spaceId, datasource) => {
4372
+ try {
4373
+ const client = mapiClient();
4374
+ const { data } = await client.datasources.create({
4375
+ path: {
4376
+ space_id: spaceId
4377
+ },
4378
+ body: { datasource },
4379
+ throwOnError: true
4380
+ });
4381
+ return data.datasource;
4382
+ } catch (error) {
4383
+ handleAPIError("push_datasource", error, `Failed to push datasource ${datasource.name}`);
4384
+ }
4385
+ };
4386
+ const updateDatasource = async (spaceId, datasourceId, datasource) => {
4387
+ try {
4388
+ const client = mapiClient();
4389
+ const { data } = await client.datasources.update({
4390
+ path: {
4391
+ space_id: spaceId,
4392
+ datasource_id: datasourceId
4393
+ },
4394
+ body: {
4395
+ datasource
4396
+ },
4397
+ throwOnError: true
4398
+ });
4399
+ return data.datasource;
4400
+ } catch (error) {
4401
+ handleAPIError("update_datasource", error, `Failed to update datasource ${datasource.name}`);
4402
+ }
4403
+ };
4404
+ const upsertDatasource = async (space, datasource, existingId) => {
4405
+ if (existingId) {
4406
+ return await updateDatasource(space, existingId, datasource);
4407
+ } else {
4408
+ return await pushDatasource(space, datasource);
4409
+ }
4410
+ };
4411
+ const pushDatasourceEntry = async (spaceId, datasourceId, entry) => {
4412
+ try {
4413
+ const client = mapiClient();
4414
+ const { data } = await client.datasourceEntries.create({
4415
+ path: {
4416
+ space_id: spaceId
4417
+ },
4418
+ body: {
4419
+ datasource_entry: {
4420
+ ...entry,
4421
+ datasource_id: datasourceId
4422
+ }
4423
+ },
4424
+ throwOnError: true
4425
+ });
4426
+ return data.datasource_entry;
4427
+ } catch (error) {
4428
+ handleAPIError("push_datasource", error, `Failed to push datasource entry ${entry.name}`);
4429
+ }
4430
+ };
4431
+ const updateDatasourceEntry = async (spaceId, entryId, entry) => {
4432
+ try {
4433
+ const client = mapiClient();
4434
+ await client.datasourceEntries.updateDatasourceEntry({
4435
+ path: {
4436
+ space_id: spaceId,
4437
+ datasource_entry_id: entryId
4438
+ },
4439
+ body: {
4440
+ datasource_entry: entry
4441
+ },
4442
+ throwOnError: true
4443
+ });
4444
+ } catch (error) {
4445
+ handleAPIError("update_datasource", error, `Failed to update datasource entry ${entry.name}`);
4446
+ }
4447
+ };
4448
+ const upsertDatasourceEntry = async (space, datasourceId, entry, existingId) => {
4449
+ if (existingId) {
4450
+ await updateDatasourceEntry(space, existingId, entry);
4451
+ return void 0;
4452
+ } else {
4453
+ return await pushDatasourceEntry(space, datasourceId, entry);
4454
+ }
4455
+ };
4456
+ const readDatasourcesFiles = async (options) => {
4457
+ const { from, path, separateFiles = false, suffix, space } = options;
4458
+ const resolvedPath = resolvePath(path, `datasources/${from}`);
4459
+ try {
4460
+ await readdir(resolvedPath);
4461
+ } catch (error) {
4462
+ const message = `No local datasources found for space ${chalk.bold(from)}. To push datasources, you need to pull them first:
4463
+
4464
+ 1. Pull the datasources from your source space:
4465
+ ${chalk.cyan(`storyblok datasources pull --space ${from}`)}
4466
+
4467
+ 2. Then try pushing again:
4468
+ ${chalk.cyan(`storyblok datasources push --space ${space} --from ${from}`)}`;
4469
+ throw new FileSystemError(
4470
+ "file_not_found",
4471
+ "read",
4472
+ error,
4473
+ message
4474
+ );
4475
+ }
4476
+ if (separateFiles) {
4477
+ return await readSeparateFiles(resolvedPath, suffix);
4478
+ }
4479
+ return await readConsolidatedFiles(resolvedPath, suffix);
4480
+ };
4481
+ async function readSeparateFiles(resolvedPath, suffix) {
4482
+ const files = await readdir(resolvedPath);
4483
+ const datasources = [];
4484
+ const filteredFiles = files.filter((file) => {
4485
+ if (suffix) {
4486
+ return file.endsWith(`.${suffix}.json`);
4487
+ } else {
4488
+ return !/\.\w+\.json$/.test(file);
4489
+ }
4490
+ });
4491
+ for (const file of filteredFiles) {
4492
+ const filePath = join(resolvedPath, file);
4493
+ if (file.endsWith(".json") || file.endsWith(`${suffix}.json`)) {
4494
+ if (file === "datasources.json" || /^datasources\.\w+\.json$/.test(file)) {
4495
+ continue;
4496
+ }
4497
+ const result = await readJsonFile(filePath);
4498
+ if (result.error) {
4499
+ handleFileSystemError("read", result.error);
4500
+ continue;
4501
+ }
4502
+ datasources.push(...result.data);
4503
+ }
4504
+ }
4505
+ return {
4506
+ datasources
4507
+ };
4508
+ }
4509
+ async function readConsolidatedFiles(resolvedPath, suffix) {
4510
+ const datasourcesPath = join(resolvedPath, suffix ? `datasources.${suffix}.json` : "datasources.json");
4511
+ const datasourcesResult = await readJsonFile(datasourcesPath);
4512
+ if (datasourcesResult.error || !datasourcesResult.data.length) {
4513
+ throw new FileSystemError(
4514
+ "file_not_found",
4515
+ "read",
4516
+ datasourcesResult.error || new Error("Datasources file is empty"),
4517
+ `No datasources found in ${datasourcesPath}. Please make sure you have pulled the datasources first.`
4518
+ );
4519
+ }
4520
+ return {
4521
+ datasources: datasourcesResult.data
4522
+ };
4523
+ }
4524
+
4331
4525
  const program$5 = getProgram();
4332
4526
  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(
4333
4527
  "--filename <name>",
@@ -4341,19 +4535,33 @@ typesCommand.command("generate").description("Generate types d.ts for your compo
4341
4535
  });
4342
4536
  try {
4343
4537
  spinner.start(`Generating types...`);
4344
- const spaceData = await readComponentsFiles({
4538
+ const componentsData = await readComponentsFiles({
4345
4539
  ...options,
4346
4540
  from: space,
4347
4541
  path
4348
4542
  });
4543
+ let dataSourceData;
4544
+ try {
4545
+ dataSourceData = await readDatasourcesFiles({
4546
+ ...options,
4547
+ from: space,
4548
+ path
4549
+ });
4550
+ } catch (error) {
4551
+ if (error instanceof FileSystemError && error.errorId === "file_not_found") {
4552
+ dataSourceData = { datasources: [] };
4553
+ } else {
4554
+ throw error;
4555
+ }
4556
+ }
4349
4557
  await generateStoryblokTypes({
4350
4558
  path
4351
4559
  });
4352
- const spaceDataWithDatasources = {
4353
- ...spaceData,
4354
- datasources: []
4560
+ const spaceDataWithComponentsAndDatasources = {
4561
+ ...componentsData,
4562
+ ...dataSourceData
4355
4563
  };
4356
- const typedefString = await generateTypes(spaceDataWithDatasources, {
4564
+ const typedefString = await generateTypes(spaceDataWithComponentsAndDatasources, {
4357
4565
  ...options,
4358
4566
  path
4359
4567
  });
@@ -4552,160 +4760,6 @@ datasourcesCommand.command("pull [datasourceName]").option("-f, --filename <file
4552
4760
  }
4553
4761
  });
4554
4762
 
4555
- const pushDatasource = async (spaceId, datasource) => {
4556
- try {
4557
- const client = mapiClient();
4558
- const { data } = await client.datasources.create({
4559
- path: {
4560
- space_id: spaceId
4561
- },
4562
- body: { datasource },
4563
- throwOnError: true
4564
- });
4565
- return data.datasource;
4566
- } catch (error) {
4567
- handleAPIError("push_datasource", error, `Failed to push datasource ${datasource.name}`);
4568
- }
4569
- };
4570
- const updateDatasource = async (spaceId, datasourceId, datasource) => {
4571
- try {
4572
- const client = mapiClient();
4573
- const { data } = await client.datasources.update({
4574
- path: {
4575
- space_id: spaceId,
4576
- datasource_id: datasourceId
4577
- },
4578
- body: {
4579
- datasource
4580
- },
4581
- throwOnError: true
4582
- });
4583
- return data.datasource;
4584
- } catch (error) {
4585
- handleAPIError("update_datasource", error, `Failed to update datasource ${datasource.name}`);
4586
- }
4587
- };
4588
- const upsertDatasource = async (space, datasource, existingId) => {
4589
- if (existingId) {
4590
- return await updateDatasource(space, existingId, datasource);
4591
- } else {
4592
- return await pushDatasource(space, datasource);
4593
- }
4594
- };
4595
- const pushDatasourceEntry = async (spaceId, datasourceId, entry) => {
4596
- try {
4597
- const client = mapiClient();
4598
- const { data } = await client.datasourceEntries.create({
4599
- path: {
4600
- space_id: spaceId
4601
- },
4602
- body: {
4603
- datasource_entry: {
4604
- ...entry,
4605
- datasource_id: datasourceId
4606
- }
4607
- },
4608
- throwOnError: true
4609
- });
4610
- return data.datasource_entry;
4611
- } catch (error) {
4612
- handleAPIError("push_datasource", error, `Failed to push datasource entry ${entry.name}`);
4613
- }
4614
- };
4615
- const updateDatasourceEntry = async (spaceId, entryId, entry) => {
4616
- try {
4617
- const client = mapiClient();
4618
- await client.datasourceEntries.updateDatasourceEntry({
4619
- path: {
4620
- space_id: spaceId,
4621
- datasource_entry_id: entryId
4622
- },
4623
- body: {
4624
- datasource_entry: entry
4625
- },
4626
- throwOnError: true
4627
- });
4628
- } catch (error) {
4629
- handleAPIError("update_datasource", error, `Failed to update datasource entry ${entry.name}`);
4630
- }
4631
- };
4632
- const upsertDatasourceEntry = async (space, datasourceId, entry, existingId) => {
4633
- if (existingId) {
4634
- await updateDatasourceEntry(space, existingId, entry);
4635
- return void 0;
4636
- } else {
4637
- return await pushDatasourceEntry(space, datasourceId, entry);
4638
- }
4639
- };
4640
- const readDatasourcesFiles = async (options) => {
4641
- const { from, path, separateFiles = false, suffix, space } = options;
4642
- const resolvedPath = resolvePath(path, `datasources/${from}`);
4643
- try {
4644
- await readdir(resolvedPath);
4645
- } catch (error) {
4646
- const message = `No local datasources found for space ${chalk.bold(from)}. To push datasources, you need to pull them first:
4647
-
4648
- 1. Pull the datasources from your source space:
4649
- ${chalk.cyan(`storyblok datasources pull --space ${from}`)}
4650
-
4651
- 2. Then try pushing again:
4652
- ${chalk.cyan(`storyblok datasources push --space ${space} --from ${from}`)}`;
4653
- throw new FileSystemError(
4654
- "file_not_found",
4655
- "read",
4656
- error,
4657
- message
4658
- );
4659
- }
4660
- if (separateFiles) {
4661
- return await readSeparateFiles(resolvedPath, suffix);
4662
- }
4663
- return await readConsolidatedFiles(resolvedPath, suffix);
4664
- };
4665
- async function readSeparateFiles(resolvedPath, suffix) {
4666
- const files = await readdir(resolvedPath);
4667
- const datasources = [];
4668
- const filteredFiles = files.filter((file) => {
4669
- if (suffix) {
4670
- return file.endsWith(`.${suffix}.json`);
4671
- } else {
4672
- return !/\.\w+\.json$/.test(file);
4673
- }
4674
- });
4675
- for (const file of filteredFiles) {
4676
- const filePath = join(resolvedPath, file);
4677
- if (file.endsWith(".json") || file.endsWith(`${suffix}.json`)) {
4678
- if (file === "datasources.json" || /^datasources\.\w+\.json$/.test(file)) {
4679
- continue;
4680
- }
4681
- const result = await readJsonFile(filePath);
4682
- if (result.error) {
4683
- handleFileSystemError("read", result.error);
4684
- continue;
4685
- }
4686
- datasources.push(...result.data);
4687
- }
4688
- }
4689
- return {
4690
- datasources
4691
- };
4692
- }
4693
- async function readConsolidatedFiles(resolvedPath, suffix) {
4694
- const datasourcesPath = join(resolvedPath, suffix ? `datasources.${suffix}.json` : "datasources.json");
4695
- const datasourcesResult = await readJsonFile(datasourcesPath);
4696
- if (datasourcesResult.error || !datasourcesResult.data.length) {
4697
- throw new FileSystemError(
4698
- "file_not_found",
4699
- "read",
4700
- datasourcesResult.error || new Error("Datasources file is empty"),
4701
- `No datasources found in ${datasourcesPath}. Please make sure you have pulled the datasources first.`
4702
- );
4703
- }
4704
- return {
4705
- datasources: datasourcesResult.data
4706
- };
4707
- }
4708
-
4709
4763
  const program$2 = getProgram();
4710
4764
  datasourcesCommand.command("push [datasourceName]").description(`Push your space's datasources schema as json`).option("-f, --from <from>", "source space id").option("--fi, --filter <filter>", "glob filter to apply to the datasources before pushing").option("--sf, --separate-files", "Read from separate files instead of consolidated files").option("--su, --suffix <suffix>", "Suffix to add to the datasource name").action(async (datasourceName, options) => {
4711
4765
  konsola.title(`${commands.DATASOURCES}`, colorPalette.DATASOURCES, datasourceName ? `Pushing datasource ${datasourceName}...` : "Pushing datasources...");
@@ -5217,7 +5271,7 @@ program$1.command(`${commands.CREATE} [project-path]`).alias("c").description(`S
5217
5271
  konsola.br();
5218
5272
  });
5219
5273
 
5220
- const version = "4.6.14";
5274
+ const version = "4.7.0";
5221
5275
  const pkg = {
5222
5276
  version: version};
5223
5277