@bobbykim/manguito-cms-cli 0.6.1 → 0.6.2

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-JVP33FI2.mjs
52
+ // ../api/dist/chunk-FXPKGPYF.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-JVP33FI2.mjs
1215
+ // ../api/dist/chunk-FXPKGPYF.mjs
1216
1216
  function isColumnBacked(field) {
1217
1217
  const col = field.db_column;
1218
1218
  if (col === null) return false;
@@ -1220,7 +1220,7 @@ function isColumnBacked(field) {
1220
1220
  if (col.junction) return false;
1221
1221
  return true;
1222
1222
  }
1223
- function buildFieldKeyMap(pairs, allLabels, droppedKeys) {
1223
+ function buildFieldKeyMap(pairs, allLabels, droppedColumns, droppedLabels) {
1224
1224
  const labelToColumn = /* @__PURE__ */ new Map();
1225
1225
  const columnToLabel = /* @__PURE__ */ new Map();
1226
1226
  for (const { label, column } of pairs) {
@@ -1228,7 +1228,7 @@ function buildFieldKeyMap(pairs, allLabels, droppedKeys) {
1228
1228
  columnToLabel.set(column, label);
1229
1229
  }
1230
1230
  for (const { label, ownColumn } of allLabels) {
1231
- if (ownColumn === label) continue;
1231
+ if (ownColumn !== void 0) continue;
1232
1232
  const columnOwner = columnToLabel.get(label);
1233
1233
  if (columnOwner !== void 0 && columnOwner !== label) {
1234
1234
  throw new Error(
@@ -1237,23 +1237,33 @@ function buildFieldKeyMap(pairs, allLabels, droppedKeys) {
1237
1237
  }
1238
1238
  }
1239
1239
  for (const label of labelToColumn.keys()) {
1240
- if (droppedKeys.has(label)) labelToColumn.delete(label);
1240
+ if (droppedLabels.has(label)) labelToColumn.delete(label);
1241
1241
  }
1242
1242
  for (const column of columnToLabel.keys()) {
1243
- if (droppedKeys.has(column)) columnToLabel.delete(column);
1243
+ if (droppedColumns.has(column)) columnToLabel.delete(column);
1244
1244
  }
1245
1245
  const diverges = [...labelToColumn].some(([label, column]) => label !== column);
1246
- function remap(input, lookup) {
1246
+ function remap(input, lookup, dropped, droppedIfUnmapped) {
1247
1247
  const out = {};
1248
1248
  for (const key of Object.keys(input)) {
1249
- if (droppedKeys.has(key)) continue;
1250
- out[lookup.get(key) ?? key] = input[key];
1249
+ const mapped = lookup.get(key);
1250
+ if (mapped !== void 0) {
1251
+ out[mapped] = input[key];
1252
+ continue;
1253
+ }
1254
+ if (dropped.has(key) || droppedIfUnmapped?.has(key)) continue;
1255
+ out[key] = input[key];
1251
1256
  }
1252
1257
  return out;
1253
1258
  }
1254
1259
  return {
1255
- toStorage: (input) => remap(input, labelToColumn),
1256
- toLabels: (row) => remap(row, columnToLabel),
1260
+ // toStorage reads LABEL-keyed input: a live label maps and writes
1261
+ // regardless of either drop set; an unmapped key is refused if it is
1262
+ // EITHER the tombstone's own name (droppedLabels) or a raw, unexposed
1263
+ // column (droppedColumns) — see remap's comment.
1264
+ // toLabels reads COLUMN-keyed input, so it consults only droppedColumns.
1265
+ toStorage: (input) => remap(input, labelToColumn, droppedLabels, droppedColumns),
1266
+ toLabels: (row) => remap(row, columnToLabel, droppedColumns),
1257
1267
  columnFor: (label) => labelToColumn.get(label),
1258
1268
  labelFor: (column) => columnToLabel.get(column),
1259
1269
  labels: [...labelToColumn.keys()],
@@ -1261,14 +1271,15 @@ function buildFieldKeyMap(pairs, allLabels, droppedKeys) {
1261
1271
  };
1262
1272
  }
1263
1273
  function createFieldKeyMap(fields) {
1264
- const droppedKeys = /* @__PURE__ */ new Set();
1274
+ const droppedColumns = /* @__PURE__ */ new Set();
1275
+ const droppedLabels = /* @__PURE__ */ new Set();
1265
1276
  const pairs = [];
1266
1277
  for (const f of fields) {
1267
1278
  if (!isColumnBacked(f)) continue;
1268
1279
  pairs.push({ label: f.name, column: f.db_column.column_name });
1269
1280
  if (f.removed === true) {
1270
- droppedKeys.add(f.name);
1271
- droppedKeys.add(f.db_column.column_name);
1281
+ droppedLabels.add(f.name);
1282
+ droppedColumns.add(f.db_column.column_name);
1272
1283
  }
1273
1284
  }
1274
1285
  return buildFieldKeyMap(
@@ -1279,30 +1290,33 @@ function createFieldKeyMap(fields) {
1279
1290
  // forbids present-and-undefined.
1280
1291
  ...isColumnBacked(f) && { ownColumn: f.db_column.column_name }
1281
1292
  })),
1282
- droppedKeys
1293
+ droppedColumns,
1294
+ droppedLabels
1283
1295
  );
1284
1296
  }
1285
1297
  function createFieldKeyMapFromProjection(projectionType, allFields) {
1286
1298
  const pairs = projectionType.fields.map((f) => ({ label: f.exposed_as, column: f.column_name }));
1287
- const projected = new Set(pairs.map((p) => p.label));
1288
- const dropped = /* @__PURE__ */ new Set();
1299
+ const projectedColumns = new Set(pairs.map((p) => p.column));
1300
+ const projectedLabels = new Set(pairs.map((p) => p.label));
1301
+ const droppedColumns = /* @__PURE__ */ new Set();
1302
+ const droppedLabels = /* @__PURE__ */ new Set();
1289
1303
  for (const f of allFields) {
1290
1304
  if (!isColumnBacked(f)) continue;
1291
- dropped.add(f.name);
1292
- dropped.add(f.db_column.column_name);
1305
+ if (!projectedColumns.has(f.db_column.column_name)) droppedColumns.add(f.db_column.column_name);
1306
+ if (!projectedLabels.has(f.name)) droppedLabels.add(f.name);
1293
1307
  }
1294
- for (const p of pairs) dropped.delete(p.column);
1295
- for (const label of projected) dropped.delete(label);
1296
1308
  return buildFieldKeyMap(
1297
1309
  pairs,
1298
1310
  allFields.map((f) => ({
1299
1311
  label: f.name,
1300
- // See buildFieldKeyMap's collision check: this is what lets it tell a
1301
- // version exposing a field's own column under a new label (fine) from a
1302
- // label that reuses another field's column (not fine).
1312
+ // See buildFieldKeyMap's collision check: `ownColumn` marks every
1313
+ // column-backed field so the check skips it entirely — only a
1314
+ // paragraph/junction/programmatic label (no column of its own) can
1315
+ // still collide.
1303
1316
  ...isColumnBacked(f) && { ownColumn: f.db_column.column_name }
1304
1317
  })),
1305
- dropped
1318
+ droppedColumns,
1319
+ droppedLabels
1306
1320
  );
1307
1321
  }
1308
1322
  function quoteIdent(name) {
@@ -1474,9 +1488,8 @@ function groupBy(items, key) {
1474
1488
  }
1475
1489
  return result;
1476
1490
  }
1477
- function needsFkResolution(row, fkColumn, fieldName) {
1478
- if (fkColumn !== fieldName && !(fkColumn in row)) return false;
1479
- const current = row[fieldName];
1491
+ function needsFkResolution(row, fkColumn) {
1492
+ const current = row[fkColumn];
1480
1493
  return !(typeof current === "object" && current !== null);
1481
1494
  }
1482
1495
  async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOnly = false) {
@@ -1493,15 +1506,11 @@ async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOn
1493
1506
  row[fieldName] = byParent[row["id"]] ?? [];
1494
1507
  }
1495
1508
  } else if (rel.type === "reference") {
1496
- const dropFk = rel.fk_column !== fieldName;
1497
- const pending = batch.filter((r) => needsFkResolution(r, rel.fk_column, fieldName));
1509
+ const pending = batch.filter((r) => needsFkResolution(r, rel.fk_column));
1498
1510
  if (pending.length === 0) return;
1499
1511
  const fkValues = pending.map((r) => r[rel.fk_column]).filter(Boolean);
1500
1512
  if (fkValues.length === 0) {
1501
- for (const row of pending) {
1502
- row[fieldName] = null;
1503
- if (dropFk) delete row[rel.fk_column];
1504
- }
1513
+ for (const row of pending) row[rel.fk_column] = null;
1505
1514
  return;
1506
1515
  }
1507
1516
  const unique = [...new Set(fkValues)];
@@ -1518,8 +1527,7 @@ async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOn
1518
1527
  }
1519
1528
  for (const row of pending) {
1520
1529
  const fkVal = row[rel.fk_column];
1521
- row[fieldName] = fkVal ? cache.get(`${rel.table}:${fkVal}`) ?? null : null;
1522
- if (dropFk) delete row[rel.fk_column];
1530
+ row[rel.fk_column] = fkVal ? cache.get(`${rel.table}:${fkVal}`) ?? null : null;
1523
1531
  }
1524
1532
  } else if (rel.type === "junction") {
1525
1533
  const parentIds = batch.map((r) => r["id"]);
@@ -1547,15 +1555,11 @@ async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOn
1547
1555
  row[fieldName] = jEntries.map((jr) => cache.get(`${rel.table}:${jr[rel.right_column]}`)).filter(Boolean);
1548
1556
  }
1549
1557
  } else if (rel.type === "media") {
1550
- const dropFk = rel.fk_column !== fieldName;
1551
- const pending = batch.filter((r) => needsFkResolution(r, rel.fk_column, fieldName));
1558
+ const pending = batch.filter((r) => needsFkResolution(r, rel.fk_column));
1552
1559
  if (pending.length === 0) return;
1553
1560
  const fkValues = pending.map((r) => r[rel.fk_column]).filter(Boolean);
1554
1561
  if (fkValues.length === 0) {
1555
- for (const row of pending) {
1556
- row[fieldName] = null;
1557
- if (dropFk) delete row[rel.fk_column];
1558
- }
1562
+ for (const row of pending) row[rel.fk_column] = null;
1559
1563
  return;
1560
1564
  }
1561
1565
  const unique = [...new Set(fkValues)];
@@ -1569,8 +1573,7 @@ async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOn
1569
1573
  }
1570
1574
  for (const row of pending) {
1571
1575
  const fkVal = row[rel.fk_column];
1572
- row[fieldName] = fkVal ? cache.get(`media:${fkVal}`) ?? null : null;
1573
- if (dropFk) delete row[rel.fk_column];
1576
+ row[rel.fk_column] = fkVal ? cache.get(`media:${fkVal}`) ?? null : null;
1574
1577
  }
1575
1578
  }
1576
1579
  }
