@stackbit/cms-core 0.2.1 → 0.3.0-develop.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/content-store-utils.d.ts +5 -1
- package/dist/content-store-utils.d.ts.map +1 -1
- package/dist/content-store-utils.js +28 -3
- package/dist/content-store-utils.js.map +1 -1
- package/dist/content-store.d.ts +12 -1
- package/dist/content-store.d.ts.map +1 -1
- package/dist/content-store.js +399 -177
- package/dist/content-store.js.map +1 -1
- package/dist/types/content-store-document-fields.d.ts +26 -4
- package/dist/types/content-store-document-fields.d.ts.map +1 -1
- package/dist/types/content-store-documents.d.ts +14 -3
- package/dist/types/content-store-documents.d.ts.map +1 -1
- package/dist/types/content-store-types.d.ts +7 -1
- package/dist/types/content-store-types.d.ts.map +1 -1
- package/dist/utils/backward-compatibility.d.ts +184 -0
- package/dist/utils/backward-compatibility.d.ts.map +1 -0
- package/dist/utils/backward-compatibility.js +151 -0
- package/dist/utils/backward-compatibility.js.map +1 -0
- package/dist/utils/config-delegate.d.ts +11 -0
- package/dist/utils/config-delegate.d.ts.map +1 -0
- package/dist/utils/config-delegate.js +226 -0
- package/dist/utils/config-delegate.js.map +1 -0
- package/dist/utils/create-update-csi-docs.d.ts +7 -5
- package/dist/utils/create-update-csi-docs.d.ts.map +1 -1
- package/dist/utils/create-update-csi-docs.js +24 -24
- package/dist/utils/create-update-csi-docs.js.map +1 -1
- package/dist/utils/csi-to-store-docs-converter.d.ts +17 -3
- package/dist/utils/csi-to-store-docs-converter.d.ts.map +1 -1
- package/dist/utils/csi-to-store-docs-converter.js +187 -47
- package/dist/utils/csi-to-store-docs-converter.js.map +1 -1
- package/dist/utils/site-map.d.ts.map +1 -1
- package/dist/utils/site-map.js +4 -1
- package/dist/utils/site-map.js.map +1 -1
- package/dist/utils/store-to-api-docs-converter.d.ts +6 -1
- package/dist/utils/store-to-api-docs-converter.d.ts.map +1 -1
- package/dist/utils/store-to-api-docs-converter.js +140 -51
- package/dist/utils/store-to-api-docs-converter.js.map +1 -1
- package/dist/utils/store-to-csi-docs-converter.d.ts +1 -0
- package/dist/utils/store-to-csi-docs-converter.d.ts.map +1 -1
- package/dist/utils/store-to-csi-docs-converter.js +2 -1
- package/dist/utils/store-to-csi-docs-converter.js.map +1 -1
- package/package.json +5 -5
- package/src/content-store-utils.ts +40 -6
- package/src/content-store.ts +552 -299
- package/src/types/content-store-document-fields.ts +16 -4
- package/src/types/content-store-documents.ts +12 -3
- package/src/types/content-store-types.ts +4 -1
- package/src/utils/backward-compatibility.ts +269 -0
- package/src/utils/config-delegate.ts +277 -0
- package/src/utils/create-update-csi-docs.ts +47 -50
- package/src/utils/csi-to-store-docs-converter.ts +256 -43
- package/src/utils/site-map.ts +19 -7
- package/src/utils/store-to-api-docs-converter.ts +185 -52
- package/src/utils/store-to-csi-docs-converter.ts +1 -1
package/src/content-store.ts
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
Preset,
|
|
19
19
|
PresetMap
|
|
20
20
|
} from '@stackbit/sdk';
|
|
21
|
-
import { append, deferWhileRunning, mapPromise, reducePromise } from '@stackbit/utils';
|
|
21
|
+
import { append, DeferredPromise, deferredPromise, deferWhileRunning, mapPromise, reducePromise } from '@stackbit/utils';
|
|
22
22
|
|
|
23
23
|
import * as ContentStoreTypes from './types';
|
|
24
24
|
import { Timer } from './utils/timer';
|
|
@@ -33,7 +33,10 @@ import {
|
|
|
33
33
|
getUserContextForSrcType,
|
|
34
34
|
groupDocumentsByContentSource,
|
|
35
35
|
groupModelsByContentSource,
|
|
36
|
-
|
|
36
|
+
isContentChangesEmpty,
|
|
37
|
+
isContentChangeResultEmpty,
|
|
38
|
+
updateOperationValueFieldWithCrossReference,
|
|
39
|
+
getErrorAtLine
|
|
37
40
|
} from './content-store-utils';
|
|
38
41
|
import {
|
|
39
42
|
getSiteMapEntriesFromStackbitConfig,
|
|
@@ -48,6 +51,8 @@ import { mergeObjectWithDocument } from './utils/duplicate-document';
|
|
|
48
51
|
import { normalizeModels, validateModels } from './utils/model-utils';
|
|
49
52
|
import { IMAGE_MODEL } from './common/common-schema';
|
|
50
53
|
import { getDocumentObjectFromPreset, getPresetFromDocument } from './utils/preset-utils';
|
|
54
|
+
import { BackCompatContentSourceInterface, backwardCompatibleContentSource } from './utils/backward-compatibility';
|
|
55
|
+
import { createConfigDelegate, getCreateConfigDelegateThunk } from './utils/config-delegate';
|
|
51
56
|
import { GitService } from './services';
|
|
52
57
|
import { CommandRunner } from '@stackbit/types';
|
|
53
58
|
|
|
@@ -70,6 +75,31 @@ export interface ContentSourceOptions {
|
|
|
70
75
|
|
|
71
76
|
type ContentSourceData = ContentStoreTypes.ContentSourceData;
|
|
72
77
|
type ContentSourceRawData = Omit<ContentSourceData, 'models' | 'modelMap' | 'documents' | 'documentMap'>;
|
|
78
|
+
type ContentStoreEventQueue = ContentStoreEvent[];
|
|
79
|
+
|
|
80
|
+
const ContentStoreEventType = {
|
|
81
|
+
YamlModelFilesChange: 'yamlModelFilesChange',
|
|
82
|
+
PresetFilesChange: 'presetFilesChange',
|
|
83
|
+
ContentSourceInvalidateSchema: 'contentSourceInvalidateSchema',
|
|
84
|
+
ContentSourceContentChange: 'contentSourceContentChange'
|
|
85
|
+
} as const;
|
|
86
|
+
|
|
87
|
+
type ContentStoreEvent =
|
|
88
|
+
| {
|
|
89
|
+
eventName: typeof ContentStoreEventType.YamlModelFilesChange;
|
|
90
|
+
}
|
|
91
|
+
| {
|
|
92
|
+
eventName: typeof ContentStoreEventType.PresetFilesChange;
|
|
93
|
+
}
|
|
94
|
+
| {
|
|
95
|
+
eventName: typeof ContentStoreEventType.ContentSourceInvalidateSchema;
|
|
96
|
+
contentSourceId: string;
|
|
97
|
+
}
|
|
98
|
+
| {
|
|
99
|
+
eventName: typeof ContentStoreEventType.ContentSourceContentChange;
|
|
100
|
+
contentSourceId: string;
|
|
101
|
+
contentChanges: CSITypes.ContentChanges;
|
|
102
|
+
};
|
|
73
103
|
|
|
74
104
|
export const StackbitPresetModelName = 'stackbitPreset';
|
|
75
105
|
|
|
@@ -86,9 +116,9 @@ export class ContentStore {
|
|
|
86
116
|
private readonly onContentChangeCallback: (contentChanges: ContentStoreTypes.ContentChangeResult) => void;
|
|
87
117
|
private readonly handleConfigAssets: HandleConfigAssets;
|
|
88
118
|
private readonly devAppRestartNeeded?: () => void;
|
|
89
|
-
private contentSources:
|
|
119
|
+
private contentSources: BackCompatContentSourceInterface[] = [];
|
|
90
120
|
private contentSourceDataById: Record<string, ContentSourceData> = {};
|
|
91
|
-
private presetsContentSource?:
|
|
121
|
+
private presetsContentSource?: BackCompatContentSourceInterface;
|
|
92
122
|
private contentUpdatesWatchTimer: Timer;
|
|
93
123
|
private stackbitConfig: Config | null = null;
|
|
94
124
|
private yamlModels: Model[] = [];
|
|
@@ -96,6 +126,8 @@ export class ContentStore {
|
|
|
96
126
|
private modelExtensions: ModelExtension[] | null = null;
|
|
97
127
|
private presets: PresetMap = {};
|
|
98
128
|
private siteMapEntryGroups: SiteMapEntryGroups = {};
|
|
129
|
+
private processingContentSourcesPromise: DeferredPromise<void> | null = null;
|
|
130
|
+
private contentStoreEventQueue: ContentStoreEventQueue = [];
|
|
99
131
|
|
|
100
132
|
constructor(options: ContentSourceOptions) {
|
|
101
133
|
this.logger = options.logger.createLogger({ label: 'content-store' });
|
|
@@ -188,7 +220,7 @@ export class ContentStore {
|
|
|
188
220
|
*/
|
|
189
221
|
private handleTimerTimeout() {
|
|
190
222
|
for (const contentSourceInstance of this.contentSources) {
|
|
191
|
-
contentSourceInstance.stopWatchingContentUpdates();
|
|
223
|
+
contentSourceInstance.stopWatchingContentUpdates?.();
|
|
192
224
|
}
|
|
193
225
|
}
|
|
194
226
|
|
|
@@ -215,8 +247,6 @@ export class ContentStore {
|
|
|
215
247
|
async onFilesChange(updatedFiles: string[]): Promise<void> {
|
|
216
248
|
this.logger.debug('onFilesChange');
|
|
217
249
|
|
|
218
|
-
let schemaChanged = false;
|
|
219
|
-
|
|
220
250
|
if (this.stackbitConfig && !this.stackbitConfig.modelExtensions) {
|
|
221
251
|
// Check if any of the yaml models files were changed. If yaml model files were changed,
|
|
222
252
|
// reload them and merge them with models defined in stackbit config.
|
|
@@ -224,9 +254,11 @@ export class ContentStore {
|
|
|
224
254
|
const yamlModelsChanged = updatedFiles.find((updatedFile) => _.some(modelDirs, (modelDir) => updatedFile.startsWith(modelDir)));
|
|
225
255
|
if (yamlModelsChanged) {
|
|
226
256
|
this.logger.debug('identified change in stackbit model files');
|
|
227
|
-
schemaChanged = true;
|
|
228
257
|
this.yamlModels = await this.loadYamlModels({ stackbitConfig: this.stackbitConfig });
|
|
229
258
|
this.configModels = this.mergeConfigModels(this.stackbitConfig.models ?? [], this.yamlModels);
|
|
259
|
+
this.pushContentSourceEvent({
|
|
260
|
+
eventName: ContentStoreEventType.YamlModelFilesChange
|
|
261
|
+
});
|
|
230
262
|
}
|
|
231
263
|
}
|
|
232
264
|
|
|
@@ -236,62 +268,38 @@ export class ContentStore {
|
|
|
236
268
|
const presetsChanged = updatedFiles.find((updatedFile) => _.some(presetDirs, (presetDir) => updatedFile.startsWith(presetDir)));
|
|
237
269
|
if (presetsChanged && !this.usesContentSourcePresets()) {
|
|
238
270
|
this.logger.debug('identified change in stackbit preset files');
|
|
239
|
-
schemaChanged = true;
|
|
240
271
|
this.presets = await this.loadPresetsFromConfig({ stackbitConfig: this.stackbitConfig });
|
|
272
|
+
this.pushContentSourceEvent({
|
|
273
|
+
eventName: ContentStoreEventType.PresetFilesChange
|
|
274
|
+
});
|
|
241
275
|
}
|
|
242
276
|
}
|
|
243
277
|
|
|
244
|
-
const contentSourceIdsWithChangedSchema: string[] = [];
|
|
245
|
-
const contentChangeEvents: { contentSourceId: string; contentChangeEvent: CSITypes.ContentChangeEvent }[] = [];
|
|
246
|
-
|
|
247
278
|
for (const contentSourceInstance of this.contentSources) {
|
|
248
279
|
const contentSourceId = getContentSourceIdForContentSource(contentSourceInstance);
|
|
249
280
|
this.logger.debug(`call onFilesChange for contentSource: ${contentSourceId}`);
|
|
250
|
-
const onFilesChangeResult =
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
//
|
|
254
|
-
//
|
|
255
|
-
if (onFilesChangeResult.
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
281
|
+
const onFilesChangeResult = await contentSourceInstance.onFilesChange({ updatedFiles: updatedFiles });
|
|
282
|
+
|
|
283
|
+
// If the schema was changed in a specific content source, there is no need to process and notify for content changes.
|
|
284
|
+
// Because the schema changes will trigger loadContentSourcesAndProcessData and reload all models and content of that
|
|
285
|
+
// content source and send the schemaChanged notification that will cause the Studio to reload the schema and documents.
|
|
286
|
+
if (onFilesChangeResult.invalidateSchema) {
|
|
287
|
+
this.logger.debug(`schema was invalidated for contentSource: ${contentSourceId}`);
|
|
288
|
+
this.pushContentSourceEvent({
|
|
289
|
+
eventName: ContentStoreEventType.ContentSourceInvalidateSchema,
|
|
290
|
+
contentSourceId: contentSourceId
|
|
291
|
+
});
|
|
292
|
+
} else if (!isContentChangesEmpty(onFilesChangeResult.contentChanges)) {
|
|
293
|
+
this.logger.debug(`content was changed for contentSource: ${contentSourceId}`);
|
|
294
|
+
this.pushContentSourceEvent({
|
|
295
|
+
eventName: ContentStoreEventType.ContentSourceContentChange,
|
|
296
|
+
contentSourceId: contentSourceId,
|
|
297
|
+
contentChanges: onFilesChangeResult.contentChanges
|
|
298
|
+
});
|
|
260
299
|
}
|
|
261
300
|
}
|
|
262
301
|
|
|
263
|
-
|
|
264
|
-
// The processData will update the store with the latest data. And once the Studio receives
|
|
265
|
-
// the schemaChanged notification it will reload all the models and the documents with their latest state.
|
|
266
|
-
if (schemaChanged) {
|
|
267
|
-
await this.loadContentSourcesAndProcessData({ init: false, contentSourceIds: contentSourceIdsWithChangedSchema });
|
|
268
|
-
|
|
269
|
-
this.onSchemaChangeCallback();
|
|
270
|
-
} else {
|
|
271
|
-
const contentChanges = contentChangeEvents.reduce((contentChanges: ContentStoreTypes.ContentChangeResult, { contentSourceId, contentChangeEvent }) => {
|
|
272
|
-
const contentChangeResult = this.onContentChange(contentSourceId, contentChangeEvent);
|
|
273
|
-
return {
|
|
274
|
-
updatedDocuments: contentChanges.updatedDocuments.concat(contentChangeResult.updatedDocuments),
|
|
275
|
-
updatedAssets: contentChanges.updatedAssets.concat(contentChangeResult.updatedAssets),
|
|
276
|
-
deletedDocuments: contentChanges.deletedDocuments.concat(contentChangeResult.deletedDocuments),
|
|
277
|
-
deletedAssets: contentChanges.deletedAssets.concat(contentChangeResult.deletedAssets)
|
|
278
|
-
};
|
|
279
|
-
}, {
|
|
280
|
-
updatedDocuments: [],
|
|
281
|
-
updatedAssets: [],
|
|
282
|
-
deletedDocuments: [],
|
|
283
|
-
deletedAssets: []
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
this.siteMapEntryGroups = await updateSiteMapEntriesWithContentChanges({
|
|
287
|
-
siteMapEntryGroups: this.siteMapEntryGroups,
|
|
288
|
-
contentChanges,
|
|
289
|
-
stackbitConfig: this.stackbitConfig,
|
|
290
|
-
contentSourceDataById: this.contentSourceDataById
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
this.onContentChangeCallback(contentChanges);
|
|
294
|
-
}
|
|
302
|
+
await this.processContentStoreEvents();
|
|
295
303
|
}
|
|
296
304
|
|
|
297
305
|
private async loadYamlModels({ stackbitConfig }: { stackbitConfig: Config }): Promise<Model[]> {
|
|
@@ -371,19 +379,20 @@ export class ContentStore {
|
|
|
371
379
|
*/
|
|
372
380
|
private async loadContentSourcesAndProcessData({ init, contentSourceIds }: { init: boolean; contentSourceIds?: string[] }) {
|
|
373
381
|
this.logger.debug('loadContentSourcesAndProcessData', { init, contentSourceIds });
|
|
382
|
+
this.processingContentSourcesPromise = deferredPromise();
|
|
374
383
|
|
|
375
|
-
const contentSources = this.stackbitConfig?.contentSources ?? []
|
|
384
|
+
const contentSources = (this.stackbitConfig?.contentSources ?? []).map((contentSource) => {
|
|
385
|
+
return backwardCompatibleContentSource(contentSource);
|
|
386
|
+
});
|
|
376
387
|
|
|
377
|
-
const promises = contentSources.map(
|
|
378
|
-
(contentSourceInstance)
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
return Promise.resolve(_.omit(this.contentSourceDataById[contentSourceId], ['models', 'modelMap', 'documents', 'documentMap']));
|
|
384
|
-
}
|
|
388
|
+
const promises = contentSources.map((contentSourceInstance): Promise<ContentSourceRawData> => {
|
|
389
|
+
const contentSourceId = getContentSourceIdForContentSource(contentSourceInstance);
|
|
390
|
+
if (init || !contentSourceIds || contentSourceIds.includes(contentSourceId)) {
|
|
391
|
+
return this.loadContentSourceData({ contentSourceInstance, init });
|
|
392
|
+
} else {
|
|
393
|
+
return Promise.resolve(_.omit(this.contentSourceDataById[contentSourceId], ['models', 'modelMap', 'documents', 'documentMap']));
|
|
385
394
|
}
|
|
386
|
-
);
|
|
395
|
+
});
|
|
387
396
|
|
|
388
397
|
const contentSourceRawDataArr = await Promise.all(promises);
|
|
389
398
|
|
|
@@ -391,13 +400,10 @@ export class ContentStore {
|
|
|
391
400
|
for (let i = 0; i < contentSources.length; i++) {
|
|
392
401
|
const contentSourceDataRaw = contentSourceRawDataArr[i];
|
|
393
402
|
if (contentSourceDataRaw?.csiModelMap?.[StackbitPresetModelName]) {
|
|
394
|
-
this.presetsContentSource =
|
|
395
|
-
if
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
if (init || !contentSourceIds || contentSourceIds.includes(contentSourceId)) {
|
|
399
|
-
this.presets = await this.loadPresetsFromContentSource(contentSourceDataRaw);
|
|
400
|
-
}
|
|
403
|
+
this.presetsContentSource = contentSourceDataRaw.instance;
|
|
404
|
+
// reload presets from content source only if needed
|
|
405
|
+
if (init || !contentSourceIds || contentSourceIds.includes(contentSourceDataRaw.id)) {
|
|
406
|
+
this.presets = await this.loadPresetsFromContentSource(contentSourceDataRaw);
|
|
401
407
|
}
|
|
402
408
|
break;
|
|
403
409
|
}
|
|
@@ -422,47 +428,302 @@ export class ContentStore {
|
|
|
422
428
|
stackbitConfig: this.stackbitConfig,
|
|
423
429
|
contentSourceDataById: this.contentSourceDataById
|
|
424
430
|
});
|
|
431
|
+
|
|
432
|
+
if (!init) {
|
|
433
|
+
this.onSchemaChangeCallback();
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const processingPromise = this.processingContentSourcesPromise;
|
|
437
|
+
this.processingContentSourcesPromise = null;
|
|
438
|
+
|
|
439
|
+
// Do not "await" on processContentStoreEvents as it may introduce a deadlock with
|
|
440
|
+
// the nested loadContentSourcesAndProcessData call which is wrapped by deferWhileRunning.
|
|
441
|
+
this.processContentStoreEvents()
|
|
442
|
+
.catch((error) => {
|
|
443
|
+
this.logger.error('error processing content source events', { error });
|
|
444
|
+
})
|
|
445
|
+
.finally(() => {
|
|
446
|
+
processingPromise.resolve();
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
private async processContentStoreEvents() {
|
|
451
|
+
// If the ContentStore is currently loading content sources, return to prevent parallel data updates.
|
|
452
|
+
// This method will be called once current loading cycle ends.
|
|
453
|
+
if (this.processingContentSourcesPromise) {
|
|
454
|
+
return this.processingContentSourcesPromise.promise;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
const contentSourceIdsWithInvalidatedSchema: string[] = [];
|
|
458
|
+
const contentChanges: ContentStoreTypes.ContentChangeResult = {
|
|
459
|
+
updatedDocuments: [],
|
|
460
|
+
updatedAssets: [],
|
|
461
|
+
deletedDocuments: [],
|
|
462
|
+
deletedAssets: []
|
|
463
|
+
};
|
|
464
|
+
let invalidateSchema = false;
|
|
465
|
+
let presetsUpdated = false;
|
|
466
|
+
|
|
467
|
+
const contentSourceEvents = this.contentStoreEventQueue;
|
|
468
|
+
this.contentStoreEventQueue = [];
|
|
469
|
+
for (const contentSourceEvent of contentSourceEvents) {
|
|
470
|
+
if (
|
|
471
|
+
contentSourceEvent.eventName === ContentStoreEventType.YamlModelFilesChange ||
|
|
472
|
+
contentSourceEvent.eventName === ContentStoreEventType.PresetFilesChange
|
|
473
|
+
) {
|
|
474
|
+
invalidateSchema = true;
|
|
475
|
+
} else if (contentSourceEvent.eventName === ContentStoreEventType.ContentSourceInvalidateSchema) {
|
|
476
|
+
invalidateSchema = true;
|
|
477
|
+
contentSourceIdsWithInvalidatedSchema.push(contentSourceEvent.contentSourceId);
|
|
478
|
+
} else if (contentSourceEvent.eventName === ContentStoreEventType.ContentSourceContentChange) {
|
|
479
|
+
const result = this.onContentChange(contentSourceEvent.contentSourceId, contentSourceEvent.contentChanges);
|
|
480
|
+
contentChanges.updatedDocuments = contentChanges.updatedDocuments.concat(result.contentChangeResult.updatedDocuments);
|
|
481
|
+
contentChanges.updatedAssets = contentChanges.updatedAssets.concat(result.contentChangeResult.updatedAssets);
|
|
482
|
+
contentChanges.deletedDocuments = contentChanges.deletedDocuments.concat(result.contentChangeResult.deletedDocuments);
|
|
483
|
+
contentChanges.deletedAssets = contentChanges.deletedAssets.concat(result.contentChangeResult.deletedAssets);
|
|
484
|
+
if (result.presetsUpdated) {
|
|
485
|
+
presetsUpdated = true;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// If the schema was changed, call loadContentSourcesAndProcessData method, this will reload all the SiteMapEntries and call the onSchemaChangeCallback.
|
|
491
|
+
// As soon as the Studio receives the schemaChanged notification it will reload all the models and the documents.
|
|
492
|
+
if (invalidateSchema) {
|
|
493
|
+
await this.loadContentSourcesAndProcessData({
|
|
494
|
+
init: false,
|
|
495
|
+
contentSourceIds: contentSourceIdsWithInvalidatedSchema
|
|
496
|
+
});
|
|
497
|
+
} else {
|
|
498
|
+
// If the schema wasn't changed, update SiteMapEntries with the changed content.
|
|
499
|
+
this.siteMapEntryGroups = await updateSiteMapEntriesWithContentChanges({
|
|
500
|
+
siteMapEntryGroups: this.siteMapEntryGroups,
|
|
501
|
+
contentChanges: contentChanges,
|
|
502
|
+
stackbitConfig: this.stackbitConfig,
|
|
503
|
+
contentSourceDataById: this.contentSourceDataById
|
|
504
|
+
});
|
|
505
|
+
// If presets were updated, call onSchemaChangeCallback to notify the Studio.
|
|
506
|
+
// The Studio will refresh the models and the documents, so no need to notify
|
|
507
|
+
// content changes in this case.
|
|
508
|
+
if (presetsUpdated) {
|
|
509
|
+
this.onSchemaChangeCallback();
|
|
510
|
+
} else if (!isContentChangeResultEmpty(contentChanges)) {
|
|
511
|
+
this.onContentChangeCallback(contentChanges);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
private pushContentSourceEvent(contentStoreEvent: ContentStoreEvent) {
|
|
517
|
+
if (contentStoreEvent.eventName === ContentStoreEventType.ContentSourceContentChange) {
|
|
518
|
+
// If a content source enqueued the 'contentSourceInvalidateSchema' event,
|
|
519
|
+
// don't push the 'contentSourceContentChange' event, because 'contentSourceInvalidateSchema'
|
|
520
|
+
// will reload all the content source data.
|
|
521
|
+
const hasContentSourceSchemaChangeEvent = this.contentStoreEventQueue.find(
|
|
522
|
+
(event) =>
|
|
523
|
+
event.eventName === ContentStoreEventType.ContentSourceInvalidateSchema && event.contentSourceId === contentStoreEvent.contentSourceId
|
|
524
|
+
);
|
|
525
|
+
if (!hasContentSourceSchemaChangeEvent) {
|
|
526
|
+
this.contentStoreEventQueue.push(contentStoreEvent);
|
|
527
|
+
}
|
|
528
|
+
} else if (contentStoreEvent.eventName === ContentStoreEventType.ContentSourceInvalidateSchema) {
|
|
529
|
+
// Clear any 'contentSourceContentChange' events for a content source,
|
|
530
|
+
// the 'contentSourceInvalidateSchema' will reload all the content source data.
|
|
531
|
+
this.clearEventsForContentSourceId(contentStoreEvent.contentSourceId);
|
|
532
|
+
this.contentStoreEventQueue.push(contentStoreEvent);
|
|
533
|
+
} else if (contentStoreEvent.eventName === ContentStoreEventType.YamlModelFilesChange) {
|
|
534
|
+
this.contentStoreEventQueue = this.contentStoreEventQueue.filter((event) => event.eventName !== ContentStoreEventType.YamlModelFilesChange);
|
|
535
|
+
this.contentStoreEventQueue.push(contentStoreEvent);
|
|
536
|
+
} else if (contentStoreEvent.eventName === ContentStoreEventType.PresetFilesChange) {
|
|
537
|
+
this.contentStoreEventQueue = this.contentStoreEventQueue.filter((event) => event.eventName !== ContentStoreEventType.PresetFilesChange);
|
|
538
|
+
this.contentStoreEventQueue.push(contentStoreEvent);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
private clearEventsForContentSourceId(contentSourceId: string) {
|
|
543
|
+
this.contentStoreEventQueue = this.contentStoreEventQueue.filter((contentSourceEvent) => {
|
|
544
|
+
if (
|
|
545
|
+
contentSourceEvent.eventName === ContentStoreEventType.ContentSourceContentChange ||
|
|
546
|
+
contentSourceEvent.eventName === ContentStoreEventType.ContentSourceInvalidateSchema
|
|
547
|
+
) {
|
|
548
|
+
return contentSourceEvent.contentSourceId !== contentSourceId;
|
|
549
|
+
}
|
|
550
|
+
return true;
|
|
551
|
+
});
|
|
425
552
|
}
|
|
426
553
|
|
|
427
554
|
private async loadContentSourceData({
|
|
428
555
|
contentSourceInstance,
|
|
429
556
|
init
|
|
430
557
|
}: {
|
|
431
|
-
contentSourceInstance:
|
|
558
|
+
contentSourceInstance: BackCompatContentSourceInterface;
|
|
432
559
|
init: boolean;
|
|
433
560
|
}): Promise<ContentSourceRawData> {
|
|
434
561
|
const contentSourceId = getContentSourceIdForContentSource(contentSourceInstance);
|
|
435
562
|
this.logger.debug('loadContentSourceData', { contentSourceId, init });
|
|
436
563
|
|
|
564
|
+
// clear content source events emitted by this content source because all the content source data is reloaded
|
|
565
|
+
this.clearEventsForContentSourceId(contentSourceId);
|
|
566
|
+
|
|
567
|
+
const localCache: Partial<
|
|
568
|
+
Pick<ContentSourceRawData, 'csiSchema' | 'csiModels' | 'csiModelMap' | 'locales' | 'csiDocuments' | 'csiDocumentMap' | 'csiAssets' | 'csiAssetMap'>
|
|
569
|
+
> = {};
|
|
570
|
+
|
|
571
|
+
const getContentSourceDataForCurrentInstance = (methodName: keyof CSITypes.Cache | 'getModelMap' | 'getDocument' | 'getAsset') => {
|
|
572
|
+
const contentSourceData = this.contentSourceDataById[contentSourceId];
|
|
573
|
+
if (!contentSourceData) {
|
|
574
|
+
// When loading the content sources for the first time, this.contentSourceDataById will be empty.
|
|
575
|
+
// However, while being loaded, content sources may call cache methods, for example a content
|
|
576
|
+
// source may call getModelByName from within getDocuments. In this case, return locally cached data.
|
|
577
|
+
if (this.processingContentSourcesPromise) {
|
|
578
|
+
return localCache;
|
|
579
|
+
}
|
|
580
|
+
const atLine = getErrorAtLine(2, getContentSourceDataForCurrentInstance);
|
|
581
|
+
const errorMessage = `Error executing 'cache.${methodName}' method${atLine}. The content source with id '${contentSourceId}' was not found.`;
|
|
582
|
+
this.logger.error(errorMessage);
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
if (contentSourceData.instance !== contentSourceInstance) {
|
|
586
|
+
const atLine = getErrorAtLine(2, getContentSourceDataForCurrentInstance);
|
|
587
|
+
const errorMessage =
|
|
588
|
+
`Content source life cycle error! The content source with id '${contentSourceId}' called the 'cache.${methodName}' ` +
|
|
589
|
+
`method${atLine} after the destroy() method was called.`;
|
|
590
|
+
this.logger.error(errorMessage);
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
// While loading the content source, it may call cache methods, when this happens, return the
|
|
594
|
+
// stale data overridden with the most frequent loaded data
|
|
595
|
+
if (this.processingContentSourcesPromise) {
|
|
596
|
+
return Object.assign(contentSourceData, localCache);
|
|
597
|
+
}
|
|
598
|
+
return contentSourceData;
|
|
599
|
+
};
|
|
600
|
+
|
|
601
|
+
const cache: CSITypes.Cache = {
|
|
602
|
+
getSchema: () => {
|
|
603
|
+
const contentSourceData = getContentSourceDataForCurrentInstance('getSchema');
|
|
604
|
+
if (!contentSourceData?.csiSchema) {
|
|
605
|
+
const atLine = getErrorAtLine(1);
|
|
606
|
+
const errorMessage =
|
|
607
|
+
`Content source life cycle error! The content source with id '${contentSourceId}' called the 'cache.getSchema' ` +
|
|
608
|
+
`method${atLine} before the content source's getSchema() method was called.`;
|
|
609
|
+
this.logger.error(errorMessage);
|
|
610
|
+
return { models: [], locales: [], context: null };
|
|
611
|
+
}
|
|
612
|
+
return contentSourceData.csiSchema;
|
|
613
|
+
},
|
|
614
|
+
getModelByName: (modelName) => {
|
|
615
|
+
const contentSourceData = getContentSourceDataForCurrentInstance('getModelByName');
|
|
616
|
+
if (!contentSourceData?.csiModelMap) {
|
|
617
|
+
const atLine = getErrorAtLine(1);
|
|
618
|
+
const errorMessage =
|
|
619
|
+
`Content source life cycle error! The content source with id '${contentSourceId}' called the 'cache.getModelByName' ` +
|
|
620
|
+
`method${atLine} before the content source's getSchema() method was called.`;
|
|
621
|
+
this.logger.error(errorMessage);
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
return contentSourceData.csiModelMap[modelName];
|
|
625
|
+
},
|
|
626
|
+
getDocuments: () => {
|
|
627
|
+
const contentSourceData = getContentSourceDataForCurrentInstance('getDocuments');
|
|
628
|
+
return contentSourceData?.csiDocuments ?? [];
|
|
629
|
+
},
|
|
630
|
+
getDocumentById: (documentId) => {
|
|
631
|
+
const contentSourceData = getContentSourceDataForCurrentInstance('getDocumentById');
|
|
632
|
+
return contentSourceData?.csiDocumentMap?.[documentId];
|
|
633
|
+
},
|
|
634
|
+
getAssets: () => {
|
|
635
|
+
const contentSourceData = getContentSourceDataForCurrentInstance('getAssets');
|
|
636
|
+
return contentSourceData?.csiAssets ?? [];
|
|
637
|
+
},
|
|
638
|
+
getAssetById: (assetId) => {
|
|
639
|
+
const contentSourceData = getContentSourceDataForCurrentInstance('getAssetById');
|
|
640
|
+
return contentSourceData?.csiAssetMap?.[assetId];
|
|
641
|
+
},
|
|
642
|
+
updateContent: async (contentChanges: CSITypes.ContentChanges): Promise<void> => {
|
|
643
|
+
const contentSourceData = getContentSourceDataForCurrentInstance('updateContent');
|
|
644
|
+
if (!contentSourceData) {
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
this.logger.debug('content source called updateContent', { contentSourceId });
|
|
648
|
+
this.pushContentSourceEvent({
|
|
649
|
+
eventName: ContentStoreEventType.ContentSourceContentChange,
|
|
650
|
+
contentSourceId: contentSourceId,
|
|
651
|
+
contentChanges: contentChanges
|
|
652
|
+
});
|
|
653
|
+
await this.processContentStoreEvents();
|
|
654
|
+
},
|
|
655
|
+
|
|
656
|
+
invalidateSchema: async () => {
|
|
657
|
+
const contentSourceData = getContentSourceDataForCurrentInstance('invalidateSchema');
|
|
658
|
+
if (!contentSourceData) {
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
this.logger.debug('content source called invalidateSchema', { contentSourceId });
|
|
662
|
+
this.pushContentSourceEvent({
|
|
663
|
+
eventName: ContentStoreEventType.ContentSourceInvalidateSchema,
|
|
664
|
+
contentSourceId: contentSourceId
|
|
665
|
+
});
|
|
666
|
+
await this.processContentStoreEvents();
|
|
667
|
+
}
|
|
668
|
+
};
|
|
669
|
+
|
|
437
670
|
if (init) {
|
|
671
|
+
this.userLogger.info(
|
|
672
|
+
`Initializing content source: ${contentSourceInstance.getContentSourceType()} (project: ${contentSourceInstance.getProjectId()})`
|
|
673
|
+
);
|
|
674
|
+
// When stackbit.config.js reloads, it loads new content source instances.
|
|
675
|
+
// Previously loaded content source instances must be destroyed.
|
|
676
|
+
const contentSourceData = this.contentSourceDataById[contentSourceId];
|
|
677
|
+
if (contentSourceData && contentSourceData.instance !== contentSourceInstance) {
|
|
678
|
+
this.logger.debug('destroy previous content source instance', { contentSourceId });
|
|
679
|
+
try {
|
|
680
|
+
contentSourceData.instance.stopWatchingContentUpdates?.();
|
|
681
|
+
await contentSourceData.instance.destroy();
|
|
682
|
+
} catch (error) {
|
|
683
|
+
this.logger.debug('error destroying content source instance', { error });
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// If an instance that wasn't destroyed calls one of the InitOptions method don't return any data.
|
|
438
688
|
await contentSourceInstance.init({
|
|
439
689
|
logger: this.logger,
|
|
440
690
|
userLogger: this.userLogger,
|
|
441
|
-
userCommandSpawner: this.userCommandSpawner,
|
|
442
691
|
localDev: this.localDev,
|
|
443
692
|
webhookUrl: this.getWebhookUrl(contentSourceInstance.getContentSourceType(), contentSourceInstance.getProjectId()),
|
|
693
|
+
userCommandSpawner: this.userCommandSpawner,
|
|
444
694
|
devAppRestartNeeded: this.devAppRestartNeeded,
|
|
695
|
+
cache: cache,
|
|
445
696
|
runCommand: this.runCommand,
|
|
446
697
|
git: this.git
|
|
447
698
|
});
|
|
448
699
|
} else {
|
|
449
|
-
contentSourceInstance.stopWatchingContentUpdates();
|
|
450
700
|
await contentSourceInstance.reset();
|
|
451
701
|
}
|
|
452
702
|
|
|
453
|
-
const
|
|
703
|
+
const version = await contentSourceInstance.getVersion();
|
|
704
|
+
const csiSchema = await contentSourceInstance.getSchema();
|
|
705
|
+
const csiModels = csiSchema.models;
|
|
454
706
|
const csiModelMap = _.keyBy(csiModels, 'name');
|
|
455
|
-
|
|
456
|
-
const locales = await contentSourceInstance.getLocales();
|
|
707
|
+
const locales = csiSchema.locales;
|
|
457
708
|
const defaultLocaleCode = locales?.find((locale) => locale.default)?.code;
|
|
458
709
|
|
|
710
|
+
localCache.csiSchema = csiSchema;
|
|
711
|
+
localCache.csiModels = csiModels;
|
|
712
|
+
localCache.csiModelMap = csiModelMap;
|
|
713
|
+
localCache.locales = locales;
|
|
714
|
+
|
|
459
715
|
const csiDocuments = await contentSourceInstance.getDocuments({ modelMap: csiModelMap });
|
|
460
|
-
const csiAssets = await contentSourceInstance.getAssets();
|
|
461
716
|
const csiDocumentMap = _.keyBy(csiDocuments, 'id');
|
|
717
|
+
localCache.csiDocuments = csiDocuments;
|
|
718
|
+
localCache.csiDocumentMap = csiDocumentMap;
|
|
719
|
+
|
|
720
|
+
const csiAssets = await contentSourceInstance.getAssets();
|
|
462
721
|
const csiAssetMap = _.keyBy(csiAssets, 'id');
|
|
722
|
+
localCache.csiAssets = csiAssets;
|
|
723
|
+
localCache.csiAssetMap = csiAssetMap;
|
|
463
724
|
|
|
464
725
|
const contentStoreAssets = mapCSIAssetsToStoreAssets({
|
|
465
|
-
csiAssets,
|
|
726
|
+
csiAssets: csiAssets,
|
|
466
727
|
contentSourceInstance,
|
|
467
728
|
defaultLocaleCode
|
|
468
729
|
});
|
|
@@ -471,56 +732,47 @@ export class ContentStore {
|
|
|
471
732
|
this.logger.debug('loaded content source data', {
|
|
472
733
|
contentSourceId,
|
|
473
734
|
defaultLocaleCode,
|
|
474
|
-
localesCount: locales
|
|
735
|
+
localesCount: locales?.length ?? 0,
|
|
475
736
|
modelCount: csiModels.length,
|
|
476
737
|
documentCount: csiDocuments.length,
|
|
477
738
|
assetCount: csiAssets.length
|
|
478
739
|
});
|
|
479
740
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
},
|
|
506
|
-
onSchemaChange: async () => {
|
|
507
|
-
if (this.contentSourceDataById[contentSourceId]?.instance !== contentSourceInstance) {
|
|
508
|
-
this.logger.debug('old content source called onSchemaChange', { contentSourceId });
|
|
509
|
-
return;
|
|
510
|
-
}
|
|
511
|
-
this.logger.debug('content source called onSchemaChange', { contentSourceId });
|
|
512
|
-
await this.loadContentSourcesAndProcessData({ init: false, contentSourceIds: [contentSourceId] });
|
|
513
|
-
this.onSchemaChangeCallback();
|
|
514
|
-
}
|
|
515
|
-
});
|
|
741
|
+
if (init) {
|
|
742
|
+
this.userLogger.info(
|
|
743
|
+
`→ Loaded content source data: ${csiModels.length} model${csiModels.length !== 1 ? 's' : ''}, ${csiDocuments.length} document${
|
|
744
|
+
csiDocuments.length !== 1 ? 's' : ''
|
|
745
|
+
} and ${csiAssets.length} asset${csiAssets.length !== 1 ? 's' : ''}`
|
|
746
|
+
);
|
|
747
|
+
|
|
748
|
+
// backward compatibility
|
|
749
|
+
contentSourceInstance.startWatchingContentUpdates?.({
|
|
750
|
+
getModelMap: () => {
|
|
751
|
+
const contentSourceData = getContentSourceDataForCurrentInstance('getModelMap');
|
|
752
|
+
return contentSourceData?.csiModelMap ?? {};
|
|
753
|
+
},
|
|
754
|
+
getDocument: ({ documentId }) => {
|
|
755
|
+
const contentSourceData = getContentSourceDataForCurrentInstance('getDocument');
|
|
756
|
+
return contentSourceData?.csiDocumentMap?.[documentId];
|
|
757
|
+
},
|
|
758
|
+
getAsset: ({ assetId }) => {
|
|
759
|
+
const contentSourceData = getContentSourceDataForCurrentInstance('getAsset');
|
|
760
|
+
return contentSourceData?.csiAssetMap?.[assetId];
|
|
761
|
+
},
|
|
762
|
+
onContentChange: cache.updateContent,
|
|
763
|
+
onSchemaChange: cache.invalidateSchema
|
|
764
|
+
});
|
|
765
|
+
}
|
|
516
766
|
|
|
517
767
|
return {
|
|
518
768
|
id: contentSourceId,
|
|
769
|
+
version: version,
|
|
519
770
|
srcType: contentSourceInstance.getContentSourceType(),
|
|
520
771
|
srcProjectId: contentSourceInstance.getProjectId(),
|
|
521
772
|
instance: contentSourceInstance,
|
|
522
773
|
locales: locales,
|
|
523
774
|
defaultLocaleCode: defaultLocaleCode,
|
|
775
|
+
csiSchema: csiSchema,
|
|
524
776
|
csiModels: csiModels,
|
|
525
777
|
csiModelMap: csiModelMap,
|
|
526
778
|
csiDocuments: csiDocuments,
|
|
@@ -532,18 +784,26 @@ export class ContentStore {
|
|
|
532
784
|
};
|
|
533
785
|
}
|
|
534
786
|
|
|
535
|
-
private onContentChange(
|
|
536
|
-
|
|
537
|
-
|
|
787
|
+
private onContentChange(
|
|
788
|
+
contentSourceId: string,
|
|
789
|
+
contentChanges: CSITypes.ContentChanges
|
|
790
|
+
): { contentChangeResult: ContentStoreTypes.ContentChangeResult; presetsUpdated: boolean } {
|
|
538
791
|
// certain content changes, like preset changes are interpreted as schema changes
|
|
539
|
-
let
|
|
792
|
+
let presetsUpdated = false;
|
|
793
|
+
|
|
794
|
+
const contentChangesReq: Required<CSITypes.ContentChanges> = {
|
|
795
|
+
documents: contentChanges.documents ?? [],
|
|
796
|
+
assets: contentChanges.assets ?? [],
|
|
797
|
+
deletedDocumentIds: contentChanges.deletedDocumentIds ?? [],
|
|
798
|
+
deletedAssetIds: contentChanges.deletedAssetIds ?? []
|
|
799
|
+
};
|
|
540
800
|
|
|
541
801
|
this.logger.debug('onContentChange', {
|
|
542
802
|
contentSourceId,
|
|
543
|
-
documentCount:
|
|
544
|
-
assetCount:
|
|
545
|
-
deletedDocumentCount:
|
|
546
|
-
deletedAssetCount:
|
|
803
|
+
documentCount: contentChangesReq.documents.length,
|
|
804
|
+
assetCount: contentChangesReq.assets.length,
|
|
805
|
+
deletedDocumentCount: contentChangesReq.deletedDocumentIds.length,
|
|
806
|
+
deletedAssetCount: contentChangesReq.deletedAssetIds.length
|
|
547
807
|
});
|
|
548
808
|
|
|
549
809
|
const result: ContentStoreTypes.ContentChangeResult = {
|
|
@@ -556,11 +816,11 @@ export class ContentStore {
|
|
|
556
816
|
const contentSourceData = this.getContentSourceDataByIdOrThrow(contentSourceId);
|
|
557
817
|
|
|
558
818
|
// update contentSourceData with deleted documents
|
|
559
|
-
|
|
819
|
+
contentChangesReq.deletedDocumentIds.forEach((docId) => {
|
|
560
820
|
// remove preset, make sure there is something to remove first because
|
|
561
821
|
// were explicitly calling onContentChange from deletePreset as well
|
|
562
822
|
if (this.presets[docId] && contentSourceData.csiDocumentMap[docId]?.modelName === StackbitPresetModelName) {
|
|
563
|
-
|
|
823
|
+
presetsUpdated = true;
|
|
564
824
|
const preset = this.presets[docId]!;
|
|
565
825
|
const model = contentSourceData.modelMap[preset.modelName];
|
|
566
826
|
delete this.presets[docId];
|
|
@@ -590,7 +850,7 @@ export class ContentStore {
|
|
|
590
850
|
});
|
|
591
851
|
|
|
592
852
|
// update contentSourceData with deleted assets
|
|
593
|
-
|
|
853
|
+
contentChangesReq.deletedAssetIds.forEach((assetId) => {
|
|
594
854
|
// delete document from asset map
|
|
595
855
|
delete contentSourceData.assetMap[assetId];
|
|
596
856
|
delete contentSourceData.csiAssetMap[assetId];
|
|
@@ -611,9 +871,9 @@ export class ContentStore {
|
|
|
611
871
|
});
|
|
612
872
|
|
|
613
873
|
// map csi documents through stackbitConfig.mapDocuments
|
|
614
|
-
let mappedDocs =
|
|
874
|
+
let mappedDocs = contentChangesReq.documents;
|
|
615
875
|
if (this.stackbitConfig?.mapDocuments) {
|
|
616
|
-
const csiDocumentsWithSource =
|
|
876
|
+
const csiDocumentsWithSource = contentChangesReq.documents.map(
|
|
617
877
|
(csiDocument): CSITypes.DocumentWithSource => ({
|
|
618
878
|
srcType: contentSourceData.srcType,
|
|
619
879
|
srcProjectId: contentSourceData.srcProjectId,
|
|
@@ -621,15 +881,13 @@ export class ContentStore {
|
|
|
621
881
|
})
|
|
622
882
|
);
|
|
623
883
|
|
|
624
|
-
const modelsWithSource = contentSourceData.models.map(
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
}
|
|
632
|
-
);
|
|
884
|
+
const modelsWithSource = contentSourceData.models.map((model): CSITypes.ModelWithSource => {
|
|
885
|
+
return {
|
|
886
|
+
srcType: contentSourceData.srcType,
|
|
887
|
+
srcProjectId: contentSourceData.srcProjectId,
|
|
888
|
+
...model
|
|
889
|
+
};
|
|
890
|
+
});
|
|
633
891
|
|
|
634
892
|
mappedDocs =
|
|
635
893
|
this.stackbitConfig?.mapDocuments?.({
|
|
@@ -643,24 +901,28 @@ export class ContentStore {
|
|
|
643
901
|
csiDocuments: mappedDocs,
|
|
644
902
|
contentSourceInstance: contentSourceData.instance,
|
|
645
903
|
modelMap: contentSourceData.modelMap,
|
|
646
|
-
defaultLocaleCode: contentSourceData.defaultLocaleCode
|
|
904
|
+
defaultLocaleCode: contentSourceData.defaultLocaleCode,
|
|
905
|
+
createConfigDelegate: getCreateConfigDelegateThunk({
|
|
906
|
+
getContentSourceDataById: () => this.contentSourceDataById,
|
|
907
|
+
logger: this.userLogger
|
|
908
|
+
})
|
|
647
909
|
});
|
|
648
910
|
const assets = mapCSIAssetsToStoreAssets({
|
|
649
|
-
csiAssets:
|
|
911
|
+
csiAssets: contentChangesReq.assets,
|
|
650
912
|
contentSourceInstance: contentSourceData.instance,
|
|
651
913
|
defaultLocaleCode: contentSourceData.defaultLocaleCode
|
|
652
914
|
});
|
|
653
915
|
|
|
654
916
|
// update contentSourceData with new or updated documents and assets
|
|
655
|
-
Object.assign(contentSourceData.csiDocumentMap, _.keyBy(
|
|
656
|
-
Object.assign(contentSourceData.csiAssetMap, _.keyBy(
|
|
917
|
+
Object.assign(contentSourceData.csiDocumentMap, _.keyBy(contentChangesReq.documents, 'id'));
|
|
918
|
+
Object.assign(contentSourceData.csiAssetMap, _.keyBy(contentChangesReq.assets, 'id'));
|
|
657
919
|
Object.assign(contentSourceData.documentMap, _.keyBy(documents, 'srcObjectId'));
|
|
658
920
|
Object.assign(contentSourceData.assetMap, _.keyBy(assets, 'srcObjectId'));
|
|
659
921
|
|
|
660
922
|
for (let idx = 0; idx < documents.length; idx++) {
|
|
661
923
|
// the indexes of mapped documents and documents from changeEvent are the same
|
|
662
924
|
const document = documents[idx]!;
|
|
663
|
-
const csiDocument =
|
|
925
|
+
const csiDocument = contentChangesReq.documents[idx]!;
|
|
664
926
|
const dataIndex = contentSourceData.documents.findIndex((existingDoc) => existingDoc.srcObjectId === document.srcObjectId);
|
|
665
927
|
if (dataIndex === -1) {
|
|
666
928
|
contentSourceData.documents.push(document);
|
|
@@ -670,7 +932,7 @@ export class ContentStore {
|
|
|
670
932
|
contentSourceData.csiDocuments.splice(dataIndex, 1, csiDocument);
|
|
671
933
|
}
|
|
672
934
|
if (csiDocument.modelName === StackbitPresetModelName) {
|
|
673
|
-
|
|
935
|
+
presetsUpdated = true;
|
|
674
936
|
const preset = getPresetFromDocument({
|
|
675
937
|
srcType: contentSourceData.srcType,
|
|
676
938
|
srcProjectId: contentSourceData.srcProjectId,
|
|
@@ -696,7 +958,7 @@ export class ContentStore {
|
|
|
696
958
|
for (let idx = 0; idx < assets.length; idx++) {
|
|
697
959
|
// the indexes of mapped assets and assets from changeEvent are the same
|
|
698
960
|
const asset = assets[idx]!;
|
|
699
|
-
const csiAsset =
|
|
961
|
+
const csiAsset = contentChangesReq.assets[idx]!;
|
|
700
962
|
const index = contentSourceData.assets.findIndex((existingAsset) => existingAsset.srcObjectId === asset.srcObjectId);
|
|
701
963
|
if (index === -1) {
|
|
702
964
|
contentSourceData.assets.push(asset);
|
|
@@ -713,11 +975,10 @@ export class ContentStore {
|
|
|
713
975
|
});
|
|
714
976
|
}
|
|
715
977
|
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
return result;
|
|
978
|
+
return {
|
|
979
|
+
contentChangeResult: result,
|
|
980
|
+
presetsUpdated
|
|
981
|
+
};
|
|
721
982
|
}
|
|
722
983
|
|
|
723
984
|
private async processData({
|
|
@@ -807,15 +1068,13 @@ export class ContentStore {
|
|
|
807
1068
|
externalModels: csData.csiModels,
|
|
808
1069
|
logger: this.userLogger
|
|
809
1070
|
});
|
|
810
|
-
const modelsWithSource = mergedModels.map(
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
}
|
|
818
|
-
);
|
|
1071
|
+
const modelsWithSource = mergedModels.map((model): CSITypes.ModelWithSource => {
|
|
1072
|
+
return {
|
|
1073
|
+
srcType: csData.srcType,
|
|
1074
|
+
srcProjectId: csData.srcProjectId,
|
|
1075
|
+
...model
|
|
1076
|
+
};
|
|
1077
|
+
});
|
|
819
1078
|
return accum.concat(modelsWithSource);
|
|
820
1079
|
}, []);
|
|
821
1080
|
|
|
@@ -852,31 +1111,48 @@ export class ContentStore {
|
|
|
852
1111
|
|
|
853
1112
|
const modelMapByContentSource = groupModelsByContentSource({ models: models });
|
|
854
1113
|
|
|
855
|
-
const contentSourceDataArr = contentSourceRawDataArr.map(
|
|
856
|
-
(csData
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
1114
|
+
const contentSourceDataArr = contentSourceRawDataArr.map((csData): ContentSourceData => {
|
|
1115
|
+
const modelMap = _.get(modelMapByContentSource, [csData.srcType, csData.srcProjectId], {});
|
|
1116
|
+
const csiDocuments = documentMapByContentSource
|
|
1117
|
+
? _.get(documentMapByContentSource, [csData.srcType, csData.srcProjectId], [])
|
|
1118
|
+
: csData.csiDocuments;
|
|
1119
|
+
const documents = mapCSIDocumentsToStoreDocuments({
|
|
1120
|
+
csiDocuments: csiDocuments,
|
|
1121
|
+
contentSourceInstance: csData.instance,
|
|
1122
|
+
modelMap: modelMap,
|
|
1123
|
+
defaultLocaleCode: csData.defaultLocaleCode,
|
|
1124
|
+
createConfigDelegate: getCreateConfigDelegateThunk({
|
|
1125
|
+
getContentSourceDataById: () => this.contentSourceDataById,
|
|
1126
|
+
logger: this.userLogger
|
|
1127
|
+
})
|
|
1128
|
+
});
|
|
1129
|
+
return {
|
|
1130
|
+
...csData,
|
|
1131
|
+
models: Object.values(modelMap),
|
|
1132
|
+
modelMap,
|
|
1133
|
+
documents,
|
|
1134
|
+
documentMap: _.keyBy(documents, 'srcObjectId')
|
|
1135
|
+
};
|
|
1136
|
+
});
|
|
876
1137
|
|
|
877
1138
|
return _.keyBy(contentSourceDataArr, 'id');
|
|
878
1139
|
}
|
|
879
1140
|
|
|
1141
|
+
getContentSourceMeta(): { srcType: string; srcProjectId: string; srcVersion: string; csiVersion: string }[] {
|
|
1142
|
+
return _.reduce(
|
|
1143
|
+
this.contentSourceDataById,
|
|
1144
|
+
(result: { srcType: string; srcProjectId: string; srcVersion: string; csiVersion: string }[], contentSourceData) => {
|
|
1145
|
+
return result.concat({
|
|
1146
|
+
srcType: contentSourceData.srcType,
|
|
1147
|
+
srcProjectId: contentSourceData.srcProjectId,
|
|
1148
|
+
srcVersion: contentSourceData.version.contentSourceVersion,
|
|
1149
|
+
csiVersion: contentSourceData.version.interfaceVersion
|
|
1150
|
+
});
|
|
1151
|
+
},
|
|
1152
|
+
[]
|
|
1153
|
+
);
|
|
1154
|
+
}
|
|
1155
|
+
|
|
880
1156
|
getModels(): Record<string, Record<string, Record<string, Model | ImageModel>>> {
|
|
881
1157
|
return _.reduce(
|
|
882
1158
|
this.contentSourceDataById,
|
|
@@ -942,14 +1218,7 @@ export class ContentStore {
|
|
|
942
1218
|
const srcType = contentSourceData.srcType;
|
|
943
1219
|
const srcProjectId = contentSourceData.srcProjectId;
|
|
944
1220
|
const userContext = getUserContextForSrcType(srcType, user);
|
|
945
|
-
|
|
946
|
-
// backwards compatibility with older CSI version
|
|
947
|
-
if (typeof result === 'boolean') {
|
|
948
|
-
result = {
|
|
949
|
-
hasConnection: result,
|
|
950
|
-
hasPermissions: result
|
|
951
|
-
};
|
|
952
|
-
}
|
|
1221
|
+
const result = await contentSourceData.instance.hasAccess({ userContext });
|
|
953
1222
|
return {
|
|
954
1223
|
hasConnection: accum.hasConnection && result.hasConnection,
|
|
955
1224
|
hasPermissions: accum.hasPermissions && result.hasPermissions,
|
|
@@ -1091,7 +1360,7 @@ export class ContentStore {
|
|
|
1091
1360
|
return contentSourceData.documentMap[srcDocumentId];
|
|
1092
1361
|
}
|
|
1093
1362
|
|
|
1094
|
-
getDocuments({ locale }: { locale?: string }): ContentStoreTypes.Document[] {
|
|
1363
|
+
getDocuments({ locale }: { locale?: string } = {}): ContentStoreTypes.Document[] {
|
|
1095
1364
|
return _.reduce(
|
|
1096
1365
|
this.contentSourceDataById,
|
|
1097
1366
|
(documents: ContentStoreTypes.Document[], contentSourceData) => {
|
|
@@ -1124,7 +1393,7 @@ export class ContentStore {
|
|
|
1124
1393
|
);
|
|
1125
1394
|
}
|
|
1126
1395
|
|
|
1127
|
-
getLocalizedApiObjects({ locale, objectIds }: { locale?: string
|
|
1396
|
+
getLocalizedApiObjects({ locale, objectIds }: { locale?: string; objectIds?: string[] }): ContentStoreTypes.APIObject[] {
|
|
1128
1397
|
const hasExplicitLocale = !_.isEmpty(locale);
|
|
1129
1398
|
return _.reduce(
|
|
1130
1399
|
this.contentSourceDataById,
|
|
@@ -1132,18 +1401,16 @@ export class ContentStore {
|
|
|
1132
1401
|
let documents = objectIds
|
|
1133
1402
|
? contentSourceData.documents.filter((document) => objectIds.includes(document.srcObjectId))
|
|
1134
1403
|
: contentSourceData.documents;
|
|
1135
|
-
documents = hasExplicitLocale
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
let assets = objectIds
|
|
1139
|
-
? contentSourceData.assets.filter((asset) => objectIds.includes(asset.srcObjectId))
|
|
1140
|
-
: contentSourceData.assets;
|
|
1141
|
-
assets = hasExplicitLocale
|
|
1142
|
-
? assets.filter((asset) => !asset.locale || asset.locale === locale)
|
|
1143
|
-
: assets;
|
|
1404
|
+
documents = hasExplicitLocale ? documents.filter((document) => !document.locale || document.locale === locale) : documents;
|
|
1405
|
+
let assets = objectIds ? contentSourceData.assets.filter((asset) => objectIds.includes(asset.srcObjectId)) : contentSourceData.assets;
|
|
1406
|
+
assets = hasExplicitLocale ? assets.filter((asset) => !asset.locale || asset.locale === locale) : assets;
|
|
1144
1407
|
const currentLocale = locale ?? contentSourceData.defaultLocaleCode;
|
|
1145
1408
|
const filteredDocuments = documents.filter((document) => document.srcModelName !== StackbitPresetModelName);
|
|
1146
|
-
const documentObjects = mapDocumentsToLocalizedApiObjects(
|
|
1409
|
+
const documentObjects = mapDocumentsToLocalizedApiObjects({
|
|
1410
|
+
documents: filteredDocuments,
|
|
1411
|
+
locale: currentLocale,
|
|
1412
|
+
delegate: createConfigDelegate({ contentSourceDataById: this.contentSourceDataById, logger: this.userLogger })
|
|
1413
|
+
});
|
|
1147
1414
|
const imageObjects = mapAssetsToLocalizedApiImages(assets, this.staticAssetsPublicPath, currentLocale);
|
|
1148
1415
|
return objects.concat(documentObjects, imageObjects);
|
|
1149
1416
|
},
|
|
@@ -1305,7 +1572,7 @@ export class ContentStore {
|
|
|
1305
1572
|
refProjectId: refProjectId
|
|
1306
1573
|
});
|
|
1307
1574
|
}
|
|
1308
|
-
|
|
1575
|
+
await contentSourceData.instance.updateDocument({
|
|
1309
1576
|
document: csiDocument,
|
|
1310
1577
|
modelMap: csiModelMap,
|
|
1311
1578
|
userContext: userContext,
|
|
@@ -1328,7 +1595,7 @@ export class ContentStore {
|
|
|
1328
1595
|
}
|
|
1329
1596
|
]
|
|
1330
1597
|
});
|
|
1331
|
-
return { srcDocumentId:
|
|
1598
|
+
return { srcDocumentId: srcDocumentId, createdDocumentId: result.srcDocumentId };
|
|
1332
1599
|
}
|
|
1333
1600
|
|
|
1334
1601
|
async createPreset({
|
|
@@ -1380,12 +1647,18 @@ export class ContentStore {
|
|
|
1380
1647
|
|
|
1381
1648
|
// we delete presets immediately because some CMSs don't notify us
|
|
1382
1649
|
// when documents have been deleted.
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1650
|
+
const contentSourceId = getContentSourceIdForContentSource(this.presetsContentSource);
|
|
1651
|
+
this.pushContentSourceEvent({
|
|
1652
|
+
eventName: ContentStoreEventType.ContentSourceContentChange,
|
|
1653
|
+
contentSourceId: contentSourceId,
|
|
1654
|
+
contentChanges: {
|
|
1655
|
+
documents: [],
|
|
1656
|
+
deletedDocumentIds: [presetId],
|
|
1657
|
+
assets: [],
|
|
1658
|
+
deletedAssetIds: []
|
|
1659
|
+
}
|
|
1388
1660
|
});
|
|
1661
|
+
await this.processContentStoreEvents();
|
|
1389
1662
|
}
|
|
1390
1663
|
|
|
1391
1664
|
async uploadAndLinkAsset({
|
|
@@ -1453,7 +1726,7 @@ export class ContentStore {
|
|
|
1453
1726
|
refType: 'asset',
|
|
1454
1727
|
refId: result.id
|
|
1455
1728
|
} as const;
|
|
1456
|
-
|
|
1729
|
+
await contentSourceData.instance.updateDocument({
|
|
1457
1730
|
document: csiDocument,
|
|
1458
1731
|
modelMap: csiModelMap,
|
|
1459
1732
|
userContext: userContext,
|
|
@@ -1476,7 +1749,7 @@ export class ContentStore {
|
|
|
1476
1749
|
}
|
|
1477
1750
|
]
|
|
1478
1751
|
});
|
|
1479
|
-
return { srcDocumentId:
|
|
1752
|
+
return { srcDocumentId: srcDocumentId };
|
|
1480
1753
|
}
|
|
1481
1754
|
|
|
1482
1755
|
async createDocument({
|
|
@@ -1514,15 +1787,9 @@ export class ContentStore {
|
|
|
1514
1787
|
})
|
|
1515
1788
|
});
|
|
1516
1789
|
|
|
1517
|
-
this.logger.debug('created document', { srcType, srcProjectId, srcDocumentId: result.
|
|
1518
|
-
|
|
1519
|
-
// do not update cache in contentSourceData.documents and documentMap,
|
|
1520
|
-
// instead wait for contentSource to call onContentChange(contentChangeEvent)
|
|
1521
|
-
// and use data from contentChangeEvent to update the cache
|
|
1522
|
-
// const newDocuments = [result.document, ...result.referencedDocuments];
|
|
1523
|
-
// contentSourceData.documentMap = Object.assign(contentSourceData.documentMap, _.keyBy(newDocuments, 'srcObjectId'));
|
|
1790
|
+
this.logger.debug('created document', { srcType, srcProjectId, srcDocumentId: result.documentId, modelName });
|
|
1524
1791
|
|
|
1525
|
-
return { srcDocumentId: result.
|
|
1792
|
+
return { srcDocumentId: result.documentId };
|
|
1526
1793
|
}
|
|
1527
1794
|
|
|
1528
1795
|
async updateDocument({
|
|
@@ -1558,88 +1825,80 @@ export class ContentStore {
|
|
|
1558
1825
|
throw new Error(`error updating document, could not find document model: '${documentModelName}'`);
|
|
1559
1826
|
}
|
|
1560
1827
|
|
|
1561
|
-
const operations = await mapPromise(
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
modelField: csiModelField
|
|
1625
|
-
};
|
|
1626
|
-
}
|
|
1828
|
+
const operations = await mapPromise(updateOperations, async (updateOperation): Promise<CSITypes.UpdateOperation> => {
|
|
1829
|
+
const locale = updateOperation.locale ?? contentSourceData.defaultLocaleCode;
|
|
1830
|
+
const modelField = getModelFieldForFieldAtPath(document, model, updateOperation.fieldPath, modelMap, locale);
|
|
1831
|
+
const csiModelField = getModelFieldForFieldAtPath(document, csiModel, updateOperation.fieldPath, csiModelMap, locale);
|
|
1832
|
+
switch (updateOperation.opType) {
|
|
1833
|
+
case 'set':
|
|
1834
|
+
const field = await convertOperationField({
|
|
1835
|
+
operationField: updateOperation.field,
|
|
1836
|
+
fieldPath: [csiModel.name, ...updateOperation.fieldPath],
|
|
1837
|
+
modelField,
|
|
1838
|
+
csiModelField,
|
|
1839
|
+
modelMap,
|
|
1840
|
+
csiModelMap,
|
|
1841
|
+
contentSourceId,
|
|
1842
|
+
contentSourceDataById: this.contentSourceDataById,
|
|
1843
|
+
createDocument: getCreateDocumentThunk({
|
|
1844
|
+
locale: updateOperation.locale,
|
|
1845
|
+
user
|
|
1846
|
+
})
|
|
1847
|
+
});
|
|
1848
|
+
return {
|
|
1849
|
+
...updateOperation,
|
|
1850
|
+
modelField: csiModelField,
|
|
1851
|
+
field
|
|
1852
|
+
};
|
|
1853
|
+
case 'unset':
|
|
1854
|
+
return {
|
|
1855
|
+
...updateOperation,
|
|
1856
|
+
modelField: csiModelField
|
|
1857
|
+
};
|
|
1858
|
+
case 'insert':
|
|
1859
|
+
if (modelField.type !== 'list' || csiModelField.type !== 'list') {
|
|
1860
|
+
throw new Error(`error updating document, 'insert' operation can be performed on 'list' fields only`);
|
|
1861
|
+
}
|
|
1862
|
+
const item = await convertOperationField({
|
|
1863
|
+
operationField: updateOperation.item,
|
|
1864
|
+
fieldPath: [csiModel.name, ...updateOperation.fieldPath],
|
|
1865
|
+
modelField: modelField.items,
|
|
1866
|
+
csiModelField: csiModelField.items,
|
|
1867
|
+
modelMap,
|
|
1868
|
+
csiModelMap,
|
|
1869
|
+
contentSourceId,
|
|
1870
|
+
contentSourceDataById: this.contentSourceDataById,
|
|
1871
|
+
createDocument: getCreateDocumentThunk({
|
|
1872
|
+
locale: updateOperation.locale,
|
|
1873
|
+
user
|
|
1874
|
+
})
|
|
1875
|
+
});
|
|
1876
|
+
return {
|
|
1877
|
+
...updateOperation,
|
|
1878
|
+
modelField: csiModelField,
|
|
1879
|
+
item
|
|
1880
|
+
} as CSITypes.UpdateOperationInsert;
|
|
1881
|
+
case 'remove':
|
|
1882
|
+
return {
|
|
1883
|
+
...updateOperation,
|
|
1884
|
+
modelField: csiModelField
|
|
1885
|
+
};
|
|
1886
|
+
case 'reorder':
|
|
1887
|
+
return {
|
|
1888
|
+
...updateOperation,
|
|
1889
|
+
modelField: csiModelField
|
|
1890
|
+
};
|
|
1627
1891
|
}
|
|
1628
|
-
);
|
|
1892
|
+
});
|
|
1629
1893
|
|
|
1630
|
-
|
|
1894
|
+
await contentSourceData.instance.updateDocument({
|
|
1631
1895
|
document: csiDocument,
|
|
1632
1896
|
modelMap: csiModelMap,
|
|
1633
1897
|
userContext,
|
|
1634
1898
|
operations
|
|
1635
1899
|
});
|
|
1636
1900
|
|
|
1637
|
-
|
|
1638
|
-
// instead wait for contentSource to call onContentChange(contentChangeEvent)
|
|
1639
|
-
// and use data from contentChangeEvent to update the cache
|
|
1640
|
-
// contentSourceData.documentMap = Object.assign(contentSourceData.documentMap, { [document.srcObjectId]: document });
|
|
1641
|
-
|
|
1642
|
-
return { srcDocumentId: updatedDocumentResult.id };
|
|
1901
|
+
return { srcDocumentId: srcDocumentId };
|
|
1643
1902
|
}
|
|
1644
1903
|
|
|
1645
1904
|
async duplicateDocument({
|
|
@@ -1666,7 +1925,6 @@ export class ContentStore {
|
|
|
1666
1925
|
throw new Error(`no document with id '${srcDocumentId}' was found in ${contentSourceData.id}`);
|
|
1667
1926
|
}
|
|
1668
1927
|
const modelMap = contentSourceData.modelMap;
|
|
1669
|
-
const csiModelMap = contentSourceData.csiModelMap;
|
|
1670
1928
|
const model = modelMap[document.srcModelName];
|
|
1671
1929
|
if (!model) {
|
|
1672
1930
|
throw new Error(`no model with name '${document.srcModelName}' was found`);
|
|
@@ -1696,9 +1954,9 @@ export class ContentStore {
|
|
|
1696
1954
|
})
|
|
1697
1955
|
});
|
|
1698
1956
|
|
|
1699
|
-
this.logger.debug('duplicated document', { srcType, srcProjectId, srcDocumentId, newDocumentId: result.
|
|
1957
|
+
this.logger.debug('duplicated document', { srcType, srcProjectId, srcDocumentId, newDocumentId: result.documentId, modelName: model.name });
|
|
1700
1958
|
|
|
1701
|
-
return { srcDocumentId: result.
|
|
1959
|
+
return { srcDocumentId: result.documentId };
|
|
1702
1960
|
}
|
|
1703
1961
|
|
|
1704
1962
|
async uploadAssets({
|
|
@@ -1770,11 +2028,6 @@ export class ContentStore {
|
|
|
1770
2028
|
throw new Error(`no document with id '${srcDocumentId}' was found in ${contentSourceData.id}`);
|
|
1771
2029
|
}
|
|
1772
2030
|
await contentSourceData.instance.deleteDocument({ document: csiDocument, userContext });
|
|
1773
|
-
|
|
1774
|
-
// do not update cache in contentSourceData.documents and documentMap,
|
|
1775
|
-
// instead wait for contentSource to call onContentChange(contentChangeEvent)
|
|
1776
|
-
// and use data from contentChangeEvent to update the cache
|
|
1777
|
-
// delete contentSourceData.documentMap[srcDocumentId];
|
|
1778
2031
|
}
|
|
1779
2032
|
|
|
1780
2033
|
async validateDocuments({
|