includio-cms 0.7.2 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +128 -0
- package/ROADMAP.md +54 -2
- package/dist/admin/api/generate-styles.d.ts +2 -0
- package/dist/admin/api/generate-styles.js +32 -0
- package/dist/admin/api/handler.js +33 -0
- package/dist/admin/api/media-gc.js +10 -4
- package/dist/admin/api/rest/handler.js +17 -0
- package/dist/admin/api/rest/routes/collections.js +25 -13
- package/dist/admin/api/rest/routes/entries.d.ts +1 -1
- package/dist/admin/api/rest/routes/entries.js +10 -10
- package/dist/admin/api/rest/routes/media.d.ts +2 -0
- package/dist/admin/api/rest/routes/media.js +9 -0
- package/dist/admin/api/rest/routes/schema.d.ts +5 -0
- package/dist/admin/api/rest/routes/schema.js +152 -0
- package/dist/admin/api/rest/routes/singletons.d.ts +1 -1
- package/dist/admin/api/rest/routes/singletons.js +8 -7
- package/dist/admin/api/rest/routes/upload.d.ts +2 -0
- package/dist/admin/api/rest/routes/upload.js +28 -0
- package/dist/admin/api/upload.js +13 -0
- package/dist/admin/client/collection/collection-entries.svelte +35 -13
- package/dist/admin/client/entry/entry.svelte +21 -23
- package/dist/admin/client/entry/header/a11y-validator.js +2 -2
- package/dist/admin/client/entry/header/publish-panel.svelte +33 -85
- package/dist/admin/client/entry/header/status-badge.svelte +2 -2
- package/dist/admin/client/entry/header/version-history-sheet.svelte +9 -9
- package/dist/admin/client/entry/header/visibility.svelte +16 -10
- package/dist/admin/client/entry/utils.d.ts +3 -0
- package/dist/admin/client/entry/utils.js +22 -4
- package/dist/admin/client/form/form-submission/form-submission-page.svelte +4 -1
- package/dist/admin/client/form/form-submission/submission-field.svelte +10 -0
- package/dist/admin/client/index.d.ts +1 -0
- package/dist/admin/client/index.js +1 -0
- package/dist/admin/client/maintenance/maintenance-page.svelte +146 -2
- package/dist/admin/client/users/users-page.svelte +5 -6
- package/dist/admin/client/users/users-page.svelte.d.ts +1 -4
- package/dist/admin/components/fields/block-picker-modal.svelte +13 -4
- package/dist/admin/components/fields/blocks-field.svelte +40 -19
- package/dist/admin/components/fields/field-renderer.svelte +4 -8
- package/dist/admin/components/fields/object-field.svelte +7 -12
- package/dist/admin/components/fields/select-field.svelte +8 -2
- package/dist/admin/components/fields/seo-field.svelte +40 -93
- package/dist/admin/components/fields/simple-array-field.svelte +27 -16
- package/dist/admin/components/fields/text-field-wrapper.svelte +52 -197
- package/dist/admin/components/fields/text-field-wrapper.svelte.d.ts +2 -2
- package/dist/admin/components/fields/url-field-wrapper.svelte +15 -25
- package/dist/admin/components/fields/url-field.svelte +61 -72
- package/dist/admin/components/layout/layout-renderer.svelte +10 -4
- package/dist/admin/components/media/file-preview.svelte +10 -1
- package/dist/admin/components/media/file-upload.svelte +5 -1
- package/dist/admin/components/media/file-upload.svelte.d.ts +1 -0
- package/dist/admin/components/media/files-list.svelte +12 -3
- package/dist/admin/components/media/media-library.svelte +109 -37
- package/dist/admin/components/media/media-selector.svelte +90 -16
- package/dist/admin/components/media/tag-sidebar.svelte +10 -6
- package/dist/admin/components/media/tag-sidebar.svelte.d.ts +7 -2
- package/dist/admin/components/tiptap/FigureNodeView.svelte +15 -10
- package/dist/admin/components/tiptap/InlineBlockNodeView.svelte +53 -94
- package/dist/admin/components/tiptap/SlashCommandPopup.svelte +8 -3
- package/dist/admin/components/tiptap/editor-toolbar.svelte +28 -23
- package/dist/admin/components/tiptap/image-dialog.svelte +12 -7
- package/dist/admin/components/tiptap/inline-block-node.js +6 -5
- package/dist/admin/components/tiptap/lang.d.ts +77 -0
- package/dist/admin/components/tiptap/lang.js +170 -0
- package/dist/admin/components/tiptap/link-dialog.svelte +31 -28
- package/dist/admin/components/tiptap/slash-command.js +27 -23
- package/dist/admin/components/tiptap/table-dialog.svelte +9 -4
- package/dist/admin/components/tiptap/video-dialog.svelte +6 -1
- package/dist/admin/remote/email.remote.d.ts +1 -0
- package/dist/admin/remote/email.remote.js +5 -0
- package/dist/admin/remote/entry.remote.d.ts +2 -5
- package/dist/admin/remote/entry.remote.js +23 -28
- package/dist/admin/remote/index.d.ts +1 -0
- package/dist/admin/remote/index.js +1 -0
- package/dist/admin/remote/media.remote.d.ts +15 -0
- package/dist/admin/remote/media.remote.js +18 -2
- package/dist/admin/remote/preview.remote.js +3 -1
- package/dist/admin/utils/entryLabel.js +9 -6
- package/dist/admin/utils/translationStatus.js +1 -2
- package/dist/cli/scaffold/admin.js +34 -2
- package/dist/cms/runtime/api.d.ts +16 -12
- package/dist/cms/runtime/api.js +7 -6
- package/dist/cms/runtime/remote.js +2 -2
- package/dist/cms/runtime/schemas.d.ts +1 -1
- package/dist/cms/runtime/schemas.js +1 -1
- package/dist/cms/runtime/types.d.ts +118 -112
- package/dist/cms/runtime/types.js +0 -12
- package/dist/core/cms.d.ts +3 -1
- package/dist/core/cms.js +30 -0
- package/dist/core/fields/fieldSchemaToTs.js +9 -15
- package/dist/core/fields/formFieldSchemaToTs.js +7 -0
- package/dist/core/server/entries/operations/create.js +10 -4
- package/dist/core/server/entries/operations/get.d.ts +1 -0
- package/dist/core/server/entries/operations/get.js +186 -191
- package/dist/core/server/entries/operations/update.d.ts +6 -7
- package/dist/core/server/entries/operations/update.js +20 -38
- package/dist/core/server/fields/populateEntry.js +16 -52
- package/dist/core/server/fields/resolveImageFields.js +69 -120
- package/dist/core/server/fields/resolveRelationFields.js +30 -51
- package/dist/core/server/fields/resolveRichtextLinks.js +46 -100
- package/dist/core/server/fields/resolveTypographyOrphans.bench.d.ts +1 -0
- package/dist/core/server/fields/resolveTypographyOrphans.bench.js +87 -0
- package/dist/core/server/fields/resolveTypographyOrphans.d.ts +3 -0
- package/dist/core/server/fields/resolveTypographyOrphans.js +128 -0
- package/dist/core/server/fields/resolveUrlFields.js +47 -56
- package/dist/core/server/fields/utils/fixOrphans.d.ts +5 -0
- package/dist/core/server/fields/utils/fixOrphans.js +12 -0
- package/dist/core/server/fields/utils/imageStyles.d.ts +4 -2
- package/dist/core/server/fields/utils/imageStyles.js +41 -25
- package/dist/core/server/fields/utils/resolveMedia.js +1 -6
- package/dist/core/server/forms/submissions/operations/delete.js +26 -2
- package/dist/core/server/forms/submissions/utils/parseMultipart.d.ts +2 -0
- package/dist/core/server/forms/submissions/utils/parseMultipart.js +75 -0
- package/dist/core/server/generator/fields.d.ts +6 -0
- package/dist/core/server/generator/fields.js +43 -5
- package/dist/core/server/generator/formFieldSchemaToString.js +10 -0
- package/dist/core/server/generator/formFields.js +1 -0
- package/dist/core/server/generator/generator.js +98 -30
- package/dist/core/server/media/operations/getFiles.d.ts +5 -0
- package/dist/core/server/media/operations/getFiles.js +6 -0
- package/dist/core/server/media/operations/uploadPrivateFile.d.ts +4 -0
- package/dist/core/server/media/operations/uploadPrivateFile.js +8 -0
- package/dist/core/server/media/styles/operations/batchGenerateStyles.d.ts +16 -0
- package/dist/core/server/media/styles/operations/batchGenerateStyles.js +144 -0
- package/dist/db-postgres/index.js +303 -37
- package/dist/db-postgres/schema/entry.d.ts +0 -94
- package/dist/db-postgres/schema/entry.js +0 -6
- package/dist/db-postgres/schema/entryVersion.d.ts +17 -0
- package/dist/db-postgres/schema/entryVersion.js +1 -0
- package/dist/entity/index.d.ts +9 -4
- package/dist/entity/index.js +24 -24
- package/dist/files-local/index.js +43 -0
- package/dist/paraglide/messages/_index.d.ts +36 -3
- package/dist/paraglide/messages/_index.js +71 -3
- package/dist/paraglide/messages/en.d.ts +5 -0
- package/dist/paraglide/messages/en.js +14 -0
- package/dist/paraglide/messages/pl.d.ts +5 -0
- package/dist/paraglide/messages/pl.js +14 -0
- package/dist/sveltekit/components/preview.svelte +2 -326
- package/dist/sveltekit/components/preview.svelte.d.ts +5 -16
- package/dist/sveltekit/server/index.d.ts +2 -1
- package/dist/sveltekit/server/index.js +2 -1
- package/dist/sveltekit/server/preview.js +4 -7
- package/dist/types/adapters/db.d.ts +15 -1
- package/dist/types/adapters/files.d.ts +6 -0
- package/dist/types/cms.d.ts +5 -0
- package/dist/types/entries.d.ts +54 -18
- package/dist/types/fields.d.ts +14 -24
- package/dist/types/formFields.d.ts +7 -2
- package/dist/types/index.d.ts +2 -2
- package/dist/types/layout.d.ts +0 -1
- package/dist/types/structured-content.d.ts +5 -0
- package/dist/updates/0.10.0/index.d.ts +2 -0
- package/dist/updates/0.10.0/index.js +15 -0
- package/dist/updates/0.11.0/index.d.ts +2 -0
- package/dist/updates/0.11.0/index.js +12 -0
- package/dist/updates/0.12.0/index.d.ts +2 -0
- package/dist/updates/0.12.0/index.js +12 -0
- package/dist/updates/0.13.0/index.d.ts +2 -0
- package/dist/updates/0.13.0/index.js +10 -0
- package/dist/updates/0.13.1/index.d.ts +2 -0
- package/dist/updates/0.13.1/index.js +20 -0
- package/dist/updates/0.7.3/index.d.ts +2 -0
- package/dist/updates/0.7.3/index.js +10 -0
- package/dist/updates/0.8.0/index.d.ts +2 -0
- package/dist/updates/0.8.0/index.js +18 -0
- package/dist/updates/0.8.0/migrate.d.ts +2 -0
- package/dist/updates/0.8.0/migrate.js +101 -0
- package/dist/updates/0.9.0/index.d.ts +2 -0
- package/dist/updates/0.9.0/index.js +38 -0
- package/dist/updates/index.js +9 -1
- package/package.json +7 -6
- package/dist/admin/components/fields/image-field.svelte +0 -198
- package/dist/admin/components/fields/image-field.svelte.d.ts +0 -8
- package/dist/admin/components/fields/richtext-field.svelte +0 -13
- package/dist/admin/components/fields/richtext-field.svelte.d.ts +0 -8
- package/dist/admin/components/tiptap.svelte +0 -11
- package/dist/admin/components/tiptap.svelte.d.ts +0 -6
- package/dist/core/server/entries/utils/getEntryTranslation.d.ts +0 -1
- package/dist/core/server/entries/utils/getEntryTranslation.js +0 -18
- package/dist/paraglide/messages/hello_world.d.ts +0 -5
- package/dist/paraglide/messages/hello_world.js +0 -33
- package/dist/paraglide/messages/login_hello.d.ts +0 -16
- package/dist/paraglide/messages/login_hello.js +0 -34
- package/dist/paraglide/messages/login_please_login.d.ts +0 -16
- package/dist/paraglide/messages/login_please_login.js +0 -34
|
@@ -1,51 +1,9 @@
|
|
|
1
|
-
import { walkInlineBlockNodes } from '../../../admin/components/tiptap/structured-content-utils.js';
|
|
2
|
-
import { translateObject } from '../entries/utils/getEntryTranslation.js';
|
|
3
1
|
import { resolveMediaFields } from './resolveImageFields.js';
|
|
4
2
|
import { resolveRelationFields } from './resolveRelationFields.js';
|
|
5
3
|
import { resolveRichtextLinks } from './resolveRichtextLinks.js';
|
|
6
4
|
import { resolveUrlFields } from './resolveUrlFields.js';
|
|
5
|
+
import { resolveTypographyOrphans } from './resolveTypographyOrphans.js';
|
|
7
6
|
import { getCMS } from '../../cms.js';
|
|
8
|
-
function translateInlineBlockData(data, fields, language) {
|
|
9
|
-
for (const field of fields) {
|
|
10
|
-
const val = data[field.slug];
|
|
11
|
-
if (val == null)
|
|
12
|
-
continue;
|
|
13
|
-
switch (field.type) {
|
|
14
|
-
case 'content': {
|
|
15
|
-
const cf = field;
|
|
16
|
-
if (cf.inlineBlocks?.length &&
|
|
17
|
-
val &&
|
|
18
|
-
typeof val === 'object' &&
|
|
19
|
-
'type' in val &&
|
|
20
|
-
val.type === 'doc') {
|
|
21
|
-
walkInlineBlockNodes(val, (node) => {
|
|
22
|
-
if (node.attrs?.blockData && typeof node.attrs.blockData === 'object') {
|
|
23
|
-
node.attrs.blockData = translateObject(node.attrs.blockData, language);
|
|
24
|
-
const def = cf.inlineBlocks.find((b) => b.slug === node.attrs?.blockType);
|
|
25
|
-
if (def) {
|
|
26
|
-
translateInlineBlockData(node.attrs.blockData, def.fields, language);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
break;
|
|
32
|
-
}
|
|
33
|
-
case 'object':
|
|
34
|
-
if (val && typeof val === 'object' && 'data' in val)
|
|
35
|
-
translateInlineBlockData(val.data, field.fields, language);
|
|
36
|
-
break;
|
|
37
|
-
case 'blocks':
|
|
38
|
-
if (Array.isArray(val)) {
|
|
39
|
-
for (const item of val) {
|
|
40
|
-
const def = field.of.find((d) => d.slug === item.slug);
|
|
41
|
-
if (def)
|
|
42
|
-
translateInlineBlockData(item.data, def.fields, language);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
break;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
7
|
async function resolveCustomFields(data, fields) {
|
|
50
8
|
// Check if any custom fields exist before accessing CMS
|
|
51
9
|
const hasCustom = fields.some((f) => f.type === 'custom' ||
|
|
@@ -72,19 +30,16 @@ async function resolveCustomFields(data, fields) {
|
|
|
72
30
|
break;
|
|
73
31
|
}
|
|
74
32
|
case 'object':
|
|
75
|
-
if (val && typeof val === 'object'
|
|
76
|
-
result[field.slug] =
|
|
77
|
-
...val,
|
|
78
|
-
data: await resolveCustomFields(val.data, field.fields)
|
|
79
|
-
};
|
|
33
|
+
if (val && typeof val === 'object') {
|
|
34
|
+
result[field.slug] = await resolveCustomFields(val, field.fields);
|
|
80
35
|
}
|
|
81
36
|
break;
|
|
82
37
|
case 'blocks':
|
|
83
38
|
if (Array.isArray(val)) {
|
|
84
39
|
result[field.slug] = await Promise.all(val.map(async (item) => {
|
|
85
|
-
const blockDef = field.of.find((d) => d.slug === item.
|
|
40
|
+
const blockDef = field.of.find((d) => d.slug === item._slug);
|
|
86
41
|
if (blockDef) {
|
|
87
|
-
return
|
|
42
|
+
return await resolveCustomFields(item, blockDef.fields);
|
|
88
43
|
}
|
|
89
44
|
return item;
|
|
90
45
|
}));
|
|
@@ -100,7 +55,16 @@ export async function populateEntryData(data, fields, language) {
|
|
|
100
55
|
populatedData = await resolveMediaFields(populatedData, fields);
|
|
101
56
|
populatedData = await resolveRichtextLinks(populatedData, fields, language);
|
|
102
57
|
populatedData = (await resolveCustomFields(populatedData, fields));
|
|
103
|
-
|
|
104
|
-
|
|
58
|
+
// Typography orphan fix — enabled by default, opt-out via config
|
|
59
|
+
let fixOrphans = true;
|
|
60
|
+
try {
|
|
61
|
+
fixOrphans = getCMS().typographyConfig.fixOrphans !== false;
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// CMS not initialized — keep default
|
|
65
|
+
}
|
|
66
|
+
if (fixOrphans) {
|
|
67
|
+
populatedData = resolveTypographyOrphans(populatedData, fields);
|
|
68
|
+
}
|
|
105
69
|
return populatedData;
|
|
106
70
|
}
|
|
@@ -14,7 +14,6 @@ export async function resolveMediaFields(data, fields) {
|
|
|
14
14
|
continue;
|
|
15
15
|
switch (field.type) {
|
|
16
16
|
case 'media':
|
|
17
|
-
case 'image':
|
|
18
17
|
case 'file': {
|
|
19
18
|
if (field.multiple && Array.isArray(val)) {
|
|
20
19
|
val.forEach((id) => {
|
|
@@ -38,39 +37,32 @@ export async function resolveMediaFields(data, fields) {
|
|
|
38
37
|
break;
|
|
39
38
|
}
|
|
40
39
|
case 'object':
|
|
41
|
-
collectIds(val
|
|
40
|
+
collectIds(val, field.fields);
|
|
42
41
|
break;
|
|
43
42
|
case 'blocks':
|
|
44
43
|
if (Array.isArray(val)) {
|
|
45
44
|
val.forEach((item) => {
|
|
46
|
-
|
|
47
|
-
const objectDef = field.of.find((objDef) => objDef.slug === item.slug);
|
|
45
|
+
const objectDef = field.of.find((objDef) => objDef.slug === item._slug);
|
|
48
46
|
if (objectDef) {
|
|
49
|
-
collectIds(item
|
|
47
|
+
collectIds(item, objectDef.fields);
|
|
50
48
|
}
|
|
51
49
|
});
|
|
52
50
|
}
|
|
53
51
|
break;
|
|
54
52
|
case 'content': {
|
|
55
53
|
const contentField = field;
|
|
56
|
-
// Content
|
|
57
|
-
if (typeof val === 'object' && val
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const def = contentField.inlineBlocks.find((b) => b.slug === node.attrs?.blockType);
|
|
69
|
-
if (def)
|
|
70
|
-
collectIds(bd, def.fields);
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
}
|
|
54
|
+
// Content is now a single doc, not Record<lang, doc>
|
|
55
|
+
if (val && typeof val === 'object' && val.type === 'doc') {
|
|
56
|
+
mediaIds.push(...extractMediaIdsFromDoc(val));
|
|
57
|
+
if (contentField.inlineBlocks?.length) {
|
|
58
|
+
walkInlineBlockNodes(val, (node) => {
|
|
59
|
+
const bd = node.attrs?.blockData;
|
|
60
|
+
if (!bd || typeof bd !== 'object')
|
|
61
|
+
return;
|
|
62
|
+
const def = contentField.inlineBlocks.find((b) => b.slug === node.attrs?.blockType);
|
|
63
|
+
if (def)
|
|
64
|
+
collectIds(bd, def.fields);
|
|
65
|
+
});
|
|
74
66
|
}
|
|
75
67
|
}
|
|
76
68
|
break;
|
|
@@ -105,12 +97,18 @@ export async function resolveMediaFields(data, fields) {
|
|
|
105
97
|
if (!mediaFile)
|
|
106
98
|
return { data: null, styles: {} };
|
|
107
99
|
if (mediaFile.type === 'image') {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
100
|
+
try {
|
|
101
|
+
const imgResult = await getImageStyles(field, mediaFile);
|
|
102
|
+
return {
|
|
103
|
+
data: mediaFile,
|
|
104
|
+
styles: imgResult.styles,
|
|
105
|
+
blurDataUrl: imgResult.blurDataUrl
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
catch (e) {
|
|
109
|
+
console.warn(`[CMS] Image style resolution failed for media field "${field.slug}", media ${mediaFile.id}:`, e);
|
|
110
|
+
return { data: mediaFile, styles: {}, blurDataUrl: null };
|
|
111
|
+
}
|
|
114
112
|
}
|
|
115
113
|
// Video/audio: resolve transcript + audioDescription
|
|
116
114
|
let transcript = null;
|
|
@@ -143,37 +141,6 @@ export async function resolveMediaFields(data, fields) {
|
|
|
143
141
|
}
|
|
144
142
|
break;
|
|
145
143
|
}
|
|
146
|
-
case 'image': {
|
|
147
|
-
if (field.multiple && Array.isArray(val)) {
|
|
148
|
-
result[field.slug] = await Promise.all(val.map(async (id) => {
|
|
149
|
-
const mediaFile = mediaMap[id];
|
|
150
|
-
if (!mediaFile) {
|
|
151
|
-
return { data: null, styles: {} };
|
|
152
|
-
}
|
|
153
|
-
const imgResult = await getImageStyles(field, mediaFile);
|
|
154
|
-
return {
|
|
155
|
-
data: mediaFile,
|
|
156
|
-
styles: imgResult.styles,
|
|
157
|
-
blurDataUrl: imgResult.blurDataUrl
|
|
158
|
-
};
|
|
159
|
-
}));
|
|
160
|
-
}
|
|
161
|
-
else {
|
|
162
|
-
const mediaFile = mediaMap[val];
|
|
163
|
-
if (!mediaFile) {
|
|
164
|
-
result[field.slug] = { data: null, styles: {} };
|
|
165
|
-
break;
|
|
166
|
-
}
|
|
167
|
-
const imgResult = await getImageStyles(field, mediaFile);
|
|
168
|
-
result[field.slug] = {
|
|
169
|
-
data: mediaFile,
|
|
170
|
-
styles: imgResult.styles,
|
|
171
|
-
blurDataUrl: imgResult.blurDataUrl
|
|
172
|
-
};
|
|
173
|
-
break;
|
|
174
|
-
}
|
|
175
|
-
break;
|
|
176
|
-
}
|
|
177
144
|
case 'file': {
|
|
178
145
|
if (field.multiple && Array.isArray(val)) {
|
|
179
146
|
result[field.slug] = val.map((id) => mediaMap[id] ?? null);
|
|
@@ -198,80 +165,62 @@ export async function resolveMediaFields(data, fields) {
|
|
|
198
165
|
break;
|
|
199
166
|
}
|
|
200
167
|
case 'object':
|
|
201
|
-
result[field.slug] =
|
|
202
|
-
...val,
|
|
203
|
-
data: await resolveValues(val.data, field.fields)
|
|
204
|
-
};
|
|
168
|
+
result[field.slug] = await resolveValues(val, field.fields);
|
|
205
169
|
break;
|
|
206
170
|
case 'blocks':
|
|
207
171
|
result[field.slug] = await Promise.all(
|
|
208
172
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
209
173
|
val.map(async (item) => {
|
|
210
|
-
|
|
211
|
-
const objectDef = field.of.find((objDef) => objDef.slug === item.slug);
|
|
174
|
+
const objectDef = field.of.find((objDef) => objDef.slug === item._slug);
|
|
212
175
|
if (objectDef) {
|
|
213
|
-
return
|
|
214
|
-
...item,
|
|
215
|
-
data: await resolveValues(item.data, objectDef.fields)
|
|
216
|
-
};
|
|
176
|
+
return await resolveValues(item, objectDef.fields);
|
|
217
177
|
}
|
|
218
|
-
// If no matching object definition found, return item unchanged
|
|
219
178
|
return item;
|
|
220
179
|
}));
|
|
221
180
|
break;
|
|
222
181
|
case 'content': {
|
|
223
|
-
// Content
|
|
182
|
+
// Content is now a single doc, not Record<lang, doc>
|
|
224
183
|
const contentField = field;
|
|
225
|
-
if (typeof val === 'object' && val
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
if (
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
if (
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
}));
|
|
263
|
-
});
|
|
264
|
-
if (promises.length > 0) {
|
|
265
|
-
await Promise.all(promises);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
resolved[lang] = cloned;
|
|
269
|
-
}
|
|
270
|
-
else {
|
|
271
|
-
resolved[lang] = doc;
|
|
184
|
+
if (val && typeof val === 'object' && val.type === 'doc') {
|
|
185
|
+
const cloned = cloneDoc(val);
|
|
186
|
+
walkMediaNodes(cloned, (node) => {
|
|
187
|
+
const mediaId = node.attrs?.['data-media-id'];
|
|
188
|
+
if (!mediaId)
|
|
189
|
+
return;
|
|
190
|
+
const mediaFile = mediaMap[mediaId];
|
|
191
|
+
if (!mediaFile)
|
|
192
|
+
return;
|
|
193
|
+
node.attrs.src = mediaFile.url;
|
|
194
|
+
if (mediaFile.width)
|
|
195
|
+
node.attrs.width = mediaFile.width;
|
|
196
|
+
if (mediaFile.height)
|
|
197
|
+
node.attrs.height = mediaFile.height;
|
|
198
|
+
if (mediaFile.alt && !node.attrs.alt)
|
|
199
|
+
node.attrs.alt = mediaFile.alt;
|
|
200
|
+
node.attrs._media = {
|
|
201
|
+
data: mediaFile,
|
|
202
|
+
...(mediaFile.type === 'image' ? { blurDataUrl: mediaFile.blurDataUrl } : {})
|
|
203
|
+
};
|
|
204
|
+
});
|
|
205
|
+
// Resolve inline block fields
|
|
206
|
+
if (contentField.inlineBlocks?.length) {
|
|
207
|
+
const promises = [];
|
|
208
|
+
walkInlineBlockNodes(cloned, (node) => {
|
|
209
|
+
const bd = node.attrs?.blockData;
|
|
210
|
+
if (!bd || typeof bd !== 'object')
|
|
211
|
+
return;
|
|
212
|
+
const def = contentField.inlineBlocks.find((b) => b.slug === node.attrs?.blockType);
|
|
213
|
+
if (!def)
|
|
214
|
+
return;
|
|
215
|
+
promises.push(resolveValues(bd, def.fields).then((resolvedBd) => {
|
|
216
|
+
node.attrs.blockData = resolvedBd;
|
|
217
|
+
}));
|
|
218
|
+
});
|
|
219
|
+
if (promises.length > 0) {
|
|
220
|
+
await Promise.all(promises);
|
|
272
221
|
}
|
|
273
222
|
}
|
|
274
|
-
result[field.slug] =
|
|
223
|
+
result[field.slug] = cloned;
|
|
275
224
|
}
|
|
276
225
|
break;
|
|
277
226
|
}
|
|
@@ -25,34 +25,30 @@ export async function resolveRelationFields(data, fields, language) {
|
|
|
25
25
|
break;
|
|
26
26
|
}
|
|
27
27
|
case 'object':
|
|
28
|
-
collectIds(val
|
|
28
|
+
collectIds(val, field.fields);
|
|
29
29
|
break;
|
|
30
30
|
case 'blocks':
|
|
31
31
|
if (Array.isArray(val)) {
|
|
32
32
|
val.forEach((item) => {
|
|
33
|
-
|
|
34
|
-
const objectDef = field.of.find((objDef) => objDef.slug === item.slug);
|
|
33
|
+
const objectDef = field.of.find((objDef) => objDef.slug === item._slug);
|
|
35
34
|
if (objectDef) {
|
|
36
|
-
collectIds(item
|
|
35
|
+
collectIds(item, objectDef.fields);
|
|
37
36
|
}
|
|
38
37
|
});
|
|
39
38
|
}
|
|
40
39
|
break;
|
|
41
40
|
case 'content': {
|
|
42
41
|
const cf = field;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
}
|
|
42
|
+
// Content is now a single doc, not Record<lang, doc>
|
|
43
|
+
if (val && typeof val === 'object' && val.type === 'doc' && cf.inlineBlocks?.length) {
|
|
44
|
+
walkInlineBlockNodes(val, (node) => {
|
|
45
|
+
const bd = node.attrs?.blockData;
|
|
46
|
+
if (!bd || typeof bd !== 'object')
|
|
47
|
+
return;
|
|
48
|
+
const def = cf.inlineBlocks.find((b) => b.slug === node.attrs?.blockType);
|
|
49
|
+
if (def)
|
|
50
|
+
collectIds(bd, def.fields);
|
|
51
|
+
});
|
|
56
52
|
}
|
|
57
53
|
break;
|
|
58
54
|
}
|
|
@@ -69,7 +65,7 @@ export async function resolveRelationFields(data, fields, language) {
|
|
|
69
65
|
ids: entriesIds,
|
|
70
66
|
language
|
|
71
67
|
});
|
|
72
|
-
const entriesMap = Object.fromEntries(entries.map((e) => [e.
|
|
68
|
+
const entriesMap = Object.fromEntries(entries.map((e) => [e._id, e]));
|
|
73
69
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
74
70
|
const resolveValues = (value, fields) => {
|
|
75
71
|
// Start with a copy of all original data to preserve non-field properties
|
|
@@ -92,50 +88,33 @@ export async function resolveRelationFields(data, fields, language) {
|
|
|
92
88
|
break;
|
|
93
89
|
}
|
|
94
90
|
case 'object':
|
|
95
|
-
result[field.slug] =
|
|
96
|
-
...val,
|
|
97
|
-
data: resolveValues(val.data, field.fields)
|
|
98
|
-
};
|
|
91
|
+
result[field.slug] = resolveValues(val, field.fields);
|
|
99
92
|
break;
|
|
100
93
|
case 'blocks':
|
|
101
94
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
102
95
|
result[field.slug] = val.map((item) => {
|
|
103
|
-
|
|
104
|
-
const objectDef = field.of.find((objDef) => objDef.slug === item.slug);
|
|
96
|
+
const objectDef = field.of.find((objDef) => objDef.slug === item._slug);
|
|
105
97
|
if (objectDef) {
|
|
106
|
-
return
|
|
107
|
-
...item,
|
|
108
|
-
data: resolveValues(item.data, objectDef.fields)
|
|
109
|
-
};
|
|
98
|
+
return resolveValues(item, objectDef.fields);
|
|
110
99
|
}
|
|
111
|
-
// If no matching object definition found, return item unchanged
|
|
112
100
|
return item;
|
|
113
101
|
});
|
|
114
102
|
break;
|
|
115
103
|
case 'content': {
|
|
116
104
|
const cf = field;
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
node.attrs.blockData = resolveValues(bd, def.fields);
|
|
131
|
-
});
|
|
132
|
-
resolved[lang] = cloned;
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
resolved[lang] = doc;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
result[field.slug] = resolved;
|
|
105
|
+
// Content is now a single doc, not Record<lang, doc>
|
|
106
|
+
if (val && typeof val === 'object' && val.type === 'doc' && cf.inlineBlocks?.length) {
|
|
107
|
+
const cloned = cloneDoc(val);
|
|
108
|
+
walkInlineBlockNodes(cloned, (node) => {
|
|
109
|
+
const bd = node.attrs?.blockData;
|
|
110
|
+
if (!bd || typeof bd !== 'object')
|
|
111
|
+
return;
|
|
112
|
+
const def = cf.inlineBlocks.find((b) => b.slug === node.attrs?.blockType);
|
|
113
|
+
if (!def)
|
|
114
|
+
return;
|
|
115
|
+
node.attrs.blockData = resolveValues(bd, def.fields);
|
|
116
|
+
});
|
|
117
|
+
result[field.slug] = cloned;
|
|
139
118
|
}
|
|
140
119
|
break;
|
|
141
120
|
}
|