@stackbit/cms-core 0.1.25-cloudinary-presets.0 → 0.1.26-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.
Files changed (99) hide show
  1. package/dist/content-store-utils.d.ts +5 -5
  2. package/dist/content-store-utils.d.ts.map +1 -1
  3. package/dist/content-store-utils.js +15 -3
  4. package/dist/content-store-utils.js.map +1 -1
  5. package/dist/content-store.d.ts +11 -3
  6. package/dist/content-store.d.ts.map +1 -1
  7. package/dist/content-store.js +10 -5
  8. package/dist/content-store.js.map +1 -1
  9. package/dist/index.d.ts +2 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +2 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/services/git.d.ts +38 -0
  14. package/dist/services/git.d.ts.map +1 -0
  15. package/dist/services/git.js +201 -0
  16. package/dist/services/git.js.map +1 -0
  17. package/dist/services/index.d.ts +3 -0
  18. package/dist/services/index.d.ts.map +1 -0
  19. package/dist/services/index.js +15 -0
  20. package/dist/services/index.js.map +1 -0
  21. package/dist/services/run.d.ts +7 -0
  22. package/dist/services/run.d.ts.map +1 -0
  23. package/dist/services/run.js +53 -0
  24. package/dist/services/run.js.map +1 -0
  25. package/dist/types/content-store-document-fields.d.ts +600 -0
  26. package/dist/types/content-store-document-fields.d.ts.map +1 -0
  27. package/dist/types/content-store-document-fields.js +3 -0
  28. package/dist/types/content-store-document-fields.js.map +1 -0
  29. package/dist/types/content-store-documents.d.ts +99 -0
  30. package/dist/types/content-store-documents.d.ts.map +1 -0
  31. package/dist/types/content-store-documents.js +3 -0
  32. package/dist/types/content-store-documents.js.map +1 -0
  33. package/dist/types/content-store-types.d.ts +75 -0
  34. package/dist/types/content-store-types.d.ts.map +1 -0
  35. package/dist/types/content-store-types.js.map +1 -0
  36. package/dist/types/content-store-update-operation.d.ts +61 -0
  37. package/dist/types/content-store-update-operation.d.ts.map +1 -0
  38. package/dist/types/content-store-update-operation.js +3 -0
  39. package/dist/types/content-store-update-operation.js.map +1 -0
  40. package/dist/types/index.d.ts +6 -0
  41. package/dist/types/index.d.ts.map +1 -0
  42. package/dist/types/index.js +18 -0
  43. package/dist/types/index.js.map +1 -0
  44. package/dist/types/search-filter.d.ts +1 -1
  45. package/dist/types/search-filter.d.ts.map +1 -1
  46. package/dist/utils/create-update-csi-docs.d.ts +1 -1
  47. package/dist/utils/create-update-csi-docs.d.ts.map +1 -1
  48. package/dist/utils/create-update-csi-docs.js +27 -13
  49. package/dist/utils/create-update-csi-docs.js.map +1 -1
  50. package/dist/utils/csi-to-store-docs-converter.d.ts +1 -1
  51. package/dist/utils/csi-to-store-docs-converter.d.ts.map +1 -1
  52. package/dist/utils/csi-to-store-docs-converter.js +20 -4
  53. package/dist/utils/csi-to-store-docs-converter.js.map +1 -1
  54. package/dist/utils/duplicate-document.d.ts +1 -1
  55. package/dist/utils/duplicate-document.d.ts.map +1 -1
  56. package/dist/utils/index.d.ts +2 -2
  57. package/dist/utils/index.d.ts.map +1 -1
  58. package/dist/utils/search-utils.d.ts +1 -1
  59. package/dist/utils/search-utils.d.ts.map +1 -1
  60. package/dist/utils/search-utils.js +16 -16
  61. package/dist/utils/search-utils.js.map +1 -1
  62. package/dist/utils/site-map.d.ts +1 -1
  63. package/dist/utils/site-map.d.ts.map +1 -1
  64. package/dist/utils/site-map.js +9 -0
  65. package/dist/utils/site-map.js.map +1 -1
  66. package/dist/utils/store-to-api-docs-converter.d.ts +2 -2
  67. package/dist/utils/store-to-api-docs-converter.d.ts.map +1 -1
  68. package/dist/utils/store-to-api-docs-converter.js +87 -38
  69. package/dist/utils/store-to-api-docs-converter.js.map +1 -1
  70. package/dist/utils/store-to-csi-docs-converter.d.ts +1 -1
  71. package/dist/utils/store-to-csi-docs-converter.d.ts.map +1 -1
  72. package/dist/utils/timer.d.ts +1 -1
  73. package/dist/utils/timer.d.ts.map +1 -1
  74. package/package.json +9 -6
  75. package/src/content-store-utils.ts +19 -8
  76. package/src/content-store.ts +28 -15
  77. package/src/index.ts +2 -1
  78. package/src/services/git.ts +245 -0
  79. package/src/services/index.ts +2 -0
  80. package/src/services/run.ts +54 -0
  81. package/src/types/content-store-document-fields.ts +658 -0
  82. package/src/types/content-store-documents.ts +113 -0
  83. package/src/types/content-store-types.ts +96 -0
  84. package/src/types/content-store-update-operation.ts +85 -0
  85. package/src/types/index.ts +5 -0
  86. package/src/types/search-filter.ts +26 -19
  87. package/src/utils/create-update-csi-docs.ts +32 -15
  88. package/src/utils/csi-to-store-docs-converter.ts +33 -14
  89. package/src/utils/duplicate-document.ts +2 -2
  90. package/src/utils/search-utils.ts +18 -19
  91. package/src/utils/site-map.ts +10 -1
  92. package/src/utils/store-to-api-docs-converter.ts +86 -38
  93. package/src/utils/store-to-csi-docs-converter.ts +1 -1
  94. package/src/utils/timer.ts +1 -1
  95. package/dist/content-store-types.d.ts +0 -413
  96. package/dist/content-store-types.d.ts.map +0 -1
  97. package/dist/content-store-types.js.map +0 -1
  98. package/src/content-store-types.ts +0 -531
  99. /package/dist/{content-store-types.js → types/content-store-types.js} +0 -0
