UNPKG

@apollo/federation-internals

Version:
286 lines 13.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CONNECT_VERSIONS = exports.ConnectSpecDefinition = exports.connectIdentity = void 0; const graphql_1 = require("graphql"); const coreSpec_1 = require("./coreSpec"); const definitions_1 = require("../definitions"); const knownCoreFeatures_1 = require("../knownCoreFeatures"); const directiveAndTypeSpecification_1 = require("../directiveAndTypeSpecification"); const error_1 = require("../error"); const types_1 = require("../types"); const utils_1 = require("../utils"); const values_1 = require("../values"); exports.connectIdentity = 'https://specs.apollo.dev/connect'; const CONNECT = 'connect'; const SOURCE = 'source'; const URL_PATH_TEMPLATE = 'URLPathTemplate'; const JSON_SELECTION = 'JSONSelection'; const CONNECT_HTTP = 'ConnectHTTP'; const CONNECT_BATCH = 'ConnectBatch'; const CONNECTOR_ERRORS = "ConnectorErrors"; const SOURCE_HTTP = "SourceHTTP"; const HTTP_HEADER_MAPPING = 'HTTPHeaderMapping'; class ConnectSpecDefinition extends coreSpec_1.FeatureDefinition { constructor(version, minimumFederationVersion) { super(new coreSpec_1.FeatureUrl(exports.connectIdentity, CONNECT, version), minimumFederationVersion); this.minimumFederationVersion = minimumFederationVersion; function lookupFeatureTypeInSchema(name, kind, schema, feature) { (0, utils_1.assert)(feature, `Shouldn't be added without being attached to a @connect spec`); const typeName = feature.typeNameInSchema(name); const type = schema.typeOfKind(typeName, kind); (0, utils_1.assert)(type, () => `Expected "${typeName}" to be defined`); return type; } this.registerType((0, directiveAndTypeSpecification_1.createScalarTypeSpecification)({ name: URL_PATH_TEMPLATE })); this.registerType((0, directiveAndTypeSpecification_1.createScalarTypeSpecification)({ name: JSON_SELECTION })); this.registerType(createInputObjectTypeSpecification({ name: CONNECTOR_ERRORS, inputFieldsFct: (schema, feature) => { const jsonSelectionType = lookupFeatureTypeInSchema(JSON_SELECTION, 'ScalarType', schema, feature); return [ { name: 'message', type: jsonSelectionType }, { name: 'extensions', type: jsonSelectionType }, ]; } })); this.registerType(createInputObjectTypeSpecification({ name: HTTP_HEADER_MAPPING, inputFieldsFct: (schema) => [ { name: 'name', type: new definitions_1.NonNullType(schema.stringType()) }, { name: 'from', type: schema.stringType() }, { name: 'value', type: schema.stringType() }, ] })); this.registerType(createInputObjectTypeSpecification({ name: CONNECT_BATCH, inputFieldsFct: (schema) => [ { name: 'maxSize', type: schema.intType() } ] })); this.registerType(createInputObjectTypeSpecification({ name: SOURCE_HTTP, inputFieldsFct: (schema, feature) => { const jsonSelectionType = lookupFeatureTypeInSchema(JSON_SELECTION, 'ScalarType', schema, feature); const httpHeaderMappingType = lookupFeatureTypeInSchema(HTTP_HEADER_MAPPING, 'InputObjectType', schema, feature); return [ { name: 'baseURL', type: new definitions_1.NonNullType(schema.stringType()) }, { name: 'headers', type: new definitions_1.ListType(new definitions_1.NonNullType(httpHeaderMappingType)) }, { name: 'path', type: jsonSelectionType }, { name: 'queryParams', type: jsonSelectionType } ]; } })); this.registerType(createInputObjectTypeSpecification({ name: CONNECT_HTTP, inputFieldsFct: (schema, feature) => { const urlPathTemplateType = lookupFeatureTypeInSchema(URL_PATH_TEMPLATE, 'ScalarType', schema, feature); const jsonSelectionType = lookupFeatureTypeInSchema(JSON_SELECTION, 'ScalarType', schema, feature); const httpHeaderMappingType = lookupFeatureTypeInSchema(HTTP_HEADER_MAPPING, 'InputObjectType', schema, feature); return [ { name: 'GET', type: urlPathTemplateType }, { name: 'POST', type: urlPathTemplateType }, { name: 'PUT', type: urlPathTemplateType }, { name: 'PATCH', type: urlPathTemplateType }, { name: 'DELETE', type: urlPathTemplateType }, { name: 'body', type: jsonSelectionType }, { name: 'headers', type: new definitions_1.ListType(new definitions_1.NonNullType(httpHeaderMappingType)) }, { name: 'path', type: jsonSelectionType }, { name: 'queryParams', type: jsonSelectionType }, ]; } })); this.registerDirective((0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ name: CONNECT, locations: [graphql_1.DirectiveLocation.FIELD_DEFINITION, graphql_1.DirectiveLocation.OBJECT], repeatable: true, args: [ { name: 'source', type: (schema) => schema.stringType() }, { name: 'id', type: (schema) => schema.stringType() }, { name: 'http', type: (schema, feature) => { const connectHttpType = lookupFeatureTypeInSchema(CONNECT_HTTP, 'InputObjectType', schema, feature); return connectHttpType; } }, { name: 'batch', type: (schema, feature) => lookupFeatureTypeInSchema(CONNECT_BATCH, 'InputObjectType', schema, feature) }, { name: 'errors', type: (schema, feature) => lookupFeatureTypeInSchema(CONNECTOR_ERRORS, 'InputObjectType', schema, feature) }, { name: 'selection', type: (schema, feature) => { const jsonSelectionType = lookupFeatureTypeInSchema(JSON_SELECTION, 'ScalarType', schema, feature); return new definitions_1.NonNullType(jsonSelectionType); } }, { name: 'entity', type: (schema) => schema.booleanType(), defaultValue: false }, { name: 'isSuccess', type: (schema, feature) => lookupFeatureTypeInSchema(JSON_SELECTION, 'ScalarType', schema, feature) } ], composes: false, })); this.registerDirective((0, directiveAndTypeSpecification_1.createDirectiveSpecification)({ name: SOURCE, locations: [graphql_1.DirectiveLocation.SCHEMA], repeatable: true, composes: false, args: [ { name: 'name', type: (schema) => new definitions_1.NonNullType(schema.stringType()) }, { name: 'http', type: (schema, feature) => { const sourceHttpType = lookupFeatureTypeInSchema(SOURCE_HTTP, 'InputObjectType', schema, feature); return new definitions_1.NonNullType(sourceHttpType); } }, { name: 'errors', type: (schema, feature) => lookupFeatureTypeInSchema(CONNECTOR_ERRORS, 'InputObjectType', schema, feature) }, { name: 'isSuccess', type: (schema, feature) => lookupFeatureTypeInSchema(JSON_SELECTION, 'ScalarType', schema, feature) } ] })); } get defaultCorePurpose() { return 'EXECUTION'; } } exports.ConnectSpecDefinition = ConnectSpecDefinition; exports.CONNECT_VERSIONS = new coreSpec_1.FeatureDefinitions(exports.connectIdentity) .add(new ConnectSpecDefinition(new coreSpec_1.FeatureVersion(0, 1), new coreSpec_1.FeatureVersion(2, 10))) .add(new ConnectSpecDefinition(new coreSpec_1.FeatureVersion(0, 2), new coreSpec_1.FeatureVersion(2, 10))) .add(new ConnectSpecDefinition(new coreSpec_1.FeatureVersion(0, 3), new coreSpec_1.FeatureVersion(2, 12))) .add(new ConnectSpecDefinition(new coreSpec_1.FeatureVersion(0, 4), new coreSpec_1.FeatureVersion(2, 13)), { preview: true }); (0, knownCoreFeatures_1.registerKnownFeature)(exports.CONNECT_VERSIONS); function createInputObjectTypeSpecification({ name, inputFieldsFct, }) { return { name, checkOrAdd: (schema, feature, asBuiltIn) => { var _a; const actualName = (_a = feature === null || feature === void 0 ? void 0 : feature.typeNameInSchema(name)) !== null && _a !== void 0 ? _a : name; const expectedFields = inputFieldsFct(schema, feature); const existing = schema.type(actualName); if (existing) { let errors = (0, directiveAndTypeSpecification_1.ensureSameTypeKind)('InputObjectType', existing); if (errors.length > 0) { return errors; } (0, utils_1.assert)((0, definitions_1.isInputObjectType)(existing), 'Should be an input object type'); for (const { name: fieldName, type, defaultValue } of expectedFields) { const existingField = existing.field(fieldName); if (!existingField) { if ((0, definitions_1.isNonNullType)(type) && defaultValue === undefined) { errors.push(error_1.ERRORS.TYPE_DEFINITION_INVALID.err(`Invalid definition for type ${name}: missing required input field "${fieldName}"`, { nodes: existing.sourceAST })); } continue; } let existingType = existingField.type; if ((0, definitions_1.isNonNullType)(existingType) && !(0, definitions_1.isNonNullType)(type)) { existingType = existingType.ofType; } if (!(0, types_1.sameType)(type, existingType)) { errors.push(error_1.ERRORS.TYPE_DEFINITION_INVALID.err(`Invalid definition for type ${name}: input field "${fieldName}" should have type "${type}" but found type "${existingField.type}"`, { nodes: existingField.sourceAST })); } else if (!(0, values_1.valueEquals)(defaultValue, existingField.defaultValue)) { errors.push(error_1.ERRORS.TYPE_DEFINITION_INVALID.err(`Invalid definition type ${name}: input field "${fieldName}" should have default value ${(0, values_1.valueToString)(defaultValue)} but found default value ${(0, values_1.valueToString)(existingField.defaultValue)}`, { nodes: existingField.sourceAST })); } } for (const existingField of existing.fields()) { if (!expectedFields.some((field) => field.name === existingField.name)) { errors.push(error_1.ERRORS.TYPE_DEFINITION_INVALID.err(`Invalid definition for type ${name}: unknown/unsupported input field "${existingField.name}"`, { nodes: existingField.sourceAST })); } } return errors; } else { const createdType = schema.addType(new definitions_1.InputObjectType(actualName, asBuiltIn)); for (const { name, type, defaultValue } of expectedFields) { const newField = createdType.addField(name, type); newField.defaultValue = defaultValue; } return []; } }, }; } //# sourceMappingURL=connectSpec.js.map