@agntcms/next 0.3.1 → 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 +25 -121
- package/dist/config.d.cts +6 -59
- package/dist/config.d.ts +6 -59
- package/dist/config.mjs +25 -114
- 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/handlers.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { C as ContentStorageAdapter, A as AssetStorageAdapter } from './assets-
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
1
|
+
import { C as ContentStorageAdapter, A as AssetStorageAdapter } from './assets-DHumg-X7.js';
|
|
2
|
+
import { R as Runtime } from './getContent-DAgAn095.js';
|
|
3
|
+
import './page-DXF0_SrY.js';
|
|
4
4
|
import './global-CV23g5Bn.js';
|
|
5
5
|
|
|
6
6
|
type TaskId = string;
|
|
@@ -261,72 +261,6 @@ interface GlobalHandler {
|
|
|
261
261
|
}
|
|
262
262
|
declare function createGlobalHandler(deps: GlobalHandlerDeps): GlobalHandler;
|
|
263
263
|
|
|
264
|
-
/**
|
|
265
|
-
* Template definition shape matching `PageTemplate` from config.
|
|
266
|
-
* Redeclared here as a structural type so the handler does not import
|
|
267
|
-
* from config/ (invariant 1).
|
|
268
|
-
*/
|
|
269
|
-
interface TemplateDef {
|
|
270
|
-
readonly name: string;
|
|
271
|
-
readonly description?: string;
|
|
272
|
-
readonly sectionTypes: readonly string[];
|
|
273
|
-
}
|
|
274
|
-
interface TemplateHandlerDeps {
|
|
275
|
-
/**
|
|
276
|
-
* Pre-resolved map: section type name -> default data for that section.
|
|
277
|
-
* Built by the wiring layer from the registered `AnySectionDefinition[]`.
|
|
278
|
-
*/
|
|
279
|
-
readonly sectionDefaults: ReadonlyMap<string, Readonly<Record<string, unknown>>>;
|
|
280
|
-
/** The template definitions from config. */
|
|
281
|
-
readonly templates: readonly TemplateDef[];
|
|
282
|
-
}
|
|
283
|
-
interface TemplateHandler {
|
|
284
|
-
/** GET /api/agntcms/template/list */
|
|
285
|
-
readonly list: (req: Request) => Promise<Response>;
|
|
286
|
-
}
|
|
287
|
-
declare function createTemplateHandler(deps: TemplateHandlerDeps): TemplateHandler;
|
|
288
|
-
|
|
289
|
-
interface SubmitHandlerDeps {
|
|
290
|
-
readonly runtime: Runtime;
|
|
291
|
-
readonly rateLimit: RateLimit;
|
|
292
|
-
}
|
|
293
|
-
declare function createSubmitFormHandler(deps: SubmitHandlerDeps): (req: Request) => Promise<Response>;
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* Adapter info surfaced to the AdminModal. Two shapes:
|
|
297
|
-
* - `{ kind: 'fs' }` — local FS submissions; readable.
|
|
298
|
-
* - `{ kind: 'webhook', host }` — webhook adapter; not locally readable.
|
|
299
|
-
*/
|
|
300
|
-
type FormsListAdapterInfo = {
|
|
301
|
-
readonly kind: 'fs';
|
|
302
|
-
} | {
|
|
303
|
-
readonly kind: 'webhook';
|
|
304
|
-
readonly host: string;
|
|
305
|
-
};
|
|
306
|
-
interface FormsListHandlerDeps {
|
|
307
|
-
/** Registered form definitions (from `defineConfig({ forms: [...] })`). */
|
|
308
|
-
readonly forms: ReadonlyArray<AnyFormDefinition>;
|
|
309
|
-
/**
|
|
310
|
-
* Optional adapter descriptor. When omitted, the handler reports
|
|
311
|
-
* `{ kind: 'fs' }` — the v1 default adapter (ARCHITECTURE.md §6.5).
|
|
312
|
-
* Frozen routes that wire a webhook adapter pass `{ kind: 'webhook',
|
|
313
|
-
* host: '<host>' }` here; the host is computed once at handler-construction
|
|
314
|
-
* time from the configured webhook URL.
|
|
315
|
-
*/
|
|
316
|
-
readonly adapter?: FormsListAdapterInfo;
|
|
317
|
-
}
|
|
318
|
-
/** Forms list handler. */
|
|
319
|
-
declare function createFormsListHandler(deps: FormsListHandlerDeps): (_req: Request) => Promise<Response>;
|
|
320
|
-
|
|
321
|
-
interface FormsReadHandlerDeps {
|
|
322
|
-
readonly submissionAdapter: SubmissionStorageAdapter;
|
|
323
|
-
/** Registered form names — used to 404 unknown forms before hitting the adapter. */
|
|
324
|
-
readonly knownForms: ReadonlySet<string>;
|
|
325
|
-
}
|
|
326
|
-
declare function createFormsReadHandler(deps: FormsReadHandlerDeps): (req: Request) => Promise<Response>;
|
|
327
|
-
|
|
328
|
-
declare function createFormsDeleteHandler(): (_req: Request) => Promise<Response>;
|
|
329
|
-
|
|
330
264
|
/**
|
|
331
265
|
* Dependencies for every endpoint the dispatcher serves. Grouped by
|
|
332
266
|
* underlying handler factory so the template wiring mirrors the v0.2
|
|
@@ -346,9 +280,6 @@ interface agntcmsRouteHandlerOptions {
|
|
|
346
280
|
readonly preview?: PreviewHandlerDeps;
|
|
347
281
|
readonly events: EventsHandlerDeps;
|
|
348
282
|
readonly mcp: McpHandlerDeps;
|
|
349
|
-
readonly template: TemplateHandlerDeps;
|
|
350
|
-
readonly formsList: FormsListHandlerDeps;
|
|
351
|
-
readonly formsRead: FormsReadHandlerDeps;
|
|
352
283
|
}
|
|
353
284
|
/** HTTP methods the dispatcher routes. */
|
|
354
285
|
type DispatcherMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
@@ -391,4 +322,4 @@ interface agntcmsRouteHandler {
|
|
|
391
322
|
*/
|
|
392
323
|
declare function createagntcmsRouteHandler(opts: agntcmsRouteHandlerOptions): agntcmsRouteHandler;
|
|
393
324
|
|
|
394
|
-
export { type AgentBridge, type AgentBridgeStatus, AgentUnreachableError, type AssetsHandler, type AssetsHandlerDeps, type CreateAgentBridgeOptions, type DispatcherMethod, type DraftHandler, type DraftHandlerDeps, type EventsHandler, type EventsHandlerDeps, type
|
|
325
|
+
export { type AgentBridge, type AgentBridgeStatus, AgentUnreachableError, type AssetsHandler, type AssetsHandlerDeps, type CreateAgentBridgeOptions, type DispatcherMethod, type DraftHandler, type DraftHandlerDeps, type EventsHandler, type EventsHandlerDeps, type GlobalHandler, type GlobalHandlerDeps, type McpHandler, type McpHandlerDeps, type PageHandler, type PageHandlerDeps, type PreviewHandler, type PreviewHandlerDeps, type PreviewToken, type PreviewTokenStore, type PreviewTokenStoreOptions, type Task, type TaskEvent, type TaskId, type TaskSnapshot, type TaskState, type TaskStore, type agntcmsRouteContext, type agntcmsRouteHandler, type agntcmsRouteHandlerOptions, createAgentBridge, createAssetsHandler, createDraftHandler, createEventsHandler, createGlobalHandler, createMcpHandler, createPageHandler, createPreviewHandler, createPreviewTokenStore, createTaskStore, createagntcmsRouteHandler };
|
package/dist/handlers.mjs
CHANGED
|
@@ -182,14 +182,6 @@ function assertValidPage(page) {
|
|
|
182
182
|
assertValidPageMeta(obj);
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
// src/domain/form.ts
|
|
186
|
-
var SubmissionsNotReadableError = class extends Error {
|
|
187
|
-
constructor(message = "submission adapter does not support reading") {
|
|
188
|
-
super(message);
|
|
189
|
-
this.name = "SubmissionsNotReadableError";
|
|
190
|
-
}
|
|
191
|
-
};
|
|
192
|
-
|
|
193
185
|
// src/storage/fs/content.ts
|
|
194
186
|
var SLUG_PATTERN = /^[a-zA-Z0-9_-]+(?:\/[a-zA-Z0-9_-]+)*$/;
|
|
195
187
|
var assertValidSlug = (slug) => {
|
|
@@ -250,7 +242,7 @@ var createFsContentAdapter = (options) => {
|
|
|
250
242
|
throw err;
|
|
251
243
|
}
|
|
252
244
|
};
|
|
253
|
-
const
|
|
245
|
+
const listJsonFiles = async (dir) => {
|
|
254
246
|
let entries;
|
|
255
247
|
try {
|
|
256
248
|
entries = await fs3.readdir(dir, { withFileTypes: true });
|
|
@@ -264,7 +256,7 @@ var createFsContentAdapter = (options) => {
|
|
|
264
256
|
results.push(entry.name);
|
|
265
257
|
} else if (entry.isDirectory()) {
|
|
266
258
|
const subDir = path3.join(dir, entry.name);
|
|
267
|
-
const subFiles = await
|
|
259
|
+
const subFiles = await listJsonFiles(subDir);
|
|
268
260
|
for (const sub of subFiles) {
|
|
269
261
|
results.push(`${entry.name}/${sub}`);
|
|
270
262
|
}
|
|
@@ -303,7 +295,7 @@ var createFsContentAdapter = (options) => {
|
|
|
303
295
|
await writeAtomic(filePath, JSON.stringify(page, null, 2));
|
|
304
296
|
};
|
|
305
297
|
const listDrafts = async () => {
|
|
306
|
-
const files = await
|
|
298
|
+
const files = await listJsonFiles(draftsDir);
|
|
307
299
|
const results = [];
|
|
308
300
|
for (const relPath of files) {
|
|
309
301
|
const slug = relPath.slice(0, -".json".length);
|
|
@@ -313,7 +305,7 @@ var createFsContentAdapter = (options) => {
|
|
|
313
305
|
return results;
|
|
314
306
|
};
|
|
315
307
|
const listPages = async () => {
|
|
316
|
-
const files = await
|
|
308
|
+
const files = await listJsonFiles(pagesDir);
|
|
317
309
|
const results = [];
|
|
318
310
|
for (const relPath of files) {
|
|
319
311
|
const slug = relPath.slice(0, -".json".length);
|
|
@@ -323,7 +315,7 @@ var createFsContentAdapter = (options) => {
|
|
|
323
315
|
return results;
|
|
324
316
|
};
|
|
325
317
|
const listPageSummaries = async () => {
|
|
326
|
-
const files = await
|
|
318
|
+
const files = await listJsonFiles(pagesDir);
|
|
327
319
|
const results = [];
|
|
328
320
|
for (const relPath of files) {
|
|
329
321
|
const slug = relPath.slice(0, -".json".length);
|
|
@@ -621,151 +613,6 @@ var createFsContentAdapter = (options) => {
|
|
|
621
613
|
};
|
|
622
614
|
};
|
|
623
615
|
|
|
624
|
-
// src/storage/fs/submissions.ts
|
|
625
|
-
import { randomUUID } from "crypto";
|
|
626
|
-
import * as fs4 from "fs/promises";
|
|
627
|
-
import * as path4 from "path";
|
|
628
|
-
var DEFAULT_MAX_LIST = 500;
|
|
629
|
-
var FORM_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
630
|
-
var parseSubmission = (raw) => {
|
|
631
|
-
let parsed;
|
|
632
|
-
try {
|
|
633
|
-
parsed = JSON.parse(raw);
|
|
634
|
-
} catch {
|
|
635
|
-
return null;
|
|
636
|
-
}
|
|
637
|
-
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
638
|
-
return null;
|
|
639
|
-
}
|
|
640
|
-
const obj = parsed;
|
|
641
|
-
if (typeof obj["formName"] !== "string") return null;
|
|
642
|
-
if (typeof obj["id"] !== "string") return null;
|
|
643
|
-
if (typeof obj["submittedAt"] !== "string") return null;
|
|
644
|
-
if (obj["payload"] === null || typeof obj["payload"] !== "object" || Array.isArray(obj["payload"])) {
|
|
645
|
-
return null;
|
|
646
|
-
}
|
|
647
|
-
return {
|
|
648
|
-
formName: obj["formName"],
|
|
649
|
-
id: obj["id"],
|
|
650
|
-
submittedAt: obj["submittedAt"],
|
|
651
|
-
payload: obj["payload"]
|
|
652
|
-
};
|
|
653
|
-
};
|
|
654
|
-
var assertValidFormName = (name) => {
|
|
655
|
-
if (typeof name !== "string" || !FORM_NAME_PATTERN.test(name)) {
|
|
656
|
-
throw new Error(`invalid form name: ${JSON.stringify(name)}`);
|
|
657
|
-
}
|
|
658
|
-
};
|
|
659
|
-
var submissionFilename = (submittedAt, id) => {
|
|
660
|
-
const ts = submittedAt.replace(/:/g, "-");
|
|
661
|
-
return `${ts}-${id}.json`;
|
|
662
|
-
};
|
|
663
|
-
var listJsonFiles = async (dir) => {
|
|
664
|
-
let entries;
|
|
665
|
-
try {
|
|
666
|
-
entries = await fs4.readdir(dir, { withFileTypes: true });
|
|
667
|
-
} catch (err) {
|
|
668
|
-
if (isEnoent(err)) return [];
|
|
669
|
-
throw err;
|
|
670
|
-
}
|
|
671
|
-
const results = [];
|
|
672
|
-
for (const entry of entries) {
|
|
673
|
-
if (entry.isFile() && entry.name.endsWith(".json")) {
|
|
674
|
-
results.push(entry.name);
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
return results;
|
|
678
|
-
};
|
|
679
|
-
var createFsSubmissionAdapter = (options) => {
|
|
680
|
-
const { submissionsRoot } = options;
|
|
681
|
-
if (!path4.isAbsolute(submissionsRoot)) {
|
|
682
|
-
throw new Error(
|
|
683
|
-
`submissionsRoot must be an absolute path, got: ${JSON.stringify(submissionsRoot)}`
|
|
684
|
-
);
|
|
685
|
-
}
|
|
686
|
-
const maxList = options.maxList ?? DEFAULT_MAX_LIST;
|
|
687
|
-
if (!Number.isFinite(maxList) || maxList <= 0 || !Number.isInteger(maxList)) {
|
|
688
|
-
throw new Error(
|
|
689
|
-
`maxList must be a positive integer, got: ${maxList}`
|
|
690
|
-
);
|
|
691
|
-
}
|
|
692
|
-
const rootResolved = path4.resolve(submissionsRoot);
|
|
693
|
-
const rootWithSep = rootResolved.endsWith(path4.sep) ? rootResolved : rootResolved + path4.sep;
|
|
694
|
-
const formDir = (formName) => {
|
|
695
|
-
assertValidFormName(formName);
|
|
696
|
-
const dir = path4.resolve(rootResolved, formName);
|
|
697
|
-
if (!dir.startsWith(rootWithSep)) {
|
|
698
|
-
throw new Error(`form name escapes submissions root: ${JSON.stringify(formName)}`);
|
|
699
|
-
}
|
|
700
|
-
return dir;
|
|
701
|
-
};
|
|
702
|
-
const cryptoSuffix = () => randomUUID();
|
|
703
|
-
const store = async (submission) => {
|
|
704
|
-
const dir = formDir(submission.formName);
|
|
705
|
-
const filename = submissionFilename(submission.submittedAt, submission.id);
|
|
706
|
-
if (filename.includes("/") || filename.includes("\\")) {
|
|
707
|
-
throw new Error(`submission id contains path separator: ${JSON.stringify(submission.id)}`);
|
|
708
|
-
}
|
|
709
|
-
const target = path4.join(dir, filename);
|
|
710
|
-
await writeAtomic(target, JSON.stringify(submission, null, 2), cryptoSuffix);
|
|
711
|
-
};
|
|
712
|
-
const list = async (formName) => {
|
|
713
|
-
const dir = formDir(formName);
|
|
714
|
-
const files = await listJsonFiles(dir);
|
|
715
|
-
const summaries = [];
|
|
716
|
-
for (const filename of files) {
|
|
717
|
-
const stem = filename.slice(0, -".json".length);
|
|
718
|
-
const lastDash = stem.lastIndexOf("-");
|
|
719
|
-
if (lastDash < 0) continue;
|
|
720
|
-
const tsRaw = stem.slice(0, lastDash);
|
|
721
|
-
const id = stem.slice(lastDash + 1);
|
|
722
|
-
if (id === "") continue;
|
|
723
|
-
const tIndex = tsRaw.indexOf("T");
|
|
724
|
-
if (tIndex < 0) continue;
|
|
725
|
-
const datePart = tsRaw.slice(0, tIndex);
|
|
726
|
-
const timePart = tsRaw.slice(tIndex + 1).replace(/-/g, ":");
|
|
727
|
-
const submittedAt = `${datePart}T${timePart}`;
|
|
728
|
-
summaries.push({ id, submittedAt });
|
|
729
|
-
}
|
|
730
|
-
summaries.sort((a, b) => {
|
|
731
|
-
if (a.submittedAt !== b.submittedAt) {
|
|
732
|
-
return a.submittedAt < b.submittedAt ? 1 : -1;
|
|
733
|
-
}
|
|
734
|
-
if (a.id !== b.id) {
|
|
735
|
-
return a.id < b.id ? 1 : -1;
|
|
736
|
-
}
|
|
737
|
-
return 0;
|
|
738
|
-
});
|
|
739
|
-
return summaries.length > maxList ? summaries.slice(0, maxList) : summaries;
|
|
740
|
-
};
|
|
741
|
-
const read = async (formName, id) => {
|
|
742
|
-
if (id.includes("/") || id.includes("\\") || id.includes("..")) {
|
|
743
|
-
return null;
|
|
744
|
-
}
|
|
745
|
-
const dir = formDir(formName);
|
|
746
|
-
let entries;
|
|
747
|
-
try {
|
|
748
|
-
entries = (await fs4.readdir(dir)).filter((n) => n.endsWith(".json"));
|
|
749
|
-
} catch (err) {
|
|
750
|
-
if (isEnoent(err)) return null;
|
|
751
|
-
throw err;
|
|
752
|
-
}
|
|
753
|
-
const suffix = `-${id}.json`;
|
|
754
|
-
const found = entries.find((n) => n.endsWith(suffix));
|
|
755
|
-
if (!found) return null;
|
|
756
|
-
const target = path4.join(dir, found);
|
|
757
|
-
let raw;
|
|
758
|
-
try {
|
|
759
|
-
raw = await fs4.readFile(target, { encoding: "utf8" });
|
|
760
|
-
} catch (err) {
|
|
761
|
-
if (isEnoent(err)) return null;
|
|
762
|
-
throw err;
|
|
763
|
-
}
|
|
764
|
-
return parseSubmission(raw);
|
|
765
|
-
};
|
|
766
|
-
return { info: { kind: "fs" }, store, list, read };
|
|
767
|
-
};
|
|
768
|
-
|
|
769
616
|
// src/config/defaults-registry.ts
|
|
770
617
|
var SLOT = /* @__PURE__ */ Symbol.for("@agntcms/next/default-adapter-factories");
|
|
771
618
|
function holder() {
|
|
@@ -776,31 +623,24 @@ function registerDefaultAdapterFactories(factories) {
|
|
|
776
623
|
}
|
|
777
624
|
|
|
778
625
|
// src/config/defaults.ts
|
|
779
|
-
import * as
|
|
626
|
+
import * as path4 from "path";
|
|
780
627
|
function createDefaultContentAdapter(options) {
|
|
781
628
|
const root = options?.projectRoot ?? process.cwd();
|
|
782
629
|
return createFsContentAdapter({
|
|
783
|
-
contentRoot:
|
|
630
|
+
contentRoot: path4.resolve(root, "content")
|
|
784
631
|
});
|
|
785
632
|
}
|
|
786
633
|
function createDefaultAssetAdapter(options) {
|
|
787
634
|
const root = options?.projectRoot ?? process.cwd();
|
|
788
635
|
return createFsAssetAdapter({
|
|
789
|
-
assetsRoot:
|
|
636
|
+
assetsRoot: path4.resolve(root, "public/assets"),
|
|
790
637
|
publicUrlBase: "/assets"
|
|
791
638
|
});
|
|
792
639
|
}
|
|
793
|
-
function createDefaultSubmissionAdapter(options) {
|
|
794
|
-
const root = options?.projectRoot ?? process.cwd();
|
|
795
|
-
return createFsSubmissionAdapter({
|
|
796
|
-
submissionsRoot: path5.resolve(root, "content/submissions")
|
|
797
|
-
});
|
|
798
|
-
}
|
|
799
640
|
function installDefaultAdapterFactories() {
|
|
800
641
|
const factories = {
|
|
801
642
|
content: createDefaultContentAdapter,
|
|
802
|
-
asset: createDefaultAssetAdapter
|
|
803
|
-
submission: createDefaultSubmissionAdapter
|
|
643
|
+
asset: createDefaultAssetAdapter
|
|
804
644
|
};
|
|
805
645
|
registerDefaultAdapterFactories(factories);
|
|
806
646
|
}
|
|
@@ -1601,11 +1441,11 @@ var createTaskStore = () => {
|
|
|
1601
1441
|
if (entries.has(task.id)) {
|
|
1602
1442
|
throw new Error(`duplicate task id: ${task.id}`);
|
|
1603
1443
|
}
|
|
1604
|
-
return new Promise((
|
|
1444
|
+
return new Promise((resolve5, reject) => {
|
|
1605
1445
|
const entry = {
|
|
1606
1446
|
state: "pending",
|
|
1607
1447
|
task,
|
|
1608
|
-
resolve:
|
|
1448
|
+
resolve: resolve5,
|
|
1609
1449
|
reject,
|
|
1610
1450
|
listeners: /* @__PURE__ */ new Set()
|
|
1611
1451
|
};
|
|
@@ -1669,7 +1509,7 @@ var createTaskStore = () => {
|
|
|
1669
1509
|
};
|
|
1670
1510
|
|
|
1671
1511
|
// src/preview-tokens/store.ts
|
|
1672
|
-
import { randomUUID
|
|
1512
|
+
import { randomUUID } from "crypto";
|
|
1673
1513
|
var DEFAULT_TTL_MS = 6e5;
|
|
1674
1514
|
var createPreviewTokenStore = (options) => {
|
|
1675
1515
|
const ttlMs = options?.ttlMs ?? DEFAULT_TTL_MS;
|
|
@@ -1684,7 +1524,7 @@ var createPreviewTokenStore = (options) => {
|
|
|
1684
1524
|
const issue = (slug) => {
|
|
1685
1525
|
const now = Date.now();
|
|
1686
1526
|
sweep(now);
|
|
1687
|
-
const token =
|
|
1527
|
+
const token = randomUUID();
|
|
1688
1528
|
const entry = { slug, createdAt: now };
|
|
1689
1529
|
entries.set(token, entry);
|
|
1690
1530
|
return { token, slug, createdAt: now };
|
|
@@ -1705,7 +1545,7 @@ var createPreviewTokenStore = (options) => {
|
|
|
1705
1545
|
};
|
|
1706
1546
|
|
|
1707
1547
|
// src/handlers/page/page-handler.ts
|
|
1708
|
-
import { randomUUID as
|
|
1548
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
1709
1549
|
var SLUG_PATTERN2 = /^[a-zA-Z0-9_-]+(?:\/[a-zA-Z0-9_-]+)*$/;
|
|
1710
1550
|
var reservedSlugResponse = (slug, error) => {
|
|
1711
1551
|
const violation = getReservedPageSlugViolation(slug);
|
|
@@ -1714,7 +1554,7 @@ var reservedSlugResponse = (slug, error) => {
|
|
|
1714
1554
|
};
|
|
1715
1555
|
var cloneSection = (section) => {
|
|
1716
1556
|
const fresh = {
|
|
1717
|
-
id: `sec_${
|
|
1557
|
+
id: `sec_${randomUUID2()}`,
|
|
1718
1558
|
type: section.type,
|
|
1719
1559
|
data: section.data,
|
|
1720
1560
|
...section.globalRef !== void 0 ? { globalRef: section.globalRef } : {}
|
|
@@ -2266,191 +2106,6 @@ function createGlobalHandler(deps) {
|
|
|
2266
2106
|
return { list, read, save, delete: deleteHandler, listHistory, rollback };
|
|
2267
2107
|
}
|
|
2268
2108
|
|
|
2269
|
-
// src/handlers/template/template-handler.ts
|
|
2270
|
-
function createTemplateHandler(deps) {
|
|
2271
|
-
const { sectionDefaults, templates } = deps;
|
|
2272
|
-
const list = async (_req) => {
|
|
2273
|
-
const resolved = [];
|
|
2274
|
-
for (const template of templates) {
|
|
2275
|
-
const sections = [];
|
|
2276
|
-
for (const typeName of template.sectionTypes) {
|
|
2277
|
-
const defaults = sectionDefaults.get(typeName);
|
|
2278
|
-
if (!defaults) {
|
|
2279
|
-
console.warn(
|
|
2280
|
-
`[agntcms] Template "${template.name}": section type "${typeName}" not found in registered sections, skipping.`
|
|
2281
|
-
);
|
|
2282
|
-
continue;
|
|
2283
|
-
}
|
|
2284
|
-
sections.push({ type: typeName, data: defaults });
|
|
2285
|
-
}
|
|
2286
|
-
resolved.push({
|
|
2287
|
-
name: template.name,
|
|
2288
|
-
...template.description !== void 0 ? { description: template.description } : {},
|
|
2289
|
-
sections
|
|
2290
|
-
});
|
|
2291
|
-
}
|
|
2292
|
-
return jsonResponse({ templates: resolved }, 200);
|
|
2293
|
-
};
|
|
2294
|
-
return { list };
|
|
2295
|
-
}
|
|
2296
|
-
|
|
2297
|
-
// src/handlers/forms/submit-handler.ts
|
|
2298
|
-
var extractIp = (req) => {
|
|
2299
|
-
const xff = req.headers.get("x-forwarded-for");
|
|
2300
|
-
if (xff) {
|
|
2301
|
-
const first = xff.split(",")[0]?.trim();
|
|
2302
|
-
if (first && first.length > 0) return first;
|
|
2303
|
-
}
|
|
2304
|
-
const xri = req.headers.get("x-real-ip");
|
|
2305
|
-
if (xri && xri.trim().length > 0) return xri.trim();
|
|
2306
|
-
return "unknown";
|
|
2307
|
-
};
|
|
2308
|
-
function createSubmitFormHandler(deps) {
|
|
2309
|
-
const { runtime, rateLimit } = deps;
|
|
2310
|
-
return async function handle(req) {
|
|
2311
|
-
let body;
|
|
2312
|
-
try {
|
|
2313
|
-
body = await req.json();
|
|
2314
|
-
} catch {
|
|
2315
|
-
return jsonResponse({ ok: false, error: "invalid_json" }, 400);
|
|
2316
|
-
}
|
|
2317
|
-
if (body === null || typeof body !== "object") {
|
|
2318
|
-
return jsonResponse({ ok: false, error: "invalid_body" }, 400);
|
|
2319
|
-
}
|
|
2320
|
-
const obj = body;
|
|
2321
|
-
if (typeof obj["formName"] !== "string" || obj["formName"] === "") {
|
|
2322
|
-
return jsonResponse({ ok: false, error: "missing_form_name" }, 400);
|
|
2323
|
-
}
|
|
2324
|
-
const payload = obj["payload"];
|
|
2325
|
-
if (payload === null || typeof payload !== "object" || Array.isArray(payload)) {
|
|
2326
|
-
return jsonResponse({ ok: false, error: "invalid_payload" }, 400);
|
|
2327
|
-
}
|
|
2328
|
-
const formName = obj["formName"];
|
|
2329
|
-
const ip = extractIp(req);
|
|
2330
|
-
const rl = rateLimit.check(ip, formName);
|
|
2331
|
-
if (!rl.allowed) {
|
|
2332
|
-
return jsonResponse({ ok: false, error: "rate_limit" }, 429, {
|
|
2333
|
-
// Inform polite clients when they may retry. Spec-compliant for 429.
|
|
2334
|
-
"Retry-After": Math.max(1, Math.ceil((rl.resetAt - Date.now()) / 1e3)).toString()
|
|
2335
|
-
});
|
|
2336
|
-
}
|
|
2337
|
-
let result;
|
|
2338
|
-
try {
|
|
2339
|
-
result = await runtime.submitForm({
|
|
2340
|
-
formName,
|
|
2341
|
-
payload
|
|
2342
|
-
});
|
|
2343
|
-
} catch (err) {
|
|
2344
|
-
void safeErrorMessage(err);
|
|
2345
|
-
return jsonResponse({ ok: false, error: "storage_unavailable" }, 502);
|
|
2346
|
-
}
|
|
2347
|
-
if (!result.ok) {
|
|
2348
|
-
switch (result.error) {
|
|
2349
|
-
case "unknown_form":
|
|
2350
|
-
return jsonResponse({ ok: false, error: "unknown_form" }, 404);
|
|
2351
|
-
case "validation_failed":
|
|
2352
|
-
return jsonResponse(
|
|
2353
|
-
{ ok: false, error: "validation_failed", errors: result.errors },
|
|
2354
|
-
400
|
|
2355
|
-
);
|
|
2356
|
-
default: {
|
|
2357
|
-
const _exhaustive = result;
|
|
2358
|
-
void _exhaustive;
|
|
2359
|
-
return jsonResponse({ ok: false, error: "internal_error" }, 500);
|
|
2360
|
-
}
|
|
2361
|
-
}
|
|
2362
|
-
}
|
|
2363
|
-
if (!result.stored) {
|
|
2364
|
-
return jsonResponse({ ok: true, stored: false }, 200);
|
|
2365
|
-
}
|
|
2366
|
-
return jsonResponse({ ok: true, stored: true, id: result.id }, 200);
|
|
2367
|
-
};
|
|
2368
|
-
}
|
|
2369
|
-
|
|
2370
|
-
// src/handlers/forms/list-handler.ts
|
|
2371
|
-
function createFormsListHandler(deps) {
|
|
2372
|
-
const adapter = deps.adapter ?? { kind: "fs" };
|
|
2373
|
-
return async function handle(_req) {
|
|
2374
|
-
try {
|
|
2375
|
-
const forms = deps.forms.map((f) => {
|
|
2376
|
-
const schema = {};
|
|
2377
|
-
for (const [name, descriptor] of Object.entries(f.schema)) {
|
|
2378
|
-
schema[name] = descriptor;
|
|
2379
|
-
}
|
|
2380
|
-
return { name: f.name, schema };
|
|
2381
|
-
});
|
|
2382
|
-
return jsonResponse({ forms, adapter }, 200);
|
|
2383
|
-
} catch (err) {
|
|
2384
|
-
console.error("[agntcms] list_forms_failed:", err);
|
|
2385
|
-
return jsonResponse({ error: "list_forms_failed", message: "internal error" }, 500);
|
|
2386
|
-
}
|
|
2387
|
-
};
|
|
2388
|
-
}
|
|
2389
|
-
|
|
2390
|
-
// src/handlers/forms/read-handler.ts
|
|
2391
|
-
var FORM_NAME_PATTERN2 = /^[a-zA-Z0-9_-]+$/;
|
|
2392
|
-
var ID_PATTERN = /^[0-9A-HJKMNPQRSTVWXYZ]{16}$/;
|
|
2393
|
-
function createFormsReadHandler(deps) {
|
|
2394
|
-
return async function handle(req) {
|
|
2395
|
-
const url = new URL(req.url);
|
|
2396
|
-
const form = url.searchParams.get("form");
|
|
2397
|
-
const id = url.searchParams.get("id");
|
|
2398
|
-
if (!form) return jsonResponse({ error: "missing_form" }, 400);
|
|
2399
|
-
if (!FORM_NAME_PATTERN2.test(form)) {
|
|
2400
|
-
return jsonResponse({ error: "invalid_form" }, 400);
|
|
2401
|
-
}
|
|
2402
|
-
if (!deps.knownForms.has(form)) {
|
|
2403
|
-
return jsonResponse({ error: "unknown_form" }, 404);
|
|
2404
|
-
}
|
|
2405
|
-
if (id !== null) {
|
|
2406
|
-
if (!ID_PATTERN.test(id)) {
|
|
2407
|
-
return jsonResponse({ error: "invalid_id" }, 400);
|
|
2408
|
-
}
|
|
2409
|
-
try {
|
|
2410
|
-
const sub = await deps.submissionAdapter.read(form, id);
|
|
2411
|
-
if (!sub) return jsonResponse({ error: "not_found" }, 404);
|
|
2412
|
-
return jsonResponse({ submission: sub }, 200);
|
|
2413
|
-
} catch (err) {
|
|
2414
|
-
if (err instanceof SubmissionsNotReadableError) {
|
|
2415
|
-
return jsonResponse(
|
|
2416
|
-
{ error: "not_supported", message: err.message },
|
|
2417
|
-
501
|
|
2418
|
-
);
|
|
2419
|
-
}
|
|
2420
|
-
console.error("[agntcms] read_failed:", err);
|
|
2421
|
-
return jsonResponse({ error: "read_failed", message: "internal error" }, 500);
|
|
2422
|
-
}
|
|
2423
|
-
}
|
|
2424
|
-
try {
|
|
2425
|
-
const summaries = await deps.submissionAdapter.list(form);
|
|
2426
|
-
return jsonResponse({ submissions: summaries }, 200);
|
|
2427
|
-
} catch (err) {
|
|
2428
|
-
if (err instanceof SubmissionsNotReadableError) {
|
|
2429
|
-
return jsonResponse(
|
|
2430
|
-
{ error: "not_supported", message: err.message },
|
|
2431
|
-
501
|
|
2432
|
-
);
|
|
2433
|
-
}
|
|
2434
|
-
console.error("[agntcms] list_failed:", err);
|
|
2435
|
-
return jsonResponse({ error: "list_failed", message: "internal error" }, 500);
|
|
2436
|
-
}
|
|
2437
|
-
};
|
|
2438
|
-
}
|
|
2439
|
-
|
|
2440
|
-
// src/handlers/forms/delete-handler.ts
|
|
2441
|
-
function createFormsDeleteHandler() {
|
|
2442
|
-
return async function handle(_req) {
|
|
2443
|
-
return jsonResponse(
|
|
2444
|
-
{
|
|
2445
|
-
ok: false,
|
|
2446
|
-
error: "not_implemented",
|
|
2447
|
-
message: "Submission delete is reserved but not implemented in v1. See ARCHITECTURE.md \xA76.5 / \xA712."
|
|
2448
|
-
},
|
|
2449
|
-
501
|
|
2450
|
-
);
|
|
2451
|
-
};
|
|
2452
|
-
}
|
|
2453
|
-
|
|
2454
2109
|
// src/handlers/dispatcher.ts
|
|
2455
2110
|
function buildRouteTable(h) {
|
|
2456
2111
|
const table = /* @__PURE__ */ new Map();
|
|
@@ -2480,10 +2135,6 @@ function buildRouteTable(h) {
|
|
|
2480
2135
|
table.set("preview/enter", { POST: async (req) => h.preview.enter(req), GET: async (req) => h.preview.enterWithToken(req) });
|
|
2481
2136
|
table.set("preview/exit", { POST: async (req) => h.preview.exit(req) });
|
|
2482
2137
|
table.set("preview/issue", { POST: h.preview.issueToken });
|
|
2483
|
-
table.set("template/list", { GET: h.template.list });
|
|
2484
|
-
table.set("forms/list", { GET: h.formsList });
|
|
2485
|
-
table.set("forms/read", { GET: h.formsRead });
|
|
2486
|
-
table.set("forms/delete", { POST: h.formsDelete });
|
|
2487
2138
|
return table;
|
|
2488
2139
|
}
|
|
2489
2140
|
function createagntcmsRouteHandler(opts) {
|
|
@@ -2497,19 +2148,15 @@ function createagntcmsRouteHandler(opts) {
|
|
|
2497
2148
|
// factory branches on `deps?.tokenStore` and `deps?.cookieName`).
|
|
2498
2149
|
preview: createPreviewHandler(opts.preview),
|
|
2499
2150
|
events: createEventsHandler(opts.events),
|
|
2500
|
-
mcp: createMcpHandler(opts.mcp)
|
|
2501
|
-
template: createTemplateHandler(opts.template),
|
|
2502
|
-
formsList: createFormsListHandler(opts.formsList),
|
|
2503
|
-
formsRead: createFormsReadHandler(opts.formsRead),
|
|
2504
|
-
formsDelete: createFormsDeleteHandler()
|
|
2151
|
+
mcp: createMcpHandler(opts.mcp)
|
|
2505
2152
|
};
|
|
2506
2153
|
const table = buildRouteTable(handlers);
|
|
2507
2154
|
const dispatch = async (method, req, ctx) => {
|
|
2508
|
-
const { path:
|
|
2509
|
-
if (!
|
|
2155
|
+
const { path: path5 } = await ctx.params;
|
|
2156
|
+
if (!path5 || path5.length === 0) {
|
|
2510
2157
|
return new Response(null, { status: 404 });
|
|
2511
2158
|
}
|
|
2512
|
-
const key =
|
|
2159
|
+
const key = path5.join("/");
|
|
2513
2160
|
const entry = table.get(key);
|
|
2514
2161
|
if (!entry) {
|
|
2515
2162
|
return new Response(null, { status: 404 });
|
|
@@ -2537,16 +2184,11 @@ export {
|
|
|
2537
2184
|
createAssetsHandler,
|
|
2538
2185
|
createDraftHandler,
|
|
2539
2186
|
createEventsHandler,
|
|
2540
|
-
createFormsDeleteHandler,
|
|
2541
|
-
createFormsListHandler,
|
|
2542
|
-
createFormsReadHandler,
|
|
2543
2187
|
createGlobalHandler,
|
|
2544
2188
|
createMcpHandler,
|
|
2545
2189
|
createPageHandler,
|
|
2546
2190
|
createPreviewHandler,
|
|
2547
2191
|
createPreviewTokenStore,
|
|
2548
|
-
createSubmitFormHandler,
|
|
2549
2192
|
createTaskStore,
|
|
2550
|
-
createTemplateHandler,
|
|
2551
2193
|
createagntcmsRouteHandler
|
|
2552
2194
|
};
|