@@ -0,0 +1,113 @@
1
+ import { DocumentStatus } from '@stackbit/types';
2
+ import { DocumentField, DocumentFieldAPI, DocumentFieldAPIForType, DocumentStringLikeFieldForType } from './content-store-document-fields';
3
+
4
+ export interface Document {
5
+ type: 'document';
6
+ srcType: string;
7
+ srcProjectId: string;
8
+ srcProjectUrl: string;
9
+ srcEnvironment: string;
10
+ srcObjectId: string;
11
+ srcObjectUrl: string;
12
+ srcObjectLabel: string;
13
+ srcModelName: string;
14
+ srcModelLabel: string;
15
+ isChanged: boolean;
16
+ status: DocumentStatus;
17
+ createdAt: string;
18
+ createdBy?: string;
19
+ updatedAt: string;
20
+ updatedBy?: string[];
21
+ locale?: string;
22
+ fields: Record<string, DocumentField>;
23
+ }
24
+
25
+ export interface Asset {
26
+ type: 'asset';
27
+ srcType: string;
28
+ srcProjectId: string;
29
+ srcProjectUrl: string;
30
+ srcEnvironment: string;
31
+ srcObjectId: string;
32
+ srcObjectUrl: string;
33
+ srcObjectLabel: string;
34
+ srcModelName: string;
35
+ srcModelLabel: string;
36
+ isChanged: boolean;
37
+ status: DocumentStatus;
38
+ createdAt: string;
39
+ createdBy?: string;
40
+ updatedAt: string;
41
+ updatedBy?: string[];
42
+ locale?: string;
43
+ fields: AssetFields;
44
+ }
45
+
46
+ export type AssetFields = {
47
+ title: DocumentStringLikeFieldForType<'string'>;
48
+ file: AssetFileField;
49
+ };
50
+
51
+ export type AssetFileField = AssetFileFieldNonLocalized | AssetFileFieldLocalized;
52
+
53
+ export interface AssetFileFieldNonLocalized extends AssetFileFieldBase, AssetFileFieldProps {
54
+ label?: string;
55
+ localized?: false;
56
+ }
57
+ export interface AssetFileFieldLocalized extends AssetFileFieldBase {
58
+ label?: string;
59
+ localized: true;
60
+ locales: Record<
61
+ string,
62
+ {
63
+ locale: string;
64
+ } & AssetFileFieldProps
65
+ >;
66
+ }
67
+
68
+ export interface AssetFileFieldBase {
69
+ type: 'assetFile';
70
+ }
71
+
72
+ export interface AssetFileFieldProps {
73
+ url: string;
74
+ fileName?: string;
75
+ contentType?: string;
76
+ size?: number;
77
+ dimensions?: {
78
+ width?: number;
79
+ height?: number;
80
+ };
81
+ }
82
+
83
+ /**
84
+ * API Documents and Assets
85
+ */
86
+ export type APIObject = APIDocumentObject | APIImageObject;
87
+
88
+ export interface APIDocumentObject extends Omit<Document, 'fields' | 'type'> {
89
+ type: 'object';
90
+ fields: Record<string, DocumentFieldAPI>;
91
+ }
92
+
93
+ export interface APIImageObject extends Omit<Asset, 'fields' | 'type'> {
94
+ type: 'image';
95
+ fields: AssetFieldsAPI;
96
+ }
97
+
98
+ export type AssetFieldsAPI = {
99
+ title: DocumentFieldAPIForType<'string'>;
100
+ url: DocumentFieldAPIForType<'string'>;
101
+ };
102
+
103
+ export interface APIAsset {
104
+ objectId: string;
105
+ createdAt: string;
106
+ url: string;
107
+ title?: string;
108
+ fileName?: string;
109
+ contentType?: string;
110
+ size?: number;
111
+ width?: number;
112
+ height?: number;
113
+ }
@@ -0,0 +1,96 @@
1
+ import * as CSITypes from '@stackbit/types';
2
+ import { Model } from '@stackbit/sdk';
3
+ import { Asset, Document } from './content-store-documents';
4
+
5
+ export interface ContentSourceData {
6
+ /* Internal content source id computed by concatenating srcType and srcProjectId */
7
+ id: string;
8
+ /* The content source instance loaded from stackbitConfig.contentSources */
9
+ instance: CSITypes.ContentSourceInterface;
10
+ srcType: string;
11
+ srcProjectId: string;
12
+ locales?: CSITypes.Locale[];
13
+ defaultLocaleCode?: string;
14
+ /* Array of extended and validated Models */
15
+ models: Model[];
16
+ /* Map of extended and validated Models by model name */
17
+ modelMap: Record<string, Model>;
18
+ /* Array of original Models (as provided by content source) */
19
+ csiModels: CSITypes.Model[];
20
+ /* Map of original Models (as provided by content source) by model name */
21
+ csiModelMap: Record<string, CSITypes.Model>;
22
+ /* Array of original content source Documents */
23
+ csiDocuments: CSITypes.Document[];
24
+ /* Map of original content source Documents by document ID */
25
+ csiDocumentMap: Record<string, CSITypes.Document>;
26
+ /* Array of converted content-store Documents */
27
+ documents: Document[];
28
+ /* Map of converted content-store Documents by document ID */
29
+ documentMap: Record<string, Document>;
30
+ /* Array of original content source Assets */
31
+ csiAssets: CSITypes.Asset[];
32
+ /* Map of original content source Assets by asset ID */
33
+ csiAssetMap: Record<string, CSITypes.Asset>;
34
+ /* Array of converted content-store Assets */
35
+ assets: Asset[];
36
+ /* Map of converted content-store Assets by asset ID */
37
+ assetMap: Record<string, Asset>;
38
+ }
39
+
40
+ export interface UploadAssetData {
41
+ url: string;
42
+ data?: string;
43
+ metadata: {
44
+ name: string;
45
+ type: string;
46
+ };
47
+ }
48
+
49
+ export interface ContentChangeResultItem {
50
+ srcType: string;
51
+ srcProjectId: string;
52
+ srcObjectId: string;
53
+ }
54
+
55
+ export interface ContentChangeResult {
56
+ updatedDocuments: ContentChangeResultItem[];
57
+ updatedAssets: ContentChangeResultItem[];
58
+ deletedDocuments: ContentChangeResultItem[];
59
+ deletedAssets: ContentChangeResultItem[];
60
+ }
61
+
62
+ export interface User {
63
+ name: string;
64
+ email: string;
65
+ connections: {
66
+ type: string;
67
+ [key: string]: any;
68
+ }[];
69
+ }
70
+
71
+ export interface ValidationError {
72
+ message: string;
73
+ srcType: string;
74
+ srcProjectId: string;
75
+ srcObjectType: string;
76
+ srcObjectId: string;
77
+ fieldPath: (string | number)[];
78
+ isUniqueValidation?: boolean;
79
+ }
80
+
81
+ export interface HasAccessResult {
82
+ hasConnection: boolean;
83
+ hasPermissions: boolean;
84
+ contentSources: {
85
+ srcType: string;
86
+ srcProjectId: string;
87
+ hasConnection: boolean;
88
+ hasPermissions: boolean;
89
+ }[];
90
+ }
91
+
92
+ export interface CrossReferenceData {
93
+ refId: string;
94
+ refSrcType: string;
95
+ refProjectId: string;
96
+ }
@@ -0,0 +1,85 @@
1
+ import { FieldType } from '@stackbit/types';
2
+
3
+ export type UpdateOperation = UpdateOperationSet | UpdateOperationUnset | UpdateOperationInsert | UpdateOperationRemove | UpdateOperationReorder;
4
+
5
+ export interface UpdateOperationBase {
6
+ opType: string;
7
+ fieldPath: (string | number)[];
8
+ locale?: string;
9
+ }
10
+
11
+ export interface UpdateOperationSet extends UpdateOperationBase {
12
+ opType: 'set';
13
+ field: UpdateOperationField;
14
+ }
15
+
16
+ export interface UpdateOperationUnset extends UpdateOperationBase {
17
+ opType: 'unset';
18
+ }
19
+
20
+ export interface UpdateOperationInsert extends UpdateOperationBase {
21
+ opType: 'insert';
22
+ index?: number;
23
+ item: Exclude<UpdateOperationField, UpdateOperationListField>;
24
+ }
25
+
26
+ export interface UpdateOperationRemove extends UpdateOperationBase {
27
+ opType: 'remove';
28
+ index: number;
29
+ }
30
+
31
+ export interface UpdateOperationReorder extends UpdateOperationBase {
32
+ opType: 'reorder';
33
+ order: number[];
34
+ }
35
+
36
+ export type UpdateOperationField =
37
+ | UpdateOperationValueField
38
+ | UpdateOperationObjectField
39
+ | UpdateOperationModelField
40
+ | UpdateOperationReferenceField
41
+ | UpdateOperationCrossReferenceField
42
+ | UpdateOperationListField;
43
+
44
+ export type UpdateOperationValueFieldType = Exclude<FieldType, 'object' | 'model' | 'reference' | 'cross-reference' | 'list'>;
45
+
46
+ export type UpdateOperationValueField = DistributeUpdateOperationValueField<UpdateOperationValueFieldType>;
47
+
48
+ export type DistributeUpdateOperationValueField<Type extends UpdateOperationValueFieldType> = Type extends UpdateOperationValueFieldType
49
+ ? UpdateOperationValueFieldForType<Type>
50
+ : never;
51
+
52
+ export interface UpdateOperationValueFieldForType<Type extends UpdateOperationValueFieldType> {
53
+ type: Type;
54
+ value: any;
55
+ }
56
+
57
+ export interface UpdateOperationObjectField {
58
+ type: 'object';
59
+ object: Record<string, any>;
60
+ }
61
+
62
+ export interface UpdateOperationModelField {
63
+ type: 'model';
64
+ modelName: string;
65
+ object: Record<string, any>;
66
+ }
67
+
68
+ export interface UpdateOperationReferenceField {
69
+ type: 'reference';
70
+ refType: 'document' | 'asset';
71
+ refId: string;
72
+ }
73
+
74
+ export interface UpdateOperationCrossReferenceField {
75
+ type: 'cross-reference';
76
+ refType: 'document' | 'asset';
77
+ refId: string;
78
+ refSrcType: string;
79
+ refProjectId: string;
80
+ }
81
+
82
+ export interface UpdateOperationListField {
83
+ type: 'list';
84
+ items: any[];
85
+ }
@@ -0,0 +1,5 @@
1
+ export * from './content-store-types';
2
+ export * from './content-store-documents';
3
+ export * from './content-store-document-fields';
4
+ export * from './content-store-update-operation';
5
+ export * from './search-filter';
@@ -3,51 +3,58 @@ type Distribute<U> = U extends any ? U[] : never;
3
3
  type ValueType = string | number | Date | boolean;
