@bobbykim/manguito-cms-api 0.6.0 → 0.8.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-JVP33FI2.mjs → chunk-IHEIX6P4.mjs} +67 -48
- package/dist/chunk-IHEIX6P4.mjs.map +1 -0
- package/dist/{chunk-XNXM4W4K.mjs → chunk-Y5SWT7PO.mjs} +24 -26
- package/dist/chunk-Y5SWT7PO.mjs.map +1 -0
- package/dist/codegen/index.js +3 -2
- package/dist/codegen/index.js.map +1 -1
- package/dist/codegen/index.mjs +3 -2
- package/dist/codegen/index.mjs.map +1 -1
- package/dist/graphql/index.d.mts +1 -0
- package/dist/graphql/index.d.ts +1 -0
- package/dist/graphql/index.js +40 -45
- package/dist/graphql/index.js.map +1 -1
- package/dist/graphql/index.mjs +2 -2
- package/dist/handler-VEOWJRAL.mjs +8 -0
- package/dist/index.js +454 -265
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +323 -150
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
- 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-VEOWJRAL.mjs.map} +0 -0
package/dist/graphql/index.d.ts
CHANGED
|
@@ -28,6 +28,7 @@ declare function createGraphQLHandler(registry: SchemaRegistry, repos: Record<st
|
|
|
28
28
|
projection?: VersionProjection;
|
|
29
29
|
currentProjection?: VersionProjection;
|
|
30
30
|
currentVersion?: string;
|
|
31
|
+
currentFieldKeyMaps?: Record<string, FieldKeyMap>;
|
|
31
32
|
}): Handler;
|
|
32
33
|
|
|
33
34
|
export { type ResolvedGraphQLOptions, createGraphQLHandler };
|
package/dist/graphql/index.js
CHANGED
|
@@ -39,6 +39,7 @@ var import_graphql_yoga = require("graphql-yoga");
|
|
|
39
39
|
|
|
40
40
|
// src/graphql/schema.ts
|
|
41
41
|
var import_graphql5 = require("graphql");
|
|
42
|
+
var import_manguito_cms_core = require("@bobbykim/manguito-cms-core");
|
|
42
43
|
|
|
43
44
|
// src/graphql/scalars.ts
|
|
44
45
|
var import_graphql = require("graphql");
|
|
@@ -269,29 +270,22 @@ function scalarFieldResolver(field, fallback) {
|
|
|
269
270
|
function relationFieldResolver(typeName, schemaFieldName) {
|
|
270
271
|
return (parent, _args, ctx) => ctx.loaders.load(typeName, schemaFieldName, parent);
|
|
271
272
|
}
|
|
272
|
-
function programmaticFieldResolver(typeName, schemaFieldName,
|
|
273
|
+
function programmaticFieldResolver(typeName, schemaFieldName, mediaFieldNames = [], fieldKeys) {
|
|
273
274
|
return async (parent, _args, ctx) => {
|
|
274
275
|
let p = ctx.programmaticMemo.get(parent);
|
|
275
276
|
if (!p) {
|
|
276
|
-
p = resolveProgrammaticRow(typeName, parent, ctx,
|
|
277
|
+
p = resolveProgrammaticRow(typeName, parent, ctx, mediaFieldNames, fieldKeys);
|
|
277
278
|
ctx.programmaticMemo.set(parent, p);
|
|
278
279
|
}
|
|
279
280
|
return (await p)[schemaFieldName];
|
|
280
281
|
};
|
|
281
282
|
}
|
|
282
|
-
async function resolveProgrammaticRow(typeName, parent, ctx,
|
|
283
|
+
async function resolveProgrammaticRow(typeName, parent, ctx, mediaFieldNames, fieldKeys) {
|
|
283
284
|
const toLabels = (row) => fieldKeys ? fieldKeys.toLabels(row) : row;
|
|
284
|
-
if (
|
|
285
|
+
if (mediaFieldNames.length === 0) return ctx.resolver.resolveItem(typeName, toLabels(parent));
|
|
285
286
|
const enriched = { ...parent };
|
|
286
|
-
await Promise.all(
|
|
287
|
-
return ctx.resolver.resolveItem(typeName,
|
|
288
|
-
}
|
|
289
|
-
function relabelMedia(record, enriched, mediaFields) {
|
|
290
|
-
for (const { name, exposedAs } of mediaFields) {
|
|
291
|
-
if (!(name in enriched)) continue;
|
|
292
|
-
record[exposedAs] = enriched[name];
|
|
293
|
-
}
|
|
294
|
-
return record;
|
|
287
|
+
await Promise.all(mediaFieldNames.map((name) => ctx.loaders.load(typeName, name, enriched)));
|
|
288
|
+
return ctx.resolver.resolveItem(typeName, toLabels(enriched));
|
|
295
289
|
}
|
|
296
290
|
function collectionResolver(typeName, nameMap, fieldKeys) {
|
|
297
291
|
return async (_root, args, ctx) => {
|
|
@@ -365,7 +359,7 @@ var MEDIA = new import_graphql5.GraphQLObjectType({
|
|
|
365
359
|
duration: { type: import_graphql5.GraphQLInt, resolve: (m) => m.duration }
|
|
366
360
|
}
|
|
367
361
|
});
|
|
368
|
-
function buildGraphQLSchema(registry, fieldKeyMaps = {}, view) {
|
|
362
|
+
function buildGraphQLSchema(registry, fieldKeyMaps = {}, view, programmaticKeyMaps = fieldKeyMaps) {
|
|
369
363
|
const objectTypes = /* @__PURE__ */ new Map();
|
|
370
364
|
const enumTypes = /* @__PURE__ */ new Map();
|
|
371
365
|
for (const [name, enumType] of Object.entries(registry.enum_types)) {
|
|
@@ -405,7 +399,8 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}, view) {
|
|
|
405
399
|
`
|
|
406
400
|
);
|
|
407
401
|
}
|
|
408
|
-
|
|
402
|
+
const t = target ?? MEDIA;
|
|
403
|
+
return (0, import_manguito_cms_core.relationCardinality)(field) === "one" ? t : new import_graphql5.GraphQLList(new import_graphql5.GraphQLNonNull(t));
|
|
409
404
|
}
|
|
410
405
|
if (field.field_type === "reference") {
|
|
411
406
|
const ref = field.ui_component.component === "typeahead-select" ? field.ui_component.ref : void 0;
|
|
@@ -414,8 +409,7 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}, view) {
|
|
|
414
409
|
process.stderr.write(`\u26A0 reference field '${field.name}' targets unknown type '${ref}'; exposing as Media
|
|
415
410
|
`);
|
|
416
411
|
}
|
|
417
|
-
const
|
|
418
|
-
const isMany = rel === "many-to-many" || rel === "one-to-many";
|
|
412
|
+
const isMany = (0, import_manguito_cms_core.relationCardinality)(field) === "many";
|
|
419
413
|
const t = target ?? MEDIA;
|
|
420
414
|
return isMany ? new import_graphql5.GraphQLList(new import_graphql5.GraphQLNonNull(t)) : t;
|
|
421
415
|
}
|
|
@@ -429,9 +423,9 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}, view) {
|
|
|
429
423
|
}
|
|
430
424
|
function buildObjectType(machineName, type) {
|
|
431
425
|
const visible = viewFieldsFor(machineName, type);
|
|
432
|
-
const
|
|
433
|
-
(
|
|
434
|
-
).map((
|
|
426
|
+
const mediaFieldNames = type.fields.filter(
|
|
427
|
+
(f) => f.removed !== true && (f.field_type === "image" || f.field_type === "video" || f.field_type === "file")
|
|
428
|
+
).map((f) => f.name);
|
|
435
429
|
return new import_graphql5.GraphQLObjectType({
|
|
436
430
|
name: graphqlTypeName(machineName),
|
|
437
431
|
fields: () => {
|
|
@@ -451,7 +445,7 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}, view) {
|
|
|
451
445
|
const outType = outputTypeForField(field, vf.required);
|
|
452
446
|
let resolve;
|
|
453
447
|
if (field.field_type === "programmatic") {
|
|
454
|
-
resolve = programmaticFieldResolver(machineName, field.name,
|
|
448
|
+
resolve = programmaticFieldResolver(machineName, field.name, mediaFieldNames, programmaticKeyMaps[machineName]);
|
|
455
449
|
} else if (field.field_type === "reference" || field.field_type === "paragraph" || field.field_type === "image" || field.field_type === "video" || field.field_type === "file") {
|
|
456
450
|
resolve = relationFieldResolver(machineName, field.name);
|
|
457
451
|
} else {
|
|
@@ -496,7 +490,10 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}, view) {
|
|
|
496
490
|
for (const [name, ct] of Object.entries(registry.content_types)) {
|
|
497
491
|
const objType = objectTypes.get(name);
|
|
498
492
|
const visible = viewFieldsFor(name, ct);
|
|
499
|
-
const nameMap = buildFieldNameMap(
|
|
493
|
+
const nameMap = buildFieldNameMap([
|
|
494
|
+
...visible.map((v) => v.exposedAs),
|
|
495
|
+
...ct.system_fields.map((s) => s.name)
|
|
496
|
+
]);
|
|
500
497
|
if (ct.only_one) {
|
|
501
498
|
queryFields[singleQueryName(name)] = { type: objType, resolve: singletonResolver(name) };
|
|
502
499
|
continue;
|
|
@@ -625,10 +622,14 @@ var import_dataloader = __toESM(require("dataloader"));
|
|
|
625
622
|
// src/relations.ts
|
|
626
623
|
var import_node_crypto = __toESM(require("crypto"));
|
|
627
624
|
var import_drizzle_orm = require("drizzle-orm");
|
|
625
|
+
var import_manguito_cms_core2 = require("@bobbykim/manguito-cms-core");
|
|
628
626
|
function quoteIdent(name) {
|
|
629
627
|
if (!/^[a-z][a-z0-9_-]*$/.test(name)) throw new Error(`Unsafe identifier: ${name}`);
|
|
630
628
|
return `"${name}"`;
|
|
631
629
|
}
|
|
630
|
+
function oneOrMany(cardinality, list) {
|
|
631
|
+
return cardinality === "one" ? list[0] ?? null : list;
|
|
632
|
+
}
|
|
632
633
|
function buildRelationsMap(fields, registry) {
|
|
633
634
|
const relations = {};
|
|
634
635
|
for (const field of fields) {
|
|
@@ -639,7 +640,11 @@ function buildRelationsMap(fields, registry) {
|
|
|
639
640
|
const ref = field.ui_component.ref;
|
|
640
641
|
const pType = ref ? registry.paragraph_types[ref] : void 0;
|
|
641
642
|
if (!pType) continue;
|
|
642
|
-
relations[field.name] = {
|
|
643
|
+
relations[field.name] = {
|
|
644
|
+
type: "paragraph",
|
|
645
|
+
table: pType.db.table_name,
|
|
646
|
+
cardinality: (0, import_manguito_cms_core2.relationCardinality)(field) ?? "many"
|
|
647
|
+
};
|
|
643
648
|
} else if (field.field_type === "reference") {
|
|
644
649
|
if (!field.db_column) continue;
|
|
645
650
|
if (field.db_column.junction) {
|
|
@@ -672,9 +677,8 @@ function groupBy(items, key) {
|
|
|
672
677
|
}
|
|
673
678
|
return result;
|
|
674
679
|
}
|
|
675
|
-
function needsFkResolution(row, fkColumn
|
|
676
|
-
|
|
677
|
-
const current = row[fieldName];
|
|
680
|
+
function needsFkResolution(row, fkColumn) {
|
|
681
|
+
const current = row[fkColumn];
|
|
678
682
|
return !(typeof current === "object" && current !== null);
|
|
679
683
|
}
|
|
680
684
|
async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOnly = false) {
|
|
@@ -688,18 +692,14 @@ async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOn
|
|
|
688
692
|
);
|
|
689
693
|
const byParent = groupBy(result.rows, "parent_id");
|
|
690
694
|
for (const row of batch) {
|
|
691
|
-
row[fieldName] = byParent[row["id"]] ?? [];
|
|
695
|
+
row[fieldName] = oneOrMany(rel.cardinality, byParent[row["id"]] ?? []);
|
|
692
696
|
}
|
|
693
697
|
} else if (rel.type === "reference") {
|
|
694
|
-
const
|
|
695
|
-
const pending = batch.filter((r) => needsFkResolution(r, rel.fk_column, fieldName));
|
|
698
|
+
const pending = batch.filter((r) => needsFkResolution(r, rel.fk_column));
|
|
696
699
|
if (pending.length === 0) return;
|
|
697
700
|
const fkValues = pending.map((r) => r[rel.fk_column]).filter(Boolean);
|
|
698
701
|
if (fkValues.length === 0) {
|
|
699
|
-
for (const row of pending)
|
|
700
|
-
row[fieldName] = null;
|
|
701
|
-
if (dropFk) delete row[rel.fk_column];
|
|
702
|
-
}
|
|
702
|
+
for (const row of pending) row[rel.fk_column] = null;
|
|
703
703
|
return;
|
|
704
704
|
}
|
|
705
705
|
const unique = [...new Set(fkValues)];
|
|
@@ -716,8 +716,7 @@ async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOn
|
|
|
716
716
|
}
|
|
717
717
|
for (const row of pending) {
|
|
718
718
|
const fkVal = row[rel.fk_column];
|
|
719
|
-
row[
|
|
720
|
-
if (dropFk) delete row[rel.fk_column];
|
|
719
|
+
row[rel.fk_column] = fkVal ? cache.get(`${rel.table}:${fkVal}`) ?? null : null;
|
|
721
720
|
}
|
|
722
721
|
} else if (rel.type === "junction") {
|
|
723
722
|
const parentIds = batch.map((r) => r["id"]);
|
|
@@ -745,15 +744,11 @@ async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOn
|
|
|
745
744
|
row[fieldName] = jEntries.map((jr) => cache.get(`${rel.table}:${jr[rel.right_column]}`)).filter(Boolean);
|
|
746
745
|
}
|
|
747
746
|
} else if (rel.type === "media") {
|
|
748
|
-
const
|
|
749
|
-
const pending = batch.filter((r) => needsFkResolution(r, rel.fk_column, fieldName));
|
|
747
|
+
const pending = batch.filter((r) => needsFkResolution(r, rel.fk_column));
|
|
750
748
|
if (pending.length === 0) return;
|
|
751
749
|
const fkValues = pending.map((r) => r[rel.fk_column]).filter(Boolean);
|
|
752
750
|
if (fkValues.length === 0) {
|
|
753
|
-
for (const row of pending)
|
|
754
|
-
row[fieldName] = null;
|
|
755
|
-
if (dropFk) delete row[rel.fk_column];
|
|
756
|
-
}
|
|
751
|
+
for (const row of pending) row[rel.fk_column] = null;
|
|
757
752
|
return;
|
|
758
753
|
}
|
|
759
754
|
const unique = [...new Set(fkValues)];
|
|
@@ -767,8 +762,7 @@ async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOn
|
|
|
767
762
|
}
|
|
768
763
|
for (const row of pending) {
|
|
769
764
|
const fkVal = row[rel.fk_column];
|
|
770
|
-
row[
|
|
771
|
-
if (dropFk) delete row[rel.fk_column];
|
|
765
|
+
row[rel.fk_column] = fkVal ? cache.get(`media:${fkVal}`) ?? null : null;
|
|
772
766
|
}
|
|
773
767
|
}
|
|
774
768
|
}
|
|
@@ -795,7 +789,8 @@ function createRelationLoaders(db, registry) {
|
|
|
795
789
|
async (parents) => {
|
|
796
790
|
const rows = parents;
|
|
797
791
|
await resolveRelationField(db, rows, fieldName, rel, cache, true);
|
|
798
|
-
|
|
792
|
+
const resultKey = rel.type === "reference" || rel.type === "media" ? rel.fk_column : fieldName;
|
|
793
|
+
return rows.map((r) => r[resultKey]);
|
|
799
794
|
},
|
|
800
795
|
// Batch within a tick; do not memoize by parent identity (rows are mutated
|
|
801
796
|
// and may recur across nesting levels).
|
|
@@ -862,7 +857,7 @@ function createGraphQLHandler(registry, repos, fieldKeyMaps, resolver, db, optio
|
|
|
862
857
|
currentVersion: versioning.currentVersion
|
|
863
858
|
});
|
|
864
859
|
}
|
|
865
|
-
const schema = buildGraphQLSchema(registry, fieldKeyMaps, view);
|
|
860
|
+
const schema = buildGraphQLSchema(registry, fieldKeyMaps, view, versioning.currentFieldKeyMaps ?? fieldKeyMaps);
|
|
866
861
|
const { plugins } = buildArmorPlugin({
|
|
867
862
|
maxDepth: options.maxDepth,
|
|
868
863
|
maxComplexity: options.maxComplexity
|