@mvriu5/payload-ai 1.2.0 → 1.3.2
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/README.md +42 -0
- package/dist/components/Icons.d.ts +0 -8
- package/dist/components/Icons.js +4 -216
- package/dist/components/{ActionToast.d.ts → action-toast/ActionToast.d.ts} +1 -2
- package/dist/components/{ActionToast.js → action-toast/ActionToast.js} +25 -34
- package/dist/components/{ActionToast.module.css → action-toast/ActionToast.module.css} +0 -79
- package/dist/components/ai-input/AIInput.js +433 -0
- package/dist/components/{AIInput.module.css → ai-input/AIInput.module.css} +111 -43
- package/dist/components/ai-input/badge.d.ts +14 -0
- package/dist/components/ai-input/badge.js +85 -0
- package/dist/components/{AuditLogList.d.ts → audit-log-list/AuditLogList.d.ts} +4 -8
- package/dist/components/{AuditLogList.js → audit-log-list/AuditLogList.js} +49 -21
- package/dist/components/{AuditLogList.module.css → audit-log-list/AuditLogList.module.css} +11 -65
- package/dist/components/dashboard/Dashboard.d.ts +2 -0
- package/dist/components/dashboard/Dashboard.js +15 -0
- package/dist/components/dashboard/Dashboard.module.css +13 -0
- package/dist/components/{DiffDialog.d.ts → diff-dialog/DiffDialog.d.ts} +2 -2
- package/dist/components/{DiffDialog.js → diff-dialog/DiffDialog.js} +200 -189
- package/dist/components/{DiffDialog.module.css → diff-dialog/DiffDialog.module.css} +17 -35
- package/dist/components/hooks/useAIChatStream.d.ts +39 -0
- package/dist/components/hooks/useAIChatStream.js +217 -0
- package/dist/components/hooks/useAISettings.js +26 -25
- package/dist/components/hooks/useAuditLog.d.ts +11 -0
- package/dist/components/hooks/useAuditLog.js +41 -0
- package/dist/components/hooks/useDocumentMentionSuggestions.d.ts +1 -1
- package/dist/components/hooks/useDocumentMentionSuggestions.js +31 -27
- package/dist/components/hooks/useMentions.d.ts +58 -0
- package/dist/components/hooks/useMentions.js +276 -0
- package/dist/components/hooks/usePluginConfig.d.ts +52 -0
- package/dist/components/hooks/usePluginConfig.js +20 -0
- package/dist/components/{MentionPopover.d.ts → mention-popover/MentionPopover.d.ts} +2 -4
- package/dist/components/{MentionPopover.js → mention-popover/MentionPopover.js} +1 -8
- package/dist/components/{MentionPopover.module.css → mention-popover/MentionPopover.module.css} +1 -1
- package/dist/exports/client.d.ts +2 -2
- package/dist/exports/client.js +2 -2
- package/dist/handlers/applyActionHandler.js +27 -7
- package/dist/handlers/chatHandler.js +302 -58
- package/dist/handlers/mediaUploadHandler.d.ts +7 -0
- package/dist/handlers/mediaUploadHandler.js +99 -0
- package/dist/handlers/mentionSuggestionHandler.js +16 -14
- package/dist/handlers/proposalDiffHandler.js +41 -29
- package/dist/index.d.ts +6 -0
- package/dist/index.js +39 -7
- package/dist/payload/collectionPermissions.js +3 -1
- package/dist/payload/normalizeData.d.ts +0 -6
- package/dist/payload/normalizeData.js +25 -13
- package/dist/payload/proposalData.js +4 -1
- package/dist/payload/schemaContext.js +98 -43
- package/package.json +6 -6
- package/dist/components/AIInput.js +0 -896
- /package/dist/components/{AIInput.d.ts → ai-input/AIInput.d.ts} +0 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { addDataAndFileToRequest } from "payload";
|
|
2
|
+
import { getNumber, getString, isRecord } from "../payload/shared.js";
|
|
3
|
+
const mimeTypeMatches = (mimeType, acceptedMimeType)=>{
|
|
4
|
+
if (acceptedMimeType === mimeType) return true;
|
|
5
|
+
if (!acceptedMimeType.endsWith("/*")) return false;
|
|
6
|
+
return mimeType.startsWith(`${acceptedMimeType.slice(0, -2)}/`);
|
|
7
|
+
};
|
|
8
|
+
const isAcceptedMimeType = (mimeType, acceptedMimeTypes)=>{
|
|
9
|
+
if (!acceptedMimeTypes || acceptedMimeTypes.length === 0) return true;
|
|
10
|
+
return acceptedMimeTypes.some((acceptedMimeType)=>mimeTypeMatches(mimeType, acceptedMimeType));
|
|
11
|
+
};
|
|
12
|
+
const getUploadData = (data)=>{
|
|
13
|
+
if (!isRecord(data)) return {};
|
|
14
|
+
const { collection: _collection, file: _file, ...uploadData } = data;
|
|
15
|
+
return uploadData;
|
|
16
|
+
};
|
|
17
|
+
const getMediaAttachment = ({ collectionSlug, doc, file })=>{
|
|
18
|
+
const record = isRecord(doc) ? doc : {};
|
|
19
|
+
const id = record.id;
|
|
20
|
+
return {
|
|
21
|
+
collection: collectionSlug,
|
|
22
|
+
filename: getString(record.filename) || file.name || "",
|
|
23
|
+
filesize: getNumber(record.filesize) || file.size || 0,
|
|
24
|
+
id: typeof id === "string" || typeof id === "number" ? String(id) : "",
|
|
25
|
+
mimeType: getString(record.mimeType) || file.mimetype || "",
|
|
26
|
+
type: "media",
|
|
27
|
+
url: getString(record.url)
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
export const createMediaUploadHandler = ({ acceptedMimeTypes, collectionSlug, maxFileSize })=>async (req)=>{
|
|
31
|
+
const uploadReq = req;
|
|
32
|
+
try {
|
|
33
|
+
await addDataAndFileToRequest(uploadReq);
|
|
34
|
+
const collectionConfig = uploadReq.payload.config.collections.find((collection)=>collection.slug === collectionSlug);
|
|
35
|
+
if (!collectionConfig) {
|
|
36
|
+
return Response.json({
|
|
37
|
+
error: `Upload collection not found: ${collectionSlug}`
|
|
38
|
+
}, {
|
|
39
|
+
status: 400
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
if (!collectionConfig.upload) {
|
|
43
|
+
return Response.json({
|
|
44
|
+
error: `Collection is not upload-enabled: ${collectionSlug}`
|
|
45
|
+
}, {
|
|
46
|
+
status: 400
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
const file = uploadReq.file;
|
|
50
|
+
if (!file) {
|
|
51
|
+
return Response.json({
|
|
52
|
+
error: "File is required"
|
|
53
|
+
}, {
|
|
54
|
+
status: 400
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
const fileSize = typeof file.size === "number" && Number.isFinite(file.size) ? file.size : 0;
|
|
58
|
+
if (maxFileSize && fileSize > maxFileSize) {
|
|
59
|
+
return Response.json({
|
|
60
|
+
error: `File exceeds max size of ${maxFileSize} bytes`
|
|
61
|
+
}, {
|
|
62
|
+
status: 413
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
const mimeType = file.mimetype || "";
|
|
66
|
+
if (mimeType && !isAcceptedMimeType(mimeType, acceptedMimeTypes)) {
|
|
67
|
+
return Response.json({
|
|
68
|
+
error: `File type is not accepted: ${mimeType}`
|
|
69
|
+
}, {
|
|
70
|
+
status: 415
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
const doc = await uploadReq.payload.create({
|
|
74
|
+
collection: collectionSlug,
|
|
75
|
+
data: getUploadData(uploadReq.data),
|
|
76
|
+
file: file,
|
|
77
|
+
overrideAccess: false,
|
|
78
|
+
req: uploadReq
|
|
79
|
+
});
|
|
80
|
+
return Response.json({
|
|
81
|
+
attachment: getMediaAttachment({
|
|
82
|
+
collectionSlug,
|
|
83
|
+
doc,
|
|
84
|
+
file
|
|
85
|
+
}),
|
|
86
|
+
doc
|
|
87
|
+
});
|
|
88
|
+
} catch (err) {
|
|
89
|
+
uploadReq.payload.logger.error({
|
|
90
|
+
err,
|
|
91
|
+
msg: "AI media upload failed"
|
|
92
|
+
});
|
|
93
|
+
return Response.json({
|
|
94
|
+
error: "Media upload failed."
|
|
95
|
+
}, {
|
|
96
|
+
status: 500
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
};
|
|
@@ -61,16 +61,13 @@ export const createMentionSuggestionHandler = (options = {})=>async (req)=>{
|
|
|
61
61
|
type: "doc"
|
|
62
62
|
});
|
|
63
63
|
};
|
|
64
|
-
|
|
65
|
-
if (suggestions.length >= 5) break;
|
|
64
|
+
const searchResults = await Promise.all(collections.flatMap((collection)=>{
|
|
66
65
|
const collectionFields = collection.fields;
|
|
67
66
|
const localeCodes = query && hasLocalizedFields(collectionFields) ? getLocaleCodes(req) : [];
|
|
68
67
|
const localesToSearch = localeCodes.length > 0 ? localeCodes : [
|
|
69
68
|
null
|
|
70
69
|
];
|
|
71
|
-
|
|
72
|
-
if (suggestions.length >= 5) break;
|
|
73
|
-
const result = await req.payload.find({
|
|
70
|
+
return localesToSearch.map((locale)=>req.payload.find({
|
|
74
71
|
collection: collection.slug,
|
|
75
72
|
depth: 0,
|
|
76
73
|
limit: query ? 100 : 10,
|
|
@@ -79,16 +76,21 @@ export const createMentionSuggestionHandler = (options = {})=>async (req)=>{
|
|
|
79
76
|
} : {},
|
|
80
77
|
overrideAccess: false,
|
|
81
78
|
req
|
|
79
|
+
}).then((result)=>({
|
|
80
|
+
collection,
|
|
81
|
+
result
|
|
82
|
+
})));
|
|
83
|
+
}));
|
|
84
|
+
for (const { collection, result } of searchResults){
|
|
85
|
+
if (suggestions.length >= 5) break;
|
|
86
|
+
for (const doc of result.docs){
|
|
87
|
+
if (suggestions.length >= 5) break;
|
|
88
|
+
addSuggestion({
|
|
89
|
+
collectionSlug: collection.slug,
|
|
90
|
+
doc,
|
|
91
|
+
requireLabelMatch: Boolean(normalizedQuery),
|
|
92
|
+
useAsTitle: collection.admin?.useAsTitle
|
|
82
93
|
});
|
|
83
|
-
for (const doc of result.docs){
|
|
84
|
-
if (suggestions.length >= 5) break;
|
|
85
|
-
addSuggestion({
|
|
86
|
-
collectionSlug: collection.slug,
|
|
87
|
-
doc,
|
|
88
|
-
requireLabelMatch: Boolean(normalizedQuery),
|
|
89
|
-
useAsTitle: collection.admin?.useAsTitle
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
94
|
}
|
|
93
95
|
}
|
|
94
96
|
return Response.json({
|
|
@@ -69,7 +69,7 @@ export const createProposalDiffHandler = (options = {})=>async (req)=>{
|
|
|
69
69
|
req,
|
|
70
70
|
slug: proposal.slug
|
|
71
71
|
}) : null;
|
|
72
|
-
|
|
72
|
+
const localizedResults = await Promise.all(Object.entries(preparedData.localizedData).map(async ([locale, localeData])=>{
|
|
73
73
|
const doc = await req.payload.findGlobal({
|
|
74
74
|
depth: 2,
|
|
75
75
|
fallbackLocale: false,
|
|
@@ -83,9 +83,16 @@ export const createProposalDiffHandler = (options = {})=>async (req)=>{
|
|
|
83
83
|
fields: globalFields,
|
|
84
84
|
preparedData: localeData
|
|
85
85
|
});
|
|
86
|
+
return {
|
|
87
|
+
completedData,
|
|
88
|
+
doc,
|
|
89
|
+
locale
|
|
90
|
+
};
|
|
91
|
+
}));
|
|
92
|
+
localizedResults.forEach(({ completedData, doc, locale })=>{
|
|
86
93
|
beforeByLocale[locale] = redactSensitiveData(doc);
|
|
87
94
|
afterByLocale[locale] = redactSensitiveData(mergeData(doc, completedData));
|
|
88
|
-
}
|
|
95
|
+
});
|
|
89
96
|
return Response.json({
|
|
90
97
|
after: afterByLocale,
|
|
91
98
|
before: beforeByLocale
|
|
@@ -177,38 +184,43 @@ export const createProposalDiffHandler = (options = {})=>async (req)=>{
|
|
|
177
184
|
req
|
|
178
185
|
}) : null;
|
|
179
186
|
let createFallbackSource = null;
|
|
180
|
-
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
overrideAccess: false,
|
|
188
|
-
req
|
|
189
|
-
}) : defaultLocaleDoc || {};
|
|
190
|
-
const completedData = applyLocalizedRequiredFallbackToPreparedData({
|
|
191
|
-
fallbackSource,
|
|
192
|
-
fields: collectionFields,
|
|
193
|
-
preparedData: localeData
|
|
194
|
-
});
|
|
195
|
-
if (proposal.action === "create") {
|
|
187
|
+
if (proposal.action === "create") {
|
|
188
|
+
for (const [locale, localeData] of Object.entries(preparedData.localizedData)){
|
|
189
|
+
const completedData = applyLocalizedRequiredFallbackToPreparedData({
|
|
190
|
+
fallbackSource: createFallbackSource || {},
|
|
191
|
+
fields: collectionFields,
|
|
192
|
+
preparedData: localeData
|
|
193
|
+
});
|
|
196
194
|
beforeByLocale[locale] = {};
|
|
197
195
|
afterByLocale[locale] = redactSensitiveData(completedData);
|
|
198
196
|
createFallbackSource = mergeData(createFallbackSource || {}, completedData);
|
|
199
|
-
continue;
|
|
200
197
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
198
|
+
} else {
|
|
199
|
+
const localizedResults = await Promise.all(Object.entries(preparedData.localizedData).map(async ([locale, localeData])=>{
|
|
200
|
+
const doc = await req.payload.findByID({
|
|
201
|
+
collection: proposal.collection,
|
|
202
|
+
depth: 2,
|
|
203
|
+
fallbackLocale: false,
|
|
204
|
+
id: proposal.id,
|
|
205
|
+
locale,
|
|
206
|
+
overrideAccess: false,
|
|
207
|
+
req
|
|
208
|
+
});
|
|
209
|
+
const completedData = applyLocalizedRequiredFallbackToPreparedData({
|
|
210
|
+
fallbackSource: locale === defaultLocale ? doc : defaultLocaleDoc || {},
|
|
211
|
+
fields: collectionFields,
|
|
212
|
+
preparedData: localeData
|
|
213
|
+
});
|
|
214
|
+
return {
|
|
215
|
+
completedData,
|
|
216
|
+
doc,
|
|
217
|
+
locale
|
|
218
|
+
};
|
|
219
|
+
}));
|
|
220
|
+
localizedResults.forEach(({ completedData, doc, locale })=>{
|
|
221
|
+
beforeByLocale[locale] = redactSensitiveData(doc);
|
|
222
|
+
afterByLocale[locale] = redactSensitiveData(mergeData(doc, completedData));
|
|
209
223
|
});
|
|
210
|
-
beforeByLocale[locale] = redactSensitiveData(doc);
|
|
211
|
-
afterByLocale[locale] = redactSensitiveData(mergeData(doc, completedData));
|
|
212
224
|
}
|
|
213
225
|
return Response.json({
|
|
214
226
|
after: afterByLocale,
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,12 @@ export type PayloadAIPluginOptions = {
|
|
|
6
6
|
collections?: CollectionPermissionMap;
|
|
7
7
|
disabled?: boolean;
|
|
8
8
|
maxOutputTokens?: number;
|
|
9
|
+
media?: {
|
|
10
|
+
acceptedMimeTypes?: string[];
|
|
11
|
+
collectionSlug?: string;
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
maxFileSize?: number;
|
|
14
|
+
};
|
|
9
15
|
models?: AIModelConfig;
|
|
10
16
|
};
|
|
11
17
|
export declare const payloadAiPlugin: (pluginOptions: PayloadAIPluginOptions) => (config: Config) => Config;
|
package/dist/index.js
CHANGED
|
@@ -2,13 +2,25 @@ import { aiProviders, getResolvedAIModelConfig } from "./ai/providerOptions.js";
|
|
|
2
2
|
import { createApplyActionHandler } from "./handlers/applyActionHandler.js";
|
|
3
3
|
import { createChatHandler } from "./handlers/chatHandler.js";
|
|
4
4
|
import { createMentionSuggestionHandler } from "./handlers/mentionSuggestionHandler.js";
|
|
5
|
+
import { createMediaUploadHandler } from "./handlers/mediaUploadHandler.js";
|
|
5
6
|
import { createProposalDiffHandler } from "./handlers/proposalDiffHandler.js";
|
|
6
7
|
import { createAuditLogHandler } from "./handlers/auditLogHandler.js";
|
|
7
8
|
import { resolveCollectionPermissions } from "./payload/collectionPermissions.js";
|
|
8
9
|
import { isInternalCollection } from "./payload/shared.js";
|
|
9
|
-
const
|
|
10
|
+
const resolveMediaUploadOptions = (media)=>{
|
|
11
|
+
if (!media || media.enabled === false) return null;
|
|
12
|
+
return {
|
|
13
|
+
...media.acceptedMimeTypes ? {
|
|
14
|
+
acceptedMimeTypes: media.acceptedMimeTypes
|
|
15
|
+
} : {},
|
|
16
|
+
collectionSlug: media.collectionSlug || "media",
|
|
17
|
+
...typeof media.maxFileSize === "number" && Number.isFinite(media.maxFileSize) && media.maxFileSize > 0 ? {
|
|
18
|
+
maxFileSize: Math.floor(media.maxFileSize)
|
|
19
|
+
} : {}
|
|
20
|
+
};
|
|
21
|
+
};
|
|
10
22
|
const createAIChangesCollection = ()=>({
|
|
11
|
-
slug:
|
|
23
|
+
slug: "payload-ai-auditlog",
|
|
12
24
|
access: {
|
|
13
25
|
create: ()=>false,
|
|
14
26
|
delete: ()=>false,
|
|
@@ -156,9 +168,10 @@ export const payloadAiPlugin = (pluginOptions)=>(config)=>{
|
|
|
156
168
|
const collectionPermissions = resolveCollectionPermissions(pluginOptions.collections);
|
|
157
169
|
const allowUserApiKeys = pluginOptions.allowUserApiKeys !== false;
|
|
158
170
|
const modelConfig = getResolvedAIModelConfig(pluginOptions.models);
|
|
171
|
+
const mediaUploadOptions = resolveMediaUploadOptions(pluginOptions.media);
|
|
159
172
|
const maxOutputTokens = typeof pluginOptions.maxOutputTokens === "number" && Number.isFinite(pluginOptions.maxOutputTokens) && pluginOptions.maxOutputTokens > 0 ? Math.floor(pluginOptions.maxOutputTokens) : undefined;
|
|
160
173
|
if (!config.collections) config.collections = [];
|
|
161
|
-
if (!config.collections.some((collection)=>collection.slug ===
|
|
174
|
+
if (!config.collections.some((collection)=>collection.slug === "payload-ai-auditlog")) {
|
|
162
175
|
config.collections.push(createAIChangesCollection());
|
|
163
176
|
}
|
|
164
177
|
addAccountFields({
|
|
@@ -166,7 +179,13 @@ export const payloadAiPlugin = (pluginOptions)=>(config)=>{
|
|
|
166
179
|
config
|
|
167
180
|
});
|
|
168
181
|
if (pluginOptions.disabled) return config;
|
|
169
|
-
const mentionCollectionSlugs = config.collections.
|
|
182
|
+
const mentionCollectionSlugs = config.collections.flatMap((collection)=>{
|
|
183
|
+
if (isInternalCollection(collection.slug)) return [];
|
|
184
|
+
if (collectionPermissions && !collectionPermissions[collection.slug]?.read) return [];
|
|
185
|
+
return [
|
|
186
|
+
collection.slug
|
|
187
|
+
];
|
|
188
|
+
});
|
|
170
189
|
if (!config.endpoints) config.endpoints = [];
|
|
171
190
|
if (!config.admin) config.admin = {};
|
|
172
191
|
config.admin.custom = {
|
|
@@ -175,12 +194,18 @@ export const payloadAiPlugin = (pluginOptions)=>(config)=>{
|
|
|
175
194
|
...config.admin.custom?.payloadAiPlugin || {},
|
|
176
195
|
collectionSlugs: mentionCollectionSlugs,
|
|
177
196
|
allowUserApiKeys,
|
|
197
|
+
...mediaUploadOptions ? {
|
|
198
|
+
media: {
|
|
199
|
+
...mediaUploadOptions,
|
|
200
|
+
enabled: true
|
|
201
|
+
}
|
|
202
|
+
} : {},
|
|
178
203
|
models: modelConfig
|
|
179
204
|
}
|
|
180
205
|
};
|
|
181
206
|
if (!config.admin.components) config.admin.components = {};
|
|
182
207
|
if (!config.admin.components.beforeDashboard) config.admin.components.beforeDashboard = [];
|
|
183
|
-
config.admin.components.beforeDashboard.push(`@mvriu5/payload-ai/client#
|
|
208
|
+
config.admin.components.beforeDashboard.push(`@mvriu5/payload-ai/client#Dashboard`);
|
|
184
209
|
config.endpoints.push({
|
|
185
210
|
handler: createChatHandler({
|
|
186
211
|
allowUserApiKeys,
|
|
@@ -193,7 +218,7 @@ export const payloadAiPlugin = (pluginOptions)=>(config)=>{
|
|
|
193
218
|
});
|
|
194
219
|
config.endpoints.push({
|
|
195
220
|
handler: createApplyActionHandler({
|
|
196
|
-
changeLogCollection:
|
|
221
|
+
changeLogCollection: "payload-ai-auditlog",
|
|
197
222
|
collections: collectionPermissions
|
|
198
223
|
}),
|
|
199
224
|
method: "post",
|
|
@@ -201,7 +226,7 @@ export const payloadAiPlugin = (pluginOptions)=>(config)=>{
|
|
|
201
226
|
});
|
|
202
227
|
config.endpoints.push({
|
|
203
228
|
handler: createAuditLogHandler({
|
|
204
|
-
changeLogCollection:
|
|
229
|
+
changeLogCollection: "payload-ai-auditlog"
|
|
205
230
|
}),
|
|
206
231
|
method: "get",
|
|
207
232
|
path: "/ai-audit-log"
|
|
@@ -220,6 +245,13 @@ export const payloadAiPlugin = (pluginOptions)=>(config)=>{
|
|
|
220
245
|
method: "post",
|
|
221
246
|
path: "/ai-mention-suggestion"
|
|
222
247
|
});
|
|
248
|
+
if (mediaUploadOptions) {
|
|
249
|
+
config.endpoints.push({
|
|
250
|
+
handler: createMediaUploadHandler(mediaUploadOptions),
|
|
251
|
+
method: "post",
|
|
252
|
+
path: "/ai-upload-media"
|
|
253
|
+
});
|
|
254
|
+
}
|
|
223
255
|
if (incomingOnInit) {
|
|
224
256
|
config.onInit = async (payload)=>{
|
|
225
257
|
await incomingOnInit(payload);
|
|
@@ -6,7 +6,9 @@ const allActions = [
|
|
|
6
6
|
"update"
|
|
7
7
|
];
|
|
8
8
|
const getKnownCollectionSlugs = (req)=>{
|
|
9
|
-
return req.payload.config.collections.
|
|
9
|
+
return req.payload.config.collections.flatMap((collection)=>isInternalCollection(collection.slug) ? [] : [
|
|
10
|
+
collection.slug
|
|
11
|
+
]);
|
|
10
12
|
};
|
|
11
13
|
export const resolveCollectionPermissions = (collections)=>{
|
|
12
14
|
if (!collections) return undefined;
|
|
@@ -33,15 +33,9 @@ export type NormalizedData = {
|
|
|
33
33
|
droppedFields: string[];
|
|
34
34
|
};
|
|
35
35
|
export declare const isAuthCollection: (collectionConfig?: CollectionConfig | null) => boolean;
|
|
36
|
-
export declare const getCollectionFields: (collectionConfig?: CollectionConfig | null) => FieldConfig[];
|
|
37
36
|
export declare const hasDrafts: (collectionConfig?: CollectionConfig | null) => boolean;
|
|
38
37
|
export declare const getSchemaFields: (collectionConfig?: CollectionConfig | null) => FieldConfig[];
|
|
39
38
|
export declare const createLexicalText: (value: unknown) => Record<string, unknown>;
|
|
40
39
|
export declare const normalizeAuthData: (collectionConfig: CollectionConfig | undefined, normalized: NormalizedData) => NormalizedData;
|
|
41
40
|
export declare const normalizeDataForFields: (fields: readonly FieldConfig[], data: Record<string, unknown>) => NormalizedData;
|
|
42
|
-
export declare const getLocalizedRequiredFallbackData: ({ fields, source, target, }: {
|
|
43
|
-
fields: readonly FieldConfig[];
|
|
44
|
-
source: Record<string, unknown>;
|
|
45
|
-
target: Record<string, unknown>;
|
|
46
|
-
}) => Record<string, unknown>;
|
|
47
41
|
export {};
|
|
@@ -6,7 +6,7 @@ const getNamedFields = (fields)=>{
|
|
|
6
6
|
export const isAuthCollection = (collectionConfig)=>{
|
|
7
7
|
return Boolean(collectionConfig?.auth);
|
|
8
8
|
};
|
|
9
|
-
|
|
9
|
+
const getCollectionFields = (collectionConfig)=>{
|
|
10
10
|
const fields = [
|
|
11
11
|
...collectionConfig?.fields || []
|
|
12
12
|
];
|
|
@@ -45,7 +45,12 @@ export const getSchemaFields = (collectionConfig)=>{
|
|
|
45
45
|
export const createLexicalText = (value)=>{
|
|
46
46
|
if (isRecord(value) && isRecord(value.root)) return value;
|
|
47
47
|
const text = Array.isArray(value) ? value.join("\n") : String(value || "");
|
|
48
|
-
const lines = text.split("\n").
|
|
48
|
+
const lines = text.split("\n").flatMap((line)=>{
|
|
49
|
+
const trimmedLine = line.trim();
|
|
50
|
+
return trimmedLine ? [
|
|
51
|
+
trimmedLine
|
|
52
|
+
] : [];
|
|
53
|
+
});
|
|
49
54
|
return {
|
|
50
55
|
root: {
|
|
51
56
|
children: (lines.length ? lines : [
|
|
@@ -89,7 +94,12 @@ const normalizeArrayValue = (field, value)=>{
|
|
|
89
94
|
});
|
|
90
95
|
};
|
|
91
96
|
const getOptionValues = (field)=>{
|
|
92
|
-
return (field.options || []).
|
|
97
|
+
return (field.options || []).flatMap((option)=>{
|
|
98
|
+
const value = typeof option === "string" ? option : option.value;
|
|
99
|
+
return value ? [
|
|
100
|
+
value
|
|
101
|
+
] : [];
|
|
102
|
+
});
|
|
93
103
|
};
|
|
94
104
|
const normalizeOptionValue = (field, value)=>{
|
|
95
105
|
const optionValues = getOptionValues(field);
|
|
@@ -101,19 +111,21 @@ const normalizeOptionValue = (field, value)=>{
|
|
|
101
111
|
};
|
|
102
112
|
const normalizeBlocksValue = (field, value)=>{
|
|
103
113
|
if (!Array.isArray(value)) return value;
|
|
104
|
-
return value.
|
|
105
|
-
if (!isRecord(item)) return
|
|
114
|
+
return value.flatMap((item)=>{
|
|
115
|
+
if (!isRecord(item)) return [];
|
|
106
116
|
const blockType = typeof item.blockType === "string" ? item.blockType : typeof item.type === "string" ? item.type : typeof item.slug === "string" ? item.slug : null;
|
|
107
|
-
if (!blockType) return
|
|
117
|
+
if (!blockType) return [];
|
|
108
118
|
const block = field.blocks?.find((candidate)=>candidate.slug === blockType);
|
|
109
|
-
if (!block) return
|
|
119
|
+
if (!block) return [];
|
|
110
120
|
const { blockType: _blockType, type: _type, slug: _slug, ...data } = item;
|
|
111
121
|
const normalizedBlock = normalizeDataForFields(block.fields || [], data).data;
|
|
112
|
-
return
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
122
|
+
return [
|
|
123
|
+
{
|
|
124
|
+
...normalizedBlock,
|
|
125
|
+
blockType
|
|
126
|
+
}
|
|
127
|
+
];
|
|
128
|
+
});
|
|
117
129
|
};
|
|
118
130
|
const normalizeFieldValue = (field, value)=>{
|
|
119
131
|
if (value === undefined) return value;
|
|
@@ -209,7 +221,7 @@ export const normalizeDataForFields = (fields, data)=>{
|
|
|
209
221
|
droppedFields
|
|
210
222
|
};
|
|
211
223
|
};
|
|
212
|
-
|
|
224
|
+
const getLocalizedRequiredFallbackData = ({ fields, source, target })=>{
|
|
213
225
|
const fallbackData = {};
|
|
214
226
|
for (const field of getNamedFields(fields)){
|
|
215
227
|
const targetValue = target[field.name];
|
|
@@ -69,7 +69,10 @@ const normalizeRelationshipScalar = (value)=>{
|
|
|
69
69
|
}
|
|
70
70
|
const trimmedValue = value.trim();
|
|
71
71
|
if (!trimmedValue || /\s/.test(trimmedValue)) return undefined;
|
|
72
|
-
if (/^\d+$/.test(trimmedValue)
|
|
72
|
+
if (/^\d+$/.test(trimmedValue)) {
|
|
73
|
+
const numericValue = Number(trimmedValue);
|
|
74
|
+
return numericValue > 0 ? numericValue : undefined;
|
|
75
|
+
}
|
|
73
76
|
return trimmedValue;
|
|
74
77
|
};
|
|
75
78
|
const normalizeRelationshipValue = ({ field, issues, path, value })=>{
|