@bobbykim/manguito-cms-cli 0.5.0 → 0.6.1

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-4Y4G564P.mjs
52
+ // ../api/dist/chunk-JVP33FI2.mjs
53
53
  init_esm_shims();
54
54
  import crypto from "crypto";
55
55
 
@@ -1212,7 +1212,99 @@ Subquery.prototype.getSQL = function() {
1212
1212
  return new SQL([this]);
1213
1213
  };
1214
1214
 
1215
- // ../api/dist/chunk-4Y4G564P.mjs
1215
+ // ../api/dist/chunk-JVP33FI2.mjs
1216
+ function isColumnBacked(field) {
1217
+ const col = field.db_column;
1218
+ if (col === null) return false;
1219
+ if (col.column_name === "") return false;
1220
+ if (col.junction) return false;
1221
+ return true;
1222
+ }
1223
+ function buildFieldKeyMap(pairs, allLabels, droppedKeys) {
1224
+ const labelToColumn = /* @__PURE__ */ new Map();
1225
+ const columnToLabel = /* @__PURE__ */ new Map();
1226
+ for (const { label, column } of pairs) {
1227
+ labelToColumn.set(label, column);
1228
+ columnToLabel.set(column, label);
1229
+ }
1230
+ for (const { label, ownColumn } of allLabels) {
1231
+ if (ownColumn === label) continue;
1232
+ const columnOwner = columnToLabel.get(label);
1233
+ if (columnOwner !== void 0 && columnOwner !== label) {
1234
+ throw new Error(
1235
+ `Fatal: field key map failed to build \u2014 field label "${label}" 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.`
1236
+ );
1237
+ }
1238
+ }
1239
+ for (const label of labelToColumn.keys()) {
1240
+ if (droppedKeys.has(label)) labelToColumn.delete(label);
1241
+ }
1242
+ for (const column of columnToLabel.keys()) {
1243
+ if (droppedKeys.has(column)) columnToLabel.delete(column);
1244
+ }
1245
+ const diverges = [...labelToColumn].some(([label, column]) => label !== column);
1246
+ function remap(input, lookup) {
1247
+ const out = {};
1248
+ for (const key of Object.keys(input)) {
1249
+ if (droppedKeys.has(key)) continue;
1250
+ out[lookup.get(key) ?? key] = input[key];
1251
+ }
1252
+ return out;
1253
+ }
1254
+ return {
1255
+ toStorage: (input) => remap(input, labelToColumn),
1256
+ toLabels: (row) => remap(row, columnToLabel),
1257
+ columnFor: (label) => labelToColumn.get(label),
1258
+ labelFor: (column) => columnToLabel.get(column),
1259
+ labels: [...labelToColumn.keys()],
1260
+ diverges
1261
+ };
1262
+ }
1263
+ function createFieldKeyMap(fields) {
1264
+ const droppedKeys = /* @__PURE__ */ new Set();
1265
+ const pairs = [];
1266
+ for (const f of fields) {
1267
+ if (!isColumnBacked(f)) continue;
1268
+ pairs.push({ label: f.name, column: f.db_column.column_name });
1269
+ if (f.removed === true) {
1270
+ droppedKeys.add(f.name);
1271
+ droppedKeys.add(f.db_column.column_name);
1272
+ }
1273
+ }
1274
+ return buildFieldKeyMap(
1275
+ pairs,
1276
+ fields.map((f) => ({
1277
+ label: f.name,
1278
+ // Conditional spread, not a plain assignment — exactOptionalPropertyTypes
1279
+ // forbids present-and-undefined.
1280
+ ...isColumnBacked(f) && { ownColumn: f.db_column.column_name }
1281
+ })),
1282
+ droppedKeys
1283
+ );
1284
+ }
1285
+ function createFieldKeyMapFromProjection(projectionType, allFields) {
1286
+ 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();
1289
+ for (const f of allFields) {
1290
+ if (!isColumnBacked(f)) continue;
1291
+ dropped.add(f.name);
1292
+ dropped.add(f.db_column.column_name);
1293
+ }
1294
+ for (const p of pairs) dropped.delete(p.column);
1295
+ for (const label of projected) dropped.delete(label);
1296
+ return buildFieldKeyMap(
1297
+ pairs,
1298
+ allFields.map((f) => ({
1299
+ 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).
1303
+ ...isColumnBacked(f) && { ownColumn: f.db_column.column_name }
1304
+ })),
1305
+ dropped
1306
+ );
1307
+ }
1216
1308
  function quoteIdent(name) {
1217
1309
  if (!/^[a-z][a-z0-9_-]*$/.test(name)) throw new Error(`Unsafe identifier: ${name}`);
1218
1310
  return `"${name}"`;
@@ -1506,58 +1598,6 @@ async function resolveRelationBareIds(db, rows, fieldName, rel) {
1506
1598
  }
1507
1599
  }
