@stackbit/cms-core 0.1.1 → 0.1.3-alpha.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.
Files changed (34) hide show
  1. package/dist/content-source-interface.d.ts +3 -11
  2. package/dist/content-source-interface.d.ts.map +1 -1
  3. package/dist/content-source-interface.js.map +1 -1
  4. package/dist/content-store-types.d.ts +15 -24
  5. package/dist/content-store-types.d.ts.map +1 -1
  6. package/dist/content-store-utils.d.ts +9 -0
  7. package/dist/content-store-utils.d.ts.map +1 -0
  8. package/dist/content-store-utils.js +139 -0
  9. package/dist/content-store-utils.js.map +1 -0
  10. package/dist/content-store.d.ts +0 -1
  11. package/dist/content-store.d.ts.map +1 -1
  12. package/dist/content-store.js +99 -945
  13. package/dist/content-store.js.map +1 -1
  14. package/dist/utils/create-update-csi-docs.d.ts +68 -0
  15. package/dist/utils/create-update-csi-docs.d.ts.map +1 -0
  16. package/dist/utils/create-update-csi-docs.js +376 -0
  17. package/dist/utils/create-update-csi-docs.js.map +1 -0
  18. package/dist/utils/csi-to-store-docs-converter.d.ts +15 -0
  19. package/dist/utils/csi-to-store-docs-converter.d.ts.map +1 -0
  20. package/dist/utils/csi-to-store-docs-converter.js +287 -0
  21. package/dist/utils/csi-to-store-docs-converter.js.map +1 -0
  22. package/dist/utils/store-to-api-docs-converter.d.ts +5 -0
  23. package/dist/utils/store-to-api-docs-converter.d.ts.map +1 -0
  24. package/dist/utils/store-to-api-docs-converter.js +247 -0
  25. package/dist/utils/store-to-api-docs-converter.js.map +1 -0
  26. package/package.json +4 -4
  27. package/src/content-source-interface.ts +4 -13
  28. package/src/content-store-types.ts +12 -10
  29. package/src/content-store-utils.ts +149 -0
  30. package/src/content-store.ts +57 -1073
  31. package/src/index.ts +1 -1
  32. package/src/utils/create-update-csi-docs.ts +440 -0
  33. package/src/utils/csi-to-store-docs-converter.ts +365 -0
  34. package/src/utils/store-to-api-docs-converter.ts +246 -0
@@ -3,16 +3,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getContentSourceId = exports.ContentStore = void 0;
6
+ exports.ContentStore = void 0;
7
7
  const lodash_1 = __importDefault(require("lodash"));
8
- const slugify_1 = __importDefault(require("slugify"));
9
8
  const path_1 = __importDefault(require("path"));
10
9
  const sanitize_filename_1 = __importDefault(require("sanitize-filename"));
11
10
  const sdk_1 = require("@stackbit/sdk");
12
11
  const utils_1 = require("@stackbit/utils");
13
- const content_source_interface_1 = require("./content-source-interface");
14
- const common_schema_1 = require("./common/common-schema");
15
12
  const timer_1 = require("./utils/timer");
