@bobbykim/manguito-cms-api 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-XNXM4W4K.mjs → chunk-4LLELFAZ.mjs} +20 -23
- package/dist/chunk-4LLELFAZ.mjs.map +1 -0
- package/dist/{chunk-JVP33FI2.mjs → chunk-FXPKGPYF.mjs} +46 -43
- package/dist/chunk-FXPKGPYF.mjs.map +1 -0
- package/dist/graphql/index.d.mts +1 -0
- package/dist/graphql/index.d.ts +1 -0
- package/dist/graphql/index.js +26 -40
- package/dist/graphql/index.js.map +1 -1
- package/dist/graphql/index.mjs +2 -2
- package/dist/handler-GED3I7Z2.mjs +8 -0
- package/dist/index.js +146 -116
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +84 -55
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-JVP33FI2.mjs.map +0 -1
- package/dist/chunk-XNXM4W4K.mjs.map +0 -1
- package/dist/handler-XZVDLKZ2.mjs +0 -8
- /package/dist/{handler-XZVDLKZ2.mjs.map → handler-GED3I7Z2.mjs.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -38,7 +38,7 @@ function isColumnBacked(field) {
|
|
|
38
38
|
if (col.junction) return false;
|
|
39
39
|
return true;
|
|
40
40
|
}
|
|
41
|
-
function buildFieldKeyMap(pairs, allLabels,
|
|
41
|
+
function buildFieldKeyMap(pairs, allLabels, droppedColumns, droppedLabels) {
|
|
42
42
|
const labelToColumn = /* @__PURE__ */ new Map();
|
|
43
43
|
const columnToLabel = /* @__PURE__ */ new Map();
|
|
44
44
|
for (const { label, column } of pairs) {
|
|
@@ -46,7 +46,7 @@ function buildFieldKeyMap(pairs, allLabels, droppedKeys) {
|
|
|
46
46
|
columnToLabel.set(column, label);
|
|
47
47
|
}
|
|
48
48
|
for (const { label, ownColumn } of allLabels) {
|
|
49
|
-
if (ownColumn
|
|
49
|
+
if (ownColumn !== void 0) continue;
|
|
50
50
|
const columnOwner = columnToLabel.get(label);
|
|
51
51
|
if (columnOwner !== void 0 && columnOwner !== label) {
|
|
52
52
|
throw new Error(
|
|
@@ -55,23 +55,33 @@ function buildFieldKeyMap(pairs, allLabels, droppedKeys) {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
for (const label of labelToColumn.keys()) {
|
|
58
|
-
if (
|
|
58
|
+
if (droppedLabels.has(label)) labelToColumn.delete(label);
|
|
59
59
|
}
|
|
60
60
|
for (const column of columnToLabel.keys()) {
|
|
61
|
-
if (
|
|
61
|
+
if (droppedColumns.has(column)) columnToLabel.delete(column);
|
|
62
62
|
}
|
|
63
63
|
const diverges = [...labelToColumn].some(([label, column]) => label !== column);
|
|
64
|
-
function remap(input, lookup) {
|
|
64
|
+
function remap(input, lookup, dropped, droppedIfUnmapped) {
|
|
65
65
|
const out = {};
|
|
66
66
|
for (const key of Object.keys(input)) {
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
const mapped = lookup.get(key);
|
|
68
|
+
if (mapped !== void 0) {
|
|
69
|
+
out[mapped] = input[key];
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (dropped.has(key) || droppedIfUnmapped?.has(key)) continue;
|
|
73
|
+
out[key] = input[key];
|
|
69
74
|
}
|
|
70
75
|
return out;
|
|
71
76
|
}
|
|
72
77
|
return {
|
|
73
|
-
toStorage
|
|
74
|
-
|
|
78
|
+
// toStorage reads LABEL-keyed input: a live label maps and writes
|
|
79
|
+
// regardless of either drop set; an unmapped key is refused if it is
|
|
80
|
+
// EITHER the tombstone's own name (droppedLabels) or a raw, unexposed
|
|
81
|
+
// column (droppedColumns) — see remap's comment.
|
|
82
|
+
// toLabels reads COLUMN-keyed input, so it consults only droppedColumns.
|
|
83
|
+
toStorage: (input) => remap(input, labelToColumn, droppedLabels, droppedColumns),
|
|
84
|
+
toLabels: (row) => remap(row, columnToLabel, droppedColumns),
|
|
75
85
|
columnFor: (label) => labelToColumn.get(label),
|
|
76
86
|
labelFor: (column) => columnToLabel.get(column),
|
|
77
87
|
labels: [...labelToColumn.keys()],
|
|
@@ -79,14 +89,15 @@ function buildFieldKeyMap(pairs, allLabels, droppedKeys) {
|
|
|
79
89
|
};
|
|
80
90
|
}
|
|
81
91
|
function createFieldKeyMap(fields) {
|
|
82
|
-
const
|
|
92
|
+
const droppedColumns = /* @__PURE__ */ new Set();
|
|
93
|
+
const droppedLabels = /* @__PURE__ */ new Set();
|
|
83
94
|
const pairs = [];
|
|
84
95
|
for (const f of fields) {
|
|
85
96
|
if (!isColumnBacked(f)) continue;
|
|
86
97
|
pairs.push({ label: f.name, column: f.db_column.column_name });
|
|
87
98
|
if (f.removed === true) {
|
|
88
|
-
|
|
89
|
-
|
|
99
|
+
droppedLabels.add(f.name);
|
|
100
|
+
droppedColumns.add(f.db_column.column_name);
|
|
90
101
|
}
|
|
91
102
|
}
|
|
92
103
|
return buildFieldKeyMap(
|
|
@@ -97,30 +108,33 @@ function createFieldKeyMap(fields) {
|
|
|
97
108
|
// forbids present-and-undefined.
|
|
98
109
|
...isColumnBacked(f) && { ownColumn: f.db_column.column_name }
|
|
99
110
|
})),
|
|
100
|
-
|
|
111
|
+
droppedColumns,
|
|
112
|
+
droppedLabels
|
|
101
113
|
);
|
|
102
114
|
}
|
|
103
115
|
function createFieldKeyMapFromProjection(projectionType, allFields) {
|
|
104
116
|
const pairs = projectionType.fields.map((f) => ({ label: f.exposed_as, column: f.column_name }));
|
|
105
|
-
const
|
|
106
|
-
const
|
|
117
|
+
const projectedColumns = new Set(pairs.map((p) => p.column));
|
|
118
|
+
const projectedLabels = new Set(pairs.map((p) => p.label));
|
|
119
|
+
const droppedColumns = /* @__PURE__ */ new Set();
|
|
120
|
+
const droppedLabels = /* @__PURE__ */ new Set();
|
|
107
121
|
for (const f of allFields) {
|
|
108
122
|
if (!isColumnBacked(f)) continue;
|
|
109
|
-
|
|
110
|
-
|
|
123
|
+
if (!projectedColumns.has(f.db_column.column_name)) droppedColumns.add(f.db_column.column_name);
|
|
124
|
+
if (!projectedLabels.has(f.name)) droppedLabels.add(f.name);
|
|
111
125
|
}
|
|
112
|
-
for (const p of pairs) dropped.delete(p.column);
|
|
113
|
-
for (const label of projected) dropped.delete(label);
|
|
114
126
|
return buildFieldKeyMap(
|
|
115
127
|
pairs,
|
|
116
128
|
allFields.map((f) => ({
|
|
117
129
|
label: f.name,
|
|
118
|
-
// See buildFieldKeyMap's collision check:
|
|
119
|
-
//
|
|
120
|
-
// label
|
|
130
|
+
// See buildFieldKeyMap's collision check: `ownColumn` marks every
|
|
131
|
+
// column-backed field so the check skips it entirely — only a
|
|
132
|
+
// paragraph/junction/programmatic label (no column of its own) can
|
|
133
|
+
// still collide.
|
|
121
134
|
...isColumnBacked(f) && { ownColumn: f.db_column.column_name }
|
|
122
135
|
})),
|
|
123
|
-
|
|
136
|
+
droppedColumns,
|
|
137
|
+
droppedLabels
|
|
124
138
|
);
|
|
125
139
|
}
|
|
126
140
|
var init_field_keys = __esm({
|
|
@@ -299,9 +313,8 @@ function groupBy(items, key) {
|
|
|
299
313
|
}
|
|
300
314
|
return result;
|
|
301
315
|
}
|
|
302
|
-
function needsFkResolution(row, fkColumn
|
|
303
|
-
|
|
304
|
-
const current = row[fieldName];
|
|
316
|
+
function needsFkResolution(row, fkColumn) {
|
|
317
|
+
const current = row[fkColumn];
|
|
305
318
|
return !(typeof current === "object" && current !== null);
|
|
306
319
|
}
|
|
307
320
|
async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOnly = false) {
|
|
@@ -318,15 +331,11 @@ async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOn
|
|
|
318
331
|
row[fieldName] = byParent[row["id"]] ?? [];
|
|
319
332
|
}
|
|
320
333
|
} else if (rel.type === "reference") {
|
|
321
|
-
const
|
|
322
|
-
const pending = batch.filter((r) => needsFkResolution(r, rel.fk_column, fieldName));
|
|
334
|
+
const pending = batch.filter((r) => needsFkResolution(r, rel.fk_column));
|
|
323
335
|
if (pending.length === 0) return;
|
|
324
336
|
const fkValues = pending.map((r) => r[rel.fk_column]).filter(Boolean);
|
|
325
337
|
if (fkValues.length === 0) {
|
|
326
|
-
for (const row of pending)
|
|
327
|
-
row[fieldName] = null;
|
|
328
|
-
if (dropFk) delete row[rel.fk_column];
|
|
329
|
-
}
|
|
338
|
+
for (const row of pending) row[rel.fk_column] = null;
|
|
330
339
|
return;
|
|
331
340
|
}
|
|
332
341
|
const unique = [...new Set(fkValues)];
|
|
@@ -343,8 +352,7 @@ async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOn
|
|
|
343
352
|
}
|
|
344
353
|
for (const row of pending) {
|
|
345
354
|
const fkVal = row[rel.fk_column];
|
|
346
|
-
row[
|
|
347
|
-
if (dropFk) delete row[rel.fk_column];
|
|
355
|
+
row[rel.fk_column] = fkVal ? cache.get(`${rel.table}:${fkVal}`) ?? null : null;
|
|
348
356
|
}
|
|
349
357
|
} else if (rel.type === "junction") {
|
|
350
358
|
const parentIds = batch.map((r) => r["id"]);
|
|
@@ -372,15 +380,11 @@ async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOn
|
|
|
372
380
|
row[fieldName] = jEntries.map((jr) => cache.get(`${rel.table}:${jr[rel.right_column]}`)).filter(Boolean);
|
|
373
381
|
}
|
|
374
382
|
} else if (rel.type === "media") {
|
|
375
|
-
const
|
|
376
|
-
const pending = batch.filter((r) => needsFkResolution(r, rel.fk_column, fieldName));
|
|
383
|
+
const pending = batch.filter((r) => needsFkResolution(r, rel.fk_column));
|
|
377
384
|
if (pending.length === 0) return;
|
|
378
385
|
const fkValues = pending.map((r) => r[rel.fk_column]).filter(Boolean);
|
|
379
386
|
if (fkValues.length === 0) {
|
|
380
|
-
for (const row of pending)
|
|
381
|
-
row[fieldName] = null;
|
|
382
|
-
if (dropFk) delete row[rel.fk_column];
|
|
383
|
-
}
|
|
387
|
+
for (const row of pending) row[rel.fk_column] = null;
|
|
384
388
|
return;
|
|
385
389
|
}
|
|
386
390
|
const unique = [...new Set(fkValues)];
|
|
@@ -394,8 +398,7 @@ async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOn
|
|
|
394
398
|
}
|
|
395
399
|
for (const row of pending) {
|
|
396
400
|
const fkVal = row[rel.fk_column];
|
|
397
|
-
row[
|
|
398
|
-
if (dropFk) delete row[rel.fk_column];
|
|
401
|
+
row[rel.fk_column] = fkVal ? cache.get(`media:${fkVal}`) ?? null : null;
|
|
399
402
|
}
|
|
400
403
|
}
|
|
401
404
|
}
|
|
@@ -677,29 +680,22 @@ function scalarFieldResolver(field, fallback) {
|
|
|
677
680
|
function relationFieldResolver(typeName, schemaFieldName) {
|
|
678
681
|
return (parent, _args, ctx) => ctx.loaders.load(typeName, schemaFieldName, parent);
|
|
679
682
|
}
|
|
680
|
-
function programmaticFieldResolver(typeName, schemaFieldName,
|
|
683
|
+
function programmaticFieldResolver(typeName, schemaFieldName, mediaFieldNames = [], fieldKeys) {
|
|
681
684
|
return async (parent, _args, ctx) => {
|
|
682
685
|
let p = ctx.programmaticMemo.get(parent);
|
|
683
686
|
if (!p) {
|
|
684
|
-
p = resolveProgrammaticRow(typeName, parent, ctx,
|
|
687
|
+
p = resolveProgrammaticRow(typeName, parent, ctx, mediaFieldNames, fieldKeys);
|
|
685
688
|
ctx.programmaticMemo.set(parent, p);
|
|
686
689
|
}
|
|
687
690
|
return (await p)[schemaFieldName];
|
|
688
691
|
};
|
|
689
692
|
}
|
|
690
|
-
async function resolveProgrammaticRow(typeName, parent, ctx,
|
|
693
|
+
async function resolveProgrammaticRow(typeName, parent, ctx, mediaFieldNames, fieldKeys) {
|
|
691
694
|
const toLabels = (row) => fieldKeys ? fieldKeys.toLabels(row) : row;
|
|
692
|
-
if (
|
|
695
|
+
if (mediaFieldNames.length === 0) return ctx.resolver.resolveItem(typeName, toLabels(parent));
|
|
693
696
|
const enriched = { ...parent };
|
|
694
|
-
await Promise.all(
|
|
695
|
-
return ctx.resolver.resolveItem(typeName,
|
|
696
|
-
}
|
|
697
|
-
function relabelMedia(record, enriched, mediaFields) {
|
|
698
|
-
for (const { name, exposedAs } of mediaFields) {
|
|
699
|
-
if (!(name in enriched)) continue;
|
|
700
|
-
record[exposedAs] = enriched[name];
|
|
701
|
-
}
|
|
702
|
-
return record;
|
|
697
|
+
await Promise.all(mediaFieldNames.map((name) => ctx.loaders.load(typeName, name, enriched)));
|
|
698
|
+
return ctx.resolver.resolveItem(typeName, toLabels(enriched));
|
|
703
699
|
}
|
|
704
700
|
function collectionResolver(typeName, nameMap, fieldKeys) {
|
|
705
701
|
return async (_root, args, ctx) => {
|
|
@@ -757,7 +753,7 @@ var init_resolvers = __esm({
|
|
|
757
753
|
});
|
|
758
754
|
|
|
759
755
|
// src/graphql/schema.ts
|
|
760
|
-
function buildGraphQLSchema(registry, fieldKeyMaps = {}, view) {
|
|
756
|
+
function buildGraphQLSchema(registry, fieldKeyMaps = {}, view, programmaticKeyMaps = fieldKeyMaps) {
|
|
761
757
|
const objectTypes = /* @__PURE__ */ new Map();
|
|
762
758
|
const enumTypes = /* @__PURE__ */ new Map();
|
|
763
759
|
for (const [name, enumType] of Object.entries(registry.enum_types)) {
|
|
@@ -821,9 +817,9 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}, view) {
|
|
|
821
817
|
}
|
|
822
818
|
function buildObjectType(machineName, type) {
|
|
823
819
|
const visible = viewFieldsFor(machineName, type);
|
|
824
|
-
const
|
|
825
|
-
(
|
|
826
|
-
).map((
|
|
820
|
+
const mediaFieldNames = type.fields.filter(
|
|
821
|
+
(f) => f.removed !== true && (f.field_type === "image" || f.field_type === "video" || f.field_type === "file")
|
|
822
|
+
).map((f) => f.name);
|
|
827
823
|
return new import_graphql5.GraphQLObjectType({
|
|
828
824
|
name: graphqlTypeName(machineName),
|
|
829
825
|
fields: () => {
|
|
@@ -843,7 +839,7 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}, view) {
|
|
|
843
839
|
const outType = outputTypeForField(field, vf.required);
|
|
844
840
|
let resolve;
|
|
845
841
|
if (field.field_type === "programmatic") {
|
|
846
|
-
resolve = programmaticFieldResolver(machineName, field.name,
|
|
842
|
+
resolve = programmaticFieldResolver(machineName, field.name, mediaFieldNames, programmaticKeyMaps[machineName]);
|
|
847
843
|
} else if (field.field_type === "reference" || field.field_type === "paragraph" || field.field_type === "image" || field.field_type === "video" || field.field_type === "file") {
|
|
848
844
|
resolve = relationFieldResolver(machineName, field.name);
|
|
849
845
|
} else {
|
|
@@ -888,7 +884,10 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}, view) {
|
|
|
888
884
|
for (const [name, ct] of Object.entries(registry.content_types)) {
|
|
889
885
|
const objType = objectTypes.get(name);
|
|
890
886
|
const visible = viewFieldsFor(name, ct);
|
|
891
|
-
const nameMap = buildFieldNameMap(
|
|
887
|
+
const nameMap = buildFieldNameMap([
|
|
888
|
+
...visible.map((v) => v.exposedAs),
|
|
889
|
+
...ct.system_fields.map((s) => s.name)
|
|
890
|
+
]);
|
|
892
891
|
if (ct.only_one) {
|
|
893
892
|
queryFields[singleQueryName(name)] = { type: objType, resolve: singletonResolver(name) };
|
|
894
893
|
continue;
|
|
@@ -1076,7 +1075,8 @@ function createRelationLoaders(db, registry) {
|
|
|
1076
1075
|
async (parents) => {
|
|
1077
1076
|
const rows = parents;
|
|
1078
1077
|
await resolveRelationField(db, rows, fieldName, rel, cache, true);
|
|
1079
|
-
|
|
1078
|
+
const resultKey = rel.type === "reference" || rel.type === "media" ? rel.fk_column : fieldName;
|
|
1079
|
+
return rows.map((r) => r[resultKey]);
|
|
1080
1080
|
},
|
|
1081
1081
|
// Batch within a tick; do not memoize by parent identity (rows are mutated
|
|
1082
1082
|
// and may recur across nesting levels).
|
|
@@ -1161,7 +1161,7 @@ function createGraphQLHandler(registry, repos, fieldKeyMaps, resolver, db, optio
|
|
|
1161
1161
|
currentVersion: versioning.currentVersion
|
|
1162
1162
|
});
|
|
1163
1163
|
}
|
|
1164
|
-
const schema = buildGraphQLSchema(registry, fieldKeyMaps, view);
|
|
1164
|
+
const schema = buildGraphQLSchema(registry, fieldKeyMaps, view, versioning.currentFieldKeyMaps ?? fieldKeyMaps);
|
|
1165
1165
|
const { plugins } = buildArmorPlugin({
|
|
1166
1166
|
maxDepth: options.maxDepth,
|
|
1167
1167
|
maxComplexity: options.maxComplexity
|
|
@@ -1817,18 +1817,21 @@ function createProgrammaticResolver(resolvers, options) {
|
|
|
1817
1817
|
}
|
|
1818
1818
|
|
|
1819
1819
|
// src/projector.ts
|
|
1820
|
+
init_field_keys();
|
|
1820
1821
|
function isPlainRow(v) {
|
|
1821
1822
|
return typeof v === "object" && v !== null && !Array.isArray(v) && !(v instanceof Date);
|
|
1822
1823
|
}
|
|
1823
1824
|
var MEDIA_FIELD_TYPES = /* @__PURE__ */ new Set(["image", "video", "file"]);
|
|
1824
|
-
function nestedTargets(fields) {
|
|
1825
|
+
function nestedTargets(fields, map) {
|
|
1825
1826
|
const out = [];
|
|
1826
1827
|
for (const f of fields) {
|
|
1827
1828
|
if (MEDIA_FIELD_TYPES.has(f.field_type)) continue;
|
|
1828
1829
|
if (f.field_type !== "paragraph" && f.field_type !== "reference") continue;
|
|
1829
1830
|
const ref = f.ui_component.ref;
|
|
1830
1831
|
if (!ref) continue;
|
|
1831
|
-
|
|
1832
|
+
const label = isColumnBacked(f) ? map.labelFor(f.db_column.column_name) : f.name;
|
|
1833
|
+
if (label === void 0) continue;
|
|
1834
|
+
out.push({ label, target: ref });
|
|
1832
1835
|
}
|
|
1833
1836
|
return out;
|
|
1834
1837
|
}
|
|
@@ -1846,7 +1849,7 @@ function buildProjectors(registry, fieldKeyMaps, fallbacks) {
|
|
|
1846
1849
|
const typeFallbacks = fallbacks?.[typeName];
|
|
1847
1850
|
projectors[typeName] = {
|
|
1848
1851
|
map,
|
|
1849
|
-
nested: nestedTargets(type.fields),
|
|
1852
|
+
nested: nestedTargets(type.fields, map),
|
|
1850
1853
|
// Spread rather than assign: with exactOptionalPropertyTypes, an optional
|
|
1851
1854
|
// property may be ABSENT but not present-and-undefined.
|
|
1852
1855
|
...typeFallbacks !== void 0 && { fallbacks: typeFallbacks }
|
|
@@ -1933,7 +1936,28 @@ function parseFilters(url, validFields, columnFor) {
|
|
|
1933
1936
|
function isPublished(item) {
|
|
1934
1937
|
return item["published"] === true;
|
|
1935
1938
|
}
|
|
1936
|
-
function registerPublicContentRoutes(app, registry, repos, projectors, paths, listRateLimit, resolver) {
|
|
1939
|
+
function registerPublicContentRoutes(app, registry, repos, projectors, paths, listRateLimit, resolver, resolverProjectors) {
|
|
1940
|
+
const forResolver = resolverProjectors ?? projectors;
|
|
1941
|
+
function pickProgrammatic(resolved, names) {
|
|
1942
|
+
const out = {};
|
|
1943
|
+
for (const name of names) if (name in resolved) out[name] = resolved[name];
|
|
1944
|
+
return out;
|
|
1945
|
+
}
|
|
1946
|
+
async function respondItem(row, typeName, programmatic) {
|
|
1947
|
+
const data = projectRow(row, typeName, projectors);
|
|
1948
|
+
if (!resolver?.hasSchema(typeName)) return data;
|
|
1949
|
+
const resolved = await resolver.resolveItem(typeName, projectRow(row, typeName, forResolver));
|
|
1950
|
+
return { ...data, ...pickProgrammatic(resolved, programmatic) };
|
|
1951
|
+
}
|
|
1952
|
+
async function respondList(rows, typeName, programmatic) {
|
|
1953
|
+
const data = rows.map((row) => projectRow(row, typeName, projectors));
|
|
1954
|
+
if (!resolver?.hasSchema(typeName)) return data;
|
|
1955
|
+
const resolved = await resolver.resolveList(
|
|
1956
|
+
typeName,
|
|
1957
|
+
rows.map((row) => projectRow(row, typeName, forResolver))
|
|
1958
|
+
);
|
|
1959
|
+
return data.map((d, i) => ({ ...d, ...pickProgrammatic(resolved[i], programmatic) }));
|
|
1960
|
+
}
|
|
1937
1961
|
function registerListRoute(path, handler) {
|
|
1938
1962
|
if (listRateLimit) {
|
|
1939
1963
|
app.get(path, listRateLimit, handler);
|
|
@@ -1957,18 +1981,29 @@ function registerPublicContentRoutes(app, registry, repos, projectors, paths, li
|
|
|
1957
1981
|
return c.json({ ok: true, data });
|
|
1958
1982
|
});
|
|
1959
1983
|
for (const [typeName, contentType] of Object.entries(registry.content_types)) {
|
|
1984
|
+
let translateInclude2 = function(requested) {
|
|
1985
|
+
const include = [];
|
|
1986
|
+
for (const field of requested) {
|
|
1987
|
+
const registryName = includeNames.get(field);
|
|
1988
|
+
if (registryName === void 0) return { ok: false, field };
|
|
1989
|
+
include.push(registryName);
|
|
1990
|
+
}
|
|
1991
|
+
return { ok: true, include };
|
|
1992
|
+
};
|
|
1993
|
+
var translateInclude = translateInclude2;
|
|
1960
1994
|
const basePath = contentType.default_base_path;
|
|
1961
1995
|
const repo = repos[typeName];
|
|
1962
1996
|
if (!repo) continue;
|
|
1963
1997
|
const fieldKeys = projectors[typeName].map;
|
|
1964
|
-
const
|
|
1998
|
+
const programmatic = contentType.fields.filter((f) => f.field_type === "programmatic").map((f) => f.name);
|
|
1999
|
+
const includeNames = /* @__PURE__ */ new Map();
|
|
1965
2000
|
for (const f of contentType.fields) {
|
|
1966
2001
|
if (!RELATION_FIELD_TYPES.has(f.field_type)) continue;
|
|
1967
2002
|
if (isColumnBacked(f)) {
|
|
1968
2003
|
const label = fieldKeys.labelFor(f.db_column.column_name);
|
|
1969
|
-
if (label !== void 0)
|
|
2004
|
+
if (label !== void 0) includeNames.set(label, f.name);
|
|
1970
2005
|
} else {
|
|
1971
|
-
|
|
2006
|
+
includeNames.set(f.name, f.name);
|
|
1972
2007
|
}
|
|
1973
2008
|
}
|
|
1974
2009
|
const filterableFieldNames = /* @__PURE__ */ new Set([
|
|
@@ -1987,8 +2022,11 @@ function registerPublicContentRoutes(app, registry, repos, projectors, paths, li
|
|
|
1987
2022
|
404
|
|
1988
2023
|
);
|
|
1989
2024
|
}
|
|
1990
|
-
|
|
1991
|
-
|
|
2025
|
+
const data = await respondItem(
|
|
2026
|
+
result.data[0],
|
|
2027
|
+
typeName,
|
|
2028
|
+
programmatic
|
|
2029
|
+
);
|
|
1992
2030
|
return c.json({ ok: true, data });
|
|
1993
2031
|
});
|
|
1994
2032
|
} else {
|
|
@@ -2045,21 +2083,20 @@ function registerPublicContentRoutes(app, registry, repos, projectors, paths, li
|
|
|
2045
2083
|
400
|
|
2046
2084
|
);
|
|
2047
2085
|
}
|
|
2048
|
-
const
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
);
|
|
2061
|
-
}
|
|
2086
|
+
const translated = translateInclude2(parseInclude(c.req.query("include")));
|
|
2087
|
+
if (!translated.ok) {
|
|
2088
|
+
return c.json(
|
|
2089
|
+
{
|
|
2090
|
+
ok: false,
|
|
2091
|
+
error: {
|
|
2092
|
+
code: "INVALID_INCLUDE_FIELD",
|
|
2093
|
+
message: `'${translated.field}' is not a valid relation field`
|
|
2094
|
+
}
|
|
2095
|
+
},
|
|
2096
|
+
400
|
|
2097
|
+
);
|
|
2062
2098
|
}
|
|
2099
|
+
const include = translated.include;
|
|
2063
2100
|
const sortColumn = fieldKeys.labels.includes(sortBy) ? fieldKeys.columnFor(sortBy) : sortBy;
|
|
2064
2101
|
const result = await repo.findMany({
|
|
2065
2102
|
published_only: true,
|
|
@@ -2070,29 +2107,25 @@ function registerPublicContentRoutes(app, registry, repos, projectors, paths, li
|
|
|
2070
2107
|
filters: filtersResult.filters,
|
|
2071
2108
|
include
|
|
2072
2109
|
});
|
|
2073
|
-
const
|
|
2074
|
-
(row) => projectRow(row, typeName, projectors)
|
|
2075
|
-
);
|
|
2076
|
-
const data = resolver?.hasSchema(typeName) ? await resolver.resolveList(typeName, labeled) : labeled;
|
|
2110
|
+
const data = await respondList(result.data, typeName, programmatic);
|
|
2077
2111
|
return c.json({ ...result, data });
|
|
2078
2112
|
});
|
|
2079
2113
|
app.get(paths.item(basePath), async (c) => {
|
|
2080
2114
|
const slug = c.req.param("slug");
|
|
2081
|
-
const
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
);
|
|
2094
|
-
}
|
|
2115
|
+
const translated = translateInclude2(parseInclude(c.req.query("include")));
|
|
2116
|
+
if (!translated.ok) {
|
|
2117
|
+
return c.json(
|
|
2118
|
+
{
|
|
2119
|
+
ok: false,
|
|
2120
|
+
error: {
|
|
2121
|
+
code: "INVALID_INCLUDE_FIELD",
|
|
2122
|
+
message: `'${translated.field}' is not a valid relation field`
|
|
2123
|
+
}
|
|
2124
|
+
},
|
|
2125
|
+
400
|
|
2126
|
+
);
|
|
2095
2127
|
}
|
|
2128
|
+
const include = translated.include;
|
|
2096
2129
|
const item = await repo.findBySlug(slug, include);
|
|
2097
2130
|
if (!item || !isPublished(item)) {
|
|
2098
2131
|
return c.json(
|
|
@@ -2103,15 +2136,15 @@ function registerPublicContentRoutes(app, registry, repos, projectors, paths, li
|
|
|
2103
2136
|
404
|
|
2104
2137
|
);
|
|
2105
2138
|
}
|
|
2106
|
-
|
|
2107
|
-
if (resolver?.hasSchema(typeName)) data = await resolver.resolveItem(typeName, data);
|
|
2139
|
+
const data = await respondItem(item, typeName, programmatic);
|
|
2108
2140
|
return c.json({ ok: true, data });
|
|
2109
2141
|
});
|
|
2110
2142
|
}
|
|
2111
2143
|
}
|
|
2112
|
-
for (const [typeName] of Object.entries(registry.taxonomy_types)) {
|
|
2144
|
+
for (const [typeName, taxonomyType] of Object.entries(registry.taxonomy_types)) {
|
|
2113
2145
|
const repo = repos[typeName];
|
|
2114
2146
|
if (!repo) continue;
|
|
2147
|
+
const programmatic = taxonomyType.fields.filter((f) => f.field_type === "programmatic").map((f) => f.name);
|
|
2115
2148
|
registerListRoute(paths.taxonomyCollection(typeName), async (c) => {
|
|
2116
2149
|
const pagination = parsePagination(c.req.query("page"), c.req.query("per_page"));
|
|
2117
2150
|
if (!pagination.ok) {
|
|
@@ -2131,10 +2164,7 @@ function registerPublicContentRoutes(app, registry, repos, projectors, paths, li
|
|
|
2131
2164
|
page: pagination.page,
|
|
2132
2165
|
per_page: pagination.per_page
|
|
2133
2166
|
});
|
|
2134
|
-
const
|
|
2135
|
-
(row) => projectRow(row, typeName, projectors)
|
|
2136
|
-
);
|
|
2137
|
-
const data = resolver?.hasSchema(typeName) ? await resolver.resolveList(typeName, labeled) : labeled;
|
|
2167
|
+
const data = await respondList(result.data, typeName, programmatic);
|
|
2138
2168
|
return c.json({ ...result, data });
|
|
2139
2169
|
});
|
|
2140
2170
|
app.get(paths.taxonomyItem(typeName), async (c) => {
|
|
@@ -2149,8 +2179,7 @@ function registerPublicContentRoutes(app, registry, repos, projectors, paths, li
|
|
|
2149
2179
|
404
|
|
2150
2180
|
);
|
|
2151
2181
|
}
|
|
2152
|
-
|
|
2153
|
-
if (resolver?.hasSchema(typeName)) data = await resolver.resolveItem(typeName, data);
|
|
2182
|
+
const data = await respondItem(item, typeName, programmatic);
|
|
2154
2183
|
return c.json({ ok: true, data });
|
|
2155
2184
|
});
|
|
2156
2185
|
}
|
|
@@ -3942,7 +3971,7 @@ function registerUserRoutes(app, db, requirePermission, requireHierarchy) {
|
|
|
3942
3971
|
var import_drizzle_orm6 = require("drizzle-orm");
|
|
3943
3972
|
var API_VERSION = (() => {
|
|
3944
3973
|
try {
|
|
3945
|
-
return "0.
|
|
3974
|
+
return "0.7.0";
|
|
3946
3975
|
} catch {
|
|
3947
3976
|
return "0.0.0";
|
|
3948
3977
|
}
|
|
@@ -4606,7 +4635,7 @@ function createCmsApp(options) {
|
|
|
4606
4635
|
app.use(path, attachDeprecationHeaders);
|
|
4607
4636
|
}
|
|
4608
4637
|
}
|
|
4609
|
-
registerPublicContentRoutes(app, registry, surface.repos, surface.projectors, surface.paths, listRateLimit, programmaticResolver);
|
|
4638
|
+
registerPublicContentRoutes(app, registry, surface.repos, surface.projectors, surface.paths, listRateLimit, programmaticResolver, projectors);
|
|
4610
4639
|
}
|
|
4611
4640
|
if (options.versions !== void 0) {
|
|
4612
4641
|
app.all(`${prefix}/:version/*`, async (c, next) => {
|
|
@@ -4672,7 +4701,8 @@ function createCmsApp(options) {
|
|
|
4672
4701
|
endpoint: mount.path,
|
|
4673
4702
|
currentVersion: model.current,
|
|
4674
4703
|
...projection !== void 0 && { projection },
|
|
4675
|
-
...currentProjection !== void 0 && { currentProjection }
|
|
4704
|
+
...currentProjection !== void 0 && { currentProjection },
|
|
4705
|
+
currentFieldKeyMaps: fieldKeyMaps
|
|
4676
4706
|
}
|
|
4677
4707
|
);
|
|
4678
4708
|
} catch (err) {
|