1508
1600
  }
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
- const droppedKeys = /* @__PURE__ */ new Set();
1520
- for (const f of fields) {
1521
- if (!isColumnBacked(f)) continue;
1522
- columnToLabel.set(f.db_column.column_name, f.name);
1523
- if (f.removed === true) {
1524
- droppedKeys.add(f.name);
1525
- droppedKeys.add(f.db_column.column_name);
1526
- continue;
1527
- }
1528
- labelToColumn.set(f.name, f.db_column.column_name);
1529
- }
1530
- for (const f of fields) {
1531
- const columnOwner = columnToLabel.get(f.name);
1532
- if (columnOwner !== void 0 && columnOwner !== f.name) {
1533
- throw new Error(
1534
- `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.`
1535
- );
1536
- }
1537
- }
1538
- for (const f of fields) {
1539
- if (isColumnBacked(f) && f.removed === true) {
1540
- columnToLabel.delete(f.db_column.column_name);
1541
- }
1542
- }
1543
- const diverges = [...labelToColumn].some(([label, column]) => label !== column);
1544
- function remap(input, lookup) {
1545
- const out = {};
1546
- for (const key of Object.keys(input)) {
1547
- if (droppedKeys.has(key)) continue;
1548
- out[lookup.get(key) ?? key] = input[key];
1549
- }
1550
- return out;
1551
- }
1552
- return {
1553
- toStorage: (input) => remap(input, labelToColumn),
1554
- toLabels: (row) => remap(row, columnToLabel),
1555
- columnFor: (label) => labelToColumn.get(label),
1556
- labelFor: (column) => columnToLabel.get(column),
1557
- labels: [...labelToColumn.keys()],
1558
- diverges
1559
- };
1560
- }
1561
1601
 
1562
1602
  export {
1563
1603
  __require,
@@ -1590,12 +1630,13 @@ export {
1590
1630
  Placeholder,
1591
1631
  fillPlaceholders,
1592
1632
  View,
1633
+ isColumnBacked,
1634
+ createFieldKeyMap,
1635
+ createFieldKeyMapFromProjection,
1593
1636
  persistParagraphField,
1594
1637
  deleteParagraphField,
1595
1638
  persistJunctionField,
1596
1639
  buildRelationsMap,
1597
1640
  resolveRelationField,
1598
- resolveRelationBareIds,
1599
- isColumnBacked,
1600
- createFieldKeyMap
1641
+ resolveRelationBareIds
1601
1642
  };
@@ -11,7 +11,7 @@ import {
11
11
  init_esm_shims,
12
12
  isColumnBacked,
13
13
  resolveRelationField
14
- } from "./chunk-LFMOJRYP.js";
14
+ } from "./chunk-SW3T2M64.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-45O5OX2C.mjs
10789
+ // ../api/dist/handler-XZVDLKZ2.mjs
10790
10790
  init_esm_shims();
10791
10791
 
