@bobbykim/manguito-cms-api 0.5.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.
@@ -2,7 +2,7 @@ import {
2
2
  buildRelationsMap,
3
3
  isColumnBacked,
4
4
  resolveRelationField
5
- } from "./chunk-D5AO4BTL.mjs";
5
+ } from "./chunk-FXPKGPYF.mjs";
6
6
 
7
7
  // src/graphql/handler.ts
8
8
  import { createYoga, maskError } from "graphql-yoga";
@@ -142,10 +142,13 @@ var SORTABLE = [
142
142
  { gql: "createdAt", value: "created_at" },
143
143
  { gql: "updatedAt", value: "updated_at" }
144
144
  ];
145
- function buildSortFieldEnum(typeName) {
145
+ function buildSortFieldEnum(typeName, fieldKeys) {
146
+ const resolvable = SORTABLE.filter(
147
+ (s) => s.gql === "createdAt" || s.gql === "updatedAt" || fieldKeys === void 0 || fieldKeys.columnFor(s.value) !== void 0
148
+ );
146
149
  return new GraphQLEnumType({
147
150
  name: `${typeName}SortField`,
148
- values: Object.fromEntries(SORTABLE.map((s) => [s.gql, { value: s.value }]))
151
+ values: Object.fromEntries(resolvable.map((s) => [s.gql, { value: s.value }]))
149
152
  });
150
153
  }
151
154
  function comparableFilterInput(name, scalar) {
@@ -189,18 +192,19 @@ function filterInputForField(fieldType) {
189
192
  if (scalar === null) return null;
190
193
  return StringFilter;
191
194
  }
192
- function buildFilterInputType(type) {
195
+ function buildFilterInputType(type, viewFields) {
193
196
  const fields = {};
194
197
  fields["id"] = { type: IDFilter };
195
198
  fields["published"] = { type: BooleanFilter };
196
199
  fields["createdAt"] = { type: DateTimeFilter };
197
200
  fields["updatedAt"] = { type: DateTimeFilter };
198
201
  if (type.schema_type === "content-type") fields["slug"] = { type: StringFilter };
199
- for (const f of type.fields) {
202
+ 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 }));
203
+ for (const { field: f, exposedAs } of entries) {
200
204
  if (f.field_type === "programmatic" || f.field_type === "paragraph") continue;
201
205
  if (f.field_type === "image" || f.field_type === "video" || f.field_type === "file") continue;
202
206
  const input = filterInputForField(f.field_type);
203
- if (input) fields[buildFieldNameMap([f.name]).toGraphql(f.name)] = { type: input };
207
+ if (input) fields[buildFieldNameMap([exposedAs]).toGraphql(exposedAs)] = { type: input };
204
208
  }
205
209
  if (Object.keys(fields).length === 0) return null;
206
210
  return new GraphQLInputObjectType({ name: `${graphqlTypeName(type.name)}Filter`, fields });
@@ -236,12 +240,14 @@ function codeError(code, message) {
236
240
  function isPublished(item) {
237
241
  return !!item && item["published"] === true;
238
242
  }
239
- function resolveFieldValue(field, row) {
243
+ function resolveFieldValue(field, row, fallback) {
240
244
  const key = isColumnBacked(field) ? field.db_column.column_name : field.name;
241
- return row[key] ?? null;
245
+ const value = row[key];
246
+ if ((value === null || value === void 0) && fallback !== void 0) return fallback;
247
+ return value ?? null;
242
248
  }
243
- function scalarFieldResolver(field) {
244
- return (parent) => resolveFieldValue(field, parent);
249
+ function scalarFieldResolver(field, fallback) {
250
+ return (parent) => resolveFieldValue(field, parent, fallback);
245
251
  }
246
252
  function relationFieldResolver(typeName, schemaFieldName) {
247
253
  return (parent, _args, ctx) => ctx.loaders.load(typeName, schemaFieldName, parent);
@@ -335,7 +341,7 @@ var MEDIA = new GraphQLObjectType({
335
341
  duration: { type: GraphQLInt3, resolve: (m) => m.duration }
336
342
  }
337
343
  });
338
- function buildGraphQLSchema(registry, fieldKeyMaps = {}) {
344
+ function buildGraphQLSchema(registry, fieldKeyMaps = {}, view, programmaticKeyMaps = fieldKeyMaps) {
339
345
  const objectTypes = /* @__PURE__ */ new Map();
340
346
  const enumTypes = /* @__PURE__ */ new Map();
341
347
  for (const [name, enumType] of Object.entries(registry.enum_types)) {
@@ -354,14 +360,14 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}) {
354
360
  );
355
361
  }
356
362
  }
357
- function outputTypeForField(field) {
363
+ function outputTypeForField(field, required) {
358
364
  const scalar = scalarOutputType(field.field_type);
359
- if (scalar) return field.required ? new GraphQLNonNull2(scalar) : scalar;
365
+ if (scalar) return required ? new GraphQLNonNull2(scalar) : scalar;
360
366
  if (field.field_type === "enum") {
361
367
  const ref = field.ui_component.component === "select" ? field.ui_component.enum_ref : void 0;
362
368
  const et = ref ? enumTypes.get(ref) : void 0;
363
369
  const t = et ?? GraphQLString3;
364
- return field.required ? new GraphQLNonNull2(t) : t;
370
+ return required ? new GraphQLNonNull2(t) : t;
365
371
  }
366
372
  if (field.field_type === "image" || field.field_type === "video" || field.field_type === "file") {
367
373
  return MEDIA;
@@ -391,8 +397,17 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}) {
391
397
  }
392
398
  return GraphQLString3;
393
399
  }
400
+ function exposedFields(type) {
401
+ return type.fields.filter((f) => f.removed !== true);
402
+ }
403
+ function viewFieldsFor(machineName, type) {
404
+ return view?.[machineName]?.fields ?? exposedFields(type).map((f) => ({ field: f, exposedAs: f.name, required: f.required }));
405
+ }
394
406
  function buildObjectType(machineName, type) {
395
- const mediaFieldNames = type.fields.filter((f) => f.field_type === "image" || f.field_type === "video" || f.field_type === "file").map((f) => f.name);
407
+ const visible = viewFieldsFor(machineName, type);
408
+ const mediaFieldNames = type.fields.filter(
409
+ (f) => f.removed !== true && (f.field_type === "image" || f.field_type === "video" || f.field_type === "file")
410
+ ).map((f) => f.name);
396
411
  return new GraphQLObjectType({
397
412
  name: graphqlTypeName(machineName),
398
413
  fields: () => {
@@ -406,23 +421,25 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}) {
406
421
  }
407
422
  fields["createdAt"] = { type: new GraphQLNonNull2(DateTimeScalar), resolve: (p) => p["created_at"] };
408
423
  fields["updatedAt"] = { type: new GraphQLNonNull2(DateTimeScalar), resolve: (p) => p["updated_at"] };
409
- for (const field of type.fields) {
410
- const gqlName = toCamelCase(field.name);
411
- const outType = outputTypeForField(field);
424
+ for (const vf of visible) {
425
+ const field = vf.field;
426
+ const gqlName = toCamelCase(vf.exposedAs);
427
+ const outType = outputTypeForField(field, vf.required);
412
428
  let resolve;
413
429
  if (field.field_type === "programmatic") {
414
- resolve = programmaticFieldResolver(
415
- machineName,
416
- field.name,
417
- mediaFieldNames,
418
- fieldKeyMaps[machineName]
419
- );
430
+ resolve = programmaticFieldResolver(machineName, field.name, mediaFieldNames, programmaticKeyMaps[machineName]);
420
431
  } else if (field.field_type === "reference" || field.field_type === "paragraph" || field.field_type === "image" || field.field_type === "video" || field.field_type === "file") {
421
432
  resolve = relationFieldResolver(machineName, field.name);
422
433
  } else {
423
- resolve = scalarFieldResolver(field);
434
+ resolve = scalarFieldResolver(field, vf.fallback);
424
435
  }
425
- fields[gqlName] = { type: outType, resolve };
436
+ fields[gqlName] = {
437
+ type: outType,
438
+ resolve,
439
+ // Conditional spread, not `deprecationReason: vf.deprecationReason`
440
+ // — exactOptionalPropertyTypes forbids present-and-undefined.
441
+ ...vf.deprecationReason !== void 0 && { deprecationReason: vf.deprecationReason }
442
+ };
426
443
  }
427
444
  return fields;
428
445
  }
@@ -454,7 +471,11 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}) {
454
471
  const queryFields = {};
455
472
  for (const [name, ct] of Object.entries(registry.content_types)) {
456
473
  const objType = objectTypes.get(name);
457
- const nameMap = buildFieldNameMap(ct.fields.map((f) => f.name));
474
+ const visible = viewFieldsFor(name, ct);
475
+ const nameMap = buildFieldNameMap([
476
+ ...visible.map((v) => v.exposedAs),
477
+ ...ct.system_fields.map((s) => s.name)
478
+ ]);
458
479
  if (ct.only_one) {
459
480
  queryFields[singleQueryName(name)] = { type: objType, resolve: singletonResolver(name) };
460
481
  continue;
@@ -466,13 +487,13 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}) {
466
487
  meta: { type: new GraphQLNonNull2(PAGE_META), resolve: (r) => r.meta }
467
488
  }
468
489
  });
469
- const filterType = buildFilterInputType(ct);
490
+ const filterType = buildFilterInputType(ct, visible);
470
491
  queryFields[collectionQueryName(name)] = {
471
492
  type: new GraphQLNonNull2(listType),
472
493
  args: {
473
494
  page: { type: GraphQLInt3 },
474
495
  perPage: { type: GraphQLInt3 },
475
- sortBy: { type: buildSortFieldEnum(graphqlTypeName(name)) },
496
+ sortBy: { type: buildSortFieldEnum(graphqlTypeName(name), fieldKeyMaps[name]) },
476
497
  sortOrder: { type: SortOrderEnum },
477
498
  ...filterType ? { filter: { type: filterType } } : {}
478
499
  },
@@ -496,7 +517,11 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}) {
496
517
  queryFields[collectionQueryName(name)] = {
497
518
  type: new GraphQLNonNull2(listType),
498
519
  args: { page: { type: GraphQLInt3 }, perPage: { type: GraphQLInt3 } },
499
- resolve: collectionResolver(name, buildFieldNameMap(tt.fields.map((f) => f.name)), fieldKeyMaps[name])
520
+ resolve: collectionResolver(
521
+ name,
522
+ buildFieldNameMap(viewFieldsFor(name, tt).map((v) => v.exposedAs)),
523
+ fieldKeyMaps[name]
524
+ )
500
525
  };
501
526
  queryFields[singleQueryName(name)] = {
502
527
  type: objType,
@@ -509,6 +534,70 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}) {
509
534
  });
510
535
  }
511
536
 
537
+ // src/graphql/version-view.ts
538
+ function byColumn(fields) {
539
+ const out = /* @__PURE__ */ new Map();
540
+ for (const f of fields) {
541
+ if (!isColumnBacked(f)) continue;
542
+ out.set(f.db_column.column_name, f);
543
+ }
544
+ return out;
545
+ }
546
+ function deprecationFor(field, currentLabels, currentVersion) {
547
+ const currentLabel = currentLabels.get(field.column_name);
548
+ if (currentLabel === void 0) {
549
+ return `Removed in ${currentVersion}; column retained while this version is live.`;
550
+ }
551
+ if (currentLabel !== field.exposed_as) {
552
+ return `Renamed to '${currentLabel}' in ${currentVersion}.`;
553
+ }
554
+ return void 0;
555
+ }
556
+ function buildVersionView(input) {
557
+ const { registry, projection, currentProjection, currentVersion } = input;
558
+ const out = {};
559
+ const sources = [
560
+ registry.content_types,
561
+ registry.taxonomy_types,
562
+ registry.paragraph_types
563
+ ];
564
+ for (const source of sources) {
565
+ for (const [typeName, type] of Object.entries(source)) {
566
+ const projectionType = projection?.types[typeName];
567
+ if (projectionType === void 0) {
568
+ out[typeName] = {
569
+ fields: type.fields.filter((f) => f.removed !== true).map((f) => ({ field: f, exposedAs: f.name, required: f.required }))
570
+ };
571
+ continue;
572
+ }
573
+ const columns = byColumn(type.fields);
574
+ const currentLabels = /* @__PURE__ */ new Map();
575
+ for (const f of currentProjection?.types[typeName]?.fields ?? []) {
576
+ currentLabels.set(f.column_name, f.exposed_as);
577
+ }
578
+ const fields = [];
579
+ for (const pf of projectionType.fields) {
580
+ const field = columns.get(pf.column_name);
581
+ if (field === void 0) continue;
582
+ const reason = deprecationFor(pf, currentLabels, currentVersion);
583
+ fields.push({
584
+ field,
585
+ exposedAs: pf.exposed_as,
586
+ required: pf.required,
587
+ ...pf.fallback !== void 0 && { fallback: pf.fallback },
588
+ ...reason !== void 0 && { deprecationReason: reason }
589
+ });
590
+ }
591
+ for (const f of type.fields) {
592
+ if (isColumnBacked(f) || f.removed === true) continue;
593
+ fields.push({ field: f, exposedAs: f.name, required: f.required });
594
+ }
595
+ out[typeName] = { fields };
596
+ }
597
+ }
598
+ return out;
599
+ }
600
+
512
601
  // src/graphql/dataloaders.ts
513
602
  import DataLoader from "dataloader";
