@stackbit/cms-core 0.1.25-cloudinary-presets.0 → 0.1.26-gitcms.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 (46) hide show
  1. package/dist/content-store-types.d.ts +0 -2
  2. package/dist/content-store-types.d.ts.map +1 -1
  3. package/dist/content-store.d.ts +5 -0
  4. package/dist/content-store.d.ts.map +1 -1
  5. package/dist/content-store.js +11 -6
  6. package/dist/content-store.js.map +1 -1
  7. package/dist/index.d.ts +1 -0
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +1 -0
  10. package/dist/index.js.map +1 -1
  11. package/dist/services/git.d.ts +35 -0
  12. package/dist/services/git.d.ts.map +1 -0
  13. package/dist/services/git.js +182 -0
  14. package/dist/services/git.js.map +1 -0
  15. package/dist/services/index.d.ts +3 -0
  16. package/dist/services/index.d.ts.map +1 -0
  17. package/dist/services/index.js +15 -0
  18. package/dist/services/index.js.map +1 -0
  19. package/dist/services/run.d.ts +17 -0
  20. package/dist/services/run.d.ts.map +1 -0
  21. package/dist/services/run.js +54 -0
  22. package/dist/services/run.js.map +1 -0
  23. package/dist/utils/create-update-csi-docs.d.ts.map +1 -1
  24. package/dist/utils/create-update-csi-docs.js +18 -5
  25. package/dist/utils/create-update-csi-docs.js.map +1 -1
  26. package/dist/utils/duplicate-document.js +0 -7
  27. package/dist/utils/duplicate-document.js.map +1 -1
  28. package/dist/utils/index.d.ts +2 -2
  29. package/dist/utils/index.d.ts.map +1 -1
  30. package/dist/utils/store-to-api-docs-converter.d.ts +3 -3
  31. package/dist/utils/store-to-api-docs-converter.d.ts.map +1 -1
  32. package/dist/utils/store-to-api-docs-converter.js +66 -45
  33. package/dist/utils/store-to-api-docs-converter.js.map +1 -1
  34. package/dist/utils/store-to-csi-docs-converter.js +0 -4
  35. package/dist/utils/store-to-csi-docs-converter.js.map +1 -1
  36. package/package.json +9 -6
  37. package/src/content-store-types.ts +1 -5
  38. package/src/content-store.ts +17 -7
  39. package/src/index.ts +1 -0
  40. package/src/services/git.ts +227 -0
  41. package/src/services/index.ts +2 -0
  42. package/src/services/run.ts +59 -0
  43. package/src/utils/create-update-csi-docs.ts +18 -5
  44. package/src/utils/duplicate-document.ts +1 -8
  45. package/src/utils/store-to-api-docs-converter.ts +63 -44
  46. package/src/utils/store-to-csi-docs-converter.ts +0 -4
