@mvriu5/payload-ai 0.5.8 → 0.5.10

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 (65) hide show
  1. package/README.md +62 -6
  2. package/dist/ai/{proposals.d.ts → proposalSigning.d.ts} +1 -1
  3. package/dist/ai/{proposals.js → proposalSigning.js} +6 -11
  4. package/dist/ai/providerOptions.d.ts +17 -1
  5. package/dist/ai/providerOptions.js +35 -7
  6. package/dist/ai/providerRuntime.d.ts +2 -2
  7. package/dist/ai/providerRuntime.js +50 -16
  8. package/dist/ai/sensitiveData.js +2 -6
  9. package/dist/components/AIInput.d.ts +2 -1
  10. package/dist/components/AIInput.js +327 -41
  11. package/dist/components/AIInput.module.css +41 -6
  12. package/dist/components/APIKeyField.d.ts +3 -0
  13. package/dist/components/{AIApiKeyField.js → APIKeyField.js} +3 -4
  14. package/dist/components/ActionToast.d.ts +30 -0
  15. package/dist/components/{AIActionProposalList.js → ActionToast.js} +78 -8
  16. package/dist/components/{AIActionProposalList.module.css → ActionToast.module.css} +49 -5
  17. package/dist/components/AuditLogList.d.ts +32 -0
  18. package/dist/components/AuditLogList.js +67 -0
  19. package/dist/components/AuditLogList.module.css +152 -0
  20. package/dist/components/DiffDialog.d.ts +19 -0
  21. package/dist/components/DiffDialog.js +396 -0
  22. package/dist/components/DiffDialog.module.css +333 -0
  23. package/dist/components/Icons.d.ts +9 -0
  24. package/dist/components/Icons.js +193 -0
  25. package/dist/components/MentionPopover.d.ts +19 -0
  26. package/dist/components/{CollectionMentionPopover.js → MentionPopover.js} +11 -4
  27. package/dist/components/{CollectionMentionPopover.module.css → MentionPopover.module.css} +0 -2
  28. package/dist/components/hooks/useAISettings.d.ts +6 -4
  29. package/dist/components/hooks/useAISettings.js +18 -3
  30. package/dist/components/hooks/useDocumentMentionSuggestions.d.ts +3 -3
  31. package/dist/components/hooks/useDocumentMentionSuggestions.js +2 -2
  32. package/dist/exports/client.d.ts +4 -2
  33. package/dist/exports/client.js +4 -2
  34. package/dist/handlers/applyActionHandler.d.ts +8 -0
  35. package/dist/handlers/applyActionHandler.js +563 -0
  36. package/dist/handlers/auditLogHandler.d.ts +6 -0
  37. package/dist/handlers/auditLogHandler.js +39 -0
  38. package/dist/handlers/chatHandler.d.ts +42 -0
  39. package/dist/handlers/chatHandler.js +634 -0
  40. package/dist/handlers/mentionSuggestionHandler.d.ts +7 -0
  41. package/dist/handlers/mentionSuggestionHandler.js +97 -0
  42. package/dist/handlers/proposalDiffHandler.d.ts +7 -0
  43. package/dist/handlers/proposalDiffHandler.js +208 -0
  44. package/dist/index.d.ts +6 -6
  45. package/dist/index.js +151 -8
  46. package/dist/payload/collectionPermissions.d.ts +14 -13
  47. package/dist/payload/collectionPermissions.js +3 -2
  48. package/dist/payload/normalizeData.d.ts +8 -0
  49. package/dist/payload/normalizeData.js +25 -3
  50. package/dist/payload/schemaContext.d.ts +79 -9
  51. package/dist/payload/schemaContext.js +231 -22
  52. package/dist/payload/shared.d.ts +33 -0
  53. package/dist/payload/shared.js +114 -0
  54. package/package.json +7 -2
  55. package/dist/components/AIActionProposalList.d.ts +0 -25
  56. package/dist/components/AIApiKeyField.d.ts +0 -2
  57. package/dist/components/CollectionMentionPopover.d.ts +0 -16
  58. package/dist/components/hooks/utils.d.ts +0 -1
  59. package/dist/components/hooks/utils.js +0 -3
  60. package/dist/endpoints/aiApplyActionEndpointHandler.d.ts +0 -7
  61. package/dist/endpoints/aiApplyActionEndpointHandler.js +0 -169
  62. package/dist/endpoints/aiChatEndpointHandler.d.ts +0 -35
  63. package/dist/endpoints/aiChatEndpointHandler.js +0 -321
  64. package/dist/endpoints/aiMentionSuggestionsEndpointHandler.d.ts +0 -7
  65. package/dist/endpoints/aiMentionSuggestionsEndpointHandler.js +0 -63
