@stackbit/cms-core 0.1.3-alpha.2 → 0.1.3

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