@agntcms/next 0.3.2 → 0.3.4
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/{assets-Cyt9upqW.d.cts → assets-B3oNeLdj.d.cts} +1 -1
- package/dist/{assets-P8OCigDG.d.ts → assets-DHumg-X7.d.ts} +1 -1
- package/dist/client.cjs +2831 -4747
- package/dist/client.d.cts +11 -153
- package/dist/client.d.ts +11 -153
- package/dist/client.mjs +4750 -6675
- package/dist/config.cjs +2 -123
- package/dist/config.d.cts +4 -59
- package/dist/config.d.ts +4 -59
- package/dist/config.mjs +2 -116
- package/dist/{defineSection-Kr0pWqMY.d.ts → defineSection-ByG5uwiR.d.cts} +5 -24
- package/dist/{defineSection-9qQ5ulAH.d.cts → defineSection-ChkZCQyQ.d.ts} +5 -24
- package/dist/{rateLimit-CXptRM_K.d.ts → getContent-DAgAn095.d.ts} +3 -132
- package/dist/{rateLimit-CiROGTLE.d.cts → getContent-yK-sARoc.d.cts} +3 -132
- package/dist/handlers.cjs +19 -382
- package/dist/handlers.d.cts +4 -73
- package/dist/handlers.d.ts +4 -73
- package/dist/handlers.mjs +19 -377
- package/dist/index.cjs +1 -109
- package/dist/index.d.cts +3 -4
- package/dist/index.d.ts +3 -4
- package/dist/index.mjs +1 -103
- package/dist/{form-BqY0H1V5.d.cts → page-DXF0_SrY.d.cts} +3 -293
- package/dist/{form-BqY0H1V5.d.ts → page-DXF0_SrY.d.ts} +3 -293
- package/dist/server.cjs +15 -635
- package/dist/server.d.cts +8 -75
- package/dist/server.d.ts +8 -75
- package/dist/server.mjs +11 -618
- package/package.json +1 -1
- package/dist/defineForm-Bp9vzW56.d.ts +0 -71
- package/dist/defineForm-CJ8KZC93.d.cts +0 -71
- package/dist/registry-CraTTwT7.d.cts +0 -29
- package/dist/registry-DMujGqt0.d.ts +0 -29
package/dist/config.cjs
CHANGED
|
@@ -22,23 +22,16 @@ var config_exports = {};
|
|
|
22
22
|
__export(config_exports, {
|
|
23
23
|
BooleanField: () => BooleanField,
|
|
24
24
|
ButtonField: () => ButtonField,
|
|
25
|
-
DuplicateFormNameError: () => DuplicateFormNameError,
|
|
26
|
-
FormOverridesField: () => FormOverridesField,
|
|
27
|
-
HoneypotCollisionError: () => HoneypotCollisionError,
|
|
28
25
|
ImageField: () => ImageField,
|
|
29
|
-
InvalidFormFieldError: () => InvalidFormFieldError,
|
|
30
|
-
InvalidFormNameError: () => InvalidFormNameError,
|
|
31
26
|
LinkField: () => LinkField,
|
|
32
27
|
ListField: () => ListField,
|
|
33
28
|
NumberField: () => NumberField,
|
|
34
29
|
ReferenceField: () => ReferenceField,
|
|
35
30
|
RichTextField: () => RichTextField,
|
|
36
31
|
SelectField: () => SelectField,
|
|
37
|
-
SubmissionsNotReadableError: () => SubmissionsNotReadableError,
|
|
38
32
|
TextField: () => TextField,
|
|
39
33
|
VideoField: () => VideoField,
|
|
40
34
|
defineConfig: () => defineConfig,
|
|
41
|
-
defineForm: () => defineForm,
|
|
42
35
|
withagntcms: () => withagntcms
|
|
43
36
|
});
|
|
44
37
|
module.exports = __toCommonJS(config_exports);
|
|
@@ -52,7 +45,7 @@ function getDefaultAdapterFactories(requested) {
|
|
|
52
45
|
const f = holder()[SLOT];
|
|
53
46
|
if (f === void 0) {
|
|
54
47
|
throw new Error(
|
|
55
|
-
`[agntcms] defineConfig: cannot fill the default ${requested} adapter because the server-only adapter factories were never registered. Import \`@agntcms/next/server\` (or \`@agntcms/next/handlers\`) before evaluating \`agntcms/config.ts\`, or pass an explicit adapter to \`defineConfig({ contentAdapter, assetAdapter
|
|
48
|
+
`[agntcms] defineConfig: cannot fill the default ${requested} adapter because the server-only adapter factories were never registered. Import \`@agntcms/next/server\` (or \`@agntcms/next/handlers\`) before evaluating \`agntcms/config.ts\`, or pass an explicit adapter to \`defineConfig({ contentAdapter, assetAdapter })\`.`
|
|
56
49
|
);
|
|
57
50
|
}
|
|
58
51
|
return f;
|
|
@@ -67,15 +60,10 @@ function defineConfig(config) {
|
|
|
67
60
|
}
|
|
68
61
|
const contentAdapter = config.contentAdapter ?? getDefaultAdapterFactories("content").content();
|
|
69
62
|
const assetAdapter = config.assetAdapter ?? getDefaultAdapterFactories("asset").asset();
|
|
70
|
-
const submissionAdapter = config.submissionAdapter ?? getDefaultAdapterFactories("submission").submission();
|
|
71
63
|
return {
|
|
72
64
|
sections: config.sections,
|
|
73
65
|
contentAdapter,
|
|
74
|
-
assetAdapter
|
|
75
|
-
templates: config.templates ?? [],
|
|
76
|
-
forms: config.forms ?? [],
|
|
77
|
-
submissionAdapter,
|
|
78
|
-
submissionRateLimit: config.submissionRateLimit ?? { perMinute: 5 }
|
|
66
|
+
assetAdapter
|
|
79
67
|
};
|
|
80
68
|
}
|
|
81
69
|
|
|
@@ -118,101 +106,6 @@ function mergeTracingIncludes(user, framework) {
|
|
|
118
106
|
return result;
|
|
119
107
|
}
|
|
120
108
|
|
|
121
|
-
// src/domain/form.ts
|
|
122
|
-
var FORM_FORBIDDEN_KINDS = /* @__PURE__ */ new Set([
|
|
123
|
-
"image",
|
|
124
|
-
"video",
|
|
125
|
-
"reference",
|
|
126
|
-
"list",
|
|
127
|
-
// `formOverrides` is a section-only descriptor (it overrides another
|
|
128
|
-
// form schema instance). Putting it inside a form would mean a form's
|
|
129
|
-
// payload could carry overrides for itself or another form — a
|
|
130
|
-
// recursive shape with no ergonomic editor UI. Section-only by design.
|
|
131
|
-
"formOverrides",
|
|
132
|
-
// `button` is a section-only descriptor: a styled CTA with an
|
|
133
|
-
// optional link. Public-form payloads collect user input — a button
|
|
134
|
-
// value is authored content, not a submitted answer. Section-only
|
|
135
|
-
// by design (mirrors `formOverrides`).
|
|
136
|
-
"button"
|
|
137
|
-
]);
|
|
138
|
-
var SubmissionsNotReadableError = class extends Error {
|
|
139
|
-
constructor(message = "submission adapter does not support reading") {
|
|
140
|
-
super(message);
|
|
141
|
-
this.name = "SubmissionsNotReadableError";
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
// src/forms/defineForm.ts
|
|
146
|
-
var InvalidFormFieldError = class extends Error {
|
|
147
|
-
formName;
|
|
148
|
-
fieldName;
|
|
149
|
-
fieldKind;
|
|
150
|
-
constructor(formName, fieldName, fieldKind) {
|
|
151
|
-
super(
|
|
152
|
-
`Form "${formName}": field "${fieldName}" uses kind "${fieldKind}", which is not allowed in a form schema in v1. Allowed kinds: text, richText, number, boolean, select, link. Forbidden kinds: image, reference, list, formOverrides. See ARCHITECTURE.md \xA76.5.`
|
|
153
|
-
);
|
|
154
|
-
this.name = "InvalidFormFieldError";
|
|
155
|
-
this.formName = formName;
|
|
156
|
-
this.fieldName = fieldName;
|
|
157
|
-
this.fieldKind = fieldKind;
|
|
158
|
-
}
|
|
159
|
-
};
|
|
160
|
-
var HoneypotCollisionError = class extends Error {
|
|
161
|
-
formName;
|
|
162
|
-
fieldName;
|
|
163
|
-
reason;
|
|
164
|
-
constructor(formName, fieldName, reason = "collision") {
|
|
165
|
-
super(
|
|
166
|
-
reason === "empty" ? `Form "${formName}": honeypot name must be a non-empty string.` : `Form "${formName}": honeypot name "${fieldName}" collides with a real field. Choose a honeypot name that does not appear in the schema.`
|
|
167
|
-
);
|
|
168
|
-
this.name = "HoneypotCollisionError";
|
|
169
|
-
this.formName = formName;
|
|
170
|
-
this.fieldName = fieldName;
|
|
171
|
-
this.reason = reason;
|
|
172
|
-
}
|
|
173
|
-
};
|
|
174
|
-
var InvalidFormNameError = class extends Error {
|
|
175
|
-
constructor(name) {
|
|
176
|
-
super(
|
|
177
|
-
`Invalid form name ${JSON.stringify(name)}. Use letters, digits, hyphen, and underscore only (no path separators).`
|
|
178
|
-
);
|
|
179
|
-
this.name = "InvalidFormNameError";
|
|
180
|
-
}
|
|
181
|
-
};
|
|
182
|
-
var FORM_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
183
|
-
function defineForm(input) {
|
|
184
|
-
if (typeof input.name !== "string" || !FORM_NAME_PATTERN.test(input.name)) {
|
|
185
|
-
throw new InvalidFormNameError(input.name);
|
|
186
|
-
}
|
|
187
|
-
for (const [fieldName, descriptor] of Object.entries(input.schema)) {
|
|
188
|
-
const kind = descriptor.kind;
|
|
189
|
-
if (FORM_FORBIDDEN_KINDS.has(kind)) {
|
|
190
|
-
throw new InvalidFormFieldError(input.name, fieldName, kind);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
if (input.honeypot !== void 0) {
|
|
194
|
-
if (typeof input.honeypot !== "string" || input.honeypot === "") {
|
|
195
|
-
throw new HoneypotCollisionError(input.name, input.honeypot, "empty");
|
|
196
|
-
}
|
|
197
|
-
if (Object.prototype.hasOwnProperty.call(input.schema, input.honeypot)) {
|
|
198
|
-
throw new HoneypotCollisionError(input.name, input.honeypot, "collision");
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
return input.honeypot !== void 0 ? { name: input.name, schema: input.schema, honeypot: input.honeypot } : { name: input.name, schema: input.schema };
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// src/forms/registry.ts
|
|
205
|
-
var DuplicateFormNameError = class extends Error {
|
|
206
|
-
formName;
|
|
207
|
-
constructor(name) {
|
|
208
|
-
super(
|
|
209
|
-
`Form name "${name}" is registered more than once. Form names must be unique within a config.`
|
|
210
|
-
);
|
|
211
|
-
this.name = "DuplicateFormNameError";
|
|
212
|
-
this.formName = name;
|
|
213
|
-
}
|
|
214
|
-
};
|
|
215
|
-
|
|
216
109
|
// src/domain/fields.ts
|
|
217
110
|
var TextField = { kind: "text" };
|
|
218
111
|
var RichTextField = { kind: "richText" };
|
|
@@ -239,33 +132,19 @@ var ListField = (itemSchema, opts) => ({
|
|
|
239
132
|
...opts?.max !== void 0 ? { max: opts.max } : {},
|
|
240
133
|
...opts?.default !== void 0 ? { default: opts.default } : {}
|
|
241
134
|
});
|
|
242
|
-
|
|
243
|
-
// src/domain/formOverrides.ts
|
|
244
|
-
var FormOverridesField = (formName, opts) => ({
|
|
245
|
-
kind: "formOverrides",
|
|
246
|
-
formName,
|
|
247
|
-
...opts?.default !== void 0 ? { default: opts.default } : {}
|
|
248
|
-
});
|
|
249
135
|
// Annotate the CommonJS export names for ESM import in node:
|
|
250
136
|
0 && (module.exports = {
|
|
251
137
|
BooleanField,
|
|
252
138
|
ButtonField,
|
|
253
|
-
DuplicateFormNameError,
|
|
254
|
-
FormOverridesField,
|
|
255
|
-
HoneypotCollisionError,
|
|
256
139
|
ImageField,
|
|
257
|
-
InvalidFormFieldError,
|
|
258
|
-
InvalidFormNameError,
|
|
259
140
|
LinkField,
|
|
260
141
|
ListField,
|
|
261
142
|
NumberField,
|
|
262
143
|
ReferenceField,
|
|
263
144
|
RichTextField,
|
|
264
145
|
SelectField,
|
|
265
|
-
SubmissionsNotReadableError,
|
|
266
146
|
TextField,
|
|
267
147
|
VideoField,
|
|
268
148
|
defineConfig,
|
|
269
|
-
defineForm,
|
|
270
149
|
withagntcms
|
|
271
150
|
});
|
package/dist/config.d.cts
CHANGED
|
@@ -1,36 +1,8 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import { C as ContentStorageAdapter, A as AssetStorageAdapter } from './assets-Cyt9upqW.cjs';
|
|
5
|
-
export { D as DefineFormInput, H as HoneypotCollisionError, I as InvalidFormFieldError, a as InvalidFormNameError, d as defineForm } from './defineForm-CJ8KZC93.cjs';
|
|
6
|
-
export { D as DuplicateFormNameError } from './registry-CraTTwT7.cjs';
|
|
1
|
+
import { A as AnySectionDefinition } from './defineSection-ByG5uwiR.cjs';
|
|
2
|
+
import { C as ContentStorageAdapter, A as AssetStorageAdapter } from './assets-B3oNeLdj.cjs';
|
|
3
|
+
export { g as BooleanField, B as ButtonField, I as ImageField, L as LinkField, i as ListField, N as NumberField, c as ReferenceField, R as RichTextField, h as SelectField, T as TextField, V as VideoField } from './page-DXF0_SrY.cjs';
|
|
7
4
|
import './global-CV23g5Bn.cjs';
|
|
8
5
|
|
|
9
|
-
/**
|
|
10
|
-
* A named preset that pre-fills sections when creating a new page.
|
|
11
|
-
*
|
|
12
|
-
* Templates are a config-level concept only — after creation, the page is a
|
|
13
|
-
* normal page with no template constraints. The `sectionTypes` array
|
|
14
|
-
* references section names from the registered `sections` list; unknown
|
|
15
|
-
* names are silently skipped at list time.
|
|
16
|
-
*/
|
|
17
|
-
interface PageTemplate {
|
|
18
|
-
readonly name: string;
|
|
19
|
-
readonly description?: string;
|
|
20
|
-
/** Ordered list of section type names to pre-fill. */
|
|
21
|
-
readonly sectionTypes: readonly string[];
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Submission rate-limit configuration knob (ARCHITECTURE.md §6.5).
|
|
25
|
-
*
|
|
26
|
-
* Single field on purpose — multiplexing perWindow/windowMs/strategy into
|
|
27
|
-
* a struct here would invite YAGNI bikeshedding. The window is fixed at
|
|
28
|
-
* 60 seconds in v1; only the per-window count is user-tunable.
|
|
29
|
-
*/
|
|
30
|
-
interface SubmissionRateLimit {
|
|
31
|
-
/** Max submissions per minute per (IP, form) pair. Default: 5. */
|
|
32
|
-
readonly perMinute: number;
|
|
33
|
-
}
|
|
34
6
|
/**
|
|
35
7
|
* User-facing configuration shape passed to `defineConfig`.
|
|
36
8
|
*
|
|
@@ -45,25 +17,6 @@ interface AgentCmsConfig {
|
|
|
45
17
|
readonly contentAdapter?: ContentStorageAdapter;
|
|
46
18
|
/** Asset storage adapter. Defaults to FS adapter with standard paths. */
|
|
47
19
|
readonly assetAdapter?: AssetStorageAdapter;
|
|
48
|
-
/** Page creation templates. Optional — defaults to [] (blank pages only). */
|
|
49
|
-
readonly templates?: readonly PageTemplate[];
|
|
50
|
-
/**
|
|
51
|
-
* Registered form definitions (ARCHITECTURE.md §6.5). Optional — when
|
|
52
|
-
* omitted, no forms are registered and the submit handler returns 404
|
|
53
|
-
* for every form name.
|
|
54
|
-
*/
|
|
55
|
-
readonly forms?: readonly AnyFormDefinition[];
|
|
56
|
-
/**
|
|
57
|
-
* Submission storage adapter. Defaults to the FS adapter rooted at
|
|
58
|
-
* `<projectRoot>/content/submissions`. Use `createWebhookSubmissionAdapter`
|
|
59
|
-
* (or a custom implementation) to send submissions to an external service.
|
|
60
|
-
*/
|
|
61
|
-
readonly submissionAdapter?: SubmissionStorageAdapter;
|
|
62
|
-
/**
|
|
63
|
-
* Rate-limit knob for the submit endpoint. Defaults to `{ perMinute: 5 }`.
|
|
64
|
-
* The window is always 60 seconds in v1 — only the count is user-tunable.
|
|
65
|
-
*/
|
|
66
|
-
readonly submissionRateLimit?: SubmissionRateLimit;
|
|
67
20
|
}
|
|
68
21
|
/**
|
|
69
22
|
* Fully-resolved configuration with all defaults filled in.
|
|
@@ -74,14 +27,6 @@ interface ResolvedConfig {
|
|
|
74
27
|
readonly sections: readonly AnySectionDefinition[];
|
|
75
28
|
readonly contentAdapter: ContentStorageAdapter;
|
|
76
29
|
readonly assetAdapter: AssetStorageAdapter;
|
|
77
|
-
/** Page creation templates. Always present (defaults to []). */
|
|
78
|
-
readonly templates: readonly PageTemplate[];
|
|
79
|
-
/** Registered forms. Always present (defaults to []). */
|
|
80
|
-
readonly forms: readonly AnyFormDefinition[];
|
|
81
|
-
/** Submission storage adapter. Always present. */
|
|
82
|
-
readonly submissionAdapter: SubmissionStorageAdapter;
|
|
83
|
-
/** Resolved rate-limit knob. Always present. */
|
|
84
|
-
readonly submissionRateLimit: SubmissionRateLimit;
|
|
85
30
|
}
|
|
86
31
|
/**
|
|
87
32
|
* Resolve a user config into a fully-populated config with defaults.
|
|
@@ -115,4 +60,4 @@ declare function withagntcms<T extends Record<string, unknown>>(nextConfig: T):
|
|
|
115
60
|
outputFileTracingIncludes: TracingIncludes;
|
|
116
61
|
};
|
|
117
62
|
|
|
118
|
-
export { type AgentCmsConfig,
|
|
63
|
+
export { type AgentCmsConfig, type ResolvedConfig, defineConfig, withagntcms };
|
package/dist/config.d.ts
CHANGED
|
@@ -1,36 +1,8 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import { C as ContentStorageAdapter, A as AssetStorageAdapter } from './assets-P8OCigDG.js';
|
|
5
|
-
export { D as DefineFormInput, H as HoneypotCollisionError, I as InvalidFormFieldError, a as InvalidFormNameError, d as defineForm } from './defineForm-Bp9vzW56.js';
|
|
6
|
-
export { D as DuplicateFormNameError } from './registry-DMujGqt0.js';
|
|
1
|
+
import { A as AnySectionDefinition } from './defineSection-ChkZCQyQ.js';
|
|
2
|
+
import { C as ContentStorageAdapter, A as AssetStorageAdapter } from './assets-DHumg-X7.js';
|
|
3
|
+
export { g as BooleanField, B as ButtonField, I as ImageField, L as LinkField, i as ListField, N as NumberField, c as ReferenceField, R as RichTextField, h as SelectField, T as TextField, V as VideoField } from './page-DXF0_SrY.js';
|
|
7
4
|
import './global-CV23g5Bn.js';
|
|
8
5
|
|
|
9
|
-
/**
|
|
10
|
-
* A named preset that pre-fills sections when creating a new page.
|
|
11
|
-
*
|
|
12
|
-
* Templates are a config-level concept only — after creation, the page is a
|
|
13
|
-
* normal page with no template constraints. The `sectionTypes` array
|
|
14
|
-
* references section names from the registered `sections` list; unknown
|
|
15
|
-
* names are silently skipped at list time.
|
|
16
|
-
*/
|
|
17
|
-
interface PageTemplate {
|
|
18
|
-
readonly name: string;
|
|
19
|
-
readonly description?: string;
|
|
20
|
-
/** Ordered list of section type names to pre-fill. */
|
|
21
|
-
readonly sectionTypes: readonly string[];
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Submission rate-limit configuration knob (ARCHITECTURE.md §6.5).
|
|
25
|
-
*
|
|
26
|
-
* Single field on purpose — multiplexing perWindow/windowMs/strategy into
|
|
27
|
-
* a struct here would invite YAGNI bikeshedding. The window is fixed at
|
|
28
|
-
* 60 seconds in v1; only the per-window count is user-tunable.
|
|
29
|
-
*/
|
|
30
|
-
interface SubmissionRateLimit {
|
|
31
|
-
/** Max submissions per minute per (IP, form) pair. Default: 5. */
|
|
32
|
-
readonly perMinute: number;
|
|
33
|
-
}
|
|
34
6
|
/**
|
|
35
7
|
* User-facing configuration shape passed to `defineConfig`.
|
|
36
8
|
*
|
|
@@ -45,25 +17,6 @@ interface AgentCmsConfig {
|
|
|
45
17
|
readonly contentAdapter?: ContentStorageAdapter;
|
|
46
18
|
/** Asset storage adapter. Defaults to FS adapter with standard paths. */
|
|
47
19
|
readonly assetAdapter?: AssetStorageAdapter;
|
|
48
|
-
/** Page creation templates. Optional — defaults to [] (blank pages only). */
|
|
49
|
-
readonly templates?: readonly PageTemplate[];
|
|
50
|
-
/**
|
|
51
|
-
* Registered form definitions (ARCHITECTURE.md §6.5). Optional — when
|
|
52
|
-
* omitted, no forms are registered and the submit handler returns 404
|
|
53
|
-
* for every form name.
|
|
54
|
-
*/
|
|
55
|
-
readonly forms?: readonly AnyFormDefinition[];
|
|
56
|
-
/**
|
|
57
|
-
* Submission storage adapter. Defaults to the FS adapter rooted at
|
|
58
|
-
* `<projectRoot>/content/submissions`. Use `createWebhookSubmissionAdapter`
|
|
59
|
-
* (or a custom implementation) to send submissions to an external service.
|
|
60
|
-
*/
|
|
61
|
-
readonly submissionAdapter?: SubmissionStorageAdapter;
|
|
62
|
-
/**
|
|
63
|
-
* Rate-limit knob for the submit endpoint. Defaults to `{ perMinute: 5 }`.
|
|
64
|
-
* The window is always 60 seconds in v1 — only the count is user-tunable.
|
|
65
|
-
*/
|
|
66
|
-
readonly submissionRateLimit?: SubmissionRateLimit;
|
|
67
20
|
}
|
|
68
21
|
/**
|
|
69
22
|
* Fully-resolved configuration with all defaults filled in.
|
|
@@ -74,14 +27,6 @@ interface ResolvedConfig {
|
|
|
74
27
|
readonly sections: readonly AnySectionDefinition[];
|
|
75
28
|
readonly contentAdapter: ContentStorageAdapter;
|
|
76
29
|
readonly assetAdapter: AssetStorageAdapter;
|
|
77
|
-
/** Page creation templates. Always present (defaults to []). */
|
|
78
|
-
readonly templates: readonly PageTemplate[];
|
|
79
|
-
/** Registered forms. Always present (defaults to []). */
|
|
80
|
-
readonly forms: readonly AnyFormDefinition[];
|
|
81
|
-
/** Submission storage adapter. Always present. */
|
|
82
|
-
readonly submissionAdapter: SubmissionStorageAdapter;
|
|
83
|
-
/** Resolved rate-limit knob. Always present. */
|
|
84
|
-
readonly submissionRateLimit: SubmissionRateLimit;
|
|
85
30
|
}
|
|
86
31
|
/**
|
|
87
32
|
* Resolve a user config into a fully-populated config with defaults.
|
|
@@ -115,4 +60,4 @@ declare function withagntcms<T extends Record<string, unknown>>(nextConfig: T):
|
|
|
115
60
|
outputFileTracingIncludes: TracingIncludes;
|
|
116
61
|
};
|
|
117
62
|
|
|
118
|
-
export { type AgentCmsConfig,
|
|
63
|
+
export { type AgentCmsConfig, type ResolvedConfig, defineConfig, withagntcms };
|
package/dist/config.mjs
CHANGED
|
@@ -7,7 +7,7 @@ function getDefaultAdapterFactories(requested) {
|
|
|
7
7
|
const f = holder()[SLOT];
|
|
8
8
|
if (f === void 0) {
|
|
9
9
|
throw new Error(
|
|
10
|
-
`[agntcms] defineConfig: cannot fill the default ${requested} adapter because the server-only adapter factories were never registered. Import \`@agntcms/next/server\` (or \`@agntcms/next/handlers\`) before evaluating \`agntcms/config.ts\`, or pass an explicit adapter to \`defineConfig({ contentAdapter, assetAdapter
|
|
10
|
+
`[agntcms] defineConfig: cannot fill the default ${requested} adapter because the server-only adapter factories were never registered. Import \`@agntcms/next/server\` (or \`@agntcms/next/handlers\`) before evaluating \`agntcms/config.ts\`, or pass an explicit adapter to \`defineConfig({ contentAdapter, assetAdapter })\`.`
|
|
11
11
|
);
|
|
12
12
|
}
|
|
13
13
|
return f;
|
|
@@ -22,15 +22,10 @@ function defineConfig(config) {
|
|
|
22
22
|
}
|
|
23
23
|
const contentAdapter = config.contentAdapter ?? getDefaultAdapterFactories("content").content();
|
|
24
24
|
const assetAdapter = config.assetAdapter ?? getDefaultAdapterFactories("asset").asset();
|
|
25
|
-
const submissionAdapter = config.submissionAdapter ?? getDefaultAdapterFactories("submission").submission();
|
|
26
25
|
return {
|
|
27
26
|
sections: config.sections,
|
|
28
27
|
contentAdapter,
|
|
29
|
-
assetAdapter
|
|
30
|
-
templates: config.templates ?? [],
|
|
31
|
-
forms: config.forms ?? [],
|
|
32
|
-
submissionAdapter,
|
|
33
|
-
submissionRateLimit: config.submissionRateLimit ?? { perMinute: 5 }
|
|
28
|
+
assetAdapter
|
|
34
29
|
};
|
|
35
30
|
}
|
|
36
31
|
|
|
@@ -73,101 +68,6 @@ function mergeTracingIncludes(user, framework) {
|
|
|
73
68
|
return result;
|
|
74
69
|
}
|
|
75
70
|
|
|
76
|
-
// src/domain/form.ts
|
|
77
|
-
var FORM_FORBIDDEN_KINDS = /* @__PURE__ */ new Set([
|
|
78
|
-
"image",
|
|
79
|
-
"video",
|
|
80
|
-
"reference",
|
|
81
|
-
"list",
|
|
82
|
-
// `formOverrides` is a section-only descriptor (it overrides another
|
|
83
|
-
// form schema instance). Putting it inside a form would mean a form's
|
|
84
|
-
// payload could carry overrides for itself or another form — a
|
|
85
|
-
// recursive shape with no ergonomic editor UI. Section-only by design.
|
|
86
|
-
"formOverrides",
|
|
87
|
-
// `button` is a section-only descriptor: a styled CTA with an
|
|
88
|
-
// optional link. Public-form payloads collect user input — a button
|
|
89
|
-
// value is authored content, not a submitted answer. Section-only
|
|
90
|
-
// by design (mirrors `formOverrides`).
|
|
91
|
-
"button"
|
|
92
|
-
]);
|
|
93
|
-
var SubmissionsNotReadableError = class extends Error {
|
|
94
|
-
constructor(message = "submission adapter does not support reading") {
|
|
95
|
-
super(message);
|
|
96
|
-
this.name = "SubmissionsNotReadableError";
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
// src/forms/defineForm.ts
|
|
101
|
-
var InvalidFormFieldError = class extends Error {
|
|
102
|
-
formName;
|
|
103
|
-
fieldName;
|
|
104
|
-
fieldKind;
|
|
105
|
-
constructor(formName, fieldName, fieldKind) {
|
|
106
|
-
super(
|
|
107
|
-
`Form "${formName}": field "${fieldName}" uses kind "${fieldKind}", which is not allowed in a form schema in v1. Allowed kinds: text, richText, number, boolean, select, link. Forbidden kinds: image, reference, list, formOverrides. See ARCHITECTURE.md \xA76.5.`
|
|
108
|
-
);
|
|
109
|
-
this.name = "InvalidFormFieldError";
|
|
110
|
-
this.formName = formName;
|
|
111
|
-
this.fieldName = fieldName;
|
|
112
|
-
this.fieldKind = fieldKind;
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
var HoneypotCollisionError = class extends Error {
|
|
116
|
-
formName;
|
|
117
|
-
fieldName;
|
|
118
|
-
reason;
|
|
119
|
-
constructor(formName, fieldName, reason = "collision") {
|
|
120
|
-
super(
|
|
121
|
-
reason === "empty" ? `Form "${formName}": honeypot name must be a non-empty string.` : `Form "${formName}": honeypot name "${fieldName}" collides with a real field. Choose a honeypot name that does not appear in the schema.`
|
|
122
|
-
);
|
|
123
|
-
this.name = "HoneypotCollisionError";
|
|
124
|
-
this.formName = formName;
|
|
125
|
-
this.fieldName = fieldName;
|
|
126
|
-
this.reason = reason;
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
var InvalidFormNameError = class extends Error {
|
|
130
|
-
constructor(name) {
|
|
131
|
-
super(
|
|
132
|
-
`Invalid form name ${JSON.stringify(name)}. Use letters, digits, hyphen, and underscore only (no path separators).`
|
|
133
|
-
);
|
|
134
|
-
this.name = "InvalidFormNameError";
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
var FORM_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
138
|
-
function defineForm(input) {
|
|
139
|
-
if (typeof input.name !== "string" || !FORM_NAME_PATTERN.test(input.name)) {
|
|
140
|
-
throw new InvalidFormNameError(input.name);
|
|
141
|
-
}
|
|
142
|
-
for (const [fieldName, descriptor] of Object.entries(input.schema)) {
|
|
143
|
-
const kind = descriptor.kind;
|
|
144
|
-
if (FORM_FORBIDDEN_KINDS.has(kind)) {
|
|
145
|
-
throw new InvalidFormFieldError(input.name, fieldName, kind);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
if (input.honeypot !== void 0) {
|
|
149
|
-
if (typeof input.honeypot !== "string" || input.honeypot === "") {
|
|
150
|
-
throw new HoneypotCollisionError(input.name, input.honeypot, "empty");
|
|
151
|
-
}
|
|
152
|
-
if (Object.prototype.hasOwnProperty.call(input.schema, input.honeypot)) {
|
|
153
|
-
throw new HoneypotCollisionError(input.name, input.honeypot, "collision");
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
return input.honeypot !== void 0 ? { name: input.name, schema: input.schema, honeypot: input.honeypot } : { name: input.name, schema: input.schema };
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// src/forms/registry.ts
|
|
160
|
-
var DuplicateFormNameError = class extends Error {
|
|
161
|
-
formName;
|
|
162
|
-
constructor(name) {
|
|
163
|
-
super(
|
|
164
|
-
`Form name "${name}" is registered more than once. Form names must be unique within a config.`
|
|
165
|
-
);
|
|
166
|
-
this.name = "DuplicateFormNameError";
|
|
167
|
-
this.formName = name;
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
|
-
|
|
171
71
|
// src/domain/fields.ts
|
|
172
72
|
var TextField = { kind: "text" };
|
|
173
73
|
var RichTextField = { kind: "richText" };
|
|
@@ -194,32 +94,18 @@ var ListField = (itemSchema, opts) => ({
|
|
|
194
94
|
...opts?.max !== void 0 ? { max: opts.max } : {},
|
|
195
95
|
...opts?.default !== void 0 ? { default: opts.default } : {}
|
|
196
96
|
});
|
|
197
|
-
|
|
198
|
-
// src/domain/formOverrides.ts
|
|
199
|
-
var FormOverridesField = (formName, opts) => ({
|
|
200
|
-
kind: "formOverrides",
|
|
201
|
-
formName,
|
|
202
|
-
...opts?.default !== void 0 ? { default: opts.default } : {}
|
|
203
|
-
});
|
|
204
97
|
export {
|
|
205
98
|
BooleanField,
|
|
206
99
|
ButtonField,
|
|
207
|
-
DuplicateFormNameError,
|
|
208
|
-
FormOverridesField,
|
|
209
|
-
HoneypotCollisionError,
|
|
210
100
|
ImageField,
|
|
211
|
-
InvalidFormFieldError,
|
|
212
|
-
InvalidFormNameError,
|
|
213
101
|
LinkField,
|
|
214
102
|
ListField,
|
|
215
103
|
NumberField,
|
|
216
104
|
ReferenceField,
|
|
217
105
|
RichTextField,
|
|
218
106
|
SelectField,
|
|
219
|
-
SubmissionsNotReadableError,
|
|
220
107
|
TextField,
|
|
221
108
|
VideoField,
|
|
222
109
|
defineConfig,
|
|
223
|
-
defineForm,
|
|
224
110
|
withagntcms
|
|
225
111
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { S as SectionSchema,
|
|
1
|
+
import { S as SectionSchema, F as FieldDescriptor, T as TextField, R as RichTextField, I as ImageField, a as ImageValue, V as VideoField, b as VideoValue, c as ReferenceField, d as ReferenceValue, L as LinkField, e as LinkValue, B as ButtonField, f as ButtonValue, N as NumberField, g as BooleanField, h as SelectField, i as ListField } from './page-DXF0_SrY.cjs';
|
|
2
2
|
|
|
3
3
|
declare const __slot: unique symbol;
|
|
4
4
|
/**
|
|
@@ -70,7 +70,6 @@ type SlotItem<S extends SectionSchema> = {
|
|
|
70
70
|
* select → EditableSlot<'select', string>
|
|
71
71
|
* list → EditableSlot<'list', ReadonlyArray<SlotItem<S>>>
|
|
72
72
|
* reference → ReferenceValue (raw — see decision #3)
|
|
73
|
-
* formOverrides → FormFieldOverrides (raw — see decision #4)
|
|
74
73
|
*
|
|
75
74
|
* EDITABILITY_DESIGN.md gates this design. The slot wrapping is the
|
|
76
75
|
* load-bearing change: a slot is not assignable to `React.ReactNode`, so
|
|
@@ -80,11 +79,7 @@ type SlotItem<S extends SectionSchema> = {
|
|
|
80
79
|
*
|
|
81
80
|
* `ReferenceField` stays raw because references are not inline-editable
|
|
82
81
|
* in v1 (decision #3): a slot would force a no-op `<EditableReference>`
|
|
83
|
-
* wrapper without UX value.
|
|
84
|
-
* forms render via a built-in `<Form>` component that reads the schema
|
|
85
|
-
* itself; there is no author-defined component receiving raw form-field
|
|
86
|
-
* values, and therefore no JSX surface where a raw render could leak
|
|
87
|
-
* (decision #4).
|
|
82
|
+
* wrapper without UX value.
|
|
88
83
|
*
|
|
89
84
|
* `FieldDataType` and `FieldValueFor` (`domain/schema.ts`) NO LONGER
|
|
90
85
|
* agree element-by-element: `FieldValueFor` is the bare runtime payload
|
|
@@ -100,13 +95,13 @@ type SlotItem<S extends SectionSchema> = {
|
|
|
100
95
|
* "user-extensible field types" — invariant 5 (CLAUDE.md) forbids a
|
|
101
96
|
* plugin system; this is just the internal seam.
|
|
102
97
|
*/
|
|
103
|
-
type FieldDataType<F extends FieldDescriptor> = F extends TextField ? EditableSlot<'text', string> : F extends RichTextField ? EditableSlot<'richText', string> : F extends ImageField ? EditableSlot<'image', ImageValue> : F extends VideoField ? EditableSlot<'video', VideoValue> : F extends ReferenceField ? ReferenceValue : F extends LinkField ? EditableSlot<'link', LinkValue> : F extends ButtonField ? EditableSlot<'button', ButtonValue> : F extends NumberField ? EditableSlot<'number', number> : F extends BooleanField ? EditableSlot<'boolean', boolean> : F extends SelectField ? EditableSlot<'select', string> : F extends ListField<infer S> ? EditableSlot<'list', ReadonlyArray<SlotItem<S>>> :
|
|
98
|
+
type FieldDataType<F extends FieldDescriptor> = F extends TextField ? EditableSlot<'text', string> : F extends RichTextField ? EditableSlot<'richText', string> : F extends ImageField ? EditableSlot<'image', ImageValue> : F extends VideoField ? EditableSlot<'video', VideoValue> : F extends ReferenceField ? ReferenceValue : F extends LinkField ? EditableSlot<'link', LinkValue> : F extends ButtonField ? EditableSlot<'button', ButtonValue> : F extends NumberField ? EditableSlot<'number', number> : F extends BooleanField ? EditableSlot<'boolean', boolean> : F extends SelectField ? EditableSlot<'select', string> : F extends ListField<infer S> ? EditableSlot<'list', ReadonlyArray<SlotItem<S>>> : never;
|
|
104
99
|
/**
|
|
105
100
|
* Derives the SECTION-COMPONENT prop shape from its schema.
|
|
106
101
|
*
|
|
107
102
|
* Per `FieldDataType`, every editable field becomes an `EditableSlot<K,V>`
|
|
108
|
-
* (so `<h1>{title}</h1>` is a TS error); `ReferenceValue`
|
|
109
|
-
*
|
|
103
|
+
* (so `<h1>{title}</h1>` is a TS error); `ReferenceValue` stays raw.
|
|
104
|
+
* Example:
|
|
110
105
|
*
|
|
111
106
|
* type HeroSchema = { title: TextField; image: ImageField; ref: ReferenceField }
|
|
112
107
|
* DataOf<HeroSchema> ≡ {
|
|
@@ -172,16 +167,6 @@ interface SectionDefinition<S extends SectionSchema, C extends SectionComponent<
|
|
|
172
167
|
* never interprets these — consumers that read a specific field narrow
|
|
173
168
|
* at the call site. */
|
|
174
169
|
readonly defaults: Record<string, unknown>;
|
|
175
|
-
/** Optional list of layout names supported by this section. When present
|
|
176
|
-
* with length >= 2, the preview-mode section picker renders a "Layout"
|
|
177
|
-
* tab so authors can switch the layout without editing JSON. The section
|
|
178
|
-
* component reads the active layout from its `layout` prop; the picker
|
|
179
|
-
* writes that value via the existing per-field save round-trip.
|
|
180
|
-
*
|
|
181
|
-
* Layouts are a SECTION-level concern, not a field descriptor, because
|
|
182
|
-
* they gate structure inside a single component rather than introducing
|
|
183
|
-
* a new field type. See ARCHITECTURE.md §4. */
|
|
184
|
-
readonly layouts?: readonly string[];
|
|
185
170
|
}
|
|
186
171
|
/**
|
|
187
172
|
* The erased/heterogeneous form used by the registry and by
|
|
@@ -208,8 +193,6 @@ interface AnySectionDefinition {
|
|
|
208
193
|
readonly component: (props: never) => unknown;
|
|
209
194
|
/** Pre-computed placeholder values — see `SectionDefinition.defaults`. */
|
|
210
195
|
readonly defaults: Record<string, unknown>;
|
|
211
|
-
/** Optional layout names — see `SectionDefinition.layouts`. */
|
|
212
|
-
readonly layouts?: readonly string[];
|
|
213
196
|
}
|
|
214
197
|
/**
|
|
215
198
|
* Input shape for `defineSection`. Split out so the factory can use a single
|
|
@@ -221,8 +204,6 @@ interface DefineSectionInput<S extends SectionSchema, C extends SectionComponent
|
|
|
221
204
|
readonly category?: string;
|
|
222
205
|
readonly schema: S;
|
|
223
206
|
readonly component: C;
|
|
224
|
-
/** Optional layout names — see `SectionDefinition.layouts`. */
|
|
225
|
-
readonly layouts?: readonly string[];
|
|
226
207
|
}
|
|
227
208
|
/**
|
|
228
209
|
* Type-safe factory for a `SectionDefinition`.
|