@mvriu5/payload-ai 0.5.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.
Files changed (43) hide show
  1. package/README.md +99 -0
  2. package/dist/ai/proposals.d.ts +12 -0
  3. package/dist/ai/proposals.js +50 -0
  4. package/dist/ai/providerOptions.d.ts +85 -0
  5. package/dist/ai/providerOptions.js +141 -0
  6. package/dist/ai/providerRuntime.d.ts +18 -0
  7. package/dist/ai/providerRuntime.js +53 -0
  8. package/dist/ai/sensitiveData.d.ts +2 -0
  9. package/dist/ai/sensitiveData.js +30 -0
  10. package/dist/components/AIActionProposalList.d.ts +25 -0
  11. package/dist/components/AIActionProposalList.js +94 -0
  12. package/dist/components/AIActionProposalList.module.css +175 -0
  13. package/dist/components/AIApiKeyField.d.ts +2 -0
  14. package/dist/components/AIApiKeyField.js +55 -0
  15. package/dist/components/AIInput.d.ts +1 -0
  16. package/dist/components/AIInput.js +386 -0
  17. package/dist/components/AIInput.module.css +237 -0
  18. package/dist/components/CollectionMentionPopover.d.ts +16 -0
  19. package/dist/components/CollectionMentionPopover.js +77 -0
  20. package/dist/components/CollectionMentionPopover.module.css +67 -0
  21. package/dist/components/hooks/useAISettings.d.ts +10 -0
  22. package/dist/components/hooks/useAISettings.js +56 -0
  23. package/dist/components/hooks/useDocumentMentionSuggestions.d.ts +16 -0
  24. package/dist/components/hooks/useDocumentMentionSuggestions.js +53 -0
  25. package/dist/components/hooks/utils.d.ts +1 -0
  26. package/dist/components/hooks/utils.js +3 -0
  27. package/dist/endpoints/aiApplyActionEndpointHandler.d.ts +6 -0
  28. package/dist/endpoints/aiApplyActionEndpointHandler.js +164 -0
  29. package/dist/endpoints/aiChatEndpointHandler.d.ts +31 -0
  30. package/dist/endpoints/aiChatEndpointHandler.js +297 -0
  31. package/dist/endpoints/aiMentionSuggestionsEndpointHandler.d.ts +6 -0
  32. package/dist/endpoints/aiMentionSuggestionsEndpointHandler.js +63 -0
  33. package/dist/exports/client.d.ts +2 -0
  34. package/dist/exports/client.js +2 -0
  35. package/dist/index.d.ts +9 -0
  36. package/dist/index.js +75 -0
  37. package/dist/payload/normalizeData.d.ts +29 -0
  38. package/dist/payload/normalizeData.js +192 -0
  39. package/dist/payload/schemaContext.d.ts +52 -0
  40. package/dist/payload/schemaContext.js +162 -0
  41. package/dist/payload/shared.d.ts +2 -0
  42. package/dist/payload/shared.js +11 -0
  43. package/package.json +126 -0