10792
- // ../api/dist/chunk-HEYT5CH5.mjs
10792
+ // ../api/dist/chunk-XNXM4W4K.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-HEYT5CH5.mjs
30125
+ // ../api/dist/chunk-XNXM4W4K.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-HEYT5CH5.mjs
30883
+ // ../api/dist/chunk-XNXM4W4K.mjs
30884
30884
  var DateTimeScalar = new GraphQLScalarType({
30885
30885
  name: "DateTime",
30886
30886
  description: "ISO-8601 date-time string",
@@ -30979,10 +30979,13 @@ var SORTABLE = [
30979
30979
  { gql: "createdAt", value: "created_at" },
30980
30980
  { gql: "updatedAt", value: "updated_at" }
30981
30981
  ];
30982
- function buildSortFieldEnum(typeName) {
30982
+ function buildSortFieldEnum(typeName, fieldKeys) {
30983
+ const resolvable = SORTABLE.filter(
30984
+ (s) => s.gql === "createdAt" || s.gql === "updatedAt" || fieldKeys === void 0 || fieldKeys.columnFor(s.value) !== void 0
30985
+ );
30983
30986
  return new GraphQLEnumType({
30984
30987
  name: `${typeName}SortField`,
30985
- values: Object.fromEntries(SORTABLE.map((s) => [s.gql, { value: s.value }]))
30988
+ values: Object.fromEntries(resolvable.map((s) => [s.gql, { value: s.value }]))
30986
30989
  });
30987
30990
  }
30988
30991
  function comparableFilterInput(name, scalar) {
@@ -31026,18 +31029,19 @@ function filterInputForField(fieldType) {
31026
31029
  if (scalar === null) return null;
31027
31030
  return StringFilter;
31028
31031
  }
31029
- function buildFilterInputType(type) {
31032
+ function buildFilterInputType(type, viewFields) {
31030
31033
  const fields = {};
31031
31034
  fields["id"] = { type: IDFilter };
31032
31035
  fields["published"] = { type: BooleanFilter };
31033
31036
  fields["createdAt"] = { type: DateTimeFilter };
31034
31037
  fields["updatedAt"] = { type: DateTimeFilter };
31035
31038
  if (type.schema_type === "content-type") fields["slug"] = { type: StringFilter };
31036
- for (const f of type.fields) {
31039
+ const entries = viewFields !== void 0 ? viewFields.map((v) => ({ field: v.field, exposedAs: v.exposedAs })) : type.fields.filter((f) => f.removed !== true).map((f) => ({ field: f, exposedAs: f.name }));
31040
+ for (const { field: f, exposedAs } of entries) {
31037
31041
  if (f.field_type === "programmatic" || f.field_type === "paragraph") continue;
31038
31042
  if (f.field_type === "image" || f.field_type === "video" || f.field_type === "file") continue;
31039
31043
  const input = filterInputForField(f.field_type);
31040
- if (input) fields[buildFieldNameMap([f.name]).toGraphql(f.name)] = { type: input };
31044
+ if (input) fields[buildFieldNameMap([exposedAs]).toGraphql(exposedAs)] = { type: input };
31041
31045
  }
31042
31046
  if (Object.keys(fields).length === 0) return null;
31043
31047
  return new GraphQLInputObjectType({ name: `${graphqlTypeName(type.name)}Filter`, fields });
@@ -31070,32 +31074,41 @@ function codeError(code, message) {
31070
31074
  function isPublished(item) {
31071
31075
  return !!item && item["published"] === true;
31072
31076
  }
31073
- function resolveFieldValue(field, row) {
31077
+ function resolveFieldValue(field, row, fallback) {
31074
31078
  const key = isColumnBacked(field) ? field.db_column.column_name : field.name;
31075
- return row[key] ?? null;
31079
+ const value = row[key];
31080
+ if ((value === null || value === void 0) && fallback !== void 0) return fallback;
31081
+ return value ?? null;
31076
31082
  }
31077
- function scalarFieldResolver(field) {
31078
- return (parent) => resolveFieldValue(field, parent);
31083
+ function scalarFieldResolver(field, fallback) {
31084
+ return (parent) => resolveFieldValue(field, parent, fallback);
31079
31085
  }
31080
31086
  function relationFieldResolver(typeName, schemaFieldName) {
31081
31087
  return (parent, _args, ctx) => ctx.loaders.load(typeName, schemaFieldName, parent);
31082
31088
  }
31083
- function programmaticFieldResolver(typeName, schemaFieldName, mediaFieldNames = [], fieldKeys) {
31089
+ function programmaticFieldResolver(typeName, schemaFieldName, mediaFields = [], fieldKeys) {
31084
31090
  return async (parent, _args, ctx) => {
31085
31091
  let p = ctx.programmaticMemo.get(parent);
31086
31092
  if (!p) {
31087
- p = resolveProgrammaticRow(typeName, parent, ctx, mediaFieldNames, fieldKeys);
31093
+ p = resolveProgrammaticRow(typeName, parent, ctx, mediaFields, fieldKeys);
31088
31094
  ctx.programmaticMemo.set(parent, p);
31089
31095
  }
31090
31096
  return (await p)[schemaFieldName];
31091
31097
  };
31092
31098
  }
31093
- async function resolveProgrammaticRow(typeName, parent, ctx, mediaFieldNames, fieldKeys) {
31099
+ async function resolveProgrammaticRow(typeName, parent, ctx, mediaFields, fieldKeys) {
31094
31100
  const toLabels = (row) => fieldKeys ? fieldKeys.toLabels(row) : row;
31095
- if (mediaFieldNames.length === 0) return ctx.resolver.resolveItem(typeName, toLabels(parent));
31101
+ if (mediaFields.length === 0) return ctx.resolver.resolveItem(typeName, toLabels(parent));
31096
31102
  const enriched = { ...parent };
31097
- await Promise.all(mediaFieldNames.map((name) => ctx.loaders.load(typeName, name, enriched)));
31098
- return ctx.resolver.resolveItem(typeName, toLabels(enriched));
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;
31099
31112
  }
31100
31113
  function collectionResolver(typeName, nameMap, fieldKeys) {
31101
31114
  return async (_root, args, ctx) => {
@@ -31167,7 +31180,7 @@ var MEDIA = new GraphQLObjectType({
31167
31180
  duration: { type: GraphQLInt, resolve: (m) => m.duration }
31168
31181
  }
31169
31182
  });
31170
- function buildGraphQLSchema(registry, fieldKeyMaps = {}) {
31183
+ function buildGraphQLSchema(registry, fieldKeyMaps = {}, view) {
31171
31184
  const objectTypes = /* @__PURE__ */ new Map();
31172
31185
  const enumTypes = /* @__PURE__ */ new Map();
31173
31186
  for (const [name, enumType] of Object.entries(registry.enum_types)) {
@@ -31186,14 +31199,14 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}) {
31186
31199
  );
31187
31200
  }
31188
31201
  }
31189
- function outputTypeForField(field) {
31202
+ function outputTypeForField(field, required) {
31190
31203
  const scalar = scalarOutputType(field.field_type);
31191
- if (scalar) return field.required ? new GraphQLNonNull(scalar) : scalar;
31204
+ if (scalar) return required ? new GraphQLNonNull(scalar) : scalar;
31192
31205
  if (field.field_type === "enum") {
31193
31206
  const ref = field.ui_component.component === "select" ? field.ui_component.enum_ref : void 0;
31194
31207
  const et = ref ? enumTypes.get(ref) : void 0;
31195
31208
  const t = et ?? GraphQLString;
31196
- return field.required ? new GraphQLNonNull(t) : t;
31209
+ return required ? new GraphQLNonNull(t) : t;
31197
31210
  }
31198
31211
  if (field.field_type === "image" || field.field_type === "video" || field.field_type === "file") {
31199
31212
  return MEDIA;
@@ -31223,8 +31236,17 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}) {
31223
31236
  }
31224
31237
  return GraphQLString;
31225
31238
  }
31239
+ function exposedFields(type) {
31240
+ return type.fields.filter((f) => f.removed !== true);
31241
+ }
31242
+ function viewFieldsFor(machineName, type) {
31243
+ return view?.[machineName]?.fields ?? exposedFields(type).map((f) => ({ field: f, exposedAs: f.name, required: f.required }));
31244
+ }
31226
31245
  function buildObjectType(machineName, type) {
31227
- const mediaFieldNames = type.fields.filter((f) => f.field_type === "image" || f.field_type === "video" || f.field_type === "file").map((f) => f.name);
31246
+ 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 }));
31228
31250
  return new GraphQLObjectType({
31229
31251
  name: graphqlTypeName(machineName),
31230
31252
  fields: () => {
@@ -31238,23 +31260,25 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}) {
31238
31260
  }
31239
31261
  fields["createdAt"] = { type: new GraphQLNonNull(DateTimeScalar), resolve: (p) => p["created_at"] };
31240
31262
  fields["updatedAt"] = { type: new GraphQLNonNull(DateTimeScalar), resolve: (p) => p["updated_at"] };
31241
- for (const field of type.fields) {
31242
- const gqlName = toCamelCase(field.name);
31243
- const outType = outputTypeForField(field);
31263
+ for (const vf of visible) {
31264
+ const field = vf.field;
31265
+ const gqlName = toCamelCase(vf.exposedAs);
31266
+ const outType = outputTypeForField(field, vf.required);
31244
31267
  let resolve;
31245
31268
  if (field.field_type === "programmatic") {
31246
- resolve = programmaticFieldResolver(
31247
- machineName,
31248
- field.name,
31249
- mediaFieldNames,
31250
- fieldKeyMaps[machineName]
31251
- );
31269
+ resolve = programmaticFieldResolver(machineName, field.name, mediaFields, fieldKeyMaps[machineName]);
31252
31270
  } else if (field.field_type === "reference" || field.field_type === "paragraph" || field.field_type === "image" || field.field_type === "video" || field.field_type === "file") {
31253
31271
  resolve = relationFieldResolver(machineName, field.name);
31254
31272
  } else {
31255
- resolve = scalarFieldResolver(field);
31273
+ resolve = scalarFieldResolver(field, vf.fallback);
31256
31274
  }
31257
- fields[gqlName] = { type: outType, resolve };
31275
+ fields[gqlName] = {
31276
+ type: outType,
31277
+ resolve,
31278
+ // Conditional spread, not `deprecationReason: vf.deprecationReason`
31279
+ // — exactOptionalPropertyTypes forbids present-and-undefined.
31280
+ ...vf.deprecationReason !== void 0 && { deprecationReason: vf.deprecationReason }
31281
+ };
31258
31282
  }
31259
31283
  return fields;
31260
31284
  }
@@ -31286,7 +31310,8 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}) {
31286
31310
  const queryFields = {};
31287
31311
  for (const [name, ct] of Object.entries(registry.content_types)) {
31288
31312
  const objType = objectTypes.get(name);
31289
- const nameMap = buildFieldNameMap(ct.fields.map((f) => f.name));
31313
+ const visible = viewFieldsFor(name, ct);
31314
+ const nameMap = buildFieldNameMap(visible.map((v) => v.exposedAs));
31290
31315
  if (ct.only_one) {
31291
31316
  queryFields[singleQueryName(name)] = { type: objType, resolve: singletonResolver(name) };
31292
31317
  continue;
@@ -31298,13 +31323,13 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}) {
31298
31323
  meta: { type: new GraphQLNonNull(PAGE_META), resolve: (r) => r.meta }
31299
31324
  }
31300
31325
  });
31301
- const filterType = buildFilterInputType(ct);
31326
+ const filterType = buildFilterInputType(ct, visible);
31302
31327
  queryFields[collectionQueryName(name)] = {
31303
31328
  type: new GraphQLNonNull(listType),
31304
31329
  args: {
31305
31330
  page: { type: GraphQLInt },
31306
31331
  perPage: { type: GraphQLInt },
31307
- sortBy: { type: buildSortFieldEnum(graphqlTypeName(name)) },
31332
+ sortBy: { type: buildSortFieldEnum(graphqlTypeName(name), fieldKeyMaps[name]) },
31308
31333
  sortOrder: { type: SortOrderEnum },
31309
31334
  ...filterType ? { filter: { type: filterType } } : {}
31310
31335
  },
@@ -31328,7 +31353,11 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}) {
31328
31353
  queryFields[collectionQueryName(name)] = {
31329
31354
  type: new GraphQLNonNull(listType),
31330
31355
  args: { page: { type: GraphQLInt }, perPage: { type: GraphQLInt } },
31331
- resolve: collectionResolver(name, buildFieldNameMap(tt.fields.map((f) => f.name)), fieldKeyMaps[name])
31356
+ resolve: collectionResolver(
31357
+ name,
31358
+ buildFieldNameMap(viewFieldsFor(name, tt).map((v) => v.exposedAs)),
31359
+ fieldKeyMaps[name]
31360
+ )
31332
31361
  };
31333
31362
  queryFields[singleQueryName(name)] = {
31334
31363
  type: objType,
@@ -31340,6 +31369,68 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}) {
31340
31369
  query: new GraphQLObjectType({ name: "Query", fields: queryFields })
31341
31370
  });
31342
31371
  }
31372
+ function byColumn(fields) {
31373
+ const out = /* @__PURE__ */ new Map();
31374
+ for (const f of fields) {
31375
+ if (!isColumnBacked(f)) continue;
31376
+ out.set(f.db_column.column_name, f);
31377
+ }
31378
+ return out;
31379
+ }
31380
+ function deprecationFor(field, currentLabels, currentVersion) {
31381
+ const currentLabel = currentLabels.get(field.column_name);
31382
+ if (currentLabel === void 0) {
31383
+ return `Removed in ${currentVersion}; column retained while this version is live.`;
31384
+ }
31385
+ if (currentLabel !== field.exposed_as) {
31386
+ return `Renamed to '${currentLabel}' in ${currentVersion}.`;
31387
+ }
31388
+ return void 0;
31389
+ }
31390
+ function buildVersionView(input) {
31391
+ const { registry, projection, currentProjection, currentVersion } = input;
31392
+ const out = {};
31393
+ const sources = [
31394
+ registry.content_types,
31395
+ registry.taxonomy_types,
31396
+ registry.paragraph_types
31397
+ ];
31398
+ for (const source of sources) {
31399
+ for (const [typeName, type] of Object.entries(source)) {
31400
+ const projectionType = projection?.types[typeName];
31401
+ if (projectionType === void 0) {
31402
+ out[typeName] = {
31403
+ fields: type.fields.filter((f) => f.removed !== true).map((f) => ({ field: f, exposedAs: f.name, required: f.required }))
31404
+ };
31405
+ continue;
31406
+ }
31407
+ const columns = byColumn(type.fields);
31408
+ const currentLabels = /* @__PURE__ */ new Map();
31409
+ for (const f of currentProjection?.types[typeName]?.fields ?? []) {
31410
+ currentLabels.set(f.column_name, f.exposed_as);
31411
+ }
31412
+ const fields = [];
31413
+ for (const pf of projectionType.fields) {
31414
+ const field = columns.get(pf.column_name);
31415
+ if (field === void 0) continue;
31416
+ const reason = deprecationFor(pf, currentLabels, currentVersion);
31417
+ fields.push({
31418
+ field,
31419
+ exposedAs: pf.exposed_as,
31420
+ required: pf.required,
31421
+ ...pf.fallback !== void 0 && { fallback: pf.fallback },
31422
+ ...reason !== void 0 && { deprecationReason: reason }
31423
+ });
31424
+ }
31425
+ for (const f of type.fields) {
31426
+ if (isColumnBacked(f) || f.removed === true) continue;
31427
+ fields.push({ field: f, exposedAs: f.name, required: f.required });
31428
+ }
31429
+ out[typeName] = { fields };
31430
+ }
31431
+ }
31432
+ return out;
31433
+ }
31343
31434
  function createRelationLoaders(db, registry) {
31344
31435
  const relMaps = /* @__PURE__ */ new Map();
31345
31436
  const loaders = /* @__PURE__ */ new Map();
@@ -31407,15 +31498,29 @@ function isClientSafeGraphQLError(error) {
31407
31498
  }
31408
31499
  return false;
31409
31500
  }
31410
- function createGraphQLHandler(registry, repos, fieldKeyMaps, resolver, db, options) {
31411
- const schema = buildGraphQLSchema(registry, fieldKeyMaps);
31501
+ function createGraphQLHandler(registry, repos, fieldKeyMaps, resolver, db, options, versioning = {}) {
31502
+ let view;
31503
+ if (versioning.projection !== void 0) {
31504
+ if (versioning.currentVersion === void 0) {
31505
+ throw new Error(
31506
+ 'createGraphQLHandler: currentVersion is required when a projection is supplied \u2014 deprecation reasons name it, and an empty one ships "Removed in ." into published SDL.'
31507
+ );
31508
+ }
31509
+ view = buildVersionView({
31510
+ registry,
31511
+ projection: versioning.projection,
31512
+ currentProjection: versioning.currentProjection,
31513
+ currentVersion: versioning.currentVersion
31514
+ });
31515
+ }
31516
+ const schema = buildGraphQLSchema(registry, fieldKeyMaps, view);
31412
31517
  const { plugins } = buildArmorPlugin({
31413
31518
  maxDepth: options.maxDepth,
31414
31519
  maxComplexity: options.maxComplexity
31415
31520
  });
31416
31521
  const yoga = createYoga({
31417
31522
  schema,
31418
- graphqlEndpoint: "/graphql",
31523
+ graphqlEndpoint: versioning.endpoint ?? "/graphql",
31419
31524
  graphiql: options.graphiql,
31420
31525
  landingPage: false,
31421
31526
  maskedErrors: {