13
+ const content_source_interface_1 = require("./content-source-interface");
14
+ const csi_to_store_docs_converter_1 = require("./utils/csi-to-store-docs-converter");
15
+ const content_store_utils_1 = require("./content-store-utils");
16
+ const store_to_api_docs_converter_1 = require("./utils/store-to-api-docs-converter");
17
+ const create_update_csi_docs_1 = require("./utils/create-update-csi-docs");
16
18
  class ContentStore {
17
19
  constructor(options) {
18
20
  this.contentSources = [];
@@ -40,7 +42,7 @@ class ContentStore {
40
42
  thisArg: this,
41
43
  // Group the deferred calls by content source ID.
42
44
  groupResolver: ({ contentSourceInstance }) => {
43
- return getContentSourceIdForContentSource(contentSourceInstance);
45
+ return (0, content_store_utils_1.getContentSourceIdForContentSource)(contentSourceInstance);
44
46
  },
45
47
  // When the loadContentSourceData call is called multiple times with
46
48
  // different "init" values, ensure that the deferred call will be
@@ -75,7 +77,10 @@ class ContentStore {
75
77
  this.rawStackbitConfig = null;
76
78
  }
77
79
  else {
78
- const rawConfigResult = await (0, sdk_1.loadConfigFromDir)({ dirPath: stackbitConfig.dirPath });
80
+ const rawConfigResult = await (0, sdk_1.loadConfigFromDir)({
81
+ dirPath: stackbitConfig.dirPath,
82
+ logger: this.logger
83
+ });
79
84
  for (const error of rawConfigResult.errors) {
80
85
  this.userLogger.warn(error.message);
81
86
  }
@@ -142,7 +147,7 @@ class ContentStore {
142
147
  deletedAssets: []
143
148
  };
144
149
  for (const contentSourceInstance of this.contentSources) {
145
- const contentSourceId = getContentSourceIdForContentSource(contentSourceInstance);
150
+ const contentSourceId = (0, content_store_utils_1.getContentSourceIdForContentSource)(contentSourceInstance);
146
151
  this.logger.debug(`call onFilesChange for contentSource: ${contentSourceId}`);
147
152
  const { schemaChanged, contentChangeEvent } = (_b = (_a = contentSourceInstance.onFilesChange) === null || _a === void 0 ? void 0 : _a.call(contentSourceInstance, { updatedFiles: updatedFiles })) !== null && _b !== void 0 ? _b : {};
148
153
  this.logger.debug(`schemaChanged: ${schemaChanged}, has contentChangeEvent: ${!!contentChangeEvent}`);
@@ -182,8 +187,8 @@ class ContentStore {
182
187
  this.contentUpdatesWatchTimer.startTimer();
183
188
  }
184
189
  async loadContentSourceData({ contentSourceInstance, init }) {
185
- var _a, _b, _c, _d;
186
- const contentSourceId = getContentSourceIdForContentSource(contentSourceInstance);
190
+ var _a, _b, _c, _d, _e;
191
+ const contentSourceId = (0, content_store_utils_1.getContentSourceIdForContentSource)(contentSourceInstance);
187
192
  this.logger.debug('loadContentSourceData', { contentSourceId, init });
188
193
  if (init) {
189
194
  await contentSourceInstance.init({
@@ -216,10 +221,19 @@ class ContentStore {
216
221
  models = (_c = config === null || config === void 0 ? void 0 : config.models) !== null && _c !== void 0 ? _c : [];
217
222
  // TODO: load presets externally from config, and create additional map
218
223
  // that maps presetIds by model name instead of storing that map inside every model
219
- // TODO: adjust presets to have srcType and srcProjectId
220
- this.presets = config === null || config === void 0 ? void 0 : config.presets;
224
+ // Augment presets with srcType and srcProjectId if they don't exist
225
+ this.presets = lodash_1.default.reduce(Object.keys((_d = config === null || config === void 0 ? void 0 : config.presets) !== null && _d !== void 0 ? _d : {}), (accum, presetId) => {
226
+ var _a, _b, _c;
227
+ const preset = (_a = config === null || config === void 0 ? void 0 : config.presets) === null || _a === void 0 ? void 0 : _a[presetId];
228
+ lodash_1.default.set(accum, [presetId], {
229
+ ...preset,
230
+ srcType: (_b = preset === null || preset === void 0 ? void 0 : preset.srcType) !== null && _b !== void 0 ? _b : contentSourceInstance.getContentSourceType(),
231
+ srcProjectId: (_c = preset === null || preset === void 0 ? void 0 : preset.srcProjectId) !== null && _c !== void 0 ? _c : contentSourceInstance.getProjectId()
232
+ });
233
+ return accum;
234
+ }, {});
221
235
  }
222
- if ((_d = this.rawStackbitConfig) === null || _d === void 0 ? void 0 : _d.mapModels) {
236
+ if ((_e = this.rawStackbitConfig) === null || _e === void 0 ? void 0 : _e.mapModels) {
223
237
  models = this.rawStackbitConfig.mapModels({
224
238
  models: models,
225
239
  contentSourceType: contentSourceInstance.getContentSourceType(),
@@ -232,13 +246,13 @@ class ContentStore {
232
246
  const csiDocumentMap = lodash_1.default.keyBy(csiDocuments, 'id');
233
247
  const csiAssetMap = lodash_1.default.keyBy(csiAssets, 'id');
234
248
  const csiModelMap = lodash_1.default.keyBy(csiModels, 'name');
235
- const contentStoreDocuments = mapCSIDocumentsToStoreDocuments({
249
+ const contentStoreDocuments = (0, csi_to_store_docs_converter_1.mapCSIDocumentsToStoreDocuments)({
236
250
  csiDocuments,
237
251
  contentSourceInstance,
238
252
  modelMap,
239
253
  defaultLocaleCode
240
254
  });
241
- const contentStoreAssets = mapCSIAssetsToStoreAssets({
255
+ const contentStoreAssets = (0, csi_to_store_docs_converter_1.mapCSIAssetsToStoreAssets)({
242
256
  csiAssets,
243
257
  contentSourceInstance,
244
258
  defaultLocaleCode
@@ -350,13 +364,13 @@ class ContentStore {
350
364
  });
351
365
  });
352
366
  // map csi documents and assets to content store documents and assets
353
- const documents = mapCSIDocumentsToStoreDocuments({
367
+ const documents = (0, csi_to_store_docs_converter_1.mapCSIDocumentsToStoreDocuments)({
354
368
  csiDocuments: contentChangeEvent.documents,
355
369
  contentSourceInstance: contentSourceData.instance,
356
370
  modelMap: contentSourceData.modelMap,
357
371
  defaultLocaleCode: contentSourceData.defaultLocaleCode
358
372
  });
359
- const assets = mapCSIAssetsToStoreAssets({
373
+ const assets = (0, csi_to_store_docs_converter_1.mapCSIAssetsToStoreAssets)({
360
374
  csiAssets: contentChangeEvent.assets,
361
375
  contentSourceInstance: contentSourceData.instance,
362
376
  defaultLocaleCode: contentSourceData.defaultLocaleCode
@@ -428,25 +442,25 @@ class ContentStore {
428
442
  return (_a = this.presets) !== null && _a !== void 0 ? _a : {};
429
443
  }
430
444
  getContentSourceEnvironment({ srcProjectId, srcType }) {
431
- const contentSourceId = getContentSourceId(srcType, srcProjectId);
445
+ const contentSourceId = (0, content_store_utils_1.getContentSourceId)(srcType, srcProjectId);
432
446
  const contentSourceData = this.getContentSourceDataByIdOrThrow(contentSourceId);
433
447
  return contentSourceData.instance.getProjectEnvironment();
434
448
  }
435
449
  hasAccess({ srcType, srcProjectId, user }) {
436
- const contentSourceId = getContentSourceId(srcType, srcProjectId);
450
+ const contentSourceId = (0, content_store_utils_1.getContentSourceId)(srcType, srcProjectId);
437
451
  const contentSourceData = this.getContentSourceDataByIdOrThrow(contentSourceId);
438
- const userContext = getUserContextForSrcType(srcType, user);
452
+ const userContext = (0, content_store_utils_1.getUserContextForSrcType)(srcType, user);
439
453
  return contentSourceData.instance.hasAccess({ userContext });
440
454
  }
441
455
  hasChanges({ srcType, srcProjectId, documents }) {
442
456
  let result;
443
457
  if (srcType && srcProjectId) {
444
- const contentSourceId = getContentSourceId(srcType, srcProjectId);
458
+ const contentSourceId = (0, content_store_utils_1.getContentSourceId)(srcType, srcProjectId);
445
459
  const contentSourceData = this.getContentSourceDataByIdOrThrow(contentSourceId);
446
460
  result = [...contentSourceData.documents, ...contentSourceData.assets];
447
461
  }
448
462
  else if (documents && documents.length > 0) {
449
- const documentsBySourceId = lodash_1.default.groupBy(documents, (document) => getContentSourceId(document.srcType, document.srcProjectId));
463
+ const documentsBySourceId = lodash_1.default.groupBy(documents, (document) => (0, content_store_utils_1.getContentSourceId)(document.srcType, document.srcProjectId));
450
464
  result = lodash_1.default.reduce(documentsBySourceId, (result, documents, contentSourceId) => {
451
465
  const contentSourceData = this.getContentSourceDataByIdOrThrow(contentSourceId);
452
466
  for (const document of documents) {
@@ -476,7 +490,7 @@ class ContentStore {
476
490
  };
477
491
  }
478
492
  getDocument({ srcDocumentId, srcProjectId, srcType }) {
479
- const contentSourceId = getContentSourceId(srcType, srcProjectId);
493
+ const contentSourceId = (0, content_store_utils_1.getContentSourceId)(srcType, srcProjectId);
480
494
  const contentSourceData = this.getContentSourceDataByIdOrThrow(contentSourceId);
481
495
  return contentSourceData.documentMap[srcDocumentId];
482
496
  }
@@ -486,7 +500,7 @@ class ContentStore {
486
500
  }, []);
487
501
  }
488
502
  getAsset({ srcAssetId, srcProjectId, srcType }) {
489
- const contentSourceId = getContentSourceId(srcType, srcProjectId);
503
+ const contentSourceId = (0, content_store_utils_1.getContentSourceId)(srcType, srcProjectId);
490
504
  const contentSourceData = this.getContentSourceDataByIdOrThrow(contentSourceId);
491
505
  return contentSourceData.assetMap[srcAssetId];
492
506
  }
@@ -498,21 +512,21 @@ class ContentStore {
498
512
  getLocalizedApiObjects({ locale }) {
499
513
  return lodash_1.default.reduce(this.contentSourceDataById, (objects, contentSourceData) => {
500
514
  locale = locale !== null && locale !== void 0 ? locale : contentSourceData.defaultLocaleCode;
501
- const documentObjects = mapDocumentsToLocalizedApiObjects(contentSourceData.documents, locale);
502
- const imageObjects = mapAssetsToLocalizedApiImages(contentSourceData.assets, locale);
515
+ const documentObjects = (0, store_to_api_docs_converter_1.mapDocumentsToLocalizedApiObjects)(contentSourceData.documents, locale);
516
+ const imageObjects = (0, store_to_api_docs_converter_1.mapAssetsToLocalizedApiImages)(contentSourceData.assets, locale);
503
517
  return objects.concat(documentObjects, imageObjects);
504
518
  }, []);
505
519
  }
506
520
  getApiAssets({ srcType, srcProjectId, pageSize = 20, pageNum = 1, searchQuery } = {}) {
507
521
  let assets;
508
522
  if (srcProjectId && srcType) {
509
- const contentSourceId = getContentSourceId(srcType, srcProjectId);
523
+ const contentSourceId = (0, content_store_utils_1.getContentSourceId)(srcType, srcProjectId);
510
524
  const contentSourceData = this.getContentSourceDataByIdOrThrow(contentSourceId);
511
- assets = mapStoreAssetsToAPIAssets(contentSourceData.assets, contentSourceData.defaultLocaleCode);
525
+ assets = (0, store_to_api_docs_converter_1.mapStoreAssetsToAPIAssets)(contentSourceData.assets, contentSourceData.defaultLocaleCode);
512
526
  }
513
527
  else {
514
528
  assets = lodash_1.default.reduce(this.contentSourceDataById, (result, contentSourceData) => {
515
- const assets = mapStoreAssetsToAPIAssets(contentSourceData.assets, contentSourceData.defaultLocaleCode);
529
+ const assets = (0, store_to_api_docs_converter_1.mapStoreAssetsToAPIAssets)(contentSourceData.assets, contentSourceData.defaultLocaleCode);
516
530
  return result.concat(assets);
517
531
  }, []);
518
532
  }
@@ -534,7 +548,7 @@ class ContentStore {
534
548
  }
535
549
  async createAndLinkDocument({ srcType, srcProjectId, srcDocumentId, fieldPath, modelName, object, index, locale, user }) {
536
550
  this.logger.debug('createAndLinkDocument', { srcType, srcProjectId, srcDocumentId, fieldPath, modelName, index, locale });
537
- const contentSourceId = getContentSourceId(srcType, srcProjectId);
551
+ const contentSourceId = (0, content_store_utils_1.getContentSourceId)(srcType, srcProjectId);
538
552
  const contentSourceData = this.getContentSourceDataByIdOrThrow(contentSourceId);
539
553
  // get the document that is being updated
540
554
  const document = contentSourceData.documentMap[srcDocumentId];
@@ -551,7 +565,7 @@ class ContentStore {
551
565
  }
552
566
  // get the 'reference' model field in the updated document that will be used to link the new document
553
567
  locale = locale !== null && locale !== void 0 ? locale : contentSourceData.defaultLocaleCode;
554
- const modelField = getModelFieldForFieldAtPath(document, model, fieldPath, csiModelMap, locale);
568
+ const modelField = (0, content_store_utils_1.getModelFieldForFieldAtPath)(document, model, fieldPath, csiModelMap, locale);
555
569
  if (!modelField) {
556
570
  throw Error(`the "fieldPath" points to non existing model field: ${fieldPath.join('.')}`);
557
571
  }
@@ -576,7 +590,7 @@ class ContentStore {
576
590
  user: user
577
591
  });
578
592
  // update the document by linking the field to the created document
579
- const userContext = getUserContextForSrcType(srcType, user);
593
+ const userContext = (0, content_store_utils_1.getUserContextForSrcType)(srcType, user);
580
594
  const field = {
581
595
  type: 'reference',
582
596
  refType: 'document',
@@ -610,7 +624,7 @@ class ContentStore {
610
624
  async uploadAndLinkAsset({ srcType, srcProjectId, srcDocumentId, fieldPath, asset, index, locale, user }) {
611
625
  this.logger.debug('uploadAndLinkAsset', { srcType, srcProjectId, srcDocumentId, fieldPath, index, locale });
612
626
  // get the document that is being updated
613
- const contentSourceId = getContentSourceId(srcType, srcProjectId);
627
+ const contentSourceId = (0, content_store_utils_1.getContentSourceId)(srcType, srcProjectId);
614
628
  const contentSourceData = this.getContentSourceDataByIdOrThrow(contentSourceId);
615
629
  const document = contentSourceData.documentMap[srcDocumentId];
616
630
  const csiDocument = contentSourceData.csiDocumentMap[srcDocumentId];
@@ -626,7 +640,7 @@ class ContentStore {
626
640
  }
627
641
  // get the 'reference' model field in the updated document that will be used to link the new asset
628
642
  locale = locale !== null && locale !== void 0 ? locale : contentSourceData.defaultLocaleCode;
629
- const modelField = getModelFieldForFieldAtPath(document, csiModel, fieldPath, csiModelMap, locale);
643
+ const modelField = (0, content_store_utils_1.getModelFieldForFieldAtPath)(document, csiModel, fieldPath, csiModelMap, locale);
630
644
  if (!modelField) {
631
645
  throw Error(`the "fieldPath" points to non existing model field: ${fieldPath.join('.')}`);
632
646
  }
@@ -635,7 +649,7 @@ class ContentStore {
635
649
  throw Error(`error in "uploadAndLinkAsset", this operation can only be used on reference and image fields: ${fieldPath.join('.')}`);
636
650
  }
637
651
  // upload the new asset
638
- const userContext = getUserContextForSrcType(srcType, user);
652
+ const userContext = (0, content_store_utils_1.getUserContextForSrcType)(srcType, user);
639
653
  const result = await contentSourceData.instance.uploadAsset({
640
654
  url: asset.url,
641
655
  fileName: asset.metadata.name,
@@ -676,22 +690,22 @@ class ContentStore {
676
690
  }
677
691
  async createDocument({ srcType, srcProjectId, modelName, object, locale, user }) {
678
692
  this.logger.debug('createDocument', { srcType, srcProjectId, modelName, locale });
679
- const contentSourceId = getContentSourceId(srcType, srcProjectId);
693
+ const contentSourceId = (0, content_store_utils_1.getContentSourceId)(srcType, srcProjectId);
680
694
  const contentSourceData = this.getContentSourceDataByIdOrThrow(contentSourceId);
681
695
  const modelMap = contentSourceData.modelMap;
682
- const model = modelMap[modelName];
683
- if (!model) {
684
- throw new Error(`no model with name '${modelName}' was found`);
685
- }
686
- locale = locale !== null && locale !== void 0 ? locale : contentSourceData.defaultLocaleCode;
687
- const userContext = getUserContextForSrcType(srcType, user);
688
- const result = await createDocumentRecursively({
696
+ const csiModelMap = contentSourceData.csiModelMap;
697
+ const userContext = (0, content_store_utils_1.getUserContextForSrcType)(srcType, user);
698
+ const resolvedLocale = locale !== null && locale !== void 0 ? locale : contentSourceData.defaultLocaleCode;
699
+ const result = await (0, create_update_csi_docs_1.createDocumentRecursively)({
689
700
  object,
690
- model,
701
+ modelName,
691
702
  modelMap,
692
- locale,
693
- userContext,
694
- contentSourceInstance: contentSourceData.instance
703
+ createDocument: (0, create_update_csi_docs_1.getCreateDocumentThunk)({
704
+ locale: resolvedLocale,
705
+ csiModelMap,
706
+ userContext,
707
+ contentSourceInstance: contentSourceData.instance
708
+ })
695
709
  });
696
710
  this.logger.debug('created document', { srcType, srcProjectId, srcDocumentId: result.document.id, modelName });
697
711
  // do not update cache in contentSourceData.documents and documentMap,
@@ -703,9 +717,9 @@ class ContentStore {
703
717
  }
704
718
  async updateDocument({ srcType, srcProjectId, srcDocumentId, updateOperations, user }) {
705
719
  this.logger.debug('updateDocument');
706
- const contentSourceId = getContentSourceId(srcType, srcProjectId);
720
+ const contentSourceId = (0, content_store_utils_1.getContentSourceId)(srcType, srcProjectId);
707
721
  const contentSourceData = this.getContentSourceDataByIdOrThrow(contentSourceId);
708
- const userContext = getUserContextForSrcType(srcType, user);
722
+ const userContext = (0, content_store_utils_1.getUserContextForSrcType)(srcType, user);
709
723
  const document = contentSourceData.documentMap[srcDocumentId];
710
724
  const csiDocument = contentSourceData.csiDocumentMap[srcDocumentId];
711
725
  if (!document || !csiDocument) {
@@ -721,17 +735,20 @@ class ContentStore {
721
735
  const operations = await (0, utils_1.mapPromise)(updateOperations, async (updateOperation) => {
722
736
  var _a;
723
737
  const locale = (_a = updateOperation.locale) !== null && _a !== void 0 ? _a : contentSourceData.defaultLocaleCode;
724
- const modelField = getModelFieldForFieldAtPath(document, model, updateOperation.fieldPath, modelMap, locale);
738
+ const modelField = (0, content_store_utils_1.getModelFieldForFieldAtPath)(document, model, updateOperation.fieldPath, modelMap, locale);
725
739
  switch (updateOperation.opType) {
726
740
  case 'set':
727
- const field = await convertOperationField({
741
+ const field = await (0, create_update_csi_docs_1.convertOperationField)({
728
742
  operationField: updateOperation.field,
729
743
  fieldPath: updateOperation.fieldPath,
730
- locale: updateOperation.locale,
731
744
  modelField,
732
745
  modelMap,
733
- userContext,
734
- contentSourceInstance: contentSourceData.instance
746
+ createDocument: (0, create_update_csi_docs_1.getCreateDocumentThunk)({
747
+ locale: updateOperation.locale,
748
+ csiModelMap,
749
+ userContext,
750
+ contentSourceInstance: contentSourceData.instance
751
+ })
735
752
  });
736
753
  return {
737
754
  ...updateOperation,
@@ -741,14 +758,17 @@ class ContentStore {
741
758
  case 'unset':
742
759
  return { ...updateOperation, modelField };
743
760
  case 'insert':
744
- const item = await convertOperationField({
761
+ const item = await (0, create_update_csi_docs_1.convertOperationField)({
745
762
  operationField: updateOperation.item,
746
763
  fieldPath: updateOperation.fieldPath,
747
- locale: updateOperation.locale,
748
764
  modelField,
749
765
  modelMap,
750
- userContext,
751
- contentSourceInstance: contentSourceData.instance
766
+ createDocument: (0, create_update_csi_docs_1.getCreateDocumentThunk)({
767
+ locale: updateOperation.locale,
768
+ csiModelMap,
769
+ userContext,
770
+ contentSourceInstance: contentSourceData.instance
771
+ })
752
772
  });
753
773
  return {
754
774
  ...updateOperation,
@@ -775,22 +795,24 @@ class ContentStore {
775
795
  }
776
796
  async duplicateDocument({ srcType, srcProjectId, srcDocumentId, object, user }) {
777
797
  this.logger.debug('duplicateDocument');
778
- const contentSourceId = getContentSourceId(srcType, srcProjectId);
798
+ const contentSourceId = (0, content_store_utils_1.getContentSourceId)(srcType, srcProjectId);
779
799
  const contentSourceData = this.getContentSourceDataByIdOrThrow(contentSourceId);
780
800
  const document = contentSourceData.documentMap[srcDocumentId];
781
801
  if (!document) {
782
802
  throw new Error(`no document with id '${srcDocumentId}' was found in ${contentSourceData.id}`);
783
803
  }
784
804
  const modelMap = contentSourceData.modelMap;
805
+ const csiModelMap = contentSourceData.csiModelMap;
785
806
  const model = modelMap[document.srcModelName];
786
- if (!model) {
807
+ const csiModel = csiModelMap[document.srcModelName];
808
+ if (!model || !csiModel) {
787
809
  throw new Error(`no model with name '${document.srcModelName}' was found`);
788
810
  }
789
- const userContext = getUserContextForSrcType(srcType, user);
811
+ const userContext = (0, content_store_utils_1.getUserContextForSrcType)(srcType, user);
790
812
  // TODO: take the data from the provided 'object' and merge them with
791
813
  // DocumentFields of the existing Document:
792
814
  // Option 1: Map the DocumentFields of the existing Document into flat
793
- // object with '$$ref' and '$type' properties for references and
815
+ // object with '$$ref' and '$$type' properties for references and
794
816
  // nested objects (needs to be implemented), and then merge it with
795
817
  // the provided object recursively, and then pass that object to
796
818
  // createNestedObjectRecursively()
@@ -806,12 +828,14 @@ class ContentStore {
806
828
  modelFields: model.fields,
807
829
  modelMap: contentSourceData.modelMap
808
830
  });
831
+ // When passing model and modelMap to contentSourceInstance, we have to pass
832
+ // the original models (i.e., csiModel and csiModelMap) that we've received
833
+ // from that contentSourceInstance. We can't pass internal models as they
834
+ // might
809
835
  const documentResult = await contentSourceData.instance.createDocument({
810
836
  updateOperationFields,
811
- // TODO: pass csiModel
812
- model,
813
- // TODO: pass csiModelMap
814
- modelMap,
837
+ model: csiModel,
838
+ modelMap: csiModelMap,
815
839
  locale: contentSourceData.defaultLocaleCode,
816
840
  userContext
817
841
  });
@@ -819,10 +843,10 @@ class ContentStore {
819
843
  }
820
844
  async uploadAssets({ srcType, srcProjectId, assets, locale, user }) {
821
845
  this.logger.debug('uploadAssets');
822
- const contentSourceId = getContentSourceId(srcType, srcProjectId);
846
+ const contentSourceId = (0, content_store_utils_1.getContentSourceId)(srcType, srcProjectId);
823
847
  const contentSourceData = this.getContentSourceDataByIdOrThrow(contentSourceId);
824
848
  const sourceAssets = [];
825
- const userContext = getUserContextForSrcType(srcType, user);
849
+ const userContext = (0, content_store_utils_1.getUserContextForSrcType)(srcType, user);
826
850
  locale = locale !== null && locale !== void 0 ? locale : contentSourceData.defaultLocaleCode;
827
851
  for (const asset of assets) {
828
852
  let base64 = undefined;
@@ -842,17 +866,17 @@ class ContentStore {
842
866
  });
843
867
  sourceAssets.push(sourceAsset);
844
868
  }
845
- const storeAssets = mapCSIAssetsToStoreAssets({
869
+ const storeAssets = (0, csi_to_store_docs_converter_1.mapCSIAssetsToStoreAssets)({
846
870
  csiAssets: sourceAssets,
847
871
  contentSourceInstance: contentSourceData.instance,
848
872
  defaultLocaleCode: contentSourceData.defaultLocaleCode
849
873
  });
850
- return mapStoreAssetsToAPIAssets(storeAssets, locale);
874
+ return (0, store_to_api_docs_converter_1.mapStoreAssetsToAPIAssets)(storeAssets, locale);
851
875
  }
852
876
  async deleteDocument({ srcType, srcProjectId, srcDocumentId, user }) {
853
877
  this.logger.debug('deleteDocument');
854
- const userContext = getUserContextForSrcType(srcType, user);
855
- const contentSourceId = getContentSourceId(srcType, srcProjectId);
878
+ const userContext = (0, content_store_utils_1.getUserContextForSrcType)(srcType, user);
879
+ const contentSourceId = (0, content_store_utils_1.getContentSourceId)(srcType, srcProjectId);
856
880
  const contentSourceData = this.getContentSourceDataByIdOrThrow(contentSourceId);
857
881
  const csiDocument = contentSourceData.csiDocumentMap[srcDocumentId];
858
882
  if (!csiDocument) {
@@ -866,13 +890,13 @@ class ContentStore {
866
890
  }
867
891
  async validateDocuments({ objects, locale, user }) {
868
892
  this.logger.debug('validateDocuments');
869
- const objectsBySourceId = lodash_1.default.groupBy(objects, (object) => getContentSourceId(object.srcType, object.srcProjectId));
893
+ const objectsBySourceId = lodash_1.default.groupBy(objects, (object) => (0, content_store_utils_1.getContentSourceId)(object.srcType, object.srcProjectId));
870
894
  let errors = [];
871
895
  for (const [contentSourceId, contentSourceObjects] of Object.entries(objectsBySourceId)) {
872
896
  const contentSourceData = this.getContentSourceDataByIdOrThrow(contentSourceId);
873
897
  locale = locale !== null && locale !== void 0 ? locale : contentSourceData.defaultLocaleCode;
874
898
  const { documents, assets } = getCSIDocumentsAndAssetsFromContentSourceDataByIds(contentSourceData, contentSourceObjects);
875
- const userContext = getUserContextForSrcType(contentSourceData.type, user);
899
+ const userContext = (0, content_store_utils_1.getUserContextForSrcType)(contentSourceData.type, user);
876
900
  const internalValidationErrors = internalValidateContent(documents, assets, contentSourceData);
877
901
  const validationResult = await contentSourceData.instance.validateDocuments({ documents, assets, locale, userContext });
878
902
  errors = errors.concat(internalValidationErrors, validationResult.errors.map((validationError) => ({
@@ -903,10 +927,10 @@ class ContentStore {
903
927
  }
904
928
  async publishDocuments({ objects, user }) {
905
929
  this.logger.debug('publishDocuments');
906
- const objectsBySourceId = lodash_1.default.groupBy(objects, (object) => getContentSourceId(object.srcType, object.srcProjectId));
930
+ const objectsBySourceId = lodash_1.default.groupBy(objects, (object) => (0, content_store_utils_1.getContentSourceId)(object.srcType, object.srcProjectId));
907
931
  for (const [contentSourceId, contentSourceObjects] of Object.entries(objectsBySourceId)) {
908
932
  const contentSourceData = this.getContentSourceDataByIdOrThrow(contentSourceId);
909
- const userContext = getUserContextForSrcType(contentSourceData.type, user);
933
+ const userContext = (0, content_store_utils_1.getUserContextForSrcType)(contentSourceData.type, user);
910
934
  const { documents, assets } = getCSIDocumentsAndAssetsFromContentSourceDataByIds(contentSourceData, contentSourceObjects);
911
935
  await contentSourceData.instance.publishDocuments({ documents, assets, userContext });
912
936
  }
@@ -920,880 +944,10 @@ class ContentStore {
920
944
  }
921
945
  }
922
946
  exports.ContentStore = ContentStore;
923
- function getContentSourceId(contentSourceType, srcProjectId) {
924
- return contentSourceType + ':' + srcProjectId;
925
- }
926
- exports.getContentSourceId = getContentSourceId;
927
- function getUserContextForSrcType(srcType, user) {
928
- var _a;
929
- return (_a = user === null || user === void 0 ? void 0 : user.connections) === null || _a === void 0 ? void 0 : _a.find((connection) => connection.type === srcType);
930
- }
931
- function mapCSIAssetsToStoreAssets({ csiAssets, contentSourceInstance, defaultLocaleCode }) {
932
- const extra = {
933
- srcType: contentSourceInstance.getContentSourceType(),
934
- srcProjectId: contentSourceInstance.getProjectId(),
935
- srcProjectUrl: contentSourceInstance.getProjectManageUrl(),
936
- srcEnvironment: contentSourceInstance.getProjectEnvironment()
937
- };
938
- return csiAssets.map((csiAsset) => sourceAssetToStoreAsset({ csiAsset, defaultLocaleCode, extra }));
939
- }
940
- function sourceAssetToStoreAsset({ csiAsset, defaultLocaleCode, extra }) {
941
- return {
942
- type: 'asset',
943
- ...extra,
944
- srcObjectId: csiAsset.id,
945
- srcObjectUrl: csiAsset.manageUrl,
946
- srcObjectLabel: getObjectLabel(csiAsset.fields, common_schema_1.IMAGE_MODEL, defaultLocaleCode),
947
- srcModelName: common_schema_1.IMAGE_MODEL.name,
948
- srcModelLabel: common_schema_1.IMAGE_MODEL.label,
949
- isChanged: csiAsset.status === 'added' || csiAsset.status === 'modified',
950
- status: csiAsset.status,
951
- createdAt: csiAsset.createdAt,
952
- createdBy: csiAsset.createdBy,
953
- updatedAt: csiAsset.updatedAt,
954
- updatedBy: csiAsset.updatedBy,
955
- fields: {
956
- title: {
957
- label: 'Title',
958
- ...csiAsset.fields.title
959
- },
960
- file: {
961
- label: 'File',
962
- ...csiAsset.fields.file
963
- }
964
- }
965
- };
966
- }
967
- function mapCSIDocumentsToStoreDocuments({ csiDocuments, contentSourceInstance, modelMap, defaultLocaleCode }) {
968
- const extra = {
969
- srcType: contentSourceInstance.getContentSourceType(),
970
- srcProjectId: contentSourceInstance.getProjectId(),
971
- srcProjectUrl: contentSourceInstance.getProjectManageUrl(),
972
- srcEnvironment: contentSourceInstance.getProjectEnvironment()
973
- };
974
- return csiDocuments.map((csiDocument) => mapCSIDocumentToStoreDocument({ csiDocument, model: modelMap[csiDocument.modelName], modelMap, defaultLocaleCode, extra }));
975
- }
976
- function mapCSIDocumentToStoreDocument({ csiDocument, model, modelMap, defaultLocaleCode, extra }) {
977
- var _a, _b;
978
- return {
979
- type: 'document',
980
- ...extra,
981
- srcObjectId: csiDocument.id,
982
- srcObjectUrl: csiDocument.manageUrl,
983
- srcObjectLabel: getObjectLabel(csiDocument.fields, model, defaultLocaleCode),
984
- srcModelLabel: (_a = model.label) !== null && _a !== void 0 ? _a : lodash_1.default.startCase(csiDocument.modelName),
985
- srcModelName: csiDocument.modelName,
986
- isChanged: csiDocument.status === 'added' || csiDocument.status === 'modified',
987
- status: csiDocument.status,
988
- createdAt: csiDocument.createdAt,
989
- createdBy: csiDocument.createdBy,
990
- updatedAt: csiDocument.updatedAt,
991
- updatedBy: csiDocument.updatedBy,
992
- fields: mapCSIFieldsToStoreFields({
993
- csiDocumentFields: csiDocument.fields,
994
- modelFields: (_b = model.fields) !== null && _b !== void 0 ? _b : [],
995
- context: {
996
- modelMap,
997
- defaultLocaleCode
998
- }
999
- })
1000
- };
1001
- }
1002
- function mapCSIFieldsToStoreFields({ csiDocumentFields, modelFields, context }) {
1003
- return modelFields.reduce((result, modelField) => {
1004
- const csiDocumentField = csiDocumentFields[modelField.name];
1005
- const docField = mapCSIFieldToStoreField({
1006
- csiDocumentField,
1007
- modelField,
1008
- context
1009
- });
1010
- docField.label = modelField.label;
1011
- result[modelField.name] = docField;
1012
- return result;
1013
- }, {});
1014
- }
1015
- function mapCSIFieldToStoreField({ csiDocumentField, modelField, context }) {
1016
- if (!csiDocumentField) {
1017
- const isUnset = ['object', 'model', 'reference', 'richText', 'markdown', 'image', 'file', 'json'].includes(modelField.type);
1018
- return {
1019
- type: modelField.type,
1020
- ...(isUnset ? { isUnset } : null),
1021
- ...(modelField.type === 'list' ? { items: [] } : null)
1022
- };
1023
- }
1024
- // TODO: check if need to add "options" to "enum" and subtype/min/max to "number"
1025
- switch (modelField.type) {
1026
- case 'object':
1027
- return mapObjectField(csiDocumentField, modelField, context);
1028
- case 'model':
1029
- return mapModelField(csiDocumentField, modelField, context);
1030
- case 'list':
1031
- return mapListField(csiDocumentField, modelField, context);
1032
- case 'richText':
1033
- return mapRichTextField(csiDocumentField);
1034
- case 'markdown':
1035
- return mapMarkdownField(csiDocumentField);
1036
- default:
1037
- return csiDocumentField;
1038
- }
1039
- }
1040
- function mapObjectField(csiDocumentField, modelField, context) {
1041
- var _a, _b, _c;
1042
- if (!(0, content_source_interface_1.isLocalizedField)(csiDocumentField)) {
1043
- return {
1044
- type: csiDocumentField.type,
1045
- srcObjectLabel: getObjectLabel((_a = csiDocumentField.fields) !== null && _a !== void 0 ? _a : {}, modelField !== null && modelField !== void 0 ? modelField : [], context.defaultLocaleCode),
1046
- fields: mapCSIFieldsToStoreFields({
1047
- csiDocumentFields: (_b = csiDocumentField.fields) !== null && _b !== void 0 ? _b : {},
1048
- modelFields: (_c = modelField.fields) !== null && _c !== void 0 ? _c : [],
1049
- context
1050
- })
1051
- };
1052
- }
1053
- return {
1054
- type: csiDocumentField.type,
1055
- localized: true,
1056
- locales: lodash_1.default.mapValues(csiDocumentField.locales, (locale) => {
1057
- var _a, _b, _c;
1058
- return {
1059
- locale: locale.locale,
1060
- srcObjectLabel: getObjectLabel((_a = locale.fields) !== null && _a !== void 0 ? _a : {}, modelField, locale.locale),
1061
- fields: mapCSIFieldsToStoreFields({
1062
- csiDocumentFields: (_b = locale.fields) !== null && _b !== void 0 ? _b : {},
1063
- modelFields: (_c = modelField.fields) !== null && _c !== void 0 ? _c : [],
1064
- context
1065
- })
1066
- };
1067
- })
1068
- };
1069
- }
1070
- function mapModelField(csiDocumentField, modelField, context) {
1071
- var _a, _b, _c, _d;
1072
- if (!(0, content_source_interface_1.isLocalizedField)(csiDocumentField)) {
1073
- const model = context.modelMap[csiDocumentField.modelName];
1074
- return {
1075
- type: csiDocumentField.type,
1076
- srcObjectLabel: getObjectLabel((_a = csiDocumentField.fields) !== null && _a !== void 0 ? _a : {}, model, context.defaultLocaleCode),
1077
- srcModelName: csiDocumentField.modelName,
1078
- srcModelLabel: (_b = model.label) !== null && _b !== void 0 ? _b : lodash_1.default.startCase(model.name),
1079
- fields: mapCSIFieldsToStoreFields({
1080
- csiDocumentFields: (_c = csiDocumentField.fields) !== null && _c !== void 0 ? _c : {},
1081
- modelFields: (_d = model.fields) !== null && _d !== void 0 ? _d : [],
1082
- context
1083
- })
1084
- };
1085
- }
1086
- return {
1087
- type: csiDocumentField.type,
1088
- localized: true,
1089
- locales: lodash_1.default.mapValues(csiDocumentField.locales, (locale) => {
1090
- var _a, _b, _c, _d;
1091
- const model = context.modelMap[locale.modelName];
1092
- return {
1093
- locale: locale.locale,
1094
- srcObjectLabel: getObjectLabel((_a = locale.fields) !== null && _a !== void 0 ? _a : {}, model, locale.locale),
1095
- srcModelName: locale.modelName,
1096
- srcModelLabel: (_b = model.label) !== null && _b !== void 0 ? _b : lodash_1.default.startCase(model.name),
1097
- fields: mapCSIFieldsToStoreFields({
1098
- csiDocumentFields: (_c = locale.fields) !== null && _c !== void 0 ? _c : {},
1099
- modelFields: (_d = model.fields) !== null && _d !== void 0 ? _d : [],
1100
- context
1101
- })
1102
- };
1103
- })
1104
- };
1105
- }
1106
- function mapListField(csiDocumentField, modelField, context) {
1107
- if (!(0, content_source_interface_1.isLocalizedField)(csiDocumentField)) {
1108
- return {
1109
- type: csiDocumentField.type,
1110
- items: csiDocumentField.items.map((item) => {
1111
- var _a;
1112
- return mapCSIFieldToStoreField({
1113
- csiDocumentField: item,
1114
- modelField: (_a = modelField.items) !== null && _a !== void 0 ? _a : { type: 'string' },
1115
- context
1116
- });
1117
- })
1118
- };
1119
- }
1120
- return {
1121
- type: csiDocumentField.type,
1122
- localized: true,
1123
- locales: lodash_1.default.mapValues(csiDocumentField.locales, (locale) => {
1124
- var _a;
1125
- return {
1126
- locale: locale.locale,
1127
- items: ((_a = locale.items) !== null && _a !== void 0 ? _a : []).map((item) => {
1128
- var _a;
1129
- return mapCSIFieldToStoreField({
1130
- csiDocumentField: item,
1131
- modelField: (_a = modelField.items) !== null && _a !== void 0 ? _a : { type: 'string' },
1132
- context
1133
- });
1134
- })
1135
- };
1136
- })
1137
- };
1138
- }
1139
- function mapRichTextField(csiDocumentField) {
1140
- if (!(0, content_source_interface_1.isLocalizedField)(csiDocumentField)) {
1141
- return {
1142
- ...csiDocumentField,
1143
- multiElement: true
1144
- };
1145
- }
1146
- return {
1147
- type: csiDocumentField.type,
1148
- localized: true,
1149
- locales: lodash_1.default.mapValues(csiDocumentField.locales, (locale) => {
1150
- return {
1151
- ...locale,
1152
- multiElement: true
1153
- };
1154
- })
1155
- };
1156
- }
1157
- function mapMarkdownField(csiDocumentField) {
1158
- if (!(0, content_source_interface_1.isLocalizedField)(csiDocumentField)) {
1159
- return {
1160
- type: 'markdown',
1161
- value: csiDocumentField.value,
1162
- multiElement: true
1163
- };
1164
- }
1165
- return {
1166
- type: 'markdown',
1167
- localized: true,
1168
- locales: lodash_1.default.mapValues(csiDocumentField.locales, (locale) => {
1169
- return {
1170
- ...locale,
1171
- multiElement: true
1172
- };
1173
- })
1174
- };
1175
- }
1176
947
  function mapStoreFieldsToOperationFields({ documentFields, modelFields, modelMap }) {
1177
948
  // TODO: implement
1178
949
  throw new Error(`duplicateDocument not implemented yet`);
1179
950
  }
1180
- function getContentSourceIdForContentSource(contentSource) {
1181
- return getContentSourceId(contentSource.getContentSourceType(), contentSource.getProjectId());
1182
- }
1183
- function extractTokensFromString(input) {
1184
- return input.match(/(?<={)[^}]+(?=})/g) || [];
1185
- }
1186
- function sanitizeSlug(slug) {
1187
- return slug
1188
- .split('/')
1189
- .map((part) => (0, slugify_1.default)(part, { lower: true }))
1190
- .join('/');
1191
- }
1192
- function getObjectLabel(documentFields, modelOrObjectField, locale) {
1193
- const labelField = modelOrObjectField.labelField;
1194
- let label = null;
1195
- if (labelField) {
1196
- const field = lodash_1.default.get(documentFields, labelField, null);
1197
- if (field && ['string', 'url', 'slug', 'text', 'markdown', 'number', 'enum', 'date', 'datetime', 'color', 'image', 'file'].includes(field.type)) {
1198
- if ((0, content_source_interface_1.isLocalizedField)(field) && locale) {
1199
- label = lodash_1.default.get(field, ['locales', locale, 'value'], null);
1200
- }
1201
- else if (!(0, content_source_interface_1.isLocalizedField)(field)) {
1202
- label = lodash_1.default.get(field, 'value', null);
1203
- }
1204
- }
1205
- }
1206
- if (!label) {
1207
- label = lodash_1.default.get(modelOrObjectField, 'label');
1208
- }
1209
- if (!label && lodash_1.default.has(modelOrObjectField, 'name')) {
1210
- label = lodash_1.default.startCase(lodash_1.default.get(modelOrObjectField, 'name'));
1211
- }
1212
- return label;
1213
- }
1214
- function mapDocumentsToLocalizedApiObjects(documents, locale) {
1215
- return documents.map((document) => documentToLocalizedApiObject(document, locale));
1216
- }
1217
- function documentToLocalizedApiObject(document, locale) {
1218
- const { type, fields, ...rest } = document;
1219
- return {
1220
- type: 'object',
1221
- ...rest,
1222
- fields: toLocalizedAPIFields(fields, locale)
1223
- };
1224
- }
1225
- function toLocalizedAPIFields(docFields, locale) {
1226
- return lodash_1.default.mapValues(docFields, (docField) => toLocalizedAPIField(docField, locale));
1227
- }
1228
- function toLocalizedAPIField(docField, locale, isListItem = false) {
1229
- const hasUnsetFlag = ['object', 'model', 'reference', 'richText', 'markdown', 'image', 'file', 'json'].includes(docField.type);
1230
- let docFieldLocalized;
1231
- let unset = false;
1232
- if (docField.localized) {
1233
- const { locales, localized, ...base } = docField;
1234
- const localeProps = locale ? locales[locale] : undefined;
1235
- docFieldLocalized = {
1236
- ...base,
1237
- ...localeProps,
1238
- ...(hasUnsetFlag && !localeProps ? { isUnset: true } : null)
1239
- };
1240
- }
1241
- else {
1242
- docFieldLocalized = docField;
1243
- }
1244
- locale = locale !== null && locale !== void 0 ? locale : docFieldLocalized.locale;
1245
- const commonProps = isListItem
1246
- ? null
1247
- : {
1248
- localized: !!docField.localized,
1249
- ...(locale ? { locale } : null)
1250
- };
1251
- if (docFieldLocalized.type === 'object' || docFieldLocalized.type === 'model') {
1252
- return {
1253
- ...docFieldLocalized,
1254
- type: 'object',
1255
- ...commonProps,
1256
- ...(docFieldLocalized.isUnset
1257
- ? null
1258
- : {
1259
- fields: toLocalizedAPIFields(docFieldLocalized.fields, locale)
1260
- })
1261
- };
1262
- }
1263
- else if (docFieldLocalized.type === 'reference') {
1264
- const { type, refType, ...rest } = docFieldLocalized;
1265
- // if reference field isUnset === true, it behaves like a regular object
1266
- if (rest.isUnset) {
1267
- return {
1268
- type: 'object',
1269
- ...rest,
1270
- ...commonProps
1271
- };
1272
- }
1273
- return {
1274
- type: 'unresolved_reference',
1275
- refType: refType === 'asset' ? 'image' : 'object',
1276
- ...rest,
1277
- ...commonProps
1278
- };
1279
- }
1280
- else if (docFieldLocalized.type === 'list') {
1281
- const { items, ...rest } = docFieldLocalized;
1282
- return {
1283
- ...rest,
1284
- ...commonProps,
1285
- items: items.map((field) => toLocalizedAPIField(field, locale, true))
1286
- };
1287
- }
1288
- else {
1289
- return {
1290
- ...docFieldLocalized,
1291
- ...commonProps
1292
- };
1293
- }
1294
- }
1295
- function mapAssetsToLocalizedApiImages(assets, locale) {
1296
- return assets.map((asset) => assetToLocalizedApiImage(asset, locale));
1297
- }
1298
- function assetToLocalizedApiImage(asset, locale) {
1299
- const { type, fields, ...rest } = asset;
1300
- return {
1301
- type: 'image',
1302
- ...rest,
1303
- fields: localizeAssetFields(fields, locale)
1304
- };
1305
- }
1306
- function localizeAssetFields(assetFields, locale) {
1307
- var _a, _b;
1308
- const fields = {
1309
- title: {
1310
- type: 'string',
1311
- value: null
1312
- },
1313
- url: {
1314
- type: 'string',
1315
- value: null
1316
- }
1317
- };
1318
- const titleFieldNonLocalized = getDocumentFieldForLocale(assetFields.title, locale);
1319
- fields.title.value = titleFieldNonLocalized === null || titleFieldNonLocalized === void 0 ? void 0 : titleFieldNonLocalized.value;
1320
- fields.title.locale = locale !== null && locale !== void 0 ? locale : titleFieldNonLocalized === null || titleFieldNonLocalized === void 0 ? void 0 : titleFieldNonLocalized.locale;
1321
- const assetFileField = assetFields.file;
1322
- if (assetFileField.localized) {
1323
- if (locale) {
1324
- fields.url.value = (_b = (_a = assetFileField.locales[locale]) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : null;
1325
- fields.url.locale = locale;
1326
- }
1327
- }
1328
- else {
1329
- fields.url.value = assetFileField.url;
1330
- fields.url.locale = assetFileField.locale;
1331
- }
1332
- return fields;
1333
- }
1334
- function mapStoreAssetsToAPIAssets(assets, locale) {
1335
- return assets.map((asset) => storeAssetToAPIAsset(asset, locale));
1336
- }
1337
- function storeAssetToAPIAsset(asset, locale) {
1338
- var _a, _b;
1339
- const assetTitleField = asset.fields.title;
1340
- const localizedTitleField = assetTitleField.localized ? assetTitleField.locales[locale] : assetTitleField;
1341
- const assetFileField = asset.fields.file;
1342
- const localizedFileField = assetFileField.localized ? assetFileField.locales[locale] : assetFileField;
1343
- return {
1344
- objectId: asset.srcObjectId,
1345
- createdAt: asset.createdAt,
1346
- url: localizedFileField.url,
1347
- ...(0, utils_1.omitByNil)({
1348
- title: localizedTitleField.value,
1349
- fileName: localizedFileField.fileName,
1350
- contentType: localizedFileField.contentType,
1351
- size: localizedFileField.size,
1352
- width: (_a = localizedFileField.dimensions) === null || _a === void 0 ? void 0 : _a.width,
1353
- height: (_b = localizedFileField.dimensions) === null || _b === void 0 ? void 0 : _b.height
1354
- })
1355
- };
1356
- }
1357
- /**
1358
- * Iterates recursively objects with $$type and $$ref, creating nested objects
1359
- * as needed and returns standard ContentSourceInterface Documents
1360
- */
1361
- async function createDocumentRecursively({ object, model, modelMap, locale, userContext, contentSourceInstance }) {
1362
- var _a;
1363
- if (model.type === 'page') {
1364
- const tokens = extractTokensFromString(String(model.urlPath));
1365
- const slugField = lodash_1.default.last(tokens);
1366
- if (object && slugField && slugField in object) {
1367
- const slugFieldValue = object[slugField];
1368
- object[slugField] = sanitizeSlug(slugFieldValue);
1369
- }
1370
- }
1371
- const nestedResult = await createNestedObjectRecursively({
1372
- object,
1373
- modelFields: (_a = model.fields) !== null && _a !== void 0 ? _a : [],
1374
- fieldPath: [],
1375
- modelMap,
1376
- locale,
1377
- userContext,
1378
- contentSourceInstance
1379
- });
1380
- const document = await contentSourceInstance.createDocument({
1381
- updateOperationFields: nestedResult.fields,
1382
- // TODO: pass csiModel
1383
- model,
1384
- // TODO: pass csiModelMap
1385
- modelMap,
1386
- locale,
1387
- userContext
1388
- });
1389
- return {
1390
- document: document,
1391
- newRefDocuments: nestedResult.newRefDocuments
1392
- };
1393
- }
1394
- async function createNestedObjectRecursively({ object, modelFields, fieldPath, modelMap, locale, userContext, contentSourceInstance }) {
1395
- object = object !== null && object !== void 0 ? object : {};
1396
- const result = {
1397
- fields: {},
1398
- newRefDocuments: []
1399
- };
1400
- const objectFieldNames = Object.keys(object);
1401
- for (const modelField of modelFields) {
1402
- const fieldName = modelField.name;
1403
- let value;
1404
- if (fieldName in object) {
1405
- value = object[fieldName];
1406
- lodash_1.default.pull(objectFieldNames, fieldName);
1407
- }
1408
- else if (modelField.const) {
1409
- value = modelField.const;
1410
- }
1411
- else if (!lodash_1.default.isNil(modelField.default)) {
1412
- value = modelField.default;
1413
- }
1414
- if (!lodash_1.default.isNil(value)) {
1415
- const fieldResult = await createNestedField({
1416
- value,
1417
- modelField,
1418
- fieldPath: fieldPath.concat(fieldName),
1419
- modelMap,
1420
- locale,
1421
- userContext,
1422
- contentSourceInstance
1423
- });
1424
- result.fields[fieldName] = fieldResult.field;
1425
- result.newRefDocuments = result.newRefDocuments.concat(fieldResult.newRefDocuments);
1426
- }
1427
- }
1428
- if (objectFieldNames.length > 0) {
1429
- throw new Error(`no model fields found when creating a document with fields: '${objectFieldNames.join(', ')}'`);
1430
- }
1431
- return result;
1432
- }
1433
- async function createNestedField({ value, modelField, fieldPath, modelMap, locale, userContext, contentSourceInstance }) {
1434
- var _a;
1435
- if (modelField.type === 'object') {
1436
- const result = await createNestedObjectRecursively({
1437
- object: value,
1438
- modelFields: modelField.fields,
1439
- fieldPath,
1440
- modelMap,
1441
- locale,
1442
- userContext,
1443
- contentSourceInstance
1444
- });
1445
- return {
1446
- field: {
1447
- type: 'object',
1448
- fields: result.fields
1449
- },
1450
- newRefDocuments: result.newRefDocuments
1451
- };
1452
- }
1453
- else if (modelField.type === 'model') {
1454
- let { $$type, ...rest } = value;
1455
- const modelNames = modelField.models;
1456
- // for backward compatibility check if the object has 'type' instead of '$$type' because older projects use
1457
- // the 'type' property in default values
1458
- if (!$$type && 'type' in rest) {
1459
- $$type = rest.type;
1460
- rest = lodash_1.default.omit(rest, 'type');
1461
- }
1462
- const modelName = $$type !== null && $$type !== void 0 ? $$type : (modelNames.length === 1 ? modelNames[0] : null);
1463
- if (!modelName) {
1464
- throw new Error(`no $$type was specified for nested model`);
1465
- }
1466
- const model = modelMap[modelName];
1467
- if (!model) {
1468
- throw new Error(`no model with name '${modelName}' was found`);
1469
- }
1470
- const result = await createNestedObjectRecursively({
1471
- object: rest,
1472
- modelFields: (_a = model.fields) !== null && _a !== void 0 ? _a : [],
1473
- fieldPath,
1474
- modelMap,
1475
- locale,
1476
- userContext,
1477
- contentSourceInstance
1478
- });
1479
- return {
1480
- field: {
1481
- type: 'model',
1482
- modelName: modelName,
1483
- fields: result.fields
1484
- },
1485
- newRefDocuments: result.newRefDocuments
1486
- };
1487
- }
1488
- else if (modelField.type === 'image') {
1489
- let refId;
1490
- if (lodash_1.default.isPlainObject(value)) {
1491
- refId = value.$$ref;
1492
- }
1493
- else {
1494
- refId = value;
1495
- }
1496
- if (!refId) {
1497
- throw new Error(`reference field must specify a value`);
1498
- }
1499
- return {
1500
- field: {
1501
- type: 'reference',
1502
- refType: 'asset',
1503
- refId: refId
1504
- },
1505
- newRefDocuments: []
1506
- };
1507
- }
1508
- else if (modelField.type === 'reference') {
1509
- let { $$ref: refId = null, $$type: modelName = null, ...rest } = lodash_1.default.isPlainObject(value) ? value : { $$ref: value };
1510
- if (refId) {
1511
- return {
1512
- field: {
1513
- type: 'reference',
1514
- refType: 'document',
1515
- refId: refId
1516
- },
1517
- newRefDocuments: []
1518
- };
1519
- }
1520
- else {
1521
- const modelNames = modelField.models;
1522
- if (!modelName) {
1523
- // for backward compatibility check if the object has 'type' instead of '$$type' because older projects use
1524
- // the 'type' property in default values
1525
- if ('type' in rest) {
1526
- modelName = rest.type;
1527
- rest = lodash_1.default.omit(rest, 'type');
1528
- }
1529
- else if (modelNames.length === 1) {
1530
- modelName = modelNames[0];
1531
- }
1532
- }
1533
- const model = modelMap[modelName];
1534
- if (!model) {
1535
- throw new Error(`no model with name '${modelName}' was found`);
1536
- }
1537
- const { document, newRefDocuments } = await createDocumentRecursively({
1538
- object: rest,
1539
- model: model,
1540
- modelMap,
1541
- locale,
1542
- userContext,
1543
- contentSourceInstance
1544
- });
1545
- return {
1546
- field: {
1547
- type: 'reference',
1548
- refType: 'document',
1549
- refId: document.id
1550
- },
1551
- newRefDocuments: [document, ...newRefDocuments]
1552
- };
1553
- }
1554
- }
1555
- else if (modelField.type === 'list') {
1556
- if (!Array.isArray(value)) {
1557
- throw new Error(`value for list field must be array`);
1558
- }
1559
- const itemsField = modelField.items;
1560
- if (!itemsField) {
1561
- throw new Error(`list field does not define items`);
1562
- }
1563
- const arrayResult = await (0, utils_1.mapPromise)(value, async (item, index) => {
1564
- return createNestedField({
1565
- value: item,
1566
- modelField: itemsField,
1567
- fieldPath: fieldPath.concat(index),
1568
- modelMap,
1569
- locale,
1570
- userContext,
1571
- contentSourceInstance
1572
- });
1573
- });
1574
- return {
1575
- field: {
1576
- type: 'list',
1577
- items: arrayResult.map((result) => result.field)
1578
- },
1579
- newRefDocuments: arrayResult.reduce((result, { newRefDocuments }) => result.concat(newRefDocuments), [])
1580
- };
1581
- }
1582
- return {
1583
- field: {
1584
- type: modelField.type,
1585
- value: value
1586
- },
1587
- newRefDocuments: []
1588
- };
1589
- }
1590
- function getModelFieldForFieldAtPath(document, model, fieldPath, modelMap, locale) {
1591
- if (lodash_1.default.isEmpty(fieldPath)) {
1592
- throw new Error('the fieldPath can not be empty');
1593
- }
1594
- function getField(docField, modelField, fieldPath) {
1595
- const fieldName = lodash_1.default.head(fieldPath);
1596
- if (typeof fieldName === 'undefined') {
1597
- throw new Error('the first fieldPath item must be string');
1598
- }
1599
- const childFieldPath = lodash_1.default.tail(fieldPath);
1600
- let childDocField;
1601
- let childModelField;
1602
- switch (docField.type) {
1603
- case 'object':
1604
- const localizedObjectField = getDocumentFieldForLocale(docField, locale);
1605
- if (!localizedObjectField) {
1606
- throw new Error(`locale for field was not found`);
1607
- }
1608
- if (localizedObjectField.isUnset) {
1609
- throw new Error(`field is not set`);
1610
- }
1611
- childDocField = localizedObjectField.fields[fieldName];
1612
- childModelField = lodash_1.default.find(modelField.fields, (field) => field.name === fieldName);
1613
- if (!childDocField || !childModelField) {
1614
- throw new Error(`field ${fieldName} doesn't exist`);
1615
- }
1616
- if (childFieldPath.length === 0) {
1617
- return childModelField;
1618
- }
1619
- return getField(childDocField, childModelField, childFieldPath);
1620
- case 'model':
1621
- const localizedModelField = getDocumentFieldForLocale(docField, locale);
1622
- if (!localizedModelField) {
1623
- throw new Error(`locale for field was not found`);
1624
- }
1625
- if (localizedModelField.isUnset) {
1626
- throw new Error(`field is not set`);
1627
- }
1628
- const modelName = localizedModelField.srcModelName;
1629
- const childModel = modelMap[modelName];
1630
- if (!childModel) {
1631
- throw new Error(`model ${modelName} doesn't exist`);
1632
- }
1633
- childModelField = lodash_1.default.find(childModel.fields, (field) => field.name === fieldName);
1634
- childDocField = localizedModelField.fields[fieldName];
1635
- if (!childDocField || !childModelField) {
1636
- throw new Error(`field ${fieldName} doesn't exist`);
1637
- }
1638
- if (childFieldPath.length === 0) {
1639
- return childModelField;
1640
- }
1641
- return getField(childDocField, childModelField, childFieldPath);
1642
- case 'list':
1643
- const localizedListField = getDocumentFieldForLocale(docField, locale);
1644
- if (!localizedListField) {
1645
- throw new Error(`locale for field was not found`);
1646
- }
1647
- const listItem = localizedListField.items && localizedListField.items[fieldName];
1648
- const listItemsModel = modelField.items;
1649
- if (!listItem || !listItemsModel) {
1650
- throw new Error(`field ${fieldName} doesn't exist`);
1651
- }
1652
- if (childFieldPath.length === 0) {
1653
- return modelField;
1654
- }
1655
- if (!Array.isArray(listItemsModel)) {
1656
- return getField(listItem, listItemsModel, childFieldPath);
1657
- }
1658
- else {
1659
- const fieldListItems = listItemsModel.find((listItemsModel) => listItemsModel.type === listItem.type);
1660
- if (!fieldListItems) {
1661
- throw new Error('cannot find matching field model');
1662
- }
1663
- return getField(listItem, fieldListItems, childFieldPath);
1664
- }
1665
- default:
1666
- if (!lodash_1.default.isEmpty(childFieldPath)) {
1667
- throw new Error('illegal fieldPath');
1668
- }
1669
- return modelField;
1670
- }
1671
- }
1672
- const fieldName = lodash_1.default.head(fieldPath);
1673
- const childFieldPath = lodash_1.default.tail(fieldPath);
1674
- if (typeof fieldName !== 'string') {
1675
- throw new Error('the first fieldPath item must be string');
1676
- }
1677
- const childDocField = document.fields[fieldName];
1678
- const childModelField = lodash_1.default.find(model.fields, { name: fieldName });
1679
- if (!childDocField || !childModelField) {
1680
- throw new Error(`field ${fieldName} doesn't exist`);
1681
- }
1682
- if (childFieldPath.length === 0) {
1683
- return childModelField;
1684
- }
1685
- return getField(childDocField, childModelField, childFieldPath);
1686
- }
1687
- async function convertOperationField({ operationField, fieldPath, modelField, modelMap, locale, userContext, contentSourceInstance }) {
1688
- // for insert operations, the modelField will be of the list, so get the modelField of the list items
1689
- const modelFieldOrListItems = modelField.type === 'list' ? modelField.items : modelField;
1690
- switch (operationField.type) {
1691
- case 'object': {
1692
- const result = await createNestedObjectRecursively({
1693
- object: operationField.object,
1694
- modelFields: modelFieldOrListItems.fields,
1695
- fieldPath: fieldPath,
1696
- modelMap,
1697
- locale,
1698
- userContext,
1699
- contentSourceInstance
1700
- });
1701
- return {
1702
- type: operationField.type,
1703
- fields: result.fields
1704
- };
1705
- }
1706
- case 'model': {
1707
- const model = modelMap[operationField.modelName];
1708
- if (!model) {
1709
- throw new Error(`error updating document, could not find document model: '${operationField.modelName}'`);
1710
- }
1711
- const result = await createNestedObjectRecursively({
1712
- object: operationField.object,
1713
- modelFields: model.fields,
1714
- fieldPath,
1715
- modelMap,
1716
- locale,
1717
- userContext,
1718
- contentSourceInstance
1719
- });
1720
- return {
1721
- type: operationField.type,
1722
- modelName: operationField.modelName,
1723
- fields: result.fields
1724
- };
1725
- }
1726
- case 'list': {
1727
- if (modelField.type !== 'list') {
1728
- throw new Error(`'the operation field type '${operationField.type}' does not match the model field type '${modelField.type}'`);
1729
- }
1730
- const result = await (0, utils_1.mapPromise)(operationField.items, async (item, index) => {
1731
- const result = await createNestedField({
1732
- value: item,
1733
- modelField: modelField.items,
1734
- fieldPath,
1735
- modelMap,
1736
- locale,
1737
- userContext,
1738
- contentSourceInstance
1739
- });
1740
- return result.field;
1741
- });
1742
- return {
1743
- type: operationField.type,
1744
- items: result
1745
- };
1746
- }
1747
- case 'string':
1748
- // When inserting new string value into a list, the client does not
1749
- // send value. Set an empty string value.
1750
- if (typeof operationField.value !== 'string') {
1751
- return {
1752
- type: operationField.type,
1753
- value: ''
1754
- };
1755
- }
1756
- return operationField;
1757
- case 'enum':
1758
- // When inserting new enum value into a list, the client does not
1759
- // send value. Set first option as the value.
1760
- if (typeof operationField.value !== 'string') {
1761
- if (modelFieldOrListItems.type !== 'enum') {
1762
- throw new Error(`'the operation field type 'enum' does not match the model field type '${modelFieldOrListItems.type}'`);
1763
- }
1764
- const option = modelFieldOrListItems.options[0];
1765
- const optionValue = typeof option === 'object' ? option.value : option;
1766
- return {
1767
- type: operationField.type,
1768
- value: optionValue
1769
- };
1770
- }
1771
- return operationField;
1772
- case 'image':
1773
- return operationField;
1774
- default:
1775
- return operationField;
1776
- }
1777
- }
1778
- function getDocumentFieldForLocale(docField, locale) {
1779
- if (docField.localized) {
1780
- if (!locale) {
1781
- return null;
1782
- }
1783
- const { localized, locales, ...base } = docField;
1784
- const localizedField = locales[locale];
1785
- if (!localizedField) {
1786
- return null;
1787
- }
1788
- return {
1789
- ...base,
1790
- ...localizedField
1791
- };
1792
- }
1793
- else {
1794
- return docField;
1795
- }
1796
- }
1797
951
  function getCSIDocumentsAndAssetsFromContentSourceDataByIds(contentSourceData, objects) {
1798
952
  const documents = [];
1799
953
  const assets = [];