@@ -11,7 +11,7 @@ import {
11
11
  init_esm_shims,
12
12
  isColumnBacked,
13
13
  resolveRelationField
14
- } from "./chunk-SW3T2M64.js";
14
+ } from "./chunk-52I54C3X.js";
15
15
 
16
16
  // ../../node_modules/.pnpm/@whatwg-node+fetch@0.10.13/node_modules/@whatwg-node/fetch/dist/shouldSkipPonyfill.js
17
17
  var require_shouldSkipPonyfill = __commonJS({
@@ -10786,10 +10786,10 @@ var require_parser = __commonJS({
10786
10786
  }
10787
10787
  });
10788
10788
 
10789
- // ../api/dist/handler-XZVDLKZ2.mjs
10789
+ // ../api/dist/handler-GED3I7Z2.mjs
10790
10790
  init_esm_shims();
10791
10791
 
10792
- // ../api/dist/chunk-XNXM4W4K.mjs
10792
+ // ../api/dist/chunk-4LLELFAZ.mjs
10793
10793
  init_esm_shims();
10794
10794
 
10795
10795
  // ../../node_modules/.pnpm/graphql-yoga@5.21.2_graphql@16.14.2/node_modules/graphql-yoga/esm/index.js
@@ -30122,7 +30122,7 @@ function createYoga(options) {
30122
30122
  });
