@bobbykim/manguito-cms-cli 0.11.2 → 0.11.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.
|
@@ -9270,7 +9270,7 @@ var require_bcryptjs = __commonJS({
|
|
|
9270
9270
|
}
|
|
9271
9271
|
});
|
|
9272
9272
|
|
|
9273
|
-
// ../api/dist/chunk-
|
|
9273
|
+
// ../api/dist/chunk-IFE2L4VM.mjs
|
|
9274
9274
|
init_esm_shims();
|
|
9275
9275
|
import crypto from "crypto";
|
|
9276
9276
|
|
|
@@ -25308,6 +25308,7 @@ function validateCrossReferences(registry2, globalMaxFileSize) {
|
|
|
25308
25308
|
errors.push(...checkFieldRefs(registry2));
|
|
25309
25309
|
errors.push(...checkCircularParagraphRefs(registry2));
|
|
25310
25310
|
errors.push(...checkParagraphRelations(registry2));
|
|
25311
|
+
errors.push(...checkTableNameCollisions(registry2));
|
|
25311
25312
|
if (globalMaxFileSize !== void 0) {
|
|
25312
25313
|
errors.push(...checkMaxSizeLimit(registry2, globalMaxFileSize));
|
|
25313
25314
|
}
|
|
@@ -25328,6 +25329,58 @@ function checkParagraphRelations(registry2) {
|
|
|
25328
25329
|
}
|
|
25329
25330
|
return errors;
|
|
25330
25331
|
}
|
|
25332
|
+
var POSTGRES_IDENTIFIER_LIMIT = 63;
|
|
25333
|
+
function rawFieldPath(owner, field) {
|
|
25334
|
+
if (owner.schema_type !== "content-type") return `fields[${field.order}].name`;
|
|
25335
|
+
const t = owner.ui.tabs.findIndex((tab) => tab.fields.includes(field.name));
|
|
25336
|
+
const i = t < 0 ? -1 : owner.ui.tabs[t].fields.indexOf(field.name);
|
|
25337
|
+
return t < 0 ? `fields[${field.order}].name` : `fields[${t}].tab.fields[${i}].name`;
|
|
25338
|
+
}
|
|
25339
|
+
function checkTableNameCollisions(registry2) {
|
|
25340
|
+
const uses = [];
|
|
25341
|
+
for (const p of Object.values(registry2.paragraph_types)) {
|
|
25342
|
+
uses.push({ table: p.db.table_name, file: p.source_file, what: `type "${p.name}"`, shorten: `shorten the name of type "${p.name}"` });
|
|
25343
|
+
}
|
|
25344
|
+
for (const owner of [...Object.values(registry2.content_types), ...Object.values(registry2.taxonomy_types)]) {
|
|
25345
|
+
uses.push({
|
|
25346
|
+
table: owner.db.table_name,
|
|
25347
|
+
file: owner.source_file,
|
|
25348
|
+
what: `type "${owner.name}"`,
|
|
25349
|
+
shorten: `shorten the name of type "${owner.name}"`
|
|
25350
|
+
});
|
|
25351
|
+
for (const jt of owner.db.junction_tables) {
|
|
25352
|
+
const field = owner.fields.find((f) => f.db_column?.junction?.table_name === jt.table_name);
|
|
25353
|
+
if (!field) continue;
|
|
25354
|
+
const prefix = `junction_${owner.db.table_name}_`.length;
|
|
25355
|
+
const room = POSTGRES_IDENTIFIER_LIMIT - prefix;
|
|
25356
|
+
uses.push({
|
|
25357
|
+
table: jt.table_name,
|
|
25358
|
+
file: owner.source_file,
|
|
25359
|
+
what: `field "${field.name}" of "${owner.name}"`,
|
|
25360
|
+
shorten: room < 1 ? `shorten the name of type "${owner.name}": its link table names already have ${prefix} characters before the field name` : `shorten field "${field.name}" to at most ${room} characters, or the name of type "${owner.name}"`,
|
|
25361
|
+
path: rawFieldPath(owner, field)
|
|
25362
|
+
});
|
|
25363
|
+
}
|
|
25364
|
+
}
|
|
25365
|
+
const errors = [];
|
|
25366
|
+
const first = /* @__PURE__ */ new Map();
|
|
25367
|
+
for (const use of uses) {
|
|
25368
|
+
const stored = use.table.slice(0, POSTGRES_IDENTIFIER_LIMIT);
|
|
25369
|
+
const earlier = first.get(stored);
|
|
25370
|
+
if (!earlier) {
|
|
25371
|
+
first.set(stored, use);
|
|
25372
|
+
continue;
|
|
25373
|
+
}
|
|
25374
|
+
const tooLong = use.table.length > POSTGRES_IDENTIFIER_LIMIT ? use : earlier;
|
|
25375
|
+
errors.push({
|
|
25376
|
+
file: use.file,
|
|
25377
|
+
code: "TABLE_NAME_COLLISION",
|
|
25378
|
+
message: earlier.table === use.table ? `The ${use.what} would store its data in table "${use.table}", the same table as the ${earlier.what}. Rename one of the two so their tables differ.` : `The ${use.what} and the ${earlier.what} would get tables "${use.table}" and "${earlier.table}". Postgres keeps only the first ${POSTGRES_IDENTIFIER_LIMIT} characters of a name, which are the same, so they would be one table. To keep "${tooLong.table}" within ${POSTGRES_IDENTIFIER_LIMIT} characters, ${tooLong.shorten}.`,
|
|
25379
|
+
...use.path !== void 0 && { path: use.path }
|
|
25380
|
+
});
|
|
25381
|
+
}
|
|
25382
|
+
return errors;
|
|
25383
|
+
}
|
|
25331
25384
|
function checkDuplicateSchemaNames(allSchemas) {
|
|
25332
25385
|
const errors = [];
|
|
25333
25386
|
const seen = /* @__PURE__ */ new Map();
|
|
@@ -25904,7 +25957,17 @@ function checkDuplicateColumns(fields, sourceFile, schemaName) {
|
|
|
25904
25957
|
for (const f of fields) {
|
|
25905
25958
|
if (!hasStorageColumn(f)) continue;
|
|
25906
25959
|
const column = f.column ?? f.name;
|
|
25907
|
-
const
|
|
25960
|
+
const stored = column.slice(0, 63);
|
|
25961
|
+
const firstUse = owner.get(stored);
|
|
25962
|
+
if (firstUse !== void 0 && firstUse.column !== column) {
|
|
25963
|
+
errors.push({
|
|
25964
|
+
file: sourceFile,
|
|
25965
|
+
code: "DUPLICATE_COLUMN",
|
|
25966
|
+
message: `Fields "${firstUse.field}" and "${f.name}" in schema "${schemaName}" resolve to columns "${firstUse.column}" and "${column}". Postgres keeps only the first 63 characters of a column name, which are the same, so they would be one column. Shorten one of the field names to at most 63 characters.`
|
|
25967
|
+
});
|
|
25968
|
+
continue;
|
|
25969
|
+
}
|
|
25970
|
+
const first = firstUse?.field;
|
|
25908
25971
|
if (first !== void 0) {
|
|
25909
25972
|
errors.push({
|
|
25910
25973
|
file: sourceFile,
|
|
@@ -25913,7 +25976,7 @@ function checkDuplicateColumns(fields, sourceFile, schemaName) {
|
|
|
25913
25976
|
});
|
|
25914
25977
|
continue;
|
|
25915
25978
|
}
|
|
25916
|
-
owner.set(
|
|
25979
|
+
owner.set(stored, { field: f.name, column });
|
|
25917
25980
|
}
|
|
25918
25981
|
return errors;
|
|
25919
25982
|
}
|
|
@@ -26618,7 +26681,7 @@ function describeSchemaChange(input) {
|
|
|
26618
26681
|
return { from: from?.version ?? null, to: to.version, types, identical };
|
|
26619
26682
|
}
|
|
26620
26683
|
|
|
26621
|
-
// ../api/dist/chunk-
|
|
26684
|
+
// ../api/dist/chunk-IFE2L4VM.mjs
|
|
26622
26685
|
function isColumnBacked2(field) {
|
|
26623
26686
|
const col = field.db_column;
|
|
26624
26687
|
if (col === null) return false;
|
|
@@ -26725,10 +26788,131 @@ function createFieldKeyMapFromProjection(projectionType, allFields) {
|
|
|
26725
26788
|
droppedLabels
|
|
26726
26789
|
);
|
|
26727
26790
|
}
|
|
26791
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
26792
|
+
function isUuid(v) {
|
|
26793
|
+
return typeof v === "string" && UUID_RE.test(v);
|
|
26794
|
+
}
|
|
26795
|
+
function isPlainObject2(v) {
|
|
26796
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
26797
|
+
}
|
|
26798
|
+
function checkRelationInput(fields, body, registry2, path4 = "") {
|
|
26799
|
+
const errors = [];
|
|
26800
|
+
for (const field of fields) {
|
|
26801
|
+
if (!Object.hasOwn(body, field.name)) continue;
|
|
26802
|
+
const cardinality = relationCardinality(field);
|
|
26803
|
+
if (cardinality === null) continue;
|
|
26804
|
+
const value = body[field.name];
|
|
26805
|
+
const name = `${path4}${field.name}`;
|
|
26806
|
+
if (field.field_type === "reference") {
|
|
26807
|
+
const ok = cardinality === "one" ? value === null || isUuid(value) : Array.isArray(value) && value.every(isUuid);
|
|
26808
|
+
if (!ok) {
|
|
26809
|
+
errors.push({
|
|
26810
|
+
field: name,
|
|
26811
|
+
message: cardinality === "one" ? `${name} holds one item: send a UUID string or null.` : `${name} holds a list: send an array of UUID strings.`
|
|
26812
|
+
});
|
|
26813
|
+
}
|
|
26814
|
+
continue;
|
|
26815
|
+
}
|
|
26816
|
+
const items = cardinality === "one" ? value === null ? [] : isPlainObject2(value) ? [value] : void 0 : Array.isArray(value) && value.every(isPlainObject2) ? value : void 0;
|
|
26817
|
+
if (items === void 0) {
|
|
26818
|
+
errors.push({
|
|
26819
|
+
field: name,
|
|
26820
|
+
message: cardinality === "one" ? `${name} holds one item: send an object or null.` : `${name} holds a list: send an array of objects.`
|
|
26821
|
+
});
|
|
26822
|
+
continue;
|
|
26823
|
+
}
|
|
26824
|
+
const pType = paragraphTypeOf(field, registry2);
|
|
26825
|
+
if (!pType) continue;
|
|
26826
|
+
items.forEach((item, i) => {
|
|
26827
|
+
const prefix = cardinality === "one" ? `${name}.` : `${name}[${i}].`;
|
|
26828
|
+
errors.push(...checkRelationInput(pType.fields, item, registry2, prefix));
|
|
26829
|
+
});
|
|
26830
|
+
}
|
|
26831
|
+
return errors;
|
|
26832
|
+
}
|
|
26833
|
+
function paragraphTypeOf(field, registry2) {
|
|
26834
|
+
const comp = field.ui_component;
|
|
26835
|
+
return comp.component === "paragraph-embed" ? registry2.paragraph_types[comp.ref] : void 0;
|
|
26836
|
+
}
|
|
26837
|
+
function paragraphItemsIn(fields, body, registry2, path4) {
|
|
26838
|
+
const out = [];
|
|
26839
|
+
for (const field of fields) {
|
|
26840
|
+
if (field.field_type !== "paragraph" || !Object.hasOwn(body, field.name)) continue;
|
|
26841
|
+
const pType = paragraphTypeOf(field, registry2);
|
|
26842
|
+
if (!pType) continue;
|
|
26843
|
+
const value = body[field.name];
|
|
26844
|
+
const name = `${path4}${field.name}`;
|
|
26845
|
+
if (relationCardinality(field) === "one") {
|
|
26846
|
+
if (isPlainObject2(value)) out.push({ item: value, fields: pType.fields, prefix: `${name}.` });
|
|
26847
|
+
} else if (Array.isArray(value)) {
|
|
26848
|
+
value.forEach((item, i) => {
|
|
26849
|
+
if (isPlainObject2(item)) out.push({ item, fields: pType.fields, prefix: `${name}[${i}].` });
|
|
26850
|
+
});
|
|
26851
|
+
}
|
|
26852
|
+
}
|
|
26853
|
+
return out;
|
|
26854
|
+
}
|
|
26855
|
+
function isMissing(value) {
|
|
26856
|
+
if (value === null || value === void 0) return true;
|
|
26857
|
+
if (typeof value === "string" && value.trim() === "") return true;
|
|
26858
|
+
if (Array.isArray(value) && value.length === 0) return true;
|
|
26859
|
+
return false;
|
|
26860
|
+
}
|
|
26861
|
+
function checkRequiredInParagraphItems(fields, body, registry2, path4 = "") {
|
|
26862
|
+
const errors = [];
|
|
26863
|
+
for (const { item, fields: itemFields, prefix } of paragraphItemsIn(fields, body, registry2, path4)) {
|
|
26864
|
+
for (const f of itemFields) {
|
|
26865
|
+
if (!f.required || f.removed === true || !f.db_column || f.db_column.junction) continue;
|
|
26866
|
+
if (isMissing(item[f.name])) {
|
|
26867
|
+
errors.push({ field: `${prefix}${f.name}`, message: `${prefix}${f.name} is required.` });
|
|
26868
|
+
}
|
|
26869
|
+
}
|
|
26870
|
+
errors.push(...checkRequiredInParagraphItems(itemFields, item, registry2, prefix));
|
|
26871
|
+
}
|
|
26872
|
+
return errors;
|
|
26873
|
+
}
|
|
26728
26874
|
function quoteIdent(name) {
|
|
26729
26875
|
if (!/^[a-z][a-z0-9_-]*$/.test(name)) throw new Error(`Unsafe identifier: ${name}`);
|
|
26730
26876
|
return `"${name}"`;
|
|
26731
26877
|
}
|
|
26878
|
+
function collectReferences(fields, body, registry2, path4, out) {
|
|
26879
|
+
for (const f of fields) {
|
|
26880
|
+
if (!Object.hasOwn(body, f.name) || !f.db_column) continue;
|
|
26881
|
+
const table = f.db_column.junction ? f.db_column.junction.right_table : f.db_column.foreign_key?.table;
|
|
26882
|
+
if (!table) continue;
|
|
26883
|
+
const value = body[f.name];
|
|
26884
|
+
const name = `${path4}${f.name}`;
|
|
26885
|
+
if (typeof value === "string") {
|
|
26886
|
+
out.push({ table, id: value, field: name });
|
|
26887
|
+
} else if (Array.isArray(value)) {
|
|
26888
|
+
value.forEach((v, i) => {
|
|
26889
|
+
if (typeof v === "string") out.push({ table, id: v, field: `${name}[${i}]` });
|
|
26890
|
+
});
|
|
26891
|
+
}
|
|
26892
|
+
}
|
|
26893
|
+
for (const { item, fields: itemFields, prefix } of paragraphItemsIn(fields, body, registry2, path4)) {
|
|
26894
|
+
collectReferences(itemFields, item, registry2, prefix, out);
|
|
26895
|
+
}
|
|
26896
|
+
}
|
|
26897
|
+
async function findMissingReferences(db, fields, body, registry2) {
|
|
26898
|
+
const uses = [];
|
|
26899
|
+
collectReferences(fields, body, registry2, "", uses);
|
|
26900
|
+
if (uses.length === 0) return [];
|
|
26901
|
+
const lookups = [...new Set(uses.map((u) => u.table))].map(async (table) => {
|
|
26902
|
+
const ids = [...new Set(uses.filter((u) => u.table === table && isUuid(u.id)).map((u) => u.id.toLowerCase()))];
|
|
26903
|
+
if (ids.length === 0) return [table, /* @__PURE__ */ new Set()];
|
|
26904
|
+
const result = await db.execute(
|
|
26905
|
+
sql`SELECT id FROM ${sql.raw(quoteIdent(table))} WHERE id IN (${sql.join(ids.map((id) => sql`${id}`), sql`, `)})`
|
|
26906
|
+
);
|
|
26907
|
+
return [table, new Set(result.rows.map((r) => String(r.id).toLowerCase()))];
|
|
26908
|
+
});
|
|
26909
|
+
const found = new Map(await Promise.all(lookups));
|
|
26910
|
+
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.` }));
|
|
26911
|
+
}
|
|
26912
|
+
function quoteIdent2(name) {
|
|
26913
|
+
if (!/^[a-z][a-z0-9_-]*$/.test(name)) throw new Error(`Unsafe identifier: ${name}`);
|
|
26914
|
+
return `"${name}"`;
|
|
26915
|
+
}
|
|
26732
26916
|
function paragraphMediaFieldNames(pType) {
|
|
26733
26917
|
return new Set(
|
|
26734
26918
|
pType.fields.filter((f) => f.field_type === "image" || f.field_type === "video" || f.field_type === "file").map((f) => f.name)
|
|
@@ -26737,8 +26921,8 @@ function paragraphMediaFieldNames(pType) {
|
|
|
26737
26921
|
async function fetchParagraphMediaIds(db, pType, itemId, fieldName) {
|
|
26738
26922
|
const mediaColumns = pType.fields.filter((f) => f.field_type === "image" || f.field_type === "video" || f.field_type === "file").map((f) => f.db_column.column_name);
|
|
26739
26923
|
if (mediaColumns.length === 0) return [];
|
|
26740
|
-
const tbl = sql.raw(
|
|
26741
|
-
const cols = sql.join(mediaColumns.map((c) => sql.raw(
|
|
26924
|
+
const tbl = sql.raw(quoteIdent2(pType.db.table_name));
|
|
26925
|
+
const cols = sql.join(mediaColumns.map((c) => sql.raw(quoteIdent2(c))), sql`, `);
|
|
26742
26926
|
const result = await db.execute(
|
|
26743
26927
|
sql`SELECT ${cols} FROM ${tbl} WHERE parent_id = ${itemId} AND parent_field = ${fieldName}`
|
|
26744
26928
|
);
|
|
@@ -26756,20 +26940,37 @@ function nestedParagraphFields(pType, registry2) {
|
|
|
26756
26940
|
const out = [];
|
|
26757
26941
|
for (const f of pType.fields) {
|
|
26758
26942
|
if (f.db_column !== null) continue;
|
|
26759
|
-
const
|
|
26760
|
-
if (comp.component !== "paragraph-embed" || !comp.ref) continue;
|
|
26761
|
-
const nType = registry2.paragraph_types[comp.ref];
|
|
26943
|
+
const nType = paragraphTypeOf(f, registry2);
|
|
26762
26944
|
if (nType) out.push({ fieldName: f.name, nType, field: f });
|
|
26763
26945
|
}
|
|
26764
26946
|
return out;
|
|
26765
26947
|
}
|
|
26766
26948
|
async function fetchParagraphRowIds(db, pType, itemId, fieldName) {
|
|
26767
|
-
const tbl = sql.raw(
|
|
26949
|
+
const tbl = sql.raw(quoteIdent2(pType.db.table_name));
|
|
26768
26950
|
const result = await db.execute(
|
|
26769
26951
|
sql`SELECT id FROM ${tbl} WHERE parent_id = ${itemId} AND parent_field = ${fieldName}`
|
|
26770
26952
|
);
|
|
26771
26953
|
return result.rows.map((r) => r["id"]).filter((id) => typeof id === "string");
|
|
26772
26954
|
}
|
|
26955
|
+
async function ownParagraphRowIds(db, registry2, fields, itemId) {
|
|
26956
|
+
const ids = [];
|
|
26957
|
+
for (const f of fields) {
|
|
26958
|
+
const pType = paragraphTypeOf(f, registry2);
|
|
26959
|
+
if (!pType) continue;
|
|
26960
|
+
const rowIds = await fetchParagraphRowIds(db, pType, itemId, f.name);
|
|
26961
|
+
ids.push(...rowIds);
|
|
26962
|
+
if (rowIds.length === 0) continue;
|
|
26963
|
+
for (const n of nestedParagraphFields(pType, registry2)) {
|
|
26964
|
+
const result = await db.execute(
|
|
26965
|
+
sql`SELECT id FROM ${sql.raw(quoteIdent2(n.nType.db.table_name))} WHERE parent_id = ANY(${sql.param(rowIds)}::uuid[]) AND parent_field = ${n.fieldName}`
|
|
26966
|
+
);
|
|
26967
|
+
for (const r of result.rows) {
|
|
26968
|
+
if (typeof r["id"] === "string") ids.push(r["id"]);
|
|
26969
|
+
}
|
|
26970
|
+
}
|
|
26971
|
+
}
|
|
26972
|
+
return ids;
|
|
26973
|
+
}
|
|
26773
26974
|
async function persistParagraphField(db, itemId, parentType, fieldName, pType, items, registry2) {
|
|
26774
26975
|
const removed = await fetchParagraphMediaIds(db, pType, itemId, fieldName);
|
|
26775
26976
|
const nested = nestedParagraphFields(pType, registry2);
|
|
@@ -26782,7 +26983,7 @@ async function persistParagraphField(db, itemId, parentType, fieldName, pType, i
|
|
|
26782
26983
|
}
|
|
26783
26984
|
}
|
|
26784
26985
|
}
|
|
26785
|
-
const tbl = sql.raw(
|
|
26986
|
+
const tbl = sql.raw(quoteIdent2(pType.db.table_name));
|
|
26786
26987
|
await db.execute(sql`DELETE FROM ${tbl} WHERE parent_id = ${itemId} AND parent_field = ${fieldName}`);
|
|
26787
26988
|
const mediaFieldNames = paragraphMediaFieldNames(pType);
|
|
26788
26989
|
const added = [];
|
|
@@ -26802,7 +27003,7 @@ async function persistParagraphField(db, itemId, parentType, fieldName, pType, i
|
|
|
26802
27003
|
if (!pf.db_column || pf.db_column.junction) continue;
|
|
26803
27004
|
data[pf.db_column.column_name] = pItem[pf.name] ?? null;
|
|
26804
27005
|
}
|
|
26805
|
-
const cols = sql.join(Object.keys(data).map((k) => sql.raw(
|
|
27006
|
+
const cols = sql.join(Object.keys(data).map((k) => sql.raw(quoteIdent2(k))), sql`, `);
|
|
26806
27007
|
const vals = sql.join(Object.values(data).map((v) => sql`${v}`), sql`, `);
|
|
26807
27008
|
await db.execute(sql`INSERT INTO ${tbl} (${cols}) VALUES (${vals})`);
|
|
26808
27009
|
for (const name of mediaFieldNames) {
|
|
@@ -26838,14 +27039,14 @@ async function deleteParagraphField(db, itemId, fieldName, pType, registry2) {
|
|
|
26838
27039
|
}
|
|
26839
27040
|
}
|
|
26840
27041
|
}
|
|
26841
|
-
const tbl = sql.raw(
|
|
27042
|
+
const tbl = sql.raw(quoteIdent2(pType.db.table_name));
|
|
26842
27043
|
await db.execute(sql`DELETE FROM ${tbl} WHERE parent_id = ${itemId} AND parent_field = ${fieldName}`);
|
|
26843
27044
|
return { added: [], removed };
|
|
26844
27045
|
}
|
|
26845
27046
|
async function persistJunctionField(db, itemId, junction, relatedIds) {
|
|
26846
|
-
const tbl = sql.raw(
|
|
26847
|
-
const left = sql.raw(
|
|
26848
|
-
const right = sql.raw(
|
|
27047
|
+
const tbl = sql.raw(quoteIdent2(junction.table_name));
|
|
27048
|
+
const left = sql.raw(quoteIdent2(junction.left_column));
|
|
27049
|
+
const right = sql.raw(quoteIdent2(junction.right_column));
|
|
26849
27050
|
const seen = /* @__PURE__ */ new Set();
|
|
26850
27051
|
const ids = relatedIds.filter((id) => {
|
|
26851
27052
|
const key = id.toLowerCase();
|
|
@@ -26866,9 +27067,18 @@ async function persistJunctionField(db, itemId, junction, relatedIds) {
|
|
|
26866
27067
|
);
|
|
26867
27068
|
}
|
|
26868
27069
|
function junctionOrderBy(junction) {
|
|
26869
|
-
const right = sql.raw(
|
|
27070
|
+
const right = sql.raw(quoteIdent2(junction.right_column));
|
|
26870
27071
|
return junction.order_column ? sql` ORDER BY "order" ASC, ${right} ASC` : sql` ORDER BY ${right} ASC`;
|
|
26871
27072
|
}
|
|
27073
|
+
function firstOfEach(items, key) {
|
|
27074
|
+
const seen = /* @__PURE__ */ new Set();
|
|
27075
|
+
return items.filter((item) => {
|
|
27076
|
+
const k = key(item);
|
|
27077
|
+
if (seen.has(k)) return false;
|
|
27078
|
+
seen.add(k);
|
|
27079
|
+
return true;
|
|
27080
|
+
});
|
|
27081
|
+
}
|
|
26872
27082
|
function oneOrMany(cardinality, list) {
|
|
26873
27083
|
return cardinality === "one" ? list[0] ?? null : list;
|
|
26874
27084
|
}
|
|
@@ -26936,7 +27146,7 @@ async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOn
|
|
|
26936
27146
|
const parentIds = batch.map((r) => r["id"]);
|
|
26937
27147
|
const inList = sql.join(parentIds.map((id) => sql`${id}`), sql`, `);
|
|
26938
27148
|
const result = await db.execute(
|
|
26939
|
-
sql`SELECT * FROM ${sql.raw(
|
|
27149
|
+
sql`SELECT * FROM ${sql.raw(quoteIdent2(rel.table))} WHERE parent_id IN (${inList}) AND parent_field = ${fieldName} ORDER BY "order" ASC, id ASC`
|
|
26940
27150
|
);
|
|
26941
27151
|
const byParent = groupBy(result.rows, "parent_id");
|
|
26942
27152
|
for (const row of batch) {
|
|
@@ -26956,7 +27166,7 @@ async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOn
|
|
|
26956
27166
|
const inList = sql.join(uncached.map((id) => sql`${id}`), sql`, `);
|
|
26957
27167
|
const publishedCond = publishedOnly ? sql` AND published = true` : sql``;
|
|
26958
27168
|
const result = await db.execute(
|
|
26959
|
-
sql`SELECT * FROM ${sql.raw(
|
|
27169
|
+
sql`SELECT * FROM ${sql.raw(quoteIdent2(rel.table))} WHERE id IN (${inList})${publishedCond}`
|
|
26960
27170
|
);
|
|
26961
27171
|
for (const item of result.rows) {
|
|
26962
27172
|
cache.set(`${rel.table}:${item["id"]}`, item);
|
|
@@ -26970,7 +27180,7 @@ async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOn
|
|
|
26970
27180
|
const parentIds = batch.map((r) => r["id"]);
|
|
26971
27181
|
const inList = sql.join(parentIds.map((id) => sql`${id}`), sql`, `);
|
|
26972
27182
|
const junctionResult = await db.execute(
|
|
26973
|
-
sql`SELECT * FROM ${sql.raw(
|
|
27183
|
+
sql`SELECT * FROM ${sql.raw(quoteIdent2(rel.junction_table))} WHERE ${sql.raw(quoteIdent2(rel.left_column))} IN (${inList})${junctionOrderBy(rel)}`
|
|
26974
27184
|
);
|
|
26975
27185
|
const jRows = junctionResult.rows;
|
|
26976
27186
|
const rightIds = [...new Set(jRows.map((r) => r[rel.right_column]))];
|
|
@@ -26979,7 +27189,7 @@ async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOn
|
|
|
26979
27189
|
const rightInList = sql.join(uncached.map((id) => sql`${id}`), sql`, `);
|
|
26980
27190
|
const publishedCond = publishedOnly ? sql` AND published = true` : sql``;
|
|
26981
27191
|
const entitiesResult = await db.execute(
|
|
26982
|
-
sql`SELECT * FROM ${sql.raw(
|
|
27192
|
+
sql`SELECT * FROM ${sql.raw(quoteIdent2(rel.table))} WHERE id IN (${rightInList})${publishedCond}`
|
|
26983
27193
|
);
|
|
26984
27194
|
for (const item of entitiesResult.rows) {
|
|
26985
27195
|
cache.set(`${rel.table}:${item["id"]}`, item);
|
|
@@ -26987,7 +27197,7 @@ async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOn
|
|
|
26987
27197
|
}
|
|
26988
27198
|
const byLeft = groupBy(jRows, rel.left_column);
|
|
26989
27199
|
for (const row of batch) {
|
|
26990
|
-
const jEntries = byLeft[row["id"]] ?? [];
|
|
27200
|
+
const jEntries = firstOfEach(byLeft[row["id"]] ?? [], (jr) => jr[rel.right_column]);
|
|
26991
27201
|
row[fieldName] = jEntries.map((jr) => cache.get(`${rel.table}:${jr[rel.right_column]}`)).filter(Boolean);
|
|
26992
27202
|
}
|
|
26993
27203
|
} else if (rel.type === "media") {
|
|
@@ -27019,7 +27229,7 @@ async function resolveRelationBareIds(db, rows, fieldName, rel) {
|
|
|
27019
27229
|
const parentIds = rows.map((r) => r["id"]);
|
|
27020
27230
|
const inList = sql.join(parentIds.map((id) => sql`${id}`), sql`, `);
|
|
27021
27231
|
const result = await db.execute(
|
|
27022
|
-
sql`SELECT id, parent_id FROM ${sql.raw(
|
|
27232
|
+
sql`SELECT id, parent_id FROM ${sql.raw(quoteIdent2(rel.table))} WHERE parent_id IN (${inList}) AND parent_field = ${fieldName} ORDER BY "order" ASC, id ASC`
|
|
27023
27233
|
);
|
|
27024
27234
|
const byParent = groupBy(result.rows, "parent_id");
|
|
27025
27235
|
for (const row of rows) {
|
|
@@ -27029,11 +27239,11 @@ async function resolveRelationBareIds(db, rows, fieldName, rel) {
|
|
|
27029
27239
|
const parentIds = rows.map((r) => r["id"]);
|
|
27030
27240
|
const inList = sql.join(parentIds.map((id) => sql`${id}`), sql`, `);
|
|
27031
27241
|
const result = await db.execute(
|
|
27032
|
-
sql`SELECT ${sql.raw(
|
|
27242
|
+
sql`SELECT ${sql.raw(quoteIdent2(rel.left_column))} AS left_id, ${sql.raw(quoteIdent2(rel.right_column))} AS right_id FROM ${sql.raw(quoteIdent2(rel.junction_table))} WHERE ${sql.raw(quoteIdent2(rel.left_column))} IN (${inList})${junctionOrderBy(rel)}`
|
|
27033
27243
|
);
|
|
27034
27244
|
const byLeft = groupBy(result.rows, "left_id");
|
|
27035
27245
|
for (const row of rows) {
|
|
27036
|
-
row[fieldName] = (byLeft[row["id"]] ?? []).map((r) => r["right_id"]);
|
|
27246
|
+
row[fieldName] = firstOfEach(byLeft[row["id"]] ?? [], (r) => r["right_id"]).map((r) => r["right_id"]);
|
|
27037
27247
|
}
|
|
27038
27248
|
}
|
|
27039
27249
|
}
|
|
@@ -27086,6 +27296,14 @@ export {
|
|
|
27086
27296
|
isColumnBacked2 as isColumnBacked,
|
|
27087
27297
|
createFieldKeyMap,
|
|
27088
27298
|
createFieldKeyMapFromProjection,
|
|
27299
|
+
isPlainObject2 as isPlainObject,
|
|
27300
|
+
checkRelationInput,
|
|
27301
|
+
paragraphTypeOf,
|
|
27302
|
+
paragraphItemsIn,
|
|
27303
|
+
isMissing,
|
|
27304
|
+
checkRequiredInParagraphItems,
|
|
27305
|
+
findMissingReferences,
|
|
27306
|
+
ownParagraphRowIds,
|
|
27089
27307
|
persistParagraphField,
|
|
27090
27308
|
deleteParagraphField,
|
|
27091
27309
|
persistJunctionField,
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
isColumnBacked,
|
|
13
13
|
relationCardinality,
|
|
14
14
|
resolveRelationField
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-44VXH5BN.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-N5IMQJBP.mjs
|
|
10791
10791
|
init_esm_shims();
|
|
10792
10792
|
|
|
10793
|
-
// ../api/dist/chunk-
|
|
10793
|
+
// ../api/dist/chunk-IMDC3NGM.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-IMDC3NGM.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-IMDC3NGM.mjs
|
|
30885
30885
|
var DateTimeScalar = new GraphQLScalarType({
|
|
30886
30886
|
name: "DateTime",
|
|
30887
30887
|
description: "ISO-8601 date-time string",
|
package/dist/index.js
CHANGED
|
@@ -21,6 +21,8 @@ import {
|
|
|
21
21
|
__toESM,
|
|
22
22
|
buildRelationsMap,
|
|
23
23
|
buildSchemaRegistry,
|
|
24
|
+
checkRelationInput,
|
|
25
|
+
checkRequiredInParagraphItems,
|
|
24
26
|
computeVersionModel,
|
|
25
27
|
createFieldKeyMap,
|
|
26
28
|
createFieldKeyMapFromProjection,
|
|
@@ -28,6 +30,7 @@ import {
|
|
|
28
30
|
describeSchemaChange,
|
|
29
31
|
entityKind,
|
|
30
32
|
fillPlaceholders,
|
|
33
|
+
findMissingReferences,
|
|
31
34
|
findSchemaDeprecations,
|
|
32
35
|
getTableName,
|
|
33
36
|
getTableUniqueName,
|
|
@@ -36,12 +39,17 @@ import {
|
|
|
36
39
|
is,
|
|
37
40
|
isColumnBacked,
|
|
38
41
|
isDriverValueEncoder,
|
|
42
|
+
isMissing,
|
|
43
|
+
isPlainObject,
|
|
39
44
|
isSQLWrapper,
|
|
40
45
|
junctionOrderBy,
|
|
41
46
|
loadSchemaFile,
|
|
42
47
|
loadVersionSnapshots,
|
|
43
48
|
oneOrMany,
|
|
49
|
+
ownParagraphRowIds,
|
|
44
50
|
paragraphItems,
|
|
51
|
+
paragraphItemsIn,
|
|
52
|
+
paragraphTypeOf,
|
|
45
53
|
parseRoles,
|
|
46
54
|
parseRoutes,
|
|
47
55
|
parseSchema,
|
|
@@ -55,7 +63,7 @@ import {
|
|
|
55
63
|
validateCrossReferences,
|
|
56
64
|
verifyPassword,
|
|
57
65
|
walkSchemaDirectory
|
|
58
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-44VXH5BN.js";
|
|
59
67
|
|
|
60
68
|
// ../../node_modules/.pnpm/postgres-array@2.0.0/node_modules/postgres-array/index.js
|
|
61
69
|
var require_postgres_array = __commonJS({
|
|
@@ -21901,7 +21909,7 @@ var ERROR_STATUS_MAP = {
|
|
|
21901
21909
|
var errorHandler2 = (err, c) => {
|
|
21902
21910
|
console.error(err.stack ?? err.message);
|
|
21903
21911
|
const raw2 = err.code;
|
|
21904
|
-
const deliberate = raw2 !== void 0 && raw2 !== "INTERNAL_ERROR" && raw2
|
|
21912
|
+
const deliberate = raw2 !== void 0 && raw2 !== "INTERNAL_ERROR" && Object.hasOwn(ERROR_STATUS_MAP, raw2);
|
|
21905
21913
|
if (!deliberate) {
|
|
21906
21914
|
return c.json({ ok: false, error: { code: "INTERNAL_ERROR", message: "Internal server error" } }, 500);
|
|
21907
21915
|
}
|
|
@@ -22464,16 +22472,16 @@ function parseFilters(url, validFields, columnFor) {
|
|
|
22464
22472
|
}
|
|
22465
22473
|
return { ok: true, filters };
|
|
22466
22474
|
}
|
|
22475
|
+
function pickProgrammatic(resolved, names) {
|
|
22476
|
+
const out = {};
|
|
22477
|
+
for (const name of names) if (Object.hasOwn(resolved, name)) out[name] = resolved[name];
|
|
22478
|
+
return out;
|
|
22479
|
+
}
|
|
22467
22480
|
function isPublished(item) {
|
|
22468
22481
|
return item["published"] === true;
|
|
22469
22482
|
}
|
|
22470
22483
|
function registerPublicContentRoutes(app, registry, repos, projectors, paths, listRateLimit, resolver, resolverProjectors) {
|
|
22471
22484
|
const forResolver = resolverProjectors ?? projectors;
|
|
22472
|
-
function pickProgrammatic(resolved, names) {
|
|
22473
|
-
const out = {};
|
|
22474
|
-
for (const name of names) if (name in resolved) out[name] = resolved[name];
|
|
22475
|
-
return out;
|
|
22476
|
-
}
|
|
22477
22485
|
async function respondItem(row, typeName, programmatic) {
|
|
22478
22486
|
const data = projectRow(row, typeName, projectors);
|
|
22479
22487
|
if (!resolver?.hasSchema(typeName)) return data;
|
|
@@ -22785,25 +22793,42 @@ function quoteIdent(name) {
|
|
|
22785
22793
|
function isRequiredSingleReferenceTo(f, targetType) {
|
|
22786
22794
|
return f.field_type === "reference" && f.required && relationCardinality(f) === "one" && f.db_column?.foreign_key !== void 0 && f.ui_component.component === "typeahead-select" && f.ui_component.ref === targetType;
|
|
22787
22795
|
}
|
|
22796
|
+
function requiredReferencesTo(owners, targetType) {
|
|
22797
|
+
return owners.flatMap(
|
|
22798
|
+
(owner) => owner.fields.filter((f) => isRequiredSingleReferenceTo(f, targetType)).map((f) => ({ owner, f }))
|
|
22799
|
+
);
|
|
22800
|
+
}
|
|
22788
22801
|
async function findRequiredReferrers(db, registry, targetType, id) {
|
|
22789
|
-
const
|
|
22790
|
-
|
|
22791
|
-
|
|
22792
|
-
|
|
22793
|
-
];
|
|
22794
|
-
const
|
|
22795
|
-
|
|
22796
|
-
|
|
22797
|
-
|
|
22798
|
-
|
|
22799
|
-
|
|
22800
|
-
|
|
22801
|
-
|
|
22802
|
-
|
|
22803
|
-
|
|
22804
|
-
|
|
22802
|
+
const targetFields = registry.content_types[targetType]?.fields ?? registry.taxonomy_types[targetType]?.fields ?? [];
|
|
22803
|
+
const itemOwners = [...Object.values(registry.content_types), ...Object.values(registry.taxonomy_types)];
|
|
22804
|
+
const itemFields = requiredReferencesTo(itemOwners, targetType);
|
|
22805
|
+
const paragraphFields = requiredReferencesTo(Object.values(registry.paragraph_types), targetType);
|
|
22806
|
+
const ownIds = paragraphFields.length > 0 ? await ownParagraphRowIds(db, registry, targetFields, id) : [];
|
|
22807
|
+
const [itemCounts, paragraphCounts] = await Promise.all([
|
|
22808
|
+
Promise.all(
|
|
22809
|
+
itemFields.map(async ({ owner, f }) => {
|
|
22810
|
+
const notSelf = owner.name === targetType ? sql` AND id <> ${id}` : sql``;
|
|
22811
|
+
const r = await db.execute(
|
|
22812
|
+
sql`SELECT count(*)::int AS n FROM ${sql.raw(quoteIdent(owner.db.table_name))} WHERE ${sql.raw(quoteIdent(f.db_column.column_name))} = ${id}${notSelf}`
|
|
22813
|
+
);
|
|
22814
|
+
return { owner, f, n: r.rows[0].n, own: 0 };
|
|
22815
|
+
})
|
|
22816
|
+
),
|
|
22817
|
+
Promise.all(
|
|
22818
|
+
paragraphFields.map(async ({ owner, f }) => {
|
|
22819
|
+
const r = await db.execute(
|
|
22820
|
+
sql`SELECT count(*)::int AS n, count(*) FILTER (WHERE id = ANY(${sql.param(ownIds)}::uuid[]))::int AS own FROM ${sql.raw(quoteIdent(owner.db.table_name))} WHERE ${sql.raw(quoteIdent(f.db_column.column_name))} = ${id}`
|
|
22821
|
+
);
|
|
22822
|
+
const { n, own } = r.rows[0];
|
|
22823
|
+
return { owner, f, n, own };
|
|
22824
|
+
})
|
|
22825
|
+
)
|
|
22826
|
+
]);
|
|
22827
|
+
const others = [];
|
|
22828
|
+
for (const { owner, f, n, own } of [...itemCounts, ...paragraphCounts]) {
|
|
22829
|
+
if (n - own > 0) others.push({ type_label: owner.label, field_label: f.label, count: n - own });
|
|
22805
22830
|
}
|
|
22806
|
-
return
|
|
22831
|
+
return { others, fromOwnParagraphs: paragraphCounts.some((c) => c.own > 0) };
|
|
22807
22832
|
}
|
|
22808
22833
|
function inUseMessage(referrers) {
|
|
22809
22834
|
const total = referrers.reduce((sum, r) => sum + r.count, 0);
|
|
@@ -22828,7 +22853,7 @@ function topLevelMediaDelta(mediaFields, before, after) {
|
|
|
22828
22853
|
for (const f of mediaFields) {
|
|
22829
22854
|
const key = f.db_column?.column_name;
|
|
22830
22855
|
if (key === void 0 || key === "") continue;
|
|
22831
|
-
if (after !== null && !(key
|
|
22856
|
+
if (after !== null && !Object.hasOwn(after, key)) continue;
|
|
22832
22857
|
const oldId = before ? extractMediaId(before[key]) : null;
|
|
22833
22858
|
const newId = after ? extractMediaId(after[key]) : null;
|
|
22834
22859
|
if (newId === oldId) continue;
|
|
@@ -22851,127 +22876,6 @@ async function applyMediaReferenceDelta(delta, mediaRepo) {
|
|
|
22851
22876
|
if (netAdd.length > 0) await mediaRepo.incrementReferenceCount(netAdd);
|
|
22852
22877
|
if (netRemove.length > 0) await mediaRepo.decrementReferenceCount(netRemove);
|
|
22853
22878
|
}
|
|
22854
|
-
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
22855
|
-
function isUuid(v2) {
|
|
22856
|
-
return typeof v2 === "string" && UUID_RE.test(v2);
|
|
22857
|
-
}
|
|
22858
|
-
function isPlainObject(v2) {
|
|
22859
|
-
return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
|
|
22860
|
-
}
|
|
22861
|
-
function checkRelationInput(fields, body, registry, path5 = "") {
|
|
22862
|
-
const errors = [];
|
|
22863
|
-
for (const field of fields) {
|
|
22864
|
-
if (!(field.name in body)) continue;
|
|
22865
|
-
const cardinality = relationCardinality(field);
|
|
22866
|
-
if (cardinality === null) continue;
|
|
22867
|
-
const value = body[field.name];
|
|
22868
|
-
const name = `${path5}${field.name}`;
|
|
22869
|
-
if (field.field_type === "reference") {
|
|
22870
|
-
const ok = cardinality === "one" ? value === null || isUuid(value) : Array.isArray(value) && value.every(isUuid);
|
|
22871
|
-
if (!ok) {
|
|
22872
|
-
errors.push({
|
|
22873
|
-
field: name,
|
|
22874
|
-
message: cardinality === "one" ? `${name} holds one item: send a UUID string or null.` : `${name} holds a list: send an array of UUID strings.`
|
|
22875
|
-
});
|
|
22876
|
-
}
|
|
22877
|
-
continue;
|
|
22878
|
-
}
|
|
22879
|
-
const items = cardinality === "one" ? value === null ? [] : isPlainObject(value) ? [value] : void 0 : Array.isArray(value) && value.every(isPlainObject) ? value : void 0;
|
|
22880
|
-
if (items === void 0) {
|
|
22881
|
-
errors.push({
|
|
22882
|
-
field: name,
|
|
22883
|
-
message: cardinality === "one" ? `${name} holds one item: send an object or null.` : `${name} holds a list: send an array of objects.`
|
|
22884
|
-
});
|
|
22885
|
-
continue;
|
|
22886
|
-
}
|
|
22887
|
-
const pType = paragraphTypeOf(field, registry);
|
|
22888
|
-
if (!pType) continue;
|
|
22889
|
-
items.forEach((item, i) => {
|
|
22890
|
-
const prefix = cardinality === "one" ? `${name}.` : `${name}[${i}].`;
|
|
22891
|
-
errors.push(...checkRelationInput(pType.fields, item, registry, prefix));
|
|
22892
|
-
});
|
|
22893
|
-
}
|
|
22894
|
-
return errors;
|
|
22895
|
-
}
|
|
22896
|
-
function paragraphTypeOf(field, registry) {
|
|
22897
|
-
const comp = field.ui_component;
|
|
22898
|
-
return comp.component === "paragraph-embed" ? registry.paragraph_types[comp.ref] : void 0;
|
|
22899
|
-
}
|
|
22900
|
-
function paragraphItemsIn(fields, body, registry, path5) {
|
|
22901
|
-
const out = [];
|
|
22902
|
-
for (const field of fields) {
|
|
22903
|
-
if (field.field_type !== "paragraph" || !(field.name in body)) continue;
|
|
22904
|
-
const pType = paragraphTypeOf(field, registry);
|
|
22905
|
-
if (!pType) continue;
|
|
22906
|
-
const value = body[field.name];
|
|
22907
|
-
const name = `${path5}${field.name}`;
|
|
22908
|
-
if (relationCardinality(field) === "one") {
|
|
22909
|
-
if (isPlainObject(value)) out.push({ item: value, fields: pType.fields, prefix: `${name}.` });
|
|
22910
|
-
} else if (Array.isArray(value)) {
|
|
22911
|
-
value.forEach((item, i) => {
|
|
22912
|
-
if (isPlainObject(item)) out.push({ item, fields: pType.fields, prefix: `${name}[${i}].` });
|
|
22913
|
-
});
|
|
22914
|
-
}
|
|
22915
|
-
}
|
|
22916
|
-
return out;
|
|
22917
|
-
}
|
|
22918
|
-
function isMissing(value) {
|
|
22919
|
-
if (value === null || value === void 0) return true;
|
|
22920
|
-
if (typeof value === "string" && value.trim() === "") return true;
|
|
22921
|
-
if (Array.isArray(value) && value.length === 0) return true;
|
|
22922
|
-
return false;
|
|
22923
|
-
}
|
|
22924
|
-
function checkRequiredInParagraphItems(fields, body, registry, path5 = "") {
|
|
22925
|
-
const errors = [];
|
|
22926
|
-
for (const { item, fields: itemFields, prefix } of paragraphItemsIn(fields, body, registry, path5)) {
|
|
22927
|
-
for (const f of itemFields) {
|
|
22928
|
-
if (!f.required || f.removed === true || !f.db_column || f.db_column.junction) continue;
|
|
22929
|
-
if (isMissing(item[f.name])) {
|
|
22930
|
-
errors.push({ field: `${prefix}${f.name}`, message: `${prefix}${f.name} is required.` });
|
|
22931
|
-
}
|
|
22932
|
-
}
|
|
22933
|
-
errors.push(...checkRequiredInParagraphItems(itemFields, item, registry, prefix));
|
|
22934
|
-
}
|
|
22935
|
-
return errors;
|
|
22936
|
-
}
|
|
22937
|
-
function quoteIdent2(name) {
|
|
22938
|
-
if (!/^[a-z][a-z0-9_-]*$/.test(name)) throw new Error(`Unsafe identifier: ${name}`);
|
|
22939
|
-
return `"${name}"`;
|
|
22940
|
-
}
|
|
22941
|
-
function collectReferences(fields, body, registry, path5, out) {
|
|
22942
|
-
for (const f of fields) {
|
|
22943
|
-
if (!(f.name in body) || !f.db_column) continue;
|
|
22944
|
-
const table = f.db_column.junction ? f.db_column.junction.right_table : f.db_column.foreign_key?.table;
|
|
22945
|
-
if (!table) continue;
|
|
22946
|
-
const value = body[f.name];
|
|
22947
|
-
const name = `${path5}${f.name}`;
|
|
22948
|
-
if (typeof value === "string") {
|
|
22949
|
-
out.push({ table, id: value, field: name });
|
|
22950
|
-
} else if (Array.isArray(value)) {
|
|
22951
|
-
value.forEach((v2, i) => {
|
|
22952
|
-
if (typeof v2 === "string") out.push({ table, id: v2, field: `${name}[${i}]` });
|
|
22953
|
-
});
|
|
22954
|
-
}
|
|
22955
|
-
}
|
|
22956
|
-
for (const { item, fields: itemFields, prefix } of paragraphItemsIn(fields, body, registry, path5)) {
|
|
22957
|
-
collectReferences(itemFields, item, registry, prefix, out);
|
|
22958
|
-
}
|
|
22959
|
-
}
|
|
22960
|
-
async function findMissingReferences(db, fields, body, registry) {
|
|
22961
|
-
const uses = [];
|
|
22962
|
-
collectReferences(fields, body, registry, "", uses);
|
|
22963
|
-
if (uses.length === 0) return [];
|
|
22964
|
-
const lookups = [...new Set(uses.map((u) => u.table))].map(async (table) => {
|
|
22965
|
-
const ids = [...new Set(uses.filter((u) => u.table === table && isUuid(u.id)).map((u) => u.id.toLowerCase()))];
|
|
22966
|
-
if (ids.length === 0) return [table, /* @__PURE__ */ new Set()];
|
|
22967
|
-
const result = await db.execute(
|
|
22968
|
-
sql`SELECT id FROM ${sql.raw(quoteIdent2(table))} WHERE id IN (${sql.join(ids.map((id) => sql`${id}`), sql`, `)})`
|
|
22969
|
-
);
|
|
22970
|
-
return [table, new Set(result.rows.map((r) => String(r.id).toLowerCase()))];
|
|
22971
|
-
});
|
|
22972
|
-
const found = new Map(await Promise.all(lookups));
|
|
22973
|
-
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.` }));
|
|
22974
|
-
}
|
|
22975
22879
|
var VARCHAR_DEFAULT_LIMIT = 255;
|
|
22976
22880
|
var INTEGER_MIN = -2147483648;
|
|
22977
22881
|
var INTEGER_MAX = 2147483647;
|
|
@@ -22982,7 +22886,7 @@ var EMPTY_MEANS_NULL = /* @__PURE__ */ new Set(["date", "integer", "float", "enu
|
|
|
22982
22886
|
function emptyValuesToNull(fields, body, registry) {
|
|
22983
22887
|
const out = { ...body };
|
|
22984
22888
|
for (const f of fields) {
|
|
22985
|
-
if (!(f.name
|
|
22889
|
+
if (!Object.hasOwn(out, f.name)) continue;
|
|
22986
22890
|
const value = out[f.name];
|
|
22987
22891
|
if (value === "" && EMPTY_MEANS_NULL.has(f.field_type)) {
|
|
22988
22892
|
out[f.name] = null;
|
|
@@ -23087,7 +22991,7 @@ function rangeError(name, value, min, max) {
|
|
|
23087
22991
|
function checkFieldValues(fields, body, registry, path5 = "") {
|
|
23088
22992
|
const errors = [];
|
|
23089
22993
|
for (const f of fields) {
|
|
23090
|
-
if (!(f.name
|
|
22994
|
+
if (!Object.hasOwn(body, f.name) || f.removed === true) continue;
|
|
23091
22995
|
const name = `${path5}${f.name}`;
|
|
23092
22996
|
const message = valueError(f, body[f.name], name);
|
|
23093
22997
|
if (message) errors.push({ field: name, message });
|
|
@@ -23097,20 +23001,18 @@ function checkFieldValues(fields, body, registry, path5 = "") {
|
|
|
23097
23001
|
}
|
|
23098
23002
|
return errors;
|
|
23099
23003
|
}
|
|
23100
|
-
function
|
|
23004
|
+
function quoteIdent2(name) {
|
|
23101
23005
|
if (!/^[a-z][a-z0-9_-]*$/.test(name)) throw new Error(`Unsafe identifier: ${name}`);
|
|
23102
23006
|
return `"${name}"`;
|
|
23103
23007
|
}
|
|
23104
23008
|
async function loadParagraphRows(db, registry, pType, parentId, fieldName) {
|
|
23105
23009
|
const result = await db.execute(
|
|
23106
|
-
sql`SELECT * FROM ${sql.raw(
|
|
23010
|
+
sql`SELECT * FROM ${sql.raw(quoteIdent2(pType.db.table_name))} WHERE parent_id = ${parentId} AND parent_field = ${fieldName} ORDER BY "order" ASC, id ASC`
|
|
23107
23011
|
);
|
|
23108
23012
|
const rows = result.rows;
|
|
23109
23013
|
for (const nf of pType.fields) {
|
|
23110
23014
|
if (nf.db_column !== null) continue;
|
|
23111
|
-
const
|
|
23112
|
-
if (comp.component !== "paragraph-embed" || !comp.ref) continue;
|
|
23113
|
-
const nType = registry.paragraph_types[comp.ref];
|
|
23015
|
+
const nType = paragraphTypeOf(nf, registry);
|
|
23114
23016
|
if (!nType) continue;
|
|
23115
23017
|
for (const row of rows) {
|
|
23116
23018
|
row[nf.name] = oneOrMany(
|
|
@@ -23122,35 +23024,36 @@ async function loadParagraphRows(db, registry, pType, parentId, fieldName) {
|
|
|
23122
23024
|
return rows;
|
|
23123
23025
|
}
|
|
23124
23026
|
async function loadRelationsForEdit(db, registry, fields, id, row) {
|
|
23125
|
-
|
|
23126
|
-
|
|
23127
|
-
|
|
23128
|
-
|
|
23129
|
-
|
|
23130
|
-
|
|
23131
|
-
|
|
23132
|
-
|
|
23133
|
-
|
|
23134
|
-
|
|
23135
|
-
|
|
23136
|
-
|
|
23137
|
-
|
|
23138
|
-
|
|
23139
|
-
|
|
23027
|
+
const loaded = await Promise.all(
|
|
23028
|
+
fields.map(async (f) => {
|
|
23029
|
+
if (f.db_column === null) {
|
|
23030
|
+
const pType = paragraphTypeOf(f, registry);
|
|
23031
|
+
if (!pType) return null;
|
|
23032
|
+
return [f.name, oneOrMany(relationCardinality(f) ?? "many", await loadParagraphRows(db, registry, pType, id, f.name))];
|
|
23033
|
+
}
|
|
23034
|
+
if (f.db_column.junction) {
|
|
23035
|
+
const j = f.db_column.junction;
|
|
23036
|
+
const r = await db.execute(
|
|
23037
|
+
sql`SELECT ${sql.raw(quoteIdent2(j.right_column))} FROM ${sql.raw(quoteIdent2(j.table_name))} WHERE ${sql.raw(quoteIdent2(j.left_column))} = ${id}${junctionOrderBy(j)}`
|
|
23038
|
+
);
|
|
23039
|
+
return [f.name, [...new Set(r.rows.map((linked) => linked[j.right_column]))]];
|
|
23040
|
+
}
|
|
23041
|
+
return null;
|
|
23042
|
+
})
|
|
23043
|
+
);
|
|
23044
|
+
for (const entry of loaded) if (entry) row[entry[0]] = entry[1];
|
|
23140
23045
|
}
|
|
23141
23046
|
async function valuesForPublishCheck(db, registry, requiredFields, id, storedLabels, body) {
|
|
23142
23047
|
const stored = { ...storedLabels };
|
|
23143
|
-
if (db) await loadRelationsForEdit(db, registry, requiredFields.filter((f) => !(f.name
|
|
23048
|
+
if (db) await loadRelationsForEdit(db, registry, requiredFields.filter((f) => !Object.hasOwn(body, f.name)), id, stored);
|
|
23144
23049
|
return { ...stored, ...body };
|
|
23145
23050
|
}
|
|
23146
23051
|
async function persistRelationFields(db, registry, fields, body, itemId, ownerTable) {
|
|
23147
23052
|
const deltas = [];
|
|
23148
23053
|
for (const f of fields) {
|
|
23149
|
-
if (!(f.name
|
|
23054
|
+
if (!Object.hasOwn(body, f.name)) continue;
|
|
23150
23055
|
if (f.db_column === null) {
|
|
23151
|
-
const
|
|
23152
|
-
if (comp.component !== "paragraph-embed" || !comp.ref) continue;
|
|
23153
|
-
const pType = registry.paragraph_types[comp.ref];
|
|
23056
|
+
const pType = paragraphTypeOf(f, registry);
|
|
23154
23057
|
if (!pType) continue;
|
|
23155
23058
|
deltas.push(await persistParagraphField(db, itemId, ownerTable, f.name, pType, paragraphItems(f, body[f.name]), registry));
|
|
23156
23059
|
} else if (f.db_column.junction) {
|
|
@@ -23161,6 +23064,46 @@ async function persistRelationFields(db, registry, fields, body, itemId, ownerTa
|
|
|
23161
23064
|
}
|
|
23162
23065
|
return deltas;
|
|
23163
23066
|
}
|
|
23067
|
+
async function deleteOwnParagraphs(db, registry, fields, itemId) {
|
|
23068
|
+
const deltas = [];
|
|
23069
|
+
for (const f of fields) {
|
|
23070
|
+
const pType = paragraphTypeOf(f, registry);
|
|
23071
|
+
if (!pType) continue;
|
|
23072
|
+
deltas.push(await deleteParagraphField(db, itemId, f.name, pType, registry));
|
|
23073
|
+
}
|
|
23074
|
+
return deltas;
|
|
23075
|
+
}
|
|
23076
|
+
function releasedFromParagraphsOnly(paragraphDeltas, topLevel) {
|
|
23077
|
+
const stillHeld = new Set(topLevel.removed);
|
|
23078
|
+
return { added: [], removed: mergeMediaDeltas(...paragraphDeltas).removed.filter((mediaId) => !stillHeld.has(mediaId)) };
|
|
23079
|
+
}
|
|
23080
|
+
async function deleteItemCascade(db, registry, mediaRepo, target) {
|
|
23081
|
+
const { typeName, fields, mediaFields, repo, id, row } = target;
|
|
23082
|
+
const referrers = db ? await findRequiredReferrers(db, registry, typeName, id) : { others: [], fromOwnParagraphs: false };
|
|
23083
|
+
if (referrers.others.length > 0) return { ok: false, message: inUseMessage(referrers.others) };
|
|
23084
|
+
const topLevel = topLevelMediaDelta(mediaFields, row, null);
|
|
23085
|
+
if (!db || !referrers.fromOwnParagraphs) {
|
|
23086
|
+
try {
|
|
23087
|
+
await repo.delete(id);
|
|
23088
|
+
} catch (err) {
|
|
23089
|
+
if (isForeignKeyViolation(err)) return { ok: false, message: IN_USE_RACE_MESSAGE };
|
|
23090
|
+
throw err;
|
|
23091
|
+
}
|
|
23092
|
+
const paragraphDeltas2 = db ? await deleteOwnParagraphs(db, registry, fields, id) : [];
|
|
23093
|
+
await applyMediaReferenceDelta(mergeMediaDeltas(topLevel, ...paragraphDeltas2), mediaRepo);
|
|
23094
|
+
return { ok: true };
|
|
23095
|
+
}
|
|
23096
|
+
const paragraphDeltas = await deleteOwnParagraphs(db, registry, fields, id);
|
|
23097
|
+
try {
|
|
23098
|
+
await repo.delete(id);
|
|
23099
|
+
} catch (err) {
|
|
23100
|
+
await applyMediaReferenceDelta(releasedFromParagraphsOnly(paragraphDeltas, topLevel), mediaRepo);
|
|
23101
|
+
if (isForeignKeyViolation(err)) return { ok: false, message: IN_USE_RACE_MESSAGE };
|
|
23102
|
+
throw err;
|
|
23103
|
+
}
|
|
23104
|
+
await applyMediaReferenceDelta(mergeMediaDeltas(topLevel, ...paragraphDeltas), mediaRepo);
|
|
23105
|
+
return { ok: true };
|
|
23106
|
+
}
|
|
23164
23107
|
async function lookupBasePathId(db, pathOrName) {
|
|
23165
23108
|
const r = await db.execute(
|
|
23166
23109
|
sql`SELECT id FROM base_paths WHERE path = ${pathOrName} OR name = ${pathOrName} LIMIT 1`
|
|
@@ -23270,7 +23213,6 @@ function registerAdminContentRoutes(app, registry, repos, projectors, mediaRepo,
|
|
|
23270
23213
|
const mediaFields = contentType.fields.filter(
|
|
23271
23214
|
(f) => f.field_type === "image" || f.field_type === "video" || f.field_type === "file"
|
|
23272
23215
|
);
|
|
23273
|
-
const paragraphFieldDefs = contentType.fields.filter((f) => f.db_column === null);
|
|
23274
23216
|
const searchableColumns = [
|
|
23275
23217
|
...contentType.fields.filter((f) => f.field_type === "text/plain" && f.db_column !== null).map((f) => f.db_column.column_name),
|
|
23276
23218
|
...contentType.system_fields.some((f) => f.name === "slug") ? ["slug"] : []
|
|
@@ -23420,7 +23362,7 @@ function registerAdminContentRoutes(app, registry, repos, projectors, mediaRepo,
|
|
|
23420
23362
|
}
|
|
23421
23363
|
for (const f of columnBackedFields) {
|
|
23422
23364
|
const key = f.db_column.column_name;
|
|
23423
|
-
if (!(key
|
|
23365
|
+
if (!Object.hasOwn(storageBody, key)) continue;
|
|
23424
23366
|
columnData[key] = storageBody[key];
|
|
23425
23367
|
}
|
|
23426
23368
|
if (db) {
|
|
@@ -23462,7 +23404,7 @@ function registerAdminContentRoutes(app, registry, repos, projectors, mediaRepo,
|
|
|
23462
23404
|
404
|
|
23463
23405
|
);
|
|
23464
23406
|
}
|
|
23465
|
-
if (!contentType.only_one && "slug"
|
|
23407
|
+
if (!contentType.only_one && Object.hasOwn(body, "slug")) {
|
|
23466
23408
|
const slug = body["slug"];
|
|
23467
23409
|
if (typeof slug !== "string" || slug.trim() === "") {
|
|
23468
23410
|
return c.json(
|
|
@@ -23532,11 +23474,11 @@ function registerAdminContentRoutes(app, registry, repos, projectors, mediaRepo,
|
|
|
23532
23474
|
}
|
|
23533
23475
|
const patchColumnBackedFields = contentType.fields.filter(isColumnBacked);
|
|
23534
23476
|
const patchData = {};
|
|
23535
|
-
if (!contentType.only_one && "slug"
|
|
23536
|
-
if ("published"
|
|
23477
|
+
if (!contentType.only_one && Object.hasOwn(body, "slug")) patchData["slug"] = body["slug"];
|
|
23478
|
+
if (Object.hasOwn(body, "published")) patchData["published"] = body["published"];
|
|
23537
23479
|
for (const f of patchColumnBackedFields) {
|
|
23538
23480
|
const key = f.db_column.column_name;
|
|
23539
|
-
if (!(key
|
|
23481
|
+
if (!Object.hasOwn(storageBody, key)) continue;
|
|
23540
23482
|
patchData[key] = storageBody[key];
|
|
23541
23483
|
}
|
|
23542
23484
|
const updated = await repo.update(id, patchData);
|
|
@@ -23586,31 +23528,17 @@ function registerAdminContentRoutes(app, registry, repos, projectors, mediaRepo,
|
|
|
23586
23528
|
404
|
|
23587
23529
|
);
|
|
23588
23530
|
}
|
|
23589
|
-
const
|
|
23590
|
-
|
|
23591
|
-
|
|
23592
|
-
|
|
23593
|
-
|
|
23594
|
-
|
|
23595
|
-
|
|
23596
|
-
|
|
23597
|
-
|
|
23598
|
-
}
|
|
23599
|
-
throw err;
|
|
23600
|
-
}
|
|
23601
|
-
const mediaDeltas = [
|
|
23602
|
-
topLevelMediaDelta(mediaFields, item, null)
|
|
23603
|
-
];
|
|
23604
|
-
if (db) {
|
|
23605
|
-
for (const f of paragraphFieldDefs) {
|
|
23606
|
-
const comp = f.ui_component;
|
|
23607
|
-
if (comp.component !== "paragraph-embed" || !comp.ref) continue;
|
|
23608
|
-
const pType = registry.paragraph_types[comp.ref];
|
|
23609
|
-
if (!pType) continue;
|
|
23610
|
-
mediaDeltas.push(await deleteParagraphField(db, id, f.name, pType, registry));
|
|
23611
|
-
}
|
|
23531
|
+
const outcome = await deleteItemCascade(db, registry, mediaRepo, {
|
|
23532
|
+
typeName,
|
|
23533
|
+
fields: contentType.fields,
|
|
23534
|
+
mediaFields,
|
|
23535
|
+
repo,
|
|
23536
|
+
id,
|
|
23537
|
+
row: item
|
|
23538
|
+
});
|
|
23539
|
+
if (!outcome.ok) {
|
|
23540
|
+
return c.json({ ok: false, error: { code: "ITEM_IN_USE", message: outcome.message } }, 409);
|
|
23612
23541
|
}
|
|
23613
|
-
await applyMediaReferenceDelta(mergeMediaDeltas(...mediaDeltas), mediaRepo);
|
|
23614
23542
|
return c.json({ ok: true });
|
|
23615
23543
|
}
|
|
23616
23544
|
);
|
|
@@ -23631,7 +23559,6 @@ function registerAdminContentRoutes(app, registry, repos, projectors, mediaRepo,
|
|
|
23631
23559
|
const mediaFields = taxonomyType.fields.filter(
|
|
23632
23560
|
(f) => f.field_type === "image" || f.field_type === "video" || f.field_type === "file"
|
|
23633
23561
|
);
|
|
23634
|
-
const paragraphFieldDefs = taxonomyType.fields.filter((f) => f.db_column === null);
|
|
23635
23562
|
const searchableColumns = [
|
|
23636
23563
|
...taxonomyType.fields.filter((f) => f.field_type === "text/plain" && f.db_column !== null).map((f) => f.db_column.column_name),
|
|
23637
23564
|
...taxonomyType.system_fields.some((f) => f.name === "slug") ? ["slug"] : []
|
|
@@ -23717,7 +23644,7 @@ function registerAdminContentRoutes(app, registry, repos, projectors, mediaRepo,
|
|
|
23717
23644
|
};
|
|
23718
23645
|
for (const f of taxColumnBackedFields) {
|
|
23719
23646
|
const key = f.db_column.column_name;
|
|
23720
|
-
if (!(key
|
|
23647
|
+
if (!Object.hasOwn(storageBody, key)) continue;
|
|
23721
23648
|
taxColumnData[key] = storageBody[key];
|
|
23722
23649
|
}
|
|
23723
23650
|
const item = await repo.create(taxColumnData);
|
|
@@ -23769,10 +23696,10 @@ function registerAdminContentRoutes(app, registry, repos, projectors, mediaRepo,
|
|
|
23769
23696
|
}
|
|
23770
23697
|
const taxPatchColumnBackedFields = taxonomyType.fields.filter(isColumnBacked);
|
|
23771
23698
|
const taxPatchData = {};
|
|
23772
|
-
if ("published"
|
|
23699
|
+
if (Object.hasOwn(body, "published")) taxPatchData["published"] = body["published"];
|
|
23773
23700
|
for (const f of taxPatchColumnBackedFields) {
|
|
23774
23701
|
const key = f.db_column.column_name;
|
|
23775
|
-
if (!(key
|
|
23702
|
+
if (!Object.hasOwn(storageBody, key)) continue;
|
|
23776
23703
|
taxPatchData[key] = storageBody[key];
|
|
23777
23704
|
}
|
|
23778
23705
|
const updated = await repo.update(id, taxPatchData);
|
|
@@ -23805,31 +23732,17 @@ function registerAdminContentRoutes(app, registry, repos, projectors, mediaRepo,
|
|
|
23805
23732
|
404
|
|
23806
23733
|
);
|
|
23807
23734
|
}
|
|
23808
|
-
const
|
|
23809
|
-
|
|
23810
|
-
|
|
23811
|
-
|
|
23812
|
-
|
|
23813
|
-
|
|
23814
|
-
|
|
23815
|
-
|
|
23816
|
-
|
|
23817
|
-
}
|
|
23818
|
-
throw err;
|
|
23819
|
-
}
|
|
23820
|
-
const mediaDeltas = [
|
|
23821
|
-
topLevelMediaDelta(mediaFields, item, null)
|
|
23822
|
-
];
|
|
23823
|
-
if (db) {
|
|
23824
|
-
for (const f of paragraphFieldDefs) {
|
|
23825
|
-
const comp = f.ui_component;
|
|
23826
|
-
if (comp.component !== "paragraph-embed" || !comp.ref) continue;
|
|
23827
|
-
const pType = registry.paragraph_types[comp.ref];
|
|
23828
|
-
if (!pType) continue;
|
|
23829
|
-
mediaDeltas.push(await deleteParagraphField(db, id, f.name, pType, registry));
|
|
23830
|
-
}
|
|
23735
|
+
const outcome = await deleteItemCascade(db, registry, mediaRepo, {
|
|
23736
|
+
typeName,
|
|
23737
|
+
fields: taxonomyType.fields,
|
|
23738
|
+
mediaFields,
|
|
23739
|
+
repo,
|
|
23740
|
+
id,
|
|
23741
|
+
row: item
|
|
23742
|
+
});
|
|
23743
|
+
if (!outcome.ok) {
|
|
23744
|
+
return c.json({ ok: false, error: { code: "ITEM_IN_USE", message: outcome.message } }, 409);
|
|
23831
23745
|
}
|
|
23832
|
-
await applyMediaReferenceDelta(mergeMediaDeltas(...mediaDeltas), mediaRepo);
|
|
23833
23746
|
return c.json({ ok: true });
|
|
23834
23747
|
}
|
|
23835
23748
|
);
|
|
@@ -24774,7 +24687,7 @@ function registerUserRoutes(app, db, requirePermission, requireHierarchy) {
|
|
|
24774
24687
|
}
|
|
24775
24688
|
var API_VERSION = (() => {
|
|
24776
24689
|
try {
|
|
24777
|
-
return "0.9.
|
|
24690
|
+
return "0.9.3";
|
|
24778
24691
|
} catch {
|
|
24779
24692
|
return "0.0.0";
|
|
24780
24693
|
}
|
|
@@ -24883,7 +24796,7 @@ function codeError(code, message) {
|
|
|
24883
24796
|
err.code = code;
|
|
24884
24797
|
return err;
|
|
24885
24798
|
}
|
|
24886
|
-
function
|
|
24799
|
+
function quoteIdent3(name) {
|
|
24887
24800
|
if (!/^[a-z][a-z0-9_-]*$/.test(name)) {
|
|
24888
24801
|
throw new Error(`Unsafe SQL identifier: ${name}`);
|
|
24889
24802
|
}
|
|
@@ -24934,7 +24847,7 @@ function whereFragment(conds) {
|
|
|
24934
24847
|
function createDrizzleContentRepository(db, tableName, options = {}) {
|
|
24935
24848
|
const { relations = {}, publishedRelations = false, sortableColumns } = options;
|
|
24936
24849
|
function tableRaw() {
|
|
24937
|
-
return sql.raw(
|
|
24850
|
+
return sql.raw(quoteIdent3(tableName));
|
|
24938
24851
|
}
|
|
24939
24852
|
async function resolveRows(rows, include, cache) {
|
|
24940
24853
|
if (rows.length === 0) return rows;
|
|
@@ -24977,7 +24890,7 @@ function createDrizzleContentRepository(db, tableName, options = {}) {
|
|
|
24977
24890
|
const offset = (page - 1) * per_page;
|
|
24978
24891
|
const conds = buildConditions(published_only, filters, search);
|
|
24979
24892
|
const where = whereFragment(conds);
|
|
24980
|
-
const sortCol = sql.raw(
|
|
24893
|
+
const sortCol = sql.raw(quoteIdent3(sort_by));
|
|
24981
24894
|
const sortDir = sql.raw(sort_order === "desc" ? "DESC" : "ASC");
|
|
24982
24895
|
const countResult = await db.execute(
|
|
24983
24896
|
sql`SELECT COUNT(*) AS total FROM ${tableRaw()}${where}`
|
|
@@ -25031,7 +24944,7 @@ function createDrizzleContentRepository(db, tableName, options = {}) {
|
|
|
25031
24944
|
updated_at: /* @__PURE__ */ new Date()
|
|
25032
24945
|
};
|
|
25033
24946
|
const entries = Object.entries(record).filter(([, v2]) => v2 !== void 0);
|
|
25034
|
-
const colsSql = sql.join(entries.map(([k]) => sql.raw(
|
|
24947
|
+
const colsSql = sql.join(entries.map(([k]) => sql.raw(quoteIdent3(k))), sql`, `);
|
|
25035
24948
|
const valsSql = sql.join(entries.map(([, v2]) => sql`${v2}`), sql`, `);
|
|
25036
24949
|
const result = await db.execute(
|
|
25037
24950
|
sql`INSERT INTO ${tableRaw()} (${colsSql}) VALUES (${valsSql}) RETURNING *`
|
|
@@ -25048,7 +24961,7 @@ function createDrizzleContentRepository(db, tableName, options = {}) {
|
|
|
25048
24961
|
return this.findOne(id);
|
|
25049
24962
|
}
|
|
25050
24963
|
const setClauses = sql.join(
|
|
25051
|
-
entries.map(([k, v2]) => sql`${sql.raw(
|
|
24964
|
+
entries.map(([k, v2]) => sql`${sql.raw(quoteIdent3(k))} = ${v2}`),
|
|
25052
24965
|
sql`, `
|
|
25053
24966
|
);
|
|
25054
24967
|
const result = await db.execute(
|
|
@@ -25457,7 +25370,7 @@ function createCmsApp(options) {
|
|
|
25457
25370
|
handler: null,
|
|
25458
25371
|
error: null
|
|
25459
25372
|
}));
|
|
25460
|
-
const ready = import("./handler-
|
|
25373
|
+
const ready = import("./handler-N5IMQJBP-USVWSLZP.js").then(({ createGraphQLHandler }) => {
|
|
25461
25374
|
gqlPasses.forEach((pass, i) => {
|
|
25462
25375
|
const mount = mounts[i];
|
|
25463
25376
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobbykim/manguito-cms-cli",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.4",
|
|
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.6.
|
|
33
|
-
"@bobbykim/manguito-cms-
|
|
34
|
-
"@bobbykim/manguito-cms-
|
|
35
|
-
"@bobbykim/manguito-cms-
|
|
32
|
+
"@bobbykim/manguito-cms-admin": "0.6.2",
|
|
33
|
+
"@bobbykim/manguito-cms-api": "0.9.3",
|
|
34
|
+
"@bobbykim/manguito-cms-db": "0.2.1",
|
|
35
|
+
"@bobbykim/manguito-cms-core": "0.11.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/node": "^25.9.5",
|