@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.
Files changed (51) hide show
  1. package/README.md +42 -0
  2. package/dist/components/Icons.d.ts +0 -8
  3. package/dist/components/Icons.js +4 -216
  4. package/dist/components/{ActionToast.d.ts → action-toast/ActionToast.d.ts} +1 -2
  5. package/dist/components/{ActionToast.js → action-toast/ActionToast.js} +25 -34
  6. package/dist/components/{ActionToast.module.css → action-toast/ActionToast.module.css} +0 -79
  7. package/dist/components/ai-input/AIInput.js +433 -0
  8. package/dist/components/{AIInput.module.css → ai-input/AIInput.module.css} +111 -43
  9. package/dist/components/ai-input/badge.d.ts +14 -0
  10. package/dist/components/ai-input/badge.js +85 -0
  11. package/dist/components/{AuditLogList.d.ts → audit-log-list/AuditLogList.d.ts} +4 -8
  12. package/dist/components/{AuditLogList.js → audit-log-list/AuditLogList.js} +49 -21
  13. package/dist/components/{AuditLogList.module.css → audit-log-list/AuditLogList.module.css} +11 -65
  14. package/dist/components/dashboard/Dashboard.d.ts +2 -0
  15. package/dist/components/dashboard/Dashboard.js +15 -0
  16. package/dist/components/dashboard/Dashboard.module.css +13 -0
  17. package/dist/components/{DiffDialog.d.ts → diff-dialog/DiffDialog.d.ts} +2 -2
  18. package/dist/components/{DiffDialog.js → diff-dialog/DiffDialog.js} +200 -189
  19. package/dist/components/{DiffDialog.module.css → diff-dialog/DiffDialog.module.css} +17 -35
  20. package/dist/components/hooks/useAIChatStream.d.ts +39 -0
  21. package/dist/components/hooks/useAIChatStream.js +217 -0
  22. package/dist/components/hooks/useAISettings.js +26 -25
  23. package/dist/components/hooks/useAuditLog.d.ts +11 -0
  24. package/dist/components/hooks/useAuditLog.js +41 -0
  25. package/dist/components/hooks/useDocumentMentionSuggestions.d.ts +1 -1
  26. package/dist/components/hooks/useDocumentMentionSuggestions.js +31 -27
  27. package/dist/components/hooks/useMentions.d.ts +58 -0
  28. package/dist/components/hooks/useMentions.js +276 -0
  29. package/dist/components/hooks/usePluginConfig.d.ts +52 -0
  30. package/dist/components/hooks/usePluginConfig.js +20 -0
  31. package/dist/components/{MentionPopover.d.ts → mention-popover/MentionPopover.d.ts} +2 -4
  32. package/dist/components/{MentionPopover.js → mention-popover/MentionPopover.js} +1 -8
  33. package/dist/components/{MentionPopover.module.css → mention-popover/MentionPopover.module.css} +1 -1
  34. package/dist/exports/client.d.ts +2 -2
  35. package/dist/exports/client.js +2 -2
  36. package/dist/handlers/applyActionHandler.js +27 -7
  37. package/dist/handlers/chatHandler.js +302 -58
  38. package/dist/handlers/mediaUploadHandler.d.ts +7 -0
  39. package/dist/handlers/mediaUploadHandler.js +99 -0
  40. package/dist/handlers/mentionSuggestionHandler.js +16 -14
  41. package/dist/handlers/proposalDiffHandler.js +41 -29
  42. package/dist/index.d.ts +6 -0
  43. package/dist/index.js +39 -7
  44. package/dist/payload/collectionPermissions.js +3 -1
  45. package/dist/payload/normalizeData.d.ts +0 -6
  46. package/dist/payload/normalizeData.js +25 -13
  47. package/dist/payload/proposalData.js +4 -1
  48. package/dist/payload/schemaContext.js +98 -43
  49. package/package.json +6 -6
  50. package/dist/components/AIInput.js +0 -896
  51. /package/dist/components/{AIInput.d.ts → ai-input/AIInput.d.ts} +0 -0
@@ -44,26 +44,30 @@ const getLocaleConfigs = (req)=>{
44
44
  };
45
45
  const getSerializableOptions = (options)=>{
46
46
  if (!Array.isArray(options)) return undefined;
47
- const serializedOptions = options.map((option)=>{
47
+ const serializedOptions = options.flatMap((option)=>{
48
48
  if (typeof option === "string") {
49
- return {
50
- label: option,
51
- value: option
52
- };
49
+ return [
50
+ {
51
+ label: option,
52
+ value: option
53
+ }
54
+ ];
53
55
  }
54
- if (!isRecord(option)) return null;
56
+ if (!isRecord(option)) return [];
55
57
  const label = "label" in option ? getSerializableLabel(option.label) : undefined;
56
58
  const value = "value" in option && typeof option.value === "string" ? option.value : undefined;
57
- if (!label && !value) return null;
58
- return {
59
- ...label ? {
60
- label
61
- } : {},
62
- ...value ? {
63
- value
64
- } : {}
65
- };
66
- }).filter(Boolean);
59
+ if (!label && !value) return [];
60
+ return [
61
+ {
62
+ ...label ? {
63
+ label
64
+ } : {},
65
+ ...value ? {
66
+ value
67
+ } : {}
68
+ }
69
+ ];
70
+ });
67
71
  return serializedOptions.length > 0 ? serializedOptions : undefined;
68
72
  };