@@ -0,0 +1,396 @@
1
+ import { XIcon } from "@payloadcms/ui/icons/X";
2
+ import { useEffect, useState } from "react";
3
+ import { getJSONLineKey } from "../payload/shared.js";
4
+ import styles from "./DiffDialog.module.css";
5
+ const formatDiffValue = (value)=>{
6
+ return JSON.stringify(value, null, 2);
7
+ };
8
+ const formatDateTime = (value)=>{
9
+ if (!value) return null;
10
+ const date = new Date(value);
11
+ if (Number.isNaN(date.getTime())) return value;
12
+ return new Intl.DateTimeFormat(undefined, {
13
+ dateStyle: "medium",
14
+ timeStyle: "short"
15
+ }).format(date);
16
+ };
17
+ const createLine = ({ changed, path, placeholder = false, text = "" })=>({
18
+ changed,
19
+ path,
20
+ placeholder,
21
+ text
22
+ });
23
+ const shouldPairChangedLines = (beforeLine, afterLine)=>{
24
+ const beforeKey = getJSONLineKey(beforeLine);
25
+ const afterKey = getJSONLineKey(afterLine);
26
+ return Boolean(beforeKey && afterKey && beforeKey === afterKey);
27
+ };
28
+ const getJSONLinePaths = (lines)=>{
29
+ const stack = [];
30
+ return lines.map((line)=>{
31
+ const indentation = line.match(/^\s*/)?.[0].length || 0;
32
+ const level = Math.floor(indentation / 2);
33
+ const keyMatch = /^\s*"([^"]+)":/.exec(line);
34
+ stack.length = level;
35
+ if (keyMatch?.[1]) {
36
+ stack[level] = keyMatch[1];
37
+ return stack.slice(0, level + 1).join(".");
38
+ }
39
+ return stack.slice(0, level).join(".");
40
+ });
41
+ };
42
+ const getRowPath = (row)=>{
43
+ return row.after.path || row.before.path;
44
+ };
45
+ const isChangedRow = (row)=>{
46
+ return row.before.changed || row.after.changed;
47
+ };
48
+ const buildDisplayRows = (rows, expandedGroups, groupPrefix = "")=>{
49
+ const displayRows = [];
50
+ const contextRows = 2;
51
+ let index = 0;
52
+ while(index < rows.length){
53
+ if (isChangedRow(rows[index])) {
54
+ displayRows.push({
55
+ index,
56
+ row: rows[index],
57
+ type: "row"
58
+ });
59
+ index += 1;
60
+ continue;
61
+ }
62
+ const start = index;
63
+ while(index < rows.length && !isChangedRow(rows[index])){
64
+ index += 1;
65
+ }
66
+ const end = index;
67
+ const count = end - start;
68
+ const groupID = `${start}-${end}`;
69
+ if (count <= contextRows * 2 + 2) {
70
+ for(let rowIndex = start; rowIndex < end; rowIndex += 1){
71
+ displayRows.push({
72
+ index: rowIndex,
73
+ row: rows[rowIndex],
74
+ type: "row"
75
+ });
76
+ }
77
+ continue;
78
+ }
79
+ const scopedGroupID = groupPrefix ? `${groupPrefix}:${groupID}` : groupID;
80
+ const isExpanded = expandedGroups.has(scopedGroupID);
81
+ for(let rowIndex = start; rowIndex < start + contextRows; rowIndex += 1){
82
+ displayRows.push({
83
+ index: rowIndex,
84
+ row: rows[rowIndex],
85
+ type: "row"
86
+ });
87
+ }
88
+ displayRows.push({
89
+ count: count - contextRows * 2,
90
+ expanded: isExpanded,
91
+ id: groupID,
92
+ path: getRowPath(rows[start + contextRows]),
93
+ type: "collapsed"
94
+ });
95
+ if (isExpanded) {
96
+ for(let rowIndex = start + contextRows; rowIndex < end - contextRows; rowIndex += 1){
97
+ displayRows.push({
98
+ index: rowIndex,
99
+ row: rows[rowIndex],
100
+ type: "row"
101
+ });
102
+ }
103
+ }
104
+ for(let rowIndex = end - contextRows; rowIndex < end; rowIndex += 1){
105
+ displayRows.push({
106
+ index: rowIndex,
107
+ row: rows[rowIndex],
108
+ type: "row"
109
+ });
110
+ }
111
+ }
112
+ return displayRows;
113
+ };
114
+ const getDiffRows = (before, after)=>{
115
+ const beforeLines = before.split("\n");
116
+ const afterLines = after.split("\n");
117
+ const beforeLinePaths = getJSONLinePaths(beforeLines);
118
+ const afterLinePaths = getJSONLinePaths(afterLines);
119
+ const dp = Array.from({
120
+ length: beforeLines.length + 1
121
+ }, ()=>Array(afterLines.length + 1).fill(0));
122
+ for(let i = beforeLines.length - 1; i >= 0; i -= 1){
123
+ for(let j = afterLines.length - 1; j >= 0; j -= 1){
124
+ dp[i][j] = beforeLines[i] === afterLines[j] ? dp[i + 1][j + 1] + 1 : Math.max(dp[i + 1][j], dp[i][j + 1]);
125
+ }
126
+ }
127
+ const rows = [];
128
+ let beforeIndex = 0;
129
+ let afterIndex = 0;
130
+ while(beforeIndex < beforeLines.length && afterIndex < afterLines.length){
131
+ if (beforeLines[beforeIndex] === afterLines[afterIndex]) {
132
+ rows.push({
133
+ after: createLine({
134
+ changed: false,
135
+ path: afterLinePaths[afterIndex],
136
+ text: afterLines[afterIndex]
137
+ }),
138
+ before: createLine({
139
+ changed: false,
140
+ path: beforeLinePaths[beforeIndex],
141
+ text: beforeLines[beforeIndex]
142
+ })
143
+ });
144
+ beforeIndex += 1;
145
+ afterIndex += 1;
146
+ continue;
147
+ }
148
+ if (shouldPairChangedLines(beforeLines[beforeIndex], afterLines[afterIndex])) {
149
+ rows.push({
150
+ after: createLine({
151
+ changed: true,
152
+ path: afterLinePaths[afterIndex],
153
+ text: afterLines[afterIndex]
154
+ }),
155
+ before: createLine({
156
+ changed: true,
157
+ path: beforeLinePaths[beforeIndex],
158
+ text: beforeLines[beforeIndex]
159
+ })
160
+ });
161
+ beforeIndex += 1;
162
+ afterIndex += 1;
163
+ continue;
164
+ }
165
+ if (dp[beforeIndex + 1][afterIndex] >= dp[beforeIndex][afterIndex + 1]) {
166
+ rows.push({
167
+ after: createLine({
168
+ changed: false,
169
+ placeholder: true
170
+ }),
171
+ before: createLine({
172
+ changed: true,
173
+ path: beforeLinePaths[beforeIndex],
174
+ text: beforeLines[beforeIndex]
175
+ })
176
+ });
177
+ beforeIndex += 1;
178
+ } else {
179
+ rows.push({
180
+ after: createLine({
181
+ changed: true,
182
+ path: afterLinePaths[afterIndex],
183
+ text: afterLines[afterIndex]
184
+ }),
185
+ before: createLine({
186
+ changed: false,
187
+ placeholder: true
188
+ })
189
+ });
190
+ afterIndex += 1;
191
+ }
192
+ }
193
+ while(beforeIndex < beforeLines.length){
194
+ rows.push({
195
+ after: createLine({
196
+ changed: false,
197
+ placeholder: true
198
+ }),
199
+ before: createLine({
200
+ changed: true,
201
+ path: beforeLinePaths[beforeIndex],
202
+ text: beforeLines[beforeIndex]
203
+ })
204
+ });
205
+ beforeIndex += 1;
206
+ }
207
+ while(afterIndex < afterLines.length){
208
+ rows.push({
209
+ after: createLine({
210
+ changed: true,
211
+ path: afterLinePaths[afterIndex],
212
+ text: afterLines[afterIndex]
213
+ }),
214
+ before: createLine({
215
+ changed: false,
216
+ placeholder: true
217
+ })
218
+ });
219
+ afterIndex += 1;
220
+ }
221
+ return rows;
222
+ };
223
+ const isLocaleDiffMap = (value)=>{
224
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
225
+ return Object.values(value).every((entry)=>entry && typeof entry === "object" && !Array.isArray(entry));
226
+ };
227
+ const getDiffSections = (diff)=>{
228
+ if (isLocaleDiffMap(diff.before) && isLocaleDiffMap(diff.after)) {
229
+ const beforeByLocale = diff.before;
230
+ const afterByLocale = diff.after;
231
+ const localeKeys = Array.from(new Set([
232
+ ...Object.keys(beforeByLocale),
233
+ ...Object.keys(afterByLocale)
234
+ ]));
235
+ return localeKeys.map((locale)=>({
236
+ afterValue: formatDiffValue(afterByLocale[locale] ?? {}),
237
+ beforeValue: formatDiffValue(beforeByLocale[locale] ?? {}),
238
+ id: locale,
239
+ label: `Locale: ${locale}`
240
+ }));
241
+ }
242
+ return [
243
+ {
244
+ afterValue: formatDiffValue(diff.after),
245
+ beforeValue: formatDiffValue(diff.before),
246
+ id: "default"
247
+ }
248
+ ];
249
+ };
250
+ const formatTokenUsage = (value)=>{
251
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value.toLocaleString() : null;
252
+ };
253
+ export const DiffDialog = ({ change, diff, onClose, proposal, tokenUsage })=>{
254
+ const [scrollLeft, setScrollLeft] = useState(0);
255
+ const [expandedGroups, setExpandedGroups] = useState(()=>new Set());
256
+ const diffSections = getDiffSections(diff);
257
+ const totalTokens = formatTokenUsage(change?.totalTokens) || formatTokenUsage(tokenUsage?.totalTokens);
258
+ const inputTokens = formatTokenUsage(change?.inputTokens) || formatTokenUsage(tokenUsage?.inputTokens);
259
+ const outputTokens = formatTokenUsage(change?.outputTokens) || formatTokenUsage(tokenUsage?.outputTokens);
260
+ useEffect(()=>{
261
+ const handleKeyDown = (event)=>{
262
+ if (event.key === "Escape") {
263
+ onClose();
264
+ }
265
+ };
266
+ window.addEventListener("keydown", handleKeyDown);
267
+ return ()=>{
268
+ window.removeEventListener("keydown", handleKeyDown);
269
+ };
270
+ }, [
271
+ onClose
272
+ ]);
273
+ return /*#__PURE__*/ React.createElement("div", {
274
+ "aria-modal": "true",
275
+ className: styles.dialogOverlay,
276
+ role: "dialog"
277
+ }, /*#__PURE__*/ React.createElement("div", {
278
+ className: styles.dialog
279
+ }, /*#__PURE__*/ React.createElement("div", {
280
+ className: styles.dialogHeader
281
+ }, /*#__PURE__*/ React.createElement("div", null, /*#__PURE__*/ React.createElement("div", {
282
+ className: styles.dialogTitle
283
+ }, proposal.label), /*#__PURE__*/ React.createElement("div", {
284
+ className: styles.meta
285
+ }, proposal.action, " in ", proposal.collection || proposal.slug, proposal.id ? ` #${proposal.id}` : "")), /*#__PURE__*/ React.createElement("button", {
286
+ "aria-label": "Close",
287
+ className: styles.closeButton,
288
+ onClick: onClose,
289
+ type: "button"
290
+ }, /*#__PURE__*/ React.createElement(XIcon, null))), /*#__PURE__*/ React.createElement("div", {
291
+ className: styles.dialogContent
292
+ }, change ? /*#__PURE__*/ React.createElement("div", {
293
+ className: styles.detailSection
294
+ }, /*#__PURE__*/ React.createElement("div", {
295
+ className: styles.detailGrid
296
+ }, /*#__PURE__*/ React.createElement("span", {
297
+ className: styles.detailLabel
298
+ }, "User"), /*#__PURE__*/ React.createElement("span", {
299
+ className: styles.detailValue
300
+ }, change.userLabel || change.userID || "Unknown"), /*#__PURE__*/ React.createElement("span", {
301
+ className: styles.detailLabel
302
+ }, "Date"), /*#__PURE__*/ React.createElement("span", {
303
+ className: styles.detailValue
304
+ }, formatDateTime(change.createdAt) || "Unknown"), totalTokens && /*#__PURE__*/ React.createElement(React.Fragment, null, /*#__PURE__*/ React.createElement("span", {
305
+ className: styles.detailLabel
306
+ }, "Tokens"), /*#__PURE__*/ React.createElement("span", {
307
+ className: styles.detailValue
308
+ }, totalTokens, inputTokens && outputTokens ? ` (${inputTokens} in / ${outputTokens} out)` : "")))) : totalTokens && /*#__PURE__*/ React.createElement("div", {
309
+ className: styles.detailSection
310
+ }, /*#__PURE__*/ React.createElement("div", {
311
+ className: styles.detailGrid
312
+ }, /*#__PURE__*/ React.createElement("span", {
313
+ className: styles.detailLabel
314
+ }, "Tokens"), /*#__PURE__*/ React.createElement("span", {
315
+ className: styles.detailValue
316
+ }, totalTokens, inputTokens && outputTokens ? ` (${inputTokens} in / ${outputTokens} out)` : ""))), diffSections.map((section)=>{
317
+ const diffRows = getDiffRows(section.beforeValue, section.afterValue);
318
+ const displayRows = buildDisplayRows(diffRows, expandedGroups, section.id);
319
+ const longestLineLength = Math.max(...section.beforeValue.split("\n").map((line)=>line.length), ...section.afterValue.split("\n").map((line)=>line.length), 80);
320
+ const diffShellStyle = {
321
+ "--diff-line-offset": `-${scrollLeft}px`,
322
+ "--diff-line-width": `${longestLineLength + 8}ch`
323
+ };
324
+ return /*#__PURE__*/ React.createElement("div", {
325
+ className: styles.diffSection,
326
+ key: section.id
327
+ }, section.label ? /*#__PURE__*/ React.createElement("div", {
328
+ className: styles.diffSectionLabel
329
+ }, section.label) : null, /*#__PURE__*/ React.createElement("div", {
330
+ className: styles.diffShell,
331
+ style: diffShellStyle
332
+ }, /*#__PURE__*/ React.createElement("div", {
333
+ className: styles.diffScroll
334
+ }, /*#__PURE__*/ React.createElement("div", {
335
+ className: styles.diffHeaderGrid
336
+ }, /*#__PURE__*/ React.createElement("div", {
337
+ className: styles.diffPaneHeader
338
+ }, "Current"), /*#__PURE__*/ React.createElement("div", {
339
+ className: styles.diffPaneHeader
340
+ }, "Proposed")), /*#__PURE__*/ React.createElement("div", {
341
+ className: styles.diffRows
342
+ }, displayRows.map((displayRow)=>{
343
+ if (displayRow.type === "collapsed") {
344
+ return /*#__PURE__*/ React.createElement("button", {
345
+ className: styles.diffCollapsedRow,
346
+ key: `${section.id}-collapsed-${displayRow.id}`,
347
+ onClick: ()=>{
348
+ setExpandedGroups((current)=>{
349
+ const next = new Set(current);
350
+ const groupID = `${section.id}:${displayRow.id}`;
351
+ if (displayRow.expanded) {
352
+ next.delete(groupID);
353
+ } else {
354
+ next.add(groupID);
355
+ }
356
+ return next;
357
+ });
358
+ },
359
+ type: "button"
360
+ }, displayRow.expanded ? "Hide" : "Show", " ", displayRow.count, " unchanged lines", displayRow.path && /*#__PURE__*/ React.createElement("span", {
361
+ className: styles.diffCollapsedPath
362
+ }, displayRow.path));
363
+ }
364
+ const row = displayRow.row;
365
+ return /*#__PURE__*/ React.createElement("div", {
366
+ className: styles.diffRow,
367
+ key: `${section.id}-row-${displayRow.index}`
368
+ }, /*#__PURE__*/ React.createElement("span", {
369
+ className: [
370
+ styles.diffLine,
371
+ row.before.changed && styles.diffLineRemoved,
372
+ row.before.placeholder && styles.diffLinePlaceholder
373
+ ].filter(Boolean).join(" ")
374
+ }, row.before.changed && row.before.path && /*#__PURE__*/ React.createElement("span", {
375
+ className: styles.diffPathBadge
376
+ }, row.before.path), /*#__PURE__*/ React.createElement("span", {
377
+ className: styles.diffLineContent
378
+ }, row.before.text || " ")), /*#__PURE__*/ React.createElement("span", {
379
+ className: [
380
+ styles.diffLine,
381
+ row.after.changed && styles.diffLineAdded,
382
+ row.after.placeholder && styles.diffLinePlaceholder
383
+ ].filter(Boolean).join(" ")
384
+ }, row.after.changed && row.after.path && /*#__PURE__*/ React.createElement("span", {
385
+ className: styles.diffPathBadge
386
+ }, row.after.path), /*#__PURE__*/ React.createElement("span", {
387
+ className: styles.diffLineContent
388
+ }, row.after.text || " ")));
389
+ }))), /*#__PURE__*/ React.createElement("div", {
390
+ className: styles.horizontalScroll,
391
+ onScroll: (event)=>setScrollLeft(event.currentTarget.scrollLeft)
392
+ }, /*#__PURE__*/ React.createElement("div", {
393
+ className: styles.horizontalScrollSpacer
394
+ }))));
395
+ }))));
396
+ };