@bobbykim/manguito-cms-cli 0.10.0 → 0.11.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.
|
@@ -9270,7 +9270,7 @@ var require_bcryptjs = __commonJS({
|
|
|
9270
9270
|
}
|
|
9271
9271
|
});
|
|
9272
9272
|
|
|
9273
|
-
// ../api/dist/chunk-
|
|
9273
|
+
// ../api/dist/chunk-GUZZQZSN.mjs
|
|
9274
9274
|
init_esm_shims();
|
|
9275
9275
|
import crypto from "crypto";
|
|
9276
9276
|
|
|
@@ -25795,7 +25795,8 @@ var fieldTypeRegistry = {
|
|
|
25795
25795
|
left_column: "left_id",
|
|
25796
25796
|
right_column: "right_id",
|
|
25797
25797
|
right_table: targetTableName,
|
|
25798
|
-
|
|
25798
|
+
// Every list keeps the order the editor gave it (#57).
|
|
25799
|
+
order_column: true
|
|
25799
25800
|
}
|
|
25800
25801
|
} : {
|
|
25801
25802
|
// FK column on the owning table. An optional reference is cleared when
|
|
@@ -26617,7 +26618,7 @@ function describeSchemaChange(input) {
|
|
|
26617
26618
|
return { from: from?.version ?? null, to: to.version, types, identical };
|
|
26618
26619
|
}
|
|
26619
26620
|
|
|
26620
|
-
// ../api/dist/chunk-
|
|
26621
|
+
// ../api/dist/chunk-GUZZQZSN.mjs
|
|
26621
26622
|
function isColumnBacked2(field) {
|
|
26622
26623
|
const col = field.db_column;
|
|
26623
26624
|
if (col === null) return false;
|
|
@@ -26845,10 +26846,28 @@ async function persistJunctionField(db, itemId, junction, relatedIds) {
|
|
|
26845
26846
|
const tbl = sql.raw(quoteIdent(junction.table_name));
|
|
26846
26847
|
const left = sql.raw(quoteIdent(junction.left_column));
|
|
26847
26848
|
const right = sql.raw(quoteIdent(junction.right_column));
|
|
26849
|
+
const seen = /* @__PURE__ */ new Set();
|
|
26850
|
+
const ids = relatedIds.filter((id) => {
|
|
26851
|
+
const key = id.toLowerCase();
|
|
26852
|
+
if (seen.has(key)) return false;
|
|
26853
|
+
seen.add(key);
|
|
26854
|
+
return true;
|
|
26855
|
+
});
|
|
26848
26856
|
await db.execute(sql`DELETE FROM ${tbl} WHERE ${left} = ${itemId}`);
|
|
26849
|
-
|
|
26850
|
-
|
|
26851
|
-
|
|
26857
|
+
if (ids.length === 0) return;
|
|
26858
|
+
const rows = sql.join(
|
|
26859
|
+
ids.map(
|
|
26860
|
+
(rid, position) => junction.order_column ? sql`(${itemId}, ${rid}, ${position})` : sql`(${itemId}, ${rid})`
|
|
26861
|
+
),
|
|
26862
|
+
sql`, `
|
|
26863
|
+
);
|
|
26864
|
+
await db.execute(
|
|
26865
|
+
junction.order_column ? sql`INSERT INTO ${tbl} (${left}, ${right}, "order") VALUES ${rows}` : sql`INSERT INTO ${tbl} (${left}, ${right}) VALUES ${rows}`
|
|
26866
|
+
);
|
|
26867
|
+
}
|
|
26868
|
+
function junctionOrderBy(junction) {
|
|
26869
|
+
const right = sql.raw(quoteIdent(junction.right_column));
|
|
26870
|
+
return junction.order_column ? sql` ORDER BY "order" ASC, ${right} ASC` : sql` ORDER BY ${right} ASC`;
|
|
26852
26871
|
}
|
|
26853
26872
|
function oneOrMany(cardinality, list) {
|
|
26854
26873
|
return cardinality === "one" ? list[0] ?? null : list;
|
|
@@ -26950,9 +26969,8 @@ async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOn
|
|
|
26950
26969
|
} else if (rel.type === "junction") {
|
|
26951
26970
|
const parentIds = batch.map((r) => r["id"]);
|
|
26952
26971
|
const inList = sql.join(parentIds.map((id) => sql`${id}`), sql`, `);
|
|
26953
|
-
const orderBy = rel.order_column ? sql` ORDER BY "order" ASC` : sql``;
|
|
26954
26972
|
const junctionResult = await db.execute(
|
|
26955
|
-
sql`SELECT * FROM ${sql.raw(quoteIdent(rel.junction_table))} WHERE ${sql.raw(quoteIdent(rel.left_column))} IN (${inList})${
|
|
26973
|
+
sql`SELECT * FROM ${sql.raw(quoteIdent(rel.junction_table))} WHERE ${sql.raw(quoteIdent(rel.left_column))} IN (${inList})${junctionOrderBy(rel)}`
|
|
26956
26974
|
);
|
|
26957
26975
|
const jRows = junctionResult.rows;
|
|
26958
26976
|
const rightIds = [...new Set(jRows.map((r) => r[rel.right_column]))];
|
|
@@ -27011,7 +27029,7 @@ async function resolveRelationBareIds(db, rows, fieldName, rel) {
|
|
|
27011
27029
|
const parentIds = rows.map((r) => r["id"]);
|
|
27012
27030
|
const inList = sql.join(parentIds.map((id) => sql`${id}`), sql`, `);
|
|
27013
27031
|
const result = await db.execute(
|
|
27014
|
-
sql`SELECT ${sql.raw(quoteIdent(rel.left_column))} AS left_id, ${sql.raw(quoteIdent(rel.right_column))} AS right_id FROM ${sql.raw(quoteIdent(rel.junction_table))} WHERE ${sql.raw(quoteIdent(rel.left_column))} IN (${inList})`
|
|
27032
|
+
sql`SELECT ${sql.raw(quoteIdent(rel.left_column))} AS left_id, ${sql.raw(quoteIdent(rel.right_column))} AS right_id FROM ${sql.raw(quoteIdent(rel.junction_table))} WHERE ${sql.raw(quoteIdent(rel.left_column))} IN (${inList})${junctionOrderBy(rel)}`
|
|
27015
27033
|
);
|
|
27016
27034
|
const byLeft = groupBy(result.rows, "left_id");
|
|
27017
27035
|
for (const row of rows) {
|
|
@@ -27071,6 +27089,7 @@ export {
|
|
|
27071
27089
|
persistParagraphField,
|
|
27072
27090
|
deleteParagraphField,
|
|
27073
27091
|
persistJunctionField,
|
|
27092
|
+
junctionOrderBy,
|
|
27074
27093
|
oneOrMany,
|
|
27075
27094
|
paragraphItems,
|
|
27076
27095
|
buildRelationsMap,
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
isColumnBacked,
|
|
13
13
|
relationCardinality,
|
|
14
14
|
resolveRelationField
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-WTZBHFCV.js";
|
|
16
16
|
|
|
17
17
|
// ../../node_modules/.pnpm/@whatwg-node+fetch@0.10.13/node_modules/@whatwg-node/fetch/dist/shouldSkipPonyfill.js
|
|
18
18
|
var require_shouldSkipPonyfill = __commonJS({
|
|
@@ -10787,10 +10787,10 @@ var require_parser = __commonJS({
|
|
|
10787
10787
|
}
|
|
10788
10788
|
});
|
|
10789
10789
|
|
|
10790
|
-
// ../api/dist/handler-
|
|
10790
|
+
// ../api/dist/handler-MFF32JB4.mjs
|
|
10791
10791
|
init_esm_shims();
|
|
10792
10792
|
|
|
10793
|
-
// ../api/dist/chunk-
|
|
10793
|
+
// ../api/dist/chunk-ITOSMGDT.mjs
|
|
10794
10794
|
init_esm_shims();
|
|
10795
10795
|
|
|
10796
10796
|
// ../../node_modules/.pnpm/graphql-yoga@5.21.2_graphql@16.14.2/node_modules/graphql-yoga/esm/index.js
|
|
@@ -30123,7 +30123,7 @@ function createYoga(options) {
|
|
|
30123
30123
|
});
|
|
30124
30124
|
}
|
|
30125
30125
|
|
|
30126
|
-
// ../api/dist/chunk-
|
|
30126
|
+
// ../api/dist/chunk-ITOSMGDT.mjs
|
|
30127
30127
|
var import_dataloader = __toESM(require_dataloader(), 1);
|
|
30128
30128
|
|
|
30129
30129
|
// ../../node_modules/.pnpm/@escape.tech+graphql-armor@3.2.0_@envelop+core@5.5.1_@escape.tech+graphql-armor-types@0.7.0/node_modules/@escape.tech/graphql-armor/dist/graphql-armor.esm.js
|
|
@@ -30881,7 +30881,7 @@ var EnvelopArmor = class {
|
|
|
30881
30881
|
}
|
|
30882
30882
|
};
|
|
30883
30883
|
|
|
30884
|
-
// ../api/dist/chunk-
|
|
30884
|
+
// ../api/dist/chunk-ITOSMGDT.mjs
|
|
30885
30885
|
var DateTimeScalar = new GraphQLScalarType({
|
|
30886
30886
|
name: "DateTime",
|
|
30887
30887
|
description: "ISO-8601 date-time string",
|
package/dist/index.js
CHANGED
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
isColumnBacked,
|
|
38
38
|
isDriverValueEncoder,
|
|
39
39
|
isSQLWrapper,
|
|
40
|
+
junctionOrderBy,
|
|
40
41
|
loadSchemaFile,
|
|
41
42
|
loadVersionSnapshots,
|
|
42
43
|
oneOrMany,
|
|
@@ -54,7 +55,7 @@ import {
|
|
|
54
55
|
validateCrossReferences,
|
|
55
56
|
verifyPassword,
|
|
56
57
|
walkSchemaDirectory
|
|
57
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-WTZBHFCV.js";
|
|
58
59
|
|
|
59
60
|
// ../../node_modules/.pnpm/postgres-array@2.0.0/node_modules/postgres-array/index.js
|
|
60
61
|
var require_postgres_array = __commonJS({
|
|
@@ -22848,8 +22849,7 @@ function checkRelationInput(fields, body, registry, path5 = "") {
|
|
|
22848
22849
|
});
|
|
22849
22850
|
continue;
|
|
22850
22851
|
}
|
|
22851
|
-
const
|
|
22852
|
-
const pType = comp.component === "paragraph-embed" ? registry.paragraph_types[comp.ref] : void 0;
|
|
22852
|
+
const pType = paragraphTypeOf(field, registry);
|
|
22853
22853
|
if (!pType) continue;
|
|
22854
22854
|
items.forEach((item, i) => {
|
|
22855
22855
|
const prefix = cardinality === "one" ? `${name}.` : `${name}[${i}].`;
|
|
@@ -22858,12 +22858,15 @@ function checkRelationInput(fields, body, registry, path5 = "") {
|
|
|
22858
22858
|
}
|
|
22859
22859
|
return errors;
|
|
22860
22860
|
}
|
|
22861
|
+
function paragraphTypeOf(field, registry) {
|
|
22862
|
+
const comp = field.ui_component;
|
|
22863
|
+
return comp.component === "paragraph-embed" ? registry.paragraph_types[comp.ref] : void 0;
|
|
22864
|
+
}
|
|
22861
22865
|
function paragraphItemsIn(fields, body, registry, path5) {
|
|
22862
22866
|
const out = [];
|
|
22863
22867
|
for (const field of fields) {
|
|
22864
22868
|
if (field.field_type !== "paragraph" || !(field.name in body)) continue;
|
|
22865
|
-
const
|
|
22866
|
-
const pType = comp.component === "paragraph-embed" ? registry.paragraph_types[comp.ref] : void 0;
|
|
22869
|
+
const pType = paragraphTypeOf(field, registry);
|
|
22867
22870
|
if (!pType) continue;
|
|
22868
22871
|
const value = body[field.name];
|
|
22869
22872
|
const name = `${path5}${field.name}`;
|
|
@@ -22934,6 +22937,131 @@ async function findMissingReferences(db, fields, body, registry) {
|
|
|
22934
22937
|
const found = new Map(await Promise.all(lookups));
|
|
22935
22938
|
return uses.filter((u) => !found.get(u.table).has(u.id.toLowerCase())).map((u) => ({ field: u.field, message: `${u.field} refers to an item that does not exist.` }));
|
|
22936
22939
|
}
|
|
22940
|
+
var VARCHAR_DEFAULT_LIMIT = 255;
|
|
22941
|
+
var INTEGER_MIN = -2147483648;
|
|
22942
|
+
var INTEGER_MAX = 2147483647;
|
|
22943
|
+
var DECIMAL_LIMIT = 1e6;
|
|
22944
|
+
var ISO_TIMESTAMP = /^(\d{4})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2})?)?$/;
|
|
22945
|
+
var DECIMAL_STRING = /^-?\d+(?:\.\d+)?$/;
|
|
22946
|
+
var EMPTY_MEANS_NULL = /* @__PURE__ */ new Set(["date", "integer", "float", "enum"]);
|
|
22947
|
+
function emptyValuesToNull(fields, body, registry) {
|
|
22948
|
+
const out = { ...body };
|
|
22949
|
+
for (const f of fields) {
|
|
22950
|
+
if (!(f.name in out)) continue;
|
|
22951
|
+
const value = out[f.name];
|
|
22952
|
+
if (value === "" && EMPTY_MEANS_NULL.has(f.field_type)) {
|
|
22953
|
+
out[f.name] = null;
|
|
22954
|
+
continue;
|
|
22955
|
+
}
|
|
22956
|
+
if (f.field_type !== "paragraph") continue;
|
|
22957
|
+
const pType = paragraphTypeOf(f, registry);
|
|
22958
|
+
if (!pType) continue;
|
|
22959
|
+
if (isPlainObject(value)) out[f.name] = emptyValuesToNull(pType.fields, value, registry);
|
|
22960
|
+
else if (Array.isArray(value)) {
|
|
22961
|
+
out[f.name] = value.map((item) => isPlainObject(item) ? emptyValuesToNull(pType.fields, item, registry) : item);
|
|
22962
|
+
}
|
|
22963
|
+
}
|
|
22964
|
+
return out;
|
|
22965
|
+
}
|
|
22966
|
+
var compiled = /* @__PURE__ */ new Map();
|
|
22967
|
+
function patternOf(source) {
|
|
22968
|
+
if (!compiled.has(source)) {
|
|
22969
|
+
let re;
|
|
22970
|
+
try {
|
|
22971
|
+
re = new RegExp(source);
|
|
22972
|
+
} catch {
|
|
22973
|
+
re = null;
|
|
22974
|
+
}
|
|
22975
|
+
compiled.set(source, re);
|
|
22976
|
+
}
|
|
22977
|
+
return compiled.get(source) ?? null;
|
|
22978
|
+
}
|
|
22979
|
+
function isRealDate(value) {
|
|
22980
|
+
const m2 = ISO_TIMESTAMP.exec(value);
|
|
22981
|
+
if (!m2) return false;
|
|
22982
|
+
const [y, mo, d2, h = 0, mi2 = 0, sec = 0] = m2.slice(1).map((part) => part === void 0 ? void 0 : Number(part));
|
|
22983
|
+
if (y === void 0 || mo === void 0 || d2 === void 0 || y < 1) return false;
|
|
22984
|
+
const date2 = new Date(Date.UTC(y, mo - 1, d2));
|
|
22985
|
+
date2.setUTCFullYear(y);
|
|
22986
|
+
return date2.getUTCMonth() === mo - 1 && date2.getUTCDate() === d2 && h <= 23 && mi2 <= 59 && sec <= 59;
|
|
22987
|
+
}
|
|
22988
|
+
function valueError(f, value, name) {
|
|
22989
|
+
const v2 = f.validation;
|
|
22990
|
+
if (Array.isArray(value) && (f.field_type === "paragraph" || f.field_type === "reference")) {
|
|
22991
|
+
if (v2.max_items !== void 0 && value.length > v2.max_items) {
|
|
22992
|
+
return `${name} can hold at most ${v2.max_items} items.`;
|
|
22993
|
+
}
|
|
22994
|
+
return null;
|
|
22995
|
+
}
|
|
22996
|
+
const col = f.db_column;
|
|
22997
|
+
if (!col || col.junction || col.column_type === "uuid") return null;
|
|
22998
|
+
if (value === null || value === void 0) {
|
|
22999
|
+
if (col.nullable) return null;
|
|
23000
|
+
return f.required ? `${name} is required.` : `${name} cannot be empty.`;
|
|
23001
|
+
}
|
|
23002
|
+
switch (f.field_type) {
|
|
23003
|
+
case "text/plain": {
|
|
23004
|
+
if (typeof value !== "string") return `${name} must be text.`;
|
|
23005
|
+
if (value.includes("\0")) return `${name} contains a character that cannot be stored (U+0000).`;
|
|
23006
|
+
const limit = v2.limit ?? VARCHAR_DEFAULT_LIMIT;
|
|
23007
|
+
if ([...value].length > limit) return `${name} can be at most ${limit} characters.`;
|
|
23008
|
+
const pattern = v2.pattern === void 0 ? null : patternOf(v2.pattern);
|
|
23009
|
+
if (value !== "" && pattern && !pattern.test(value)) return `${name} is not in the correct format.`;
|
|
23010
|
+
return null;
|
|
23011
|
+
}
|
|
23012
|
+
case "text/rich":
|
|
23013
|
+
if (typeof value !== "string") return `${name} must be text.`;
|
|
23014
|
+
return value.includes("\0") ? `${name} contains a character that cannot be stored (U+0000).` : null;
|
|
23015
|
+
case "integer":
|
|
23016
|
+
if (typeof value !== "number" || !Number.isInteger(value)) return `${name} must be a whole number.`;
|
|
23017
|
+
if (value < INTEGER_MIN || value > INTEGER_MAX) {
|
|
23018
|
+
return `${name} must be between ${INTEGER_MIN} and ${INTEGER_MAX}.`;
|
|
23019
|
+
}
|
|
23020
|
+
return rangeError(name, value, v2.min, v2.max);
|
|
23021
|
+
case "float": {
|
|
23022
|
+
const n = typeof value === "number" ? value : typeof value === "string" && DECIMAL_STRING.test(value) ? Number(value) : NaN;
|
|
23023
|
+
if (!Number.isFinite(n)) return `${name} must be a number.`;
|
|
23024
|
+
if (roundedSize(typeof value === "string" ? value : String(n)) >= DECIMAL_LIMIT) {
|
|
23025
|
+
return `${name} must be less than ${DECIMAL_LIMIT} in size.`;
|
|
23026
|
+
}
|
|
23027
|
+
return rangeError(name, n, v2.min, v2.max);
|
|
23028
|
+
}
|
|
23029
|
+
case "boolean":
|
|
23030
|
+
return typeof value === "boolean" ? null : `${name} must be true or false.`;
|
|
23031
|
+
case "date":
|
|
23032
|
+
return typeof value === "string" && isRealDate(value) ? null : `${name} must be a date, such as 2026-10-11 or 2026-10-11T09:30:00Z.`;
|
|
23033
|
+
case "enum": {
|
|
23034
|
+
const allowed = v2.allowed_values ?? [];
|
|
23035
|
+
return typeof value === "string" && allowed.includes(value) ? null : `${name} must be one of: ${allowed.join(", ")}.`;
|
|
23036
|
+
}
|
|
23037
|
+
default:
|
|
23038
|
+
return null;
|
|
23039
|
+
}
|
|
23040
|
+
}
|
|
23041
|
+
function roundedSize(text2) {
|
|
23042
|
+
if (text2.includes("e")) return Math.abs(Number(text2));
|
|
23043
|
+
const [int = "0", frac = ""] = text2.replace("-", "").split(".");
|
|
23044
|
+
const kept = Number(`${int}.${frac.slice(0, 4) || "0"}`);
|
|
23045
|
+
return frac.length > 4 && frac.charAt(4) >= "5" ? kept + 1e-4 : kept;
|
|
23046
|
+
}
|
|
23047
|
+
function rangeError(name, value, min, max) {
|
|
23048
|
+
if (min !== void 0 && value < min) return `${name} must be at least ${min}.`;
|
|
23049
|
+
if (max !== void 0 && value > max) return `${name} must be at most ${max}.`;
|
|
23050
|
+
return null;
|
|
23051
|
+
}
|
|
23052
|
+
function checkFieldValues(fields, body, registry, path5 = "") {
|
|
23053
|
+
const errors = [];
|
|
23054
|
+
for (const f of fields) {
|
|
23055
|
+
if (!(f.name in body) || f.removed === true) continue;
|
|
23056
|
+
const name = `${path5}${f.name}`;
|
|
23057
|
+
const message = valueError(f, body[f.name], name);
|
|
23058
|
+
if (message) errors.push({ field: name, message });
|
|
23059
|
+
}
|
|
23060
|
+
for (const { item, fields: itemFields, prefix } of paragraphItemsIn(fields, body, registry, path5)) {
|
|
23061
|
+
errors.push(...checkFieldValues(itemFields, item, registry, prefix));
|
|
23062
|
+
}
|
|
23063
|
+
return errors;
|
|
23064
|
+
}
|
|
22937
23065
|
function quoteIdent3(name) {
|
|
22938
23066
|
if (!/^[a-z][a-z0-9_-]*$/.test(name)) throw new Error(`Unsafe identifier: ${name}`);
|
|
22939
23067
|
return `"${name}"`;
|
|
@@ -22969,7 +23097,7 @@ async function loadRelationsForEdit(db, registry, fields, id, row) {
|
|
|
22969
23097
|
} else if (f.db_column.junction) {
|
|
22970
23098
|
const j = f.db_column.junction;
|
|
22971
23099
|
const r = await db.execute(
|
|
22972
|
-
sql`SELECT ${sql.raw(quoteIdent3(j.right_column))} FROM ${sql.raw(quoteIdent3(j.table_name))} WHERE ${sql.raw(quoteIdent3(j.left_column))} = ${id}`
|
|
23100
|
+
sql`SELECT ${sql.raw(quoteIdent3(j.right_column))} FROM ${sql.raw(quoteIdent3(j.table_name))} WHERE ${sql.raw(quoteIdent3(j.left_column))} = ${id}${junctionOrderBy(j)}`
|
|
22973
23101
|
);
|
|
22974
23102
|
row[f.name] = r.rows.map((linked) => linked[j.right_column]);
|
|
22975
23103
|
}
|
|
@@ -23012,6 +23140,8 @@ async function relationInputError(c, fields, body, registry, db) {
|
|
|
23012
23140
|
const refuse = (message, details) => c.json({ ok: false, error: { code: "VALIDATION_ERROR", message, details } }, 422);
|
|
23013
23141
|
const shape = checkRelationInput(fields, body, registry);
|
|
23014
23142
|
if (shape.length > 0) return refuse("Relation fields have the wrong shape", shape);
|
|
23143
|
+
const values = checkFieldValues(fields, body, registry);
|
|
23144
|
+
if (values.length > 0) return refuse("Some values are not valid", values);
|
|
23015
23145
|
const required = checkRequiredInParagraphItems(fields, body, registry);
|
|
23016
23146
|
if (required.length > 0) return refuse("Required fields are missing", required);
|
|
23017
23147
|
if (db) {
|
|
@@ -23162,7 +23292,7 @@ function registerAdminContentRoutes(app, registry, repos, projectors, mediaRepo,
|
|
|
23162
23292
|
`/admin/api/${basePath}`,
|
|
23163
23293
|
requirePermission("content:create"),
|
|
23164
23294
|
async (c) => {
|
|
23165
|
-
const body = await c.req.json();
|
|
23295
|
+
const body = emptyValuesToNull(contentType.fields, await c.req.json(), registry);
|
|
23166
23296
|
if (contentType.only_one) {
|
|
23167
23297
|
const existing = await repo.findMany({ page: 1, per_page: 1 });
|
|
23168
23298
|
if (existing.meta.total > 0) {
|
|
@@ -23289,7 +23419,7 @@ function registerAdminContentRoutes(app, registry, repos, projectors, mediaRepo,
|
|
|
23289
23419
|
requirePermission("content:edit"),
|
|
23290
23420
|
async (c) => {
|
|
23291
23421
|
const id = c.req.param("id");
|
|
23292
|
-
const body = await c.req.json();
|
|
23422
|
+
const body = emptyValuesToNull(contentType.fields, await c.req.json(), registry);
|
|
23293
23423
|
const existing = await repo.findOne(id);
|
|
23294
23424
|
if (!existing) {
|
|
23295
23425
|
return c.json(
|
|
@@ -23396,7 +23526,7 @@ function registerAdminContentRoutes(app, registry, repos, projectors, mediaRepo,
|
|
|
23396
23526
|
`/admin/api/${basePath}`,
|
|
23397
23527
|
requirePermission("content:edit"),
|
|
23398
23528
|
async (c) => {
|
|
23399
|
-
const body = await c.req.json();
|
|
23529
|
+
const body = emptyValuesToNull(contentType.fields, await c.req.json(), registry);
|
|
23400
23530
|
const existingResult = await repo.findMany({ page: 1, per_page: 1 });
|
|
23401
23531
|
const existing = existingResult.data[0];
|
|
23402
23532
|
if (!existing) {
|
|
@@ -23523,7 +23653,7 @@ function registerAdminContentRoutes(app, registry, repos, projectors, mediaRepo,
|
|
|
23523
23653
|
`/admin/api/taxonomy/${typeName}`,
|
|
23524
23654
|
requirePermission("content:create"),
|
|
23525
23655
|
async (c) => {
|
|
23526
|
-
const body = await c.req.json();
|
|
23656
|
+
const body = emptyValuesToNull(taxonomyType.fields, await c.req.json(), registry);
|
|
23527
23657
|
const inputError = await relationInputError(c, taxonomyType.fields, body, registry, db);
|
|
23528
23658
|
if (inputError) return inputError;
|
|
23529
23659
|
const storageBody = fieldKeys.toStorage(body);
|
|
@@ -23571,7 +23701,7 @@ function registerAdminContentRoutes(app, registry, repos, projectors, mediaRepo,
|
|
|
23571
23701
|
requirePermission("content:edit"),
|
|
23572
23702
|
async (c) => {
|
|
23573
23703
|
const id = c.req.param("id");
|
|
23574
|
-
const body = await c.req.json();
|
|
23704
|
+
const body = emptyValuesToNull(taxonomyType.fields, await c.req.json(), registry);
|
|
23575
23705
|
const storageBody = fieldKeys.toStorage(body);
|
|
23576
23706
|
const existing = await repo.findOne(id);
|
|
23577
23707
|
if (!existing) {
|
|
@@ -24609,7 +24739,7 @@ function registerUserRoutes(app, db, requirePermission, requireHierarchy) {
|
|
|
24609
24739
|
}
|
|
24610
24740
|
var API_VERSION = (() => {
|
|
24611
24741
|
try {
|
|
24612
|
-
return "0.
|
|
24742
|
+
return "0.9.0";
|
|
24613
24743
|
} catch {
|
|
24614
24744
|
return "0.0.0";
|
|
24615
24745
|
}
|
|
@@ -25292,7 +25422,7 @@ function createCmsApp(options) {
|
|
|
25292
25422
|
handler: null,
|
|
25293
25423
|
error: null
|
|
25294
25424
|
}));
|
|
25295
|
-
const ready = import("./handler-
|
|
25425
|
+
const ready = import("./handler-MFF32JB4-MEMKPHHQ.js").then(({ createGraphQLHandler }) => {
|
|
25296
25426
|
gqlPasses.forEach((pass, i) => {
|
|
25297
25427
|
const mount = mounts[i];
|
|
25298
25428
|
try {
|
|
@@ -25570,18 +25700,18 @@ async function runDev(options, deps) {
|
|
|
25570
25700
|
await mkdir2(manguitoDir, { recursive: true });
|
|
25571
25701
|
const drizzleConfigPath = resolve6(manguitoDir, "drizzle.config.ts");
|
|
25572
25702
|
const needsSeed = !await db.tableExists("users");
|
|
25573
|
-
const
|
|
25574
|
-
|
|
25575
|
-
|
|
25576
|
-
printValidationErrors(crossRefErrors, "Schema reference errors", "manguito validate");
|
|
25703
|
+
const loaded = loadValidatedSchema(cwd, config2);
|
|
25704
|
+
if (!loaded.ok) {
|
|
25705
|
+
printValidationErrors(loaded.errors, "Schema errors", "manguito validate");
|
|
25577
25706
|
process.exit(1);
|
|
25578
25707
|
}
|
|
25708
|
+
const { registry, versionModel } = loaded.value;
|
|
25579
25709
|
await generateDrizzleConfig(config2, manguitoDir);
|
|
25580
|
-
await writeFile9(join11(manguitoDir, "schema.ts"), generateSchemaFile(
|
|
25710
|
+
await writeFile9(join11(manguitoDir, "schema.ts"), generateSchemaFile(registry), "utf8");
|
|
25581
25711
|
await runDevMigration(drizzleConfigPath);
|
|
25582
25712
|
printSuccess(needsSeed ? "Schema tables created" : "Schema tables up to date");
|
|
25583
25713
|
if (needsSeed) {
|
|
25584
|
-
await seedSystemTables(db.getDb(),
|
|
25714
|
+
await seedSystemTables(db.getDb(), registry);
|
|
25585
25715
|
printSuccess("System tables seeded");
|
|
25586
25716
|
}
|
|
25587
25717
|
const adminCountResult = await db.getDb().execute(sql`
|
|
@@ -25614,7 +25744,6 @@ async function runDev(options, deps) {
|
|
|
25614
25744
|
process.stdout.write("\n");
|
|
25615
25745
|
printSuccess("Admin account created");
|
|
25616
25746
|
}
|
|
25617
|
-
const registry = bootstrapRegistry;
|
|
25618
25747
|
const contentCount = Object.keys(registry.content_types).length;
|
|
25619
25748
|
const paragraphCount = Object.keys(registry.paragraph_types).length;
|
|
25620
25749
|
const taxonomyCount = Object.keys(registry.taxonomy_types).length;
|
|
@@ -25625,12 +25754,6 @@ async function runDev(options, deps) {
|
|
|
25625
25754
|
await generateRoutes2(registry, manguitoDir);
|
|
25626
25755
|
await generateForms(registry, join11(manguitoDir, "forms"));
|
|
25627
25756
|
await generateNav(registry, manguitoDir);
|
|
25628
|
-
const versionsResult = loadProjectVersionModel(resolveSchemaConfig(cwd, config2), registry);
|
|
25629
|
-
if (!versionsResult.ok) {
|
|
25630
|
-
printValidationErrors(versionsResult.errors, "Version model errors", "manguito validate");
|
|
25631
|
-
process.exit(1);
|
|
25632
|
-
}
|
|
25633
|
-
const versionModel = reduceVersionModel(versionsResult.value.model);
|
|
25634
25757
|
const resolverMap = await loadProgrammaticResolvers(cwd, config2.programmatic.dir);
|
|
25635
25758
|
const adapter = createCmsApp({
|
|
25636
25759
|
name: config2.name,
|
|
@@ -25718,7 +25841,7 @@ async function runDev(options, deps) {
|
|
|
25718
25841
|
void (async () => {
|
|
25719
25842
|
for await (const event of watcher) {
|
|
25720
25843
|
if (event.filename && /\.(json|ya?ml)$/.test(event.filename)) {
|
|
25721
|
-
await
|
|
25844
|
+
await reloadSafely({
|
|
25722
25845
|
cwd,
|
|
25723
25846
|
config: config2,
|
|
25724
25847
|
manguitoDir,
|
|
@@ -25738,7 +25861,7 @@ async function runDev(options, deps) {
|
|
|
25738
25861
|
void (async () => {
|
|
25739
25862
|
for await (const event of progWatcher) {
|
|
25740
25863
|
if (event.filename && /\.(ts|mjs|js)$/.test(event.filename)) {
|
|
25741
|
-
await
|
|
25864
|
+
await reloadSafely({
|
|
25742
25865
|
cwd,
|
|
25743
25866
|
config: config2,
|
|
25744
25867
|
manguitoDir,
|
|
@@ -25754,34 +25877,32 @@ async function runDev(options, deps) {
|
|
|
25754
25877
|
})();
|
|
25755
25878
|
}
|
|
25756
25879
|
}
|
|
25757
|
-
async function
|
|
25758
|
-
const { cwd, config: config2, manguitoDir, drizzleConfigPath, db, updateFetch, getResolvers } = args;
|
|
25759
|
-
let registry;
|
|
25880
|
+
async function reloadSafely(args) {
|
|
25760
25881
|
try {
|
|
25761
|
-
|
|
25762
|
-
} catch {
|
|
25763
|
-
process.stderr.write(
|
|
25764
|
-
|
|
25882
|
+
await onSchemaFileChange(args);
|
|
25883
|
+
} catch (err) {
|
|
25884
|
+
process.stderr.write(
|
|
25885
|
+
`\u26A0 Reload failed: ${err instanceof Error ? err.message : String(err)}
|
|
25886
|
+
\u26A0 Still serving the previous version.
|
|
25887
|
+
`
|
|
25888
|
+
);
|
|
25765
25889
|
}
|
|
25766
|
-
|
|
25767
|
-
|
|
25768
|
-
|
|
25890
|
+
}
|
|
25891
|
+
async function onSchemaFileChange(args) {
|
|
25892
|
+
const { cwd, config: config2, manguitoDir, drizzleConfigPath, db, updateFetch, getResolvers } = args;
|
|
25893
|
+
const loaded = loadValidatedSchema(cwd, config2);
|
|
25894
|
+
if (!loaded.ok) {
|
|
25895
|
+
printValidationErrors(loaded.errors, "Schema errors", "manguito validate");
|
|
25769
25896
|
process.stderr.write("\u26A0 Changes not applied.\n");
|
|
25770
25897
|
return;
|
|
25771
25898
|
}
|
|
25899
|
+
const { registry, versionModel } = loaded.value;
|
|
25772
25900
|
await generateDrizzleConfig(config2, manguitoDir);
|
|
25773
25901
|
await writeFile9(join11(manguitoDir, "schema.ts"), generateSchemaFile(registry), "utf8");
|
|
25774
25902
|
await generateSchemaRegistry(registry, manguitoDir);
|
|
25775
25903
|
await generateRoutes2(registry, manguitoDir);
|
|
25776
25904
|
await generateForms(registry, join11(manguitoDir, "forms"));
|
|
25777
25905
|
await generateNav(registry, manguitoDir);
|
|
25778
|
-
const versionsResult = loadProjectVersionModel(resolveSchemaConfig(cwd, config2), registry);
|
|
25779
|
-
if (!versionsResult.ok) {
|
|
25780
|
-
printValidationErrors(versionsResult.errors, "Version model errors", "manguito validate");
|
|
25781
|
-
process.stderr.write("\u26A0 Changes not applied.\n");
|
|
25782
|
-
return;
|
|
25783
|
-
}
|
|
25784
|
-
const versionModel = reduceVersionModel(versionsResult.value.model);
|
|
25785
25906
|
try {
|
|
25786
25907
|
await runDevMigration(drizzleConfigPath);
|
|
25787
25908
|
} catch (err) {
|
|
@@ -25806,46 +25927,40 @@ async function onSchemaFileChange(args) {
|
|
|
25806
25927
|
updateFetch((req) => newAdapter.app.fetch(req));
|
|
25807
25928
|
printSuccess("Schema updated");
|
|
25808
25929
|
}
|
|
25809
|
-
|
|
25930
|
+
function loadValidatedSchema(cwd, config2) {
|
|
25931
|
+
const parsed = parseAllSchemas(cwd, config2);
|
|
25932
|
+
if (!parsed.ok) return parsed;
|
|
25933
|
+
const registry = parsed.value;
|
|
25934
|
+
const crossRefErrors = validateCrossReferences(registry, config2.api.media?.max_file_size);
|
|
25935
|
+
if (crossRefErrors.length > 0) return { ok: false, errors: crossRefErrors };
|
|
25936
|
+
const versions = loadProjectVersionModel(resolveSchemaConfig(cwd, config2), registry);
|
|
25937
|
+
if (!versions.ok) return { ok: false, errors: versions.errors };
|
|
25938
|
+
printSchemaDeprecations(findSchemaDeprecations(registry));
|
|
25939
|
+
return { ok: true, value: { registry, versionModel: reduceVersionModel(versions.value.model) } };
|
|
25940
|
+
}
|
|
25941
|
+
function parseAllSchemas(cwd, config2) {
|
|
25942
|
+
const errors = [];
|
|
25810
25943
|
const parsedSchemas = [];
|
|
25811
25944
|
const walkResult = walkSchemaDirectory(config2.schema);
|
|
25812
25945
|
if (!walkResult.ok) {
|
|
25813
|
-
|
|
25814
|
-
|
|
25815
|
-
|
|
25816
|
-
|
|
25817
|
-
|
|
25818
|
-
|
|
25819
|
-
printGuidedError("Schema parse errors \u2014 run `manguito validate` for details.");
|
|
25820
|
-
process.exit(1);
|
|
25946
|
+
errors.push(...walkResult.errors);
|
|
25947
|
+
} else {
|
|
25948
|
+
for (const file of walkResult.value) {
|
|
25949
|
+
const parseResult = parseSchema(file.raw, file.schema_type, file.path);
|
|
25950
|
+
if (parseResult.ok) parsedSchemas.push(parseResult.schema);
|
|
25951
|
+
else errors.push(...parseResult.errors);
|
|
25821
25952
|
}
|
|
25822
|
-
parsedSchemas.push(parseResult.schema);
|
|
25823
25953
|
}
|
|
25824
25954
|
const rolesPath = resolve6(cwd, config2.schema.base_path, "roles.json");
|
|
25825
25955
|
const rolesLoad = loadSchemaFile(rolesPath);
|
|
25826
|
-
|
|
25827
|
-
|
|
25828
|
-
process.exit(1);
|
|
25829
|
-
}
|
|
25830
|
-
const rolesResult = parseRoles(rolesLoad.value, rolesPath);
|
|
25831
|
-
if (!rolesResult.ok) {
|
|
25832
|
-
printGuidedError("roles.json parse errors \u2014 run `manguito validate` for details.");
|
|
25833
|
-
process.exit(1);
|
|
25834
|
-
}
|
|
25956
|
+
const rolesResult = rolesLoad.ok ? parseRoles(rolesLoad.value, rolesPath) : rolesLoad;
|
|
25957
|
+
if (!rolesResult.ok) errors.push(...rolesResult.errors);
|
|
25835
25958
|
const routesPath = resolve6(cwd, config2.schema.base_path, "routes.json");
|
|
25836
25959
|
const routesLoad = loadSchemaFile(routesPath);
|
|
25837
|
-
|
|
25838
|
-
|
|
25839
|
-
|
|
25840
|
-
}
|
|
25841
|
-
const routesResult = parseRoutes(routesLoad.value, routesPath);
|
|
25842
|
-
if (!routesResult.ok) {
|
|
25843
|
-
printGuidedError("routes.json parse errors \u2014 run `manguito validate` for details.");
|
|
25844
|
-
process.exit(1);
|
|
25845
|
-
}
|
|
25846
|
-
const registry = buildSchemaRegistry(parsedSchemas, routesResult.value, rolesResult.value);
|
|
25847
|
-
printSchemaDeprecations(findSchemaDeprecations(registry));
|
|
25848
|
-
return registry;
|
|
25960
|
+
const routesResult = routesLoad.ok ? parseRoutes(routesLoad.value, routesPath) : routesLoad;
|
|
25961
|
+
if (!routesResult.ok) errors.push(...routesResult.errors);
|
|
25962
|
+
if (errors.length > 0 || !rolesResult.ok || !routesResult.ok) return { ok: false, errors };
|
|
25963
|
+
return { ok: true, value: buildSchemaRegistry(parsedSchemas, routesResult.value, rolesResult.value) };
|
|
25849
25964
|
}
|
|
25850
25965
|
function resolveAdminRoot2(cwd) {
|
|
25851
25966
|
const cwdRequire = createRequire2(join11(cwd, "package.json"));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobbykim/manguito-cms-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Bobby Kim <bobby.sihun.kim@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/bobbykim89/manguito-cms",
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
"tsup": "^8.5.1",
|
|
30
30
|
"typescript": "^6.0.3",
|
|
31
31
|
"vite": "^8.1.3",
|
|
32
|
-
"@bobbykim/manguito-cms-admin": "0.5.
|
|
33
|
-
"@bobbykim/manguito-cms-api": "0.
|
|
34
|
-
"@bobbykim/manguito-cms-core": "0.
|
|
35
|
-
"@bobbykim/manguito-cms-db": "0.1.
|
|
32
|
+
"@bobbykim/manguito-cms-admin": "0.5.4",
|
|
33
|
+
"@bobbykim/manguito-cms-api": "0.9.0",
|
|
34
|
+
"@bobbykim/manguito-cms-core": "0.10.0",
|
|
35
|
+
"@bobbykim/manguito-cms-db": "0.1.10"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/node": "^25.9.5",
|