@@ -0,0 +1,227 @@
1
+ import _ from 'lodash';
2
+ import os from 'os';
3
+ import path from 'path';
4
+ import { v4 as uuid } from 'uuid';
5
+ import fse from 'fs-extra';
6
+
7
+ import { GitServiceInterface, GitFileObject, GitAuthor, GitCommitLogEntry, Logger } from '@stackbit/types';
8
+ import { Worker } from '@stackbit/utils';
9
+
10
+ import { RunService } from './run';
11
+ import { DocumentStatus } from '@stackbit/types';
12
+
13
+ const GIT_LOG_CHANGE_TYPES: Record<string, DocumentStatus> = {
14
+ M: 'modified',
15
+ A: 'added',
16
+ D: 'deleted'
17
+ };
18
+
19
+ export class GitService implements GitServiceInterface {
20
+ private readonly repoUrl: string;
21
+ private readonly repoDir: string;
22
+ private readonly repoBranch: string;
23
+ private readonly repoPublishBranch: string;
24
+ private readonly worker: Worker;
25
+ private readonly run: RunService;
26
+ private readonly logger: Logger;
27
+ private readonly userLogger: Logger;
28
+
29
+ private branchFetched: boolean = false;
30
+
31
+ constructor(options: {
32
+ repoUrl: string;
33
+ repoDir: string;
34
+ repoBranch: string;
35
+ repoPublishBranch: string;
36
+ worker: Worker;
37
+ runService: RunService;
38
+ logger: Logger;
39
+ userLogger: Logger;
40
+ }) {
41
+ this.repoUrl = options.repoUrl;
42
+ this.repoDir = options.repoDir;
43
+ this.repoBranch = options.repoBranch;
44
+ this.repoPublishBranch = options.repoPublishBranch;
45
+ this.worker = options.worker;
46
+ this.run = options.runService;
47
+ this.logger = options.logger;
48
+ this.userLogger = options.userLogger;
49
+ }
50
+
51
+ private async commit(author: GitAuthor, files: GitFileObject[]) {
52
+ const filePaths = _.map(files, 'filePath');
53
+ this.logger.debug('[git] Commit scheduled', filePaths);
54
+ return this.worker.schedule(async () => {
55
+ this.logger.debug('[git] Commit running', filePaths);
56
+ const message = files
57
+ .reduce((messages: string[], file) => {
58
+ messages.push(`${path.parse(file.filePath).base}: ${file.description}`);
59
+ return messages;
60
+ }, [])
61
+ .join('.\n');
62
+ await this.run.command('git', ['add', ...filePaths], this.repoDir);
63
+ await this.run.command(
64
+ 'git',
65
+ ['commit', '--no-verify', '--author', `${author.name || author.email} <${author.email}>`, '-m', message],
66
+ this.repoDir
67
+ );
68
+ this.logger.debug('[git] Commit done', filePaths);
69
+ });
70
+ }
71
+
72
+ private push() {
73
+ this.logger.debug('[git] Push scheduled');
74
+ return this.worker.schedule(async () => {
75
+ this.logger.debug('[git] Push running');
76
+ await this.run.command('git', ['pull', 'origin', '--rebase', '--autostash', '-Xtheirs'], this.repoDir);
77
+ await this.run.command('git', ['push', 'origin'], this.repoDir);
78
+ this.logger.debug('[git] Push done');
79
+ });
80
+ }
81
+
82
+ async commitAndPush(author: GitAuthor, files: GitFileObject[]) {
83
+ await this.commit(author, files);
84
+ return this.push();
85
+ }
86
+
87
+ pull() {
88
+ this.logger.debug('[git] Pull scheduled');
89
+ return this.worker.schedule(async () => {
90
+ this.logger.debug('[git] Pull running');
91
+ await this.run.command('git', ['pull', 'origin', '--rebase', '--autostash', '-Xtheirs'], this.repoDir);
92
+ this.logger.debug('[git] Pull done');
93
+ });
94
+ }
95
+
96
+ private async publishAll(author: GitAuthor) {
97
+ this.logger.debug('[git] Publish all started');
98
+ const publishDir = path.join(os.tmpdir(), uuid());
99
+ await this.run.command('git', ['clone', this.repoUrl, '--branch', this.repoPublishBranch, publishDir]);
100
+ try {
101
+ await this.run.command('git', ['merge', `origin/${this.repoBranch}`, this.repoPublishBranch, '-Xtheirs'], publishDir);
102
+ await this.run
103
+ .command('git', ['commit', '--author', `${author.name || author.email} <${author.email}>`, `-m`, 'Publish'], publishDir)
104
+ .catch(() => {});
105
+ await this.run.command('git', ['push', 'origin'], publishDir);
106
+ } finally {
107
+ await fse.remove(publishDir);
108
+ }
109
+ this.logger.debug('[git] Publish all done');
110
+ }
111
+
112
+ private async publishFiles(author: GitAuthor, filePaths: string[]) {
113
+ this.logger.debug('[git] Publish files started', filePaths);
114
+ const publishDir = path.join(os.tmpdir(), uuid());
115
+ await this.run.command('git', ['clone', this.repoUrl, '--branch', this.repoPublishBranch, publishDir]);
116
+ try {
117
+ await Promise.all(
118
+ filePaths.map(async (filePath) => {
119
+ const destFilePath = path.join(publishDir, filePath);
120
+ await fse.ensureDir(path.dirname(destFilePath));
121
+ return fse.copy(path.join(this.repoDir, filePath), destFilePath);
122
+ })
123
+ );
124
+
125
+ await this.run.command('git', ['checkout', '-b', 'stackbit-publish-branch'], publishDir);
126
+ await this.run.command('git', ['add', ...filePaths], publishDir);
127
+ await this.run.command('git', ['commit', '--author', `${author.name || author.email} <${author.email}>`, `-m`, 'Publish'], publishDir);
128
+
129
+ await this.run.command('git', ['checkout', this.repoBranch], publishDir);
130
+ await this.run.command('git', ['merge', 'stackbit-publish-branch', this.repoBranch, '-Xtheirs'], publishDir);
131
+
132
+ await this.run.command('git', ['checkout', this.repoPublishBranch], publishDir);
133
+ await this.run.command('git', ['merge', 'stackbit-publish-branch', this.repoPublishBranch, '-Xtheirs'], publishDir);
134
+
135
+ await this.run.command('git', ['push', 'origin', this.repoPublishBranch, this.repoBranch], publishDir);
136
+ } finally {
137
+ await fse.remove(publishDir);
138
+ }
139
+ this.logger.debug('[git] Publish files done', filePaths);
140
+ }
141
+
142
+ publish(author: GitAuthor, filePaths?: string[]): Promise<void> {
143
+ this.logger.debug('[git] Publish scheduled');
144
+ return this.worker.schedule(async () => {
145
+ if (filePaths) {
146
+ if (!filePaths.length) {
147
+ this.logger.debug('[git] Nothing to publish');
148
+ return;
149
+ }
150
+ return this.publishFiles(author, filePaths);
151
+ } else {
152
+ return this.publishAll(author);
153
+ }
154
+ });
155
+ }
156
+
157
+ private parseGitCommitAuthor(author?: string) {
158
+ if (!author) {
159
+ return author;
160
+ }
161
+ const regex = /(.*)\((.*)\)/;
162
+ const match = author.match(regex);
163
+ if (match) {
164
+ const [authorEmail, authorName] = match.slice(1);
165
+
166
+ if (authorName === 'Stackbit Code Editor') {
167
+ return 'stackbit';
168
+ }
169
+ return authorEmail ? authorEmail.toLowerCase() : author;
170
+ }
171
+ return author;
172
+ }
173
+
174
+ async diff(): Promise<string[]> {
175
+ this.logger.debug('[git] Diff check scheduled');
176
+ return this.worker.schedule(async () => {
177
+ this.logger.debug('[git] Diff check running');
178
+ const result = await this.run.command(
179
+ 'git',
180
+ [
181
+ 'diff',
182
+ '--name-only',
183
+ '--no-renames', // this flag makes sure we get both old and new name of renamed file
184
+ `origin/${this.repoPublishBranch}..${this.repoBranch}`
185
+ ],
186
+ this.repoDir
187
+ );
188
+ this.logger.debug('[git] Diff check done');
189
+ return result.stdout.split('\n').filter(Boolean);
190
+ });
191
+ }
192
+
193
+ async commitLog(): Promise<GitCommitLogEntry[]> {
194
+ this.logger.debug('[git] Changes check scheduled');
195
+ return this.worker.schedule(async () => {
196
+ this.logger.debug('[git] Changes check running');
197
+ if (!this.branchFetched) {
198
+ await this.run.command('git', ['fetch', 'origin', `${this.repoPublishBranch}:${this.repoPublishBranch}`], this.repoDir);
199
+ this.branchFetched = true;
200
+ }
201
+ const logResult = await this.run.command(
202
+ 'git',
203
+ ['log', '--pretty=format:commit:%H%n%at%n%ae%x28%an%x29', '--name-status', `${this.repoPublishBranch}..${this.repoBranch}`],
204
+ this.repoDir
205
+ );
206
+ this.logger.debug('[git] Changes check done');
207
+ return logResult.stdout
208
+ .split('commit:')
209
+ .filter(Boolean)
210
+ .map((rawCommit) => {
211
+ const split = rawCommit.trim().split('\n');
212
+ return {
213
+ author: this.parseGitCommitAuthor(split[2]),
214
+ timestamp: split[1] ? new Date(parseInt(split[1]) * 1000) : undefined,
215
+ commitHash: split[0],
216
+ changes: split
217
+ .slice(3)
218
+ .map((line) => line.trim().split(/\t/))
219
+ .filter(Boolean)
220
+ .filter(([status, filename]) => status && filename)
221
+ .map(([status, filename]) => [GIT_LOG_CHANGE_TYPES[status!] || 'modified', filename])
222
+ };
223
+ })
224
+ .reverse();
225
+ });
226
+ }
227
+ }
@@ -0,0 +1,2 @@
1
+ export * from './run';
2
+ export * from './git';
@@ -0,0 +1,59 @@
1
+ import childProcess, { ChildProcessWithoutNullStreams } from 'child_process';
2
+ import { RunServiceInterface } from '@stackbit/types';
3
+
4
+ export class RunService implements RunServiceInterface {
5
+ private readonly env: NodeJS.ProcessEnv;
6
+ private readonly uid?: number;
7
+
8
+ constructor(options: { env: NodeJS.ProcessEnv; uid?: number }) {
9
+ this.env = options.env;
10
+ this.uid = options.uid;
11
+ }
12
+
13
+ command(command: string, args: string[], cwd?: string, shell?: boolean) {
14
+ return getProcessPromise(
15
+ childProcess.spawn(command, args, {
16
+ cwd: cwd,
17
+ shell: shell,
18
+ env: this.env,
19
+ ...(this.uid ? { uid: this.uid } : {})
20
+ })
21
+ );
22
+ }
23
+ }
24
+
25
+ function getProcessPromise(p: ChildProcessWithoutNullStreams): Promise<{
26
+ stdout: string;
27
+ stderr: string;
28
+ exitCode?: number;
29
+ err?: Error;
30
+ }> {
31
+ return new Promise((resolve, reject) => {
32
+ let stdout = '';
33
+ let stderr = '';
34
+ p.stdout.on('data', (out) => (stdout += out));
35
+ p.stderr.on('data', (out) => (stderr += out));
36
+ p.on('exit', (exitCode) => {
37
+ if (exitCode !== 0) {
38
+ reject({
39
+ err: new Error(`process exited with code: ${exitCode}, stderr: ${stderr}`),
40
+ stdout,
41
+ stderr,
42
+ exitCode
43
+ });
44
+ } else {
45
+ resolve({
46
+ stdout,
47
+ stderr
48
+ });
49
+ }
50
+ });
51
+ p.on('error', (err) => {
52
+ reject({
53
+ err,
54
+ stdout,
55
+ stderr
56
+ });
57
+ });
58
+ });
59
+ }
@@ -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
+ const modelFields = model.fields ?? [];
115
+ const 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.push({
125
+ type: 'slug',
126
+ name: slugField
127
+ });
128
+ csiModelFields.push({
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,
@@ -324,7 +337,7 @@ async function createUpdateOperationFieldRecursively({
324
337
  return {
325
338
  field: {
326
339
  type: 'image',
327
- value: _.omit(value, ['$$type']) // backwards compatibility with legacy presets
340
+ value: _.omit(value, ['$$type'])
328
341
  },
329
342
  newRefDocuments: []
330
343
  }
@@ -110,16 +110,9 @@ function mergeObjectWithDocumentField({
110
110
  }
111
111
  break;
112
112
  }
113
- case 'image': {
114
- if (typeof value !== 'undefined') {
115
- return value;
116
- }
113
+ case 'image': {
117
114
  const localizedField = getDocumentFieldForLocale(documentField, locale);
118
115
  if (localizedField && !localizedField.isUnset && isPlainObjectOrUndefined(value)) {
119
- if (localizedField?.sourceData) {
120
- return localizedField?.sourceData;
121
- }
122
- //TODO needs testing, looks like we need to use the url field instead of this
123
116
  return mergeObjectWithDocumentFields({
124
117
  object: value,
125
118
  documentFields: localizedField.fields,
@@ -1,25 +1,26 @@
1
1
  import _ from 'lodash';
2
+ import path from 'path';
2
3
  import { omitByNil } from '@stackbit/utils';
3
4
  import * as ContentStoreTypes from '../content-store-types';
4
5
 
5
- export function mapDocumentsToLocalizedApiObjects(documents: ContentStoreTypes.Document[], locale?: string): ContentStoreTypes.APIDocumentObject[] {
6
- return documents.map((document) => documentToLocalizedApiObject(document, locale));
6
+ export function mapDocumentsToLocalizedApiObjects(documents: ContentStoreTypes.Document[], staticAssetsPublicPath: string, locale?: string): ContentStoreTypes.APIDocumentObject[] {
7
+ return documents.map((document) => documentToLocalizedApiObject(document, staticAssetsPublicPath, locale));
7
8
  }
8
9
 
9
- function documentToLocalizedApiObject(document: ContentStoreTypes.Document, locale?: string): ContentStoreTypes.APIDocumentObject {
10
+ function documentToLocalizedApiObject(document: ContentStoreTypes.Document, staticAssetsPublicPath: string, locale?: string): ContentStoreTypes.APIDocumentObject {
10
11
  const { type, fields, ...rest } = document;
11
12
  return {
12
13
  type: 'object',
13
14
  ...rest,
14
- fields: toLocalizedAPIFields(fields, locale)
15
+ fields: toLocalizedAPIFields(fields, staticAssetsPublicPath, locale)
15
16
  };
16
17
  }
17
18
 
18
- function toLocalizedAPIFields(docFields: Record<string, ContentStoreTypes.DocumentField>, locale?: string): Record<string, ContentStoreTypes.DocumentFieldAPI> {
19
- return _.mapValues(docFields, (docField) => toLocalizedAPIField(docField, locale));
19
+ function toLocalizedAPIFields(docFields: Record<string, ContentStoreTypes.DocumentField>, staticAssetsPublicPath: string, locale?: string): Record<string, ContentStoreTypes.DocumentFieldAPI> {
20
+ return _.mapValues(docFields, (docField) => toLocalizedAPIField(docField, staticAssetsPublicPath, locale));
20
21
  }
21
22
 
22
- function toLocalizedAPIField(docField: ContentStoreTypes.DocumentField, locale?: string, isListItem = false): ContentStoreTypes.DocumentFieldAPI {
23
+ function toLocalizedAPIField(docField: ContentStoreTypes.DocumentField, staticAssetsPublicPath: string, locale?: string, isListItem = false): ContentStoreTypes.DocumentFieldAPI {
23
24
  type ToBoolean<T extends boolean | undefined> = T extends true ? true : false;
24
25
  function localeFields<T extends boolean | undefined>(localized: T): null | { localized: false } | { localized: true; locale: string } {
25
26
  const isLocalized = !!localized as ToBoolean<T>;
@@ -71,33 +72,43 @@ function toLocalizedAPIField(docField: ContentStoreTypes.DocumentField, locale?:
71
72
  ...localeFields(docField.localized)
72
73
  };
73
74
  case 'image':
75
+ let result: ContentStoreTypes.DocumentFieldAPI;
74
76
  if (docField.localized) {
75
77
  const { localized, locales, ...base } = docField;
76
78
  const localeProps = locales && locale ? locales[locale] : undefined;
77
- return {
78
- ...base,
79
- ...(localeProps
80
- ? {
81
- ...localeProps,
82
- fields: toLocalizedAPIFields(localeProps.fields, locale) as ContentStoreTypes.ImageFieldsAPI
83
- }
84
- : { isUnset: true }),
85
- ...localeFields(localized)
86
- };
79
+ if (localeProps) {
80
+ const fields = toLocalizedAPIFields(localeProps.fields, staticAssetsPublicPath, locale) as ContentStoreTypes.ImageFieldsAPI;
81
+ result = {
82
+ ...base,
83
+ ...localeProps,
84
+ fields,
85
+ ...localeFields(localized)
86
+ };
87
+ } else {
88
+ result = {
89
+ ...base,
90
+ isUnset: true,
91
+ ...localeFields(localized)
92
+ }
93
+ }
94
+ } else {
95
+ if (docField.isUnset) {
96
+ result = {
97
+ ...docField,
98
+ type: 'image',
99
+ ...localeFields(docField.localized)
100
+ }
101
+ } else {
102
+ const fields = toLocalizedAPIFields(docField.fields, staticAssetsPublicPath, locale) as ContentStoreTypes.ImageFieldsAPI;
103
+ result = {
104
+ ...docField,
105
+ type: 'image',
106
+ fields,
107
+ ...localeFields(docField.localized)
108
+ }
109
+ }
87
110
  }
88
- return {
89
- ...(!docField.isUnset
90
- ? {
91
- ...docField,
92
- type: 'image',
93
- fields: toLocalizedAPIFields(docField.fields, locale) as ContentStoreTypes.ImageFieldsAPI
94
- }
95
- : {
96
- ...docField,
97
- type: 'image'
98
- }),
99
- ...localeFields(docField.localized)
100
- };
111
+ return result;
101
112
  case 'object':
102
113
  case 'model':
103
114
  if (docField.localized) {
@@ -109,7 +120,7 @@ function toLocalizedAPIField(docField: ContentStoreTypes.DocumentField, locale?:
109
120
  ...(localeProps
110
121
  ? {
111
122
  ...localeProps,
112
- fields: toLocalizedAPIFields(localeProps.fields, locale)
123
+ fields: toLocalizedAPIFields(localeProps.fields, staticAssetsPublicPath, locale)
113
124
  }
114
125
  : { isUnset: true }),
115
126
  ...localeFields(localized)
@@ -123,7 +134,7 @@ function toLocalizedAPIField(docField: ContentStoreTypes.DocumentField, locale?:
123
134
  ...(localeProps
124
135
  ? {
125
136
  ...localeProps,
126
- fields: toLocalizedAPIFields(localeProps.fields, locale)
137
+ fields: toLocalizedAPIFields(localeProps.fields, staticAssetsPublicPath, locale)
127
138
  }
128
139
  : { isUnset: true }),
129
140
  ...localeFields(localized)
@@ -135,7 +146,7 @@ function toLocalizedAPIField(docField: ContentStoreTypes.DocumentField, locale?:
135
146
  ? {
136
147
  ...docField,
137
148
  type: 'object',
138
- fields: toLocalizedAPIFields(docField.fields, locale)
149
+ fields: toLocalizedAPIFields(docField.fields, staticAssetsPublicPath, locale)
139
150
  }
140
151
  : {
141
152
  ...docField,
@@ -222,14 +233,14 @@ function toLocalizedAPIField(docField: ContentStoreTypes.DocumentField, locale?:
222
233
  return {
223
234
  ...base,
224
235
  ...localeProps,
225
- items: (localeProps?.items ?? []).map((field) => toLocalizedAPIField(field, locale, true) as ContentStoreTypes.DocumentListFieldItemsAPI),
236
+ items: (localeProps?.items ?? []).map((field) => toLocalizedAPIField(field, staticAssetsPublicPath, locale, true) as ContentStoreTypes.DocumentListFieldItemsAPI),
226
237
  ...localeFields(localized)
227
238
  };
228
239
  }
229
240
  return {
230
241
  ...docField,
231
242
  ...localeFields(docField.localized),
232
- items: docField.items.map((field) => toLocalizedAPIField(field, locale, true) as ContentStoreTypes.DocumentListFieldItemsAPI)
243
+ items: docField.items.map((field) => toLocalizedAPIField(field, staticAssetsPublicPath, locale, true) as ContentStoreTypes.DocumentListFieldItemsAPI)
233
244
  };
234
245
  default:
235
246
  const _exhaustiveCheck: never = docField;
@@ -238,20 +249,20 @@ function toLocalizedAPIField(docField: ContentStoreTypes.DocumentField, locale?:
238
249
  }
239
250
  }
240
251
 
241
- export function mapAssetsToLocalizedApiImages(assets: ContentStoreTypes.Asset[], locale?: string): ContentStoreTypes.APIImageObject[] {
242
- return assets.map((asset) => assetToLocalizedApiImage(asset, locale));
252
+ export function mapAssetsToLocalizedApiImages(assets: ContentStoreTypes.Asset[], staticAssetsPublicPath: string, locale?: string): ContentStoreTypes.APIImageObject[] {
253
+ return assets.map((asset) => assetToLocalizedApiImage(asset, staticAssetsPublicPath, locale));
243
254
  }
244
255
 
245
- function assetToLocalizedApiImage(asset: ContentStoreTypes.Asset, locale?: string): ContentStoreTypes.APIImageObject {
256
+ function assetToLocalizedApiImage(asset: ContentStoreTypes.Asset, staticAssetsPublicPath: string, locale?: string): ContentStoreTypes.APIImageObject {
246
257
  const { type, fields, ...rest } = asset;
247
258
  return {
248
259
  type: 'image',
249
260
  ...rest,
250
- fields: localizeAssetFields(fields, locale)
261
+ fields: localizeAssetFields(fields, staticAssetsPublicPath, locale)
251
262
  };
252
263
  }
253
264
 
254
- function localizeAssetFields(assetFields: ContentStoreTypes.AssetFields, locale?: string): ContentStoreTypes.AssetFieldsAPI {
265
+ function localizeAssetFields(assetFields: ContentStoreTypes.AssetFields, staticAssetsPublicPath: string, locale?: string): ContentStoreTypes.AssetFieldsAPI {
255
266
  const fields: ContentStoreTypes.AssetFieldsAPI = {
256
267
  title: {
257
268
  type: 'string' as const,
@@ -285,11 +296,11 @@ function localizeAssetFields(assetFields: ContentStoreTypes.AssetFields, locale?
285
296
  return fields;
286
297
  }
287
298
 
288
- export function mapStoreAssetsToAPIAssets(assets: ContentStoreTypes.Asset[], locale?: string): ContentStoreTypes.APIAsset[] {
289
- return assets.map((asset) => storeAssetToAPIAsset(asset, locale)).filter((asset): asset is ContentStoreTypes.APIAsset => !!asset);
299
+ export function mapStoreAssetsToAPIAssets(assets: ContentStoreTypes.Asset[], staticAssetsPublicPath: string, locale?: string): ContentStoreTypes.APIAsset[] {
300
+ return assets.map((asset) => storeAssetToAPIAsset(asset, staticAssetsPublicPath, locale)).filter((asset): asset is ContentStoreTypes.APIAsset => !!asset);
290
301
  }
291
302
 
292
- function storeAssetToAPIAsset(asset: ContentStoreTypes.Asset, locale?: string): ContentStoreTypes.APIAsset | null {
303
+ function storeAssetToAPIAsset(asset: ContentStoreTypes.Asset, staticAssetsPublicPath: string, locale?: string): ContentStoreTypes.APIAsset | null {
293
304
  const assetTitleField = asset.fields.title;
294
305
  const localizedTitleField = assetTitleField.localized ? assetTitleField.locales?.[locale!] : assetTitleField;
295
306
  const assetFileField = asset.fields.file;
@@ -300,7 +311,7 @@ function storeAssetToAPIAsset(asset: ContentStoreTypes.Asset, locale?: string):
300
311
  return {
301
312
  objectId: asset.srcObjectId,
302
313
  createdAt: asset.createdAt,
303
- url: localizedFileField.url,
314
+ url: replaceAssetUrlIfNeeded(staticAssetsPublicPath, localizedFileField.url) ?? staticAssetsPublicPath,
304
315
  ...omitByNil({
305
316
  title: localizedTitleField?.value ?? null,
306
317
  fileName: localizedFileField.fileName,
@@ -311,3 +322,11 @@ function storeAssetToAPIAsset(asset: ContentStoreTypes.Asset, locale?: string):
311
322
  })
312
323
  };
313
324
  }
325
+
326
+ function replaceAssetUrlIfNeeded(staticAssetsPublicPath: string, value: string | undefined) {
327
+ let url = value;
328
+ if (url && !url.startsWith('http:') && !url.startsWith('https:')) {
329
+ url = path.join(staticAssetsPublicPath, url);
330
+ }
331
+ return url;
332
+ }
@@ -95,8 +95,6 @@ function mapStoreFieldToCSIField(documentField: ContentStoreTypes.DocumentField)
95
95
  return {
96
96
  type: 'image',
97
97
  localized: true,
98
- source: documentField.source,
99
- sourceData: documentField.sourceData,
100
98
  locales: _.mapValues(documentField.locales, (locale) => ({
101
99
  locale: locale.locale,
102
100
  fields: mapStoreFieldsToCSIFields(locale.fields)
@@ -108,8 +106,6 @@ function mapStoreFieldToCSIField(documentField: ContentStoreTypes.DocumentField)
108
106
  }
109
107
  return {
110
108
  type: 'image',
111
- source: documentField.source,
112
- sourceData: documentField.sourceData,
113
109
  fields: mapStoreFieldsToCSIFields(documentField.fields)
114
110
  } as CSITypes.DocumentImageFieldNonLocalized;
115
111
  }