@bobbykim/manguito-cms-cli 0.4.3 → 0.4.5
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.
|
@@ -49,7 +49,7 @@ var init_esm_shims = __esm({
|
|
|
49
49
|
}
|
|
50
50
|
});
|
|
51
51
|
|
|
52
|
-
// ../api/dist/chunk-
|
|
52
|
+
// ../api/dist/chunk-4F2CRXPG.mjs
|
|
53
53
|
init_esm_shims();
|
|
54
54
|
import crypto from "crypto";
|
|
55
55
|
|
|
@@ -1212,7 +1212,7 @@ Subquery.prototype.getSQL = function() {
|
|
|
1212
1212
|
return new SQL([this]);
|
|
1213
1213
|
};
|
|
1214
1214
|
|
|
1215
|
-
// ../api/dist/chunk-
|
|
1215
|
+
// ../api/dist/chunk-4F2CRXPG.mjs
|
|
1216
1216
|
function quoteIdent(name) {
|
|
1217
1217
|
if (!/^[a-z][a-z0-9_-]*$/.test(name)) throw new Error(`Unsafe identifier: ${name}`);
|
|
1218
1218
|
return `"${name}"`;
|
|
@@ -1382,22 +1382,34 @@ function groupBy(items, key) {
|
|
|
1382
1382
|
}
|
|
1383
1383
|
return result;
|
|
1384
1384
|
}
|
|
1385
|
+
function needsFkResolution(row, fkColumn, fieldName) {
|
|
1386
|
+
if (fkColumn !== fieldName && !(fkColumn in row)) return false;
|
|
1387
|
+
const current = row[fieldName];
|
|
1388
|
+
return !(typeof current === "object" && current !== null);
|
|
1389
|
+
}
|
|
1385
1390
|
async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOnly = false) {
|
|
1386
1391
|
if (rows.length === 0) return;
|
|
1392
|
+
const batch = [...new Set(rows)];
|
|
1387
1393
|
if (rel.type === "paragraph") {
|
|
1388
|
-
const parentIds =
|
|
1394
|
+
const parentIds = batch.map((r) => r["id"]);
|
|
1389
1395
|
const inList = sql.join(parentIds.map((id) => sql`${id}`), sql`, `);
|
|
1390
1396
|
const result = await db.execute(
|
|
1391
1397
|
sql`SELECT * FROM ${sql.raw(quoteIdent(rel.table))} WHERE parent_id IN (${inList}) AND parent_field = ${fieldName} ORDER BY "order" ASC`
|
|
1392
1398
|
);
|
|
1393
1399
|
const byParent = groupBy(result.rows, "parent_id");
|
|
1394
|
-
for (const row of
|
|
1400
|
+
for (const row of batch) {
|
|
1395
1401
|
row[fieldName] = byParent[row["id"]] ?? [];
|
|
1396
1402
|
}
|
|
1397
1403
|
} else if (rel.type === "reference") {
|
|
1398
|
-
const
|
|
1404
|
+
const dropFk = rel.fk_column !== fieldName;
|
|
1405
|
+
const pending = batch.filter((r) => needsFkResolution(r, rel.fk_column, fieldName));
|
|
1406
|
+
if (pending.length === 0) return;
|
|
1407
|
+
const fkValues = pending.map((r) => r[rel.fk_column]).filter(Boolean);
|
|
1399
1408
|
if (fkValues.length === 0) {
|
|
1400
|
-
for (const row of
|
|
1409
|
+
for (const row of pending) {
|
|
1410
|
+
row[fieldName] = null;
|
|
1411
|
+
if (dropFk) delete row[rel.fk_column];
|
|
1412
|
+
}
|
|
1401
1413
|
return;
|
|
1402
1414
|
}
|
|
1403
1415
|
const unique = [...new Set(fkValues)];
|
|
@@ -1412,12 +1424,13 @@ async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOn
|
|
|
1412
1424
|
cache.set(`${rel.table}:${item["id"]}`, item);
|
|
1413
1425
|
}
|
|
1414
1426
|
}
|
|
1415
|
-
for (const row of
|
|
1427
|
+
for (const row of pending) {
|
|
1416
1428
|
const fkVal = row[rel.fk_column];
|
|
1417
1429
|
row[fieldName] = fkVal ? cache.get(`${rel.table}:${fkVal}`) ?? null : null;
|
|
1430
|
+
if (dropFk) delete row[rel.fk_column];
|
|
1418
1431
|
}
|
|
1419
1432
|
} else if (rel.type === "junction") {
|
|
1420
|
-
const parentIds =
|
|
1433
|
+
const parentIds = batch.map((r) => r["id"]);
|
|
1421
1434
|
const inList = sql.join(parentIds.map((id) => sql`${id}`), sql`, `);
|
|
1422
1435
|
const orderBy = rel.order_column ? sql` ORDER BY "order" ASC` : sql``;
|
|
1423
1436
|
const junctionResult = await db.execute(
|
|
@@ -1437,14 +1450,20 @@ async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOn
|
|
|
1437
1450
|
}
|
|
1438
1451
|
}
|
|
1439
1452
|
const byLeft = groupBy(jRows, rel.left_column);
|
|
1440
|
-
for (const row of
|
|
1453
|
+
for (const row of batch) {
|
|
1441
1454
|
const jEntries = byLeft[row["id"]] ?? [];
|
|
1442
1455
|
row[fieldName] = jEntries.map((jr) => cache.get(`${rel.table}:${jr[rel.right_column]}`)).filter(Boolean);
|
|
1443
1456
|
}
|
|
1444
1457
|
} else if (rel.type === "media") {
|
|
1445
|
-
const
|
|
1458
|
+
const dropFk = rel.fk_column !== fieldName;
|
|
1459
|
+
const pending = batch.filter((r) => needsFkResolution(r, rel.fk_column, fieldName));
|
|
1460
|
+
if (pending.length === 0) return;
|
|
1461
|
+
const fkValues = pending.map((r) => r[rel.fk_column]).filter(Boolean);
|
|
1446
1462
|
if (fkValues.length === 0) {
|
|
1447
|
-
for (const row of
|
|
1463
|
+
for (const row of pending) {
|
|
1464
|
+
row[fieldName] = null;
|
|
1465
|
+
if (dropFk) delete row[rel.fk_column];
|
|
1466
|
+
}
|
|
1448
1467
|
return;
|
|
1449
1468
|
}
|
|
1450
1469
|
const unique = [...new Set(fkValues)];
|
|
@@ -1456,9 +1475,10 @@ async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOn
|
|
|
1456
1475
|
cache.set(`media:${item["id"]}`, item);
|
|
1457
1476
|
}
|
|
1458
1477
|
}
|
|
1459
|
-
for (const row of
|
|
1478
|
+
for (const row of pending) {
|
|
1460
1479
|
const fkVal = row[rel.fk_column];
|
|
1461
1480
|
row[fieldName] = fkVal ? cache.get(`media:${fkVal}`) ?? null : null;
|
|
1481
|
+
if (dropFk) delete row[rel.fk_column];
|
|
1462
1482
|
}
|
|
1463
1483
|
}
|
|
1464
1484
|
}
|
|
@@ -1486,6 +1506,46 @@ async function resolveRelationBareIds(db, rows, fieldName, rel) {
|
|
|
1486
1506
|
}
|
|
1487
1507
|
}
|
|
1488
1508
|
}
|
|
1509
|
+
function isColumnBacked(field) {
|
|
1510
|
+
const col = field.db_column;
|
|
1511
|
+
if (col === null) return false;
|
|
1512
|
+
if (col.column_name === "") return false;
|
|
1513
|
+
if (col.junction) return false;
|
|
1514
|
+
return true;
|
|
1515
|
+
}
|
|
1516
|
+
function createFieldKeyMap(fields) {
|
|
1517
|
+
const labelToColumn = /* @__PURE__ */ new Map();
|
|
1518
|
+
const columnToLabel = /* @__PURE__ */ new Map();
|
|
1519
|
+
for (const f of fields) {
|
|
1520
|
+
if (!isColumnBacked(f)) continue;
|
|
1521
|
+
labelToColumn.set(f.name, f.db_column.column_name);
|
|
1522
|
+
columnToLabel.set(f.db_column.column_name, f.name);
|
|
1523
|
+
}
|
|
1524
|
+
for (const f of fields) {
|
|
1525
|
+
const columnOwner = columnToLabel.get(f.name);
|
|
1526
|
+
if (columnOwner !== void 0 && columnOwner !== f.name) {
|
|
1527
|
+
throw new Error(
|
|
1528
|
+
`Fatal: field key map failed to build \u2014 field label "${f.name}" collides with the storage column of field "${columnOwner}". A field label may not reuse another field's column name. Rename the field, then run \`manguito validate\` to check your schema.`
|
|
1529
|
+
);
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
const diverges = [...labelToColumn].some(([label, column]) => label !== column);
|
|
1533
|
+
function remap(input, lookup) {
|
|
1534
|
+
const out = {};
|
|
1535
|
+
for (const key of Object.keys(input)) {
|
|
1536
|
+
out[lookup.get(key) ?? key] = input[key];
|
|
1537
|
+
}
|
|
1538
|
+
return out;
|
|
1539
|
+
}
|
|
1540
|
+
return {
|
|
1541
|
+
toStorage: (input) => remap(input, labelToColumn),
|
|
1542
|
+
toLabels: (row) => remap(row, columnToLabel),
|
|
1543
|
+
columnFor: (label) => labelToColumn.get(label),
|
|
1544
|
+
labelFor: (column) => columnToLabel.get(column),
|
|
1545
|
+
labels: [...labelToColumn.keys()],
|
|
1546
|
+
diverges
|
|
1547
|
+
};
|
|
1548
|
+
}
|
|
1489
1549
|
|
|
1490
1550
|
export {
|
|
1491
1551
|
__require,
|
|
@@ -1523,5 +1583,7 @@ export {
|
|
|
1523
1583
|
persistJunctionField,
|
|
1524
1584
|
buildRelationsMap,
|
|
1525
1585
|
resolveRelationField,
|
|
1526
|
-
resolveRelationBareIds
|
|
1586
|
+
resolveRelationBareIds,
|
|
1587
|
+
isColumnBacked,
|
|
1588
|
+
createFieldKeyMap
|
|
1527
1589
|
};
|
|
@@ -9,8 +9,9 @@ import {
|
|
|
9
9
|
__toESM,
|
|
10
10
|
buildRelationsMap,
|
|
11
11
|
init_esm_shims,
|
|
12
|
+
isColumnBacked,
|
|
12
13
|
resolveRelationField
|
|
13
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-UNBMPHIT.js";
|
|
14
15
|
|
|
15
16
|
// ../../node_modules/.pnpm/@whatwg-node+fetch@0.10.13/node_modules/@whatwg-node/fetch/dist/shouldSkipPonyfill.js
|
|
16
17
|
var require_shouldSkipPonyfill = __commonJS({
|
|
@@ -10785,10 +10786,10 @@ var require_parser = __commonJS({
|
|
|
10785
10786
|
}
|
|
10786
10787
|
});
|
|
10787
10788
|
|
|
10788
|
-
// ../api/dist/handler-
|
|
10789
|
+
// ../api/dist/handler-7LVYEU5C.mjs
|
|
10789
10790
|
init_esm_shims();
|
|
10790
10791
|
|
|
10791
|
-
// ../api/dist/chunk-
|
|
10792
|
+
// ../api/dist/chunk-S4NT6FUM.mjs
|
|
10792
10793
|
init_esm_shims();
|
|
10793
10794
|
|
|
10794
10795
|
// ../../node_modules/.pnpm/graphql-yoga@5.21.2_graphql@16.14.2/node_modules/graphql-yoga/esm/index.js
|
|
@@ -30121,7 +30122,7 @@ function createYoga(options) {
|
|
|
30121
30122
|
});
|
|
30122
30123
|
}
|
|
30123
30124
|
|
|
30124
|
-
// ../api/dist/chunk-
|
|
30125
|
+
// ../api/dist/chunk-S4NT6FUM.mjs
|
|
30125
30126
|
var import_dataloader = __toESM(require_dataloader(), 1);
|
|
30126
30127
|
|
|
30127
30128
|
// ../../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
|
|
@@ -30879,7 +30880,7 @@ var EnvelopArmor = class {
|
|
|
30879
30880
|
}
|
|
30880
30881
|
};
|
|
30881
30882
|
|
|
30882
|
-
// ../api/dist/chunk-
|
|
30883
|
+
// ../api/dist/chunk-S4NT6FUM.mjs
|
|
30883
30884
|
var DateTimeScalar = new GraphQLScalarType({
|
|
30884
30885
|
name: "DateTime",
|
|
30885
30886
|
description: "ISO-8601 date-time string",
|
|
@@ -30974,14 +30975,14 @@ var SortOrderEnum = new GraphQLEnumType({
|
|
|
30974
30975
|
values: { ASC: { value: "asc" }, DESC: { value: "desc" } }
|
|
30975
30976
|
});
|
|
30976
30977
|
var SORTABLE = [
|
|
30977
|
-
{ gql: "title",
|
|
30978
|
-
{ gql: "createdAt",
|
|
30979
|
-
{ gql: "updatedAt",
|
|
30978
|
+
{ gql: "title", value: "title" },
|
|
30979
|
+
{ gql: "createdAt", value: "created_at" },
|
|
30980
|
+
{ gql: "updatedAt", value: "updated_at" }
|
|
30980
30981
|
];
|
|
30981
30982
|
function buildSortFieldEnum(typeName) {
|
|
30982
30983
|
return new GraphQLEnumType({
|
|
30983
30984
|
name: `${typeName}SortField`,
|
|
30984
|
-
values: Object.fromEntries(SORTABLE.map((s) => [s.gql, { value: s.
|
|
30985
|
+
values: Object.fromEntries(SORTABLE.map((s) => [s.gql, { value: s.value }]))
|
|
30985
30986
|
});
|
|
30986
30987
|
}
|
|
30987
30988
|
function comparableFilterInput(name, scalar) {
|
|
@@ -31041,12 +31042,13 @@ function buildFilterInputType(type) {
|
|
|
31041
31042
|
if (Object.keys(fields).length === 0) return null;
|
|
31042
31043
|
return new GraphQLInputObjectType({ name: `${graphqlTypeName(type.name)}Filter`, fields });
|
|
31043
31044
|
}
|
|
31044
|
-
function translateFilters(input, nameMap) {
|
|
31045
|
+
function translateFilters(input, nameMap, columnFor) {
|
|
31045
31046
|
const out = {};
|
|
31046
31047
|
if (!input) return out;
|
|
31047
31048
|
for (const [gqlField, raw] of Object.entries(input)) {
|
|
31048
31049
|
if (raw === null || typeof raw !== "object") continue;
|
|
31049
|
-
const
|
|
31050
|
+
const label = nameMap.toSchema(gqlField);
|
|
31051
|
+
const column = columnFor?.(label) ?? label;
|
|
31050
31052
|
const spec = raw;
|
|
31051
31053
|
if (spec["eq"] !== void 0) {
|
|
31052
31054
|
out[column] = spec["eq"];
|
|
@@ -31068,29 +31070,34 @@ function codeError(code, message) {
|
|
|
31068
31070
|
function isPublished(item) {
|
|
31069
31071
|
return !!item && item["published"] === true;
|
|
31070
31072
|
}
|
|
31071
|
-
function
|
|
31072
|
-
|
|
31073
|
+
function resolveFieldValue(field, row) {
|
|
31074
|
+
const key = isColumnBacked(field) ? field.db_column.column_name : field.name;
|
|
31075
|
+
return row[key] ?? null;
|
|
31076
|
+
}
|
|
31077
|
+
function scalarFieldResolver(field) {
|
|
31078
|
+
return (parent) => resolveFieldValue(field, parent);
|
|
31073
31079
|
}
|
|
31074
31080
|
function relationFieldResolver(typeName, schemaFieldName) {
|
|
31075
31081
|
return (parent, _args, ctx) => ctx.loaders.load(typeName, schemaFieldName, parent);
|
|
31076
31082
|
}
|
|
31077
|
-
function programmaticFieldResolver(typeName, schemaFieldName, mediaFieldNames = []) {
|
|
31083
|
+
function programmaticFieldResolver(typeName, schemaFieldName, mediaFieldNames = [], fieldKeys) {
|
|
31078
31084
|
return async (parent, _args, ctx) => {
|
|
31079
31085
|
let p = ctx.programmaticMemo.get(parent);
|
|
31080
31086
|
if (!p) {
|
|
31081
|
-
p = resolveProgrammaticRow(typeName, parent, ctx, mediaFieldNames);
|
|
31087
|
+
p = resolveProgrammaticRow(typeName, parent, ctx, mediaFieldNames, fieldKeys);
|
|
31082
31088
|
ctx.programmaticMemo.set(parent, p);
|
|
31083
31089
|
}
|
|
31084
31090
|
return (await p)[schemaFieldName];
|
|
31085
31091
|
};
|
|
31086
31092
|
}
|
|
31087
|
-
async function resolveProgrammaticRow(typeName, parent, ctx, mediaFieldNames) {
|
|
31088
|
-
|
|
31093
|
+
async function resolveProgrammaticRow(typeName, parent, ctx, mediaFieldNames, fieldKeys) {
|
|
31094
|
+
const toLabels = (row) => fieldKeys ? fieldKeys.toLabels(row) : row;
|
|
31095
|
+
if (mediaFieldNames.length === 0) return ctx.resolver.resolveItem(typeName, toLabels(parent));
|
|
31089
31096
|
const enriched = { ...parent };
|
|
31090
31097
|
await Promise.all(mediaFieldNames.map((name) => ctx.loaders.load(typeName, name, enriched)));
|
|
31091
|
-
return ctx.resolver.resolveItem(typeName, enriched);
|
|
31098
|
+
return ctx.resolver.resolveItem(typeName, toLabels(enriched));
|
|
31092
31099
|
}
|
|
31093
|
-
function collectionResolver(typeName, nameMap) {
|
|
31100
|
+
function collectionResolver(typeName, nameMap, fieldKeys) {
|
|
31094
31101
|
return async (_root, args, ctx) => {
|
|
31095
31102
|
const page = args.page ?? 1;
|
|
31096
31103
|
const perPage = args.perPage ?? 10;
|
|
@@ -31101,13 +31108,15 @@ function collectionResolver(typeName, nameMap) {
|
|
|
31101
31108
|
throw codeError("INVALID_PAGINATION", "perPage must be between 1 and 100");
|
|
31102
31109
|
}
|
|
31103
31110
|
const repo = ctx.repos[typeName];
|
|
31111
|
+
const sortBy = args.sortBy ?? "created_at";
|
|
31112
|
+
const sortColumn = fieldKeys?.columnFor(sortBy) ?? sortBy;
|
|
31104
31113
|
const result = await repo.findMany({
|
|
31105
31114
|
published_only: true,
|
|
31106
31115
|
page,
|
|
31107
31116
|
per_page: perPage,
|
|
31108
|
-
sort_by:
|
|
31117
|
+
sort_by: sortColumn,
|
|
31109
31118
|
sort_order: args.sortOrder ?? "asc",
|
|
31110
|
-
filters: translateFilters(args.filter, nameMap)
|
|
31119
|
+
filters: translateFilters(args.filter, nameMap, fieldKeys?.columnFor)
|
|
31111
31120
|
});
|
|
31112
31121
|
return { data: result.data, meta: result.meta };
|
|
31113
31122
|
};
|
|
@@ -31158,7 +31167,7 @@ var MEDIA = new GraphQLObjectType({
|
|
|
31158
31167
|
duration: { type: GraphQLInt, resolve: (m) => m.duration }
|
|
31159
31168
|
}
|
|
31160
31169
|
});
|
|
31161
|
-
function buildGraphQLSchema(registry) {
|
|
31170
|
+
function buildGraphQLSchema(registry, fieldKeyMaps = {}) {
|
|
31162
31171
|
const objectTypes = /* @__PURE__ */ new Map();
|
|
31163
31172
|
const enumTypes = /* @__PURE__ */ new Map();
|
|
31164
31173
|
for (const [name, enumType] of Object.entries(registry.enum_types)) {
|
|
@@ -31234,11 +31243,16 @@ function buildGraphQLSchema(registry) {
|
|
|
31234
31243
|
const outType = outputTypeForField(field);
|
|
31235
31244
|
let resolve;
|
|
31236
31245
|
if (field.field_type === "programmatic") {
|
|
31237
|
-
resolve = programmaticFieldResolver(
|
|
31246
|
+
resolve = programmaticFieldResolver(
|
|
31247
|
+
machineName,
|
|
31248
|
+
field.name,
|
|
31249
|
+
mediaFieldNames,
|
|
31250
|
+
fieldKeyMaps[machineName]
|
|
31251
|
+
);
|
|
31238
31252
|
} else if (field.field_type === "reference" || field.field_type === "paragraph" || field.field_type === "image" || field.field_type === "video" || field.field_type === "file") {
|
|
31239
31253
|
resolve = relationFieldResolver(machineName, field.name);
|
|
31240
31254
|
} else {
|
|
31241
|
-
resolve = scalarFieldResolver(field
|
|
31255
|
+
resolve = scalarFieldResolver(field);
|
|
31242
31256
|
}
|
|
31243
31257
|
fields[gqlName] = { type: outType, resolve };
|
|
31244
31258
|
}
|
|
@@ -31294,7 +31308,7 @@ function buildGraphQLSchema(registry) {
|
|
|
31294
31308
|
sortOrder: { type: SortOrderEnum },
|
|
31295
31309
|
...filterType ? { filter: { type: filterType } } : {}
|
|
31296
31310
|
},
|
|
31297
|
-
resolve: collectionResolver(name, nameMap)
|
|
31311
|
+
resolve: collectionResolver(name, nameMap, fieldKeyMaps[name])
|
|
31298
31312
|
};
|
|
31299
31313
|
queryFields[singleQueryName(name)] = {
|
|
31300
31314
|
type: objType,
|
|
@@ -31314,7 +31328,7 @@ function buildGraphQLSchema(registry) {
|
|
|
31314
31328
|
queryFields[collectionQueryName(name)] = {
|
|
31315
31329
|
type: new GraphQLNonNull(listType),
|
|
31316
31330
|
args: { page: { type: GraphQLInt }, perPage: { type: GraphQLInt } },
|
|
31317
|
-
resolve: collectionResolver(name, buildFieldNameMap(tt.fields.map((f) => f.name)))
|
|
31331
|
+
resolve: collectionResolver(name, buildFieldNameMap(tt.fields.map((f) => f.name)), fieldKeyMaps[name])
|
|
31318
31332
|
};
|
|
31319
31333
|
queryFields[singleQueryName(name)] = {
|
|
31320
31334
|
type: objType,
|
|
@@ -31393,8 +31407,8 @@ function isClientSafeGraphQLError(error) {
|
|
|
31393
31407
|
}
|
|
31394
31408
|
return false;
|
|
31395
31409
|
}
|
|
31396
|
-
function createGraphQLHandler(registry, repos, resolver, db, options) {
|
|
31397
|
-
const schema = buildGraphQLSchema(registry);
|
|
31410
|
+
function createGraphQLHandler(registry, repos, fieldKeyMaps, resolver, db, options) {
|
|
31411
|
+
const schema = buildGraphQLSchema(registry, fieldKeyMaps);
|
|
31398
31412
|
const { plugins } = buildArmorPlugin({
|
|
31399
31413
|
maxDepth: options.maxDepth,
|
|
31400
31414
|
maxComplexity: options.maxComplexity
|
package/dist/index.js
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
__require,
|
|
22
22
|
__toESM,
|
|
23
23
|
buildRelationsMap,
|
|
24
|
+
createFieldKeyMap,
|
|
24
25
|
deleteParagraphField,
|
|
25
26
|
entityKind,
|
|
26
27
|
fillPlaceholders,
|
|
@@ -28,6 +29,7 @@ import {
|
|
|
28
29
|
getTableUniqueName,
|
|
29
30
|
init_esm_shims,
|
|
30
31
|
is,
|
|
32
|
+
isColumnBacked,
|
|
31
33
|
isDriverValueEncoder,
|
|
32
34
|
isSQLWrapper,
|
|
33
35
|
persistJunctionField,
|
|
@@ -36,7 +38,7 @@ import {
|
|
|
36
38
|
resolveRelationField,
|
|
37
39
|
sql,
|
|
38
40
|
tracer
|
|
39
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-UNBMPHIT.js";
|
|
40
42
|
|
|
41
43
|
// ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/identity.js
|
|
42
44
|
var require_identity = __commonJS({
|
|
@@ -46557,6 +46559,23 @@ var sign2 = Jwt.sign;
|
|
|
46557
46559
|
import { randomBytes } from "crypto";
|
|
46558
46560
|
import crypto3 from "crypto";
|
|
46559
46561
|
import crypto22 from "crypto";
|
|
46562
|
+
function normalizePrefix(prefix) {
|
|
46563
|
+
if (prefix === void 0) return "/api";
|
|
46564
|
+
const withSlash = prefix.startsWith("/") ? prefix : `/${prefix}`;
|
|
46565
|
+
const trimmed = withSlash.replace(/\/+$/, "");
|
|
46566
|
+
return trimmed === "" ? "/api" : trimmed;
|
|
46567
|
+
}
|
|
46568
|
+
function createPublicPaths(prefix) {
|
|
46569
|
+
return {
|
|
46570
|
+
collection: (basePath) => `${prefix}/${basePath}`,
|
|
46571
|
+
item: (basePath) => `${prefix}/${basePath}/:slug`,
|
|
46572
|
+
taxonomyCollection: (typeName) => `${prefix}/taxonomy/${typeName}`,
|
|
46573
|
+
taxonomyItem: (typeName) => `${prefix}/taxonomy/${typeName}/:id`,
|
|
46574
|
+
mediaCollection: () => `${prefix}/media`,
|
|
46575
|
+
mediaItem: () => `${prefix}/media/:id`,
|
|
46576
|
+
openapi: () => `${prefix}/openapi.json`
|
|
46577
|
+
};
|
|
46578
|
+
}
|
|
46560
46579
|
function createCorsMiddleware(corsConfig) {
|
|
46561
46580
|
const allowList = Array.isArray(corsConfig.origin) ? corsConfig.origin : [corsConfig.origin];
|
|
46562
46581
|
const wildcard = allowList.includes("*");
|
|
@@ -47103,6 +47122,52 @@ function createProgrammaticResolver(resolvers, options) {
|
|
|
47103
47122
|
}
|
|
47104
47123
|
return { resolveItem, resolveList, hasSchema };
|
|
47105
47124
|
}
|
|
47125
|
+
function isPlainRow(v2) {
|
|
47126
|
+
return typeof v2 === "object" && v2 !== null && !Array.isArray(v2) && !(v2 instanceof Date);
|
|
47127
|
+
}
|
|
47128
|
+
var MEDIA_FIELD_TYPES = /* @__PURE__ */ new Set(["image", "video", "file"]);
|
|
47129
|
+
function nestedTargets(fields) {
|
|
47130
|
+
const out = [];
|
|
47131
|
+
for (const f of fields) {
|
|
47132
|
+
if (MEDIA_FIELD_TYPES.has(f.field_type)) continue;
|
|
47133
|
+
if (f.field_type !== "paragraph" && f.field_type !== "reference") continue;
|
|
47134
|
+
const ref = f.ui_component.ref;
|
|
47135
|
+
if (!ref) continue;
|
|
47136
|
+
out.push({ label: f.name, target: ref });
|
|
47137
|
+
}
|
|
47138
|
+
return out;
|
|
47139
|
+
}
|
|
47140
|
+
function buildProjectors(registry2, fieldKeyMaps) {
|
|
47141
|
+
const projectors = {};
|
|
47142
|
+
const sources = [
|
|
47143
|
+
registry2.content_types,
|
|
47144
|
+
registry2.taxonomy_types,
|
|
47145
|
+
registry2.paragraph_types
|
|
47146
|
+
];
|
|
47147
|
+
for (const source of sources) {
|
|
47148
|
+
for (const [typeName, type] of Object.entries(source)) {
|
|
47149
|
+
const map2 = fieldKeyMaps[typeName];
|
|
47150
|
+
if (!map2) continue;
|
|
47151
|
+
projectors[typeName] = { map: map2, nested: nestedTargets(type.fields) };
|
|
47152
|
+
}
|
|
47153
|
+
}
|
|
47154
|
+
return projectors;
|
|
47155
|
+
}
|
|
47156
|
+
function projectRow(row, typeName, projectors) {
|
|
47157
|
+
const p2 = projectors[typeName];
|
|
47158
|
+
if (!p2) return row;
|
|
47159
|
+
const out = p2.map.toLabels(row);
|
|
47160
|
+
for (const { label, target } of p2.nested) {
|
|
47161
|
+
const v2 = out[label];
|
|
47162
|
+
if (v2 === null || v2 === void 0) continue;
|
|
47163
|
+
if (Array.isArray(v2)) {
|
|
47164
|
+
out[label] = v2.map((item) => isPlainRow(item) ? projectRow(item, target, projectors) : item);
|
|
47165
|
+
} else if (isPlainRow(v2)) {
|
|
47166
|
+
out[label] = projectRow(v2, target, projectors);
|
|
47167
|
+
}
|
|
47168
|
+
}
|
|
47169
|
+
return out;
|
|
47170
|
+
}
|
|
47106
47171
|
var SORTABLE_FIELDS = /* @__PURE__ */ new Set(["title", "created_at", "updated_at"]);
|
|
47107
47172
|
var RELATION_FIELD_TYPES = /* @__PURE__ */ new Set([
|
|
47108
47173
|
"paragraph",
|
|
@@ -47122,28 +47187,31 @@ function parseInclude(includeParam) {
|
|
|
47122
47187
|
if (!includeParam) return [];
|
|
47123
47188
|
return includeParam.split(",").map((s) => s.trim()).filter(Boolean);
|
|
47124
47189
|
}
|
|
47125
|
-
function parseFilters(url2, validFields) {
|
|
47190
|
+
function parseFilters(url2, validFields, columnFor) {
|
|
47126
47191
|
const { searchParams } = new URL(url2);
|
|
47127
47192
|
const filters = {};
|
|
47193
|
+
const toKey = (label) => columnFor?.(label) ?? label;
|
|
47128
47194
|
for (const [key, value] of searchParams.entries()) {
|
|
47129
47195
|
const simpleMatch = /^filter\[([^\]]+)\]$/.exec(key);
|
|
47130
47196
|
const opMatch = /^filter\[([^\]]+)\]\[([^\]]+)\]$/.exec(key);
|
|
47131
47197
|
if (simpleMatch) {
|
|
47132
47198
|
const field = simpleMatch[1];
|
|
47133
47199
|
if (!validFields.has(field)) return { ok: false, invalidField: field };
|
|
47134
|
-
const
|
|
47200
|
+
const storageKey = toKey(field);
|
|
47201
|
+
const existing = filters[storageKey];
|
|
47135
47202
|
if (existing !== void 0) {
|
|
47136
|
-
filters[
|
|
47203
|
+
filters[storageKey] = Array.isArray(existing) ? [...existing, value] : [existing, value];
|
|
47137
47204
|
} else {
|
|
47138
|
-
filters[
|
|
47205
|
+
filters[storageKey] = value;
|
|
47139
47206
|
}
|
|
47140
47207
|
} else if (opMatch) {
|
|
47141
47208
|
const field = opMatch[1];
|
|
47142
47209
|
const operator = opMatch[2];
|
|
47143
47210
|
if (!validFields.has(field)) return { ok: false, invalidField: field };
|
|
47144
47211
|
if (!["gt", "gte", "lt", "lte"].includes(operator)) continue;
|
|
47145
|
-
const
|
|
47146
|
-
|
|
47212
|
+
const storageKey = toKey(field);
|
|
47213
|
+
const existing = filters[storageKey] ?? {};
|
|
47214
|
+
filters[storageKey] = { ...existing, [operator]: value };
|
|
47147
47215
|
}
|
|
47148
47216
|
}
|
|
47149
47217
|
return { ok: true, filters };
|
|
@@ -47151,7 +47219,7 @@ function parseFilters(url2, validFields) {
|
|
|
47151
47219
|
function isPublished(item) {
|
|
47152
47220
|
return item["published"] === true;
|
|
47153
47221
|
}
|
|
47154
|
-
function registerPublicContentRoutes(app, registry2, repos, listRateLimit, resolver) {
|
|
47222
|
+
function registerPublicContentRoutes(app, registry2, repos, projectors, paths, listRateLimit, resolver) {
|
|
47155
47223
|
function registerListRoute(path3, handler) {
|
|
47156
47224
|
if (listRateLimit) {
|
|
47157
47225
|
app.get(path3, listRateLimit, handler);
|
|
@@ -47159,7 +47227,7 @@ function registerPublicContentRoutes(app, registry2, repos, listRateLimit, resol
|
|
|
47159
47227
|
app.get(path3, handler);
|
|
47160
47228
|
}
|
|
47161
47229
|
}
|
|
47162
|
-
registerListRoute("
|
|
47230
|
+
registerListRoute(paths.collection("content"), (c) => {
|
|
47163
47231
|
const data = Object.values(registry2.content_types).map((ct2) => ({
|
|
47164
47232
|
name: ct2.name,
|
|
47165
47233
|
label: ct2.label,
|
|
@@ -47167,7 +47235,7 @@ function registerPublicContentRoutes(app, registry2, repos, listRateLimit, resol
|
|
|
47167
47235
|
}));
|
|
47168
47236
|
return c.json({ ok: true, data });
|
|
47169
47237
|
});
|
|
47170
|
-
registerListRoute("
|
|
47238
|
+
registerListRoute(paths.collection("taxonomy"), (c) => {
|
|
47171
47239
|
const data = Object.values(registry2.taxonomy_types).map((tt2) => ({
|
|
47172
47240
|
name: tt2.name,
|
|
47173
47241
|
label: tt2.label
|
|
@@ -47186,7 +47254,7 @@ function registerPublicContentRoutes(app, registry2, repos, listRateLimit, resol
|
|
|
47186
47254
|
...contentType.system_fields.map((f) => f.name)
|
|
47187
47255
|
]);
|
|
47188
47256
|
if (contentType.only_one) {
|
|
47189
|
-
app.get(
|
|
47257
|
+
app.get(paths.collection(basePath), async (c) => {
|
|
47190
47258
|
const result = await repo.findMany({ published_only: true, page: 1, per_page: 1 });
|
|
47191
47259
|
if (result.data.length === 0) {
|
|
47192
47260
|
return c.json(
|
|
@@ -47194,12 +47262,14 @@ function registerPublicContentRoutes(app, registry2, repos, listRateLimit, resol
|
|
|
47194
47262
|
404
|
|
47195
47263
|
);
|
|
47196
47264
|
}
|
|
47197
|
-
let data = result.data[0];
|
|
47265
|
+
let data = projectRow(result.data[0], typeName, projectors);
|
|
47198
47266
|
if (resolver?.hasSchema(typeName)) data = await resolver.resolveItem(typeName, data);
|
|
47199
47267
|
return c.json({ ok: true, data });
|
|
47200
47268
|
});
|
|
47201
47269
|
} else {
|
|
47202
|
-
registerListRoute(
|
|
47270
|
+
registerListRoute(paths.collection(basePath), async (c) => {
|
|
47271
|
+
const projector = projectors[typeName];
|
|
47272
|
+
const fieldKeys = projector.map;
|
|
47203
47273
|
const pagination = parsePagination(c.req.query("page"), c.req.query("per_page"));
|
|
47204
47274
|
if (!pagination.ok) {
|
|
47205
47275
|
return c.json(
|
|
@@ -47239,7 +47309,7 @@ function registerPublicContentRoutes(app, registry2, repos, listRateLimit, resol
|
|
|
47239
47309
|
400
|
|
47240
47310
|
);
|
|
47241
47311
|
}
|
|
47242
|
-
const filtersResult = parseFilters(c.req.url, filterableFieldNames);
|
|
47312
|
+
const filtersResult = parseFilters(c.req.url, filterableFieldNames, fieldKeys.columnFor);
|
|
47243
47313
|
if (!filtersResult.ok) {
|
|
47244
47314
|
return c.json(
|
|
47245
47315
|
{
|
|
@@ -47267,22 +47337,23 @@ function registerPublicContentRoutes(app, registry2, repos, listRateLimit, resol
|
|
|
47267
47337
|
);
|
|
47268
47338
|
}
|
|
47269
47339
|
}
|
|
47340
|
+
const sortColumn = fieldKeys.columnFor(sortBy) ?? sortBy;
|
|
47270
47341
|
const result = await repo.findMany({
|
|
47271
47342
|
published_only: true,
|
|
47272
47343
|
page: pagination.page,
|
|
47273
47344
|
per_page: pagination.per_page,
|
|
47274
|
-
sort_by:
|
|
47345
|
+
sort_by: sortColumn,
|
|
47275
47346
|
sort_order: sortOrder,
|
|
47276
47347
|
filters: filtersResult.filters,
|
|
47277
47348
|
include
|
|
47278
47349
|
});
|
|
47279
|
-
|
|
47280
|
-
|
|
47281
|
-
|
|
47282
|
-
|
|
47283
|
-
return c.json(result);
|
|
47350
|
+
const labeled = result.data.map(
|
|
47351
|
+
(row) => projectRow(row, typeName, projectors)
|
|
47352
|
+
);
|
|
47353
|
+
const data = resolver?.hasSchema(typeName) ? await resolver.resolveList(typeName, labeled) : labeled;
|
|
47354
|
+
return c.json({ ...result, data });
|
|
47284
47355
|
});
|
|
47285
|
-
app.get(
|
|
47356
|
+
app.get(paths.item(basePath), async (c) => {
|
|
47286
47357
|
const slug = c.req.param("slug");
|
|
47287
47358
|
const include = parseInclude(c.req.query("include"));
|
|
47288
47359
|
for (const field of include) {
|
|
@@ -47309,7 +47380,7 @@ function registerPublicContentRoutes(app, registry2, repos, listRateLimit, resol
|
|
|
47309
47380
|
404
|
|
47310
47381
|
);
|
|
47311
47382
|
}
|
|
47312
|
-
let data = item;
|
|
47383
|
+
let data = projectRow(item, typeName, projectors);
|
|
47313
47384
|
if (resolver?.hasSchema(typeName)) data = await resolver.resolveItem(typeName, data);
|
|
47314
47385
|
return c.json({ ok: true, data });
|
|
47315
47386
|
});
|
|
@@ -47318,7 +47389,7 @@ function registerPublicContentRoutes(app, registry2, repos, listRateLimit, resol
|
|
|
47318
47389
|
for (const [typeName] of Object.entries(registry2.taxonomy_types)) {
|
|
47319
47390
|
const repo = repos[typeName];
|
|
47320
47391
|
if (!repo) continue;
|
|
47321
|
-
registerListRoute(
|
|
47392
|
+
registerListRoute(paths.taxonomyCollection(typeName), async (c) => {
|
|
47322
47393
|
const pagination = parsePagination(c.req.query("page"), c.req.query("per_page"));
|
|
47323
47394
|
if (!pagination.ok) {
|
|
47324
47395
|
return c.json(
|
|
@@ -47337,13 +47408,13 @@ function registerPublicContentRoutes(app, registry2, repos, listRateLimit, resol
|
|
|
47337
47408
|
page: pagination.page,
|
|
47338
47409
|
per_page: pagination.per_page
|
|
47339
47410
|
});
|
|
47340
|
-
|
|
47341
|
-
|
|
47342
|
-
|
|
47343
|
-
|
|
47344
|
-
return c.json(result);
|
|
47411
|
+
const labeled = result.data.map(
|
|
47412
|
+
(row) => projectRow(row, typeName, projectors)
|
|
47413
|
+
);
|
|
47414
|
+
const data = resolver?.hasSchema(typeName) ? await resolver.resolveList(typeName, labeled) : labeled;
|
|
47415
|
+
return c.json({ ...result, data });
|
|
47345
47416
|
});
|
|
47346
|
-
app.get(
|
|
47417
|
+
app.get(paths.taxonomyItem(typeName), async (c) => {
|
|
47347
47418
|
const id = c.req.param("id");
|
|
47348
47419
|
const item = await repo.findOne(id);
|
|
47349
47420
|
if (!item || !isPublished(item)) {
|
|
@@ -47355,7 +47426,7 @@ function registerPublicContentRoutes(app, registry2, repos, listRateLimit, resol
|
|
|
47355
47426
|
404
|
|
47356
47427
|
);
|
|
47357
47428
|
}
|
|
47358
|
-
let data = item;
|
|
47429
|
+
let data = projectRow(item, typeName, projectors);
|
|
47359
47430
|
if (resolver?.hasSchema(typeName)) data = await resolver.resolveItem(typeName, data);
|
|
47360
47431
|
return c.json({ ok: true, data });
|
|
47361
47432
|
});
|
|
@@ -47369,7 +47440,7 @@ function parsePagination2(pageStr, perPageStr) {
|
|
|
47369
47440
|
if (!Number.isInteger(per_page) || per_page < 1 || per_page > 100) return { ok: false };
|
|
47370
47441
|
return { ok: true, page, per_page };
|
|
47371
47442
|
}
|
|
47372
|
-
function registerPublicMediaRoutes(app, mediaRepo, listRateLimit) {
|
|
47443
|
+
function registerPublicMediaRoutes(app, mediaRepo, paths, listRateLimit) {
|
|
47373
47444
|
const mediaListHandler = async (c) => {
|
|
47374
47445
|
const pagination = parsePagination2(c.req.query("page"), c.req.query("per_page"));
|
|
47375
47446
|
if (!pagination.ok) {
|
|
@@ -47408,11 +47479,11 @@ function registerPublicMediaRoutes(app, mediaRepo, listRateLimit) {
|
|
|
47408
47479
|
return c.json(result);
|
|
47409
47480
|
};
|
|
47410
47481
|
if (listRateLimit) {
|
|
47411
|
-
app.get(
|
|
47482
|
+
app.get(paths.mediaCollection(), listRateLimit, mediaListHandler);
|
|
47412
47483
|
} else {
|
|
47413
|
-
app.get(
|
|
47484
|
+
app.get(paths.mediaCollection(), mediaListHandler);
|
|
47414
47485
|
}
|
|
47415
|
-
app.get(
|
|
47486
|
+
app.get(paths.mediaItem(), async (c) => {
|
|
47416
47487
|
const id = c.req.param("id");
|
|
47417
47488
|
const item = await mediaRepo.findOne(id);
|
|
47418
47489
|
if (!item) {
|
|
@@ -47431,9 +47502,11 @@ function topLevelMediaDelta(mediaFields, before, after) {
|
|
|
47431
47502
|
const added = [];
|
|
47432
47503
|
const removed = [];
|
|
47433
47504
|
for (const f of mediaFields) {
|
|
47434
|
-
|
|
47435
|
-
|
|
47436
|
-
|
|
47505
|
+
const key = f.db_column?.column_name;
|
|
47506
|
+
if (key === void 0 || key === "") continue;
|
|
47507
|
+
if (after !== null && !(key in after)) continue;
|
|
47508
|
+
const oldId = before ? extractMediaId(before[key]) : null;
|
|
47509
|
+
const newId = after ? extractMediaId(after[key]) : null;
|
|
47437
47510
|
if (newId === oldId) continue;
|
|
47438
47511
|
if (oldId) removed.push(oldId);
|
|
47439
47512
|
if (newId) added.push(newId);
|
|
@@ -47491,7 +47564,7 @@ function isEmpty(value) {
|
|
|
47491
47564
|
function checkRequiredFields(fields, data) {
|
|
47492
47565
|
return fields.filter((f) => f.required && isEmpty(data[f.name])).map((f) => ({ field: f.name, message: `${f.label} is required` }));
|
|
47493
47566
|
}
|
|
47494
|
-
function parseListQuery(url2, schemaFieldNames, relationFieldNames) {
|
|
47567
|
+
function parseListQuery(url2, schemaFieldNames, relationFieldNames, columnFor) {
|
|
47495
47568
|
const searchParams = new URL(url2).searchParams;
|
|
47496
47569
|
const pagination = parsePagination(
|
|
47497
47570
|
searchParams.get("page") ?? void 0,
|
|
@@ -47526,7 +47599,7 @@ function parseListQuery(url2, schemaFieldNames, relationFieldNames) {
|
|
|
47526
47599
|
status: 400
|
|
47527
47600
|
};
|
|
47528
47601
|
}
|
|
47529
|
-
const filtersResult = parseFilters(url2, schemaFieldNames);
|
|
47602
|
+
const filtersResult = parseFilters(url2, schemaFieldNames, columnFor);
|
|
47530
47603
|
if (!filtersResult.ok) {
|
|
47531
47604
|
return {
|
|
47532
47605
|
ok: false,
|
|
@@ -47558,7 +47631,7 @@ function parseListQuery(url2, schemaFieldNames, relationFieldNames) {
|
|
|
47558
47631
|
search
|
|
47559
47632
|
};
|
|
47560
47633
|
}
|
|
47561
|
-
function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePermission, db) {
|
|
47634
|
+
function registerAdminContentRoutes(app, registry2, repos, projectors, mediaRepo, requirePermission, db) {
|
|
47562
47635
|
for (const [typeName, contentType] of Object.entries(registry2.content_types)) {
|
|
47563
47636
|
const basePath = `content/${typeName}`;
|
|
47564
47637
|
const repo = repos[typeName];
|
|
@@ -47570,6 +47643,8 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
47570
47643
|
const relationFieldNames = new Set(
|
|
47571
47644
|
contentType.fields.filter((f) => RELATION_FIELD_TYPES.has(f.field_type)).map((f) => f.name)
|
|
47572
47645
|
);
|
|
47646
|
+
const projector = projectors[typeName];
|
|
47647
|
+
const fieldKeys = projector.map;
|
|
47573
47648
|
const requiredFields = contentType.fields.filter((f) => f.required);
|
|
47574
47649
|
const mediaFields = contentType.fields.filter(
|
|
47575
47650
|
(f) => f.field_type === "image" || f.field_type === "video" || f.field_type === "file"
|
|
@@ -47583,17 +47658,18 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
47583
47658
|
`/admin/api/${basePath}`,
|
|
47584
47659
|
requirePermission("content:read"),
|
|
47585
47660
|
async (c) => {
|
|
47586
|
-
const parsed = parseListQuery(c.req.url, schemaFieldNames, relationFieldNames);
|
|
47661
|
+
const parsed = parseListQuery(c.req.url, schemaFieldNames, relationFieldNames, fieldKeys.columnFor);
|
|
47587
47662
|
if (!parsed.ok) {
|
|
47588
47663
|
return c.json({ ok: false, error: parsed.response }, parsed.status);
|
|
47589
47664
|
}
|
|
47590
47665
|
const publishedParam = c.req.query("published");
|
|
47591
47666
|
const extraFilters = {};
|
|
47592
47667
|
if (publishedParam === "false") extraFilters["published"] = false;
|
|
47668
|
+
const sortColumn = fieldKeys.columnFor(parsed.sortBy) ?? parsed.sortBy;
|
|
47593
47669
|
const findOpts = {
|
|
47594
47670
|
page: parsed.pagination.page,
|
|
47595
47671
|
per_page: parsed.pagination.per_page,
|
|
47596
|
-
sort_by:
|
|
47672
|
+
sort_by: sortColumn,
|
|
47597
47673
|
sort_order: parsed.sortOrder,
|
|
47598
47674
|
filters: { ...parsed.filters, ...extraFilters },
|
|
47599
47675
|
include: parsed.include
|
|
@@ -47603,7 +47679,10 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
47603
47679
|
findOpts.search = { term: parsed.search, columns: searchableColumns };
|
|
47604
47680
|
}
|
|
47605
47681
|
const result = await repo.findMany(findOpts);
|
|
47606
|
-
|
|
47682
|
+
const data = result.data.map(
|
|
47683
|
+
(row) => projectRow(row, typeName, projectors)
|
|
47684
|
+
);
|
|
47685
|
+
return c.json({ ...result, data });
|
|
47607
47686
|
}
|
|
47608
47687
|
);
|
|
47609
47688
|
app.get(
|
|
@@ -47638,7 +47717,8 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
47638
47717
|
}
|
|
47639
47718
|
}
|
|
47640
47719
|
}
|
|
47641
|
-
|
|
47720
|
+
const data = projectRow(item, typeName, projectors);
|
|
47721
|
+
return c.json({ ok: true, data });
|
|
47642
47722
|
}
|
|
47643
47723
|
);
|
|
47644
47724
|
app.post(
|
|
@@ -47705,6 +47785,7 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
47705
47785
|
}
|
|
47706
47786
|
);
|
|
47707
47787
|
const writeNewItem = async (c, body) => {
|
|
47788
|
+
const storageBody = fieldKeys.toStorage(body);
|
|
47708
47789
|
const fieldErrors = checkRequiredFields(requiredFields, body);
|
|
47709
47790
|
if (fieldErrors.length > 0) {
|
|
47710
47791
|
return c.json(
|
|
@@ -47728,9 +47809,7 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
47728
47809
|
const junctionFields = contentType.fields.filter(
|
|
47729
47810
|
(f) => f.db_column !== null && f.db_column.junction !== void 0
|
|
47730
47811
|
);
|
|
47731
|
-
const
|
|
47732
|
-
(f) => f.db_column !== null && f.db_column.junction === void 0
|
|
47733
|
-
);
|
|
47812
|
+
const columnBackedFields = contentType.fields.filter(isColumnBacked);
|
|
47734
47813
|
const columnData = {
|
|
47735
47814
|
published: body["published"] ?? false
|
|
47736
47815
|
};
|
|
@@ -47739,9 +47818,10 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
47739
47818
|
} else {
|
|
47740
47819
|
columnData["slug"] = body["slug"];
|
|
47741
47820
|
}
|
|
47742
|
-
for (const f of
|
|
47743
|
-
const
|
|
47744
|
-
|
|
47821
|
+
for (const f of columnBackedFields) {
|
|
47822
|
+
const key = f.db_column.column_name;
|
|
47823
|
+
if (!(key in storageBody)) continue;
|
|
47824
|
+
columnData[key] = storageBody[key];
|
|
47745
47825
|
}
|
|
47746
47826
|
if (db) {
|
|
47747
47827
|
const basePathId = await lookupBasePathId(db, contentType.default_base_path);
|
|
@@ -47761,7 +47841,7 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
47761
47841
|
}
|
|
47762
47842
|
const item = await repo.create(columnData);
|
|
47763
47843
|
const itemId = item["id"];
|
|
47764
|
-
const mediaDeltas = [topLevelMediaDelta(mediaFields, null,
|
|
47844
|
+
const mediaDeltas = [topLevelMediaDelta(mediaFields, null, storageBody)];
|
|
47765
47845
|
if (db) {
|
|
47766
47846
|
for (const f of paragraphFields) {
|
|
47767
47847
|
const comp = f.ui_component;
|
|
@@ -47778,7 +47858,8 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
47778
47858
|
}
|
|
47779
47859
|
}
|
|
47780
47860
|
await applyMediaReferenceDelta(mergeMediaDeltas(...mediaDeltas), mediaRepo);
|
|
47781
|
-
|
|
47861
|
+
const data = projectRow(item, typeName, projectors);
|
|
47862
|
+
return c.json({ ok: true, data }, 201);
|
|
47782
47863
|
};
|
|
47783
47864
|
app.patch(
|
|
47784
47865
|
`/admin/api/${basePath}/:id`,
|
|
@@ -47838,11 +47919,12 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
47838
47919
|
}
|
|
47839
47920
|
);
|
|
47840
47921
|
const writeExistingItem = async (c, id, existing, body) => {
|
|
47922
|
+
const storageBody = fieldKeys.toStorage(body);
|
|
47841
47923
|
if (body["published"] === true) {
|
|
47842
47924
|
const publishDeny = await requirePermission("content:edit")(c, async () => {
|
|
47843
47925
|
});
|
|
47844
47926
|
if (publishDeny) return publishDeny;
|
|
47845
|
-
const merged = { ...existing, ...body };
|
|
47927
|
+
const merged = { ...fieldKeys.toLabels(existing), ...body };
|
|
47846
47928
|
const fieldErrors = checkRequiredFields(requiredFields, merged);
|
|
47847
47929
|
if (fieldErrors.length > 0) {
|
|
47848
47930
|
return c.json(
|
|
@@ -47862,17 +47944,14 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
47862
47944
|
const patchJunctionFields = contentType.fields.filter(
|
|
47863
47945
|
(f) => f.db_column !== null && f.db_column.junction !== void 0
|
|
47864
47946
|
);
|
|
47865
|
-
const
|
|
47866
|
-
(f) => f.db_column !== null && f.db_column.junction === void 0
|
|
47867
|
-
);
|
|
47947
|
+
const patchColumnBackedFields = contentType.fields.filter(isColumnBacked);
|
|
47868
47948
|
const patchData = {};
|
|
47869
47949
|
if (!contentType.only_one && "slug" in body) patchData["slug"] = body["slug"];
|
|
47870
47950
|
if ("published" in body) patchData["published"] = body["published"];
|
|
47871
|
-
for (const f of
|
|
47872
|
-
|
|
47873
|
-
|
|
47874
|
-
|
|
47875
|
-
}
|
|
47951
|
+
for (const f of patchColumnBackedFields) {
|
|
47952
|
+
const key = f.db_column.column_name;
|
|
47953
|
+
if (!(key in storageBody)) continue;
|
|
47954
|
+
patchData[key] = storageBody[key];
|
|
47876
47955
|
}
|
|
47877
47956
|
const updated = await repo.update(id, patchData);
|
|
47878
47957
|
if (!updated) {
|
|
@@ -47882,7 +47961,7 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
47882
47961
|
);
|
|
47883
47962
|
}
|
|
47884
47963
|
const mediaDeltas = [
|
|
47885
|
-
topLevelMediaDelta(mediaFields, existing,
|
|
47964
|
+
topLevelMediaDelta(mediaFields, existing, storageBody)
|
|
47886
47965
|
];
|
|
47887
47966
|
if (db) {
|
|
47888
47967
|
for (const f of patchParagraphFields) {
|
|
@@ -47900,7 +47979,8 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
47900
47979
|
}
|
|
47901
47980
|
}
|
|
47902
47981
|
await applyMediaReferenceDelta(mergeMediaDeltas(...mediaDeltas), mediaRepo);
|
|
47903
|
-
|
|
47982
|
+
const data = projectRow(updated, typeName, projectors);
|
|
47983
|
+
return c.json({ ok: true, data });
|
|
47904
47984
|
};
|
|
47905
47985
|
if (contentType.only_one) {
|
|
47906
47986
|
app.put(
|
|
@@ -47960,6 +48040,8 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
47960
48040
|
const relationFieldNames = new Set(
|
|
47961
48041
|
taxonomyType.fields.filter((f) => RELATION_FIELD_TYPES.has(f.field_type)).map((f) => f.name)
|
|
47962
48042
|
);
|
|
48043
|
+
const projector = projectors[typeName];
|
|
48044
|
+
const fieldKeys = projector.map;
|
|
47963
48045
|
const requiredFields = taxonomyType.fields.filter((f) => f.required);
|
|
47964
48046
|
const mediaFields = taxonomyType.fields.filter(
|
|
47965
48047
|
(f) => f.field_type === "image" || f.field_type === "video" || f.field_type === "file"
|
|
@@ -47973,17 +48055,18 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
47973
48055
|
`/admin/api/taxonomy/${typeName}`,
|
|
47974
48056
|
requirePermission("content:read"),
|
|
47975
48057
|
async (c) => {
|
|
47976
|
-
const parsed = parseListQuery(c.req.url, schemaFieldNames, relationFieldNames);
|
|
48058
|
+
const parsed = parseListQuery(c.req.url, schemaFieldNames, relationFieldNames, fieldKeys.columnFor);
|
|
47977
48059
|
if (!parsed.ok) {
|
|
47978
48060
|
return c.json({ ok: false, error: parsed.response }, parsed.status);
|
|
47979
48061
|
}
|
|
47980
48062
|
const publishedParam = c.req.query("published");
|
|
47981
48063
|
const extraFilters = {};
|
|
47982
48064
|
if (publishedParam === "false") extraFilters["published"] = false;
|
|
48065
|
+
const sortColumn = fieldKeys.columnFor(parsed.sortBy) ?? parsed.sortBy;
|
|
47983
48066
|
const findOpts = {
|
|
47984
48067
|
page: parsed.pagination.page,
|
|
47985
48068
|
per_page: parsed.pagination.per_page,
|
|
47986
|
-
sort_by:
|
|
48069
|
+
sort_by: sortColumn,
|
|
47987
48070
|
sort_order: parsed.sortOrder,
|
|
47988
48071
|
filters: { ...parsed.filters, ...extraFilters },
|
|
47989
48072
|
include: parsed.include
|
|
@@ -47993,7 +48076,10 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
47993
48076
|
findOpts.search = { term: parsed.search, columns: searchableColumns };
|
|
47994
48077
|
}
|
|
47995
48078
|
const result = await repo.findMany(findOpts);
|
|
47996
|
-
|
|
48079
|
+
const data = result.data.map(
|
|
48080
|
+
(row) => projectRow(row, typeName, projectors)
|
|
48081
|
+
);
|
|
48082
|
+
return c.json({ ...result, data });
|
|
47997
48083
|
}
|
|
47998
48084
|
);
|
|
47999
48085
|
app.get(
|
|
@@ -48008,7 +48094,8 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
48008
48094
|
404
|
|
48009
48095
|
);
|
|
48010
48096
|
}
|
|
48011
|
-
|
|
48097
|
+
const data = projectRow(item, typeName, projectors);
|
|
48098
|
+
return c.json({ ok: true, data });
|
|
48012
48099
|
}
|
|
48013
48100
|
);
|
|
48014
48101
|
app.post(
|
|
@@ -48016,6 +48103,7 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
48016
48103
|
requirePermission("content:create"),
|
|
48017
48104
|
async (c) => {
|
|
48018
48105
|
const body = await c.req.json();
|
|
48106
|
+
const storageBody = fieldKeys.toStorage(body);
|
|
48019
48107
|
const fieldErrors = checkRequiredFields(requiredFields, body);
|
|
48020
48108
|
if (fieldErrors.length > 0) {
|
|
48021
48109
|
return c.json(
|
|
@@ -48035,20 +48123,19 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
48035
48123
|
});
|
|
48036
48124
|
if (publishDeny) return publishDeny;
|
|
48037
48125
|
}
|
|
48038
|
-
const taxColumnFields = taxonomyType.fields.filter(
|
|
48039
|
-
(f) => f.db_column !== null && f.db_column.junction === void 0
|
|
48040
|
-
);
|
|
48041
48126
|
const taxParagraphFields = taxonomyType.fields.filter((f) => f.db_column === null);
|
|
48127
|
+
const taxColumnBackedFields = taxonomyType.fields.filter(isColumnBacked);
|
|
48042
48128
|
const taxColumnData = {
|
|
48043
48129
|
published: body["published"] ?? false
|
|
48044
48130
|
};
|
|
48045
|
-
for (const f of
|
|
48046
|
-
const
|
|
48047
|
-
|
|
48131
|
+
for (const f of taxColumnBackedFields) {
|
|
48132
|
+
const key = f.db_column.column_name;
|
|
48133
|
+
if (!(key in storageBody)) continue;
|
|
48134
|
+
taxColumnData[key] = storageBody[key];
|
|
48048
48135
|
}
|
|
48049
48136
|
const item = await repo.create(taxColumnData);
|
|
48050
48137
|
const taxItemId = item["id"];
|
|
48051
|
-
const mediaDeltas = [topLevelMediaDelta(mediaFields, null,
|
|
48138
|
+
const mediaDeltas = [topLevelMediaDelta(mediaFields, null, storageBody)];
|
|
48052
48139
|
if (db) {
|
|
48053
48140
|
for (const f of taxParagraphFields) {
|
|
48054
48141
|
const comp = f.ui_component;
|
|
@@ -48060,7 +48147,8 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
48060
48147
|
}
|
|
48061
48148
|
}
|
|
48062
48149
|
await applyMediaReferenceDelta(mergeMediaDeltas(...mediaDeltas), mediaRepo);
|
|
48063
|
-
|
|
48150
|
+
const data = projectRow(item, typeName, projectors);
|
|
48151
|
+
return c.json({ ok: true, data }, 201);
|
|
48064
48152
|
}
|
|
48065
48153
|
);
|
|
48066
48154
|
app.patch(
|
|
@@ -48069,6 +48157,7 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
48069
48157
|
async (c) => {
|
|
48070
48158
|
const id = c.req.param("id");
|
|
48071
48159
|
const body = await c.req.json();
|
|
48160
|
+
const storageBody = fieldKeys.toStorage(body);
|
|
48072
48161
|
const existing = await repo.findOne(id);
|
|
48073
48162
|
if (!existing) {
|
|
48074
48163
|
return c.json(
|
|
@@ -48080,7 +48169,7 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
48080
48169
|
const publishDeny = await requirePermission("content:edit")(c, async () => {
|
|
48081
48170
|
});
|
|
48082
48171
|
if (publishDeny) return publishDeny;
|
|
48083
|
-
const merged = { ...existing, ...body };
|
|
48172
|
+
const merged = { ...fieldKeys.toLabels(existing), ...body };
|
|
48084
48173
|
const fieldErrors = checkRequiredFields(requiredFields, merged);
|
|
48085
48174
|
if (fieldErrors.length > 0) {
|
|
48086
48175
|
return c.json(
|
|
@@ -48096,17 +48185,14 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
48096
48185
|
);
|
|
48097
48186
|
}
|
|
48098
48187
|
}
|
|
48099
|
-
const taxPatchColumnFields = taxonomyType.fields.filter(
|
|
48100
|
-
(f) => f.db_column !== null && f.db_column.junction === void 0
|
|
48101
|
-
);
|
|
48102
48188
|
const taxPatchParagraphFields = taxonomyType.fields.filter((f) => f.db_column === null);
|
|
48189
|
+
const taxPatchColumnBackedFields = taxonomyType.fields.filter(isColumnBacked);
|
|
48103
48190
|
const taxPatchData = {};
|
|
48104
48191
|
if ("published" in body) taxPatchData["published"] = body["published"];
|
|
48105
|
-
for (const f of
|
|
48106
|
-
|
|
48107
|
-
|
|
48108
|
-
|
|
48109
|
-
}
|
|
48192
|
+
for (const f of taxPatchColumnBackedFields) {
|
|
48193
|
+
const key = f.db_column.column_name;
|
|
48194
|
+
if (!(key in storageBody)) continue;
|
|
48195
|
+
taxPatchData[key] = storageBody[key];
|
|
48110
48196
|
}
|
|
48111
48197
|
const updated = await repo.update(id, taxPatchData);
|
|
48112
48198
|
if (!updated) {
|
|
@@ -48116,7 +48202,7 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
48116
48202
|
);
|
|
48117
48203
|
}
|
|
48118
48204
|
const mediaDeltas = [
|
|
48119
|
-
topLevelMediaDelta(mediaFields, existing,
|
|
48205
|
+
topLevelMediaDelta(mediaFields, existing, storageBody)
|
|
48120
48206
|
];
|
|
48121
48207
|
if (db) {
|
|
48122
48208
|
for (const f of taxPatchParagraphFields) {
|
|
@@ -48129,7 +48215,8 @@ function registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePer
|
|
|
48129
48215
|
}
|
|
48130
48216
|
}
|
|
48131
48217
|
await applyMediaReferenceDelta(mergeMediaDeltas(...mediaDeltas), mediaRepo);
|
|
48132
|
-
|
|
48218
|
+
const data = projectRow(updated, typeName, projectors);
|
|
48219
|
+
return c.json({ ok: true, data });
|
|
48133
48220
|
}
|
|
48134
48221
|
);
|
|
48135
48222
|
app.delete(
|
|
@@ -49102,7 +49189,7 @@ function registerUserRoutes(app, db, requirePermission, requireHierarchy) {
|
|
|
49102
49189
|
}
|
|
49103
49190
|
var API_VERSION = (() => {
|
|
49104
49191
|
try {
|
|
49105
|
-
return "0.
|
|
49192
|
+
return "0.4.1";
|
|
49106
49193
|
} catch {
|
|
49107
49194
|
return "0.0.0";
|
|
49108
49195
|
}
|
|
@@ -49257,7 +49344,7 @@ function whereFragment(conds) {
|
|
|
49257
49344
|
return conds.length > 0 ? sql` WHERE ${sql.join(conds, sql` AND `)}` : sql``;
|
|
49258
49345
|
}
|
|
49259
49346
|
function createDrizzleContentRepository(db, tableName, options = {}) {
|
|
49260
|
-
const { relations = {}, publishedRelations = false } = options;
|
|
49347
|
+
const { relations = {}, publishedRelations = false, sortableColumns } = options;
|
|
49261
49348
|
function tableRaw() {
|
|
49262
49349
|
return sql.raw(quoteIdent2(tableName));
|
|
49263
49350
|
}
|
|
@@ -49295,8 +49382,9 @@ function createDrizzleContentRepository(db, tableName, options = {}) {
|
|
|
49295
49382
|
sort_order = "asc",
|
|
49296
49383
|
search
|
|
49297
49384
|
} = opts;
|
|
49298
|
-
|
|
49299
|
-
|
|
49385
|
+
const allowed = sortableColumns ?? SORTABLE_FIELDS2;
|
|
49386
|
+
if (!allowed.has(sort_by)) {
|
|
49387
|
+
throw codeError("INVALID_SORT_FIELD", `'${sort_by}' is not sortable.`);
|
|
49300
49388
|
}
|
|
49301
49389
|
const offset = (page - 1) * per_page;
|
|
49302
49390
|
const conds = buildConditions(published_only, filters, search);
|
|
@@ -49500,7 +49588,8 @@ function createCmsApp(options) {
|
|
|
49500
49588
|
if (!options.storage) {
|
|
49501
49589
|
throw new Error(MISSING_STORAGE_ERROR);
|
|
49502
49590
|
}
|
|
49503
|
-
const prefix = options.prefix
|
|
49591
|
+
const prefix = normalizePrefix(options.prefix);
|
|
49592
|
+
const publicPaths = createPublicPaths(prefix);
|
|
49504
49593
|
const { storage, registry: registry2, db, rateLimit, media, cors } = options;
|
|
49505
49594
|
const cmsName = options.name ?? "Manguito CMS";
|
|
49506
49595
|
const maxFileSize = media?.max_file_size;
|
|
@@ -49534,16 +49623,38 @@ function createCmsApp(options) {
|
|
|
49534
49623
|
return result.rows[0]?.role ?? null;
|
|
49535
49624
|
};
|
|
49536
49625
|
const requireHierarchy = createHierarchyMiddleware(rolesRegistry, getUserRole);
|
|
49626
|
+
const fieldKeyMaps = Object.fromEntries([
|
|
49627
|
+
...Object.entries(registry2.content_types).map(([typeName, ct2]) => [
|
|
49628
|
+
typeName,
|
|
49629
|
+
createFieldKeyMap(ct2.fields)
|
|
49630
|
+
]),
|
|
49631
|
+
...Object.entries(registry2.taxonomy_types).map(([typeName, tt2]) => [
|
|
49632
|
+
typeName,
|
|
49633
|
+
createFieldKeyMap(tt2.fields)
|
|
49634
|
+
]),
|
|
49635
|
+
...Object.entries(registry2.paragraph_types).map(([typeName, pt]) => [
|
|
49636
|
+
typeName,
|
|
49637
|
+
createFieldKeyMap(pt.fields)
|
|
49638
|
+
])
|
|
49639
|
+
]);
|
|
49640
|
+
const projectors = buildProjectors(registry2, fieldKeyMaps);
|
|
49641
|
+
const sortableColumnsFor = (typeName) => new Set(
|
|
49642
|
+
[...SORTABLE_FIELDS].map((label) => fieldKeyMaps[typeName].columnFor(label) ?? label)
|
|
49643
|
+
);
|
|
49537
49644
|
const contentRepos = Object.fromEntries(
|
|
49538
49645
|
Object.entries(registry2.content_types).map(([typeName, ct2]) => [
|
|
49539
49646
|
typeName,
|
|
49540
|
-
createDrizzleContentRepository(db, ct2.db.table_name
|
|
49647
|
+
createDrizzleContentRepository(db, ct2.db.table_name, {
|
|
49648
|
+
sortableColumns: sortableColumnsFor(typeName)
|
|
49649
|
+
})
|
|
49541
49650
|
])
|
|
49542
49651
|
);
|
|
49543
49652
|
const taxonomyRepos = Object.fromEntries(
|
|
49544
49653
|
Object.entries(registry2.taxonomy_types).map(([typeName, tt2]) => [
|
|
49545
49654
|
typeName,
|
|
49546
|
-
createDrizzleContentRepository(db, tt2.db.table_name
|
|
49655
|
+
createDrizzleContentRepository(db, tt2.db.table_name, {
|
|
49656
|
+
sortableColumns: sortableColumnsFor(typeName)
|
|
49657
|
+
})
|
|
49547
49658
|
])
|
|
49548
49659
|
);
|
|
49549
49660
|
const repos = { ...contentRepos, ...taxonomyRepos };
|
|
@@ -49553,7 +49664,8 @@ function createCmsApp(options) {
|
|
|
49553
49664
|
typeName,
|
|
49554
49665
|
createDrizzleContentRepository(db, ct2.db.table_name, {
|
|
49555
49666
|
relations: buildRelationsMap(ct2.fields, registry2),
|
|
49556
|
-
publishedRelations: true
|
|
49667
|
+
publishedRelations: true,
|
|
49668
|
+
sortableColumns: sortableColumnsFor(typeName)
|
|
49557
49669
|
})
|
|
49558
49670
|
])
|
|
49559
49671
|
);
|
|
@@ -49562,7 +49674,8 @@ function createCmsApp(options) {
|
|
|
49562
49674
|
typeName,
|
|
49563
49675
|
createDrizzleContentRepository(db, tt2.db.table_name, {
|
|
49564
49676
|
relations: buildRelationsMap(tt2.fields, registry2),
|
|
49565
|
-
publishedRelations: true
|
|
49677
|
+
publishedRelations: true,
|
|
49678
|
+
sortableColumns: sortableColumnsFor(typeName)
|
|
49566
49679
|
})
|
|
49567
49680
|
])
|
|
49568
49681
|
);
|
|
@@ -49570,33 +49683,41 @@ function createCmsApp(options) {
|
|
|
49570
49683
|
const graphqlRepos = Object.fromEntries([
|
|
49571
49684
|
...Object.entries(registry2.content_types).map(([typeName, ct2]) => [
|
|
49572
49685
|
typeName,
|
|
49573
|
-
createDrizzleContentRepository(db, ct2.db.table_name
|
|
49686
|
+
createDrizzleContentRepository(db, ct2.db.table_name, {
|
|
49687
|
+
sortableColumns: sortableColumnsFor(typeName)
|
|
49688
|
+
})
|
|
49574
49689
|
]),
|
|
49575
49690
|
...Object.entries(registry2.taxonomy_types).map(([typeName, tt2]) => [
|
|
49576
49691
|
typeName,
|
|
49577
|
-
createDrizzleContentRepository(db, tt2.db.table_name
|
|
49692
|
+
createDrizzleContentRepository(db, tt2.db.table_name, {
|
|
49693
|
+
sortableColumns: sortableColumnsFor(typeName)
|
|
49694
|
+
})
|
|
49578
49695
|
])
|
|
49579
49696
|
]);
|
|
49580
49697
|
registerAuthRoutes(app, db);
|
|
49581
49698
|
app.use("/admin/api/*", authMiddleware);
|
|
49582
49699
|
app.use("/admin/api/*", mustChangePasswordCheck);
|
|
49583
|
-
app.get(
|
|
49700
|
+
app.get(publicPaths.openapi(), (c) => {
|
|
49584
49701
|
const paths = {};
|
|
49585
49702
|
for (const ct2 of Object.values(registry2.content_types)) {
|
|
49586
49703
|
const base = ct2.default_base_path;
|
|
49587
49704
|
if (ct2.only_one) {
|
|
49588
|
-
paths[
|
|
49705
|
+
paths[publicPaths.collection(base)] = { get: { summary: `Get ${ct2.label}`, tags: [ct2.label] } };
|
|
49589
49706
|
} else {
|
|
49590
|
-
paths[
|
|
49591
|
-
paths[
|
|
49707
|
+
paths[publicPaths.collection(base)] = { get: { summary: `List published ${ct2.label}`, tags: [ct2.label] } };
|
|
49708
|
+
paths[publicPaths.item(base).replace(":slug", "{slug}")] = {
|
|
49709
|
+
get: { summary: `Get ${ct2.label} by slug`, tags: [ct2.label] }
|
|
49710
|
+
};
|
|
49592
49711
|
}
|
|
49593
49712
|
}
|
|
49594
49713
|
for (const tt2 of Object.values(registry2.taxonomy_types)) {
|
|
49595
|
-
paths[
|
|
49596
|
-
paths[
|
|
49714
|
+
paths[publicPaths.taxonomyCollection(tt2.name)] = { get: { summary: `List published ${tt2.label}`, tags: [tt2.label] } };
|
|
49715
|
+
paths[publicPaths.taxonomyItem(tt2.name).replace(":id", "{id}")] = {
|
|
49716
|
+
get: { summary: `Get ${tt2.label} by id`, tags: [tt2.label] }
|
|
49717
|
+
};
|
|
49597
49718
|
}
|
|
49598
|
-
paths[
|
|
49599
|
-
paths["
|
|
49719
|
+
paths[publicPaths.mediaCollection()] = { get: { summary: "List media items", tags: ["Media"] } };
|
|
49720
|
+
paths[publicPaths.mediaItem().replace(":id", "{id}")] = { get: { summary: "Get media item by id", tags: ["Media"] } };
|
|
49600
49721
|
return c.json({
|
|
49601
49722
|
openapi: "3.0.3",
|
|
49602
49723
|
info: { title: "Manguito CMS Public API", version: "1.0.0" },
|
|
@@ -49611,14 +49732,14 @@ function createCmsApp(options) {
|
|
|
49611
49732
|
paths: {}
|
|
49612
49733
|
})
|
|
49613
49734
|
);
|
|
49614
|
-
registerPublicContentRoutes(app, registry2, publicRepos, listRateLimit, programmaticResolver);
|
|
49615
|
-
registerPublicMediaRoutes(app, mediaRepo, listRateLimit);
|
|
49735
|
+
registerPublicContentRoutes(app, registry2, publicRepos, projectors, publicPaths, listRateLimit, programmaticResolver);
|
|
49736
|
+
registerPublicMediaRoutes(app, mediaRepo, publicPaths, listRateLimit);
|
|
49616
49737
|
if (options.graphql?.enabled) {
|
|
49617
49738
|
const gqlOptions = options.graphql;
|
|
49618
49739
|
let gqlHandler = null;
|
|
49619
49740
|
let initError = null;
|
|
49620
|
-
const ready = import("./handler-
|
|
49621
|
-
gqlHandler = createGraphQLHandler(registry2, graphqlRepos, programmaticResolver, db, gqlOptions);
|
|
49741
|
+
const ready = import("./handler-7LVYEU5C-ZAJVEGKT.js").then(({ createGraphQLHandler }) => {
|
|
49742
|
+
gqlHandler = createGraphQLHandler(registry2, graphqlRepos, fieldKeyMaps, programmaticResolver, db, gqlOptions);
|
|
49622
49743
|
}).catch((err) => {
|
|
49623
49744
|
initError = err;
|
|
49624
49745
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -49658,7 +49779,7 @@ function createCmsApp(options) {
|
|
|
49658
49779
|
);
|
|
49659
49780
|
registerSchemaRoute(app, registry2, db);
|
|
49660
49781
|
registerUserRoutes(app, db, requirePermission, requireHierarchy);
|
|
49661
|
-
registerAdminContentRoutes(app, registry2, repos, mediaRepo, requirePermission, db);
|
|
49782
|
+
registerAdminContentRoutes(app, registry2, repos, projectors, mediaRepo, requirePermission, db);
|
|
49662
49783
|
registerAdminMediaRoutes(app, mediaRepo, storage, requirePermission, maxFileSize);
|
|
49663
49784
|
return { prefix, app };
|
|
49664
49785
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobbykim/manguito-cms-cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Bobby Kim <bobby.sihun.kim@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/bobbykim89/manguito-cms",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"@bobbykim/manguito-cms-admin": "0.4.0",
|
|
33
33
|
"@bobbykim/manguito-cms-core": "0.3.0",
|
|
34
34
|
"@bobbykim/manguito-cms-db": "0.1.3",
|
|
35
|
-
"@bobbykim/manguito-cms-api": "0.
|
|
35
|
+
"@bobbykim/manguito-cms-api": "0.4.1"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/node": "^25.9.5",
|