514
603
  function createRelationLoaders(db, registry) {
@@ -532,7 +621,8 @@ function createRelationLoaders(db, registry) {
532
621
  async (parents) => {
533
622
  const rows = parents;
534
623
  await resolveRelationField(db, rows, fieldName, rel, cache, true);
535
- return rows.map((r) => r[fieldName]);
624
+ const resultKey = rel.type === "reference" || rel.type === "media" ? rel.fk_column : fieldName;
625
+ return rows.map((r) => r[resultKey]);
536
626
  },
537
627
  // Batch within a tick; do not memoize by parent identity (rows are mutated
538
628
  // and may recur across nesting levels).
@@ -584,15 +674,29 @@ function isClientSafeGraphQLError(error) {
584
674
  }
585
675
  return false;
586
676
  }
587
- function createGraphQLHandler(registry, repos, fieldKeyMaps, resolver, db, options) {
588
- const schema = buildGraphQLSchema(registry, fieldKeyMaps);
677
+ function createGraphQLHandler(registry, repos, fieldKeyMaps, resolver, db, options, versioning = {}) {
678
+ let view;
679
+ if (versioning.projection !== void 0) {
680
+ if (versioning.currentVersion === void 0) {
681
+ throw new Error(
682
+ 'createGraphQLHandler: currentVersion is required when a projection is supplied \u2014 deprecation reasons name it, and an empty one ships "Removed in ." into published SDL.'
683
+ );
684
+ }
685
+ view = buildVersionView({
686
+ registry,
687
+ projection: versioning.projection,
688
+ currentProjection: versioning.currentProjection,
689
+ currentVersion: versioning.currentVersion
690
+ });
691
+ }
692
+ const schema = buildGraphQLSchema(registry, fieldKeyMaps, view, versioning.currentFieldKeyMaps ?? fieldKeyMaps);
589
693
  const { plugins } = buildArmorPlugin({
590
694
  maxDepth: options.maxDepth,
591
695
  maxComplexity: options.maxComplexity
592
696
  });
593
697
  const yoga = createYoga({
594
698
  schema,
595
- graphqlEndpoint: "/graphql",
699
+ graphqlEndpoint: versioning.endpoint ?? "/graphql",
596
700
  graphiql: options.graphiql,
597
701
  landingPage: false,
598
702
  maskedErrors: {
@@ -618,4 +722,4 @@ function createGraphQLHandler(registry, repos, fieldKeyMaps, resolver, db, optio
618
722
  export {
619
723
  createGraphQLHandler
620
724
  };
621
- //# sourceMappingURL=chunk-ARZXLNZS.mjs.map
725
+ //# sourceMappingURL=chunk-4LLELFAZ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/graphql/handler.ts","../src/graphql/schema.ts","../src/graphql/scalars.ts","../src/graphql/type-mapping.ts","../src/graphql/naming.ts","../src/graphql/filters.ts","../src/graphql/resolvers.ts","../src/graphql/version-view.ts","../src/graphql/dataloaders.ts","../src/graphql/security.ts"],"sourcesContent":["import { createYoga, maskError } from 'graphql-yoga'\nimport type { Handler } from 'hono'\nimport type { SchemaRegistry, ContentRepository, VersionProjection } from '@bobbykim/manguito-cms-core'\nimport type { DrizzlePostgresInstance } from '@bobbykim/manguito-cms-db'\nimport type { ProgrammaticResolver } from '../programmatic/resolve.js'\nimport type { FieldKeyMap } from '../field-keys.js'\nimport type { GraphQLContext } from './context.js'\nimport { buildGraphQLSchema } from './schema.js'\nimport { buildVersionView, type VersionView } from './version-view.js'\nimport { createRelationLoaders } from './dataloaders.js'\nimport { buildArmorPlugin, introspectionPlugin } from './security.js'\n\nexport type ResolvedGraphQLOptions = {\n enabled: boolean\n maxDepth: number\n maxComplexity: number\n graphiql: boolean\n introspection: boolean\n}\n\n// Yoga decides whether an error is safe to show a client with\n// `error instanceof GraphQLError`. That check is realm-sensitive: GraphQL Armor\n// is CJS and throws a GraphQLError built from graphql's CJS entry, while Yoga is\n// ESM and compares against the class from graphql's ESM entry. Same version, two\n// classes — so `instanceof` fails and a depth/complexity rejection, which is the\n// client's own query being too large, was masked as\n// `INTERNAL_SERVER_ERROR: Unexpected error.` and logged server-side as a fault.\n//\n// Identify by name instead (what envelop's own masking does), walking the\n// originalError chain the same way. A GraphQLError with no originalError was\n// constructed deliberately by a validation rule or by us and carries no internals;\n// anything else — a resolver throwing, a driver error — still goes to Yoga's\n// masking untouched, dev-mode originalError detail included.\nfunction isClientSafeGraphQLError(error: unknown): boolean {\n let current = error as { name?: string; originalError?: unknown } | null | undefined\n while (current != null && typeof current === 'object' && current.name === 'GraphQLError') {\n if (current.originalError == null) return true\n current = current.originalError as typeof current\n }\n return false\n}\n\nexport function createGraphQLHandler(\n registry: SchemaRegistry,\n repos: Record<string, ContentRepository<unknown>>,\n fieldKeyMaps: Record<string, FieldKeyMap>,\n resolver: ProgrammaticResolver,\n db: DrizzlePostgresInstance,\n options: ResolvedGraphQLOptions,\n // The view is built HERE, not in app.ts: the `.` entry must keep no static\n // import of anything under graphql/ (ADR api/0006), so app.ts passes the\n // plain projection data it already imports as types from core.\n versioning: {\n endpoint?: string\n projection?: VersionProjection\n currentProjection?: VersionProjection\n currentVersion?: string\n // Current's field-key maps. A programmatic resolver reads its record in\n // current's labels on every version; omitted, it reads `fieldKeyMaps`.\n currentFieldKeyMaps?: Record<string, FieldKeyMap>\n } = {}\n): Handler {\n let view: VersionView | undefined\n if (versioning.projection !== undefined) {\n if (versioning.currentVersion === undefined) {\n throw new Error(\n 'createGraphQLHandler: currentVersion is required when a projection is supplied — ' +\n 'deprecation reasons name it, and an empty one ships \"Removed in .\" into published SDL.'\n )\n }\n view = buildVersionView({\n registry,\n projection: versioning.projection,\n currentProjection: versioning.currentProjection,\n currentVersion: versioning.currentVersion,\n })\n }\n const schema = buildGraphQLSchema(registry, fieldKeyMaps, view, versioning.currentFieldKeyMaps ?? fieldKeyMaps)\n const { plugins } = buildArmorPlugin({\n maxDepth: options.maxDepth,\n maxComplexity: options.maxComplexity,\n })\n\n const yoga = createYoga<Record<string, never>, GraphQLContext>({\n schema,\n graphqlEndpoint: versioning.endpoint ?? '/graphql',\n graphiql: options.graphiql,\n landingPage: false,\n maskedErrors: {\n maskError: (error, message, isDev) =>\n isClientSafeGraphQLError(error) ? (error as Error) : maskError(error, message, isDev),\n },\n // buildArmorPlugin's return type is `unknown[]` (see security.ts) since Armor's\n // plugin shapes aren't part of its public typings; Yoga's `plugins` option only\n // accepts its own `Plugin` type, so the cast bridges the two.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n plugins: [...(plugins as any[]), introspectionPlugin(options.introspection)],\n context: (): GraphQLContext => ({\n db,\n registry,\n repos,\n resolver,\n loaders: createRelationLoaders(db, registry),\n programmaticMemo: new WeakMap(),\n }),\n })\n\n return (c) => yoga.fetch(c.req.raw, {})\n}\n","import {\n GraphQLSchema,\n GraphQLObjectType,\n GraphQLEnumType,\n GraphQLNonNull,\n GraphQLList,\n GraphQLID,\n GraphQLString,\n GraphQLInt,\n GraphQLBoolean,\n type GraphQLFieldConfig,\n type GraphQLOutputType,\n type GraphQLFieldConfigMap,\n} from 'graphql'\nimport type {\n SchemaRegistry,\n ParsedContentType,\n ParsedTaxonomyType,\n ParsedParagraphType,\n ParsedField,\n ParsedEnumType,\n} from '@bobbykim/manguito-cms-core'\nimport type { GraphQLContext } from './context.js'\nimport type { FieldKeyMap } from '../field-keys.js'\nimport type { VersionView, ViewField } from './version-view.js'\nimport { DateTimeScalar } from './scalars.js'\nimport { scalarOutputType } from './type-mapping.js'\nimport {\n graphqlTypeName,\n singleQueryName,\n collectionQueryName,\n toCamelCase,\n isValidGraphQLName,\n buildFieldNameMap,\n} from './naming.js'\nimport { SortOrderEnum, buildSortFieldEnum, buildFilterInputType } from './filters.js'\nimport {\n scalarFieldResolver,\n relationFieldResolver,\n programmaticFieldResolver,\n collectionResolver,\n singleBySlugResolver,\n singletonResolver,\n taxonomySingleResolver,\n} from './resolvers.js'\n\nconst PAGE_META = new GraphQLObjectType({\n name: 'PageMeta',\n fields: {\n total: { type: new GraphQLNonNull(GraphQLInt), resolve: (m) => m.total },\n page: { type: new GraphQLNonNull(GraphQLInt), resolve: (m) => m.page },\n perPage: { type: new GraphQLNonNull(GraphQLInt), resolve: (m) => m.per_page },\n totalPages: { type: new GraphQLNonNull(GraphQLInt), resolve: (m) => m.total_pages },\n hasNext: { type: new GraphQLNonNull(GraphQLBoolean), resolve: (m) => m.has_next },\n hasPrev: { type: new GraphQLNonNull(GraphQLBoolean), resolve: (m) => m.has_prev },\n },\n})\n\nconst MEDIA = new GraphQLObjectType({\n name: 'Media',\n fields: {\n id: { type: new GraphQLNonNull(GraphQLID), resolve: (m) => m.id },\n type: { type: new GraphQLNonNull(GraphQLString), resolve: (m) => m.type },\n url: { type: new GraphQLNonNull(GraphQLString), resolve: (m) => m.url },\n mimeType: { type: new GraphQLNonNull(GraphQLString), resolve: (m) => m.mime_type },\n alt: { type: GraphQLString, resolve: (m) => m.alt },\n fileSize: { type: GraphQLInt, resolve: (m) => m.file_size },\n width: { type: GraphQLInt, resolve: (m) => m.width },\n height: { type: GraphQLInt, resolve: (m) => m.height },\n duration: { type: GraphQLInt, resolve: (m) => m.duration },\n },\n})\n\nexport function buildGraphQLSchema(\n registry: SchemaRegistry,\n fieldKeyMaps: Record<string, FieldKeyMap> = {},\n view?: VersionView,\n // The maps a programmatic resolver's record is built with: current's, on\n // every version. Defaults to `fieldKeyMaps`, which is right when they ARE\n // current's (no view, or the current version's own endpoint).\n programmaticKeyMaps: Record<string, FieldKeyMap> = fieldKeyMaps\n): GraphQLSchema {\n const objectTypes = new Map<string, GraphQLObjectType>() // machineName → type\n const enumTypes = new Map<string, GraphQLEnumType>() // enum machineName → type (only when valid)\n\n // Enum types (only when every value is a valid GraphQL identifier).\n for (const [name, enumType] of Object.entries(registry.enum_types) as [string, ParsedEnumType][]) {\n if (enumType.values.every(isValidGraphQLName)) {\n enumTypes.set(\n name,\n new GraphQLEnumType({\n name: graphqlTypeName(name),\n values: Object.fromEntries(enumType.values.map((v) => [v, { value: v }])),\n })\n )\n } else {\n process.stderr.write(\n `⚠ enum '${name}' has values that aren't valid GraphQL identifiers; exposing as String\\n`\n )\n }\n }\n\n // Output type for one field (scalar, enum, relation, media, programmatic).\n function outputTypeForField(field: ParsedField, required: boolean): GraphQLOutputType {\n const scalar = scalarOutputType(field.field_type)\n if (scalar) return required ? new GraphQLNonNull(scalar) : scalar\n\n if (field.field_type === 'enum') {\n const ref = field.ui_component.component === 'select' ? field.ui_component.enum_ref : undefined\n const et = ref ? enumTypes.get(ref) : undefined\n const t = et ?? GraphQLString\n return required ? new GraphQLNonNull(t) : t\n }\n\n if (field.field_type === 'image' || field.field_type === 'video' || field.field_type === 'file') {\n return MEDIA\n }\n\n if (field.field_type === 'paragraph') {\n const ref = field.ui_component.component === 'paragraph-embed' ? field.ui_component.ref : undefined\n const target = ref ? objectTypes.get(ref) : undefined\n if (ref && !target) {\n process.stderr.write(\n `⚠ paragraph field '${field.name}' targets unknown paragraph type '${ref}'; exposing as Media\\n`\n )\n }\n return new GraphQLList(new GraphQLNonNull(target ?? MEDIA))\n }\n\n if (field.field_type === 'reference') {\n const ref = field.ui_component.component === 'typeahead-select' ? field.ui_component.ref : undefined\n const target = ref ? objectTypes.get(ref) : undefined\n if (ref && !target) {\n process.stderr.write(`⚠ reference field '${field.name}' targets unknown type '${ref}'; exposing as Media\\n`)\n }\n const rel = field.ui_component.component === 'typeahead-select' ? field.ui_component.rel : undefined\n const isMany = rel === 'many-to-many' || rel === 'one-to-many'\n const t = (target ?? MEDIA) as GraphQLObjectType\n return isMany ? new GraphQLList(new GraphQLNonNull(t)) : t\n }\n\n return GraphQLString\n }\n\n /**\n * A type's fields minus its tombstones.\n *\n * A tombstone (`removed: true`) is column-backed — the parser keeps its\n * column alive for older live versions — but the version being served must\n * never expose it. REST drops it via the FieldKeyMap's drop-set, which\n * `remap` applies; GraphQL resolves per field by column through\n * `resolveFieldValue` and never touches that map, so the exclusion has to\n * happen where the schema is BUILT. A field absent from the schema is a\n * validation error, so the retained value cannot reach a response at all.\n */\n function exposedFields(type: { fields: ParsedField[] }): ParsedField[] {\n return type.fields.filter((f) => f.removed !== true)\n }\n\n /**\n * The fields one schema exposes for a type, as ViewFields. With a view, the\n * served version's own list; without one, the registry's minus tombstones.\n */\n function viewFieldsFor(machineName: string, type: { fields: ParsedField[] }): ViewField[] {\n return (\n view?.[machineName]?.fields ??\n exposedFields(type).map((f) => ({ field: f, exposedAs: f.name, required: f.required }))\n )\n }\n\n // Build the object type for a content/taxonomy/paragraph type. Fields are a\n // thunk so relations can reference types created later (circular graphs).\n function buildObjectType(\n machineName: string,\n type: ParsedContentType | ParsedTaxonomyType | ParsedParagraphType\n ): GraphQLObjectType {\n const visible = viewFieldsFor(machineName, type)\n\n // Every live media field the type has NOW, by registry name. That is the\n // key ctx.loaders.load looks a field up by. The set is current's, not this\n // version's visible one: the programmatic record speaks current's labels,\n // and REST resolves every media field in the registry for it too.\n // Tombstones are excluded; current's map drops their column regardless.\n const mediaFieldNames = type.fields\n .filter(\n (f) =>\n f.removed !== true &&\n (f.field_type === 'image' || f.field_type === 'video' || f.field_type === 'file')\n )\n .map((f) => f.name)\n\n return new GraphQLObjectType({\n name: graphqlTypeName(machineName),\n fields: () => {\n const fields: GraphQLFieldConfigMap<Record<string, unknown>, GraphQLContext> = {}\n // System fields.\n fields['id'] = { type: new GraphQLNonNull(GraphQLID), resolve: (p) => p['id'] }\n if (type.schema_type !== 'paragraph-type') {\n fields['published'] = { type: new GraphQLNonNull(GraphQLBoolean), resolve: (p) => p['published'] }\n }\n if (type.schema_type === 'content-type') {\n fields['slug'] = { type: new GraphQLNonNull(GraphQLString), resolve: (p) => p['slug'] }\n }\n fields['createdAt'] = { type: new GraphQLNonNull(DateTimeScalar), resolve: (p) => p['created_at'] }\n fields['updatedAt'] = { type: new GraphQLNonNull(DateTimeScalar), resolve: (p) => p['updated_at'] }\n\n for (const vf of visible) {\n const field = vf.field\n const gqlName = toCamelCase(vf.exposedAs)\n const outType = outputTypeForField(field, vf.required)\n let resolve: GraphQLFieldConfig<Record<string, unknown>, GraphQLContext>['resolve']\n if (field.field_type === 'programmatic') {\n resolve = programmaticFieldResolver(machineName, field.name, mediaFieldNames, programmaticKeyMaps[machineName])\n } else if (\n field.field_type === 'reference' ||\n field.field_type === 'paragraph' ||\n field.field_type === 'image' ||\n field.field_type === 'video' ||\n field.field_type === 'file'\n ) {\n resolve = relationFieldResolver(machineName, field.name)\n } else {\n resolve = scalarFieldResolver(field, vf.fallback)\n }\n fields[gqlName] = {\n type: outType,\n resolve,\n // Conditional spread, not `deprecationReason: vf.deprecationReason`\n // — exactOptionalPropertyTypes forbids present-and-undefined.\n ...(vf.deprecationReason !== undefined && { deprecationReason: vf.deprecationReason }),\n }\n }\n return fields\n },\n })\n }\n\n // Pass 1: create every object type (empty-safe thunks resolve later).\n // Track GraphQL type name → machine name so two schemas that collapse to the\n // same GraphQL type name (e.g. content--author / taxonomy--author both → \"Author\")\n // fail loud here instead of surfacing as a cryptic GraphQLSchema build error.\n const typeNameOwners = new Map<string, string>() // graphqlTypeName → machineName\n function registerTypeName(machineName: string): void {\n const gqlName = graphqlTypeName(machineName)\n const owner = typeNameOwners.get(gqlName)\n if (owner !== undefined && owner !== machineName) {\n throw new Error(\n `GraphQL type name collision: '${gqlName}' is produced by both '${owner}' and '${machineName}'. ` +\n `Rename one schema's machine name segment so their GraphQL type names differ.`\n )\n }\n typeNameOwners.set(gqlName, machineName)\n }\n\n for (const [name, ct] of Object.entries(registry.content_types)) {\n registerTypeName(name)\n objectTypes.set(name, buildObjectType(name, ct))\n }\n for (const [name, tt] of Object.entries(registry.taxonomy_types)) {\n registerTypeName(name)\n objectTypes.set(name, buildObjectType(name, tt))\n }\n for (const [name, pt] of Object.entries(registry.paragraph_types)) {\n registerTypeName(name)\n objectTypes.set(name, buildObjectType(name, pt))\n }\n\n // Pass 2: build the root Query type.\n const queryFields: GraphQLFieldConfigMap<unknown, GraphQLContext> = {}\n\n for (const [name, ct] of Object.entries(registry.content_types) as [string, ParsedContentType][]) {\n const objType = objectTypes.get(name)!\n const visible = viewFieldsFor(name, ct)\n // The version's own labels: translateFilters maps a GraphQL name back to a\n // label, and columnFor then takes that label to the storage column. System\n // fields go in too, because buildFilterInputType advertises createdAt and\n // updatedAt on every filter. Without them `createdAt` would fall through as\n // its own column name. columnFor returns nothing for a system field, so\n // translateFilters falls back to the name itself, which IS its column.\n const nameMap = buildFieldNameMap([\n ...visible.map((v) => v.exposedAs),\n ...ct.system_fields.map((s) => s.name),\n ])\n\n if (ct.only_one) {\n queryFields[singleQueryName(name)] = { type: objType, resolve: singletonResolver(name) }\n continue\n }\n\n const listType = new GraphQLObjectType({\n name: `${graphqlTypeName(name)}List`,\n fields: {\n data: { type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(objType))), resolve: (r) => r.data },\n meta: { type: new GraphQLNonNull(PAGE_META), resolve: (r) => r.meta },\n },\n })\n const filterType = buildFilterInputType(ct, visible)\n\n queryFields[collectionQueryName(name)] = {\n type: new GraphQLNonNull(listType),\n args: {\n page: { type: GraphQLInt },\n perPage: { type: GraphQLInt },\n sortBy: { type: buildSortFieldEnum(graphqlTypeName(name), fieldKeyMaps[name]) },\n sortOrder: { type: SortOrderEnum },\n ...(filterType ? { filter: { type: filterType } } : {}),\n },\n resolve: collectionResolver(name, nameMap, fieldKeyMaps[name]),\n }\n queryFields[singleQueryName(name)] = {\n type: objType,\n args: { slug: { type: new GraphQLNonNull(GraphQLString) } },\n resolve: singleBySlugResolver(name),\n }\n }\n\n for (const [name, tt] of Object.entries(registry.taxonomy_types) as [string, ParsedTaxonomyType][]) {\n const objType = objectTypes.get(name)!\n const listType = new GraphQLObjectType({\n name: `${graphqlTypeName(name)}List`,\n fields: {\n data: { type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(objType))), resolve: (r) => r.data },\n meta: { type: new GraphQLNonNull(PAGE_META), resolve: (r) => r.meta },\n },\n })\n queryFields[collectionQueryName(name)] = {\n type: new GraphQLNonNull(listType),\n args: { page: { type: GraphQLInt }, perPage: { type: GraphQLInt } },\n resolve: collectionResolver(\n name,\n buildFieldNameMap(viewFieldsFor(name, tt).map((v) => v.exposedAs)),\n fieldKeyMaps[name]\n ),\n }\n queryFields[singleQueryName(name)] = {\n type: objType,\n args: { id: { type: new GraphQLNonNull(GraphQLID) } },\n resolve: taxonomySingleResolver(name),\n }\n }\n\n return new GraphQLSchema({\n query: new GraphQLObjectType({ name: 'Query', fields: queryFields }),\n })\n}\n","import { GraphQLScalarType, Kind, valueFromASTUntyped } from 'graphql'\n\nexport const DateTimeScalar = new GraphQLScalarType({\n name: 'DateTime',\n description: 'ISO-8601 date-time string',\n serialize(value) {\n if (value instanceof Date) return value.toISOString()\n if (typeof value === 'string') return value\n if (typeof value === 'number') return new Date(value).toISOString()\n throw new TypeError(`DateTime cannot serialize value: ${String(value)}`)\n },\n parseValue(value) {\n if (typeof value !== 'string') throw new TypeError('DateTime must be a string')\n return value\n },\n parseLiteral(ast) {\n if (ast.kind !== Kind.STRING) throw new TypeError('DateTime must be a string')\n return ast.value\n },\n})\n\nexport const JSONScalar = new GraphQLScalarType({\n name: 'JSON',\n description: 'Arbitrary JSON value',\n serialize: (value) => value,\n parseValue: (value) => value,\n parseLiteral: (ast, variables) => valueFromASTUntyped(ast, variables ?? undefined),\n})\n","import {\n GraphQLString,\n GraphQLInt,\n GraphQLFloat,\n GraphQLBoolean,\n type GraphQLScalarType,\n} from 'graphql'\nimport type { FieldType } from '@bobbykim/manguito-cms-core'\nimport { DateTimeScalar, JSONScalar } from './scalars.js'\n\n// Scalar output type for a field. Relation/enum fields return null — schema.ts\n// resolves those against its type caches.\nexport function scalarOutputType(fieldType: FieldType): GraphQLScalarType | null {\n switch (fieldType) {\n case 'text/plain':\n case 'text/rich':\n return GraphQLString\n case 'integer':\n return GraphQLInt\n case 'float':\n return GraphQLFloat\n case 'boolean':\n return GraphQLBoolean\n case 'date':\n return DateTimeScalar\n case 'programmatic':\n return JSONScalar\n default:\n return null\n }\n}\n","// \"content--blog_post\" → \"blog_post\"; \"category\" → \"category\"\nexport function schemaSegment(machineName: string): string {\n const idx = machineName.indexOf('--')\n return idx === -1 ? machineName : machineName.slice(idx + 2)\n}\n\nfunction words(input: string): string[] {\n return input.split(/[_\\s-]+/).filter(Boolean)\n}\n\nexport function toPascalCase(input: string): string {\n return words(input)\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join('')\n}\n\nexport function toCamelCase(input: string): string {\n const pascal = toPascalCase(input)\n return pascal.charAt(0).toLowerCase() + pascal.slice(1)\n}\n\n// Deterministic English pluralization for the common cases; irregular plurals\n// (person→people) are a known limitation — an optional per-type override can be\n// added later if one is wrong.\nexport function pluralize(word: string): string {\n if (/[^aeiou]y$/.test(word)) return word.slice(0, -1) + 'ies'\n if (/(s|x|z|ch|sh)$/.test(word)) return word + 'es'\n return word + 's'\n}\n\nconst GRAPHQL_NAME = /^[_A-Za-z][_0-9A-Za-z]*$/\nexport function isValidGraphQLName(name: string): boolean {\n return GRAPHQL_NAME.test(name)\n}\n\nexport function graphqlTypeName(machineName: string): string {\n return toPascalCase(schemaSegment(machineName))\n}\n\nexport function singleQueryName(machineName: string): string {\n return toCamelCase(schemaSegment(machineName))\n}\n\nexport function collectionQueryName(machineName: string): string {\n return pluralize(singleQueryName(machineName))\n}\n\nexport function buildFieldNameMap(schemaNames: string[]): {\n toGraphql(schemaName: string): string\n toSchema(graphqlName: string): string\n} {\n const toG = new Map<string, string>()\n const toS = new Map<string, string>()\n for (const name of schemaNames) {\n const g = toCamelCase(name)\n toG.set(name, g)\n toS.set(g, name)\n }\n return {\n toGraphql: (schemaName) => toG.get(schemaName) ?? toCamelCase(schemaName),\n toSchema: (graphqlName) => toS.get(graphqlName) ?? graphqlName,\n }\n}\n","import {\n GraphQLEnumType,\n GraphQLInputObjectType,\n GraphQLList,\n GraphQLNonNull,\n GraphQLString,\n GraphQLBoolean,\n GraphQLInt,\n GraphQLFloat,\n type GraphQLInputType,\n} from 'graphql'\nimport type {\n ParsedContentType,\n ParsedTaxonomyType,\n ParsedField,\n FilterValue,\n FilterOperator,\n FieldType,\n} from '@bobbykim/manguito-cms-core'\nimport { graphqlTypeName, buildFieldNameMap } from './naming.js'\nimport { scalarOutputType } from './type-mapping.js'\nimport { DateTimeScalar } from './scalars.js'\nimport type { FieldKeyMap } from '../field-keys.js'\nimport type { ViewField } from './version-view.js'\n\nexport const SortOrderEnum = new GraphQLEnumType({\n name: 'SortOrder',\n values: { ASC: { value: 'asc' }, DESC: { value: 'desc' } },\n})\n\n// Only these fields are sortable (mirrors the REST SORTABLE_FIELDS).\n//\n// `value` is the enum's internal value, and it is NOT uniformly a storage\n// column: `created_at` / `updated_at` are the snake_case forms of real system\n// columns, but `title` is a schema field's LABEL — the same value REST accepts\n// in `?sort_by=`. `collectionResolver` maps it to a column through the type's\n// FieldKeyMap before the repository builds its ORDER BY.\nconst SORTABLE: Array<{ gql: string; value: string }> = [\n { gql: 'title', value: 'title' },\n { gql: 'createdAt', value: 'created_at' },\n { gql: 'updatedAt', value: 'updated_at' },\n]\n\n/**\n * `fieldKeys` is THIS version's map. `title` in SORTABLE is a schema field's\n * LABEL, not a column, so a version that has no field with that label cannot\n * resolve it — and offering it anyway hands the repository a label that maps\n * to nothing, which surfaces as a 500 from SQL rather than a rejected query.\n * Mirrors `sortableColumnsFor` in versions.ts.\n *\n * `createdAt`/`updatedAt` are real system columns on every content type, so\n * they are always offered and the enum can never end up empty — which\n * GraphQL rejects.\n *\n * With no map, every value is kept: callers that have not threaded a\n * FieldKeyMap through behave exactly as before.\n */\nexport function buildSortFieldEnum(typeName: string, fieldKeys?: FieldKeyMap): GraphQLEnumType {\n const resolvable = SORTABLE.filter(\n (s) =>\n s.gql === 'createdAt' ||\n s.gql === 'updatedAt' ||\n fieldKeys === undefined ||\n fieldKeys.columnFor(s.value) !== undefined\n )\n return new GraphQLEnumType({\n name: `${typeName}SortField`,\n values: Object.fromEntries(resolvable.map((s) => [s.gql, { value: s.value }])),\n })\n}\n\n// A comparable filter input (eq/in/gt/gte/lt/lte) for a given scalar input type.\nfunction comparableFilterInput(name: string, scalar: GraphQLInputType): GraphQLInputObjectType {\n return new GraphQLInputObjectType({\n name,\n fields: {\n eq: { type: scalar },\n in: { type: new GraphQLList(new GraphQLNonNull(scalar)) },\n gt: { type: scalar },\n gte: { type: scalar },\n lt: { type: scalar },\n lte: { type: scalar },\n },\n })\n}\n\nfunction equalityFilterInput(name: string, scalar: GraphQLInputType): GraphQLInputObjectType {\n return new GraphQLInputObjectType({\n name,\n fields: {\n eq: { type: scalar },\n in: { type: new GraphQLList(new GraphQLNonNull(scalar)) },\n },\n })\n}\n\n// Shared per-scalar filter inputs (built once).\nconst StringFilter = equalityFilterInput('StringFilter', GraphQLString)\nconst BooleanFilter = new GraphQLInputObjectType({\n name: 'BooleanFilter',\n fields: { eq: { type: GraphQLBoolean } },\n})\nconst DateTimeFilter = comparableFilterInput('DateTimeFilter', DateTimeScalar)\nconst IDFilter = equalityFilterInput('IDFilter', GraphQLString)\nconst IntFilter = comparableFilterInput('IntFilter', GraphQLInt)\nconst FloatFilter = comparableFilterInput('FloatFilter', GraphQLFloat)\n\n// Choose a filter input for a field based on its scalar output type.\nfunction filterInputForField(fieldType: FieldType): GraphQLInputObjectType | null {\n const scalar = scalarOutputType(fieldType)\n if (fieldType === 'boolean') return BooleanFilter\n if (fieldType === 'date') return DateTimeFilter\n if (fieldType === 'integer') return IntFilter\n if (fieldType === 'float') return FloatFilter\n if (fieldType === 'reference') return IDFilter\n if (scalar === null) return null // only 'enum' reaches here — not filterable via a scalar input\n return StringFilter\n}\n\n// Build the <Type>Filter input. Programmatic fields are excluded (no column).\nexport function buildFilterInputType(\n type: ParsedContentType | ParsedTaxonomyType,\n viewFields?: ViewField[]\n): GraphQLInputObjectType | null {\n const fields: Record<string, { type: GraphQLInputObjectType }> = {}\n\n // System fields that are filterable columns.\n fields['id'] = { type: IDFilter }\n fields['published'] = { type: BooleanFilter }\n fields['createdAt'] = { type: DateTimeFilter }\n fields['updatedAt'] = { type: DateTimeFilter }\n if (type.schema_type === 'content-type') fields['slug'] = { type: StringFilter }\n\n // A view states the label THIS version exposes each field under; without\n // one, fall back to the field's own name minus tombstones (Task 2's rule).\n const entries: Array<{ field: ParsedField; exposedAs: string }> =\n viewFields !== undefined\n ? viewFields.map((v) => ({ field: v.field, exposedAs: v.exposedAs }))\n : type.fields.filter((f) => f.removed !== true).map((f) => ({ field: f, exposedAs: f.name }))\n\n for (const { field: f, exposedAs } of entries) {\n if (f.field_type === 'programmatic' || f.field_type === 'paragraph') continue\n if (f.field_type === 'image' || f.field_type === 'video' || f.field_type === 'file') continue\n const input = filterInputForField(f.field_type)\n if (input) fields[buildFieldNameMap([exposedAs]).toGraphql(exposedAs)] = { type: input }\n }\n\n if (Object.keys(fields).length === 0) return null\n return new GraphQLInputObjectType({ name: `${graphqlTypeName(type.name)}Filter`, fields })\n}\n\n// Convert a GraphQL filter argument into the repository's filters map, keyed by\n// snake_case column. eq → scalar, in → array (OR/IN), gt/gte/lt/lte → operator.\n//\n// `nameMap.toSchema` only ever recovers the schema field's LABEL (`field.name`)\n// from the GraphQL name — that mapping is unaware of storage columns. `columnFor`\n// (typically `FieldKeyMap.columnFor`) takes that label the rest of the way to the\n// storage column the repository actually filters on. It's optional so callers\n// that haven't threaded a FieldKeyMap through yet keep working unchanged: with no\n// mapper, or when it returns nothing for a given label, the label itself is used —\n// correct as long as it equals its column.\nexport function translateFilters(\n input: Record<string, unknown> | undefined,\n nameMap: { toSchema(g: string): string },\n columnFor?: (label: string) => string | undefined\n): Record<string, FilterValue> {\n const out: Record<string, FilterValue> = {}\n if (!input) return out\n\n for (const [gqlField, raw] of Object.entries(input)) {\n if (raw === null || typeof raw !== 'object') continue\n const label = nameMap.toSchema(gqlField)\n const column = columnFor?.(label) ?? label\n const spec = raw as Record<string, unknown>\n\n // eq/in take priority over range operators (gt/gte/lt/lte) when a client sends\n // both in one field filter — the range operators are silently dropped.\n if (spec['eq'] !== undefined) {\n out[column] = spec['eq'] as FilterValue\n } else if (Array.isArray(spec['in'])) {\n out[column] = spec['in'] as FilterValue\n } else {\n const op: FilterOperator = {}\n for (const k of ['gt', 'gte', 'lt', 'lte'] as const) {\n if (spec[k] !== undefined) op[k] = spec[k] as number | string\n }\n if (Object.keys(op).length > 0) out[column] = op\n }\n }\n return out\n}\n","import { GraphQLError } from 'graphql'\nimport type { ParsedField } from '@bobbykim/manguito-cms-core'\nimport type { GraphQLContext } from './context.js'\nimport { translateFilters } from './filters.js'\nimport { isColumnBacked, type FieldKeyMap } from '../field-keys.js'\n\ntype Row = Record<string, unknown>\n\nfunction codeError(code: string, message: string): GraphQLError {\n return new GraphQLError(message, { extensions: { code } })\n}\n\nfunction isPublished(item: Row | null): boolean {\n return !!item && item['published'] === true\n}\n\n/**\n * A GraphQL field's value on a content row. The GraphQL field NAME comes from\n * the field's label (see naming.ts), but the value lives under its storage\n * column, which differs once a field has been renamed.\n *\n * `fallback` is the value a version declares for a column that stopped being\n * written: rows created since the removal hold null there. Substituted on\n * null/undefined ONLY — never on '' or 0 — matching projectRow's rule, so the\n * REST and GraphQL surfaces cannot disagree about the same version.\n */\nexport function resolveFieldValue(\n field: ParsedField,\n row: Record<string, unknown>,\n fallback?: unknown\n): unknown {\n const key = isColumnBacked(field) ? field.db_column.column_name : field.name\n const value = row[key]\n if ((value === null || value === undefined) && fallback !== undefined) return fallback\n return value ?? null\n}\n\nexport function scalarFieldResolver(field: ParsedField, fallback?: unknown) {\n return (parent: Row): unknown => resolveFieldValue(field, parent, fallback)\n}\n\nexport function relationFieldResolver(typeName: string, schemaFieldName: string) {\n return (parent: Row, _args: unknown, ctx: GraphQLContext): Promise<unknown> =>\n ctx.loaders.load(typeName, schemaFieldName, parent)\n}\n\nexport function programmaticFieldResolver(\n typeName: string,\n schemaFieldName: string,\n mediaFieldNames: readonly string[] = [],\n fieldKeys?: FieldKeyMap\n) {\n return async (parent: Row, _args: unknown, ctx: GraphQLContext): Promise<unknown> => {\n let p = ctx.programmaticMemo.get(parent)\n if (!p) {\n p = resolveProgrammaticRow(typeName, parent, ctx, mediaFieldNames, fieldKeys)\n ctx.programmaticMemo.set(parent, p)\n }\n return (await p)[schemaFieldName]\n }\n}\n\n// A programmatic resolver reads its record through `ctx.get()`, so that record\n// must look the same on both public surfaces. REST resolves media fields to full\n// objects before running resolvers; GraphQL reads through repositories that\n// resolve nothing, so without this `ctx.get('hero').url` would work over REST and\n// silently fall back to null over GraphQL.\n//\n// Media is resolved into a COPY, never the row itself: the programmatic record is\n// built from a copy so that projecting it to current's labels (toLabels below)\n// never touches the parent row, which the field resolvers still read by column.\n// The dataloaders resolve relations in place and idempotently now, so handing the\n// parent itself back to the loader would no longer break anything either — the\n// copy is kept to keep this path from mutating the parent, and it is harmless:\n// loaders still batch across the copy, so this costs no extra query.\n//\n// `ctx.get(fieldName)` takes the schema field name (the LABEL), so the record is\n// projected to CURRENT's labels (the caller passes current's map on every\n// version) before the resolver runs — the same order REST uses (see \"Response\n// projection order\" in routes/content.ts). GraphQL has no route-level\n// projection to double up with: every other field resolves per field by column\n// (resolveFieldValue), so this copy is the only mapped row, and it is mapped\n// strictly after the media loaders have run.\nasync function resolveProgrammaticRow(\n typeName: string,\n parent: Row,\n ctx: GraphQLContext,\n mediaFieldNames: readonly string[],\n fieldKeys?: FieldKeyMap\n): Promise<Record<string, unknown>> {\n const toLabels = (row: Row): Row => (fieldKeys ? fieldKeys.toLabels(row) : row)\n\n if (mediaFieldNames.length === 0) return ctx.resolver.resolveItem(typeName, toLabels(parent))\n\n const enriched: Row = { ...parent }\n await Promise.all(mediaFieldNames.map((name) => ctx.loaders.load(typeName, name, enriched)))\n // The loaders resolve each media object IN PLACE under its storage column,\n // so toLabels carries it to its label like any scalar.\n return ctx.resolver.resolveItem(typeName, toLabels(enriched))\n}\n\ntype CollectionArgs = {\n page?: number\n perPage?: number\n /**\n * The sort enum's internal value (filters.ts `SORTABLE`), which mixes two key\n * spaces: `created_at` / `updated_at` are system COLUMNS, but `title` is a\n * schema field's LABEL. It must be mapped before it reaches the repository.\n */\n sortBy?: string\n sortOrder?: 'asc' | 'desc'\n filter?: Record<string, unknown>\n}\n\nexport function collectionResolver(\n typeName: string,\n nameMap: { toSchema(g: string): string },\n fieldKeys?: FieldKeyMap\n) {\n return async (_root: unknown, args: CollectionArgs, ctx: GraphQLContext) => {\n const page = args.page ?? 1\n const perPage = args.perPage ?? 10\n if (!Number.isInteger(page) || page < 1) {\n throw codeError('INVALID_PAGINATION', 'page must be ≥ 1')\n }\n if (!Number.isInteger(perPage) || perPage < 1 || perPage > 100) {\n throw codeError('INVALID_PAGINATION', 'perPage must be between 1 and 100')\n }\n const repo = ctx.repos[typeName]!\n // `ORDER BY` takes a storage column, never a label. `columnFor` resolves a\n // schema field's label to its column; a system column (`created_at`,\n // `updated_at`) is not a label at all, so it has no entry and falls\n // through unchanged. Identity today, since every label equals its column.\n const sortBy = args.sortBy ?? 'created_at'\n const sortColumn = fieldKeys?.columnFor(sortBy) ?? sortBy\n const result = await repo.findMany({\n published_only: true,\n page,\n per_page: perPage,\n sort_by: sortColumn as 'title' | 'created_at' | 'updated_at',\n sort_order: args.sortOrder ?? 'asc',\n filters: translateFilters(args.filter, nameMap, fieldKeys?.columnFor),\n })\n return { data: result.data as Row[], meta: result.meta }\n }\n}\n\nexport function singleBySlugResolver(typeName: string) {\n return async (_root: unknown, args: { slug: string }, ctx: GraphQLContext): Promise<Row | null> => {\n const repo = ctx.repos[typeName]!\n const item = (await repo.findBySlug(args.slug)) as Row | null\n return isPublished(item) ? item : null\n }\n}\n\nexport function singletonResolver(typeName: string) {\n return async (_root: unknown, _args: unknown, ctx: GraphQLContext): Promise<Row | null> => {\n const repo = ctx.repos[typeName]!\n const result = await repo.findMany({ published_only: true, page: 1, per_page: 1 })\n return (result.data[0] as Row | undefined) ?? null\n }\n}\n\nexport function taxonomySingleResolver(typeName: string) {\n return async (_root: unknown, args: { id: string }, ctx: GraphQLContext): Promise<Row | null> => {\n const repo = ctx.repos[typeName]!\n const item = (await repo.findOne(args.id)) as Row | null\n return isPublished(item) ? item : null\n }\n}\n","import type { ParsedField, SchemaRegistry, VersionProjection } from '@bobbykim/manguito-cms-core'\nimport { isColumnBacked } from '../field-keys.js'\n\n// ─── One live version's view of the schema ────────────────────────────────────\n//\n// A VersionProjection says WHICH columns a version exposes, under WHICH labels,\n// and whether each is required. It deliberately says nothing about a field's\n// type: `field_type` and `ui_component` are recovered from CURRENT's field for\n// the same column instead.\n//\n// That join is sound, not convenient. `VERSION_COLUMN_MISSING` guarantees every\n// column a live version exposes still exists in current, and\n// `FIELD_TYPE_CHANGED_WHILE_LIVE` guarantees its type has not moved under it —\n// so current's field is a faithful source for everything except the label and\n// the requiredness, which the projection carries precisely because they DO\n// move. See the 2e design, \"Deriving a version's types\".\n\nexport type ViewField = {\n /** Current's field for this column — the source of `field_type` and `ui_component`. */\n field: ParsedField\n /** The name THIS version exposes the column under. */\n exposedAs: string\n /** THIS version's requiredness. Never current's — see VersionProjection. */\n required: boolean\n /**\n * The value to serve when the column holds null, for a column that stopped\n * being written. REST substitutes this in `projectRow`; GraphQL has no\n * route-level projection, so its scalar resolver has to do it or the two\n * surfaces disagree about the same version's contract.\n */\n fallback?: unknown\n /** Present only when this version's contract differs from current's. */\n deprecationReason?: string\n}\n\n/** Keyed by machine name, for content, taxonomy AND paragraph types. */\nexport type VersionView = Record<string, { fields: ViewField[] }>\n\n/** A type's column-backed fields keyed by column. Tombstones included — they hold a real column. */\nfunction byColumn(fields: ParsedField[]): Map<string, ParsedField> {\n const out = new Map<string, ParsedField>()\n for (const f of fields) {\n if (!isColumnBacked(f)) continue\n out.set(f.db_column.column_name, f)\n }\n return out\n}\n\n/**\n * Why this version's contract differs from current's, or undefined when it\n * does not. Keyed by COLUMN, because the label is exactly what may have moved.\n *\n * The reason names CURRENT, not the intermediate version where the change\n * happened: pinpointing that would mean walking every snapshot in between, and\n * \"what it is called now\" is the actionable fact for someone deciding whether\n * to upgrade.\n */\nfunction deprecationFor(\n field: { column_name: string; exposed_as: string },\n currentLabels: Map<string, string>,\n currentVersion: string\n): string | undefined {\n const currentLabel = currentLabels.get(field.column_name)\n if (currentLabel === undefined) {\n return `Removed in ${currentVersion}; column retained while this version is live.`\n }\n if (currentLabel !== field.exposed_as) {\n return `Renamed to '${currentLabel}' in ${currentVersion}.`\n }\n return undefined\n}\n\n/**\n * `projection` undefined means this version has no projection for a type — or\n * none at all. Those types fall back to the registry's own fields minus\n * tombstones, which is the inherited 2d boundary: paragraph types are never\n * projected, so nested paragraph content follows current's shape on every\n * version, by design.\n */\nexport function buildVersionView(input: {\n registry: SchemaRegistry\n projection: VersionProjection | undefined\n currentProjection: VersionProjection | undefined\n currentVersion: string\n}): VersionView {\n const { registry, projection, currentProjection, currentVersion } = input\n const out: VersionView = {}\n\n const sources: Array<Record<string, { fields: ParsedField[] }>> = [\n registry.content_types,\n registry.taxonomy_types,\n registry.paragraph_types,\n ]\n\n for (const source of sources) {\n for (const [typeName, type] of Object.entries(source)) {\n const projectionType = projection?.types[typeName]\n\n // No projection for this type: follow current, minus tombstones.\n if (projectionType === undefined) {\n out[typeName] = {\n fields: type.fields\n .filter((f) => f.removed !== true)\n .map((f) => ({ field: f, exposedAs: f.name, required: f.required })),\n }\n continue\n }\n\n const columns = byColumn(type.fields)\n const currentLabels = new Map<string, string>()\n for (const f of currentProjection?.types[typeName]?.fields ?? []) {\n currentLabels.set(f.column_name, f.exposed_as)\n }\n\n const fields: ViewField[] = []\n\n for (const pf of projectionType.fields) {\n const field = columns.get(pf.column_name)\n // Unreachable on a model that loaded — VERSION_COLUMN_MISSING rejects\n // it. Skipped rather than thrown so a hand-built baked model cannot\n // take the whole schema down over one field.\n if (field === undefined) continue\n const reason = deprecationFor(pf, currentLabels, currentVersion)\n fields.push({\n field,\n exposedAs: pf.exposed_as,\n required: pf.required,\n ...(pf.fallback !== undefined && { fallback: pf.fallback }),\n ...(reason !== undefined && { deprecationReason: reason }),\n })\n }\n\n // Fields with no column of their own — paragraph, many-to-many,\n // programmatic — never appear in a projection, so they must be appended\n // from the registry or an older version's schema would silently lose\n // every relation and computed field. They follow current on every\n // version (the 2d boundary), hence no deprecation reason.\n for (const f of type.fields) {\n if (isColumnBacked(f) || f.removed === true) continue\n fields.push({ field: f, exposedAs: f.name, required: f.required })\n }\n\n out[typeName] = { fields }\n }\n }\n\n return out\n}\n","import DataLoader from 'dataloader'\nimport type { DrizzlePostgresInstance } from '@bobbykim/manguito-cms-db'\nimport type {\n SchemaRegistry,\n ParsedContentType,\n ParsedTaxonomyType,\n ParsedParagraphType,\n} from '@bobbykim/manguito-cms-core'\nimport { buildRelationsMap, resolveRelationField, type RelationDef } from '../relations.js'\n\nexport interface RelationLoaders {\n load(typeName: string, fieldName: string, parent: Record<string, unknown>): Promise<unknown>\n}\n\ntype ParentRow = Record<string, unknown>\n\n// One RelationLoaders instance per request. Loaders batch sibling parents per\n// (type, field); the shared cache dedupes target lookups across all loaders in\n// the request, mirroring the repository's resolveRows cache.\nexport function createRelationLoaders(\n db: DrizzlePostgresInstance,\n registry: SchemaRegistry\n): RelationLoaders {\n const relMaps = new Map<string, Record<string, RelationDef>>()\n const loaders = new Map<string, DataLoader<ParentRow, unknown>>()\n const cache = new Map<string, unknown>()\n\n function relationsFor(typeName: string): Record<string, RelationDef> {\n let m = relMaps.get(typeName)\n if (!m) {\n const type = (registry.content_types[typeName] ??\n registry.taxonomy_types[typeName] ??\n registry.paragraph_types[typeName]) as\n | ParsedContentType\n | ParsedTaxonomyType\n | ParsedParagraphType\n | undefined\n m = type ? buildRelationsMap(type.fields, registry) : {}\n relMaps.set(typeName, m)\n }\n return m\n }\n\n function loaderFor(typeName: string, fieldName: string, rel: RelationDef): DataLoader<ParentRow, unknown> {\n const key = `${typeName}:${fieldName}`\n let dl = loaders.get(key)\n if (!dl) {\n dl = new DataLoader<ParentRow, unknown>(\n async (parents) => {\n const rows = parents as ParentRow[]\n // GraphQL is public-only (see app.ts) — always filter relation targets\n // to published rows, mirroring the REST public repos' publishedRelations.\n await resolveRelationField(db, rows, fieldName, rel, cache, true)\n // Column-backed relations resolve in place under their storage\n // column. Paragraph and junction relations have no column, so they\n // resolve under the field's name.\n // Not named `key`: loaderFor already declares one, for the cache.\n const resultKey = rel.type === 'reference' || rel.type === 'media' ? rel.fk_column : fieldName\n return rows.map((r) => r[resultKey])\n },\n // Batch within a tick; do not memoize by parent identity (rows are mutated\n // and may recur across nesting levels).\n { cache: false }\n )\n loaders.set(key, dl)\n }\n return dl\n }\n\n return {\n async load(typeName, fieldName, parent) {\n const rel = relationsFor(typeName)[fieldName]\n if (!rel) return null\n return loaderFor(typeName, fieldName, rel).load(parent)\n },\n }\n}\n","import { EnvelopArmor } from '@escape.tech/graphql-armor'\nimport { NoSchemaIntrospectionCustomRule } from 'graphql'\n\n// Depth + cost + alias + directive limits via GraphQL Armor. Returns { plugins } to\n// spread into Yoga's `plugins` array.\n//\n// Note: the installed `@escape.tech/graphql-armor` (3.2.0) exports `EnvelopArmor`, a\n// class whose `.protect()` returns `{ plugins }` — the standalone `EnvelopArmorPlugin`\n// export is a function that returns a single plugin, not a class with `.protect()`.\nexport function buildArmorPlugin(options: { maxDepth: number; maxComplexity: number }): {\n plugins: unknown[]\n} {\n const armor = new EnvelopArmor({\n maxDepth: { n: options.maxDepth },\n costLimit: { maxCost: options.maxComplexity },\n maxAliases: { n: 15 },\n maxDirectives: { n: 50 },\n blockFieldSuggestion: { enabled: true },\n // maxTokens is intentionally left at Armor's secure default (n=1000) to bound\n // GraphQL document token count at parse time, a layer the depth/cost/alias/directive\n // limits do not cover.\n })\n return armor.protect()\n}\n\n// Disables introspection (and the __schema/__type meta-fields) in production by\n// adding graphql's built-in validation rule when `enabled` is false.\nexport function introspectionPlugin(enabled: boolean): {\n onValidate(payload: { addValidationRule: (rule: unknown) => void }): void\n} {\n return {\n onValidate({ addValidationRule }) {\n if (!enabled) addValidationRule(NoSchemaIntrospectionCustomRule)\n },\n }\n}\n"],"mappings":";;;;;;;AAAA,SAAS,YAAY,iBAAiB;;;ACAtC;AAAA,EACE;AAAA,EACA;AAAA,EACA,mBAAAA;AAAA,EACA,kBAAAC;AAAA,EACA,eAAAC;AAAA,EACA;AAAA,EACA,iBAAAC;AAAA,EACA,cAAAC;AAAA,EACA,kBAAAC;AAAA,OAIK;;;ACbP,SAAS,mBAAmB,MAAM,2BAA2B;AAEtD,IAAM,iBAAiB,IAAI,kBAAkB;AAAA,EAClD,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU,OAAO;AACf,QAAI,iBAAiB,KAAM,QAAO,MAAM,YAAY;AACpD,QAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAI,OAAO,UAAU,SAAU,QAAO,IAAI,KAAK,KAAK,EAAE,YAAY;AAClE,UAAM,IAAI,UAAU,oCAAoC,OAAO,KAAK,CAAC,EAAE;AAAA,EACzE;AAAA,EACA,WAAW,OAAO;AAChB,QAAI,OAAO,UAAU,SAAU,OAAM,IAAI,UAAU,2BAA2B;AAC9E,WAAO;AAAA,EACT;AAAA,EACA,aAAa,KAAK;AAChB,QAAI,IAAI,SAAS,KAAK,OAAQ,OAAM,IAAI,UAAU,2BAA2B;AAC7E,WAAO,IAAI;AAAA,EACb;AACF,CAAC;AAEM,IAAM,aAAa,IAAI,kBAAkB;AAAA,EAC9C,MAAM;AAAA,EACN,aAAa;AAAA,EACb,WAAW,CAAC,UAAU;AAAA,EACtB,YAAY,CAAC,UAAU;AAAA,EACvB,cAAc,CAAC,KAAK,cAAc,oBAAoB,KAAK,aAAa,MAAS;AACnF,CAAC;;;AC3BD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAMA,SAAS,iBAAiB,WAAgD;AAC/E,UAAQ,WAAW;AAAA,IACjB,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;;;AC7BO,SAAS,cAAc,aAA6B;AACzD,QAAM,MAAM,YAAY,QAAQ,IAAI;AACpC,SAAO,QAAQ,KAAK,cAAc,YAAY,MAAM,MAAM,CAAC;AAC7D;AAEA,SAAS,MAAM,OAAyB;AACtC,SAAO,MAAM,MAAM,SAAS,EAAE,OAAO,OAAO;AAC9C;AAEO,SAAS,aAAa,OAAuB;AAClD,SAAO,MAAM,KAAK,EACf,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,IAAI,EAAE,MAAM,CAAC,CAAC,EACjD,KAAK,EAAE;AACZ;AAEO,SAAS,YAAY,OAAuB;AACjD,QAAM,SAAS,aAAa,KAAK;AACjC,SAAO,OAAO,OAAO,CAAC,EAAE,YAAY,IAAI,OAAO,MAAM,CAAC;AACxD;AAKO,SAAS,UAAU,MAAsB;AAC9C,MAAI,aAAa,KAAK,IAAI,EAAG,QAAO,KAAK,MAAM,GAAG,EAAE,IAAI;AACxD,MAAI,iBAAiB,KAAK,IAAI,EAAG,QAAO,OAAO;AAC/C,SAAO,OAAO;AAChB;AAEA,IAAM,eAAe;AACd,SAAS,mBAAmB,MAAuB;AACxD,SAAO,aAAa,KAAK,IAAI;AAC/B;AAEO,SAAS,gBAAgB,aAA6B;AAC3D,SAAO,aAAa,cAAc,WAAW,CAAC;AAChD;AAEO,SAAS,gBAAgB,aAA6B;AAC3D,SAAO,YAAY,cAAc,WAAW,CAAC;AAC/C;AAEO,SAAS,oBAAoB,aAA6B;AAC/D,SAAO,UAAU,gBAAgB,WAAW,CAAC;AAC/C;AAEO,SAAS,kBAAkB,aAGhC;AACA,QAAM,MAAM,oBAAI,IAAoB;AACpC,QAAM,MAAM,oBAAI,IAAoB;AACpC,aAAW,QAAQ,aAAa;AAC9B,UAAM,IAAI,YAAY,IAAI;AAC1B,QAAI,IAAI,MAAM,CAAC;AACf,QAAI,IAAI,GAAG,IAAI;AAAA,EACjB;AACA,SAAO;AAAA,IACL,WAAW,CAAC,eAAe,IAAI,IAAI,UAAU,KAAK,YAAY,UAAU;AAAA,IACxE,UAAU,CAAC,gBAAgB,IAAI,IAAI,WAAW,KAAK;AAAA,EACrD;AACF;;;AC9DA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,iBAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,cAAAC;AAAA,EACA,gBAAAC;AAAA,OAEK;AAeA,IAAM,gBAAgB,IAAI,gBAAgB;AAAA,EAC/C,MAAM;AAAA,EACN,QAAQ,EAAE,KAAK,EAAE,OAAO,MAAM,GAAG,MAAM,EAAE,OAAO,OAAO,EAAE;AAC3D,CAAC;AASD,IAAM,WAAkD;AAAA,EACtD,EAAE,KAAK,SAAS,OAAO,QAAQ;AAAA,EAC/B,EAAE,KAAK,aAAa,OAAO,aAAa;AAAA,EACxC,EAAE,KAAK,aAAa,OAAO,aAAa;AAC1C;AAgBO,SAAS,mBAAmB,UAAkB,WAA0C;AAC7F,QAAM,aAAa,SAAS;AAAA,IAC1B,CAAC,MACC,EAAE,QAAQ,eACV,EAAE,QAAQ,eACV,cAAc,UACd,UAAU,UAAU,EAAE,KAAK,MAAM;AAAA,EACrC;AACA,SAAO,IAAI,gBAAgB;AAAA,IACzB,MAAM,GAAG,QAAQ;AAAA,IACjB,QAAQ,OAAO,YAAY,WAAW,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;AAAA,EAC/E,CAAC;AACH;AAGA,SAAS,sBAAsB,MAAc,QAAkD;AAC7F,SAAO,IAAI,uBAAuB;AAAA,IAChC;AAAA,IACA,QAAQ;AAAA,MACN,IAAI,EAAE,MAAM,OAAO;AAAA,MACnB,IAAI,EAAE,MAAM,IAAI,YAAY,IAAI,eAAe,MAAM,CAAC,EAAE;AAAA,MACxD,IAAI,EAAE,MAAM,OAAO;AAAA,MACnB,KAAK,EAAE,MAAM,OAAO;AAAA,MACpB,IAAI,EAAE,MAAM,OAAO;AAAA,MACnB,KAAK,EAAE,MAAM,OAAO;AAAA,IACtB;AAAA,EACF,CAAC;AACH;AAEA,SAAS,oBAAoB,MAAc,QAAkD;AAC3F,SAAO,IAAI,uBAAuB;AAAA,IAChC;AAAA,IACA,QAAQ;AAAA,MACN,IAAI,EAAE,MAAM,OAAO;AAAA,MACnB,IAAI,EAAE,MAAM,IAAI,YAAY,IAAI,eAAe,MAAM,CAAC,EAAE;AAAA,IAC1D;AAAA,EACF,CAAC;AACH;AAGA,IAAM,eAAe,oBAAoB,gBAAgBC,cAAa;AACtE,IAAM,gBAAgB,IAAI,uBAAuB;AAAA,EAC/C,MAAM;AAAA,EACN,QAAQ,EAAE,IAAI,EAAE,MAAMC,gBAAe,EAAE;AACzC,CAAC;AACD,IAAM,iBAAiB,sBAAsB,kBAAkB,cAAc;AAC7E,IAAM,WAAW,oBAAoB,YAAYD,cAAa;AAC9D,IAAM,YAAY,sBAAsB,aAAaE,WAAU;AAC/D,IAAM,cAAc,sBAAsB,eAAeC,aAAY;AAGrE,SAAS,oBAAoB,WAAqD;AAChF,QAAM,SAAS,iBAAiB,SAAS;AACzC,MAAI,cAAc,UAAW,QAAO;AACpC,MAAI,cAAc,OAAQ,QAAO;AACjC,MAAI,cAAc,UAAW,QAAO;AACpC,MAAI,cAAc,QAAS,QAAO;AAClC,MAAI,cAAc,YAAa,QAAO;AACtC,MAAI,WAAW,KAAM,QAAO;AAC5B,SAAO;AACT;AAGO,SAAS,qBACd,MACA,YAC+B;AAC/B,QAAM,SAA2D,CAAC;AAGlE,SAAO,IAAI,IAAI,EAAE,MAAM,SAAS;AAChC,SAAO,WAAW,IAAI,EAAE,MAAM,cAAc;AAC5C,SAAO,WAAW,IAAI,EAAE,MAAM,eAAe;AAC7C,SAAO,WAAW,IAAI,EAAE,MAAM,eAAe;AAC7C,MAAI,KAAK,gBAAgB,eAAgB,QAAO,MAAM,IAAI,EAAE,MAAM,aAAa;AAI/E,QAAM,UACJ,eAAe,SACX,WAAW,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,WAAW,EAAE,UAAU,EAAE,IAClE,KAAK,OAAO,OAAO,CAAC,MAAM,EAAE,YAAY,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,WAAW,EAAE,KAAK,EAAE;AAEhG,aAAW,EAAE,OAAO,GAAG,UAAU,KAAK,SAAS;AAC7C,QAAI,EAAE,eAAe,kBAAkB,EAAE,eAAe,YAAa;AACrE,QAAI,EAAE,eAAe,WAAW,EAAE,eAAe,WAAW,EAAE,eAAe,OAAQ;AACrF,UAAM,QAAQ,oBAAoB,EAAE,UAAU;AAC9C,QAAI,MAAO,QAAO,kBAAkB,CAAC,SAAS,CAAC,EAAE,UAAU,SAAS,CAAC,IAAI,EAAE,MAAM,MAAM;AAAA,EACzF;AAEA,MAAI,OAAO,KAAK,MAAM,EAAE,WAAW,EAAG,QAAO;AAC7C,SAAO,IAAI,uBAAuB,EAAE,MAAM,GAAG,gBAAgB,KAAK,IAAI,CAAC,UAAU,OAAO,CAAC;AAC3F;AAYO,SAAS,iBACd,OACA,SACA,WAC6B;AAC7B,QAAM,MAAmC,CAAC;AAC1C,MAAI,CAAC,MAAO,QAAO;AAEnB,aAAW,CAAC,UAAU,GAAG,KAAK,OAAO,QAAQ,KAAK,GAAG;AACnD,QAAI,QAAQ,QAAQ,OAAO,QAAQ,SAAU;AAC7C,UAAM,QAAQ,QAAQ,SAAS,QAAQ;AACvC,UAAM,SAAS,YAAY,KAAK,KAAK;AACrC,UAAM,OAAO;AAIb,QAAI,KAAK,IAAI,MAAM,QAAW;AAC5B,UAAI,MAAM,IAAI,KAAK,IAAI;AAAA,IACzB,WAAW,MAAM,QAAQ,KAAK,IAAI,CAAC,GAAG;AACpC,UAAI,MAAM,IAAI,KAAK,IAAI;AAAA,IACzB,OAAO;AACL,YAAM,KAAqB,CAAC;AAC5B,iBAAW,KAAK,CAAC,MAAM,OAAO,MAAM,KAAK,GAAY;AACnD,YAAI,KAAK,CAAC,MAAM,OAAW,IAAG,CAAC,IAAI,KAAK,CAAC;AAAA,MAC3C;AACA,UAAI,OAAO,KAAK,EAAE,EAAE,SAAS,EAAG,KAAI,MAAM,IAAI;AAAA,IAChD;AAAA,EACF;AACA,SAAO;AACT;;;AC9LA,SAAS,oBAAoB;AAQ7B,SAAS,UAAU,MAAc,SAA+B;AAC9D,SAAO,IAAI,aAAa,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;AAC3D;AAEA,SAAS,YAAY,MAA2B;AAC9C,SAAO,CAAC,CAAC,QAAQ,KAAK,WAAW,MAAM;AACzC;AAYO,SAAS,kBACd,OACA,KACA,UACS;AACT,QAAM,MAAM,eAAe,KAAK,IAAI,MAAM,UAAU,cAAc,MAAM;AACxE,QAAM,QAAQ,IAAI,GAAG;AACrB,OAAK,UAAU,QAAQ,UAAU,WAAc,aAAa,OAAW,QAAO;AAC9E,SAAO,SAAS;AAClB;AAEO,SAAS,oBAAoB,OAAoB,UAAoB;AAC1E,SAAO,CAAC,WAAyB,kBAAkB,OAAO,QAAQ,QAAQ;AAC5E;AAEO,SAAS,sBAAsB,UAAkB,iBAAyB;AAC/E,SAAO,CAAC,QAAa,OAAgB,QACnC,IAAI,QAAQ,KAAK,UAAU,iBAAiB,MAAM;AACtD;AAEO,SAAS,0BACd,UACA,iBACA,kBAAqC,CAAC,GACtC,WACA;AACA,SAAO,OAAO,QAAa,OAAgB,QAA0C;AACnF,QAAI,IAAI,IAAI,iBAAiB,IAAI,MAAM;AACvC,QAAI,CAAC,GAAG;AACN,UAAI,uBAAuB,UAAU,QAAQ,KAAK,iBAAiB,SAAS;AAC5E,UAAI,iBAAiB,IAAI,QAAQ,CAAC;AAAA,IACpC;AACA,YAAQ,MAAM,GAAG,eAAe;AAAA,EAClC;AACF;AAuBA,eAAe,uBACb,UACA,QACA,KACA,iBACA,WACkC;AAClC,QAAM,WAAW,CAAC,QAAmB,YAAY,UAAU,SAAS,GAAG,IAAI;AAE3E,MAAI,gBAAgB,WAAW,EAAG,QAAO,IAAI,SAAS,YAAY,UAAU,SAAS,MAAM,CAAC;AAE5F,QAAM,WAAgB,EAAE,GAAG,OAAO;AAClC,QAAM,QAAQ,IAAI,gBAAgB,IAAI,CAAC,SAAS,IAAI,QAAQ,KAAK,UAAU,MAAM,QAAQ,CAAC,CAAC;AAG3F,SAAO,IAAI,SAAS,YAAY,UAAU,SAAS,QAAQ,CAAC;AAC9D;AAeO,SAAS,mBACd,UACA,SACA,WACA;AACA,SAAO,OAAO,OAAgB,MAAsB,QAAwB;AAC1E,UAAM,OAAO,KAAK,QAAQ;AAC1B,UAAM,UAAU,KAAK,WAAW;AAChC,QAAI,CAAC,OAAO,UAAU,IAAI,KAAK,OAAO,GAAG;AACvC,YAAM,UAAU,sBAAsB,uBAAkB;AAAA,IAC1D;AACA,QAAI,CAAC,OAAO,UAAU,OAAO,KAAK,UAAU,KAAK,UAAU,KAAK;AAC9D,YAAM,UAAU,sBAAsB,mCAAmC;AAAA,IAC3E;AACA,UAAM,OAAO,IAAI,MAAM,QAAQ;AAK/B,UAAM,SAAS,KAAK,UAAU;AAC9B,UAAM,aAAa,WAAW,UAAU,MAAM,KAAK;AACnD,UAAM,SAAS,MAAM,KAAK,SAAS;AAAA,MACjC,gBAAgB;AAAA,MAChB;AAAA,MACA,UAAU;AAAA,MACV,SAAS;AAAA,MACT,YAAY,KAAK,aAAa;AAAA,MAC9B,SAAS,iBAAiB,KAAK,QAAQ,SAAS,WAAW,SAAS;AAAA,IACtE,CAAC;AACD,WAAO,EAAE,MAAM,OAAO,MAAe,MAAM,OAAO,KAAK;AAAA,EACzD;AACF;AAEO,SAAS,qBAAqB,UAAkB;AACrD,SAAO,OAAO,OAAgB,MAAwB,QAA6C;AACjG,UAAM,OAAO,IAAI,MAAM,QAAQ;AAC/B,UAAM,OAAQ,MAAM,KAAK,WAAW,KAAK,IAAI;AAC7C,WAAO,YAAY,IAAI,IAAI,OAAO;AAAA,EACpC;AACF;AAEO,SAAS,kBAAkB,UAAkB;AAClD,SAAO,OAAO,OAAgB,OAAgB,QAA6C;AACzF,UAAM,OAAO,IAAI,MAAM,QAAQ;AAC/B,UAAM,SAAS,MAAM,KAAK,SAAS,EAAE,gBAAgB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;AACjF,WAAQ,OAAO,KAAK,CAAC,KAAyB;AAAA,EAChD;AACF;AAEO,SAAS,uBAAuB,UAAkB;AACvD,SAAO,OAAO,OAAgB,MAAsB,QAA6C;AAC/F,UAAM,OAAO,IAAI,MAAM,QAAQ;AAC/B,UAAM,OAAQ,MAAM,KAAK,QAAQ,KAAK,EAAE;AACxC,WAAO,YAAY,IAAI,IAAI,OAAO;AAAA,EACpC;AACF;;;AL3HA,IAAM,YAAY,IAAI,kBAAkB;AAAA,EACtC,MAAM;AAAA,EACN,QAAQ;AAAA,IACN,OAAO,EAAE,MAAM,IAAIC,gBAAeC,WAAU,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM;AAAA,IACvE,MAAM,EAAE,MAAM,IAAID,gBAAeC,WAAU,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK;AAAA,IACrE,SAAS,EAAE,MAAM,IAAID,gBAAeC,WAAU,GAAG,SAAS,CAAC,MAAM,EAAE,SAAS;AAAA,IAC5E,YAAY,EAAE,MAAM,IAAID,gBAAeC,WAAU,GAAG,SAAS,CAAC,MAAM,EAAE,YAAY;AAAA,IAClF,SAAS,EAAE,MAAM,IAAID,gBAAeE,eAAc,GAAG,SAAS,CAAC,MAAM,EAAE,SAAS;AAAA,IAChF,SAAS,EAAE,MAAM,IAAIF,gBAAeE,eAAc,GAAG,SAAS,CAAC,MAAM,EAAE,SAAS;AAAA,EAClF;AACF,CAAC;AAED,IAAM,QAAQ,IAAI,kBAAkB;AAAA,EAClC,MAAM;AAAA,EACN,QAAQ;AAAA,IACN,IAAI,EAAE,MAAM,IAAIF,gBAAe,SAAS,GAAG,SAAS,CAAC,MAAM,EAAE,GAAG;AAAA,IAChE,MAAM,EAAE,MAAM,IAAIA,gBAAeG,cAAa,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK;AAAA,IACxE,KAAK,EAAE,MAAM,IAAIH,gBAAeG,cAAa,GAAG,SAAS,CAAC,MAAM,EAAE,IAAI;AAAA,IACtE,UAAU,EAAE,MAAM,IAAIH,gBAAeG,cAAa,GAAG,SAAS,CAAC,MAAM,EAAE,UAAU;AAAA,IACjF,KAAK,EAAE,MAAMA,gBAAe,SAAS,CAAC,MAAM,EAAE,IAAI;AAAA,IAClD,UAAU,EAAE,MAAMF,aAAY,SAAS,CAAC,MAAM,EAAE,UAAU;AAAA,IAC1D,OAAO,EAAE,MAAMA,aAAY,SAAS,CAAC,MAAM,EAAE,MAAM;AAAA,IACnD,QAAQ,EAAE,MAAMA,aAAY,SAAS,CAAC,MAAM,EAAE,OAAO;AAAA,IACrD,UAAU,EAAE,MAAMA,aAAY,SAAS,CAAC,MAAM,EAAE,SAAS;AAAA,EAC3D;AACF,CAAC;AAEM,SAAS,mBACd,UACA,eAA4C,CAAC,GAC7C,MAIA,sBAAmD,cACpC;AACf,QAAM,cAAc,oBAAI,IAA+B;AACvD,QAAM,YAAY,oBAAI,IAA6B;AAGnD,aAAW,CAAC,MAAM,QAAQ,KAAK,OAAO,QAAQ,SAAS,UAAU,GAAiC;AAChG,QAAI,SAAS,OAAO,MAAM,kBAAkB,GAAG;AAC7C,gBAAU;AAAA,QACR;AAAA,QACA,IAAIG,iBAAgB;AAAA,UAClB,MAAM,gBAAgB,IAAI;AAAA,UAC1B,QAAQ,OAAO,YAAY,SAAS,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;AAAA,QAC1E,CAAC;AAAA,MACH;AAAA,IACF,OAAO;AACL,cAAQ,OAAO;AAAA,QACb,gBAAW,IAAI;AAAA;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AAGA,WAAS,mBAAmB,OAAoB,UAAsC;AACpF,UAAM,SAAS,iBAAiB,MAAM,UAAU;AAChD,QAAI,OAAQ,QAAO,WAAW,IAAIJ,gBAAe,MAAM,IAAI;AAE3D,QAAI,MAAM,eAAe,QAAQ;AAC/B,YAAM,MAAM,MAAM,aAAa,cAAc,WAAW,MAAM,aAAa,WAAW;AACtF,YAAM,KAAK,MAAM,UAAU,IAAI,GAAG,IAAI;AACtC,YAAM,IAAI,MAAMG;AAChB,aAAO,WAAW,IAAIH,gBAAe,CAAC,IAAI;AAAA,IAC5C;AAEA,QAAI,MAAM,eAAe,WAAW,MAAM,eAAe,WAAW,MAAM,eAAe,QAAQ;AAC/F,aAAO;AAAA,IACT;AAEA,QAAI,MAAM,eAAe,aAAa;AACpC,YAAM,MAAM,MAAM,aAAa,cAAc,oBAAoB,MAAM,aAAa,MAAM;AAC1F,YAAM,SAAS,MAAM,YAAY,IAAI,GAAG,IAAI;AAC5C,UAAI,OAAO,CAAC,QAAQ;AAClB,gBAAQ,OAAO;AAAA,UACb,2BAAsB,MAAM,IAAI,qCAAqC,GAAG;AAAA;AAAA,QAC1E;AAAA,MACF;AACA,aAAO,IAAIK,aAAY,IAAIL,gBAAe,UAAU,KAAK,CAAC;AAAA,IAC5D;AAEA,QAAI,MAAM,eAAe,aAAa;AACpC,YAAM,MAAM,MAAM,aAAa,cAAc,qBAAqB,MAAM,aAAa,MAAM;AAC3F,YAAM,SAAS,MAAM,YAAY,IAAI,GAAG,IAAI;AAC5C,UAAI,OAAO,CAAC,QAAQ;AAClB,gBAAQ,OAAO,MAAM,2BAAsB,MAAM,IAAI,2BAA2B,GAAG;AAAA,CAAwB;AAAA,MAC7G;AACA,YAAM,MAAM,MAAM,aAAa,cAAc,qBAAqB,MAAM,aAAa,MAAM;AAC3F,YAAM,SAAS,QAAQ,kBAAkB,QAAQ;AACjD,YAAM,IAAK,UAAU;AACrB,aAAO,SAAS,IAAIK,aAAY,IAAIL,gBAAe,CAAC,CAAC,IAAI;AAAA,IAC3D;AAEA,WAAOG;AAAA,EACT;AAaA,WAAS,cAAc,MAAgD;AACrE,WAAO,KAAK,OAAO,OAAO,CAAC,MAAM,EAAE,YAAY,IAAI;AAAA,EACrD;AAMA,WAAS,cAAc,aAAqB,MAA8C;AACxF,WACE,OAAO,WAAW,GAAG,UACrB,cAAc,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,WAAW,EAAE,MAAM,UAAU,EAAE,SAAS,EAAE;AAAA,EAE1F;AAIA,WAAS,gBACP,aACA,MACmB;AACnB,UAAM,UAAU,cAAc,aAAa,IAAI;AAO/C,UAAM,kBAAkB,KAAK,OAC1B;AAAA,MACC,CAAC,MACC,EAAE,YAAY,SACb,EAAE,eAAe,WAAW,EAAE,eAAe,WAAW,EAAE,eAAe;AAAA,IAC9E,EACC,IAAI,CAAC,MAAM,EAAE,IAAI;AAEpB,WAAO,IAAI,kBAAkB;AAAA,MAC3B,MAAM,gBAAgB,WAAW;AAAA,MACjC,QAAQ,MAAM;AACZ,cAAM,SAAyE,CAAC;AAEhF,eAAO,IAAI,IAAI,EAAE,MAAM,IAAIH,gBAAe,SAAS,GAAG,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE;AAC9E,YAAI,KAAK,gBAAgB,kBAAkB;AACzC,iBAAO,WAAW,IAAI,EAAE,MAAM,IAAIA,gBAAeE,eAAc,GAAG,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE;AAAA,QACnG;AACA,YAAI,KAAK,gBAAgB,gBAAgB;AACvC,iBAAO,MAAM,IAAI,EAAE,MAAM,IAAIF,gBAAeG,cAAa,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE;AAAA,QACxF;AACA,eAAO,WAAW,IAAI,EAAE,MAAM,IAAIH,gBAAe,cAAc,GAAG,SAAS,CAAC,MAAM,EAAE,YAAY,EAAE;AAClG,eAAO,WAAW,IAAI,EAAE,MAAM,IAAIA,gBAAe,cAAc,GAAG,SAAS,CAAC,MAAM,EAAE,YAAY,EAAE;AAElG,mBAAW,MAAM,SAAS;AACxB,gBAAM,QAAQ,GAAG;AACjB,gBAAM,UAAU,YAAY,GAAG,SAAS;AACxC,gBAAM,UAAU,mBAAmB,OAAO,GAAG,QAAQ;AACrD,cAAI;AACJ,cAAI,MAAM,eAAe,gBAAgB;AACvC,sBAAU,0BAA0B,aAAa,MAAM,MAAM,iBAAiB,oBAAoB,WAAW,CAAC;AAAA,UAChH,WACE,MAAM,eAAe,eACrB,MAAM,eAAe,eACrB,MAAM,eAAe,WACrB,MAAM,eAAe,WACrB,MAAM,eAAe,QACrB;AACA,sBAAU,sBAAsB,aAAa,MAAM,IAAI;AAAA,UACzD,OAAO;AACL,sBAAU,oBAAoB,OAAO,GAAG,QAAQ;AAAA,UAClD;AACA,iBAAO,OAAO,IAAI;AAAA,YAChB,MAAM;AAAA,YACN;AAAA;AAAA;AAAA,YAGA,GAAI,GAAG,sBAAsB,UAAa,EAAE,mBAAmB,GAAG,kBAAkB;AAAA,UACtF;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAAA,IACF,CAAC;AAAA,EACH;AAMA,QAAM,iBAAiB,oBAAI,IAAoB;AAC/C,WAAS,iBAAiB,aAA2B;AACnD,UAAM,UAAU,gBAAgB,WAAW;AAC3C,UAAM,QAAQ,eAAe,IAAI,OAAO;AACxC,QAAI,UAAU,UAAa,UAAU,aAAa;AAChD,YAAM,IAAI;AAAA,QACR,iCAAiC,OAAO,0BAA0B,KAAK,UAAU,WAAW;AAAA,MAE9F;AAAA,IACF;AACA,mBAAe,IAAI,SAAS,WAAW;AAAA,EACzC;AAEA,aAAW,CAAC,MAAM,EAAE,KAAK,OAAO,QAAQ,SAAS,aAAa,GAAG;AAC/D,qBAAiB,IAAI;AACrB,gBAAY,IAAI,MAAM,gBAAgB,MAAM,EAAE,CAAC;AAAA,EACjD;AACA,aAAW,CAAC,MAAM,EAAE,KAAK,OAAO,QAAQ,SAAS,cAAc,GAAG;AAChE,qBAAiB,IAAI;AACrB,gBAAY,IAAI,MAAM,gBAAgB,MAAM,EAAE,CAAC;AAAA,EACjD;AACA,aAAW,CAAC,MAAM,EAAE,KAAK,OAAO,QAAQ,SAAS,eAAe,GAAG;AACjE,qBAAiB,IAAI;AACrB,gBAAY,IAAI,MAAM,gBAAgB,MAAM,EAAE,CAAC;AAAA,EACjD;AAGA,QAAM,cAA8D,CAAC;AAErE,aAAW,CAAC,MAAM,EAAE,KAAK,OAAO,QAAQ,SAAS,aAAa,GAAoC;AAChG,UAAM,UAAU,YAAY,IAAI,IAAI;AACpC,UAAM,UAAU,cAAc,MAAM,EAAE;AAOtC,UAAM,UAAU,kBAAkB;AAAA,MAChC,GAAG,QAAQ,IAAI,CAAC,MAAM,EAAE,SAAS;AAAA,MACjC,GAAG,GAAG,cAAc,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,IACvC,CAAC;AAED,QAAI,GAAG,UAAU;AACf,kBAAY,gBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,SAAS,SAAS,kBAAkB,IAAI,EAAE;AACvF;AAAA,IACF;AAEA,UAAM,WAAW,IAAI,kBAAkB;AAAA,MACrC,MAAM,GAAG,gBAAgB,IAAI,CAAC;AAAA,MAC9B,QAAQ;AAAA,QACN,MAAM,EAAE,MAAM,IAAIA,gBAAe,IAAIK,aAAY,IAAIL,gBAAe,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK;AAAA,QACvG,MAAM,EAAE,MAAM,IAAIA,gBAAe,SAAS,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK;AAAA,MACtE;AAAA,IACF,CAAC;AACD,UAAM,aAAa,qBAAqB,IAAI,OAAO;AAEnD,gBAAY,oBAAoB,IAAI,CAAC,IAAI;AAAA,MACvC,MAAM,IAAIA,gBAAe,QAAQ;AAAA,MACjC,MAAM;AAAA,QACJ,MAAM,EAAE,MAAMC,YAAW;AAAA,QACzB,SAAS,EAAE,MAAMA,YAAW;AAAA,QAC5B,QAAQ,EAAE,MAAM,mBAAmB,gBAAgB,IAAI,GAAG,aAAa,IAAI,CAAC,EAAE;AAAA,QAC9E,WAAW,EAAE,MAAM,cAAc;AAAA,QACjC,GAAI,aAAa,EAAE,QAAQ,EAAE,MAAM,WAAW,EAAE,IAAI,CAAC;AAAA,MACvD;AAAA,MACA,SAAS,mBAAmB,MAAM,SAAS,aAAa,IAAI,CAAC;AAAA,IAC/D;AACA,gBAAY,gBAAgB,IAAI,CAAC,IAAI;AAAA,MACnC,MAAM;AAAA,MACN,MAAM,EAAE,MAAM,EAAE,MAAM,IAAID,gBAAeG,cAAa,EAAE,EAAE;AAAA,MAC1D,SAAS,qBAAqB,IAAI;AAAA,IACpC;AAAA,EACF;AAEA,aAAW,CAAC,MAAM,EAAE,KAAK,OAAO,QAAQ,SAAS,cAAc,GAAqC;AAClG,UAAM,UAAU,YAAY,IAAI,IAAI;AACpC,UAAM,WAAW,IAAI,kBAAkB;AAAA,MACrC,MAAM,GAAG,gBAAgB,IAAI,CAAC;AAAA,MAC9B,QAAQ;AAAA,QACN,MAAM,EAAE,MAAM,IAAIH,gBAAe,IAAIK,aAAY,IAAIL,gBAAe,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK;AAAA,QACvG,MAAM,EAAE,MAAM,IAAIA,gBAAe,SAAS,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK;AAAA,MACtE;AAAA,IACF,CAAC;AACD,gBAAY,oBAAoB,IAAI,CAAC,IAAI;AAAA,MACvC,MAAM,IAAIA,gBAAe,QAAQ;AAAA,MACjC,MAAM,EAAE,MAAM,EAAE,MAAMC,YAAW,GAAG,SAAS,EAAE,MAAMA,YAAW,EAAE;AAAA,MAClE,SAAS;AAAA,QACP;AAAA,QACA,kBAAkB,cAAc,MAAM,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC;AAAA,QACjE,aAAa,IAAI;AAAA,MACnB;AAAA,IACF;AACA,gBAAY,gBAAgB,IAAI,CAAC,IAAI;AAAA,MACnC,MAAM;AAAA,MACN,MAAM,EAAE,IAAI,EAAE,MAAM,IAAID,gBAAe,SAAS,EAAE,EAAE;AAAA,MACpD,SAAS,uBAAuB,IAAI;AAAA,IACtC;AAAA,EACF;AAEA,SAAO,IAAI,cAAc;AAAA,IACvB,OAAO,IAAI,kBAAkB,EAAE,MAAM,SAAS,QAAQ,YAAY,CAAC;AAAA,EACrE,CAAC;AACH;;;AMjTA,SAAS,SAAS,QAAiD;AACjE,QAAM,MAAM,oBAAI,IAAyB;AACzC,aAAW,KAAK,QAAQ;AACtB,QAAI,CAAC,eAAe,CAAC,EAAG;AACxB,QAAI,IAAI,EAAE,UAAU,aAAa,CAAC;AAAA,EACpC;AACA,SAAO;AACT;AAWA,SAAS,eACP,OACA,eACA,gBACoB;AACpB,QAAM,eAAe,cAAc,IAAI,MAAM,WAAW;AACxD,MAAI,iBAAiB,QAAW;AAC9B,WAAO,cAAc,cAAc;AAAA,EACrC;AACA,MAAI,iBAAiB,MAAM,YAAY;AACrC,WAAO,eAAe,YAAY,QAAQ,cAAc;AAAA,EAC1D;AACA,SAAO;AACT;AASO,SAAS,iBAAiB,OAKjB;AACd,QAAM,EAAE,UAAU,YAAY,mBAAmB,eAAe,IAAI;AACpE,QAAM,MAAmB,CAAC;AAE1B,QAAM,UAA4D;AAAA,IAChE,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAEA,aAAW,UAAU,SAAS;AAC5B,eAAW,CAAC,UAAU,IAAI,KAAK,OAAO,QAAQ,MAAM,GAAG;AACrD,YAAM,iBAAiB,YAAY,MAAM,QAAQ;AAGjD,UAAI,mBAAmB,QAAW;AAChC,YAAI,QAAQ,IAAI;AAAA,UACd,QAAQ,KAAK,OACV,OAAO,CAAC,MAAM,EAAE,YAAY,IAAI,EAChC,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,WAAW,EAAE,MAAM,UAAU,EAAE,SAAS,EAAE;AAAA,QACvE;AACA;AAAA,MACF;AAEA,YAAM,UAAU,SAAS,KAAK,MAAM;AACpC,YAAM,gBAAgB,oBAAI,IAAoB;AAC9C,iBAAW,KAAK,mBAAmB,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG;AAChE,sBAAc,IAAI,EAAE,aAAa,EAAE,UAAU;AAAA,MAC/C;AAEA,YAAM,SAAsB,CAAC;AAE7B,iBAAW,MAAM,eAAe,QAAQ;AACtC,cAAM,QAAQ,QAAQ,IAAI,GAAG,WAAW;AAIxC,YAAI,UAAU,OAAW;AACzB,cAAM,SAAS,eAAe,IAAI,eAAe,cAAc;AAC/D,eAAO,KAAK;AAAA,UACV;AAAA,UACA,WAAW,GAAG;AAAA,UACd,UAAU,GAAG;AAAA,UACb,GAAI,GAAG,aAAa,UAAa,EAAE,UAAU,GAAG,SAAS;AAAA,UACzD,GAAI,WAAW,UAAa,EAAE,mBAAmB,OAAO;AAAA,QAC1D,CAAC;AAAA,MACH;AAOA,iBAAW,KAAK,KAAK,QAAQ;AAC3B,YAAI,eAAe,CAAC,KAAK,EAAE,YAAY,KAAM;AAC7C,eAAO,KAAK,EAAE,OAAO,GAAG,WAAW,EAAE,MAAM,UAAU,EAAE,SAAS,CAAC;AAAA,MACnE;AAEA,UAAI,QAAQ,IAAI,EAAE,OAAO;AAAA,IAC3B;AAAA,EACF;AAEA,SAAO;AACT;;;ACnJA,OAAO,gBAAgB;AAmBhB,SAAS,sBACd,IACA,UACiB;AACjB,QAAM,UAAU,oBAAI,IAAyC;AAC7D,QAAM,UAAU,oBAAI,IAA4C;AAChE,QAAM,QAAQ,oBAAI,IAAqB;AAEvC,WAAS,aAAa,UAA+C;AACnE,QAAI,IAAI,QAAQ,IAAI,QAAQ;AAC5B,QAAI,CAAC,GAAG;AACN,YAAM,OAAQ,SAAS,cAAc,QAAQ,KAC3C,SAAS,eAAe,QAAQ,KAChC,SAAS,gBAAgB,QAAQ;AAKnC,UAAI,OAAO,kBAAkB,KAAK,QAAQ,QAAQ,IAAI,CAAC;AACvD,cAAQ,IAAI,UAAU,CAAC;AAAA,IACzB;AACA,WAAO;AAAA,EACT;AAEA,WAAS,UAAU,UAAkB,WAAmB,KAAkD;AACxG,UAAM,MAAM,GAAG,QAAQ,IAAI,SAAS;AACpC,QAAI,KAAK,QAAQ,IAAI,GAAG;AACxB,QAAI,CAAC,IAAI;AACP,WAAK,IAAI;AAAA,QACP,OAAO,YAAY;AACjB,gBAAM,OAAO;AAGb,gBAAM,qBAAqB,IAAI,MAAM,WAAW,KAAK,OAAO,IAAI;AAKhE,gBAAM,YAAY,IAAI,SAAS,eAAe,IAAI,SAAS,UAAU,IAAI,YAAY;AACrF,iBAAO,KAAK,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC;AAAA,QACrC;AAAA;AAAA;AAAA,QAGA,EAAE,OAAO,MAAM;AAAA,MACjB;AACA,cAAQ,IAAI,KAAK,EAAE;AAAA,IACrB;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,MAAM,KAAK,UAAU,WAAW,QAAQ;AACtC,YAAM,MAAM,aAAa,QAAQ,EAAE,SAAS;AAC5C,UAAI,CAAC,IAAK,QAAO;AACjB,aAAO,UAAU,UAAU,WAAW,GAAG,EAAE,KAAK,MAAM;AAAA,IACxD;AAAA,EACF;AACF;;;AC5EA,SAAS,oBAAoB;AAC7B,SAAS,uCAAuC;AAQzC,SAAS,iBAAiB,SAE/B;AACA,QAAM,QAAQ,IAAI,aAAa;AAAA,IAC7B,UAAU,EAAE,GAAG,QAAQ,SAAS;AAAA,IAChC,WAAW,EAAE,SAAS,QAAQ,cAAc;AAAA,IAC5C,YAAY,EAAE,GAAG,GAAG;AAAA,IACpB,eAAe,EAAE,GAAG,GAAG;AAAA,IACvB,sBAAsB,EAAE,SAAS,KAAK;AAAA;AAAA;AAAA;AAAA,EAIxC,CAAC;AACD,SAAO,MAAM,QAAQ;AACvB;AAIO,SAAS,oBAAoB,SAElC;AACA,SAAO;AAAA,IACL,WAAW,EAAE,kBAAkB,GAAG;AAChC,UAAI,CAAC,QAAS,mBAAkB,+BAA+B;AAAA,IACjE;AAAA,EACF;AACF;;;ATFA,SAAS,yBAAyB,OAAyB;AACzD,MAAI,UAAU;AACd,SAAO,WAAW,QAAQ,OAAO,YAAY,YAAY,QAAQ,SAAS,gBAAgB;AACxF,QAAI,QAAQ,iBAAiB,KAAM,QAAO;AAC1C,cAAU,QAAQ;AAAA,EACpB;AACA,SAAO;AACT;AAEO,SAAS,qBACd,UACA,OACA,cACA,UACA,IACA,SAIA,aAQI,CAAC,GACI;AACT,MAAI;AACJ,MAAI,WAAW,eAAe,QAAW;AACvC,QAAI,WAAW,mBAAmB,QAAW;AAC3C,YAAM,IAAI;AAAA,QACR;AAAA,MAEF;AAAA,IACF;AACA,WAAO,iBAAiB;AAAA,MACtB;AAAA,MACA,YAAY,WAAW;AAAA,MACvB,mBAAmB,WAAW;AAAA,MAC9B,gBAAgB,WAAW;AAAA,IAC7B,CAAC;AAAA,EACH;AACA,QAAM,SAAS,mBAAmB,UAAU,cAAc,MAAM,WAAW,uBAAuB,YAAY;AAC9G,QAAM,EAAE,QAAQ,IAAI,iBAAiB;AAAA,IACnC,UAAU,QAAQ;AAAA,IAClB,eAAe,QAAQ;AAAA,EACzB,CAAC;AAED,QAAM,OAAO,WAAkD;AAAA,IAC7D;AAAA,IACA,iBAAiB,WAAW,YAAY;AAAA,IACxC,UAAU,QAAQ;AAAA,IAClB,aAAa;AAAA,IACb,cAAc;AAAA,MACZ,WAAW,CAAC,OAAO,SAAS,UAC1B,yBAAyB,KAAK,IAAK,QAAkB,UAAU,OAAO,SAAS,KAAK;AAAA,IACxF;AAAA;AAAA;AAAA;AAAA;AAAA,IAKA,SAAS,CAAC,GAAI,SAAmB,oBAAoB,QAAQ,aAAa,CAAC;AAAA,IAC3E,SAAS,OAAuB;AAAA,MAC9B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS,sBAAsB,IAAI,QAAQ;AAAA,MAC3C,kBAAkB,oBAAI,QAAQ;AAAA,IAChC;AAAA,EACF,CAAC;AAED,SAAO,CAAC,MAAM,KAAK,MAAM,EAAE,IAAI,KAAK,CAAC,CAAC;AACxC;","names":["GraphQLEnumType","GraphQLNonNull","GraphQLList","GraphQLString","GraphQLInt","GraphQLBoolean","GraphQLString","GraphQLBoolean","GraphQLInt","GraphQLFloat","GraphQLString","GraphQLBoolean","GraphQLInt","GraphQLFloat","GraphQLNonNull","GraphQLInt","GraphQLBoolean","GraphQLString","GraphQLEnumType","GraphQLList"]}