69
73
  const toNormalizeCollectionConfig = (config)=>{
@@ -288,8 +292,76 @@ export const getMentionContext = async ({ blockContexts, collectionSlugs, collec
288
292
  const context = [];
289
293
  const seen = new Set();
290
294
  const localeConfigs = getLocaleConfigs(req);
291
- const selectedLocales = (mentions.filter((mention)=>mention.type === "locale" && mention.slug).map((mention)=>mention.slug) || []).filter((locale, index, array)=>array.indexOf(locale) === index);
295
+ const localeConfigsByCode = new Map(localeConfigs.map((locale)=>[
296
+ locale.code,
297
+ locale
298
+ ]));
299
+ const collectionSlugSet = new Set(collectionSlugs);
300
+ const globalSlugSet = new Set(globalSlugs);
301
+ const collectionConfigsBySlug = new Map(req.payload.config.collections.map((collection)=>[
302
+ collection.slug,
303
+ collection
304
+ ]));
305
+ const globalConfigsBySlug = new Map(req.payload.config.globals?.map((global)=>[
306
+ global.slug,
307
+ global
308
+ ]));
309
+ const blockContextsBySlug = new Map();
310
+ for (const block of blockContexts){
311
+ const blocks = blockContextsBySlug.get(block.slug) || [];
312
+ blocks.push(block);
313
+ blockContextsBySlug.set(block.slug, blocks);
314
+ }
315
+ const selectedLocales = [];
316
+ const selectedLocaleSet = new Set();
317
+ for (const mention of mentions){
318
+ if (mention.type !== "locale" || !mention.slug || selectedLocaleSet.has(mention.slug)) continue;
319
+ selectedLocaleSet.add(mention.slug);
320
+ selectedLocales.push(mention.slug);
321
+ }
292
322
  const activeLocale = selectedLocales.at(-1);
323
+ const mentionDocResults = await Promise.all(mentions.slice(0, 8).map(async (mention)=>{
324
+ if (mention.type === "global" && mention.slug) {
325
+ const slug = mention.slug;
326
+ if (!globalSlugSet.has(slug)) return null;
327
+ const globalConfig = globalConfigsBySlug.get(slug);
328
+ if (!globalConfig) return null;
329
+ return {
330
+ doc: await req.payload.findGlobal({
331
+ depth: 2,
332
+ ...activeLocale ? {
333
+ locale: activeLocale
334
+ } : {},
335
+ overrideAccess: false,
336
+ req,
337
+ slug: slug
338
+ }).catch(()=>null),
339
+ key: `global:${slug}`
340
+ };
341
+ }
342
+ if (mention.type === "doc" && mention.collection && mention.id) {
343
+ const slug = mention.collection;
344
+ if (isInternalCollection(slug) || !collectionSlugSet.has(slug)) return null;
345
+ return {
346
+ doc: await req.payload.findByID({
347
+ collection: slug,
348
+ depth: 2,
349
+ id: mention.id,
350
+ ...activeLocale ? {
351
+ locale: activeLocale
352
+ } : {},
353
+ overrideAccess: false,
354
+ req
355
+ }).catch(()=>null),
356
+ key: `doc:${slug}:${mention.id}`
357
+ };
358
+ }
359
+ return null;
360
+ }));
361
+ const docsByMentionKey = new Map();
362
+ for (const result of mentionDocResults){
363
+ if (result) docsByMentionKey.set(result.key, result.doc);
364
+ }
293
365
  if (localeConfigs.length > 0) {
294
366
  context.push({
295
367
  activeLocale,
@@ -301,7 +373,7 @@ export const getMentionContext = async ({ blockContexts, collectionSlugs, collec
301
373
  }
302
374
  for (const mention of mentions.slice(0, 8)){
303
375
  if (mention.type === "locale" && mention.slug) {
304
- const locale = localeConfigs.find((item)=>item.code === mention.slug);
376
+ const locale = localeConfigsByCode.get(mention.slug);
305
377
  if (!locale) continue;
306
378
  const key = `locale:${locale.code}`;
307
379
  if (seen.has(key)) continue;
@@ -314,8 +386,8 @@ export const getMentionContext = async ({ blockContexts, collectionSlugs, collec
314
386
  if (mention.type === "collection" && mention.slug) {
315
387
  const slug = mention.slug;
316
388
  const key = `collection:${slug}`;
317
- if (seen.has(key) || isInternalCollection(slug) || !collectionSlugs.includes(slug)) continue;
318
- const collectionConfig = req.payload.config.collections.find((collection)=>collection.slug === slug);
389
+ if (seen.has(key) || isInternalCollection(slug) || !collectionSlugSet.has(slug)) continue;
390
+ const collectionConfig = collectionConfigsBySlug.get(slug);
319
391
  if (!collectionConfig) continue;
320
392
  seen.add(key);
321
393
  context.push(describeCollectionLikeConfig({
@@ -327,18 +399,10 @@ export const getMentionContext = async ({ blockContexts, collectionSlugs, collec
327
399
  if (mention.type === "global" && mention.slug) {
328
400
  const slug = mention.slug;
329
401
  const key = `global:${slug}`;
330
- if (seen.has(key) || !globalSlugs.includes(slug)) continue;
331
- const globalConfig = req.payload.config.globals?.find((global)=>global.slug === slug);
402
+ if (seen.has(key) || !globalSlugSet.has(slug)) continue;
403
+ const globalConfig = globalConfigsBySlug.get(slug);
332
404
  if (!globalConfig) continue;
333
- const globalDoc = await req.payload.findGlobal({
334
- depth: 2,
335
- ...activeLocale ? {
336
- locale: activeLocale
337
- } : {},
338
- overrideAccess: false,
339
- req,
340
- slug: slug
341
- }).catch(()=>null);
405
+ const globalDoc = docsByMentionKey.get(key) ?? null;
342
406
  seen.add(key);
343
407
  context.push({
344
408
  ...describeCollectionLikeConfig({
@@ -349,7 +413,7 @@ export const getMentionContext = async ({ blockContexts, collectionSlugs, collec
349
413
  });
350
414
  }
351
415
  if (mention.type === "block" && mention.slug) {
352
- const matchingBlocks = blockContexts.filter((block)=>block.slug === mention.slug && (!mention.parent || block.parent === mention.parent));
416
+ const matchingBlocks = (blockContextsBySlug.get(mention.slug) || []).filter((block)=>!mention.parent || block.parent === mention.parent);
353
417
  for (const block of matchingBlocks){
354
418
  const key = `block:${block.parent}:${block.slug}`;
355
419
  if (seen.has(key)) continue;
@@ -363,17 +427,8 @@ export const getMentionContext = async ({ blockContexts, collectionSlugs, collec
363
427
  if (mention.type === "doc" && mention.collection && mention.id) {
364
428
  const slug = mention.collection;
365
429
  const key = `doc:${slug}:${mention.id}`;
366
- if (seen.has(key) || isInternalCollection(slug) || !collectionSlugs.includes(slug)) continue;
367
- const doc = await req.payload.findByID({
368
- collection: slug,
369
- depth: 2,
370
- id: mention.id,
371
- ...activeLocale ? {
372
- locale: activeLocale
373
- } : {},
374
- overrideAccess: false,
375
- req
376
- }).catch(()=>null);
430
+ if (seen.has(key) || isInternalCollection(slug) || !collectionSlugSet.has(slug)) continue;
431
+ const doc = docsByMentionKey.get(key);
377
432
  if (!doc) continue;
378
433
  seen.add(key);
379
434
  context.push({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mvriu5/payload-ai",
3
- "version": "1.2.0",
3
+ "version": "1.3.2",
4
4
  "description": "AI assistant plugin for Payload CMS with provider selection, CMS mentions, and signed action proposals.",
5
5
  "keywords": [
6
6
  "payload",
@@ -63,7 +63,7 @@
63
63
  "test:e2e:headed": "playwright test --headed",
64
64
  "test:handlers": "vitest run tests/handlers",
65
65
  "test:unit": "vitest run tests/unit",
66
- "setup:hooks": "git config core.hooksPath .githooks"
66
+ "knip": "knip"
67
67
  },
68
68
  "devDependencies": {
69
69
  "@ai-sdk/anthropic": "^3.0.81",
@@ -71,21 +71,21 @@
71
71
  "@ai-sdk/mistral": "^3.0.37",
72
72
  "@ai-sdk/openai": "^3.0.67",
73
73
  "@openrouter/ai-sdk-provider": "^2.9.1",
74
- "@playwright/test": "^1.56.1",
75
74
  "@payloadcms/db-postgres": "3.84.1",
76
75
  "@payloadcms/next": "3.84.1",
77
76
  "@payloadcms/richtext-lexical": "3.84.1",
78
77
  "@payloadcms/ui": "3.84.1",
78
+ "@playwright/test": "^1.56.1",
79
79
  "@swc/cli": "0.8.1",
80
80
  "@types/node": "25.9.3",
81
81
  "@types/react": "19.2.17",
82
82
  "@types/react-dom": "19.2.3",
83
83
  "copyfiles": "2.4.1",
84
- "cross-env": "^7.0.3",
84
+ "cross-env": "^10.1.0",
85
85
  "eslint": "^10.5.0",
86
- "graphql": "^16.8.1",
86
+ "graphql": "^17.0.1",
87
87
  "jsdom": "^29.1.1",
88
- "knip": "^6.16.1",
88
+ "knip": "^6.18.0",
89
89
  "next": "16.2.9",
90
90
  "payload": "3.84.1",
91
91
  "prettier": "^3.8.4",