@aotter/mantle 0.2.0-alpha.7 → 0.2.0-alpha.9
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/README.md +27 -5
- package/dist/auth/adapter.js +9 -6
- package/dist/auth/caller.js +2 -1
- package/dist/auth/identity.d.ts +2 -2
- package/dist/auth/oauth.d.ts +33 -1
- package/dist/auth/oauth.js +121 -28
- package/dist/auth/routes.js +6 -4
- package/dist/build/compiler.d.ts +44 -122
- package/dist/build/compiler.js +202 -277
- package/dist/build/spec/domain/model/ManifestGrammar.d.ts +6 -5
- package/dist/build/spec/domain/model/SqlIr.d.ts +2 -0
- package/dist/build/spec/domain/service/PlanFingerprint.d.ts +2 -0
- package/dist/build/spec/kernel/diagnostic.d.ts +1 -1
- package/dist/domain/describe/{chunk-ZIQVLA7X.js → chunk-ZVXBGP7Y.js} +69 -8
- package/dist/domain/describe/index.js +1 -1
- package/dist/domain/describe/target-hash.js +1 -1
- package/dist/domain/describe/targets.d.ts +1 -1
- package/dist/domain/generated-tools.js +2 -0
- package/dist/domain/paging.js +41 -15
- package/dist/infrastructure/bundle.js +118 -15
- package/dist/infrastructure/cli.js +11 -15
- package/dist/infrastructure/generate.d.ts +1 -3
- package/dist/infrastructure/generate.js +11 -3
- package/dist/infrastructure/generateAuth.js +57 -0
- package/dist/infrastructure/inputs.js +8 -3
- package/dist/infrastructure/wrangler.js +50 -12
- package/dist/kernel/binds.d.ts +0 -3
- package/dist/kernel/contracts.d.ts +1 -1
- package/dist/kernel/contracts.js +4 -4
- package/dist/kernel/dialect/common.d.ts +0 -1
- package/dist/kernel/drain.d.ts +5 -0
- package/dist/kernel/drain.js +35 -0
- package/dist/kernel/driver/postgres.js +6 -2
- package/dist/kernel/host-caller.d.ts +1 -0
- package/dist/kernel/host-caller.js +1 -0
- package/dist/kernel/mcp-apps.d.ts +29 -9
- package/dist/kernel/mcp-apps.js +3 -3
- package/dist/kernel/mcp-handler.js +101 -18
- package/dist/kernel/mcp.d.ts +12 -3
- package/dist/kernel/mcp.js +31 -6
- package/dist/kernel/rest-router.js +3 -2
- package/dist/kernel/scalars.js +3 -2
- package/dist/kernel/site.d.ts +1 -3
- package/dist/kernel/site.js +2 -2
- package/dist/kernel/web-index.js +40 -0
- package/dist/kernel/web.d.ts +3 -1
- package/dist/kernel/web.js +6 -37
- package/dist/usecase/adminBindings.js +2 -3
- package/dist/usecase/adminClient.js +87 -0
- package/dist/usecase/adminDescriptors.js +19 -65
- package/dist/usecase/generate.js +5 -4
- package/dist/usecase/mcp-media.js +2 -2
- package/dist/usecase/mcp.js +16 -12
- package/dist/usecase/paging.js +2 -3
- package/dist/usecase/publishing.js +3 -3
- package/dist/usecase/site.js +0 -1
- package/dist/usecase/tool-version.js +9 -0
- package/dist/usecase/translations.js +1 -1
- package/dist/usecase/validation.js +128 -19
- package/dist/usecase/web.js +3 -2
- package/docs/examples/README.md +1 -1
- package/docs/examples/app-shell/README.md +45 -3
- package/docs/examples/app-shell/package.json +14 -6
- package/docs/examples/app-shell/smoke-kit.mjs +54 -0
- package/docs/examples/app-shell/src/auth.ts +6 -3
- package/docs/examples/app-shell/src/service.ts +3 -3
- package/docs/examples/app-shell/tsconfig.json +4 -1
- package/docs/examples/app-shell/worker-configuration.d.ts +2 -2
- package/docs/examples/app-shell/wrangler.jsonc +5 -4
- package/docs/examples/club-events/manifests/club-events.yaml +7 -0
- package/docs/examples/club-events/src/handlers.ts +1 -1
- package/docs/examples/generated-web/README.md +6 -2
- package/docs/examples/generated-web/wrangler.jsonc +1 -0
- package/docs/examples/purchasing/README.md +1 -1
- package/docs/examples/purchasing/manifests/purchasing.yaml +17 -1
- package/docs/examples/purchasing/smoke.mjs +10 -4
- package/docs/examples/purchasing/src/admin.tsx +13 -0
- package/docs/examples/purchasing/src/handlers.ts +1 -1
- package/docs/examples/purchasing/wrangler.jsonc +5 -4
- package/docs/examples/recipes/wrangler.jsonc +5 -4
- package/docs/handbook/cloudflare/authentication.md +43 -6
- package/docs/handbook/cloudflare/chatgpt-sites.md +4 -2
- package/docs/handbook/cloudflare/deploy-and-operate.md +45 -1
- package/docs/handbook/cloudflare/media-r2.md +2 -3
- package/docs/handbook/cloudflare/service-entry.md +68 -31
- package/docs/handbook/concepts/authorization.md +1 -1
- package/docs/handbook/concepts/mcp-and-agents.md +19 -0
- package/docs/handbook/concepts/runtime-and-adapters.md +1 -1
- package/docs/handbook/examples/hub.md +1 -1
- package/docs/handbook/guides/admin-ui.md +107 -1
- package/docs/handbook/guides/agent-setup.md +27 -9
- package/docs/handbook/guides/agent-workflow-acceptance.md +222 -0
- package/docs/handbook/guides/mcp-apps.md +522 -6
- package/docs/handbook/guides/native-admin.md +300 -51
- package/docs/handbook/guides/oauth.md +119 -5
- package/docs/handbook/guides/public-pages.md +2 -2
- package/docs/handbook/guides/size-and-startup.md +1 -1
- package/docs/handbook/guides/typed-queries.md +35 -0
- package/docs/handbook/navigation.json +0 -4
- package/docs/handbook/reference/admin-descriptors.md +0 -35
- package/docs/handbook/reference/procedure.md +6 -2
- package/docs/handbook/reference/schema.md +13 -3
- package/docs/handbook/reference/surface.md +129 -15
- package/docs/handbook/reference/trigger.md +43 -1
- package/docs/handbook/reference/view.md +1 -1
- package/docs/handbook/releases/index.md +74 -2
- package/docs/handbook/start/overview.md +1 -1
- package/docs/handbook/start/project-and-cli.md +16 -8
- package/docs/handbook/start/quickstart-worker.md +1 -1
- package/docs/skills/develop/SKILL.md +46 -18
- package/docs/skills/integrate/SKILL.md +4 -9
- package/docs/skills/media-gc/SKILL.md +7 -5
- package/docs/skills/provision/SKILL.md +18 -12
- package/docs/skills/update/SKILL.md +19 -18
- package/docs/upgrade-0.1-to-0.2.md +6 -6
- package/package.json +2 -1
- package/skills/README.md +11 -16
- package/skills/mantle/SKILL.md +39 -17
- package/skills/mantle/references/local-testing.md +9 -0
- package/skills/mantle/references/web.md +1 -1
- package/skills/mantle/references/website.md +26 -22
- package/docs/examples/app-shell/src/admin.ts +0 -10
- package/docs/examples/purchasing/src/admin.ts +0 -12
- package/docs/handbook/guides/admin-extensions.md +0 -20
- package/docs/skills/develop/mcp-app.md +0 -39
- package/skills/.keep +0 -0
package/dist/build/compiler.js
CHANGED
|
@@ -115,6 +115,7 @@ function canonical(v) {
|
|
|
115
115
|
return `{${Object.keys(v).sort().filter((k) => v[k] !== void 0).map((k) => `${JSON.stringify(k)}:${canonical(v[k])}`).join(",")}}`;
|
|
116
116
|
return JSON.stringify(v) ?? "null";
|
|
117
117
|
}
|
|
118
|
+
var fnv = (s) => [...s].reduce((h, c) => Math.imul(h ^ c.codePointAt(0), 16777619) >>> 0, 2166136261).toString(16).padStart(8, "0");
|
|
118
119
|
async function planFingerprint(plan) {
|
|
119
120
|
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(canonical(plan)));
|
|
120
121
|
return [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
@@ -122,8 +123,6 @@ async function planFingerprint(plan) {
|
|
|
122
123
|
|
|
123
124
|
// src/build/spec/domain/model/ManifestGrammar.ts
|
|
124
125
|
var API_VERSION = "cms.mantle.aotter.net/v2";
|
|
125
|
-
var UI_EXTENSION_REF = /^([a-z][a-z0-9-]{0,62})\/([a-z][a-z0-9-]{0,62})$/;
|
|
126
|
-
var isUiExtensionRef = (value2) => typeof value2 === "string" && UI_EXTENSION_REF.test(value2);
|
|
127
126
|
function isMediaMcpHint(value2) {
|
|
128
127
|
return value2 === "media" || value2 === "media-image" || value2 === "media-video" || value2 === "media-file";
|
|
129
128
|
}
|
|
@@ -180,6 +179,7 @@ var RESERVED_ENTRY_COLUMNS = [
|
|
|
180
179
|
"authorId"
|
|
181
180
|
];
|
|
182
181
|
var EXPECTED_VERSION_PROPERTY = "expectedVersion";
|
|
182
|
+
var INPUT_RULE_KEYWORDS = ["dependentRequired", "anyOf", "if", "then", "else"];
|
|
183
183
|
var RESERVED_PROCEDURE_INPUT_NAMES = [EXPECTED_VERSION_PROPERTY];
|
|
184
184
|
|
|
185
185
|
// src/build/spec/domain/service/SqlRefusal.ts
|
|
@@ -280,6 +280,7 @@ function storageColumns(s) {
|
|
|
280
280
|
return cols;
|
|
281
281
|
}
|
|
282
282
|
var NATIVE_NOT_NULL = /* @__PURE__ */ new Set(["id", "version", "created_at", "updated_at", "status"]);
|
|
283
|
+
var NATIVE_COLUMNS = { id: "id", status: "status", version: "version", createdAt: "created_at", updatedAt: "updated_at", authorId: "author_id" };
|
|
283
284
|
function notNullColumns(s) {
|
|
284
285
|
const out = /* @__PURE__ */ new Set();
|
|
285
286
|
for (const u of s.userScopes ?? []) out.add(u.column);
|
|
@@ -490,8 +491,8 @@ function collectSourceSpans(root, lineCounter) {
|
|
|
490
491
|
}
|
|
491
492
|
function sourceLocationForNode(sourceId, documentIndex, path, doc, lineCounter) {
|
|
492
493
|
const parts = path === "/" ? [] : path.slice(1).split("/").map((part) => {
|
|
493
|
-
const
|
|
494
|
-
return /^\d+$/.test(
|
|
494
|
+
const decoded2 = part.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
495
|
+
return /^\d+$/.test(decoded2) ? Number(decoded2) : decoded2;
|
|
495
496
|
});
|
|
496
497
|
let range;
|
|
497
498
|
for (let length = parts.length; length >= 0 && !range; length--) {
|
|
@@ -520,34 +521,23 @@ function sourceSpan(lineCounter, range) {
|
|
|
520
521
|
}
|
|
521
522
|
|
|
522
523
|
// src/build/spec/domain/model/AdminNav.ts
|
|
523
|
-
var BUILT_IN_NAV_GROUPS =
|
|
524
|
-
var NAV_PLACEMENT_KEYS = ["group", "order", "hidden"];
|
|
524
|
+
var BUILT_IN_NAV_GROUPS = /* @__PURE__ */ new Set(["content", "operations", "reports", "more"]);
|
|
525
525
|
var ID = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
526
|
+
var PLACEMENT = {
|
|
527
|
+
group: [(v) => typeof v === "string" && ID.test(v), "a kebab-case group id"],
|
|
528
|
+
order: [Number.isInteger, "an integer"],
|
|
529
|
+
hidden: [(v) => typeof v === "boolean", "a boolean"]
|
|
530
|
+
};
|
|
531
|
+
function navPlacementProblems(nav, own = []) {
|
|
532
|
+
const keys = [...own, ...Object.keys(PLACEMENT)];
|
|
533
|
+
for (const [key, value2] of Object.entries(nav)) {
|
|
534
|
+
if (own.includes(key)) continue;
|
|
535
|
+
const rule = Object.hasOwn(PLACEMENT, key) ? PLACEMENT[key] : null;
|
|
536
|
+
if (!rule) return [key, `${keys.slice(0, -1).join(", ")} or ${keys.at(-1)}`];
|
|
537
|
+
if (!rule[0](value2)) return [key, rule[1]];
|
|
538
|
+
}
|
|
530
539
|
return null;
|
|
531
540
|
}
|
|
532
|
-
var isText = (v) => typeof v === "string" && v.length > 0 || !!v && typeof v === "object" && !Array.isArray(v) && Object.keys(v).length > 0 && Object.values(v).every((x) => typeof x === "string" && x.length > 0);
|
|
533
|
-
function navGroupProblems(groups) {
|
|
534
|
-
if (groups === void 0) return [];
|
|
535
|
-
if (!Array.isArray(groups)) return [["admin/navGroups", "navGroups must be an array."]];
|
|
536
|
-
const seen = /* @__PURE__ */ new Set(), problems = [];
|
|
537
|
-
groups.forEach((g, i) => {
|
|
538
|
-
const path = `admin/navGroups/${i}`;
|
|
539
|
-
if (!g || typeof g !== "object" || Array.isArray(g)) return problems.push([path, "A nav group is an object { id, title, order? }."]);
|
|
540
|
-
const { id, title, order, ...extra } = g;
|
|
541
|
-
if (Object.keys(extra).length) problems.push([`${path}/${Object.keys(extra)[0]}`, "A nav group has only id, title and order."]);
|
|
542
|
-
if (typeof id !== "string" || !ID.test(id)) problems.push([`${path}/id`, "A nav group id is kebab-case."]);
|
|
543
|
-
else if (Object.hasOwn(BUILT_IN_NAV_GROUPS, id) || id === "settings") problems.push([`${path}/id`, `'${id}' is a built-in group; place items in it without declaring it.`]);
|
|
544
|
-
else if (seen.has(id)) problems.push([`${path}/id`, `Duplicate nav group id '${id}'.`]);
|
|
545
|
-
else seen.add(id);
|
|
546
|
-
if (!isText(title)) problems.push([`${path}/title`, "A nav group title is text or a { locale: text } map."]);
|
|
547
|
-
if (order !== void 0 && !Number.isInteger(order)) problems.push([`${path}/order`, "A nav group order is an integer."]);
|
|
548
|
-
});
|
|
549
|
-
return problems;
|
|
550
|
-
}
|
|
551
541
|
|
|
552
542
|
// src/build/spec/domain/service/SchemaIndexChecker.ts
|
|
553
543
|
var SAFE_INDEX_NAME = /^[A-Za-z][A-Za-z0-9_.-]*$/;
|
|
@@ -820,10 +810,8 @@ function checkViewAdminUi(view) {
|
|
|
820
810
|
const nav = uiSchema["nav"];
|
|
821
811
|
if (nav !== void 0) {
|
|
822
812
|
if (!nav || typeof nav !== "object" || Array.isArray(nav)) return { list: EMPTY_VIEW_LIST, problems: [problem("/spec/uiSchema/nav", nav, "an object", "View.spec.uiSchema.nav must be an object.")] };
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
if (expected) return { list: EMPTY_VIEW_LIST, problems: [problem(`/spec/uiSchema/nav/${key}`, value2, expected, `View.spec.uiSchema.nav.${key} must be ${expected}.`)] };
|
|
826
|
-
}
|
|
813
|
+
const bad = navPlacementProblems(nav);
|
|
814
|
+
if (bad) return { list: EMPTY_VIEW_LIST, problems: [problem(`/spec/uiSchema/nav/${bad[0]}`, nav[bad[0]], bad[1], `View.spec.uiSchema.nav.${bad[0]} must be ${bad[1]}.`)] };
|
|
827
815
|
}
|
|
828
816
|
const list = uiSchema["list"];
|
|
829
817
|
if (list === void 0) return { list: EMPTY_VIEW_LIST, problems: [] };
|
|
@@ -836,13 +824,13 @@ function checkViewAdminUi(view) {
|
|
|
836
824
|
)] };
|
|
837
825
|
}
|
|
838
826
|
const config = list;
|
|
839
|
-
const allowed = /* @__PURE__ */ new Set(["columns", "searchFields", "filterFields"
|
|
827
|
+
const allowed = /* @__PURE__ */ new Set(["columns", "searchFields", "filterFields"]);
|
|
840
828
|
const unknown = Object.keys(config).find((key) => !allowed.has(key));
|
|
841
829
|
if (unknown) {
|
|
842
830
|
return { list: EMPTY_VIEW_LIST, problems: [problem(
|
|
843
831
|
`/spec/uiSchema/list/${unknown}`,
|
|
844
832
|
config[unknown],
|
|
845
|
-
"columns, searchFields,
|
|
833
|
+
"columns, searchFields, or filterFields",
|
|
846
834
|
`View.spec.uiSchema.list.${unknown} is not supported.`
|
|
847
835
|
)] };
|
|
848
836
|
}
|
|
@@ -874,16 +862,13 @@ function checkViewAdminUi(view) {
|
|
|
874
862
|
}
|
|
875
863
|
normalized[key] = raw;
|
|
876
864
|
}
|
|
877
|
-
const cellProblem = checkCells(config["cells"], (field) => field.length > 0, "View", "a View output name");
|
|
878
|
-
if (cellProblem) return { list: EMPTY_VIEW_LIST, problems: [cellProblem] };
|
|
879
865
|
return { list: normalized, problems: [] };
|
|
880
866
|
}
|
|
881
867
|
|
|
882
868
|
// src/build/spec/domain/service/SchemaAdminUiChecker.ts
|
|
883
869
|
var EMPTY_LIST = { primaryField: null, columns: [] };
|
|
884
|
-
var SCHEMA_UI_ROOTS = /* @__PURE__ */ new Set(["fields", "list", "nav"
|
|
885
|
-
var SCHEMA_LIST_KEYS = /* @__PURE__ */ new Set(["filterField", "primaryField", "columns"
|
|
886
|
-
var SCHEMA_NAV_KEYS = /* @__PURE__ */ new Set(["standalone", "parentField", ...NAV_PLACEMENT_KEYS]);
|
|
870
|
+
var SCHEMA_UI_ROOTS = /* @__PURE__ */ new Set(["fields", "list", "nav"]);
|
|
871
|
+
var SCHEMA_LIST_KEYS = /* @__PURE__ */ new Set(["filterField", "primaryField", "columns"]);
|
|
887
872
|
var SCALAR_TYPES = /* @__PURE__ */ new Set(["string", "number", "integer", "boolean"]);
|
|
888
873
|
function checkSchemaAdminUi(schema) {
|
|
889
874
|
const formProblem = checkFormUiSchema(schema.spec.schema, schema.spec.uiSchema, "Schema")[0];
|
|
@@ -896,7 +881,7 @@ function checkSchemaAdminUi(schema) {
|
|
|
896
881
|
return invalid(problem2(
|
|
897
882
|
`/spec/uiSchema/${unknownRoot}`,
|
|
898
883
|
roots[unknownRoot],
|
|
899
|
-
"fields, list,
|
|
884
|
+
"fields, list, or nav",
|
|
900
885
|
`Schema.spec.uiSchema.${unknownRoot} is not supported.`
|
|
901
886
|
));
|
|
902
887
|
}
|
|
@@ -916,7 +901,7 @@ function checkSchemaAdminUi(schema) {
|
|
|
916
901
|
return invalid(problem2(
|
|
917
902
|
`/spec/uiSchema/list/${unknownList}`,
|
|
918
903
|
config[unknownList],
|
|
919
|
-
"filterField, primaryField,
|
|
904
|
+
"filterField, primaryField, or columns",
|
|
920
905
|
`Schema.spec.uiSchema.list.${unknownList} is not supported.`
|
|
921
906
|
));
|
|
922
907
|
}
|
|
@@ -981,10 +966,6 @@ function checkSchemaAdminUi(schema) {
|
|
|
981
966
|
));
|
|
982
967
|
}
|
|
983
968
|
}
|
|
984
|
-
const cellProblem = checkCells(config["cells"], (field) => NATIVE_LIST_FIELDS.has(field) || !!schema.spec.schema.properties?.[field], "Schema", "a top-level key in spec.schema.properties or a native entry column");
|
|
985
|
-
if (cellProblem) return invalid(cellProblem);
|
|
986
|
-
const panelProblem = checkPanels(roots["panels"]);
|
|
987
|
-
if (panelProblem) return invalid(panelProblem);
|
|
988
969
|
const navResult = checkNav(schema, roots["nav"]);
|
|
989
970
|
if (navResult.problem) return invalid(navResult.problem);
|
|
990
971
|
return {
|
|
@@ -1062,41 +1043,21 @@ function checkFormUiSchema(schema, uiSchema, owner) {
|
|
|
1062
1043
|
)];
|
|
1063
1044
|
}
|
|
1064
1045
|
const config2 = rawConfig;
|
|
1065
|
-
const unknownKey = Object.keys(config2).find((key) => key !== "widget"
|
|
1046
|
+
const unknownKey = Object.keys(config2).find((key) => key !== "widget");
|
|
1066
1047
|
if (unknownKey) {
|
|
1067
1048
|
return [problem2(
|
|
1068
1049
|
`/spec/uiSchema/fields/${field}/${unknownKey}`,
|
|
1069
1050
|
config2[unknownKey],
|
|
1070
|
-
"widget
|
|
1051
|
+
"widget",
|
|
1071
1052
|
`${owner}.spec.uiSchema.fields.${field}.${unknownKey} is not supported.`
|
|
1072
1053
|
)];
|
|
1073
1054
|
}
|
|
1074
|
-
if (isUiExtensionRef(config2["widget"])) {
|
|
1075
|
-
const options = config2["options"];
|
|
1076
|
-
if (options !== void 0 && (!options || typeof options !== "object" || Array.isArray(options))) {
|
|
1077
|
-
return [problem2(
|
|
1078
|
-
`/spec/uiSchema/fields/${field}/options`,
|
|
1079
|
-
options,
|
|
1080
|
-
"an object",
|
|
1081
|
-
`${owner}.spec.uiSchema.fields.${field}.options must be an object.`
|
|
1082
|
-
)];
|
|
1083
|
-
}
|
|
1084
|
-
continue;
|
|
1085
|
-
}
|
|
1086
1055
|
if (config2["widget"] !== "textarea") {
|
|
1087
1056
|
return [problem2(
|
|
1088
1057
|
`/spec/uiSchema/fields/${field}/widget`,
|
|
1089
1058
|
config2["widget"],
|
|
1090
|
-
'"textarea"
|
|
1091
|
-
`${owner}.spec.uiSchema.fields.${field}.widget must be 'textarea'
|
|
1092
|
-
)];
|
|
1093
|
-
}
|
|
1094
|
-
if (config2["options"] !== void 0) {
|
|
1095
|
-
return [problem2(
|
|
1096
|
-
`/spec/uiSchema/fields/${field}/options`,
|
|
1097
|
-
config2["options"],
|
|
1098
|
-
"options only with an extension widget",
|
|
1099
|
-
`${owner}.spec.uiSchema.fields.${field}.options needs an extension widget.`
|
|
1059
|
+
'"textarea"',
|
|
1060
|
+
`${owner}.spec.uiSchema.fields.${field}.widget must be 'textarea'.`
|
|
1100
1061
|
)];
|
|
1101
1062
|
}
|
|
1102
1063
|
if (!isString(property)) {
|
|
@@ -1172,22 +1133,8 @@ function checkNav(schema, nav) {
|
|
|
1172
1133
|
};
|
|
1173
1134
|
}
|
|
1174
1135
|
const config = nav;
|
|
1175
|
-
const
|
|
1176
|
-
if (
|
|
1177
|
-
return {
|
|
1178
|
-
nav: null,
|
|
1179
|
-
problem: problem2(
|
|
1180
|
-
`/spec/uiSchema/nav/${unknown}`,
|
|
1181
|
-
config[unknown],
|
|
1182
|
-
"standalone, parentField, group, order or hidden",
|
|
1183
|
-
`Schema.spec.uiSchema.nav.${unknown} is not supported.`
|
|
1184
|
-
)
|
|
1185
|
-
};
|
|
1186
|
-
}
|
|
1187
|
-
for (const key of NAV_PLACEMENT_KEYS) {
|
|
1188
|
-
const expected = config[key] === void 0 ? null : navPlacementProblem(key, config[key]);
|
|
1189
|
-
if (expected) return { nav: null, problem: problem2(`/spec/uiSchema/nav/${key}`, config[key], expected, `Schema.spec.uiSchema.nav.${key} must be ${expected}.`) };
|
|
1190
|
-
}
|
|
1136
|
+
const bad = navPlacementProblems(config, ["standalone", "parentField"]);
|
|
1137
|
+
if (bad) return { nav: null, problem: problem2(`/spec/uiSchema/nav/${bad[0]}`, config[bad[0]], bad[1], `Schema.spec.uiSchema.nav.${bad[0]} must be ${bad[1]}.`) };
|
|
1191
1138
|
const standalone = config["standalone"];
|
|
1192
1139
|
if (standalone !== void 0 && typeof standalone !== "boolean") {
|
|
1193
1140
|
return {
|
|
@@ -1213,13 +1160,15 @@ function checkNav(schema, nav) {
|
|
|
1213
1160
|
};
|
|
1214
1161
|
}
|
|
1215
1162
|
if (parentField !== void 0 && standalone !== true) {
|
|
1216
|
-
|
|
1163
|
+
const required = new Set(schema.spec.schema.required ?? []);
|
|
1164
|
+
const ok = !schema.spec.translates && required.has(parentField) && resolveMantleRef(schema.spec.schema.properties?.[parentField]) !== null;
|
|
1165
|
+
return ok ? { nav: null } : {
|
|
1217
1166
|
nav: null,
|
|
1218
1167
|
problem: problem2(
|
|
1219
1168
|
"/spec/uiSchema/nav/parentField",
|
|
1220
1169
|
parentField,
|
|
1221
|
-
"
|
|
1222
|
-
|
|
1170
|
+
"a required x-mantle-ref field of a Schema that is not a translates child",
|
|
1171
|
+
schema.spec.translates ? `Schema '${schema.metadata.name}' cannot declare nav.parentField because it is a translates child.` : `Schema '${schema.metadata.name}' nav.parentField must name a required x-mantle-ref field.`
|
|
1223
1172
|
)
|
|
1224
1173
|
};
|
|
1225
1174
|
}
|
|
@@ -1235,7 +1184,7 @@ function checkNav(schema, nav) {
|
|
|
1235
1184
|
)
|
|
1236
1185
|
};
|
|
1237
1186
|
}
|
|
1238
|
-
const eligible = requiredMantleRefFields(schema);
|
|
1187
|
+
const eligible = requiredMantleRefFields(schema.spec.schema);
|
|
1239
1188
|
if (eligible.length === 0) {
|
|
1240
1189
|
return {
|
|
1241
1190
|
nav: null,
|
|
@@ -1264,17 +1213,7 @@ function checkNav(schema, nav) {
|
|
|
1264
1213
|
nav: { standalone: true, parentField: only.field, parentCollection: only.collection }
|
|
1265
1214
|
};
|
|
1266
1215
|
}
|
|
1267
|
-
if (typeof parentField !== "string") {
|
|
1268
|
-
return {
|
|
1269
|
-
nav: null,
|
|
1270
|
-
problem: problem2(
|
|
1271
|
-
"/spec/uiSchema/nav/parentField",
|
|
1272
|
-
parentField,
|
|
1273
|
-
`one of ${eligible.map((item) => item.field).join(", ")}`,
|
|
1274
|
-
`Schema '${schema.metadata.name}' declares more than one required x-mantle-ref; nav.parentField is required.`
|
|
1275
|
-
)
|
|
1276
|
-
};
|
|
1277
|
-
}
|
|
1216
|
+
if (typeof parentField !== "string") return { nav: null };
|
|
1278
1217
|
const matched = eligible.find((item) => item.field === parentField);
|
|
1279
1218
|
if (!matched) {
|
|
1280
1219
|
return {
|
|
@@ -1291,9 +1230,9 @@ function checkNav(schema, nav) {
|
|
|
1291
1230
|
nav: { standalone: true, parentField: matched.field, parentCollection: matched.collection }
|
|
1292
1231
|
};
|
|
1293
1232
|
}
|
|
1294
|
-
function requiredMantleRefFields(
|
|
1295
|
-
const required = new Set(
|
|
1296
|
-
const properties =
|
|
1233
|
+
function requiredMantleRefFields(body) {
|
|
1234
|
+
const required = new Set(body.required ?? []);
|
|
1235
|
+
const properties = body.properties ?? {};
|
|
1297
1236
|
const fields = [];
|
|
1298
1237
|
for (const [field, property] of Object.entries(properties)) {
|
|
1299
1238
|
if (!required.has(field)) continue;
|
|
@@ -1304,18 +1243,62 @@ function requiredMantleRefFields(schema) {
|
|
|
1304
1243
|
}
|
|
1305
1244
|
function checkSchemaNavTargets(schema, schemasByName) {
|
|
1306
1245
|
const { nav, problems } = checkSchemaAdminUi(schema);
|
|
1307
|
-
if (problems.length > 0 ||
|
|
1308
|
-
const
|
|
1309
|
-
|
|
1310
|
-
|
|
1246
|
+
if (problems.length > 0 || schema.spec.translates) return null;
|
|
1247
|
+
const declared = declaredParentField(schema);
|
|
1248
|
+
const target2 = nav?.parentCollection ?? (declared === void 0 ? void 0 : resolveMantleRef(schema.spec.schema.properties?.[declared])?.schema);
|
|
1249
|
+
if (target2 !== void 0 && !isFoldParent(schemasByName.get(target2))) {
|
|
1311
1250
|
return problem2(
|
|
1312
|
-
|
|
1313
|
-
|
|
1251
|
+
declared === void 0 ? "/spec/uiSchema/nav/standalone" : "/spec/uiSchema/nav/parentField",
|
|
1252
|
+
target2,
|
|
1314
1253
|
"the metadata.name of an existing non-translates Schema",
|
|
1315
|
-
`Schema '${schema.metadata.name}' nav parent collection '${
|
|
1254
|
+
`Schema '${schema.metadata.name}' nav parent collection '${target2}' is not an eligible fold parent.`
|
|
1316
1255
|
);
|
|
1317
1256
|
}
|
|
1318
|
-
|
|
1257
|
+
if (declared === void 0) {
|
|
1258
|
+
const eligible = eligibleIdRefs(schema, schemasByName);
|
|
1259
|
+
if (eligible.length < 2) return null;
|
|
1260
|
+
const names = eligible.join(", ");
|
|
1261
|
+
const keep = eligible.find((field) => !closesParentCycle(schema, field, schemasByName));
|
|
1262
|
+
return problem2(
|
|
1263
|
+
"/spec/uiSchema/nav/parentField",
|
|
1264
|
+
void 0,
|
|
1265
|
+
`one of ${names}`,
|
|
1266
|
+
`Schema '${schema.metadata.name}' has more than one required id x-mantle-ref (${names}); set uiSchema.nav.parentField to choose its parent.${keep === void 0 ? "" : ` To keep the current choice, add nav: { parentField: ${keep} }.`}`
|
|
1267
|
+
);
|
|
1268
|
+
}
|
|
1269
|
+
return closesParentCycle(schema, declared, schemasByName) ? problem2(
|
|
1270
|
+
"/spec/uiSchema/nav/parentField",
|
|
1271
|
+
declared,
|
|
1272
|
+
"a reference whose parent chain does not lead back to this Schema",
|
|
1273
|
+
`Schema '${schema.metadata.name}' nav.parentField '${declared}' creates a parent cycle.`
|
|
1274
|
+
) : null;
|
|
1275
|
+
}
|
|
1276
|
+
function closesParentCycle(schema, field, schemasByName) {
|
|
1277
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1278
|
+
for (let at = resolveMantleRef(schema.spec.schema.properties?.[field])?.schema; at !== void 0 && !seen.has(at); at = foldParentOf(schemasByName.get(at), schemasByName)) {
|
|
1279
|
+
if (at === schema.metadata.name) return true;
|
|
1280
|
+
seen.add(at);
|
|
1281
|
+
}
|
|
1282
|
+
return false;
|
|
1283
|
+
}
|
|
1284
|
+
function declaredParentField(schema) {
|
|
1285
|
+
const nav = schema.spec.uiSchema?.["nav"];
|
|
1286
|
+
return typeof nav?.["parentField"] === "string" ? nav["parentField"] : void 0;
|
|
1287
|
+
}
|
|
1288
|
+
var isFoldParent = (s) => !!s && !s.spec.translates;
|
|
1289
|
+
function eligibleIdRefs(schema, schemasByName) {
|
|
1290
|
+
return requiredMantleRefFields(schema.spec.schema).filter((r) => isFoldParent(schemasByName.get(r.collection))).map((r) => r.field);
|
|
1291
|
+
}
|
|
1292
|
+
function foldParentOf(schema, schemasByName) {
|
|
1293
|
+
if (!schema || schema.spec.translates) return void 0;
|
|
1294
|
+
const field = foldParentField(schema.spec.schema, declaredParentField(schema), (name4) => isFoldParent(schemasByName.get(name4)));
|
|
1295
|
+
return field === void 0 ? void 0 : resolveMantleRef(schema.spec.schema.properties?.[field])?.schema;
|
|
1296
|
+
}
|
|
1297
|
+
function foldParentField(body, declared, isParent) {
|
|
1298
|
+
const props = body.properties ?? {};
|
|
1299
|
+
const required = new Set(body.required ?? []);
|
|
1300
|
+
const refs = Object.keys(props).filter((f) => required.has(f) && isParent(resolveMantleRef(props[f])?.schema ?? ""));
|
|
1301
|
+
return declared ?? requiredMantleRefFields(body).find((r) => isParent(r.collection))?.field ?? refs[0];
|
|
1319
1302
|
}
|
|
1320
1303
|
var NATIVE_LIST_FIELDS = new Set(RESERVED_ENTRY_COLUMNS);
|
|
1321
1304
|
function isScalar3(schema) {
|
|
@@ -1326,24 +1309,6 @@ function isString(schema) {
|
|
|
1326
1309
|
const types = Array.isArray(schema.type) ? schema.type : schema.type ? [schema.type] : [];
|
|
1327
1310
|
return types.includes("string") && types.every((type) => type === "string" || type === "null");
|
|
1328
1311
|
}
|
|
1329
|
-
function checkCells(cells, known, owner, expected) {
|
|
1330
|
-
if (cells === void 0) return null;
|
|
1331
|
-
if (!cells || typeof cells !== "object" || Array.isArray(cells)) {
|
|
1332
|
-
return problem2("/spec/uiSchema/list/cells", cells, "an object of field -> <extension>/<contribution>", `${owner}.spec.uiSchema.list.cells must be an object.`);
|
|
1333
|
-
}
|
|
1334
|
-
for (const [field, ref2] of Object.entries(cells)) {
|
|
1335
|
-
if (!known(field)) return problem2(`/spec/uiSchema/list/cells/${field}`, field, expected, `${owner}.spec.uiSchema.list.cells references unknown field '${field}'.`);
|
|
1336
|
-
if (!isUiExtensionRef(ref2)) return problem2(`/spec/uiSchema/list/cells/${field}`, ref2, "<extension>/<contribution>", `${owner}.spec.uiSchema.list.cells.${field} must name an Admin extension contribution.`);
|
|
1337
|
-
}
|
|
1338
|
-
return null;
|
|
1339
|
-
}
|
|
1340
|
-
function checkPanels(panels) {
|
|
1341
|
-
if (panels === void 0) return null;
|
|
1342
|
-
if (!Array.isArray(panels) || panels.length > 16 || !panels.every(isUiExtensionRef) || new Set(panels).size !== panels.length) {
|
|
1343
|
-
return problem2("/spec/uiSchema/panels", panels, "up to 16 distinct <extension>/<contribution> names", "Schema.spec.uiSchema.panels must list Admin extension contributions.");
|
|
1344
|
-
}
|
|
1345
|
-
return null;
|
|
1346
|
-
}
|
|
1347
1312
|
function problem2(pointer2, value2, expected, message2) {
|
|
1348
1313
|
return { pointer: pointer2, value: value2, expected, message: message2 };
|
|
1349
1314
|
}
|
|
@@ -1684,12 +1649,8 @@ function validateSchemaSpec(m, idx) {
|
|
|
1684
1649
|
return m;
|
|
1685
1650
|
}
|
|
1686
1651
|
var UNSUPPORTED_JSON_SCHEMA_KEYWORDS = /* @__PURE__ */ new Set([
|
|
1687
|
-
"anyOf",
|
|
1688
1652
|
"allOf",
|
|
1689
1653
|
"not",
|
|
1690
|
-
"if",
|
|
1691
|
-
"then",
|
|
1692
|
-
"else",
|
|
1693
1654
|
"$anchor",
|
|
1694
1655
|
"$dynamicAnchor",
|
|
1695
1656
|
"$dynamicRef",
|
|
@@ -1731,6 +1692,16 @@ function validateJsonSchema(root, idx, kind, name4, basePointer) {
|
|
|
1731
1692
|
);
|
|
1732
1693
|
}
|
|
1733
1694
|
}
|
|
1695
|
+
if (basePointer !== "/spec/input") for (const keyword of INPUT_RULE_KEYWORDS) {
|
|
1696
|
+
if (keyword in value2) {
|
|
1697
|
+
throw new ManifestParseError(
|
|
1698
|
+
`${kind} '${name4}' uses JSON Schema keyword '${keyword}', which is supported only in View and Procedure input`,
|
|
1699
|
+
idx,
|
|
1700
|
+
`${pointer2}/${escapeJsonPointerSegment(keyword)}`,
|
|
1701
|
+
"JSON_SCHEMA_UNSUPPORTED"
|
|
1702
|
+
);
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1734
1705
|
if ("$ref" in value2) refs.push([`${pointer2}/$ref`, value2["$ref"], validateLocalSchemaRef(value2["$ref"], rootObject, idx, kind, name4, `${pointer2}/$ref`)]);
|
|
1735
1706
|
if (value2["enum"] !== void 0 && (!Array.isArray(value2["enum"]) || value2["enum"].length > MAX_JSON_SCHEMA_ENUM)) {
|
|
1736
1707
|
throw new ManifestParseError(
|
|
@@ -2026,23 +1997,23 @@ function validateViewCache(raw, view, idx) {
|
|
|
2026
1997
|
}
|
|
2027
1998
|
}
|
|
2028
1999
|
function validateViewInput(raw, idx) {
|
|
2029
|
-
const
|
|
2000
|
+
const invalid2 = (message2, pointer2, code = "VIEW_INPUT_INVALID_SHAPE") => {
|
|
2030
2001
|
throw new ManifestParseError(message2, idx, pointer2, code);
|
|
2031
2002
|
};
|
|
2032
2003
|
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
2033
|
-
|
|
2004
|
+
invalid2("View.spec.input must be a JSON Schema object", "/spec/input");
|
|
2034
2005
|
}
|
|
2035
2006
|
const p = raw;
|
|
2036
2007
|
if (p["type"] !== "object") {
|
|
2037
|
-
|
|
2008
|
+
invalid2(`View.spec.input.type must be "object"; got ${JSON.stringify(p["type"])}`, "/spec/input/type");
|
|
2038
2009
|
}
|
|
2039
2010
|
const props = p["properties"];
|
|
2040
2011
|
if (typeof props !== "object" || props === null || Array.isArray(props)) {
|
|
2041
|
-
|
|
2012
|
+
invalid2("View.spec.input.properties is required (declare each accepted parameter)", "/spec/input/properties");
|
|
2042
2013
|
}
|
|
2043
2014
|
for (const reserved2 of VIEW_INPUT_RESERVED) {
|
|
2044
2015
|
if (Object.hasOwn(props, reserved2)) {
|
|
2045
|
-
|
|
2016
|
+
invalid2(
|
|
2046
2017
|
`View.spec.input.properties.${reserved2} is reserved (the runtime owns ${VIEW_INPUT_RESERVED.join(", ")} for pagination); rename it.`,
|
|
2047
2018
|
`/spec/input/properties/${reserved2}`,
|
|
2048
2019
|
"VIEW_INPUT_RESERVED_NAME"
|
|
@@ -2829,10 +2800,41 @@ function jsonValueWithinLimits() {
|
|
|
2829
2800
|
});
|
|
2830
2801
|
}
|
|
2831
2802
|
|
|
2803
|
+
// src/build/spec/domain/service/RootRefChain.ts
|
|
2804
|
+
function lookupLocalRef(root, ref2) {
|
|
2805
|
+
if (typeof ref2 !== "string" || !ref2.startsWith("#/")) return void 0;
|
|
2806
|
+
let value2 = root;
|
|
2807
|
+
try {
|
|
2808
|
+
for (const key of decodeURIComponent(ref2.slice(2)).split("/").map((key2) => key2.replace(/~1/g, "/").replace(/~0/g, "~"))) value2 = value2 && typeof value2 === "object" && Object.hasOwn(value2, key) ? value2[key] : void 0;
|
|
2809
|
+
} catch {
|
|
2810
|
+
return void 0;
|
|
2811
|
+
}
|
|
2812
|
+
return value2 && typeof value2 === "object" ? value2 : void 0;
|
|
2813
|
+
}
|
|
2814
|
+
function rootRefChain(input) {
|
|
2815
|
+
const chain = [];
|
|
2816
|
+
for (let schema = input; schema !== void 0; schema = lookupLocalRef(input, schema.$ref)) {
|
|
2817
|
+
if (chain.includes(schema)) return void 0;
|
|
2818
|
+
chain.push(schema);
|
|
2819
|
+
if (schema.$ref === void 0) return chain;
|
|
2820
|
+
}
|
|
2821
|
+
return void 0;
|
|
2822
|
+
}
|
|
2823
|
+
|
|
2832
2824
|
// src/build/spec/domain/service/McpToolNaming.ts
|
|
2833
2825
|
function mcpToolNameSegment(name4) {
|
|
2834
2826
|
return name4.toLowerCase().replace(/-/g, "_");
|
|
2835
2827
|
}
|
|
2828
|
+
function toolTitle(name4) {
|
|
2829
|
+
const words = name4.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[-_.\s]+/g, " ").trim().toLowerCase();
|
|
2830
|
+
return words.charAt(0).toUpperCase() + words.slice(1);
|
|
2831
|
+
}
|
|
2832
|
+
var viewAnnotations = { readOnlyHint: true, destructiveHint: false };
|
|
2833
|
+
function procedureAnnotations(p) {
|
|
2834
|
+
const readOnlyHint = p.mcp?.readOnlyHint ?? false;
|
|
2835
|
+
return { readOnlyHint, destructiveHint: !readOnlyHint && ("ref" in p.handler || overwrites(p.handler.sql.stmts)), ...p.mcp };
|
|
2836
|
+
}
|
|
2837
|
+
var overwrites = (node) => !!node && typeof node === "object" && ("DeleteStmt" in node || "UpdateStmt" in node || node.onConflictClause?.action === "ONCONFLICT_UPDATE" || Object.values(node).some(overwrites));
|
|
2836
2838
|
function mcpTools(plan, surface, locale = "en") {
|
|
2837
2839
|
const text = (t) => resolveLocalizedText(t, locale, "en") ?? void 0;
|
|
2838
2840
|
const tools = /* @__PURE__ */ new Map();
|
|
@@ -2849,33 +2851,61 @@ function mcpTools(plan, surface, locale = "en") {
|
|
|
2849
2851
|
name: mcpToolNameSegment(t.procedure),
|
|
2850
2852
|
kind: "procedure",
|
|
2851
2853
|
source: t.procedure,
|
|
2852
|
-
|
|
2854
|
+
title: title ?? toolTitle(t.procedure),
|
|
2853
2855
|
description: text(p.description) ?? title ?? t.procedure,
|
|
2854
2856
|
inputSchema: p.input,
|
|
2855
2857
|
// structuredContent must be an object
|
|
2856
2858
|
...p.output.type === "object" ? { outputSchema: p.output } : {},
|
|
2857
|
-
|
|
2859
|
+
annotations: procedureAnnotations(p),
|
|
2858
2860
|
requires: p.requires
|
|
2859
2861
|
});
|
|
2860
2862
|
}
|
|
2861
2863
|
for (const [name4, v] of Object.entries(plan.views)) {
|
|
2862
2864
|
if (v.surface !== surface) continue;
|
|
2863
|
-
const
|
|
2865
|
+
const chain = (v.input ? rootRefChain(v.input) ?? [v.input] : []).reverse();
|
|
2866
|
+
const props = Object.assign({}, ...chain.map((s) => s.properties ?? {}));
|
|
2867
|
+
const required = [...new Set(chain.flatMap((s) => s.required ?? []))];
|
|
2864
2868
|
if ("limit" in props || "cursor" in props) throw new TypeError(`View '${name4}' declares an input named limit or cursor; the MCP tool reserves both for paging.`);
|
|
2869
|
+
const rules = chain.map((s) => Object.fromEntries(INPUT_RULE_KEYWORDS.flatMap((k) => s[k] === void 0 ? [] : [[k, s[k]]]))).filter((r) => Object.keys(r).length);
|
|
2870
|
+
const defs = v.input ? referencedDefs(v.input, props) : {};
|
|
2865
2871
|
const title = text(v.title);
|
|
2866
2872
|
add({
|
|
2867
2873
|
name: mcpToolNameSegment(name4),
|
|
2868
2874
|
kind: "view",
|
|
2869
2875
|
source: name4,
|
|
2870
|
-
|
|
2876
|
+
title: title ?? toolTitle(name4),
|
|
2871
2877
|
description: text(v.description) ?? title ?? name4,
|
|
2872
|
-
inputSchema: {
|
|
2873
|
-
|
|
2878
|
+
inputSchema: {
|
|
2879
|
+
type: "object",
|
|
2880
|
+
properties: { ...props, limit: { type: "integer", minimum: 1, maximum: 500 }, cursor: { type: "string" } },
|
|
2881
|
+
...required.length ? { required } : {},
|
|
2882
|
+
...rules.length > 1 ? { allOf: rules } : rules[0],
|
|
2883
|
+
...Object.keys(defs).length ? { $defs: defs } : {}
|
|
2884
|
+
},
|
|
2885
|
+
annotations: viewAnnotations,
|
|
2874
2886
|
requires: v.requires
|
|
2875
2887
|
});
|
|
2876
2888
|
}
|
|
2877
2889
|
return [...tools.values()];
|
|
2878
2890
|
}
|
|
2891
|
+
function referencedDefs(root, node, found = {}) {
|
|
2892
|
+
if (!node || typeof node !== "object") return found;
|
|
2893
|
+
const ref2 = node.$ref, [head, segment] = typeof ref2 === "string" && ref2.startsWith("#/") ? decoded(ref2.slice(2)).split("/") : [];
|
|
2894
|
+
const key = head === "$defs" ? segment?.replace(/~1/g, "/").replace(/~0/g, "~") : void 0;
|
|
2895
|
+
if (key !== void 0 && !Object.hasOwn(found, key) && root.$defs && Object.hasOwn(root.$defs, key)) {
|
|
2896
|
+
found[key] = root.$defs[key];
|
|
2897
|
+
referencedDefs(root, found[key], found);
|
|
2898
|
+
}
|
|
2899
|
+
for (const child2 of Object.values(node)) referencedDefs(root, child2, found);
|
|
2900
|
+
return found;
|
|
2901
|
+
}
|
|
2902
|
+
var decoded = (pointer2) => {
|
|
2903
|
+
try {
|
|
2904
|
+
return decodeURIComponent(pointer2);
|
|
2905
|
+
} catch {
|
|
2906
|
+
return "";
|
|
2907
|
+
}
|
|
2908
|
+
};
|
|
2879
2909
|
|
|
2880
2910
|
// src/build/spec/domain/service/TriggerGraphChecks.ts
|
|
2881
2911
|
function checkProcedureTarget(procedure, schemasByName, filePaths) {
|
|
@@ -4459,7 +4489,6 @@ function writePolicy(s, kind, o = {}) {
|
|
|
4459
4489
|
}
|
|
4460
4490
|
|
|
4461
4491
|
// src/build/spec/infrastructure/sql/compilePlan.ts
|
|
4462
|
-
var NATIVE_COLUMNS = { id: "id", status: "status", version: "version", createdAt: "created_at", updatedAt: "updated_at", authorId: "author_id" };
|
|
4463
4492
|
var indexColumn = (field) => Object.hasOwn(NATIVE_COLUMNS, field) ? NATIVE_COLUMNS[field] : field.toLowerCase();
|
|
4464
4493
|
function toDiagnostic2(d, source, pointer2) {
|
|
4465
4494
|
const at = d.line === void 0 ? void 0 : { line: d.line, column: d.column, ...d.token ? { token: d.token } : {} };
|
|
@@ -4651,10 +4680,6 @@ async function compileLinkedPlan(linked, dialect = compile_exports) {
|
|
|
4651
4680
|
diagnostics.push(validateDiagnostic({ code: "VIEW_UI_INVALID", severity: "error", path: `${source.sourceId}#/${source.documentIndex}/spec/uiSchema/list/${key}/${i}`, source: { ...source, path: `/spec/uiSchema/list/${key}/${i}` }, value: f, expected: `one of the View's outputs: ${outputs.keys.join(", ")}`, message: `View '${v.metadata.name}' uiSchema.list.${key} names '${f}', which the View's SELECT does not output.` }));
|
|
4652
4681
|
}
|
|
4653
4682
|
const wire = (outputs?.keys ?? []).map((k) => columns2[k]?.field === k ? schemas[columns2[k].schema].names?.[k] ?? k : k);
|
|
4654
|
-
for (const f of Object.keys(v.spec.uiSchema?.["list"]?.cells ?? {})) {
|
|
4655
|
-
if (!outputs?.keys || wire.includes(f)) continue;
|
|
4656
|
-
diagnostics.push(validateDiagnostic({ code: "VIEW_UI_INVALID", severity: "error", path: `${source.sourceId}#/${source.documentIndex}/spec/uiSchema/list/cells/${f}`, source: { ...source, path: `/spec/uiSchema/list/cells/${f}` }, value: f, expected: `one of the View's outputs: ${wire.join(", ")}`, message: `View '${v.metadata.name}' uiSchema.list.cells names '${f}', which the View's SELECT does not output.` }));
|
|
4657
|
-
}
|
|
4658
4683
|
for (const [i, f] of (list["columns"] ?? []).entries()) {
|
|
4659
4684
|
if (!outputs?.keys || wire.includes(f)) continue;
|
|
4660
4685
|
const folded = wire.find((k) => k.toLowerCase() === f.toLowerCase());
|
|
@@ -4887,7 +4912,7 @@ function toCanonicalLocale(input) {
|
|
|
4887
4912
|
}
|
|
4888
4913
|
function canonicalizeLocaleList(inputs) {
|
|
4889
4914
|
const valid = [];
|
|
4890
|
-
const
|
|
4915
|
+
const invalid2 = [];
|
|
4891
4916
|
const seen = /* @__PURE__ */ new Set();
|
|
4892
4917
|
for (const raw of inputs) {
|
|
4893
4918
|
try {
|
|
@@ -4897,10 +4922,10 @@ function canonicalizeLocaleList(inputs) {
|
|
|
4897
4922
|
valid.push(canonical2);
|
|
4898
4923
|
}
|
|
4899
4924
|
} catch {
|
|
4900
|
-
|
|
4925
|
+
invalid2.push(raw);
|
|
4901
4926
|
}
|
|
4902
4927
|
}
|
|
4903
|
-
return { valid, invalid:
|
|
4928
|
+
return { valid, invalid: invalid2 };
|
|
4904
4929
|
}
|
|
4905
4930
|
function containsScriptSubtagLocale(inputs) {
|
|
4906
4931
|
return inputs.some((raw) => SCRIPT_SUBTAG_SHAPE.test(raw));
|
|
@@ -4956,13 +4981,13 @@ var InvalidSiteIconsError = class extends Error {
|
|
|
4956
4981
|
};
|
|
4957
4982
|
function assertSiteDefaultsCanonical(defaults) {
|
|
4958
4983
|
if (defaults?.locales && defaults.locales.length > 0) {
|
|
4959
|
-
const { invalid:
|
|
4960
|
-
if (
|
|
4984
|
+
const { invalid: invalid2 } = canonicalizeLocaleList(defaults.locales);
|
|
4985
|
+
if (invalid2.length > 0) throw new InvalidSiteDefaultsError(invalid2);
|
|
4961
4986
|
}
|
|
4962
4987
|
if (defaults?.icons) {
|
|
4963
|
-
const
|
|
4964
|
-
if (defaults.icons.length === 0 ||
|
|
4965
|
-
throw new InvalidSiteIconsError(
|
|
4988
|
+
const invalid2 = defaults.icons.filter((icon) => !validSiteIcon(icon));
|
|
4989
|
+
if (defaults.icons.length === 0 || invalid2.length > 0) {
|
|
4990
|
+
throw new InvalidSiteIconsError(invalid2.length > 0 ? invalid2 : defaults.icons);
|
|
4966
4991
|
}
|
|
4967
4992
|
}
|
|
4968
4993
|
const origin = defaults?.origin;
|
|
@@ -5069,7 +5094,7 @@ function lifecycleHookSets(plan) {
|
|
|
5069
5094
|
}
|
|
5070
5095
|
|
|
5071
5096
|
// src/build/core/version.ts
|
|
5072
|
-
var MANTLE_VERSION = "0.2.0-alpha.
|
|
5097
|
+
var MANTLE_VERSION = "0.2.0-alpha.9";
|
|
5073
5098
|
|
|
5074
5099
|
// src/build/core/sql/ast.ts
|
|
5075
5100
|
var S = (s) => ({ String: { sval: s } });
|
|
@@ -6368,7 +6393,6 @@ function initialStorageSql(plan) {
|
|
|
6368
6393
|
// src/build/postgres/storage.ts
|
|
6369
6394
|
var q4 = (id) => `"${id.replace(/"/g, '""')}"`;
|
|
6370
6395
|
var ident = (n) => new TextEncoder().encode(n).length <= 63 ? n : `${n.slice(0, 50)}_${fnv(n)}`;
|
|
6371
|
-
var fnv = (s) => [...s].reduce((h, c) => Math.imul(h ^ c.codePointAt(0), 16777619) >>> 0, 2166136261).toString(16).padStart(8, "0");
|
|
6372
6396
|
function columns(s) {
|
|
6373
6397
|
return [
|
|
6374
6398
|
...s.scope ? [{ name: s.scope, type: "text", native: true }] : [],
|
|
@@ -6418,15 +6442,13 @@ function adminIndexColumns(s) {
|
|
|
6418
6442
|
function collectionOf(s, schemas) {
|
|
6419
6443
|
const names = new Set(schemas.filter((x) => !x.translates).map((x) => x.name));
|
|
6420
6444
|
const props = propsOf(s.schema);
|
|
6421
|
-
const required = new Set(s.schema.required ?? []);
|
|
6422
6445
|
const ui = s.uiSchema ?? {};
|
|
6423
6446
|
const list = ui["list"] ?? {};
|
|
6424
6447
|
const nav = ui["nav"];
|
|
6425
6448
|
const filterField = list["filterField"];
|
|
6426
|
-
const
|
|
6427
|
-
const
|
|
6428
|
-
const
|
|
6429
|
-
const navField = nav?.["standalone"] === true ? nav["parentField"] ?? byId : void 0;
|
|
6449
|
+
const declared = nav?.["parentField"];
|
|
6450
|
+
const parentField = foldParentField(s.schema, declared, (name4) => names.has(name4));
|
|
6451
|
+
const navField = nav?.["standalone"] === true ? declared ?? (s.translates ? void 0 : requiredMantleRefFields(s.schema).find((r) => names.has(r.collection))?.field) : void 0;
|
|
6430
6452
|
const navParent = navField ? resolveMantleRef(props[navField]) : null;
|
|
6431
6453
|
const children = schemas.filter((c) => c.translates?.parent === s.name);
|
|
6432
6454
|
return {
|
|
@@ -6448,6 +6470,10 @@ function collectionOf(s, schemas) {
|
|
|
6448
6470
|
nav: navField && navParent ? { standalone: true, parentField: navField, parentCollection: navParent.schema } : null
|
|
6449
6471
|
};
|
|
6450
6472
|
}
|
|
6473
|
+
function isPrimaryCollection(s, schemas) {
|
|
6474
|
+
const c = collectionOf(s, schemas);
|
|
6475
|
+
return !s.translates && (!c.parent || c.nav !== null);
|
|
6476
|
+
}
|
|
6451
6477
|
|
|
6452
6478
|
// src/build/admin/procedureFlow.ts
|
|
6453
6479
|
function expression(node) {
|
|
@@ -6780,114 +6806,6 @@ function developerConsole(plan) {
|
|
|
6780
6806
|
};
|
|
6781
6807
|
}
|
|
6782
6808
|
|
|
6783
|
-
// src/build/admin/extensions.ts
|
|
6784
|
-
var invalid2 = (code, path, message2, value2) => new DiagnosticError(makeDiagnostic({ code, phase: "boot", severity: "error", path, message: message2, ...value2 === void 0 ? {} : { value: value2 } }));
|
|
6785
|
-
var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
6786
|
-
var isText2 = (v) => typeof v === "string" && v.length > 0 || isObject(v) && Object.keys(v).length > 0 && Object.values(v).every((x) => typeof x === "string" && x.length > 0);
|
|
6787
|
-
var keysWithin = (o, allowed) => Object.keys(o).find((k) => !allowed.includes(k));
|
|
6788
|
-
var FORM_TYPES = ["string", "number", "integer", "boolean"];
|
|
6789
|
-
var FORM_PROPERTY_KEYS = ["type", "title", "description", "default", "enum", "oneOf", "minimum", "maximum", "minLength", "maxLength"];
|
|
6790
|
-
function formSchemaProblem(schema) {
|
|
6791
|
-
if (!isObject(schema) || schema["type"] !== "object" || !isObject(schema["properties"])) return "an object schema with properties";
|
|
6792
|
-
const extra = keysWithin(schema, ["type", "properties", "required", "title", "description", "additionalProperties"]);
|
|
6793
|
-
if (extra) return `no '${extra}' at the top level`;
|
|
6794
|
-
if (schema["additionalProperties"] !== void 0 && schema["additionalProperties"] !== false) return "additionalProperties false or absent";
|
|
6795
|
-
const props = schema["properties"];
|
|
6796
|
-
const names = Object.keys(props);
|
|
6797
|
-
if (names.length === 0 || names.length > 64) return "1 to 64 properties";
|
|
6798
|
-
if (names.includes("__proto__")) return "no property named __proto__";
|
|
6799
|
-
const required = schema["required"];
|
|
6800
|
-
if (required !== void 0 && (!Array.isArray(required) || required.some((r) => typeof r !== "string" || !names.includes(r)))) return "required naming declared properties";
|
|
6801
|
-
for (const [name4, p] of Object.entries(props)) {
|
|
6802
|
-
if (!isObject(p) || typeof p["type"] !== "string" || !FORM_TYPES.includes(p["type"])) return `property '${name4}' typed string, number, integer or boolean`;
|
|
6803
|
-
const bad = keysWithin(p, FORM_PROPERTY_KEYS);
|
|
6804
|
-
if (bad) return `property '${name4}' without '${bad}'`;
|
|
6805
|
-
if (p["title"] !== void 0 && !isText2(p["title"])) return `property '${name4}' with a text title`;
|
|
6806
|
-
if (p["description"] !== void 0 && !isText2(p["description"])) return `property '${name4}' with a text description`;
|
|
6807
|
-
if (p["enum"] !== void 0 && (!Array.isArray(p["enum"]) || p["enum"].length === 0 || p["enum"].some((x) => !matchesType(p["type"], x)))) return `property '${name4}' with an enum of its type`;
|
|
6808
|
-
if (p["oneOf"] !== void 0 && (!Array.isArray(p["oneOf"]) || p["oneOf"].length === 0 || p["oneOf"].some((o) => !isObject(o) || keysWithin(o, ["const", "title"]) || !matchesType(p["type"], o["const"]) || o["title"] !== void 0 && !isText2(o["title"])))) return `property '${name4}' with a oneOf of { const, title }`;
|
|
6809
|
-
for (const k of ["minimum", "maximum", "minLength", "maxLength"]) if (p[k] !== void 0 && (typeof p[k] !== "number" || !Number.isFinite(p[k]))) return `property '${name4}' with a numeric ${k}`;
|
|
6810
|
-
if (p["default"] !== void 0 && checkValue(p, p["default"]) !== null) return `property '${name4}' with a default it accepts`;
|
|
6811
|
-
}
|
|
6812
|
-
return null;
|
|
6813
|
-
}
|
|
6814
|
-
function matchesType(type, v) {
|
|
6815
|
-
if (type === "string") return typeof v === "string";
|
|
6816
|
-
if (type === "boolean") return typeof v === "boolean";
|
|
6817
|
-
if (type === "integer") return Number.isInteger(v);
|
|
6818
|
-
return typeof v === "number" && Number.isFinite(v);
|
|
6819
|
-
}
|
|
6820
|
-
function checkValue(p, v) {
|
|
6821
|
-
const type = p["type"];
|
|
6822
|
-
if (!matchesType(type, v)) return type === "integer" ? "an integer" : `a ${type}`;
|
|
6823
|
-
if (Array.isArray(p["enum"]) && !p["enum"].includes(v)) return "one of the listed values";
|
|
6824
|
-
if (Array.isArray(p["oneOf"]) && !p["oneOf"].some((o) => o["const"] === v)) return "one of the listed values";
|
|
6825
|
-
if (typeof v === "number") {
|
|
6826
|
-
if (typeof p["minimum"] === "number" && v < p["minimum"]) return `at least ${p["minimum"]}`;
|
|
6827
|
-
if (typeof p["maximum"] === "number" && v > p["maximum"]) return `at most ${p["maximum"]}`;
|
|
6828
|
-
}
|
|
6829
|
-
if (typeof v === "string") {
|
|
6830
|
-
const length = [...v].length;
|
|
6831
|
-
if (typeof p["minLength"] === "number" && length < p["minLength"]) return `at least ${p["minLength"]} characters`;
|
|
6832
|
-
if (typeof p["maxLength"] === "number" && length > p["maxLength"]) return `at most ${p["maxLength"]} characters`;
|
|
6833
|
-
}
|
|
6834
|
-
return null;
|
|
6835
|
-
}
|
|
6836
|
-
function checkFormValue(schema, value2) {
|
|
6837
|
-
if (!isObject(value2)) return { "": "an object" };
|
|
6838
|
-
const props = schema.properties ?? {};
|
|
6839
|
-
const errors = /* @__PURE__ */ Object.create(null);
|
|
6840
|
-
const has = (name4) => Object.hasOwn(value2, name4) && value2[name4] !== void 0;
|
|
6841
|
-
for (const k of Object.keys(value2)) if (!Object.hasOwn(props, k)) errors[k] = "no such field";
|
|
6842
|
-
for (const name4 of schema.required ?? []) if (!has(name4)) errors[name4] = "required";
|
|
6843
|
-
for (const [name4, p] of Object.entries(props)) {
|
|
6844
|
-
if (!has(name4) || Object.hasOwn(errors, name4)) continue;
|
|
6845
|
-
const problem3 = checkValue(p, value2[name4]);
|
|
6846
|
-
if (problem3) errors[name4] = `expected ${problem3}`;
|
|
6847
|
-
}
|
|
6848
|
-
return errors;
|
|
6849
|
-
}
|
|
6850
|
-
function planUiExtensionRefs(plan) {
|
|
6851
|
-
const refs = [];
|
|
6852
|
-
const fields = (owner, ui) => {
|
|
6853
|
-
for (const [name4, c] of Object.entries(isObject(ui?.["fields"]) ? ui["fields"] : {})) {
|
|
6854
|
-
if (isObject(c) && typeof c["widget"] === "string" && UI_EXTENSION_REF.test(c["widget"])) refs.push({ path: `${owner}/uiSchema/fields/${name4}/widget`, ref: c["widget"], target: "field.input/v1", ...c["options"] === void 0 ? {} : { options: c["options"] } });
|
|
6855
|
-
}
|
|
6856
|
-
};
|
|
6857
|
-
const cells = (owner, ui) => {
|
|
6858
|
-
const list = ui?.["list"];
|
|
6859
|
-
for (const [name4, ref2] of Object.entries(isObject(list) && isObject(list["cells"]) ? list["cells"] : {})) if (typeof ref2 === "string") refs.push({ path: `${owner}/uiSchema/list/cells/${name4}`, ref: ref2, target: "field.cell/v1" });
|
|
6860
|
-
};
|
|
6861
|
-
for (const [name4, s] of Object.entries(plan.schemas)) {
|
|
6862
|
-
const owner = `schema:${s.name ?? name4}`;
|
|
6863
|
-
const ui = s.uiSchema;
|
|
6864
|
-
fields(owner, ui);
|
|
6865
|
-
cells(owner, ui);
|
|
6866
|
-
const panels = ui?.["panels"];
|
|
6867
|
-
if (Array.isArray(panels)) {
|
|
6868
|
-
for (const ref2 of panels) if (typeof ref2 === "string") refs.push({ path: `${owner}/uiSchema/panels`, ref: ref2, target: "record.sidebar/v1" });
|
|
6869
|
-
}
|
|
6870
|
-
}
|
|
6871
|
-
for (const [name4, p] of Object.entries(plan.procedures)) fields(`procedure:${name4}`, p.uiSchema);
|
|
6872
|
-
for (const [name4, v] of Object.entries(plan.views)) cells(`view:${name4}`, v.uiSchema);
|
|
6873
|
-
return refs;
|
|
6874
|
-
}
|
|
6875
|
-
function checkPlanUiExtensions(plan, extensions) {
|
|
6876
|
-
for (const { path, ref: ref2, target: target2, options } of planUiExtensionRefs(plan)) {
|
|
6877
|
-
const [, extId, cId] = UI_EXTENSION_REF.exec(ref2);
|
|
6878
|
-
const ext = extensions.find((e) => e.id === extId);
|
|
6879
|
-
const c = ext ? [...ext.contributes.fields ?? [], ...ext.contributes.panels ?? []].find((x) => x.id === cId) : void 0;
|
|
6880
|
-
if (!c) throw invalid2("UI_EXTENSION_UNKNOWN", path, `no Admin extension contribution '${ref2}'`, ref2);
|
|
6881
|
-
if (c.target !== target2) throw invalid2("UI_EXTENSION_TARGET", path, `'${ref2}' is a ${c.target} contribution; this key needs ${target2}`, ref2);
|
|
6882
|
-
if (options === void 0) continue;
|
|
6883
|
-
const schema = c.optionsSchema;
|
|
6884
|
-
if (!schema) throw invalid2("UI_EXTENSION_OPTIONS", path, `'${ref2}' takes no options`, options);
|
|
6885
|
-
const errors = checkFormValue(schema, options);
|
|
6886
|
-
const first = Object.entries(errors)[0];
|
|
6887
|
-
if (first) throw invalid2("UI_EXTENSION_OPTIONS", `${path}/${first[0]}`, `options for '${ref2}': ${first[0] || "options"} ${first[1]}`, options);
|
|
6888
|
-
}
|
|
6889
|
-
}
|
|
6890
|
-
|
|
6891
6809
|
// src/build/mcp/catalog.ts
|
|
6892
6810
|
var nativeSchema = (field) => Object.hasOwn(NATIVE_OUTPUT_TYPES, field) ? NATIVE_OUTPUT_TYPES[field] === "integer" ? { type: "integer" } : { type: "string", format: "date-time" } : void 0;
|
|
6893
6811
|
function entrySchema(plan, v) {
|
|
@@ -6932,12 +6850,14 @@ function appCatalog(plan, surface) {
|
|
|
6932
6850
|
export {
|
|
6933
6851
|
BUILT_IN_NAV_GROUPS,
|
|
6934
6852
|
DiagnosticError,
|
|
6853
|
+
INPUT_RULE_KEYWORDS,
|
|
6854
|
+
NATIVE_COLUMNS,
|
|
6935
6855
|
NATIVE_NOT_NULL,
|
|
6936
6856
|
adminIndexColumns,
|
|
6937
6857
|
appCatalog,
|
|
6938
6858
|
assertSiteDefaultsCanonical,
|
|
6859
|
+
canonical,
|
|
6939
6860
|
canonicalizeLocaleList,
|
|
6940
|
-
checkPlanUiExtensions,
|
|
6941
6861
|
collectionOf,
|
|
6942
6862
|
compilePlan,
|
|
6943
6863
|
compileProgram,
|
|
@@ -6946,26 +6866,31 @@ export {
|
|
|
6946
6866
|
entrySchema,
|
|
6947
6867
|
enumOptions,
|
|
6948
6868
|
expandPolicyRequired,
|
|
6949
|
-
|
|
6869
|
+
fnv,
|
|
6870
|
+
isPrimaryCollection,
|
|
6871
|
+
lookupLocalRef,
|
|
6950
6872
|
lowerPlan,
|
|
6951
6873
|
mcpToolNameSegment,
|
|
6952
6874
|
mcpTools,
|
|
6953
|
-
|
|
6875
|
+
navPlacementProblems,
|
|
6954
6876
|
notNullColumns,
|
|
6955
6877
|
pagedOf,
|
|
6956
6878
|
parseNumeric,
|
|
6957
6879
|
parsePgSql,
|
|
6958
|
-
planUiExtensionRefs,
|
|
6959
6880
|
compile_exports2 as postgresCompiler,
|
|
6960
6881
|
postgresDialect,
|
|
6961
6882
|
initialStorageSql2 as postgresSchema,
|
|
6883
|
+
procedureAnnotations,
|
|
6962
6884
|
protectedColumns,
|
|
6963
6885
|
resolveLocalizedText,
|
|
6886
|
+
rootRefChain,
|
|
6964
6887
|
rowPolicy,
|
|
6965
6888
|
rowPreconditions,
|
|
6966
6889
|
compile_exports as sqliteCompiler,
|
|
6967
6890
|
initialStorageSql as sqliteSchema,
|
|
6891
|
+
toolTitle,
|
|
6968
6892
|
userScopeTerm,
|
|
6893
|
+
viewAnnotations,
|
|
6969
6894
|
viewOutputs,
|
|
6970
6895
|
writePolicy
|
|
6971
6896
|
};
|