@simmalugnt-se/payload-editor-assistant 0.1.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 (102) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +32 -0
  3. package/dist/capabilities.d.ts +10 -0
  4. package/dist/capabilities.js +43 -0
  5. package/dist/collections/approvals.d.ts +2 -0
  6. package/dist/collections/approvals.js +36 -0
  7. package/dist/collections/audit.d.ts +2 -0
  8. package/dist/collections/audit.js +40 -0
  9. package/dist/components/EditorAssistantAction.d.ts +1 -0
  10. package/dist/components/EditorAssistantAction.js +17 -0
  11. package/dist/components/EditorAssistantAside.d.ts +1 -0
  12. package/dist/components/EditorAssistantAside.js +335 -0
  13. package/dist/components/EditorAssistantDocumentBridge.d.ts +1 -0
  14. package/dist/components/EditorAssistantDocumentBridge.js +48 -0
  15. package/dist/components/EditorAssistantProvider.d.ts +8 -0
  16. package/dist/components/EditorAssistantProvider.js +14 -0
  17. package/dist/components/assistant-api.d.ts +9 -0
  18. package/dist/components/assistant-api.js +34 -0
  19. package/dist/components/assistant-context.d.ts +66 -0
  20. package/dist/components/assistant-context.js +69 -0
  21. package/dist/config/denied-fields.d.ts +3 -0
  22. package/dist/config/denied-fields.js +34 -0
  23. package/dist/config/validate.d.ts +15 -0
  24. package/dist/config/validate.js +86 -0
  25. package/dist/domain/allowlist.d.ts +12 -0
  26. package/dist/domain/allowlist.js +14 -0
  27. package/dist/domain/audit.d.ts +17 -0
  28. package/dist/domain/audit.js +25 -0
  29. package/dist/domain/content.d.ts +30 -0
  30. package/dist/domain/content.js +117 -0
  31. package/dist/domain/decide.d.ts +30 -0
  32. package/dist/domain/decide.js +162 -0
  33. package/dist/domain/guard.d.ts +13 -0
  34. package/dist/domain/guard.js +29 -0
  35. package/dist/domain/local-api.d.ts +16 -0
  36. package/dist/domain/local-api.js +3 -0
  37. package/dist/domain/navigate.d.ts +25 -0
  38. package/dist/domain/navigate.js +85 -0
  39. package/dist/domain/propose.d.ts +26 -0
  40. package/dist/domain/propose.js +150 -0
  41. package/dist/domain/relations.d.ts +12 -0
  42. package/dist/domain/relations.js +103 -0
  43. package/dist/endpoints/chat.d.ts +3 -0
  44. package/dist/endpoints/chat.js +88 -0
  45. package/dist/endpoints/csrf.d.ts +6 -0
  46. package/dist/endpoints/csrf.js +57 -0
  47. package/dist/endpoints/decide.d.ts +3 -0
  48. package/dist/endpoints/decide.js +33 -0
  49. package/dist/endpoints/propose.d.ts +3 -0
  50. package/dist/endpoints/propose.js +32 -0
  51. package/dist/exports/client.d.ts +4 -0
  52. package/dist/exports/client.js +4 -0
  53. package/dist/form/compile.d.ts +17 -0
  54. package/dist/form/compile.js +168 -0
  55. package/dist/form/diff.d.ts +9 -0
  56. package/dist/form/diff.js +155 -0
  57. package/dist/form/empty.d.ts +2 -0
  58. package/dist/form/empty.js +79 -0
  59. package/dist/form/hash.d.ts +2 -0
  60. package/dist/form/hash.js +22 -0
  61. package/dist/form/operations.d.ts +52 -0
  62. package/dist/form/operations.js +52 -0
  63. package/dist/form/path.d.ts +5 -0
  64. package/dist/form/path.js +79 -0
  65. package/dist/form/shape.d.ts +19 -0
  66. package/dist/form/shape.js +137 -0
  67. package/dist/index.d.ts +5 -0
  68. package/dist/index.js +3 -0
  69. package/dist/package-name.d.ts +7 -0
  70. package/dist/package-name.js +7 -0
  71. package/dist/plugin.d.ts +3 -0
  72. package/dist/plugin.js +110 -0
  73. package/dist/runtime/agent.d.ts +42 -0
  74. package/dist/runtime/agent.js +262 -0
  75. package/dist/runtime/context.d.ts +37 -0
  76. package/dist/runtime/context.js +92 -0
  77. package/dist/runtime/inflight.d.ts +2 -0
  78. package/dist/runtime/inflight.js +11 -0
  79. package/dist/runtime/language.d.ts +10 -0
  80. package/dist/runtime/language.js +27 -0
  81. package/dist/runtime/propose-loop.d.ts +7 -0
  82. package/dist/runtime/propose-loop.js +11 -0
  83. package/dist/runtime/rate-limit.d.ts +1 -0
  84. package/dist/runtime/rate-limit.js +14 -0
  85. package/dist/runtime/system-prompt.d.ts +3 -0
  86. package/dist/runtime/system-prompt.js +110 -0
  87. package/dist/runtime/tools.d.ts +56 -0
  88. package/dist/runtime/tools.js +189 -0
  89. package/dist/runtime/voice.d.ts +11 -0
  90. package/dist/runtime/voice.js +55 -0
  91. package/dist/schema/discover.d.ts +35 -0
  92. package/dist/schema/discover.js +93 -0
  93. package/dist/schema/fields.d.ts +21 -0
  94. package/dist/schema/fields.js +139 -0
  95. package/dist/schema/project.d.ts +15 -0
  96. package/dist/schema/project.js +111 -0
  97. package/dist/styles/assistant.css +362 -0
  98. package/dist/types.d.ts +61 -0
  99. package/dist/types.js +3 -0
  100. package/dist/view.d.ts +22 -0
  101. package/dist/view.js +72 -0
  102. package/package.json +73 -0