4
4
 
5
5
  type BaseFilterItem = {
6
- field: string;
7
- isMeta?: boolean;
6
+ field: string;
7
+ isMeta?: boolean;
8
8
  };
9
9
 
10
10
  type EqualFilterItem = BaseFilterItem & {
11
- operator: 'eq' | 'neq';
12
- value: ValueType;
11
+ operator: 'eq' | 'neq';
12
+ value: ValueType;
13
13
  };
14
14
 
15
15
  type UndefinedFilterItem = BaseFilterItem & {
16
- operator: 'is-undefined' | 'is-not-undefined';
17
- }
16
+ operator: 'is-undefined' | 'is-not-undefined';
17
+ };
18
18
 
19
19
  type CompareFilterItem = BaseFilterItem & {
20
- operator: 'gte' | 'lte';
21
- value: ValueType;
20
+ operator: 'gte' | 'lte';
21
+ value: ValueType;
22
22
  };
23
23
 
24
24
  type IncludeStringFilterItem = BaseFilterItem & {
25
- operator: 'includes' | 'not-includes';
26
- value: string;
25
+ operator: 'includes' | 'not-includes';
26
+ value: string;
27
27
  };
28
28
 
29
29
  type IncludeListFilterItem = BaseFilterItem & {
30
- operator: 'in' | 'nin';
31
- values: Distribute<ValueType>;
30
+ operator: 'in' | 'nin';
31
+ values: Distribute<ValueType>;
32
32
  };