@@ -0,0 +1,29 @@
1
+ export type FieldConfig = {
2
+ blocks?: BlockConfig[];
3
+ defaultValue?: unknown;
4
+ fields?: FieldConfig[];
5
+ name?: string;
6
+ options?: (string | {
7
+ value?: string;
8
+ })[];
9
+ type?: string;
10
+ };
11
+ type BlockConfig = {
12
+ fields?: FieldConfig[];
13
+ slug: string;
14
+ };
15
+ export type CollectionConfig = {
16
+ auth?: unknown;
17
+ fields: FieldConfig[];
18
+ slug: string;
19
+ };
20
+ export type NormalizedData = {
21
+ coercedFields: string[];
22
+ data: Record<string, unknown>;
23
+ droppedFields: string[];
24
+ };
25
+ export declare const isAuthCollection: (collectionConfig?: CollectionConfig | null) => boolean;
26
+ export declare const getCollectionFields: (collectionConfig?: CollectionConfig | null) => FieldConfig[];
27
+ export declare const normalizeAuthData: (collectionConfig: CollectionConfig | undefined, normalized: NormalizedData) => NormalizedData;
28
+ export declare const normalizeDataForFields: (fields: FieldConfig[], data: Record<string, unknown>) => NormalizedData;
29
+ export {};
@@ -0,0 +1,192 @@
1
+ const SKIP_FIELD = Symbol("skipField");
2
+ const isRecord = (value)=>{
3
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
4
+ };
5
+ const getNamedFields = (fields)=>{
6
+ return fields.filter((field)=>Boolean(field.name));
7
+ };
8
+ export const isAuthCollection = (collectionConfig)=>{
9
+ return Boolean(collectionConfig?.auth);
10
+ };
11
+ export const getCollectionFields = (collectionConfig)=>{
12
+ const fields = [
13
+ ...collectionConfig?.fields || []
14
+ ];
15
+ if (isAuthCollection(collectionConfig)) {
16
+ fields.push({
17
+ name: "email",
18
+ type: "email"
19
+ }, {
20
+ name: "password",
21
+ type: "text"
22
+ });
23
+ }
24
+ return fields;
25
+ };
26
+ const createLexicalText = (value)=>{
27
+ if (isRecord(value) && isRecord(value.root)) return value;
28
+ const text = Array.isArray(value) ? value.join("\n") : String(value || "");
29
+ const lines = text.split("\n").map((line)=>line.trim()).filter(Boolean);
30
+ return {
31
+ root: {
32
+ children: (lines.length ? lines : [
33
+ ""
34
+ ]).map((line)=>({
35
+ children: [
36
+ {
37
+ detail: 0,
38
+ format: 0,
39
+ mode: "normal",
40
+ style: "",
41
+ text: line,
42
+ type: "text",
43
+ version: 1
44
+ }
45
+ ],
46
+ direction: null,
47
+ format: "",
48
+ indent: 0,
49
+ type: "paragraph",
50
+ version: 1
51
+ })),
52
+ direction: null,
53
+ format: "",
54
+ indent: 0,
55
+ type: "root",
56
+ version: 1
57
+ }
58
+ };
59
+ };
60
+ const normalizeArrayValue = (field, value)=>{
61
+ if (!Array.isArray(value)) return value;
62
+ const childFields = getNamedFields(field.fields || []);
63
+ const itemLabelField = childFields.find((childField)=>childField.name === "label") || childFields.find((childField)=>childField.name === "title") || childFields.find((childField)=>childField.name === "name") || childFields.find((childField)=>childField.name === "value") || childFields[0];
64
+ if (!itemLabelField) return value;
65
+ return value.map((item)=>{
66
+ if (!isRecord(item)) return {
67
+ [itemLabelField.name]: item
68
+ };
69
+ return normalizeDataForFields(childFields, item).data;
70
+ });
71
+ };
72
+ const getOptionValues = (field)=>{
73
+ return (field.options || []).map((option)=>typeof option === "string" ? option : option.value).filter((option)=>Boolean(option));
74
+ };
75
+ const normalizeOptionValue = (field, value)=>{
76
+ const optionValues = getOptionValues(field);
77
+ const stringValue = value === null ? "" : String(value);
78
+ const defaultValue = typeof field.defaultValue === "string" ? field.defaultValue : null;
79
+ if (stringValue && optionValues.includes(stringValue)) return stringValue;
80
+ if (defaultValue && optionValues.includes(defaultValue)) return defaultValue;
81
+ return SKIP_FIELD;
82
+ };
83
+ const normalizeBlocksValue = (field, value)=>{
84
+ if (!Array.isArray(value)) return value;
85
+ return value.map((item)=>{
86
+ if (!isRecord(item)) return null;
87
+ const blockType = typeof item.blockType === "string" ? item.blockType : typeof item.type === "string" ? item.type : typeof item.slug === "string" ? item.slug : null;
88
+ if (!blockType) return null;
89
+ const block = field.blocks?.find((candidate)=>candidate.slug === blockType);
90
+ if (!block) return null;
91
+ const { blockType: _blockType, type: _type, slug: _slug, ...data } = item;
92
+ const normalizedBlock = normalizeDataForFields(block.fields || [], data).data;
93
+ return {
94
+ ...normalizedBlock,
95
+ blockType
96
+ };
97
+ }).filter(Boolean);
98
+ };
99
+ const normalizeFieldValue = (field, value)=>{
100
+ if (value === undefined) return value;
101
+ if (field.type === "array") return normalizeArrayValue(field, value);
102
+ if (field.type === "blocks") return normalizeBlocksValue(field, value);
103
+ if (field.type === "checkbox") return typeof value === "boolean" ? value : value === "true";
104
+ if (field.type === "group" && isRecord(value)) return normalizeDataForFields(field.fields || [], value).data;
105
+ if (field.type === "richText") return createLexicalText(value);
106
+ if ([
107
+ "radio",
108
+ "select"
109
+ ].includes(field.type || "")) return normalizeOptionValue(field, value);
110
+ if ([
111
+ "email",
112
+ "text",
113
+ "textarea"
114
+ ].includes(field.type || "")) return value === null ? value : String(value);
115
+ if (field.type === "date") {
116
+ const date = new Date(String(value));
117
+ return Number.isNaN(date.getTime()) ? value : date.toISOString();
118
+ }
119
+ return value;
120
+ };
121
+ export const normalizeAuthData = (collectionConfig, normalized)=>{
122
+ if (!isAuthCollection(collectionConfig)) return normalized;
123
+ const email = normalized.data.email;
124
+ const password = normalized.data.password;
125
+ if (email !== undefined && typeof email !== "string") {
126
+ normalized.data.email = String(email);
127
+ normalized.coercedFields.push("email");
128
+ }
129
+ if (password !== undefined && typeof password !== "string") {
130
+ normalized.data.password = String(password);
131
+ normalized.coercedFields.push("password");
132
+ }
133
+ if (typeof normalized.data.password === "string" && normalized.data.password.length > 0 && normalized.data.password.length < 8) {
134
+ throw new Error("Password must be at least 8 characters long.");
135
+ }
136
+ return normalized;
137
+ };
138
+ const getAliasFieldName = (key, fieldsByName)=>{
139
+ if (fieldsByName.has(key)) return key;
140
+ if (key.endsWith("Date")) {
141
+ const dateAlias = `${key.slice(0, -4)}At`;
142
+ if (fieldsByName.has(dateAlias)) return dateAlias;
143
+ }
144
+ return null;
145
+ };
146
+ const normalizeLooseKnownFieldValue = (key, value)=>{
147
+ if (key === "tags" && Array.isArray(value)) {
148
+ return value.map((item)=>isRecord(item) ? item : {
149
+ label: item
150
+ });
151
+ }
152
+ return value;
153
+ };
154
+ export const normalizeDataForFields = (fields, data)=>{
155
+ const namedFields = getNamedFields(fields);
156
+ const fieldsByName = new Map(namedFields.map((field)=>[
157
+ field.name,
158
+ field
159
+ ]));
160
+ const normalizedData = {};
161
+ const droppedFields = [];
162
+ const coercedFields = [];
163
+ for (const [key, value] of Object.entries(data)){
164
+ const fieldName = getAliasFieldName(key, fieldsByName);
165
+ if (!fieldName) {
166
+ const looseValue = normalizeLooseKnownFieldValue(key, value);
167
+ if (looseValue !== value) {
168
+ normalizedData[key] = looseValue;
169
+ coercedFields.push(key);
170
+ continue;
171
+ }
172
+ droppedFields.push(key);
173
+ continue;
174
+ }
175
+ const field = fieldsByName.get(fieldName);
176
+ if (!field) continue;
177
+ const normalizedValue = normalizeFieldValue(field, value);
178
+ if (normalizedValue === SKIP_FIELD) {
179
+ droppedFields.push(key);
180
+ continue;
181
+ }
182
+ if (fieldName !== key || normalizedValue !== value) {
183
+ coercedFields.push(key);
184
+ }
185
+ normalizedData[fieldName] = normalizedValue;
186
+ }
187
+ return {
188
+ coercedFields,
189
+ data: normalizedData,
190
+ droppedFields
191
+ };
192
+ };
@@ -0,0 +1,52 @@
1
+ import type { PayloadHandler } from "payload";
2
+ export type AIChatMention = {
3
+ collection?: string;
4
+ id?: string;
5
+ label?: string;
6
+ parent?: string;
7
+ slug?: string;
8
+ type?: "block" | "collection" | "doc" | "global";
9
+ };
10
+ export type FieldConfig = {
11
+ blocks?: BlockConfig[];
12
+ fields?: FieldConfig[];
13
+ hasMany?: boolean;
14
+ label?: unknown;
15
+ name?: string;
16
+ relationTo?: unknown;
17
+ required?: boolean;
18
+ type?: string;
19
+ };
20
+ type BlockConfig = {
21
+ fields?: FieldConfig[];
22
+ labels?: {
23
+ plural?: unknown;
24
+ singular?: unknown;
25
+ };
26
+ slug: string;
27
+ };
28
+ type MentionContext = {
29
+ blockContexts: (Record<string, unknown> & {
30
+ parent: string;
31
+ slug: string;
32
+ })[];
33
+ collectionSlugs: string[];
34
+ globalSlugs: string[];
35
+ mentions?: AIChatMention[];
36
+ req: Parameters<PayloadHandler>[0];
37
+ };
38
+ export declare const describeField: (field: FieldConfig) => Record<string, unknown>;
39
+ export declare const collectBlocks: ({ fields, parent, }: {
40
+ fields: FieldConfig[];
41
+ parent: string;
42
+ }) => (Record<string, unknown> & {
43
+ parent: string;
44
+ slug: string;
45
+ })[];
46
+ export declare const getAllowedCollectionSlugs: (req: Parameters<PayloadHandler>[0], collections?: string[]) => string[];
47
+ export declare const getMentionContext: ({ blockContexts, collectionSlugs, globalSlugs, mentions, req, }: MentionContext) => Promise<Record<string, unknown>[]>;
48
+ export declare const buildPromptWithMentionContext: ({ mentionContext, prompt, }: {
49
+ mentionContext: Record<string, unknown>[];
50
+ prompt: string;
51
+ }) => string;
52
+ export {};
@@ -0,0 +1,162 @@
1
+ import { getSerializableLabel, isInternalCollection } from "./shared.js";
2
+ const getSerializableRelationTo = (relationTo)=>{
3
+ if (typeof relationTo === "string") {
4
+ return relationTo;
5
+ }
6
+ if (Array.isArray(relationTo) && relationTo.every((item)=>typeof item === "string")) {
7
+ return relationTo;
8
+ }
9
+ return undefined;
10
+ };
11
+ export const describeField = (field)=>{
12
+ const label = getSerializableLabel(field.label);
13
+ const relationTo = getSerializableRelationTo(field.relationTo);
14
+ return {
15
+ ...label ? {
16
+ label
17
+ } : {},
18
+ ...field.name ? {
19
+ name: field.name
20
+ } : {},
21
+ ...field.type ? {
22
+ type: field.type
23
+ } : {},
24
+ ...field.required ? {
25
+ required: field.required
26
+ } : {},
27
+ ...field.hasMany ? {
28
+ hasMany: field.hasMany
29
+ } : {},
30
+ ...relationTo ? {
31
+ relationTo
32
+ } : {},
33
+ ...field.fields ? {
34
+ fields: field.fields.map(describeField)
35
+ } : {},
36
+ ...field.blocks ? {
37
+ blocks: field.blocks.map(describeBlock)
38
+ } : {}
39
+ };
40
+ };
41
+ const describeBlock = (block)=>{
42
+ return {
43
+ fields: (block.fields || []).map(describeField),
44
+ label: getSerializableLabel(block.labels?.singular) || block.slug,
45
+ slug: block.slug
46
+ };
47
+ };
48
+ export const collectBlocks = ({ fields, parent })=>{
49
+ const blocks = [];
50
+ for (const field of fields){
51
+ if (field.type === "blocks" && field.blocks) {
52
+ for (const block of field.blocks){
53
+ blocks.push({
54
+ ...describeBlock(block),
55
+ parent,
56
+ slug: block.slug
57
+ });
58
+ blocks.push(...collectBlocks({
59
+ fields: block.fields || [],
60
+ parent: `${parent}/${block.slug}`
61
+ }));
62
+ }
63
+ }
64
+ if (field.fields) {
65
+ blocks.push(...collectBlocks({
66
+ fields: field.fields,
67
+ parent
68
+ }));
69
+ }
70
+ }
71
+ return blocks;
72
+ };
73
+ export const getAllowedCollectionSlugs = (req, collections)=>{
74
+ const configuredSlugs = req.payload.config.collections.map((collection)=>collection.slug).filter((slug)=>!isInternalCollection(slug));
75
+ if (!collections) return configuredSlugs;
76
+ return configuredSlugs.filter((slug)=>collections.includes(slug));
77
+ };
78
+ export const getMentionContext = async ({ blockContexts, collectionSlugs, globalSlugs, mentions, req })=>{
79
+ if (!mentions || mentions.length === 0) return [];
80
+ const context = [];
81
+ const seen = new Set();
82
+ for (const mention of mentions.slice(0, 8)){
83
+ if (mention.type === "collection" && mention.slug) {
84
+ const slug = mention.slug;
85
+ const key = `collection:${slug}`;
86
+ if (seen.has(key) || isInternalCollection(slug) || !collectionSlugs.includes(slug)) continue;
87
+ const collectionConfig = req.payload.config.collections.find((collection)=>collection.slug === slug);
88
+ if (!collectionConfig) continue;
89
+ seen.add(key);
90
+ context.push({
91
+ fields: collectionConfig.fields.map(describeField),
92
+ label: collectionConfig.labels?.plural || collectionConfig.labels?.singular || slug,
93
+ slug,
94
+ type: "collection"
95
+ });
96
+ }
97
+ if (mention.type === "global" && mention.slug) {
98
+ const slug = mention.slug;
99
+ const key = `global:${slug}`;
100
+ if (seen.has(key) || !globalSlugs.includes(slug)) continue;
101
+ const globalConfig = req.payload.config.globals?.find((global)=>global.slug === slug);
102
+ if (!globalConfig) continue;
103
+ const globalDoc = await req.payload.findGlobal({
104
+ depth: 2,
105
+ overrideAccess: false,
106
+ req,
107
+ slug: slug
108
+ }).catch(()=>null);
109
+ seen.add(key);
110
+ context.push({
111
+ doc: globalDoc,
112
+ fields: globalConfig.fields.map(describeField),
113
+ label: globalConfig.label || slug,
114
+ slug,
115
+ type: "global"
116
+ });
117
+ }
118
+ if (mention.type === "block" && mention.slug) {
119
+ const matchingBlocks = blockContexts.filter((block)=>block.slug === mention.slug && (!mention.parent || block.parent === mention.parent));
120
+ for (const block of matchingBlocks){
121
+ const key = `block:${block.parent}:${block.slug}`;
122
+ if (seen.has(key)) continue;
123
+ seen.add(key);
124
+ context.push({
125
+ ...block,
126
+ type: "block"
127
+ });
128
+ }
129
+ }
130
+ if (mention.type === "doc" && mention.collection && mention.id) {
131
+ const slug = mention.collection;
132
+ const key = `doc:${slug}:${mention.id}`;
133
+ if (seen.has(key) || isInternalCollection(slug) || !collectionSlugs.includes(slug)) continue;
134
+ const doc = await req.payload.findByID({
135
+ collection: slug,
136
+ depth: 2,
137
+ id: mention.id,
138
+ overrideAccess: false,
139
+ req
140
+ }).catch(()=>null);
141
+ if (!doc) continue;
142
+ seen.add(key);
143
+ context.push({
144
+ collection: slug,
145
+ doc,
146
+ id: mention.id,
147
+ label: mention.label || mention.id,
148
+ type: "doc"
149
+ });
150
+ }
151
+ }
152
+ return context;
153
+ };
154
+ export const buildPromptWithMentionContext = ({ mentionContext, prompt })=>{
155
+ if (mentionContext.length === 0) return prompt;
156
+ return [
157
+ "The user selected the following Payload CMS references in the input. Treat inline text like `collection: Name` or `document: Name` as references to this context, not as literal content.",
158
+ JSON.stringify(mentionContext, null, 2),
159
+ "User request:",
160
+ prompt
161
+ ].join("\n\n");
162
+ };
@@ -0,0 +1,2 @@
1
+ export declare const getSerializableLabel: (label: unknown, fallback?: string) => string;
2
+ export declare const isInternalCollection: (slug: string) => boolean;
@@ -0,0 +1,11 @@
1
+ export const getSerializableLabel = (label, fallback = "")=>{
2
+ if (typeof label === "string") return label;
3
+ if (label && typeof label === "object") {
4
+ const firstLabel = Object.values(label).find((value)=>typeof value === "string");
5
+ if (typeof firstLabel === "string") return firstLabel;
6
+ }
7
+ return fallback;
8
+ };
9
+ export const isInternalCollection = (slug)=>{
10
+ return slug.startsWith("payload-") || slug === "plugin-collection";
11
+ };
package/package.json ADDED
@@ -0,0 +1,126 @@
1
+ {
2
+ "name": "@mvriu5/payload-ai",
3
+ "version": "0.5.0",
4
+ "description": "AI assistant plugin for Payload CMS with provider selection, CMS mentions, and signed action proposals.",
5
+ "keywords": [
6
+ "payload",
7
+ "payloadcms",
8
+ "payload-plugin",
9
+ "ai",
10
+ "cms",
11
+ "openai",
12
+ "anthropic",
13
+ "google-generative-ai",
14
+ "groq",
15
+ "mistral"
16
+ ],
17
+ "author": "Marius",
18
+ "license": "MIT",
19
+ "homepage": "https://github.com/mvriu5/payload-ai-plugin#readme",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/mvriu5/payload-ai-plugin.git"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/mvriu5/payload-ai-plugin/issues"
26
+ },
27
+ "type": "module",
28
+ "exports": {
29
+ ".": {
30
+ "import": "./dist/index.js",
31
+ "types": "./dist/index.d.ts",
32
+ "default": "./dist/index.js"
33
+ },
34
+ "./client": {
35
+ "import": "./dist/exports/client.js",
36
+ "types": "./dist/exports/client.d.ts",
37
+ "default": "./dist/exports/client.js"
38
+ }
39
+ },
40
+ "main": "./dist/index.js",
41
+ "types": "./dist/index.d.ts",
42
+ "files": [
43
+ "dist"
44
+ ],
45
+ "scripts": {
46
+ "build": "pnpm copyfiles && pnpm build:types && pnpm build:swc",
47
+ "build:swc": "swc ./src -d ./dist --config-file .swcrc --strip-leading-paths",
48
+ "build:types": "tsc --outDir dist --rootDir ./src",
49
+ "clean": "rimraf {dist,*.tsbuildinfo}",
50
+ "copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png,json}\" dist/",
51
+ "dev": "next dev dev --turbo",
52
+ "dev:generate-importmap": "pnpm dev:payload generate:importmap",
53
+ "dev:generate-types": "pnpm dev:payload generate:types",
54
+ "dev:payload": "cross-env PAYLOAD_CONFIG_PATH=./dev/payload.config.ts payload",
55
+ "generate:importmap": "pnpm dev:generate-importmap",
56
+ "generate:types": "pnpm dev:generate-types",
57
+ "lint": "eslint",
58
+ "lint:fix": "eslint ./src --fix",
59
+ "prepublishOnly": "pnpm clean && pnpm build"
60
+ },
61
+ "devDependencies": {
62
+ "@payloadcms/db-postgres": "3.84.1",
63
+ "@payloadcms/next": "3.84.1",
64
+ "@payloadcms/richtext-lexical": "3.84.1",
65
+ "@payloadcms/ui": "3.84.1",
66
+ "@swc/cli": "0.6.0",
67
+ "@types/node": "22.19.9",
68
+ "@types/react": "19.2.14",
69
+ "@types/react-dom": "19.2.3",
70
+ "copyfiles": "2.4.1",
71
+ "cross-env": "^7.0.3",
72
+ "eslint": "^9.23.0",
73
+ "graphql": "^16.8.1",
74
+ "knip": "^6.16.1",
75
+ "next": "16.2.6",
76
+ "payload": "3.84.1",
77
+ "react": "19.2.6",
78
+ "react-dom": "19.2.6",
79
+ "rimraf": "3.0.2",
80
+ "sharp": "0.34.2",
81
+ "typescript": "5.7.3",
82
+ "vite-tsconfig-paths": "6.0.5",
83
+ "vitest": "4.0.18"
84
+ },
85
+ "peerDependencies": {
86
+ "payload": "^3.84.1"
87
+ },
88
+ "engines": {
89
+ "node": "^18.20.2 || >=20.9.0",
90
+ "pnpm": "^9 || ^10"
91
+ },
92
+ "publishConfig": {
93
+ "access": "public"
94
+ },
95
+ "pnpm": {
96
+ "onlyBuiltDependencies": [
97
+ "sharp",
98
+ "esbuild",
99
+ "unrs-resolver"
100
+ ]
101
+ },
102
+ "registry": "https://registry.npmjs.org/",
103
+ "knip": {
104
+ "entry": [
105
+ "dev/payload.config.ts",
106
+ "dev/next.config.mjs",
107
+ "dev/app/**/*.{ts,tsx}"
108
+ ],
109
+ "ignore": [
110
+ "dev/payload-types.ts"
111
+ ],
112
+ "project": [
113
+ "src/**/*.{ts,tsx}",
114
+ "dev/**/*.{ts,tsx,mjs}"
115
+ ]
116
+ },
117
+ "dependencies": {
118
+ "@ai-sdk/anthropic": "^3.0.81",
119
+ "@ai-sdk/google": "^3.0.80",
120
+ "@ai-sdk/groq": "^3.0.39",
121
+ "@ai-sdk/mistral": "^3.0.37",
122
+ "@ai-sdk/openai": "^3.0.67",
123
+ "ai": "^6.0.193",
124
+ "zod": "^4.4.3"
125
+ }
126
+ }