@@ -0,0 +1,362 @@
1
+ .ea-root {
2
+ --ea-aside-width: 400px;
3
+ position: fixed;
4
+ inset: 0;
5
+ display: flex;
6
+ height: 100%;
7
+ max-height: 100dvh;
8
+ overflow: hidden;
9
+ }
10
+
11
+ .ea-root--collapsed {
12
+ --ea-aside-width: 48px;
13
+ }
14
+
15
+ html:has(.ea-root),
16
+ html:has(.ea-root) body {
17
+ height: 100%;
18
+ max-height: 100dvh;
19
+ overflow: hidden;
20
+ }
21
+
22
+ .ea-main {
23
+ flex: 1;
24
+ min-width: 0;
25
+ min-height: 0;
26
+ height: 100%;
27
+ overflow: auto;
28
+ }
29
+
30
+ .ea-main .template-default {
31
+ min-height: 100%;
32
+ }
33
+
34
+ .ea-aside {
35
+ box-sizing: border-box;
36
+ display: flex;
37
+ flex-direction: column;
38
+ flex: 0 0 var(--ea-aside-width);
39
+ width: var(--ea-aside-width);
40
+ height: 100%;
41
+ max-height: 100%;
42
+ overflow: hidden;
43
+ border-inline-start: 1px solid var(--theme-elevation-150);
44
+ background: var(--theme-bg, var(--theme-elevation-0));
45
+ color: var(--theme-text);
46
+ font-size: 13px;
47
+ line-height: 1.45;
48
+ }
49
+
50
+ .ea-aside__rail {
51
+ writing-mode: vertical-rl;
52
+ transform: rotate(180deg);
53
+ width: 100%;
54
+ height: 100%;
55
+ border: 0;
56
+ background: var(--theme-elevation-50);
57
+ color: var(--theme-elevation-800);
58
+ cursor: pointer;
59
+ letter-spacing: 0.14em;
60
+ text-transform: uppercase;
61
+ font: inherit;
62
+ font-size: 12px;
63
+ }
64
+
65
+ .ea-aside__rail:hover {
66
+ color: var(--theme-text);
67
+ background: var(--theme-elevation-100);
68
+ }
69
+
70
+ .ea-btn {
71
+ appearance: none;
72
+ display: inline-flex;
73
+ align-items: center;
74
+ justify-content: center;
75
+ margin: 0;
76
+ border: 1px solid var(--theme-elevation-150);
77
+ background: var(--theme-elevation-50);
78
+ color: var(--theme-text);
79
+ border-radius: var(--style-radius-s, 3px);
80
+ padding: 5px 10px;
81
+ font: inherit;
82
+ font-size: 12px;
83
+ font-weight: 500;
84
+ line-height: 1.2;
85
+ cursor: pointer;
86
+ }
87
+
88
+ .ea-btn:hover {
89
+ background: var(--theme-elevation-100);
90
+ }
91
+
92
+ .ea-btn:disabled {
93
+ opacity: 0.45;
94
+ cursor: not-allowed;
95
+ }
96
+
97
+ .ea-btn--ghost {
98
+ border-color: transparent;
99
+ background: transparent;
100
+ color: var(--theme-elevation-800);
101
+ }
102
+
103
+ .ea-btn--ghost:hover {
104
+ background: var(--theme-elevation-100);
105
+ color: var(--theme-text);
106
+ }
107
+
108
+ .ea-btn--primary {
109
+ border-color: var(--theme-success-500);
110
+ background: var(--theme-success-500);
111
+ color: var(--theme-success-50, #fff);
112
+ }
113
+
114
+ .ea-btn--primary:hover {
115
+ background: var(--theme-success-600, var(--theme-success-500));
116
+ }
117
+
118
+ .ea-btn--danger {
119
+ border-color: var(--theme-error-500);
120
+ background: var(--theme-error-500);
121
+ color: #fff;
122
+ }
123
+
124
+ .ea-btn--danger:hover {
125
+ background: var(--theme-error-600, var(--theme-error-500));
126
+ }
127
+
128
+ .ea-btn--stop {
129
+ border-color: var(--theme-elevation-150);
130
+ background: transparent;
131
+ color: var(--theme-error-500);
132
+ }
133
+
134
+ .ea-btn--stop:hover {
135
+ background: var(--theme-error-50, var(--theme-elevation-100));
136
+ }
137
+
138
+ .ea-btn--chip {
139
+ border-radius: 999px;
140
+ background: transparent;
141
+ color: var(--theme-elevation-800);
142
+ padding: 3px 9px;
143
+ }
144
+
145
+ .ea-btn--chip:hover {
146
+ color: var(--theme-text);
147
+ border-color: var(--theme-elevation-400, var(--theme-elevation-150));
148
+ }
149
+
150
+ .ea-aside__head {
151
+ display: flex;
152
+ align-items: center;
153
+ gap: 4px;
154
+ flex-shrink: 0;
155
+ padding: 8px 10px 8px 14px;
156
+ border-bottom: 1px solid var(--theme-elevation-150);
157
+ }
158
+
159
+ .ea-aside__head h2 {
160
+ flex: 1;
161
+ margin: 0;
162
+ font-size: 11px;
163
+ font-weight: 600;
164
+ letter-spacing: 0.08em;
165
+ text-transform: uppercase;
166
+ color: var(--theme-elevation-800);
167
+ }
168
+
169
+ .ea-aside__body {
170
+ display: flex;
171
+ flex-direction: column;
172
+ flex: 1;
173
+ min-height: 0;
174
+ overflow: hidden;
175
+ }
176
+
177
+ .ea-context {
178
+ display: flex;
179
+ flex-wrap: wrap;
180
+ align-items: center;
181
+ flex-shrink: 0;
182
+ padding: 8px 14px;
183
+ border-bottom: 1px solid var(--theme-elevation-150);
184
+ color: var(--theme-elevation-800);
185
+ font-size: 11px;
186
+ }
187
+
188
+ .ea-context span + span::before {
189
+ content: "·";
190
+ margin: 0 6px;
191
+ color: var(--theme-elevation-400, var(--theme-elevation-150));
192
+ }
193
+
194
+ .ea-context__warn {
195
+ color: var(--theme-warning-600, var(--theme-warning-500));
196
+ }
197
+
198
+ .ea-context__ok {
199
+ color: var(--theme-success-600, var(--theme-success-500));
200
+ }
201
+
202
+ .ea-messages {
203
+ flex: 1;
204
+ min-height: 0;
205
+ overflow: auto;
206
+ overscroll-behavior: contain;
207
+ padding: 14px;
208
+ display: flex;
209
+ flex-direction: column;
210
+ gap: 10px;
211
+ }
212
+
213
+ .ea-msg {
214
+ max-width: 92%;
215
+ padding: 9px 11px;
216
+ border-radius: 8px;
217
+ border: 1px solid var(--theme-elevation-150);
218
+ background: var(--theme-elevation-50);
219
+ }
220
+
221
+ .ea-msg--user {
222
+ align-self: flex-end;
223
+ background: var(--theme-elevation-100);
224
+ }
225
+
226
+ .ea-msg--assistant {
227
+ align-self: flex-start;
228
+ }
229
+
230
+ .ea-msg--system {
231
+ align-self: stretch;
232
+ max-width: none;
233
+ background: transparent;
234
+ border: 0;
235
+ color: var(--theme-elevation-800);
236
+ font-size: 12px;
237
+ padding: 2px 0;
238
+ }
239
+
240
+ .ea-approval {
241
+ flex-shrink: 0;
242
+ padding: 12px 14px;
243
+ border-top: 1px solid var(--theme-warning-300, var(--theme-elevation-150));
244
+ background: var(--theme-warning-50, var(--theme-elevation-50));
245
+ }
246
+
247
+ .ea-approval h3 {
248
+ margin: 0 0 8px;
249
+ font-size: 13px;
250
+ }
251
+
252
+ .ea-msg--working {
253
+ display: flex;
254
+ align-items: center;
255
+ gap: 8px;
256
+ color: var(--theme-elevation-800);
257
+ }
258
+
259
+ .ea-approval__diff {
260
+ max-height: 40vh;
261
+ overflow-y: auto;
262
+ margin: 0 0 10px;
263
+ padding-left: 1.1em;
264
+ font-size: 13px;
265
+ }
266
+
267
+ .ea-approval__sub {
268
+ list-style: none;
269
+ margin-left: 0.4em;
270
+ padding-left: 0.6em;
271
+ border-left: 2px solid var(--theme-elevation-150);
272
+ color: var(--theme-elevation-800);
273
+ }
274
+
275
+ .ea-approval pre {
276
+ margin: 0 0 10px;
277
+ white-space: pre-wrap;
278
+ font-size: 12px;
279
+ font-family: var(--font-mono, ui-monospace, monospace);
280
+ }
281
+
282
+ .ea-actions {
283
+ display: flex;
284
+ gap: 8px;
285
+ flex-wrap: wrap;
286
+ margin-top: 8px;
287
+ }
288
+
289
+ .ea-status {
290
+ flex-shrink: 0;
291
+ padding: 8px 14px;
292
+ color: var(--theme-error-500);
293
+ font-size: 12px;
294
+ }
295
+
296
+ .ea-composer {
297
+ flex-shrink: 0;
298
+ padding: 10px 14px 12px;
299
+ border-top: 1px solid var(--theme-elevation-150);
300
+ background: var(--theme-elevation-50);
301
+ }
302
+
303
+ .ea-shortcuts {
304
+ display: flex;
305
+ flex-wrap: wrap;
306
+ gap: 6px;
307
+ margin-bottom: 8px;
308
+ }
309
+
310
+ .ea-composer__box {
311
+ display: flex;
312
+ flex-direction: column;
313
+ gap: 6px;
314
+ border: 1px solid var(--theme-elevation-150);
315
+ border-radius: var(--style-radius-m, 4px);
316
+ background: var(--theme-input-bg, var(--theme-elevation-0));
317
+ padding: 8px 10px;
318
+ }
319
+
320
+ .ea-composer__box:focus-within {
321
+ border-color: var(--theme-elevation-400, var(--theme-elevation-150));
322
+ }
323
+
324
+ .ea-composer textarea {
325
+ width: 100%;
326
+ box-sizing: border-box;
327
+ resize: none;
328
+ border: 0;
329
+ background: transparent;
330
+ color: var(--theme-text);
331
+ padding: 0;
332
+ font: inherit;
333
+ min-height: 40px;
334
+ outline: none;
335
+ }
336
+
337
+ .ea-composer textarea:focus,
338
+ .ea-composer textarea:focus-visible {
339
+ outline: none;
340
+ box-shadow: none;
341
+ }
342
+
343
+ .ea-composer textarea:disabled {
344
+ opacity: 0.7;
345
+ }
346
+
347
+ .ea-composer__bar {
348
+ display: flex;
349
+ align-items: center;
350
+ justify-content: flex-end;
351
+ gap: 8px;
352
+ }
353
+
354
+ .ea-composer__status {
355
+ margin-right: auto;
356
+ color: var(--theme-elevation-800);
357
+ font-size: 12px;
358
+ }
359
+
360
+ .ea-trigger {
361
+ margin-inline: 8px;
362
+ }
@@ -0,0 +1,61 @@
1
+ import type { EntityCapability } from "./capabilities.ts";
2
+ import type { AdminViewKind } from "./view.ts";
3
+ export type HostLanguageModel = object;
4
+ export type ModelResolver = (args: {
5
+ userId?: string | number;
6
+ }) => HostLanguageModel | Promise<HostLanguageModel>;
7
+ export type FieldAllowlist = true | {
8
+ include: string[];
9
+ } | {
10
+ exclude: string[];
11
+ };
12
+ export type EntityAllowlist = {
13
+ capabilities: EntityCapability[];
14
+ fields?: FieldAllowlist;
15
+ };
16
+ export type AssistantShortcut = {
17
+ id: string;
18
+ label: string;
19
+ prompt: string;
20
+ /** Admin views where the shortcut is shown. Omit to show it everywhere. */
21
+ when?: AdminViewKind[];
22
+ /** Collection or global slugs where the shortcut is shown. Views without an entity (dashboard) are not filtered. */
23
+ entities?: string[];
24
+ };
25
+ export type HostToolRisk = "auto" | "approval" | "forbidden";
26
+ export type HostToolDefinition = {
27
+ id: string;
28
+ capabilityId: string;
29
+ risk?: HostToolRisk;
30
+ mcp?: boolean;
31
+ };
32
+ export type ProposalValidationResult = {
33
+ ok: true;
34
+ } | {
35
+ ok: false;
36
+ errors: string[];
37
+ };
38
+ export type EditorAssistantPluginOptions = {
39
+ disabled?: boolean;
40
+ model?: HostLanguageModel | ModelResolver;
41
+ collections?: Record<string, EntityAllowlist>;
42
+ globals?: Record<string, EntityAllowlist>;
43
+ denyFields?: string[];
44
+ instructions?: string;
45
+ shortcuts?: AssistantShortcut[];
46
+ tools?: HostToolDefinition[];
47
+ validateProposal?: (input: unknown) => ProposalValidationResult | Promise<ProposalValidationResult>;
48
+ redact?: (input: {
49
+ slug: string;
50
+ data: Record<string, unknown>;
51
+ }) => Record<string, unknown>;
52
+ enabled?: (ctx: {
53
+ userId?: string | number;
54
+ }) => boolean | Promise<boolean>;
55
+ trustedOrigins?: string[];
56
+ audit?: {
57
+ collection?: string;
58
+ retentionDays?: number;
59
+ };
60
+ };
61
+ export declare function defineEditorAssistantConfig<T extends EditorAssistantPluginOptions>(options: T): T;
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ export function defineEditorAssistantConfig(options) {
2
+ return options;
3
+ }
package/dist/view.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ export type AdminView = {
2
+ kind: "dashboard";
3
+ } | {
4
+ kind: "list";
5
+ collection: string;
6
+ } | {
7
+ kind: "document";
8
+ collection: string;
9
+ documentId?: string;
10
+ } | {
11
+ kind: "global";
12
+ global: string;
13
+ } | {
14
+ kind: "other";
15
+ };
16
+ export type AdminViewKind = AdminView["kind"];
17
+ export declare function parseAdminView(pathname: string, adminRoute?: string): AdminView;
18
+ /** Keep only views that point at something the host allowlisted. */
19
+ export declare function sanitizeAdminView(value: unknown, allowed: {
20
+ collections: Record<string, unknown>;
21
+ globals: Record<string, unknown>;
22
+ }): AdminView;
package/dist/view.js ADDED
@@ -0,0 +1,72 @@
1
+ const RESERVED_DOCUMENT_SEGMENTS = new Set(["create"]);
2
+ export function parseAdminView(pathname, adminRoute = "/admin") {
3
+ const base = trimSlashes(adminRoute);
4
+ const path = trimSlashes(pathname.split(/[?#]/)[0] ?? "");
5
+ const rest = base ? stripPrefix(path, base) : path;
6
+ if (rest === undefined) {
7
+ return { kind: "other" };
8
+ }
9
+ const segments = rest.split("/").filter(Boolean).map(safeDecode);
10
+ if (segments.length === 0) {
11
+ return { kind: "dashboard" };
12
+ }
13
+ const [section, slug, id] = segments;
14
+ if (section === "collections" && slug) {
15
+ if (!id) {
16
+ return { kind: "list", collection: slug };
17
+ }
18
+ return RESERVED_DOCUMENT_SEGMENTS.has(id)
19
+ ? { kind: "document", collection: slug }
20
+ : { kind: "document", collection: slug, documentId: id };
21
+ }
22
+ if (section === "globals" && slug) {
23
+ return { kind: "global", global: slug };
24
+ }
25
+ return { kind: "other" };
26
+ }
27
+ /** Keep only views that point at something the host allowlisted. */
28
+ export function sanitizeAdminView(value, allowed) {
29
+ if (!value || typeof value !== "object") {
30
+ return { kind: "other" };
31
+ }
32
+ const view = value;
33
+ const has = (record, key) => typeof key === "string" && Object.hasOwn(record, key);
34
+ switch (view.kind) {
35
+ case "dashboard":
36
+ return { kind: "dashboard" };
37
+ case "list":
38
+ return has(allowed.collections, view.collection)
39
+ ? { kind: "list", collection: view.collection }
40
+ : { kind: "other" };
41
+ case "document":
42
+ if (!has(allowed.collections, view.collection)) {
43
+ return { kind: "other" };
44
+ }
45
+ return typeof view.documentId === "string"
46
+ ? { kind: "document", collection: view.collection, documentId: view.documentId }
47
+ : { kind: "document", collection: view.collection };
48
+ case "global":
49
+ return has(allowed.globals, view.global)
50
+ ? { kind: "global", global: view.global }
51
+ : { kind: "other" };
52
+ default:
53
+ return { kind: "other" };
54
+ }
55
+ }
56
+ function trimSlashes(value) {
57
+ return value.replace(/^\/+|\/+$/g, "");
58
+ }
59
+ function stripPrefix(path, base) {
60
+ if (path === base) {
61
+ return "";
62
+ }
63
+ return path.startsWith(`${base}/`) ? path.slice(base.length + 1) : undefined;
64
+ }
65
+ function safeDecode(segment) {
66
+ try {
67
+ return decodeURIComponent(segment);
68
+ }
69
+ catch {
70
+ return segment;
71
+ }
72
+ }
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@simmalugnt-se/payload-editor-assistant",
3
+ "version": "0.1.0",
4
+ "description": "Context-aware editor assistant plugin for Payload Admin",
5
+ "keywords": [
6
+ "payload",
7
+ "payload-plugin"
8
+ ],
9
+ "license": "MIT",
10
+ "author": "Simmalugnt AB",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/simmalugnt-se/payload-plugins.git",
14
+ "directory": "packages/payload-editor-assistant"
15
+ },
16
+ "type": "module",
17
+ "engines": {
18
+ "node": ">=22"
19
+ },
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "sideEffects": [
24
+ "*.css"
25
+ ],
26
+ "exports": {
27
+ ".": {
28
+ "import": "./dist/index.js",
29
+ "types": "./dist/index.d.ts",
30
+ "default": "./dist/index.js"
31
+ },
32
+ "./client": {
33
+ "import": "./dist/exports/client.js",
34
+ "types": "./dist/exports/client.d.ts",
35
+ "default": "./dist/exports/client.js"
36
+ }
37
+ },
38
+ "publishConfig": {
39
+ "access": "public"
40
+ },
41
+ "peerDependencies": {
42
+ "@payloadcms/ui": ">=3.87.1 <4",
43
+ "ai": "^7.0.0",
44
+ "next": ">=16.2.6 <17",
45
+ "payload": ">=3.87.1 <4",
46
+ "react": "^19.0.0",
47
+ "react-dom": "^19.0.0"
48
+ },
49
+ "peerDependenciesMeta": {
50
+ "next": {
51
+ "optional": true
52
+ }
53
+ },
54
+ "devDependencies": {
55
+ "@payloadcms/ui": "3.87.1",
56
+ "@types/node": "^22",
57
+ "@types/react": "^19.2.18",
58
+ "@types/react-dom": "^19.2.4",
59
+ "next": "16.3.0",
60
+ "payload": "3.87.1",
61
+ "react": "19.2.8",
62
+ "react-dom": "19.2.8",
63
+ "tsx": "^4.21.0",
64
+ "typescript": "5.9.3"
65
+ },
66
+ "scripts": {
67
+ "build": "rm -rf dist && tsc -p tsconfig.build.json && cp -R src/styles dist/styles",
68
+ "test": "tsx --test tests/*.test.ts",
69
+ "typecheck": "tsc --noEmit"
70
+ },
71
+ "main": "./dist/index.js",
72
+ "types": "./dist/index.d.ts"
73
+ }