@mvriu5/payload-ai 1.1.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/AIInput.js +155 -6
- package/dist/components/AIInput.module.css +11 -2
- package/dist/components/ActionToast.d.ts +2 -1
- package/dist/components/ActionToast.js +3 -2
- package/dist/handlers/applyActionHandler.js +316 -107
- package/dist/handlers/chatHandler.js +660 -48
- package/dist/handlers/proposalDiffHandler.js +81 -26
- package/dist/payload/logging.d.ts +9 -0
- package/dist/payload/logging.js +14 -0
- package/dist/payload/normalizeData.d.ts +17 -7
- package/dist/payload/normalizeData.js +22 -1
- package/dist/payload/proposalData.d.ts +31 -0
- package/dist/payload/proposalData.js +575 -0
- package/dist/payload/schemaContext.d.ts +3 -7
- package/dist/payload/schemaContext.js +49 -23
- package/package.json +1 -1
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
import { verifyActionProposal } from "../ai/proposalSigning.js";
|
|
2
2
|
import { redactSensitiveData } from "../ai/sensitiveData.js";
|
|
3
|
-
import {
|
|
3
|
+
import { getSchemaFields } from "../payload/normalizeData.js";
|
|
4
|
+
import { applyLocalizedRequiredFallbackToPreparedData, prepareProposalWriteData } from "../payload/proposalData.js";
|
|
4
5
|
import { isCollectionActionAllowed } from "../payload/collectionPermissions.js";
|
|
5
6
|
import { getDefaultLocale, hasLocalizedData, isActionProposal, mergeData } from "../payload/shared.js";
|
|
6
|
-
const applyLocalizedRequiredFallback = ({ data, fallbackSource, fields })=>{
|
|
7
|
-
return mergeData(getLocalizedRequiredFallbackData({
|
|
8
|
-
fields,
|
|
9
|
-
source: fallbackSource,
|
|
10
|
-
target: data
|
|
11
|
-
}), data);
|
|
12
|
-
};
|
|
13
7
|
export const createProposalDiffHandler = (options = {})=>async (req)=>{
|
|
14
8
|
if (!req.user) return Response.json({
|
|
15
9
|
error: "Unauthorized"
|
|
@@ -34,6 +28,7 @@ export const createProposalDiffHandler = (options = {})=>async (req)=>{
|
|
|
34
28
|
status: 400
|
|
35
29
|
});
|
|
36
30
|
try {
|
|
31
|
+
const inferenceText = body?.prompt;
|
|
37
32
|
const defaultLocale = getDefaultLocale(req);
|
|
38
33
|
if (proposal.action === "updateGlobal") {
|
|
39
34
|
const globalConfig = req.payload.config.globals?.find((global)=>global.slug === proposal.slug);
|
|
@@ -45,7 +40,27 @@ export const createProposalDiffHandler = (options = {})=>async (req)=>{
|
|
|
45
40
|
if (hasLocalizedData(proposal)) {
|
|
46
41
|
const beforeByLocale = {};
|
|
47
42
|
const afterByLocale = {};
|
|
48
|
-
const globalFields =
|
|
43
|
+
const globalFields = getSchemaFields({
|
|
44
|
+
fields: globalConfig.fields || [],
|
|
45
|
+
slug: proposal.slug
|
|
46
|
+
});
|
|
47
|
+
const preparedData = prepareProposalWriteData({
|
|
48
|
+
collectionConfig: {
|
|
49
|
+
fields: globalConfig.fields || [],
|
|
50
|
+
slug: proposal.slug
|
|
51
|
+
},
|
|
52
|
+
inferenceText,
|
|
53
|
+
label: proposal.label,
|
|
54
|
+
localizedData: proposal.localizedData,
|
|
55
|
+
mode: "update"
|
|
56
|
+
});
|
|
57
|
+
if (preparedData.issues.length > 0 || !preparedData.localizedData) {
|
|
58
|
+
return Response.json({
|
|
59
|
+
error: "Proposal is invalid."
|
|
60
|
+
}, {
|
|
61
|
+
status: 400
|
|
62
|
+
});
|
|
63
|
+
}
|
|
49
64
|
const defaultLocaleDoc = defaultLocale ? await req.payload.findGlobal({
|
|
50
65
|
depth: 2,
|
|
51
66
|
fallbackLocale: false,
|
|
@@ -54,8 +69,7 @@ export const createProposalDiffHandler = (options = {})=>async (req)=>{
|
|
|
54
69
|
req,
|
|
55
70
|
slug: proposal.slug
|
|
56
71
|
}) : null;
|
|
57
|
-
for (const [locale, localeData] of Object.entries(
|
|
58
|
-
const normalized = normalizeDataForFields(globalFields, localeData);
|
|
72
|
+
for (const [locale, localeData] of Object.entries(preparedData.localizedData)){
|
|
59
73
|
const doc = await req.payload.findGlobal({
|
|
60
74
|
depth: 2,
|
|
61
75
|
fallbackLocale: false,
|
|
@@ -64,10 +78,10 @@ export const createProposalDiffHandler = (options = {})=>async (req)=>{
|
|
|
64
78
|
req,
|
|
65
79
|
slug: proposal.slug
|
|
66
80
|
});
|
|
67
|
-
const completedData =
|
|
68
|
-
data: normalized.data,
|
|
81
|
+
const completedData = applyLocalizedRequiredFallbackToPreparedData({
|
|
69
82
|
fallbackSource: locale === defaultLocale ? doc : defaultLocaleDoc || doc,
|
|
70
|
-
fields: globalFields
|
|
83
|
+
fields: globalFields,
|
|
84
|
+
preparedData: localeData
|
|
71
85
|
});
|
|
72
86
|
beforeByLocale[locale] = redactSensitiveData(doc);
|
|
73
87
|
afterByLocale[locale] = redactSensitiveData(mergeData(doc, completedData));
|
|
@@ -77,7 +91,23 @@ export const createProposalDiffHandler = (options = {})=>async (req)=>{
|
|
|
77
91
|
before: beforeByLocale
|
|
78
92
|
});
|
|
79
93
|
}
|
|
80
|
-
const
|
|
94
|
+
const preparedData = prepareProposalWriteData({
|
|
95
|
+
collectionConfig: {
|
|
96
|
+
fields: globalConfig.fields || [],
|
|
97
|
+
slug: proposal.slug
|
|
98
|
+
},
|
|
99
|
+
data: proposal.data,
|
|
100
|
+
inferenceText,
|
|
101
|
+
label: proposal.label,
|
|
102
|
+
mode: "update"
|
|
103
|
+
});
|
|
104
|
+
if (preparedData.issues.length > 0 || !preparedData.data) {
|
|
105
|
+
return Response.json({
|
|
106
|
+
error: "Proposal is invalid."
|
|
107
|
+
}, {
|
|
108
|
+
status: 400
|
|
109
|
+
});
|
|
110
|
+
}
|
|
81
111
|
const doc = await req.payload.findGlobal({
|
|
82
112
|
depth: 2,
|
|
83
113
|
...proposal.locale ? {
|
|
@@ -88,7 +118,7 @@ export const createProposalDiffHandler = (options = {})=>async (req)=>{
|
|
|
88
118
|
slug: proposal.slug
|
|
89
119
|
});
|
|
90
120
|
return Response.json({
|
|
91
|
-
after: redactSensitiveData(mergeData(doc,
|
|
121
|
+
after: redactSensitiveData(mergeData(doc, preparedData.data)),
|
|
92
122
|
before: redactSensitiveData(doc)
|
|
93
123
|
});
|
|
94
124
|
}
|
|
@@ -119,9 +149,22 @@ export const createProposalDiffHandler = (options = {})=>async (req)=>{
|
|
|
119
149
|
});
|
|
120
150
|
}
|
|
121
151
|
const collectionConfig = req.payload.config.collections.find((collection)=>collection.slug === proposal.collection);
|
|
122
|
-
const collectionFields =
|
|
123
|
-
const normalizeCollectionData = (data)=>normalizeAuthData(collectionConfig, normalizeDataForFields(collectionFields, data));
|
|
152
|
+
const collectionFields = getSchemaFields(collectionConfig);
|
|
124
153
|
if (hasLocalizedData(proposal)) {
|
|
154
|
+
const preparedData = prepareProposalWriteData({
|
|
155
|
+
collectionConfig,
|
|
156
|
+
inferenceText,
|
|
157
|
+
label: proposal.label,
|
|
158
|
+
localizedData: proposal.localizedData,
|
|
159
|
+
mode: proposal.action
|
|
160
|
+
});
|
|
161
|
+
if (preparedData.issues.length > 0 || !preparedData.localizedData) {
|
|
162
|
+
return Response.json({
|
|
163
|
+
error: "Proposal is invalid."
|
|
164
|
+
}, {
|
|
165
|
+
status: 400
|
|
166
|
+
});
|
|
167
|
+
}
|
|
125
168
|
const afterByLocale = {};
|
|
126
169
|
const beforeByLocale = {};
|
|
127
170
|
const defaultLocaleDoc = proposal.action === "update" && defaultLocale ? await req.payload.findByID({
|
|
@@ -134,8 +177,7 @@ export const createProposalDiffHandler = (options = {})=>async (req)=>{
|
|
|
134
177
|
req
|
|
135
178
|
}) : null;
|
|
136
179
|
let createFallbackSource = null;
|
|
137
|
-
for (const [locale, localeData] of Object.entries(
|
|
138
|
-
const normalized = normalizeCollectionData(localeData);
|
|
180
|
+
for (const [locale, localeData] of Object.entries(preparedData.localizedData)){
|
|
139
181
|
const fallbackSource = proposal.action === "create" ? createFallbackSource || {} : locale === defaultLocale ? await req.payload.findByID({
|
|
140
182
|
collection: proposal.collection,
|
|
141
183
|
depth: 2,
|
|
@@ -145,10 +187,10 @@ export const createProposalDiffHandler = (options = {})=>async (req)=>{
|
|
|
145
187
|
overrideAccess: false,
|
|
146
188
|
req
|
|
147
189
|
}) : defaultLocaleDoc || {};
|
|
148
|
-
const completedData =
|
|
149
|
-
data: normalized.data,
|
|
190
|
+
const completedData = applyLocalizedRequiredFallbackToPreparedData({
|
|
150
191
|
fallbackSource,
|
|
151
|
-
fields: collectionFields
|
|
192
|
+
fields: collectionFields,
|
|
193
|
+
preparedData: localeData
|
|
152
194
|
});
|
|
153
195
|
if (proposal.action === "create") {
|
|
154
196
|
beforeByLocale[locale] = {};
|
|
@@ -173,10 +215,23 @@ export const createProposalDiffHandler = (options = {})=>async (req)=>{
|
|
|
173
215
|
before: beforeByLocale
|
|
174
216
|
});
|
|
175
217
|
}
|
|
176
|
-
const
|
|
218
|
+
const preparedData = prepareProposalWriteData({
|
|
219
|
+
collectionConfig,
|
|
220
|
+
data: proposal.data,
|
|
221
|
+
inferenceText,
|
|
222
|
+
label: proposal.label,
|
|
223
|
+
mode: proposal.action
|
|
224
|
+
});
|
|
225
|
+
if (preparedData.issues.length > 0 || !preparedData.data) {
|
|
226
|
+
return Response.json({
|
|
227
|
+
error: "Proposal is invalid."
|
|
228
|
+
}, {
|
|
229
|
+
status: 400
|
|
230
|
+
});
|
|
231
|
+
}
|
|
177
232
|
if (proposal.action === "create") {
|
|
178
233
|
return Response.json({
|
|
179
|
-
after: redactSensitiveData(
|
|
234
|
+
after: redactSensitiveData(preparedData.data),
|
|
180
235
|
before: {}
|
|
181
236
|
});
|
|
182
237
|
}
|
|
@@ -191,7 +246,7 @@ export const createProposalDiffHandler = (options = {})=>async (req)=>{
|
|
|
191
246
|
req
|
|
192
247
|
});
|
|
193
248
|
return Response.json({
|
|
194
|
-
after: redactSensitiveData(mergeData(doc,
|
|
249
|
+
after: redactSensitiveData(mergeData(doc, preparedData.data)),
|
|
195
250
|
before: redactSensitiveData(doc)
|
|
196
251
|
});
|
|
197
252
|
} catch (err) {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PayloadHandler } from "payload";
|
|
2
|
+
type LogLevel = "error" | "info" | "warn";
|
|
3
|
+
type LogEntry = {
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
msg: string;
|
|
6
|
+
};
|
|
7
|
+
export declare const getLogPreview: (value?: string | null) => string | null;
|
|
8
|
+
export declare const logHandlerEvent: (req: Parameters<PayloadHandler>[0], level: LogLevel, entry: LogEntry) => void;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const maxPreviewLength = 180;
|
|
2
|
+
export const getLogPreview = (value)=>{
|
|
3
|
+
if (!value) return null;
|
|
4
|
+
const trimmed = value.trim();
|
|
5
|
+
if (!trimmed) return null;
|
|
6
|
+
if (trimmed.length <= maxPreviewLength) return trimmed;
|
|
7
|
+
return `${trimmed.slice(0, maxPreviewLength).trim()}...`;
|
|
8
|
+
};
|
|
9
|
+
export const logHandlerEvent = (req, level, entry)=>{
|
|
10
|
+
const logger = req.payload?.logger;
|
|
11
|
+
const log = logger?.[level];
|
|
12
|
+
if (typeof log !== "function") return;
|
|
13
|
+
log.call(logger, entry);
|
|
14
|
+
};
|
|
@@ -1,24 +1,31 @@
|
|
|
1
1
|
export type FieldConfig = {
|
|
2
|
-
|
|
2
|
+
admin?: Record<string, unknown>;
|
|
3
|
+
blocks?: readonly BlockConfig[];
|
|
3
4
|
defaultValue?: unknown;
|
|
4
|
-
fields?: FieldConfig[];
|
|
5
|
+
fields?: readonly FieldConfig[];
|
|
6
|
+
hasMany?: boolean;
|
|
5
7
|
label?: unknown;
|
|
6
8
|
localized?: boolean;
|
|
7
9
|
name?: string;
|
|
8
|
-
options?: (string | {
|
|
10
|
+
options?: readonly (string | {
|
|
9
11
|
value?: string;
|
|
10
12
|
})[];
|
|
13
|
+
relationTo?: unknown;
|
|
11
14
|
required?: boolean;
|
|
12
15
|
type?: string;
|
|
13
16
|
};
|
|
14
17
|
type BlockConfig = {
|
|
15
|
-
fields?: FieldConfig[];
|
|
18
|
+
fields?: readonly FieldConfig[];
|
|
16
19
|
slug: string;
|
|
17
20
|
};
|
|
18
21
|
export type CollectionConfig = {
|
|
22
|
+
admin?: Record<string, unknown>;
|
|
19
23
|
auth?: unknown;
|
|
20
|
-
fields
|
|
24
|
+
fields?: readonly FieldConfig[];
|
|
21
25
|
slug: string;
|
|
26
|
+
versions?: boolean | {
|
|
27
|
+
drafts?: boolean | Record<string, unknown>;
|
|
28
|
+
};
|
|
22
29
|
};
|
|
23
30
|
export type NormalizedData = {
|
|
24
31
|
coercedFields: string[];
|
|
@@ -27,10 +34,13 @@ export type NormalizedData = {
|
|
|
27
34
|
};
|
|
28
35
|
export declare const isAuthCollection: (collectionConfig?: CollectionConfig | null) => boolean;
|
|
29
36
|
export declare const getCollectionFields: (collectionConfig?: CollectionConfig | null) => FieldConfig[];
|
|
37
|
+
export declare const hasDrafts: (collectionConfig?: CollectionConfig | null) => boolean;
|
|
38
|
+
export declare const getSchemaFields: (collectionConfig?: CollectionConfig | null) => FieldConfig[];
|
|
39
|
+
export declare const createLexicalText: (value: unknown) => Record<string, unknown>;
|
|
30
40
|
export declare const normalizeAuthData: (collectionConfig: CollectionConfig | undefined, normalized: NormalizedData) => NormalizedData;
|
|
31
|
-
export declare const normalizeDataForFields: (fields: FieldConfig[], data: Record<string, unknown>) => NormalizedData;
|
|
41
|
+
export declare const normalizeDataForFields: (fields: readonly FieldConfig[], data: Record<string, unknown>) => NormalizedData;
|
|
32
42
|
export declare const getLocalizedRequiredFallbackData: ({ fields, source, target, }: {
|
|
33
|
-
fields: FieldConfig[];
|
|
43
|
+
fields: readonly FieldConfig[];
|
|
34
44
|
source: Record<string, unknown>;
|
|
35
45
|
target: Record<string, unknown>;
|
|
36
46
|
}) => Record<string, unknown>;
|
|
@@ -21,7 +21,28 @@ export const getCollectionFields = (collectionConfig)=>{
|
|
|
21
21
|
}
|
|
22
22
|
return fields;
|
|
23
23
|
};
|
|
24
|
-
const
|
|
24
|
+
export const hasDrafts = (collectionConfig)=>{
|
|
25
|
+
const versions = collectionConfig?.versions;
|
|
26
|
+
if (!versions || versions === true || !isRecord(versions)) return false;
|
|
27
|
+
return Boolean(versions.drafts);
|
|
28
|
+
};
|
|
29
|
+
export const getSchemaFields = (collectionConfig)=>{
|
|
30
|
+
const fields = getCollectionFields(collectionConfig);
|
|
31
|
+
if (hasDrafts(collectionConfig)) {
|
|
32
|
+
fields.push({
|
|
33
|
+
defaultValue: "draft",
|
|
34
|
+
name: "_status",
|
|
35
|
+
options: [
|
|
36
|
+
"draft",
|
|
37
|
+
"published"
|
|
38
|
+
],
|
|
39
|
+
required: true,
|
|
40
|
+
type: "select"
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return fields;
|
|
44
|
+
};
|
|
45
|
+
export const createLexicalText = (value)=>{
|
|
25
46
|
if (isRecord(value) && isRecord(value.root)) return value;
|
|
26
47
|
const text = Array.isArray(value) ? value.join("\n") : String(value || "");
|
|
27
48
|
const lines = text.split("\n").map((line)=>line.trim()).filter(Boolean);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type LocalizedDataInput } from "./shared.js";
|
|
2
|
+
import { type CollectionConfig, type FieldConfig } from "./normalizeData.js";
|
|
3
|
+
type ProposalMode = "create" | "update";
|
|
4
|
+
export type ProposalValidationIssue = {
|
|
5
|
+
code: "empty_localized_data" | "invalid_array" | "invalid_block_type" | "invalid_blocks" | "invalid_checkbox" | "invalid_container" | "invalid_date" | "invalid_option" | "invalid_relationship" | "missing_required_field" | "non_localized_field_in_secondary_locale" | "unknown_field";
|
|
6
|
+
message: string;
|
|
7
|
+
path: string;
|
|
8
|
+
};
|
|
9
|
+
export type PreparedProposalData = {
|
|
10
|
+
coercedFields: string[];
|
|
11
|
+
data?: Record<string, unknown>;
|
|
12
|
+
issues: ProposalValidationIssue[];
|
|
13
|
+
localizedData?: LocalizedDataInput;
|
|
14
|
+
};
|
|
15
|
+
type PrepareProposalDataArgs = {
|
|
16
|
+
collectionConfig?: CollectionConfig;
|
|
17
|
+
data?: Record<string, unknown>;
|
|
18
|
+
inferenceText?: string;
|
|
19
|
+
label: string;
|
|
20
|
+
localizedData?: LocalizedDataInput;
|
|
21
|
+
mode: ProposalMode;
|
|
22
|
+
};
|
|
23
|
+
export declare const prepareProposalWriteData: ({ collectionConfig, data, inferenceText, label, localizedData, mode }: PrepareProposalDataArgs) => PreparedProposalData;
|
|
24
|
+
export declare const applyLocalizedRequiredFallbackToPreparedData: ({ fallbackSource, fields, preparedData, }: {
|
|
25
|
+
fallbackSource: Record<string, unknown>;
|
|
26
|
+
fields: readonly FieldConfig[];
|
|
27
|
+
preparedData: Record<string, unknown>;
|
|
28
|
+
}) => {
|
|
29
|
+
[x: string]: unknown;
|
|
30
|
+
};
|
|
31
|
+
export {};
|