33
33
 
34
34
  type IncludeAllFilterItem = BaseFilterItem & {
35
- operator: 'all';
36
- values: Distribute<ValueType>;
35
+ operator: 'all';
36
+ values: Distribute<ValueType>;
37
37
  };
38
38
 
39
39
  type BetweenFilterItem = BaseFilterItem & {
40
- operator: 'between';
41
- startValue: ValueType;
42
- endValue: ValueType;
40
+ operator: 'between';
41
+ startValue: ValueType;
42
+ endValue: ValueType;
43
43
  };
44
44
 
45
- export type SearchFilterItem = EqualFilterItem | UndefinedFilterItem | CompareFilterItem | IncludeStringFilterItem | IncludeListFilterItem | IncludeAllFilterItem | BetweenFilterItem;
45
+ export type SearchFilterItem =
46
+ | EqualFilterItem
47
+ | UndefinedFilterItem
48
+ | CompareFilterItem
49
+ | IncludeStringFilterItem
50
+ | IncludeListFilterItem
51
+ | IncludeAllFilterItem
52
+ | BetweenFilterItem;
46
53
 
47
54
  export type SearchFilter = LogicalOperator;
48
55
 
49
56
  type LogicalOperator = LogicalAndOperator;
50
57
 
51
58
  type LogicalAndOperator = {
52
- 'and': SearchFilterItem[];
59
+ and: SearchFilterItem[];
53
60
  };
