@stackbit/cms-core 0.2.1 → 0.3.0-develop.1

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 (54) hide show
  1. package/dist/content-store-utils.d.ts +5 -1
  2. package/dist/content-store-utils.d.ts.map +1 -1
  3. package/dist/content-store-utils.js +28 -3
  4. package/dist/content-store-utils.js.map +1 -1
  5. package/dist/content-store.d.ts +12 -1
  6. package/dist/content-store.d.ts.map +1 -1
  7. package/dist/content-store.js +399 -177
  8. package/dist/content-store.js.map +1 -1
  9. package/dist/types/content-store-document-fields.d.ts +26 -4
  10. package/dist/types/content-store-document-fields.d.ts.map +1 -1
  11. package/dist/types/content-store-documents.d.ts +14 -3
  12. package/dist/types/content-store-documents.d.ts.map +1 -1
  13. package/dist/types/content-store-types.d.ts +7 -1
  14. package/dist/types/content-store-types.d.ts.map +1 -1
  15. package/dist/utils/backward-compatibility.d.ts +184 -0
  16. package/dist/utils/backward-compatibility.d.ts.map +1 -0
  17. package/dist/utils/backward-compatibility.js +151 -0
  18. package/dist/utils/backward-compatibility.js.map +1 -0
  19. package/dist/utils/config-delegate.d.ts +11 -0
  20. package/dist/utils/config-delegate.d.ts.map +1 -0
  21. package/dist/utils/config-delegate.js +226 -0
  22. package/dist/utils/config-delegate.js.map +1 -0
  23. package/dist/utils/create-update-csi-docs.d.ts +7 -5
  24. package/dist/utils/create-update-csi-docs.d.ts.map +1 -1
  25. package/dist/utils/create-update-csi-docs.js +24 -24
  26. package/dist/utils/create-update-csi-docs.js.map +1 -1
  27. package/dist/utils/csi-to-store-docs-converter.d.ts +17 -3
  28. package/dist/utils/csi-to-store-docs-converter.d.ts.map +1 -1
  29. package/dist/utils/csi-to-store-docs-converter.js +187 -47
  30. package/dist/utils/csi-to-store-docs-converter.js.map +1 -1
  31. package/dist/utils/site-map.d.ts.map +1 -1
  32. package/dist/utils/site-map.js +4 -1
  33. package/dist/utils/site-map.js.map +1 -1
  34. package/dist/utils/store-to-api-docs-converter.d.ts +6 -1
  35. package/dist/utils/store-to-api-docs-converter.d.ts.map +1 -1
  36. package/dist/utils/store-to-api-docs-converter.js +140 -51
  37. package/dist/utils/store-to-api-docs-converter.js.map +1 -1
  38. package/dist/utils/store-to-csi-docs-converter.d.ts +1 -0
  39. package/dist/utils/store-to-csi-docs-converter.d.ts.map +1 -1
  40. package/dist/utils/store-to-csi-docs-converter.js +2 -1
  41. package/dist/utils/store-to-csi-docs-converter.js.map +1 -1
  42. package/package.json +5 -5
  43. package/src/content-store-utils.ts +40 -6
  44. package/src/content-store.ts +552 -299
  45. package/src/types/content-store-document-fields.ts +16 -4
  46. package/src/types/content-store-documents.ts +12 -3
  47. package/src/types/content-store-types.ts +4 -1
  48. package/src/utils/backward-compatibility.ts +269 -0
  49. package/src/utils/config-delegate.ts +277 -0
  50. package/src/utils/create-update-csi-docs.ts +47 -50
  51. package/src/utils/csi-to-store-docs-converter.ts +256 -43
  52. package/src/utils/site-map.ts +19 -7
  53. package/src/utils/store-to-api-docs-converter.ts +185 -52
  54. package/src/utils/store-to-csi-docs-converter.ts +1 -1
@@ -21,6 +21,14 @@ const duplicate_document_1 = require("./utils/duplicate-document");
21
21
  const model_utils_1 = require("./utils/model-utils");
22
22
  const common_schema_1 = require("./common/common-schema");
23
23
  const preset_utils_1 = require("./utils/preset-utils");
24
+ const backward_compatibility_1 = require("./utils/backward-compatibility");
25
+ const config_delegate_1 = require("./utils/config-delegate");
26
+ const ContentStoreEventType = {
27
+ YamlModelFilesChange: 'yamlModelFilesChange',
28
+ PresetFilesChange: 'presetFilesChange',
29
+ ContentSourceInvalidateSchema: 'contentSourceInvalidateSchema',
30
+ ContentSourceContentChange: 'contentSourceContentChange'
31
+ };
24
32
  exports.StackbitPresetModelName = 'stackbitPreset';