30123
30123
  }
30124
30124
 
30125
- // ../api/dist/chunk-XNXM4W4K.mjs
30125
+ // ../api/dist/chunk-4LLELFAZ.mjs
30126
30126
  var import_dataloader = __toESM(require_dataloader(), 1);
30127
30127
 
30128
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
@@ -30880,7 +30880,7 @@ var EnvelopArmor = class {
30880
30880
  }
30881
30881
  };
30882
30882
 
30883
- // ../api/dist/chunk-XNXM4W4K.mjs
30883
+ // ../api/dist/chunk-4LLELFAZ.mjs
30884
30884
  var DateTimeScalar = new GraphQLScalarType({
30885
30885
  name: "DateTime",
30886
30886
  description: "ISO-8601 date-time string",
@@ -31086,29 +31086,22 @@ function scalarFieldResolver(field, fallback) {
31086
31086
  function relationFieldResolver(typeName, schemaFieldName) {
31087
31087
  return (parent, _args, ctx) => ctx.loaders.load(typeName, schemaFieldName, parent);
31088
31088
  }
31089
- function programmaticFieldResolver(typeName, schemaFieldName, mediaFields = [], fieldKeys) {
31089
+ function programmaticFieldResolver(typeName, schemaFieldName, mediaFieldNames = [], fieldKeys) {
31090
31090
  return async (parent, _args, ctx) => {
31091
31091
  let p = ctx.programmaticMemo.get(parent);
31092
31092
  if (!p) {
31093
- p = resolveProgrammaticRow(typeName, parent, ctx, mediaFields, fieldKeys);
31093
+ p = resolveProgrammaticRow(typeName, parent, ctx, mediaFieldNames, fieldKeys);
31094
31094
  ctx.programmaticMemo.set(parent, p);
31095
31095
  }
31096
31096
  return (await p)[schemaFieldName];
31097
31097
  };
31098
31098
  }
31099
- async function resolveProgrammaticRow(typeName, parent, ctx, mediaFields, fieldKeys) {
31099
+ async function resolveProgrammaticRow(typeName, parent, ctx, mediaFieldNames, fieldKeys) {
31100
31100
  const toLabels = (row) => fieldKeys ? fieldKeys.toLabels(row) : row;
31101
- if (mediaFields.length === 0) return ctx.resolver.resolveItem(typeName, toLabels(parent));
31101
+ if (mediaFieldNames.length === 0) return ctx.resolver.resolveItem(typeName, toLabels(parent));
31102
31102
  const enriched = { ...parent };
31103
- await Promise.all(mediaFields.map((m) => ctx.loaders.load(typeName, m.name, enriched)));
31104
- return ctx.resolver.resolveItem(typeName, relabelMedia(toLabels(enriched), enriched, mediaFields));
31105
- }
31106
- function relabelMedia(record, enriched, mediaFields) {
31107
- for (const { name, exposedAs } of mediaFields) {
31108
- if (!(name in enriched)) continue;
31109
- record[exposedAs] = enriched[name];
31110
- }
31111
- return record;
31103
+ await Promise.all(mediaFieldNames.map((name) => ctx.loaders.load(typeName, name, enriched)));
31104
+ return ctx.resolver.resolveItem(typeName, toLabels(enriched));
31112
31105
  }
31113
31106
  function collectionResolver(typeName, nameMap, fieldKeys) {
31114
31107
  return async (_root, args, ctx) => {
@@ -31180,7 +31173,7 @@ var MEDIA = new GraphQLObjectType({
31180
31173
  duration: { type: GraphQLInt, resolve: (m) => m.duration }
31181
31174
  }
31182
31175
  });
31183
- function buildGraphQLSchema(registry, fieldKeyMaps = {}, view) {
31176
+ function buildGraphQLSchema(registry, fieldKeyMaps = {}, view, programmaticKeyMaps = fieldKeyMaps) {
31184
31177
  const objectTypes = /* @__PURE__ */ new Map();
31185
31178
  const enumTypes = /* @__PURE__ */ new Map();
31186
31179
  for (const [name, enumType] of Object.entries(registry.enum_types)) {
@@ -31244,9 +31237,9 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}, view) {
31244
31237
  }
31245
31238
  function buildObjectType(machineName, type) {
31246
31239
  const visible = viewFieldsFor(machineName, type);
31247
- const mediaFields = visible.filter(
31248
- (v) => v.field.field_type === "image" || v.field.field_type === "video" || v.field.field_type === "file"
31249
- ).map((v) => ({ name: v.field.name, exposedAs: v.exposedAs }));
31240
+ const mediaFieldNames = type.fields.filter(
31241
+ (f) => f.removed !== true && (f.field_type === "image" || f.field_type === "video" || f.field_type === "file")
31242
+ ).map((f) => f.name);
31250
31243
  return new GraphQLObjectType({
31251
31244
  name: graphqlTypeName(machineName),
31252
31245
  fields: () => {
@@ -31266,7 +31259,7 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}, view) {
31266
31259
  const outType = outputTypeForField(field, vf.required);
31267
31260
  let resolve;
31268
31261
  if (field.field_type === "programmatic") {
31269
- resolve = programmaticFieldResolver(machineName, field.name, mediaFields, fieldKeyMaps[machineName]);
31262
+ resolve = programmaticFieldResolver(machineName, field.name, mediaFieldNames, programmaticKeyMaps[machineName]);
31270
31263
  } else if (field.field_type === "reference" || field.field_type === "paragraph" || field.field_type === "image" || field.field_type === "video" || field.field_type === "file") {
31271
31264
  resolve = relationFieldResolver(machineName, field.name);
31272
31265
  } else {
@@ -31311,7 +31304,10 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}, view) {
31311
31304
  for (const [name, ct] of Object.entries(registry.content_types)) {
31312
31305
  const objType = objectTypes.get(name);
31313
31306
  const visible = viewFieldsFor(name, ct);
31314
- const nameMap = buildFieldNameMap(visible.map((v) => v.exposedAs));
31307
+ const nameMap = buildFieldNameMap([
31308
+ ...visible.map((v) => v.exposedAs),
31309
+ ...ct.system_fields.map((s) => s.name)
31310
+ ]);
31315
31311
  if (ct.only_one) {
31316
31312
  queryFields[singleQueryName(name)] = { type: objType, resolve: singletonResolver(name) };
31317
31313
  continue;
@@ -31452,7 +31448,8 @@ function createRelationLoaders(db, registry) {
31452
31448
  async (parents) => {
31453
31449
  const rows = parents;
31454
31450
  await resolveRelationField(db, rows, fieldName, rel, cache, true);
31455
- return rows.map((r) => r[fieldName]);
31451
+ const resultKey = rel.type === "reference" || rel.type === "media" ? rel.fk_column : fieldName;
31452
+ return rows.map((r) => r[resultKey]);
31456
31453
  },
31457
31454
  // Batch within a tick; do not memoize by parent identity (rows are mutated
31458
31455
  // and may recur across nesting levels).
@@ -31513,7 +31510,7 @@ function createGraphQLHandler(registry, repos, fieldKeyMaps, resolver, db, optio
31513
31510
  currentVersion: versioning.currentVersion
31514
31511
  });
31515
31512
  }
31516
- const schema = buildGraphQLSchema(registry, fieldKeyMaps, view);
31513
+ const schema = buildGraphQLSchema(registry, fieldKeyMaps, view, versioning.currentFieldKeyMaps ?? fieldKeyMaps);
31517
31514
  const { plugins } = buildArmorPlugin({
31518
31515
  maxDepth: options.maxDepth,
31519
31516
  maxComplexity: options.maxComplexity
package/dist/index.js CHANGED
@@ -39,7 +39,7 @@ import {
39
39
  resolveRelationField,
40
40
  sql,
41
41
  tracer
42
- } from "./chunk-SW3T2M64.js";
42
+ } from "./chunk-52I54C3X.js";
43
43
 
44
44
  // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/identity.js
45
45
  var require_identity = __commonJS({
@@ -47618,14 +47618,16 @@ function isPlainRow(v2) {
47618
47618
  return typeof v2 === "object" && v2 !== null && !Array.isArray(v2) && !(v2 instanceof Date);
47619
47619
  }
47620
47620
  var MEDIA_FIELD_TYPES = /* @__PURE__ */ new Set(["image", "video", "file"]);
47621
- function nestedTargets(fields) {
47621
+ function nestedTargets(fields, map2) {
47622
47622
  const out = [];
47623
47623
  for (const f of fields) {
47624
47624
  if (MEDIA_FIELD_TYPES.has(f.field_type)) continue;
47625
47625
  if (f.field_type !== "paragraph" && f.field_type !== "reference") continue;
47626
47626
  const ref = f.ui_component.ref;
47627
47627
  if (!ref) continue;
47628
- out.push({ label: f.name, target: ref });
47628
+ const label = isColumnBacked(f) ? map2.labelFor(f.db_column.column_name) : f.name;
47629
+ if (label === void 0) continue;
47630
+ out.push({ label, target: ref });
47629
47631
  }
47630
47632
  return out;
47631
47633
  }
@@ -47643,7 +47645,7 @@ function buildProjectors(registry2, fieldKeyMaps, fallbacks) {
47643
47645
  const typeFallbacks = fallbacks?.[typeName];
47644
47646
  projectors[typeName] = {
47645
47647
  map: map2,
47646
- nested: nestedTargets(type.fields),
47648
+ nested: nestedTargets(type.fields, map2),
47647
47649
  // Spread rather than assign: with exactOptionalPropertyTypes, an optional
47648
47650
  // property may be ABSENT but not present-and-undefined.
47649
47651
  ...typeFallbacks !== void 0 && { fallbacks: typeFallbacks }
@@ -47723,7 +47725,28 @@ function parseFilters(url2, validFields, columnFor) {
47723
47725
  function isPublished(item) {
47724
47726
  return item["published"] === true;
47725
47727
  }
47726
- function registerPublicContentRoutes(app, registry2, repos, projectors, paths, listRateLimit, resolver) {
47728
+ function registerPublicContentRoutes(app, registry2, repos, projectors, paths, listRateLimit, resolver, resolverProjectors) {
47729
+ const forResolver = resolverProjectors ?? projectors;
47730
+ function pickProgrammatic(resolved, names) {
47731
+ const out = {};
47732
+ for (const name of names) if (name in resolved) out[name] = resolved[name];
47733
+ return out;
47734
+ }
47735
+ async function respondItem(row, typeName, programmatic) {
47736
+ const data = projectRow(row, typeName, projectors);
47737
+ if (!resolver?.hasSchema(typeName)) return data;
47738
+ const resolved = await resolver.resolveItem(typeName, projectRow(row, typeName, forResolver));
47739
+ return { ...data, ...pickProgrammatic(resolved, programmatic) };
47740
+ }
47741
+ async function respondList(rows, typeName, programmatic) {
47742
+ const data = rows.map((row) => projectRow(row, typeName, projectors));
47743
+ if (!resolver?.hasSchema(typeName)) return data;
47744
+ const resolved = await resolver.resolveList(
47745
+ typeName,
47746
+ rows.map((row) => projectRow(row, typeName, forResolver))
47747
+ );
47748
+ return data.map((d2, i) => ({ ...d2, ...pickProgrammatic(resolved[i], programmatic) }));
47749
+ }
47727
47750
  function registerListRoute(path7, handler) {
47728
47751
  if (listRateLimit) {
47729
47752
  app.get(path7, listRateLimit, handler);
@@ -47747,18 +47770,29 @@ function registerPublicContentRoutes(app, registry2, repos, projectors, paths, l
47747
47770
  return c.json({ ok: true, data });
47748
47771
  });
47749
47772
  for (const [typeName, contentType] of Object.entries(registry2.content_types)) {
47773
+ let translateInclude2 = function(requested) {
47774
+ const include = [];
47775
+ for (const field of requested) {
47776
+ const registryName = includeNames.get(field);
47777
+ if (registryName === void 0) return { ok: false, field };
47778
+ include.push(registryName);
47779
+ }
47780
+ return { ok: true, include };
47781
+ };
47782
+ var translateInclude = translateInclude2;
47750
47783
  const basePath = contentType.default_base_path;
47751
47784
  const repo = repos[typeName];
47752
47785
  if (!repo) continue;
47753
47786
  const fieldKeys = projectors[typeName].map;
47754
- const relationFieldNames = /* @__PURE__ */ new Set();
47787
+ const programmatic = contentType.fields.filter((f) => f.field_type === "programmatic").map((f) => f.name);
47788
+ const includeNames = /* @__PURE__ */ new Map();
47755
47789
  for (const f of contentType.fields) {
47756
47790
  if (!RELATION_FIELD_TYPES.has(f.field_type)) continue;
47757
47791
  if (isColumnBacked(f)) {
47758
47792
  const label = fieldKeys.labelFor(f.db_column.column_name);
47759
- if (label !== void 0) relationFieldNames.add(label);
47793
+ if (label !== void 0) includeNames.set(label, f.name);
47760
47794
  } else {
47761
- relationFieldNames.add(f.name);
47795
+ includeNames.set(f.name, f.name);
47762
47796
  }
47763
47797
  }
47764
47798
  const filterableFieldNames = /* @__PURE__ */ new Set([
@@ -47777,8 +47811,11 @@ function registerPublicContentRoutes(app, registry2, repos, projectors, paths, l
47777
47811
  404
47778
47812
  );
47779
47813
  }
47780
- let data = projectRow(result.data[0], typeName, projectors);
47781
- if (resolver?.hasSchema(typeName)) data = await resolver.resolveItem(typeName, data);
47814
+ const data = await respondItem(
47815
+ result.data[0],
47816
+ typeName,
47817
+ programmatic
47818
+ );
47782
47819
  return c.json({ ok: true, data });
47783
47820
  });
47784
47821
  } else {
@@ -47835,21 +47872,20 @@ function registerPublicContentRoutes(app, registry2, repos, projectors, paths, l
47835
47872
  400
47836
47873
  );
47837
47874
  }
47838
- const include = parseInclude(c.req.query("include"));
47839
- for (const field of include) {
47840
- if (!relationFieldNames.has(field)) {
47841
- return c.json(
47842
- {
47843
- ok: false,
47844
- error: {
47845
- code: "INVALID_INCLUDE_FIELD",
47846
- message: `'${field}' is not a valid relation field`
47847
- }
47848
- },
47849
- 400
47850
- );
47851
- }
47875
+ const translated = translateInclude2(parseInclude(c.req.query("include")));
47876
+ if (!translated.ok) {
47877
+ return c.json(
47878
+ {
47879
+ ok: false,
47880
+ error: {
47881
+ code: "INVALID_INCLUDE_FIELD",
47882
+ message: `'${translated.field}' is not a valid relation field`
47883
+ }
47884
+ },
47885
+ 400
47886
+ );
47852
47887
  }
47888
+ const include = translated.include;
47853
47889
  const sortColumn = fieldKeys.labels.includes(sortBy) ? fieldKeys.columnFor(sortBy) : sortBy;
47854
47890
  const result = await repo.findMany({
47855
47891
  published_only: true,
@@ -47860,29 +47896,25 @@ function registerPublicContentRoutes(app, registry2, repos, projectors, paths, l
47860
47896
  filters: filtersResult.filters,
47861
47897
  include
47862
47898
  });
47863
- const labeled = result.data.map(
47864
- (row) => projectRow(row, typeName, projectors)
47865
- );
47866
- const data = resolver?.hasSchema(typeName) ? await resolver.resolveList(typeName, labeled) : labeled;
47899
+ const data = await respondList(result.data, typeName, programmatic);
47867
47900
  return c.json({ ...result, data });
47868
47901
  });
47869
47902
  app.get(paths.item(basePath), async (c) => {
47870
47903
  const slug = c.req.param("slug");
47871
- const include = parseInclude(c.req.query("include"));
47872
- for (const field of include) {
47873
- if (!relationFieldNames.has(field)) {
47874
- return c.json(
47875
- {
47876
- ok: false,
47877
- error: {
47878
- code: "INVALID_INCLUDE_FIELD",
47879
- message: `'${field}' is not a valid relation field`
47880
- }
47881
- },
47882
- 400
47883
- );
47884
- }
47904
+ const translated = translateInclude2(parseInclude(c.req.query("include")));
47905
+ if (!translated.ok) {
47906
+ return c.json(
47907
+ {
47908
+ ok: false,
47909
+ error: {
47910
+ code: "INVALID_INCLUDE_FIELD",
47911
+ message: `'${translated.field}' is not a valid relation field`
47912
+ }
47913
+ },
47914
+ 400
47915
+ );
47885
47916
  }
47917
+ const include = translated.include;
47886
47918
  const item = await repo.findBySlug(slug, include);
47887
47919
  if (!item || !isPublished(item)) {
47888
47920
  return c.json(
@@ -47893,15 +47925,15 @@ function registerPublicContentRoutes(app, registry2, repos, projectors, paths, l
47893
47925
  404
47894
47926
  );
47895
47927
  }
47896
- let data = projectRow(item, typeName, projectors);
47897
- if (resolver?.hasSchema(typeName)) data = await resolver.resolveItem(typeName, data);
47928
+ const data = await respondItem(item, typeName, programmatic);
47898
47929
  return c.json({ ok: true, data });
47899
47930
  });
47900
47931
  }
47901
47932
  }
47902
- for (const [typeName] of Object.entries(registry2.taxonomy_types)) {
47933
+ for (const [typeName, taxonomyType] of Object.entries(registry2.taxonomy_types)) {
47903
47934
  const repo = repos[typeName];
47904
47935
  if (!repo) continue;
47936
+ const programmatic = taxonomyType.fields.filter((f) => f.field_type === "programmatic").map((f) => f.name);
47905
47937
  registerListRoute(paths.taxonomyCollection(typeName), async (c) => {
47906
47938
  const pagination = parsePagination(c.req.query("page"), c.req.query("per_page"));
47907
47939
  if (!pagination.ok) {
@@ -47921,10 +47953,7 @@ function registerPublicContentRoutes(app, registry2, repos, projectors, paths, l
47921
47953
  page: pagination.page,
47922
47954
  per_page: pagination.per_page
47923
47955
  });
47924
- const labeled = result.data.map(
47925
- (row) => projectRow(row, typeName, projectors)
47926
- );
47927
- const data = resolver?.hasSchema(typeName) ? await resolver.resolveList(typeName, labeled) : labeled;
47956
+ const data = await respondList(result.data, typeName, programmatic);
47928
47957
  return c.json({ ...result, data });
47929
47958
  });
47930
47959
  app.get(paths.taxonomyItem(typeName), async (c) => {
@@ -47939,8 +47968,7 @@ function registerPublicContentRoutes(app, registry2, repos, projectors, paths, l
47939
47968
  404
47940
47969
  );
47941
47970
  }
47942
- let data = projectRow(item, typeName, projectors);
47943
- if (resolver?.hasSchema(typeName)) data = await resolver.resolveItem(typeName, data);
47971
+ const data = await respondItem(item, typeName, programmatic);
47944
47972
  return c.json({ ok: true, data });
47945
47973
  });
47946
47974
  }
@@ -49702,7 +49730,7 @@ function registerUserRoutes(app, db, requirePermission, requireHierarchy) {
49702
49730
  }
49703
49731
  var API_VERSION = (() => {
49704
49732
  try {
49705
- return "0.6.0";
49733
+ return "0.7.0";
49706
49734
  } catch {
49707
49735
  return "0.0.0";
49708
49736
  }
@@ -50343,7 +50371,7 @@ function createCmsApp(options) {
50343
50371
  app.use(path7, attachDeprecationHeaders);
50344
50372
  }
50345
50373
  }
50346
- registerPublicContentRoutes(app, registry2, surface.repos, surface.projectors, surface.paths, listRateLimit, programmaticResolver);
50374
+ registerPublicContentRoutes(app, registry2, surface.repos, surface.projectors, surface.paths, listRateLimit, programmaticResolver, projectors);
50347
50375
  }
50348
50376
  if (options.versions !== void 0) {
50349
50377
  app.all(`${prefix}/:version/*`, async (c, next) => {
@@ -50385,7 +50413,7 @@ function createCmsApp(options) {
50385
50413
  handler: null,
50386
50414
  error: null
50387
50415
  }));
50388
- const ready = import("./handler-XZVDLKZ2-2TIH4GG7.js").then(({ createGraphQLHandler }) => {
50416
+ const ready = import("./handler-GED3I7Z2-HZAD77OI.js").then(({ createGraphQLHandler }) => {
50389
50417
  gqlPasses.forEach((pass, i) => {
50390
50418
  const mount = mounts[i];
50391
50419
  try {
@@ -50409,7 +50437,8 @@ function createCmsApp(options) {
50409
50437
  endpoint: mount.path,
50410
50438
  currentVersion: model.current,
50411
50439
  ...projection !== void 0 && { projection },
50412
- ...currentProjection !== void 0 && { currentProjection }
50440
+ ...currentProjection !== void 0 && { currentProjection },
50441
+ currentFieldKeyMaps: fieldKeyMaps
50413
50442
  }
50414
50443
  );
50415
50444
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobbykim/manguito-cms-cli",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
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-api": "0.6.0",
33
- "@bobbykim/manguito-cms-db": "0.1.6",
32
+ "@bobbykim/manguito-cms-admin": "0.4.3",
34
33
  "@bobbykim/manguito-cms-core": "0.6.0",
35
- "@bobbykim/manguito-cms-admin": "0.4.3"
34
+ "@bobbykim/manguito-cms-api": "0.7.0",
35
+ "@bobbykim/manguito-cms-db": "0.1.6"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/node": "^25.9.5",
@@ -42,7 +42,7 @@
42
42
  "scripts": {
43
43
  "build": "tsup",
44
44
  "dev": "tsup --watch",
45
- "test": "dotenv -e .env.test -- vitest run",
45
+ "test": "dotenv -e ../../.env.test -- vitest run",
46
46
  "lint": "eslint src",
47
47
  "typecheck": "tsc --noEmit"
48
48
  }