@@ -2,11 +2,11 @@ import _ from 'lodash';
2
2
  import slugify from 'slugify';
3
3
 
4
4
  import { Model as SDKModel } from '@stackbit/sdk';
5
- import { Model as CSIModel, Field, FieldSpecificProps, UpdateOperationListFieldItem } from '@stackbit/types';
5
+ import { Model as CSIModel, Field, FieldSpecificProps, UpdateOperationListFieldItem, isOneOfFieldTypes } from '@stackbit/types';
6
6
  import { fieldPathToString, mapPromise } from '@stackbit/utils';
7
7
  import * as CSITypes from '@stackbit/types';
8
8
 
9
- import * as ContentStoreTypes from '../content-store-types';
9
+ import * as ContentStoreTypes from '../types';
10
10
  import { getContentSourceId, getUserContextForSrcType, updateOperationValueFieldWithCrossReference } from '../content-store-utils';
11
11
 
12
12
  export type CreateDocumentCallback = ({
@@ -111,19 +111,32 @@ export async function createDocumentRecursively({
111
111
  if (!model || !csiModel) {
112
112
  throw new Error(`no model with name '${modelName}' was found`);
113
113
  }
114
+ let modelFields = model.fields ?? [];
115
+ let csiModelFields = csiModel.fields ?? [];
114
116
  if (model.type === 'page') {
115
117
  const tokens = extractTokensFromString(String(model.urlPath));
116
118
  const slugField = _.last(tokens);
117
- if (object && slugField && slugField in object) {
118
- const slugFieldValue = object[slugField];
119
+ //TODO legacy
120
+ if (object && slugField && (slugField in object || '_stackbit_slug' in object)) {
121
+ const slugFieldValue = object[slugField] || object['_stackbit_slug'];
119
122
  object[slugField] = sanitizeSlug(slugFieldValue);
123
+ if (!modelFields.find(field => field.name === slugField)) {
124
+ modelFields = [...modelFields, {
125
+ type: 'slug',
126
+ name: slugField
127
+ }];
128
+ csiModelFields = [...csiModelFields, {
129
+ type: 'slug',
130
+ name: slugField
131
+ }];
132
+ }
120
133
  }
121
134
  }
122
135
 
123
136
  const nestedResult = await createObjectRecursively({
124
137
  object,
125
- modelFields: model.fields ?? [],
126
- csiModelFields: csiModel.fields ?? [],
138
+ modelFields,
139
+ csiModelFields,
127
140
  fieldPath: [modelName],
128
141
  modelMap,
129
142
  csiModelMap,
@@ -147,9 +160,8 @@ function extractTokensFromString(input: string): string[] {
147
160
  return input.match(/(?<={)[^}]+(?=})/g) || [];
148
161
  }
149
162
 
150
- function sanitizeSlug(slug: string) {
151
- return slug
152
- .split('/')
163
+ function sanitizeSlug(slug?: string) {
164
+ return slug?.split('/')
153
165
  .map((part) => slugify(part, { lower: true }))
154
166
  .join('/');
155
167
  }
@@ -327,7 +339,7 @@ async function createUpdateOperationFieldRecursively({
327
339
  value: _.omit(value, ['$$type']) // backwards compatibility with legacy presets
328
340
  },
329
341
  newRefDocuments: []
330
- }
342
+ };
331
343
  }
332
344
  if (_.isPlainObject(value)) {
333
345
  refId = value.$$ref ?? value.url;
@@ -390,8 +402,13 @@ async function createUpdateOperationFieldRecursively({
390
402
  newRefDocuments: [document, ...newRefDocuments]
391
403
  };
392
404
  }
393
- } else if (['string', 'text', 'json'].includes(csiModelField.type) && modelField.type === 'cross-reference') {
394
- const fieldType = csiModelField.type as 'string' | 'text' | 'json';
405
+ } else if (
406
+ csiModelField.type === 'cross-reference' ||
407
+ (isOneOfFieldTypes(csiModelField.type, ['string', 'text', 'json']) && modelField.type === 'cross-reference')
408
+ ) {
409
+ if (modelField.type !== 'cross-reference') {
410
+ throw new Error(`field type mismatch between content-source and mapped models at field path ${fieldPathToString(fieldPath)}`);
411
+ }
395
412
  let { $$ref: refId = null, $$type: modelName = null, $$refSrcType: refSrcType = null, $$refProjectId: refProjectId = null, ...rest } = value;
396
413
  let refObject;
397
414
  const newRefDocuments: CSITypes.Document[] = [];
@@ -420,7 +437,7 @@ async function createUpdateOperationFieldRecursively({
420
437
  refObject = { refId: document.id, refSrcType, refProjectId };
421
438
  }
422
439
  return {
423
- field: updateOperationValueFieldWithCrossReference(fieldType, refObject),
440
+ field: updateOperationValueFieldWithCrossReference(csiModelField.type, refObject),
424
441
  newRefDocuments
425
442
  };
426
443
  } else if (csiModelField.type === 'list') {
@@ -556,7 +573,7 @@ export async function convertOperationField({
556
573
  // ContentStore and CSI 'reference' operation field have the same format
557
574
  return operationField;
558
575
  case 'cross-reference':
559
- if (csiModelField.type !== 'string' && csiModelField.type !== 'text' && csiModelField.type !== 'json') {
576
+ if (!isOneOfFieldTypes(csiModelField.type, ['string', 'text', 'json', 'cross-reference'])) {
560
577
  throw new Error(
561
578
  `update operation with with 'cross-reference' field can be performed on 'string', 'text' and 'json' content-source field types only, got '${csiModelField.type}'`
562
579
  );
@@ -568,7 +585,7 @@ export async function convertOperationField({
568
585
  };
569
586
  return {
570
587
  type: csiModelField.type,
571
- value: csiModelField.type === 'json' ? refObject : JSON.stringify(refObject)
588
+ value: isOneOfFieldTypes(csiModelField.type, ['json', 'cross-reference']) ? refObject : JSON.stringify(refObject)
572
589
  };
573
590
  case 'list': {
574
591
  if (modelField.type !== 'list' || csiModelField.type !== 'list') {
@@ -1,9 +1,9 @@
1
1
  import _ from 'lodash';
2
2
  import { Model, ImageModel } from '@stackbit/sdk';
3
- import { Field, FieldSpecificProps, FieldList, FieldModelProps, FieldObjectProps, isLocalizedField } from '@stackbit/types';
3
+ import { Field, FieldSpecificProps, FieldList, FieldModelProps, FieldObjectProps, isLocalizedField, isDocumentFieldOneOfFieldTypes } from '@stackbit/types';
4
4
  import * as CSITypes from '@stackbit/types';
5
5
 
6
- import * as ContentStoreTypes from '../content-store-types';
6
+ import * as ContentStoreTypes from '../types';
7
7
  import { IMAGE_MODEL } from '../common/common-schema';
8
8
  import { omitByNil } from '@stackbit/utils';
9
9
 
@@ -185,13 +185,13 @@ function mapCSIFieldToStoreField({
185
185
  context: MapContext;
186
186
  }): ContentStoreTypes.DocumentField {
187
187
  if (!csiDocumentField) {
188
- const isUnset = ['object', 'model', 'reference', 'cross-reference', 'richText', 'markdown', 'image', 'file', 'json'].includes(modelField.type);
188
+ const shouldUseIsUnset = ['markdown', 'richText', 'image', 'file', 'json', 'object', 'model', 'reference', 'cross-reference'].includes(modelField.type);
189
189
  return {
190
190
  type: modelField.type,
191
191
  ...(localized
192
192
  ? { localized, locales: {} }
193
193
  : {
194
- ...(isUnset ? { isUnset } : null),
194
+ ...(shouldUseIsUnset ? { isUnset: true } : null),
195
195
  ...(modelField.type === 'list' ? { items: [] } : null)
196
196
  })
197
197
  } as ContentStoreTypes.DocumentField;
@@ -225,7 +225,7 @@ function mapCSIFieldToStoreField({
225
225
  case 'reference':
226
226
  return csiDocumentField as ContentStoreTypes.DocumentField;
227
227
  case 'cross-reference':
228
- return mapReferenceField(csiDocumentField)
228
+ return mapReferenceField(csiDocumentField);
229
229
  case 'object':
230
230
  return mapObjectField(csiDocumentField as CSITypes.DocumentObjectField, modelField, context);
231
231
  case 'model':
@@ -236,7 +236,7 @@ function mapCSIFieldToStoreField({
236
236
  case 'richText':
237
237
  return mapRichTextField(csiDocumentField as CSITypes.DocumentRichTextField);
238
238
  case 'markdown':
239
- return mapMarkdownField(csiDocumentField as CSITypes.DocumentValueField);
239
+ return mapMarkdownField(csiDocumentField as CSITypes.DocumentStringLikeField);
240
240
  default: {
241
241
  const _exhaustiveCheck: never = modelField;
242
242
  return _exhaustiveCheck;
@@ -250,7 +250,8 @@ function mapReferenceField(csiDocumentField: CSITypes.DocumentField): ContentSto
250
250
  refType: 'document',
251
251
  isUnset: true
252
252
  } as const;
253
- if (csiDocumentField.type !== 'string' && csiDocumentField.type !== 'text' && csiDocumentField.type !== 'json') {
253
+
254
+ if (!isDocumentFieldOneOfFieldTypes(csiDocumentField, ['string', 'text', 'json', 'cross-reference'])) {
254
255
  if (isLocalizedField(csiDocumentField)) {
255
256
  return {
256
257
  type: 'cross-reference',
@@ -261,6 +262,28 @@ function mapReferenceField(csiDocumentField: CSITypes.DocumentField): ContentSto
261
262
  }
262
263
  return unlocalizedUnset;
263
264
  }
265
+
266
+ if (csiDocumentField.type === 'cross-reference') {
267
+ if (isLocalizedField(csiDocumentField)) {
268
+ return {
269
+ type: 'cross-reference',
270
+ refType: 'document',
271
+ localized: true,
272
+ locales: _.reduce(
273
+ csiDocumentField.locales,
274
+ (accum: Record<string, { locale: string; refId: string; refSrcType: string; refProjectId: string }>, locale, localeKey) => {
275
+ // the documentField.type is 'cross-reference', so it is already in the correct format
276
+ accum[localeKey] = locale;
277
+ return accum;
278
+ },
279
+ {}
280
+ )
281
+ };
282
+ } else {
283
+ return csiDocumentField;
284
+ }
285
+ }
286
+
264
287
  const parseRefObject = (value: any): { refId: string; refSrcType: string; refProjectId: string } | null => {
265
288
  if (typeof value === 'string') {
266
289
  try {
@@ -278,8 +301,8 @@ function mapReferenceField(csiDocumentField: CSITypes.DocumentField): ContentSto
278
301
  }
279
302
  return null;
280
303
  };
304
+
281
305
  if (isLocalizedField(csiDocumentField)) {
282
- csiDocumentField.locales;
283
306
  return {
284
307
  type: 'cross-reference',
285
308
  refType: 'document',
@@ -438,7 +461,7 @@ function mapRichTextField(csiDocumentField: CSITypes.DocumentRichTextField): Con
438
461
  };
439
462
  }
440
463
 
441
- function mapMarkdownField(csiDocumentField: CSITypes.DocumentValueField): ContentStoreTypes.DocumentMarkdownField {
464
+ function mapMarkdownField(csiDocumentField: CSITypes.DocumentStringLikeField): ContentStoreTypes.DocumentMarkdownField {
442
465
  if (!isLocalizedField(csiDocumentField)) {
443
466
  return {
444
467
  type: 'markdown',
@@ -458,11 +481,7 @@ function mapMarkdownField(csiDocumentField: CSITypes.DocumentValueField): Conten
458
481
  };
459
482
  }
460
483
 
461
- function getMetadataFromContentStore({
462
- contentSourceInstance
463
- }: {
464
- contentSourceInstance: CSITypes.ContentSourceInterface;
465
- }): {
484
+ function getMetadataFromContentStore({ contentSourceInstance }: { contentSourceInstance: CSITypes.ContentSourceInterface }): {
466
485
  srcType: string;
467
486
  srcProjectId: string;
468
487
  srcProjectUrl: string;
@@ -1,6 +1,6 @@
1
1
  import _ from 'lodash';
2
2
 
3
- import * as ContentStoreTypes from '../content-store-types';
3
+ import * as ContentStoreTypes from '../types';
4
4
  import { getContentSourceId, getDocumentFieldForLocale } from '../content-store-utils';
5
5
  import { IMAGE_MODEL } from '../common/common-schema';
6
6
 
@@ -110,7 +110,7 @@ function mergeObjectWithDocumentField({
110
110
  }
111
111
  break;
112
112
  }
113
- case 'image': {
113
+ case 'image': {
114
114
  if (typeof value !== 'undefined') {
115
115
  return value;
116
116
  }