25
33
  class ContentStore {
26
34
  constructor(options) {
@@ -32,6 +40,8 @@ class ContentStore {
32
40
  this.modelExtensions = null;
33
41
  this.presets = {};
34
42
  this.siteMapEntryGroups = {};
43
+ this.processingContentSourcesPromise = null;
44
+ this.contentStoreEventQueue = [];
35
45
  this.logger = options.logger.createLogger({ label: 'content-store' });
36
46
  this.userLogger = options.userLogger.createLogger({ label: 'content-store' });
37
47
  this.localDev = options.localDev;
@@ -112,8 +122,9 @@ class ContentStore {
112
122
  * reducing the CMS API usage.
113
123
  */
114
124
  handleTimerTimeout() {
125
+ var _a;
115
126
  for (const contentSourceInstance of this.contentSources) {
116
- contentSourceInstance.stopWatchingContentUpdates();
127
+ (_a = contentSourceInstance.stopWatchingContentUpdates) === null || _a === void 0 ? void 0 : _a.call(contentSourceInstance);
117
128
  }
118
129
  }
119
130
  /**
@@ -134,9 +145,8 @@ class ContentStore {
134
145
  this.contentUpdatesWatchTimer.stopTimer();
135
146
  }
136
147
  async onFilesChange(updatedFiles) {
137
- var _a, _b, _c;
148
+ var _a;
138
149
  this.logger.debug('onFilesChange');
139
- let schemaChanged = false;
140
150
  if (this.stackbitConfig && !this.stackbitConfig.modelExtensions) {
141
151
  // Check if any of the yaml models files were changed. If yaml model files were changed,
142
152
  // reload them and merge them with models defined in stackbit config.
@@ -144,9 +154,11 @@ class ContentStore {
144
154
  const yamlModelsChanged = updatedFiles.find((updatedFile) => lodash_1.default.some(modelDirs, (modelDir) => updatedFile.startsWith(modelDir)));
145
155
  if (yamlModelsChanged) {
146
156
  this.logger.debug('identified change in stackbit model files');
147
- schemaChanged = true;
148
157
  this.yamlModels = await this.loadYamlModels({ stackbitConfig: this.stackbitConfig });
149
158
  this.configModels = this.mergeConfigModels((_a = this.stackbitConfig.models) !== null && _a !== void 0 ? _a : [], this.yamlModels);
159
+ this.pushContentSourceEvent({
160
+ eventName: ContentStoreEventType.YamlModelFilesChange
161
+ });
150
162
  }
151
163
  }
152
164
  if (this.stackbitConfig) {
@@ -155,57 +167,36 @@ class ContentStore {
155
167
  const presetsChanged = updatedFiles.find((updatedFile) => lodash_1.default.some(presetDirs, (presetDir) => updatedFile.startsWith(presetDir)));
156
168
  if (presetsChanged && !this.usesContentSourcePresets()) {
157
169
  this.logger.debug('identified change in stackbit preset files');
158
- schemaChanged = true;
159
170
  this.presets = await this.loadPresetsFromConfig({ stackbitConfig: this.stackbitConfig });
171
+ this.pushContentSourceEvent({
172
+ eventName: ContentStoreEventType.PresetFilesChange
173
+ });
160
174
  }
161
175
  }
162
- const contentSourceIdsWithChangedSchema = [];
163
- const contentChangeEvents = [];
164
176
  for (const contentSourceInstance of this.contentSources) {
165
177
  const contentSourceId = (0, content_store_utils_1.getContentSourceIdForContentSource)(contentSourceInstance);
166
178
  this.logger.debug(`call onFilesChange for contentSource: ${contentSourceId}`);
167
- const onFilesChangeResult = (_c = (await ((_b = contentSourceInstance.onFilesChange) === null || _b === void 0 ? void 0 : _b.call(contentSourceInstance, { updatedFiles: updatedFiles })))) !== null && _c !== void 0 ? _c : {};
168
- this.logger.debug(`schemaChanged: ${onFilesChangeResult.schemaChanged}, has contentChangeEvent: ${!!onFilesChangeResult.contentChangeEvent}`);
169
- // if schema is changed, there is no need to return contentChanges
170
- // because schema changes reloads everything and implies content changes
171
- if (onFilesChangeResult.schemaChanged) {
172
- schemaChanged = true;
173
- contentSourceIdsWithChangedSchema.push(contentSourceId);
179
+ const onFilesChangeResult = await contentSourceInstance.onFilesChange({ updatedFiles: updatedFiles });
180
+ // If the schema was changed in a specific content source, there is no need to process and notify for content changes.
181
+ // Because the schema changes will trigger loadContentSourcesAndProcessData and reload all models and content of that
182
+ // content source and send the schemaChanged notification that will cause the Studio to reload the schema and documents.
183
+ if (onFilesChangeResult.invalidateSchema) {
184
+ this.logger.debug(`schema was invalidated for contentSource: ${contentSourceId}`);
185
+ this.pushContentSourceEvent({
186
+ eventName: ContentStoreEventType.ContentSourceInvalidateSchema,
187
+ contentSourceId: contentSourceId
188
+ });
174
189
  }
175
- else if (onFilesChangeResult.contentChangeEvent) {
176
- contentChangeEvents.push({ contentSourceId, contentChangeEvent: onFilesChangeResult.contentChangeEvent });
190
+ else if (!(0, content_store_utils_1.isContentChangesEmpty)(onFilesChangeResult.contentChanges)) {
191
+ this.logger.debug(`content was changed for contentSource: ${contentSourceId}`);
192
+ this.pushContentSourceEvent({
193
+ eventName: ContentStoreEventType.ContentSourceContentChange,
194
+ contentSourceId: contentSourceId,
195
+ contentChanges: onFilesChangeResult.contentChanges
196
+ });
177
197
  }
178
198
  }
179
- // If the schema was changed, there is no need to accumulate or notify about content changes.
180
- // The processData will update the store with the latest data. And once the Studio receives
181
- // the schemaChanged notification it will reload all the models and the documents with their latest state.
182
- if (schemaChanged) {
183
- await this.loadContentSourcesAndProcessData({ init: false, contentSourceIds: contentSourceIdsWithChangedSchema });
184
- this.onSchemaChangeCallback();
185
- }
186
- else {
187
- const contentChanges = contentChangeEvents.reduce((contentChanges, { contentSourceId, contentChangeEvent }) => {
188
- const contentChangeResult = this.onContentChange(contentSourceId, contentChangeEvent);
189
- return {
190
- updatedDocuments: contentChanges.updatedDocuments.concat(contentChangeResult.updatedDocuments),
191
- updatedAssets: contentChanges.updatedAssets.concat(contentChangeResult.updatedAssets),
192
- deletedDocuments: contentChanges.deletedDocuments.concat(contentChangeResult.deletedDocuments),
193
- deletedAssets: contentChanges.deletedAssets.concat(contentChangeResult.deletedAssets)
194
- };
195
- }, {
196
- updatedDocuments: [],
197
- updatedAssets: [],
198
- deletedDocuments: [],
199
- deletedAssets: []
200
- });
201
- this.siteMapEntryGroups = await (0, site_map_1.updateSiteMapEntriesWithContentChanges)({
202
- siteMapEntryGroups: this.siteMapEntryGroups,
203
- contentChanges,
204
- stackbitConfig: this.stackbitConfig,
205
- contentSourceDataById: this.contentSourceDataById
206
- });
207
- this.onContentChangeCallback(contentChanges);
208
- }
199
+ await this.processContentStoreEvents();
209
200
  }
210
201
  async loadYamlModels({ stackbitConfig }) {
211
202
  const yamlModelsResult = await (0, sdk_1.loadYamlModelsFromFiles)(stackbitConfig);
@@ -278,7 +269,10 @@ class ContentStore {
278
269
  async loadContentSourcesAndProcessData({ init, contentSourceIds }) {
279
270
  var _a, _b, _c, _d, _e;
280
271
  this.logger.debug('loadContentSourcesAndProcessData', { init, contentSourceIds });
281
- const contentSources = (_b = (_a = this.stackbitConfig) === null || _a === void 0 ? void 0 : _a.contentSources) !== null && _b !== void 0 ? _b : [];
272
+ this.processingContentSourcesPromise = (0, utils_1.deferredPromise)();
273
+ const contentSources = ((_b = (_a = this.stackbitConfig) === null || _a === void 0 ? void 0 : _a.contentSources) !== null && _b !== void 0 ? _b : []).map((contentSource) => {
274
+ return (0, backward_compatibility_1.backwardCompatibleContentSource)(contentSource);
275
+ });
282
276
  const promises = contentSources.map((contentSourceInstance) => {
283
277
  const contentSourceId = (0, content_store_utils_1.getContentSourceIdForContentSource)(contentSourceInstance);
284
278
  if (init || !contentSourceIds || contentSourceIds.includes(contentSourceId)) {
@@ -293,13 +287,10 @@ class ContentStore {
293
287
  for (let i = 0; i < contentSources.length; i++) {
294
288
  const contentSourceDataRaw = contentSourceRawDataArr[i];
295
289
  if ((_c = contentSourceDataRaw === null || contentSourceDataRaw === void 0 ? void 0 : contentSourceDataRaw.csiModelMap) === null || _c === void 0 ? void 0 : _c[exports.StackbitPresetModelName]) {
296
- this.presetsContentSource = contentSources[i];
297
- if (this.presetsContentSource) {
298
- const contentSourceId = (0, content_store_utils_1.getContentSourceIdForContentSource)(this.presetsContentSource);
299
- // reload presets from content source only if needed
300
- if (init || !contentSourceIds || contentSourceIds.includes(contentSourceId)) {
301
- this.presets = await this.loadPresetsFromContentSource(contentSourceDataRaw);
302
- }
290
+ this.presetsContentSource = contentSourceDataRaw.instance;
291
+ // reload presets from content source only if needed
292
+ if (init || !contentSourceIds || contentSourceIds.includes(contentSourceDataRaw.id)) {
293
+ this.presets = await this.loadPresetsFromContentSource(contentSourceDataRaw);
303
294
  }
304
295
  break;
305
296
  }
@@ -321,37 +312,274 @@ class ContentStore {
321
312
  stackbitConfig: this.stackbitConfig,
322
313
  contentSourceDataById: this.contentSourceDataById
323
314
  });
315
+ if (!init) {
316
+ this.onSchemaChangeCallback();
317
+ }
318
+ const processingPromise = this.processingContentSourcesPromise;
319
+ this.processingContentSourcesPromise = null;
320
+ // Do not "await" on processContentStoreEvents as it may introduce a deadlock with
321
+ // the nested loadContentSourcesAndProcessData call which is wrapped by deferWhileRunning.
322
+ this.processContentStoreEvents()
323
+ .catch((error) => {
324
+ this.logger.error('error processing content source events', { error });
325
+ })
326
+ .finally(() => {
327
+ processingPromise.resolve();
328
+ });
329
+ }
330
+ async processContentStoreEvents() {
331
+ // If the ContentStore is currently loading content sources, return to prevent parallel data updates.
332
+ // This method will be called once current loading cycle ends.
333
+ if (this.processingContentSourcesPromise) {
334
+ return this.processingContentSourcesPromise.promise;
335
+ }
336
+ const contentSourceIdsWithInvalidatedSchema = [];
337
+ const contentChanges = {
338
+ updatedDocuments: [],
339
+ updatedAssets: [],
340
+ deletedDocuments: [],
341
+ deletedAssets: []
342
+ };
343
+ let invalidateSchema = false;
344
+ let presetsUpdated = false;
345
+ const contentSourceEvents = this.contentStoreEventQueue;
346
+ this.contentStoreEventQueue = [];
347
+ for (const contentSourceEvent of contentSourceEvents) {
348
+ if (contentSourceEvent.eventName === ContentStoreEventType.YamlModelFilesChange ||
349
+ contentSourceEvent.eventName === ContentStoreEventType.PresetFilesChange) {
350
+ invalidateSchema = true;
351
+ }
352
+ else if (contentSourceEvent.eventName === ContentStoreEventType.ContentSourceInvalidateSchema) {
353
+ invalidateSchema = true;
354
+ contentSourceIdsWithInvalidatedSchema.push(contentSourceEvent.contentSourceId);
355
+ }
356
+ else if (contentSourceEvent.eventName === ContentStoreEventType.ContentSourceContentChange) {
357
+ const result = this.onContentChange(contentSourceEvent.contentSourceId, contentSourceEvent.contentChanges);
358
+ contentChanges.updatedDocuments = contentChanges.updatedDocuments.concat(result.contentChangeResult.updatedDocuments);
359
+ contentChanges.updatedAssets = contentChanges.updatedAssets.concat(result.contentChangeResult.updatedAssets);
360
+ contentChanges.deletedDocuments = contentChanges.deletedDocuments.concat(result.contentChangeResult.deletedDocuments);
361
+ contentChanges.deletedAssets = contentChanges.deletedAssets.concat(result.contentChangeResult.deletedAssets);
362
+ if (result.presetsUpdated) {
363
+ presetsUpdated = true;
364
+ }
365
+ }
366
+ }
367
+ // If the schema was changed, call loadContentSourcesAndProcessData method, this will reload all the SiteMapEntries and call the onSchemaChangeCallback.
368
+ // As soon as the Studio receives the schemaChanged notification it will reload all the models and the documents.
369
+ if (invalidateSchema) {
370
+ await this.loadContentSourcesAndProcessData({
371
+ init: false,
372
+ contentSourceIds: contentSourceIdsWithInvalidatedSchema
373
+ });
374
+ }
375
+ else {
376
+ // If the schema wasn't changed, update SiteMapEntries with the changed content.
377
+ this.siteMapEntryGroups = await (0, site_map_1.updateSiteMapEntriesWithContentChanges)({
378
+ siteMapEntryGroups: this.siteMapEntryGroups,
379
+ contentChanges: contentChanges,
380
+ stackbitConfig: this.stackbitConfig,
381
+ contentSourceDataById: this.contentSourceDataById
382
+ });
383
+ // If presets were updated, call onSchemaChangeCallback to notify the Studio.
384
+ // The Studio will refresh the models and the documents, so no need to notify
385
+ // content changes in this case.
386
+ if (presetsUpdated) {
387
+ this.onSchemaChangeCallback();
388
+ }
389
+ else if (!(0, content_store_utils_1.isContentChangeResultEmpty)(contentChanges)) {
390
+ this.onContentChangeCallback(contentChanges);
391
+ }
392
+ }
393
+ }
394
+ pushContentSourceEvent(contentStoreEvent) {
395
+ if (contentStoreEvent.eventName === ContentStoreEventType.ContentSourceContentChange) {
396
+ // If a content source enqueued the 'contentSourceInvalidateSchema' event,
397
+ // don't push the 'contentSourceContentChange' event, because 'contentSourceInvalidateSchema'
398
+ // will reload all the content source data.
399
+ const hasContentSourceSchemaChangeEvent = this.contentStoreEventQueue.find((event) => event.eventName === ContentStoreEventType.ContentSourceInvalidateSchema && event.contentSourceId === contentStoreEvent.contentSourceId);
400
+ if (!hasContentSourceSchemaChangeEvent) {
401
+ this.contentStoreEventQueue.push(contentStoreEvent);
402
+ }
403
+ }
404
+ else if (contentStoreEvent.eventName === ContentStoreEventType.ContentSourceInvalidateSchema) {
405
+ // Clear any 'contentSourceContentChange' events for a content source,
406
+ // the 'contentSourceInvalidateSchema' will reload all the content source data.
407
+ this.clearEventsForContentSourceId(contentStoreEvent.contentSourceId);
408
+ this.contentStoreEventQueue.push(contentStoreEvent);
409
+ }
410
+ else if (contentStoreEvent.eventName === ContentStoreEventType.YamlModelFilesChange) {
411
+ this.contentStoreEventQueue = this.contentStoreEventQueue.filter((event) => event.eventName !== ContentStoreEventType.YamlModelFilesChange);
412
+ this.contentStoreEventQueue.push(contentStoreEvent);
413
+ }
414
+ else if (contentStoreEvent.eventName === ContentStoreEventType.PresetFilesChange) {
415
+ this.contentStoreEventQueue = this.contentStoreEventQueue.filter((event) => event.eventName !== ContentStoreEventType.PresetFilesChange);
416
+ this.contentStoreEventQueue.push(contentStoreEvent);
417
+ }
418
+ }
419
+ clearEventsForContentSourceId(contentSourceId) {
420
+ this.contentStoreEventQueue = this.contentStoreEventQueue.filter((contentSourceEvent) => {
421
+ if (contentSourceEvent.eventName === ContentStoreEventType.ContentSourceContentChange ||
422
+ contentSourceEvent.eventName === ContentStoreEventType.ContentSourceInvalidateSchema) {
423
+ return contentSourceEvent.contentSourceId !== contentSourceId;
424
+ }
425
+ return true;
426
+ });
324
427
  }
325
428
  async loadContentSourceData({ contentSourceInstance, init }) {
326
- var _a;
429
+ var _a, _b, _c, _d, _e;
327
430
  const contentSourceId = (0, content_store_utils_1.getContentSourceIdForContentSource)(contentSourceInstance);
328
431
  this.logger.debug('loadContentSourceData', { contentSourceId, init });
432
+ // clear content source events emitted by this content source because all the content source data is reloaded
433
+ this.clearEventsForContentSourceId(contentSourceId);
434
+ const localCache = {};
435
+ const getContentSourceDataForCurrentInstance = (methodName) => {
436
+ const contentSourceData = this.contentSourceDataById[contentSourceId];
437
+ if (!contentSourceData) {
438
+ // When loading the content sources for the first time, this.contentSourceDataById will be empty.
439
+ // However, while being loaded, content sources may call cache methods, for example a content
440
+ // source may call getModelByName from within getDocuments. In this case, return locally cached data.
441
+ if (this.processingContentSourcesPromise) {
442
+ return localCache;
443
+ }
444
+ const atLine = (0, content_store_utils_1.getErrorAtLine)(2, getContentSourceDataForCurrentInstance);
445
+ const errorMessage = `Error executing 'cache.${methodName}' method${atLine}. The content source with id '${contentSourceId}' was not found.`;
446
+ this.logger.error(errorMessage);
447
+ return;
448
+ }
449
+ if (contentSourceData.instance !== contentSourceInstance) {
450
+ const atLine = (0, content_store_utils_1.getErrorAtLine)(2, getContentSourceDataForCurrentInstance);
451
+ const errorMessage = `Content source life cycle error! The content source with id '${contentSourceId}' called the 'cache.${methodName}' ` +
452
+ `method${atLine} after the destroy() method was called.`;
453
+ this.logger.error(errorMessage);
454
+ return;
455
+ }
456
+ // While loading the content source, it may call cache methods, when this happens, return the
457
+ // stale data overridden with the most frequent loaded data
458
+ if (this.processingContentSourcesPromise) {
459
+ return Object.assign(contentSourceData, localCache);
460
+ }
461
+ return contentSourceData;
462
+ };
463
+ const cache = {
464
+ getSchema: () => {
465
+ const contentSourceData = getContentSourceDataForCurrentInstance('getSchema');
466
+ if (!(contentSourceData === null || contentSourceData === void 0 ? void 0 : contentSourceData.csiSchema)) {
467
+ const atLine = (0, content_store_utils_1.getErrorAtLine)(1);
468
+ const errorMessage = `Content source life cycle error! The content source with id '${contentSourceId}' called the 'cache.getSchema' ` +
469
+ `method${atLine} before the content source's getSchema() method was called.`;
470
+ this.logger.error(errorMessage);
471
+ return { models: [], locales: [], context: null };
472
+ }
473
+ return contentSourceData.csiSchema;
474
+ },
475
+ getModelByName: (modelName) => {
476
+ const contentSourceData = getContentSourceDataForCurrentInstance('getModelByName');
477
+ if (!(contentSourceData === null || contentSourceData === void 0 ? void 0 : contentSourceData.csiModelMap)) {
478
+ const atLine = (0, content_store_utils_1.getErrorAtLine)(1);
479
+ const errorMessage = `Content source life cycle error! The content source with id '${contentSourceId}' called the 'cache.getModelByName' ` +
480
+ `method${atLine} before the content source's getSchema() method was called.`;
481
+ this.logger.error(errorMessage);
482
+ return;
483
+ }
484
+ return contentSourceData.csiModelMap[modelName];
485
+ },
486
+ getDocuments: () => {
487
+ var _a;
488
+ const contentSourceData = getContentSourceDataForCurrentInstance('getDocuments');
489
+ return (_a = contentSourceData === null || contentSourceData === void 0 ? void 0 : contentSourceData.csiDocuments) !== null && _a !== void 0 ? _a : [];
490
+ },
491
+ getDocumentById: (documentId) => {
492
+ var _a;
493
+ const contentSourceData = getContentSourceDataForCurrentInstance('getDocumentById');
494
+ return (_a = contentSourceData === null || contentSourceData === void 0 ? void 0 : contentSourceData.csiDocumentMap) === null || _a === void 0 ? void 0 : _a[documentId];
495
+ },
496
+ getAssets: () => {
497
+ var _a;
498
+ const contentSourceData = getContentSourceDataForCurrentInstance('getAssets');
499
+ return (_a = contentSourceData === null || contentSourceData === void 0 ? void 0 : contentSourceData.csiAssets) !== null && _a !== void 0 ? _a : [];
500
+ },
501
+ getAssetById: (assetId) => {
502
+ var _a;
503
+ const contentSourceData = getContentSourceDataForCurrentInstance('getAssetById');
504
+ return (_a = contentSourceData === null || contentSourceData === void 0 ? void 0 : contentSourceData.csiAssetMap) === null || _a === void 0 ? void 0 : _a[assetId];
505
+ },
506
+ updateContent: async (contentChanges) => {
507
+ const contentSourceData = getContentSourceDataForCurrentInstance('updateContent');
508
+ if (!contentSourceData) {
509
+ return;
510
+ }
511
+ this.logger.debug('content source called updateContent', { contentSourceId });
512
+ this.pushContentSourceEvent({
513
+ eventName: ContentStoreEventType.ContentSourceContentChange,
514
+ contentSourceId: contentSourceId,
515
+ contentChanges: contentChanges
516
+ });
517
+ await this.processContentStoreEvents();
518
+ },
519
+ invalidateSchema: async () => {
520
+ const contentSourceData = getContentSourceDataForCurrentInstance('invalidateSchema');
521
+ if (!contentSourceData) {
522
+ return;
523
+ }
524
+ this.logger.debug('content source called invalidateSchema', { contentSourceId });
525
+ this.pushContentSourceEvent({
526
+ eventName: ContentStoreEventType.ContentSourceInvalidateSchema,
527
+ contentSourceId: contentSourceId
528
+ });
529
+ await this.processContentStoreEvents();
530
+ }
531
+ };
329
532
  if (init) {
533
+ this.userLogger.info(`Initializing content source: ${contentSourceInstance.getContentSourceType()} (project: ${contentSourceInstance.getProjectId()})`);
534
+ // When stackbit.config.js reloads, it loads new content source instances.
535
+ // Previously loaded content source instances must be destroyed.
536
+ const contentSourceData = this.contentSourceDataById[contentSourceId];
537
+ if (contentSourceData && contentSourceData.instance !== contentSourceInstance) {
538
+ this.logger.debug('destroy previous content source instance', { contentSourceId });
539
+ try {
540
+ (_b = (_a = contentSourceData.instance).stopWatchingContentUpdates) === null || _b === void 0 ? void 0 : _b.call(_a);
541
+ await contentSourceData.instance.destroy();
542
+ }
543
+ catch (error) {
544
+ this.logger.debug('error destroying content source instance', { error });
545
+ }
546
+ }
547
+ // If an instance that wasn't destroyed calls one of the InitOptions method don't return any data.
330
548
  await contentSourceInstance.init({
331
549
  logger: this.logger,
332
550
  userLogger: this.userLogger,
333
- userCommandSpawner: this.userCommandSpawner,
334
551
  localDev: this.localDev,
335
552
  webhookUrl: this.getWebhookUrl(contentSourceInstance.getContentSourceType(), contentSourceInstance.getProjectId()),
553
+ userCommandSpawner: this.userCommandSpawner,
336
554
  devAppRestartNeeded: this.devAppRestartNeeded,
555
+ cache: cache,
337
556
  runCommand: this.runCommand,
338
557
  git: this.git
339
558
  });
340
559
  }
341
560
  else {
342
- contentSourceInstance.stopWatchingContentUpdates();
343
561
  await contentSourceInstance.reset();
344
562
  }
345
- const csiModels = await contentSourceInstance.getModels();
563
+ const version = await contentSourceInstance.getVersion();
564
+ const csiSchema = await contentSourceInstance.getSchema();
565
+ const csiModels = csiSchema.models;
346
566
  const csiModelMap = lodash_1.default.keyBy(csiModels, 'name');
347
- const locales = await contentSourceInstance.getLocales();
348
- const defaultLocaleCode = (_a = locales === null || locales === void 0 ? void 0 : locales.find((locale) => locale.default)) === null || _a === void 0 ? void 0 : _a.code;
567
+ const locales = csiSchema.locales;
568
+ const defaultLocaleCode = (_c = locales === null || locales === void 0 ? void 0 : locales.find((locale) => locale.default)) === null || _c === void 0 ? void 0 : _c.code;
569
+ localCache.csiSchema = csiSchema;
570
+ localCache.csiModels = csiModels;
571
+ localCache.csiModelMap = csiModelMap;
572
+ localCache.locales = locales;
349
573
  const csiDocuments = await contentSourceInstance.getDocuments({ modelMap: csiModelMap });
350
- const csiAssets = await contentSourceInstance.getAssets();
351
574
  const csiDocumentMap = lodash_1.default.keyBy(csiDocuments, 'id');
575
+ localCache.csiDocuments = csiDocuments;
576
+ localCache.csiDocumentMap = csiDocumentMap;
577
+ const csiAssets = await contentSourceInstance.getAssets();
352
578
  const csiAssetMap = lodash_1.default.keyBy(csiAssets, 'id');
579
+ localCache.csiAssets = csiAssets;
580
+ localCache.csiAssetMap = csiAssetMap;
353
581
  const contentStoreAssets = (0, csi_to_store_docs_converter_1.mapCSIAssetsToStoreAssets)({
354
- csiAssets,
582
+ csiAssets: csiAssets,
355
583
  contentSourceInstance,
356
584
  defaultLocaleCode
357
585
  });
@@ -359,55 +587,43 @@ class ContentStore {
359
587
  this.logger.debug('loaded content source data', {
360
588
  contentSourceId,
361
589
  defaultLocaleCode,
362
- localesCount: locales.length,
590
+ localesCount: (_d = locales === null || locales === void 0 ? void 0 : locales.length) !== null && _d !== void 0 ? _d : 0,
363
591
  modelCount: csiModels.length,
364
592
  documentCount: csiDocuments.length,
365
593
  assetCount: csiAssets.length
366
594
  });
367
- contentSourceInstance.startWatchingContentUpdates({
368
- getModelMap: () => {
369
- return csiModelMap;
370
- },
371
- getDocument({ documentId }) {
372
- return csiDocumentMap[documentId];
373
- },
374
- getAsset({ assetId }) {
375
- return csiAssetMap[assetId];
376
- },
377
- onContentChange: async (contentChangeEvent) => {
378
- var _a;
379
- if (((_a = this.contentSourceDataById[contentSourceId]) === null || _a === void 0 ? void 0 : _a.instance) !== contentSourceInstance) {
380
- this.logger.debug('old content source called onContentChange', { contentSourceId });
381
- return;
382
- }
383
- this.logger.debug('content source called onContentChange.', { contentSourceId });
384
- const result = this.onContentChange(contentSourceId, contentChangeEvent);
385
- this.siteMapEntryGroups = await (0, site_map_1.updateSiteMapEntriesWithContentChanges)({
386
- siteMapEntryGroups: this.siteMapEntryGroups,
387
- contentChanges: result,
388
- stackbitConfig: this.stackbitConfig,
389
- contentSourceDataById: this.contentSourceDataById
390
- });
391
- this.onContentChangeCallback(result);
392
- },
393
- onSchemaChange: async () => {
394
- var _a;
395
- if (((_a = this.contentSourceDataById[contentSourceId]) === null || _a === void 0 ? void 0 : _a.instance) !== contentSourceInstance) {
396
- this.logger.debug('old content source called onSchemaChange', { contentSourceId });
397
- return;
398
- }
399
- this.logger.debug('content source called onSchemaChange', { contentSourceId });
400
- await this.loadContentSourcesAndProcessData({ init: false, contentSourceIds: [contentSourceId] });
401
- this.onSchemaChangeCallback();
402
- }
403
- });
595
+ if (init) {
596
+ this.userLogger.info(`→ Loaded content source data: ${csiModels.length} model${csiModels.length !== 1 ? 's' : ''}, ${csiDocuments.length} document${csiDocuments.length !== 1 ? 's' : ''} and ${csiAssets.length} asset${csiAssets.length !== 1 ? 's' : ''}`);
597
+ // backward compatibility
598
+ (_e = contentSourceInstance.startWatchingContentUpdates) === null || _e === void 0 ? void 0 : _e.call(contentSourceInstance, {
599
+ getModelMap: () => {
600
+ var _a;
601
+ const contentSourceData = getContentSourceDataForCurrentInstance('getModelMap');
602
+ return (_a = contentSourceData === null || contentSourceData === void 0 ? void 0 : contentSourceData.csiModelMap) !== null && _a !== void 0 ? _a : {};
603
+ },
604
+ getDocument: ({ documentId }) => {
605
+ var _a;
606
+ const contentSourceData = getContentSourceDataForCurrentInstance('getDocument');
607
+ return (_a = contentSourceData === null || contentSourceData === void 0 ? void 0 : contentSourceData.csiDocumentMap) === null || _a === void 0 ? void 0 : _a[documentId];
608
+ },
609
+ getAsset: ({ assetId }) => {
610
+ var _a;
611
+ const contentSourceData = getContentSourceDataForCurrentInstance('getAsset');
612
+ return (_a = contentSourceData === null || contentSourceData === void 0 ? void 0 : contentSourceData.csiAssetMap) === null || _a === void 0 ? void 0 : _a[assetId];
613
+ },
614
+ onContentChange: cache.updateContent,
615
+ onSchemaChange: cache.invalidateSchema
616
+ });
617
+ }
404
618
  return {
405
619
  id: contentSourceId,
620
+ version: version,
406
621
  srcType: contentSourceInstance.getContentSourceType(),
407
622
  srcProjectId: contentSourceInstance.getProjectId(),
408
623
  instance: contentSourceInstance,
409
624
  locales: locales,
410
625
  defaultLocaleCode: defaultLocaleCode,
626
+ csiSchema: csiSchema,
411
627
  csiModels: csiModels,
412
628
  csiModelMap: csiModelMap,
413
629
  csiDocuments: csiDocuments,
@@ -418,17 +634,22 @@ class ContentStore {
418
634
  assetMap: assetMap
419
635
  };
420
636
  }
421
- onContentChange(contentSourceId, contentChangeEvent) {
422
- // TODO: prevent content change process for contentSourceId if loading content is in progress
423
- var _a, _b, _c, _d, _e, _f, _g;
637
+ onContentChange(contentSourceId, contentChanges) {
638
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
424
639
  // certain content changes, like preset changes are interpreted as schema changes
425
- let schemaChanged = false;
640
+ let presetsUpdated = false;
641
+ const contentChangesReq = {
642
+ documents: (_a = contentChanges.documents) !== null && _a !== void 0 ? _a : [],
643
+ assets: (_b = contentChanges.assets) !== null && _b !== void 0 ? _b : [],
644
+ deletedDocumentIds: (_c = contentChanges.deletedDocumentIds) !== null && _c !== void 0 ? _c : [],
645
+ deletedAssetIds: (_d = contentChanges.deletedAssetIds) !== null && _d !== void 0 ? _d : []
646
+ };
426
647
  this.logger.debug('onContentChange', {
427
648
  contentSourceId,
428
- documentCount: contentChangeEvent.documents.length,
429
- assetCount: contentChangeEvent.assets.length,
430
- deletedDocumentCount: contentChangeEvent.deletedDocumentIds.length,
431
- deletedAssetCount: contentChangeEvent.deletedAssetIds.length
649
+ documentCount: contentChangesReq.documents.length,
650
+ assetCount: contentChangesReq.assets.length,
651
+ deletedDocumentCount: contentChangesReq.deletedDocumentIds.length,
652
+ deletedAssetCount: contentChangesReq.deletedAssetIds.length
432
653
  });
433
654
  const result = {
434
655
  updatedDocuments: [],
@@ -438,12 +659,12 @@ class ContentStore {
438
659
  };
439
660
  const contentSourceData = this.getContentSourceDataByIdOrThrow(contentSourceId);
440
661
  // update contentSourceData with deleted documents
441
- contentChangeEvent.deletedDocumentIds.forEach((docId) => {
662
+ contentChangesReq.deletedDocumentIds.forEach((docId) => {
442
663
  var _a;
443
664
  // remove preset, make sure there is something to remove first because
444
665
  // were explicitly calling onContentChange from deletePreset as well
445
666
  if (this.presets[docId] && ((_a = contentSourceData.csiDocumentMap[docId]) === null || _a === void 0 ? void 0 : _a.modelName) === exports.StackbitPresetModelName) {
446
- schemaChanged = true;
667
+ presetsUpdated = true;
447
668
  const preset = this.presets[docId];
448
669
  const model = contentSourceData.modelMap[preset.modelName];
449
670
  delete this.presets[docId];
@@ -469,7 +690,7 @@ class ContentStore {
469
690
  });
470
691
  });
471
692
  // update contentSourceData with deleted assets
472
- contentChangeEvent.deletedAssetIds.forEach((assetId) => {
693
+ contentChangesReq.deletedAssetIds.forEach((assetId) => {
473
694
  // delete document from asset map
474
695
  delete contentSourceData.assetMap[assetId];
475
696
  delete contentSourceData.csiAssetMap[assetId];
@@ -487,9 +708,9 @@ class ContentStore {
487
708
  });
488
709
  });
489
710
  // map csi documents through stackbitConfig.mapDocuments
490
- let mappedDocs = contentChangeEvent.documents;
491
- if ((_a = this.stackbitConfig) === null || _a === void 0 ? void 0 : _a.mapDocuments) {
492
- const csiDocumentsWithSource = contentChangeEvent.documents.map((csiDocument) => ({
711
+ let mappedDocs = contentChangesReq.documents;
712
+ if ((_e = this.stackbitConfig) === null || _e === void 0 ? void 0 : _e.mapDocuments) {
713
+ const csiDocumentsWithSource = contentChangesReq.documents.map((csiDocument) => ({
493
714
  srcType: contentSourceData.srcType,
494
715
  srcProjectId: contentSourceData.srcProjectId,
495
716
  ...csiDocument
@@ -502,32 +723,36 @@ class ContentStore {
502
723
  };
503
724
  });
504
725
  mappedDocs =
505
- (_d = (_c = (_b = this.stackbitConfig) === null || _b === void 0 ? void 0 : _b.mapDocuments) === null || _c === void 0 ? void 0 : _c.call(_b, {
726
+ (_h = (_g = (_f = this.stackbitConfig) === null || _f === void 0 ? void 0 : _f.mapDocuments) === null || _g === void 0 ? void 0 : _g.call(_f, {
506
727
  documents: lodash_1.default.cloneDeep(csiDocumentsWithSource),
507
728
  models: lodash_1.default.cloneDeep(modelsWithSource)
508
- })) !== null && _d !== void 0 ? _d : csiDocumentsWithSource;
729
+ })) !== null && _h !== void 0 ? _h : csiDocumentsWithSource;
509
730
  }
510
731
  // map csi documents and assets to content store documents and assets
511
732
  const documents = (0, csi_to_store_docs_converter_1.mapCSIDocumentsToStoreDocuments)({
512
733
  csiDocuments: mappedDocs,
513
734
  contentSourceInstance: contentSourceData.instance,
514
735
  modelMap: contentSourceData.modelMap,
515
- defaultLocaleCode: contentSourceData.defaultLocaleCode
736
+ defaultLocaleCode: contentSourceData.defaultLocaleCode,
737
+ createConfigDelegate: (0, config_delegate_1.getCreateConfigDelegateThunk)({
738
+ getContentSourceDataById: () => this.contentSourceDataById,
739
+ logger: this.userLogger
740
+ })
516
741
  });
517
742
  const assets = (0, csi_to_store_docs_converter_1.mapCSIAssetsToStoreAssets)({
518
- csiAssets: contentChangeEvent.assets,
743
+ csiAssets: contentChangesReq.assets,
519
744
  contentSourceInstance: contentSourceData.instance,
520
745
  defaultLocaleCode: contentSourceData.defaultLocaleCode
521
746
  });
522
747
  // update contentSourceData with new or updated documents and assets
523
- Object.assign(contentSourceData.csiDocumentMap, lodash_1.default.keyBy(contentChangeEvent.documents, 'id'));
524
- Object.assign(contentSourceData.csiAssetMap, lodash_1.default.keyBy(contentChangeEvent.assets, 'id'));
748
+ Object.assign(contentSourceData.csiDocumentMap, lodash_1.default.keyBy(contentChangesReq.documents, 'id'));
749
+ Object.assign(contentSourceData.csiAssetMap, lodash_1.default.keyBy(contentChangesReq.assets, 'id'));
525
750
  Object.assign(contentSourceData.documentMap, lodash_1.default.keyBy(documents, 'srcObjectId'));
526
751
  Object.assign(contentSourceData.assetMap, lodash_1.default.keyBy(assets, 'srcObjectId'));
527
752
  for (let idx = 0; idx < documents.length; idx++) {
528
753
  // the indexes of mapped documents and documents from changeEvent are the same
529
754
  const document = documents[idx];
530
- const csiDocument = contentChangeEvent.documents[idx];
755
+ const csiDocument = contentChangesReq.documents[idx];
531
756
  const dataIndex = contentSourceData.documents.findIndex((existingDoc) => existingDoc.srcObjectId === document.srcObjectId);
532
757
  if (dataIndex === -1) {
533
758
  contentSourceData.documents.push(document);
@@ -538,7 +763,7 @@ class ContentStore {
538
763
  contentSourceData.csiDocuments.splice(dataIndex, 1, csiDocument);
539
764
  }
540
765
  if (csiDocument.modelName === exports.StackbitPresetModelName) {
541
- schemaChanged = true;
766
+ presetsUpdated = true;
542
767
  const preset = (0, preset_utils_1.getPresetFromDocument)({
543
768
  srcType: contentSourceData.srcType,
544
769
  srcProjectId: contentSourceData.srcProjectId,
@@ -550,7 +775,7 @@ class ContentStore {
550
775
  this.presets[csiDocument.id] = preset;
551
776
  if (dataIndex === -1) {
552
777
  //TODO recalculate assets as well
553
- (_f = (_e = contentSourceData.modelMap[preset.modelName]) === null || _e === void 0 ? void 0 : _e.presets) === null || _f === void 0 ? void 0 : _f.push(csiDocument.id);
778
+ (_k = (_j = contentSourceData.modelMap[preset.modelName]) === null || _j === void 0 ? void 0 : _j.presets) === null || _k === void 0 ? void 0 : _k.push(csiDocument.id);
554
779
  }
555
780
  }
556
781
  }
@@ -563,7 +788,7 @@ class ContentStore {
563
788
  for (let idx = 0; idx < assets.length; idx++) {
564
789
  // the indexes of mapped assets and assets from changeEvent are the same
565
790
  const asset = assets[idx];
566
- const csiAsset = contentChangeEvent.assets[idx];
791
+ const csiAsset = contentChangesReq.assets[idx];
567
792
  const index = contentSourceData.assets.findIndex((existingAsset) => existingAsset.srcObjectId === asset.srcObjectId);
568
793
  if (index === -1) {
569
794
  contentSourceData.assets.push(asset);
@@ -580,10 +805,10 @@ class ContentStore {
580
805
  srcObjectId: asset.srcObjectId
581
806
  });
582
807
  }
583
- if (schemaChanged) {
584
- (_g = this.onSchemaChangeCallback) === null || _g === void 0 ? void 0 : _g.call(this);
585
- }
586
- return result;
808
+ return {
809
+ contentChangeResult: result,
810
+ presetsUpdated
811
+ };
587
812
  }
588
813
  async processData({ stackbitConfig, configModels, presets, contentSourceRawDataArr }) {
589
814
  // Group models from all content sources by their names
@@ -704,8 +929,12 @@ class ContentStore {
704
929
  const documents = (0, csi_to_store_docs_converter_1.mapCSIDocumentsToStoreDocuments)({
705
930
  csiDocuments: csiDocuments,
706
931
  contentSourceInstance: csData.instance,
932
+ modelMap: modelMap,
707
933
  defaultLocaleCode: csData.defaultLocaleCode,
708
- modelMap: modelMap
934
+ createConfigDelegate: (0, config_delegate_1.getCreateConfigDelegateThunk)({
935
+ getContentSourceDataById: () => this.contentSourceDataById,
936
+ logger: this.userLogger
937
+ })
709
938
  });
710
939
  return {
711
940
  ...csData,
@@ -717,6 +946,16 @@ class ContentStore {
717
946
  });
718
947
  return lodash_1.default.keyBy(contentSourceDataArr, 'id');
719
948
  }
949
+ getContentSourceMeta() {
950
+ return lodash_1.default.reduce(this.contentSourceDataById, (result, contentSourceData) => {
951
+ return result.concat({
952
+ srcType: contentSourceData.srcType,
953
+ srcProjectId: contentSourceData.srcProjectId,
954
+ srcVersion: contentSourceData.version.contentSourceVersion,
955
+ csiVersion: contentSourceData.version.interfaceVersion
956
+ });
957
+ }, []);
958
+ }
720
959
  getModels() {
721
960
  return lodash_1.default.reduce(this.contentSourceDataById, (result, contentSourceData) => {
722
961
  const contentSourceType = contentSourceData.instance.getContentSourceType();
@@ -762,14 +1001,7 @@ class ContentStore {
762
1001
  const srcType = contentSourceData.srcType;
763
1002
  const srcProjectId = contentSourceData.srcProjectId;
764
1003
  const userContext = (0, content_store_utils_1.getUserContextForSrcType)(srcType, user);
765
- let result = await contentSourceData.instance.hasAccess({ userContext });
766
- // backwards compatibility with older CSI version
767
- if (typeof result === 'boolean') {
768
- result = {
769
- hasConnection: result,
770
- hasPermissions: result
771
- };
772
- }
1004
+ const result = await contentSourceData.instance.hasAccess({ userContext });
773
1005
  return {
774
1006
  hasConnection: accum.hasConnection && result.hasConnection,
775
1007
  hasPermissions: accum.hasPermissions && result.hasPermissions,
@@ -857,7 +1089,7 @@ class ContentStore {
857
1089
  const contentSourceData = this.getContentSourceDataByIdOrThrow(contentSourceId);
858
1090
  return contentSourceData.documentMap[srcDocumentId];
859
1091
  }
860
- getDocuments({ locale }) {
1092
+ getDocuments({ locale } = {}) {
861
1093
  return lodash_1.default.reduce(this.contentSourceDataById, (documents, contentSourceData) => {
862
1094
  const currentDocuments = lodash_1.default.isEmpty(locale)
863
1095
  ? contentSourceData.documents
@@ -885,18 +1117,16 @@ class ContentStore {
885
1117
  let documents = objectIds
886
1118
  ? contentSourceData.documents.filter((document) => objectIds.includes(document.srcObjectId))
887
1119
  : contentSourceData.documents;
888
- documents = hasExplicitLocale
889
- ? documents.filter((document) => !document.locale || document.locale === locale)
890
- : documents;
891
- let assets = objectIds
892
- ? contentSourceData.assets.filter((asset) => objectIds.includes(asset.srcObjectId))
893
- : contentSourceData.assets;
894
- assets = hasExplicitLocale
895
- ? assets.filter((asset) => !asset.locale || asset.locale === locale)
896
- : assets;
1120
+ documents = hasExplicitLocale ? documents.filter((document) => !document.locale || document.locale === locale) : documents;
1121
+ let assets = objectIds ? contentSourceData.assets.filter((asset) => objectIds.includes(asset.srcObjectId)) : contentSourceData.assets;
1122
+ assets = hasExplicitLocale ? assets.filter((asset) => !asset.locale || asset.locale === locale) : assets;
897
1123
  const currentLocale = locale !== null && locale !== void 0 ? locale : contentSourceData.defaultLocaleCode;
898
1124
  const filteredDocuments = documents.filter((document) => document.srcModelName !== exports.StackbitPresetModelName);
899
- const documentObjects = (0, store_to_api_docs_converter_1.mapDocumentsToLocalizedApiObjects)(filteredDocuments, currentLocale);
1125
+ const documentObjects = (0, store_to_api_docs_converter_1.mapDocumentsToLocalizedApiObjects)({
1126
+ documents: filteredDocuments,
1127
+ locale: currentLocale,
1128
+ delegate: (0, config_delegate_1.createConfigDelegate)({ contentSourceDataById: this.contentSourceDataById, logger: this.userLogger })
1129
+ });
900
1130
  const imageObjects = (0, store_to_api_docs_converter_1.mapAssetsToLocalizedApiImages)(assets, this.staticAssetsPublicPath, currentLocale);
901
1131
  return objects.concat(documentObjects, imageObjects);
902
1132
  }, []);
@@ -1009,7 +1239,7 @@ class ContentStore {
1009
1239
  refProjectId: refProjectId
1010
1240
  });
1011
1241
  }
1012
- const updatedDocument = await contentSourceData.instance.updateDocument({
1242
+ await contentSourceData.instance.updateDocument({
1013
1243
  document: csiDocument,
1014
1244
  modelMap: csiModelMap,
1015
1245
  userContext: userContext,
@@ -1032,7 +1262,7 @@ class ContentStore {
1032
1262
  }
1033
1263
  ]
1034
1264
  });
1035
- return { srcDocumentId: updatedDocument.id, createdDocumentId: result.srcDocumentId };
1265
+ return { srcDocumentId: srcDocumentId, createdDocumentId: result.srcDocumentId };
1036
1266
  }
1037
1267
  async createPreset({ preset, thumbnailAsset, user }) {
1038
1268
  var _a;
@@ -1074,12 +1304,18 @@ class ContentStore {
1074
1304
  });
1075
1305
  // we delete presets immediately because some CMSs don't notify us
1076
1306
  // when documents have been deleted.
1077
- this.onContentChange((0, content_store_utils_1.getContentSourceIdForContentSource)(this.presetsContentSource), {
1078
- documents: [],
1079
- deletedDocumentIds: [presetId],
1080
- assets: [],
1081
- deletedAssetIds: []
1307
+ const contentSourceId = (0, content_store_utils_1.getContentSourceIdForContentSource)(this.presetsContentSource);
1308
+ this.pushContentSourceEvent({
1309
+ eventName: ContentStoreEventType.ContentSourceContentChange,
1310
+ contentSourceId: contentSourceId,
1311
+ contentChanges: {
1312
+ documents: [],
1313
+ deletedDocumentIds: [presetId],
1314
+ assets: [],
1315
+ deletedAssetIds: []
1316
+ }
1082
1317
  });
1318
+ await this.processContentStoreEvents();
1083
1319
  }
1084
1320
  async uploadAndLinkAsset({ srcType, srcProjectId, srcDocumentId, fieldPath, asset, index, locale, user }) {
1085
1321
  this.logger.debug('uploadAndLinkAsset', { srcType, srcProjectId, srcDocumentId, fieldPath, index, locale });
@@ -1123,7 +1359,7 @@ class ContentStore {
1123
1359
  refType: 'asset',
1124
1360
  refId: result.id
1125
1361
  };
1126
- const updatedDocument = await contentSourceData.instance.updateDocument({
1362
+ await contentSourceData.instance.updateDocument({
1127
1363
  document: csiDocument,
1128
1364
  modelMap: csiModelMap,
1129
1365
  userContext: userContext,
@@ -1146,7 +1382,7 @@ class ContentStore {
1146
1382
  }
1147
1383
  ]
1148
1384
  });
1149
- return { srcDocumentId: updatedDocument.id };
1385
+ return { srcDocumentId: srcDocumentId };
1150
1386
  }
1151
1387
  async createDocument({ srcType, srcProjectId, modelName, object, locale, defaultLocaleDocumentId, user }) {
1152
1388
  this.logger.debug('createDocument', { srcType, srcProjectId, modelName, locale });
@@ -1164,13 +1400,8 @@ class ContentStore {
1164
1400
  user
1165
1401
  })
1166
1402
  });
1167
- this.logger.debug('created document', { srcType, srcProjectId, srcDocumentId: result.document.id, modelName });
1168
- // do not update cache in contentSourceData.documents and documentMap,
1169
- // instead wait for contentSource to call onContentChange(contentChangeEvent)
1170
- // and use data from contentChangeEvent to update the cache
1171
- // const newDocuments = [result.document, ...result.referencedDocuments];
1172
- // contentSourceData.documentMap = Object.assign(contentSourceData.documentMap, _.keyBy(newDocuments, 'srcObjectId'));
1173
- return { srcDocumentId: result.document.id };
1403
+ this.logger.debug('created document', { srcType, srcProjectId, srcDocumentId: result.documentId, modelName });
1404
+ return { srcDocumentId: result.documentId };
1174
1405
  }
1175
1406
  async updateDocument({ srcType, srcProjectId, srcDocumentId, updateOperations, user }) {
1176
1407
  this.logger.debug('updateDocument');
@@ -1256,17 +1487,13 @@ class ContentStore {
1256
1487
  };
1257
1488
  }
1258
1489
  });
1259
- const updatedDocumentResult = await contentSourceData.instance.updateDocument({
1490
+ await contentSourceData.instance.updateDocument({
1260
1491
  document: csiDocument,
1261
1492
  modelMap: csiModelMap,
1262
1493
  userContext,
1263
1494
  operations
1264
1495
  });
1265
- // do not update cache in contentSourceData.documents and documentMap,
1266
- // instead wait for contentSource to call onContentChange(contentChangeEvent)
1267
- // and use data from contentChangeEvent to update the cache
1268
- // contentSourceData.documentMap = Object.assign(contentSourceData.documentMap, { [document.srcObjectId]: document });
1269
- return { srcDocumentId: updatedDocumentResult.id };
1496
+ return { srcDocumentId: srcDocumentId };
1270
1497
  }
1271
1498
  async duplicateDocument({ srcType, srcProjectId, srcDocumentId, object, locale, user }) {
1272
1499
  var _a, _b, _c;
@@ -1278,7 +1505,6 @@ class ContentStore {
1278
1505
  throw new Error(`no document with id '${srcDocumentId}' was found in ${contentSourceData.id}`);
1279
1506
  }
1280
1507
  const modelMap = contentSourceData.modelMap;
1281
- const csiModelMap = contentSourceData.csiModelMap;
1282
1508
  const model = modelMap[document.srcModelName];
1283
1509
  if (!model) {
1284
1510
  throw new Error(`no model with name '${document.srcModelName}' was found`);
@@ -1304,8 +1530,8 @@ class ContentStore {
1304
1530
  user
1305
1531
  })
1306
1532
  });
1307
- this.logger.debug('duplicated document', { srcType, srcProjectId, srcDocumentId, newDocumentId: result.document.id, modelName: model.name });
1308
- return { srcDocumentId: result.document.id };
1533
+ this.logger.debug('duplicated document', { srcType, srcProjectId, srcDocumentId, newDocumentId: result.documentId, modelName: model.name });
1534
+ return { srcDocumentId: result.documentId };
1309
1535
  }
1310
1536
  async uploadAssets({ srcType, srcProjectId, assets, locale, user }) {
1311
1537
  this.logger.debug('uploadAssets');
@@ -1349,10 +1575,6 @@ class ContentStore {
1349
1575
  throw new Error(`no document with id '${srcDocumentId}' was found in ${contentSourceData.id}`);
1350
1576
  }
1351
1577
  await contentSourceData.instance.deleteDocument({ document: csiDocument, userContext });
1352
- // do not update cache in contentSourceData.documents and documentMap,
1353
- // instead wait for contentSource to call onContentChange(contentChangeEvent)
1354
- // and use data from contentChangeEvent to update the cache
1355
- // delete contentSourceData.documentMap[srcDocumentId];
1356
1578
  }
1357
1579
  async validateDocuments({ objects, locale, user }) {
1358
1580
  this.logger.debug('validateDocuments');