@agntcms/next 0.2.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.
- package/dist/assets-Cyt9upqW.d.cts +290 -0
- package/dist/assets-P8OCigDG.d.ts +290 -0
- package/dist/client.cjs +13244 -0
- package/dist/client.d.cts +806 -0
- package/dist/client.d.ts +806 -0
- package/dist/client.mjs +13234 -0
- package/dist/config.cjs +240 -0
- package/dist/config.d.cts +112 -0
- package/dist/config.d.ts +112 -0
- package/dist/config.mjs +194 -0
- package/dist/defineForm-Bp9vzW56.d.ts +71 -0
- package/dist/defineForm-CJ8KZC93.d.cts +71 -0
- package/dist/defineSection-9qQ5ulAH.d.cts +243 -0
- package/dist/defineSection-Kr0pWqMY.d.ts +243 -0
- package/dist/form-BqY0H1V5.d.cts +753 -0
- package/dist/form-BqY0H1V5.d.ts +753 -0
- package/dist/global-CV23g5Bn.d.cts +15 -0
- package/dist/global-CV23g5Bn.d.ts +15 -0
- package/dist/handlers.cjs +2525 -0
- package/dist/handlers.d.cts +330 -0
- package/dist/handlers.d.ts +330 -0
- package/dist/handlers.mjs +2473 -0
- package/dist/index.cjs +372 -0
- package/dist/index.d.cts +133 -0
- package/dist/index.d.ts +133 -0
- package/dist/index.mjs +319 -0
- package/dist/rateLimit-CXptRM_K.d.ts +391 -0
- package/dist/rateLimit-CiROGTLE.d.cts +391 -0
- package/dist/registry-CraTTwT7.d.cts +29 -0
- package/dist/registry-DMujGqt0.d.ts +29 -0
- package/dist/server.cjs +1970 -0
- package/dist/server.d.cts +153 -0
- package/dist/server.d.ts +153 -0
- package/dist/server.mjs +1889 -0
- package/package.json +62 -0
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
import { S as SectionSchema, x as FieldValueFor, w as PageSummary, F as FormLookup, o as SubmissionStorageAdapter, P as Page } from './form-BqY0H1V5.cjs';
|
|
2
|
+
import { C as ContentStorageAdapter } from './assets-Cyt9upqW.cjs';
|
|
3
|
+
import { G as Global } from './global-CV23g5Bn.cjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Mode discriminator for `getContent`. `'published'` is the prod hot
|
|
7
|
+
* path (bare data). `'preview'` is the editor path (data wrapped with
|
|
8
|
+
* origin metadata).
|
|
9
|
+
*/
|
|
10
|
+
type PreviewMode = 'preview' | 'published';
|
|
11
|
+
/**
|
|
12
|
+
* Origin metadata carried by every `PreviewField<T>` in preview mode.
|
|
13
|
+
*
|
|
14
|
+
* `pageSlug`, `sectionId`, and `fieldPath` together address the field in
|
|
15
|
+
* the content store uniquely enough for the save round-trip to write
|
|
16
|
+
* back to the correct draft file and the correct field inside its
|
|
17
|
+
* section payload.
|
|
18
|
+
*
|
|
19
|
+
* `source` tells the UI and save flow which bucket actually served the
|
|
20
|
+
* data: `'draft'` when a draft existed and was read, `'published'` when
|
|
21
|
+
* preview mode fell back to the published snapshot because no draft
|
|
22
|
+
* existed yet. This affects the first save: saving against a
|
|
23
|
+
* `'published'` source creates a new draft; saving against a `'draft'`
|
|
24
|
+
* source overwrites the existing one.
|
|
25
|
+
*
|
|
26
|
+
* `revision` is a content-addressable hash (SHA-256 hex) of the
|
|
27
|
+
* serialized page bytes from the source bucket at read time. See the
|
|
28
|
+
* file header for the rationale; the hash discriminates ACTUAL content
|
|
29
|
+
* drift without needing adapter-level bookkeeping.
|
|
30
|
+
*
|
|
31
|
+
* `kind` discriminates between a field that lives in a page section
|
|
32
|
+
* (`'page'`, the default) and a field that lives in a standalone global
|
|
33
|
+
* read via `getGlobal` (`'global'`). When `kind` is `'global'`,
|
|
34
|
+
* `globalName` carries the global's name so the save round-trip can
|
|
35
|
+
* route to `/api/agntcms/global/save` instead of the page draft
|
|
36
|
+
* endpoint. The discriminator is OPTIONAL for backward compatibility:
|
|
37
|
+
* existing call sites that don't set it are treated as page origins.
|
|
38
|
+
*
|
|
39
|
+
* Why not split into two unrelated origin types? Every editable widget
|
|
40
|
+
* already reads `origin.fieldPath` and (for the agent ✨ button)
|
|
41
|
+
* `origin.pageSlug`/`origin.sectionId`. Keeping a single shape with all
|
|
42
|
+
* fields present (populated with sentinel values on the global path,
|
|
43
|
+
* matching the convention `wrapGlobalData` introduced in AdminModal)
|
|
44
|
+
* avoids touching every editable component. Consumers that care about
|
|
45
|
+
* the routing decision branch on `origin.kind`.
|
|
46
|
+
*/
|
|
47
|
+
interface PreviewFieldOrigin {
|
|
48
|
+
readonly pageSlug: string;
|
|
49
|
+
readonly sectionId: string;
|
|
50
|
+
readonly fieldPath: string;
|
|
51
|
+
readonly source: 'draft' | 'published';
|
|
52
|
+
readonly revision: string;
|
|
53
|
+
/**
|
|
54
|
+
* Discriminator: `'page'` (default, when omitted) means the field
|
|
55
|
+
* lives inside a page draft; `'global'` means it lives inside a
|
|
56
|
+
* standalone global. New in v0.2 (Phase 2 globals work).
|
|
57
|
+
*/
|
|
58
|
+
readonly kind?: 'page' | 'global';
|
|
59
|
+
/**
|
|
60
|
+
* The global's name. Present iff `kind === 'global'`. Consumers that
|
|
61
|
+
* route saves on the global endpoint read this value.
|
|
62
|
+
*/
|
|
63
|
+
readonly globalName?: string;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* A field value in preview mode: the bare value plus its origin metadata
|
|
67
|
+
* and a brand so downstream code can distinguish a wrapped preview field
|
|
68
|
+
* from a bare published value both at compile time and at runtime.
|
|
69
|
+
*
|
|
70
|
+
* The brand uses a regular property `__agntcmsPreview: true` rather
|
|
71
|
+
* than a `unique symbol`. The original T-007 design used a `declare`-only
|
|
72
|
+
* unique symbol for the brand, which is structurally unforgeable at
|
|
73
|
+
* compile time. However, `declare const` symbols exist only in the type
|
|
74
|
+
* system — they have no runtime identity, so the implementation (T-008)
|
|
75
|
+
* cannot actually SET a symbol-keyed property on the wrapper objects it
|
|
76
|
+
* constructs. Using a string-keyed property solves this: the runtime can
|
|
77
|
+
* set it, the `EditableText`/`EditableImage` components (T-016) can
|
|
78
|
+
* detect it with a cheap `'__agntcmsPreview' in field` check, and it is
|
|
79
|
+
* still unforgeable enough for v1 (no user type would accidentally have
|
|
80
|
+
* a `__agntcmsPreview` property). The double-underscore prefix signals
|
|
81
|
+
* "framework internal — do not depend on this key".
|
|
82
|
+
*
|
|
83
|
+
* The `value` key carries the underlying data (e.g. a `string` for
|
|
84
|
+
* `TextField` or `ImageField`). Client-side code unwraps by reading
|
|
85
|
+
* `field.value`; servers read `field.origin` to compute where a save
|
|
86
|
+
* must land.
|
|
87
|
+
*/
|
|
88
|
+
interface PreviewField<T> {
|
|
89
|
+
readonly __agntcmsPreview: true;
|
|
90
|
+
readonly value: T;
|
|
91
|
+
readonly origin: PreviewFieldOrigin;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* `FieldIn<Mode, T>` is the mode-aware wrapper type. It is the SINGLE
|
|
95
|
+
* axiom on which everything else in this file depends:
|
|
96
|
+
*
|
|
97
|
+
* - `FieldIn<'preview', T>` → `PreviewField<T>`
|
|
98
|
+
* - `FieldIn<'published', T>` → `T` (structurally identical, zero cost)
|
|
99
|
+
*
|
|
100
|
+
* Written as a distributive conditional over a naked `Mode` parameter so
|
|
101
|
+
* that when `Mode` is itself a union, `FieldIn<Mode, T>` distributes over
|
|
102
|
+
* it. This is what makes the single `getContent` call site correctly
|
|
103
|
+
* return `PreviewField<T> | T` (rather than a widened `never`) when the
|
|
104
|
+
* caller's `mode` is known only as `'preview' | 'published'`.
|
|
105
|
+
*/
|
|
106
|
+
type FieldIn<Mode extends PreviewMode, T> = Mode extends 'preview' ? PreviewField<T> : Mode extends 'published' ? T : never;
|
|
107
|
+
/**
|
|
108
|
+
* Projects a section schema `S` into its mode-resolved field shape.
|
|
109
|
+
* Each key in `S` is mapped through `FieldValueFor<S[K]>` to its runtime
|
|
110
|
+
* value type, and then wrapped via `FieldIn<Mode, _>`.
|
|
111
|
+
*
|
|
112
|
+
* The double conditional keeps distribution working: `Mode` must remain
|
|
113
|
+
* naked in the outermost position so a union `Mode` distributes here.
|
|
114
|
+
* `S[K]` is passed through `FieldValueFor` separately (non-distributive)
|
|
115
|
+
* because each key resolves independently.
|
|
116
|
+
*
|
|
117
|
+
* Mapped type keys are preserved as-is (no `-readonly`, no `-?`) so the
|
|
118
|
+
* readonly-ness and optionality of the schema's own keys are not
|
|
119
|
+
* dropped.
|
|
120
|
+
*/
|
|
121
|
+
type PageContent<Mode extends PreviewMode, S extends SectionSchema> = Mode extends 'preview' ? {
|
|
122
|
+
readonly [K in keyof S]: PreviewField<FieldValueFor<S[K]>>;
|
|
123
|
+
} : Mode extends 'published' ? {
|
|
124
|
+
readonly [K in keyof S]: FieldValueFor<S[K]>;
|
|
125
|
+
} : never;
|
|
126
|
+
/**
|
|
127
|
+
* Parameters for a single `getContent` call.
|
|
128
|
+
*
|
|
129
|
+
* `slug` identifies the page. `mode` is the dual-mode discriminator;
|
|
130
|
+
* keeping it as a generic `Mode extends PreviewMode` is what lets the
|
|
131
|
+
* return type narrow in lockstep with the caller's `mode` value.
|
|
132
|
+
*
|
|
133
|
+
* Additional fields (e.g. locale, draft id, preview token) are
|
|
134
|
+
* deliberately out of scope for T-007. They can be added additively
|
|
135
|
+
* without breaking the mode-resolution mechanism locked in here.
|
|
136
|
+
*/
|
|
137
|
+
interface GetContentOptions<Mode extends PreviewMode> {
|
|
138
|
+
readonly slug: string;
|
|
139
|
+
readonly mode: Mode;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* The public `getContent` function type. Single call site, generic over
|
|
143
|
+
* `Mode` and over the section schema `S`, returning `null` when the
|
|
144
|
+
* requested page does not exist in the mode's resolved storage.
|
|
145
|
+
*
|
|
146
|
+
* T-008 ships the runtime implementation that satisfies this type.
|
|
147
|
+
* Typed as a function type (not an interface with a call signature) so
|
|
148
|
+
* callers using `typeof getContent` get a clean arrow-function shape in
|
|
149
|
+
* tooltips.
|
|
150
|
+
*/
|
|
151
|
+
type GetContent = <Mode extends PreviewMode, S extends SectionSchema>(options: GetContentOptions<Mode>) => Promise<PageContent<Mode, S> | null>;
|
|
152
|
+
|
|
153
|
+
interface GetGlobalInput {
|
|
154
|
+
readonly name: string;
|
|
155
|
+
readonly mode: PreviewMode;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* The runtime function shape for `getGlobal`. Returned as part of the
|
|
159
|
+
* `Runtime` surface from `createRuntime`. Returns `null` when the named
|
|
160
|
+
* global doesn't exist.
|
|
161
|
+
*/
|
|
162
|
+
type GetGlobal = (options: GetGlobalInput) => Promise<Global | null>;
|
|
163
|
+
|
|
164
|
+
/** Sort direction for `listPages`. Defaults to `'newest'`. */
|
|
165
|
+
type ListPagesSort = 'newest' | 'oldest';
|
|
166
|
+
interface ListPagesInput {
|
|
167
|
+
/** Case-sensitive exact-match filter on `Page.tags`. */
|
|
168
|
+
readonly tag?: string;
|
|
169
|
+
/** Maximum number of results. No upper bound; passing `0` returns []. */
|
|
170
|
+
readonly limit?: number;
|
|
171
|
+
/** Sort direction. Defaults to `'newest'`. */
|
|
172
|
+
readonly sort?: ListPagesSort;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Read metadata-only summaries of every PUBLISHED page, optionally
|
|
176
|
+
* filtered by tag and capped by limit.
|
|
177
|
+
*
|
|
178
|
+
* V1 limitation: returns published pages only regardless of preview /
|
|
179
|
+
* published context. Drafts are not surfaced in lists. To see a draft
|
|
180
|
+
* in a `PostList`, the page must first be published. See file header
|
|
181
|
+
* and ARCHITECTURE.md §12 for the rationale and roadmap.
|
|
182
|
+
*/
|
|
183
|
+
type ListPages = (input?: ListPagesInput) => Promise<ReadonlyArray<PageSummary>>;
|
|
184
|
+
interface CreateListPagesDeps {
|
|
185
|
+
readonly contentAdapter: ContentStorageAdapter;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Build the `listPages` runtime function.
|
|
189
|
+
*
|
|
190
|
+
* V1 limitation: the returned function reads PUBLISHED pages only. A
|
|
191
|
+
* draft-only page (never published) will not appear in the result, even
|
|
192
|
+
* when the surrounding request is in preview mode. See file header and
|
|
193
|
+
* ARCHITECTURE.md §12.
|
|
194
|
+
*/
|
|
195
|
+
declare const createListPages: ({ contentAdapter, }: CreateListPagesDeps) => ListPages;
|
|
196
|
+
|
|
197
|
+
/** Result of a `submitForm` call. */
|
|
198
|
+
type SubmitFormResult = {
|
|
199
|
+
readonly ok: true;
|
|
200
|
+
readonly stored: true;
|
|
201
|
+
readonly id: string;
|
|
202
|
+
} | {
|
|
203
|
+
readonly ok: true;
|
|
204
|
+
readonly stored: false;
|
|
205
|
+
readonly suppressed: 'honeypot';
|
|
206
|
+
} | {
|
|
207
|
+
readonly ok: false;
|
|
208
|
+
readonly error: 'unknown_form';
|
|
209
|
+
} | {
|
|
210
|
+
readonly ok: false;
|
|
211
|
+
readonly error: 'validation_failed';
|
|
212
|
+
readonly errors: Record<string, string>;
|
|
213
|
+
};
|
|
214
|
+
/** Dependencies for `submitForm`. */
|
|
215
|
+
interface SubmitFormDeps {
|
|
216
|
+
/**
|
|
217
|
+
* A `FormLookup`-shaped object: anything with `get(name)` returning a
|
|
218
|
+
* form definition. The concrete `FormRegistry` from `forms/registry.ts`
|
|
219
|
+
* structurally satisfies this interface, so the runtime can stay
|
|
220
|
+
* dependency-free of `forms/` (per ARCHITECTURE.md §8 dep graph).
|
|
221
|
+
*/
|
|
222
|
+
readonly forms: FormLookup;
|
|
223
|
+
readonly submissionAdapter: SubmissionStorageAdapter;
|
|
224
|
+
/** Optional ID generator for tests; defaults to a ULID-like generator. */
|
|
225
|
+
readonly generateId?: () => string;
|
|
226
|
+
/** Optional clock for tests; defaults to `() => new Date().toISOString()`. */
|
|
227
|
+
readonly now?: () => string;
|
|
228
|
+
}
|
|
229
|
+
/** Input to `submitForm`. */
|
|
230
|
+
interface SubmitFormInput {
|
|
231
|
+
readonly formName: string;
|
|
232
|
+
/** The raw payload from the request. Validated here, NOT in the handler. */
|
|
233
|
+
readonly payload: Readonly<Record<string, unknown>>;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Build the runtime function that handles form submissions.
|
|
237
|
+
*
|
|
238
|
+
* Returns a `submitForm(input)` that:
|
|
239
|
+
* 1. Looks up the form definition.
|
|
240
|
+
* 2. Honors honeypot.
|
|
241
|
+
* 3. Validates payload.
|
|
242
|
+
* 4. Stamps id+submittedAt and stores via the adapter.
|
|
243
|
+
*/
|
|
244
|
+
declare function createSubmitForm(deps: SubmitFormDeps): (input: SubmitFormInput) => Promise<SubmitFormResult>;
|
|
245
|
+
/** Type of the function returned by `createSubmitForm`. */
|
|
246
|
+
type SubmitForm = ReturnType<typeof createSubmitForm>;
|
|
247
|
+
|
|
248
|
+
/** Dependencies for the runtime. */
|
|
249
|
+
interface RuntimeOptions {
|
|
250
|
+
readonly contentAdapter: ContentStorageAdapter;
|
|
251
|
+
/**
|
|
252
|
+
* Form registry — required for `submitForm` to look up form definitions.
|
|
253
|
+
* Accepts any `FormLookup`-shaped object (the concrete `FormRegistry`
|
|
254
|
+
* from `forms/registry.ts` satisfies this structurally). Optional for
|
|
255
|
+
* backward compatibility: when omitted, `submitForm` is wired to an
|
|
256
|
+
* empty lookup, so any submission attempt returns `unknown_form`.
|
|
257
|
+
* Templates that use forms (ARCHITECTURE.md §6.5) MUST pass a registry
|
|
258
|
+
* built from `defineConfig({ forms: [...] })`.
|
|
259
|
+
*/
|
|
260
|
+
readonly forms?: FormLookup;
|
|
261
|
+
/**
|
|
262
|
+
* Submission storage adapter. Optional for backward compatibility: when
|
|
263
|
+
* omitted, `submitForm` is wired to a no-op adapter that throws on store.
|
|
264
|
+
* Templates that use forms MUST pass an adapter (FS or webhook).
|
|
265
|
+
*/
|
|
266
|
+
readonly submissionAdapter?: SubmissionStorageAdapter;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* The runtime surface returned by `createRuntime`. This is what
|
|
270
|
+
* `defineConfig` (T-019) will later wire up and what the handlers
|
|
271
|
+
* layer consumes.
|
|
272
|
+
*/
|
|
273
|
+
interface Runtime {
|
|
274
|
+
/**
|
|
275
|
+
* Read a page in the requested mode.
|
|
276
|
+
*
|
|
277
|
+
* In 'published' mode the bare `Page` from the adapter is returned
|
|
278
|
+
* as-is — zero allocation, no wrapping.
|
|
279
|
+
*
|
|
280
|
+
* In 'preview' mode every field value in every section is wrapped in
|
|
281
|
+
* a `PreviewField` carrying origin metadata. The runtime tries the
|
|
282
|
+
* draft bucket first and falls back to the published bucket.
|
|
283
|
+
*
|
|
284
|
+
* Returns `null` when neither bucket has a page for the given slug.
|
|
285
|
+
*/
|
|
286
|
+
readonly getContent: (options: GetContentInput) => Promise<Page | null>;
|
|
287
|
+
/**
|
|
288
|
+
* Thin wrapper over the adapter's `publishDraft`. Git commits are
|
|
289
|
+
* T-009's scope — this function does NOT touch git.
|
|
290
|
+
*/
|
|
291
|
+
readonly publishDraft: (slug: string) => Promise<Page>;
|
|
292
|
+
/**
|
|
293
|
+
* Read a named global in the requested mode.
|
|
294
|
+
*
|
|
295
|
+
* Mirrors `getContent`'s dual nature (ARCHITECTURE.md §6) for
|
|
296
|
+
* standalone globals. In `'published'` mode returns the bare
|
|
297
|
+
* `Global`; in `'preview'` mode wraps every field in `PreviewField`
|
|
298
|
+
* with a `kind: 'global'` origin so editable widgets route saves to
|
|
299
|
+
* `/api/agntcms/global/save`.
|
|
300
|
+
*
|
|
301
|
+
* Returns `null` when no global with `name` exists. Globals have no
|
|
302
|
+
* draft/publish cycle (see domain/global.ts) so there is no
|
|
303
|
+
* fall-back branch.
|
|
304
|
+
*/
|
|
305
|
+
readonly getGlobal: GetGlobal;
|
|
306
|
+
/**
|
|
307
|
+
* Accept a form submission. See `runtime/submitForm.ts` for the full
|
|
308
|
+
* pipeline (form lookup, honeypot, validation, store). Rate limiting
|
|
309
|
+
* is handled at the handler layer, not here.
|
|
310
|
+
*
|
|
311
|
+
* When the runtime was built without a `forms` registry or a
|
|
312
|
+
* `submissionAdapter`, `submitForm` returns `{ ok: false, error: 'unknown_form' }`
|
|
313
|
+
* for every call so downstream code can fail closed without crashing.
|
|
314
|
+
*/
|
|
315
|
+
readonly submitForm: SubmitForm;
|
|
316
|
+
/**
|
|
317
|
+
* Return metadata-only summaries of every published page, optionally
|
|
318
|
+
* filtered by a single tag and capped by `limit`. Used by user-defined
|
|
319
|
+
* listing sections (e.g. PostList) for blog-index-style queries.
|
|
320
|
+
*
|
|
321
|
+
* See `runtime/listPages.ts` for the sort and filter semantics
|
|
322
|
+
* (ARCHITECTURE.md §4).
|
|
323
|
+
*/
|
|
324
|
+
readonly listPages: ListPages;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
interface GetContentInput {
|
|
328
|
+
readonly slug: string;
|
|
329
|
+
readonly mode: PreviewMode;
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Create the runtime that powers `getContent` and `publishDraft`.
|
|
333
|
+
*
|
|
334
|
+
* The adapter is injected — no global state, no singleton. This is the
|
|
335
|
+
* shape `defineConfig` (T-019) will later construct under the hood.
|
|
336
|
+
*/
|
|
337
|
+
declare function createRuntime(options: RuntimeOptions): Runtime;
|
|
338
|
+
|
|
339
|
+
/** Result of a rate-limit check. */
|
|
340
|
+
interface RateLimitResult {
|
|
341
|
+
/** When `false`, the caller MUST reject the request with HTTP 429. */
|
|
342
|
+
readonly allowed: boolean;
|
|
343
|
+
/** Number of requests counted in the current window after this call. */
|
|
344
|
+
readonly count: number;
|
|
345
|
+
/** Epoch milliseconds when the current window resets. */
|
|
346
|
+
readonly resetAt: number;
|
|
347
|
+
}
|
|
348
|
+
/** Options for `createRateLimit`. */
|
|
349
|
+
interface RateLimitOptions {
|
|
350
|
+
/** Max requests per window per (ip, formName) key. Default: 5. */
|
|
351
|
+
readonly perWindow: number;
|
|
352
|
+
/** Window length in milliseconds. Default: 60_000 (1 minute). */
|
|
353
|
+
readonly windowMs: number;
|
|
354
|
+
/**
|
|
355
|
+
* Clock injection point for tests. Called once per check to read the
|
|
356
|
+
* current time. Defaults to `Date.now`.
|
|
357
|
+
*/
|
|
358
|
+
readonly now?: () => number;
|
|
359
|
+
/**
|
|
360
|
+
* Maximum number of (ip, formName) buckets retained in memory. When
|
|
361
|
+
* the map reaches this size, `check()` lazily sweeps expired buckets;
|
|
362
|
+
* if still at the cap, the oldest-resetAt buckets are dropped to make
|
|
363
|
+
* room. Default: 10_000. Must be a positive integer.
|
|
364
|
+
*
|
|
365
|
+
* Why: a public submit endpoint with one-off IPs (CDN edges, mobile
|
|
366
|
+
* NAT pools, attack traffic) would otherwise grow the map without
|
|
367
|
+
* bound until process restart.
|
|
368
|
+
*/
|
|
369
|
+
readonly maxBuckets?: number;
|
|
370
|
+
}
|
|
371
|
+
interface RateLimit {
|
|
372
|
+
/**
|
|
373
|
+
* Record one request and return whether it is allowed under the current
|
|
374
|
+
* window. Always counts (even rejected calls) — this matches the typical
|
|
375
|
+
* abuse-mitigation expectation: a flood that hits the limit shouldn't
|
|
376
|
+
* "free" itself by spinning down the counter.
|
|
377
|
+
*/
|
|
378
|
+
check(ip: string, formName: string): RateLimitResult;
|
|
379
|
+
/**
|
|
380
|
+
* Test-only utility: clear all buckets. Useful between tests to keep
|
|
381
|
+
* them order-independent without recreating the limiter.
|
|
382
|
+
*/
|
|
383
|
+
reset(): void;
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Build an in-memory rate limiter. Each created limiter is independent
|
|
387
|
+
* (no module-level singleton).
|
|
388
|
+
*/
|
|
389
|
+
declare function createRateLimit(options: RateLimitOptions): RateLimit;
|
|
390
|
+
|
|
391
|
+
export { type FieldIn as F, type GetGlobal as G, type ListPages as L, type PreviewMode as P, type RateLimit as R, type SubmitForm as S, type GetContent as a, type GetContentInput as b, type GetContentOptions as c, type GetGlobalInput as d, type ListPagesInput as e, type ListPagesSort as f, type PageContent as g, type PreviewField as h, type PreviewFieldOrigin as i, type RateLimitOptions as j, type RateLimitResult as k, type Runtime as l, type RuntimeOptions as m, type SubmitFormDeps as n, type SubmitFormInput as o, type SubmitFormResult as p, createListPages as q, createRateLimit as r, createRuntime as s, createSubmitForm as t };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { A as AnyFormDefinition, F as FormLookup } from './form-BqY0H1V5.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The input list `defineConfig` takes for forms.
|
|
5
|
+
*/
|
|
6
|
+
type FormDefinitionList = readonly AnyFormDefinition[];
|
|
7
|
+
/**
|
|
8
|
+
* Opaque, immutable lookup built from a `FormDefinitionList`. Structurally
|
|
9
|
+
* extends `FormLookup` (defined in `domain/`) so the runtime can accept
|
|
10
|
+
* any `FormLookup` without depending on `forms/`.
|
|
11
|
+
*/
|
|
12
|
+
interface FormRegistry extends FormLookup {
|
|
13
|
+
readonly definitions: FormDefinitionList;
|
|
14
|
+
get(name: string): AnyFormDefinition | undefined;
|
|
15
|
+
has(name: string): boolean;
|
|
16
|
+
}
|
|
17
|
+
/** Thrown when two form definitions share a `name`. */
|
|
18
|
+
declare class DuplicateFormNameError extends Error {
|
|
19
|
+
readonly formName: string;
|
|
20
|
+
constructor(name: string);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Build an immutable `FormRegistry` from an ordered list of definitions.
|
|
24
|
+
* Rejects duplicates eagerly — see `buildSectionRegistry` for the same
|
|
25
|
+
* rationale.
|
|
26
|
+
*/
|
|
27
|
+
declare function buildFormRegistry(definitions: FormDefinitionList): FormRegistry;
|
|
28
|
+
|
|
29
|
+
export { DuplicateFormNameError as D, type FormDefinitionList as F, type FormRegistry as a, buildFormRegistry as b };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { A as AnyFormDefinition, F as FormLookup } from './form-BqY0H1V5.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The input list `defineConfig` takes for forms.
|
|
5
|
+
*/
|
|
6
|
+
type FormDefinitionList = readonly AnyFormDefinition[];
|
|
7
|
+
/**
|
|
8
|
+
* Opaque, immutable lookup built from a `FormDefinitionList`. Structurally
|
|
9
|
+
* extends `FormLookup` (defined in `domain/`) so the runtime can accept
|
|
10
|
+
* any `FormLookup` without depending on `forms/`.
|
|
11
|
+
*/
|
|
12
|
+
interface FormRegistry extends FormLookup {
|
|
13
|
+
readonly definitions: FormDefinitionList;
|
|
14
|
+
get(name: string): AnyFormDefinition | undefined;
|
|
15
|
+
has(name: string): boolean;
|
|
16
|
+
}
|
|
17
|
+
/** Thrown when two form definitions share a `name`. */
|
|
18
|
+
declare class DuplicateFormNameError extends Error {
|
|
19
|
+
readonly formName: string;
|
|
20
|
+
constructor(name: string);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Build an immutable `FormRegistry` from an ordered list of definitions.
|
|
24
|
+
* Rejects duplicates eagerly — see `buildSectionRegistry` for the same
|
|
25
|
+
* rationale.
|
|
26
|
+
*/
|
|
27
|
+
declare function buildFormRegistry(definitions: FormDefinitionList): FormRegistry;
|
|
28
|
+
|
|
29
|
+
export { DuplicateFormNameError as D, type FormDefinitionList as F, type FormRegistry as a, buildFormRegistry as b };
|