Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@apollo/federation-internals

Package Overview
Dependencies
Maintainers
1
Versions
131
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@apollo/federation-internals - npm Package Compare versions

Comparing version 2.7.0 to 2.7.1

1

dist/error.d.ts

@@ -126,2 +126,3 @@ import { ASTNode, GraphQLError, GraphQLErrorOptions, GraphQLFormattedError } from "graphql";

INTERFACE_KEY_MISSING_IMPLEMENTATION_TYPE: ErrorCodeDefinition;
SOURCE_FEDERATION_VERSION_REQUIRED: ErrorCodeDefinition;
SOURCE_API_NAME_INVALID: ErrorCodeDefinition;

@@ -128,0 +129,0 @@ SOURCE_API_PROTOCOL_INVALID: ErrorCodeDefinition;

@@ -206,2 +206,3 @@ "use strict";

const INTERFACE_KEY_MISSING_IMPLEMENTATION_TYPE = makeCodeDefinition('INTERFACE_KEY_MISSING_IMPLEMENTATION_TYPE', 'A subgraph has a `@key` on an interface type, but that subgraph does not define an implementation (in the supergraph) of that interface', { addedIn: '2.3.0' });
const SOURCE_FEDERATION_VERSION_REQUIRED = makeCodeDefinition('SOURCE_FEDERATION_VERSION_REQUIRED', 'Schemas using `@source{API,Type,Field}` directives must @link-import v2.7 or later of federation', { addedIn: '2.7.1' });
const SOURCE_API_NAME_INVALID = makeCodeDefinition('SOURCE_API_NAME_INVALID', 'Each `@sourceAPI` directive must take a unique and valid name as an argument', { addedIn: '2.7.0' });

@@ -312,2 +313,3 @@ const SOURCE_API_PROTOCOL_INVALID = makeCodeDefinition('SOURCE_API_PROTOCOL_INVALID', 'Each `@sourceAPI` directive must specify exactly one of the known protocols', { addedIn: '2.7.0' });

INTERFACE_KEY_MISSING_IMPLEMENTATION_TYPE,
SOURCE_FEDERATION_VERSION_REQUIRED,
SOURCE_API_NAME_INVALID,

@@ -314,0 +316,0 @@ SOURCE_API_PROTOCOL_INVALID,

3

dist/specs/sourceSpec.d.ts

@@ -6,3 +6,4 @@ import { GraphQLError } from 'graphql';

export declare class SourceSpecDefinition extends FeatureDefinition {
constructor(version: FeatureVersion, minimumFederationVersion?: FeatureVersion);
readonly minimumFederationVersion: FeatureVersion;
constructor(version: FeatureVersion, minimumFederationVersion: FeatureVersion);
addElementsToSchema(schema: Schema): GraphQLError[];

@@ -9,0 +10,0 @@ allElementNames(): string[];

@@ -14,2 +14,3 @@ "use strict";

super(new coreSpec_1.FeatureUrl(exports.sourceIdentity, 'source', version), minimumFederationVersion);
this.minimumFederationVersion = minimumFederationVersion;
this.registerDirective((0, directiveAndTypeSpecification_1.createDirectiveSpecification)({

@@ -102,9 +103,10 @@ name: 'sourceAPI',

}
getSourceDirectives(schema) {
getSourceDirectives(schema, errors) {
const result = {};
let federationVersion;
schema.schemaDefinition.appliedDirectivesOf('link')
.forEach(linkDirective => {
var _a;
const { url, import: imports } = linkDirective.arguments();
if (imports && ((_a = coreSpec_1.FeatureUrl.maybeParse(url)) === null || _a === void 0 ? void 0 : _a.identity) === exports.sourceIdentity) {
const featureUrl = coreSpec_1.FeatureUrl.maybeParse(url);
if (imports && featureUrl && featureUrl.identity === exports.sourceIdentity) {
imports.forEach(nameOrRename => {

@@ -125,7 +127,16 @@ const originalName = typeof nameOrRename === 'string' ? nameOrRename : nameOrRename.name;

}
if (featureUrl && featureUrl.name === 'federation') {
federationVersion = featureUrl.version;
}
});
if (result.sourceAPI || result.sourceType || result.sourceField) {
if (!federationVersion || federationVersion.lt(this.minimumFederationVersion)) {
errors.push(error_1.ERRORS.SOURCE_FEDERATION_VERSION_REQUIRED.err(`Schemas that @link to ${exports.sourceIdentity} must also @link to federation version ${this.minimumFederationVersion} or later (found ${federationVersion})`));
}
}
return result;
}
validateSubgraphSchema(schema) {
const { sourceAPI, sourceType, sourceField, } = this.getSourceDirectives(schema);
const errors = super.validateSubgraphSchema(schema);
const { sourceAPI, sourceType, sourceField, } = this.getSourceDirectives(schema, errors);
if (!(sourceAPI || sourceType || sourceField)) {

@@ -135,3 +146,2 @@ return [];

const apiNameToProtocol = new Map();
const errors = [];
if (sourceAPI) {

@@ -151,11 +161,8 @@ this.validateSourceAPI(sourceAPI, apiNameToProtocol, errors);

const { name, ...rest } = application.arguments();
if (!isValidSourceAPIName(name)) {
errors.push(error_1.ERRORS.SOURCE_API_NAME_INVALID.err(`${sourceAPI}(name: ${JSON.stringify(name)}) must specify name using only [a-zA-Z0-9-_] characters`, { nodes: application.sourceAST }));
}
if (apiNameToProtocol.has(name)) {
errors.push(error_1.ERRORS.SOURCE_API_NAME_INVALID.err(`${sourceAPI} must specify unique name`, { nodes: application.sourceAST }));
errors.push(error_1.ERRORS.SOURCE_API_NAME_INVALID.err(`${sourceAPI} must specify unique name (${JSON.stringify(name)} reused)`, { nodes: application.sourceAST }));
}
try {
(0, graphql_1.assertName)(name);
}
catch (e) {
errors.push(error_1.ERRORS.SOURCE_API_NAME_INVALID.err(`${sourceAPI}(name: ${JSON.stringify(name)}) must specify valid GraphQL name`, { nodes: application.sourceAST }));
}
let protocol;

@@ -165,3 +172,3 @@ KNOWN_SOURCE_PROTOCOLS.forEach(knownProtocol => {

if (protocol) {
errors.push(error_1.ERRORS.SOURCE_API_PROTOCOL_INVALID.err(`${sourceAPI} must specify only one of ${KNOWN_SOURCE_PROTOCOLS.join(', ')}`, { nodes: application.sourceAST }));
errors.push(error_1.ERRORS.SOURCE_API_PROTOCOL_INVALID.err(`${sourceAPI} must specify only one of ${KNOWN_SOURCE_PROTOCOLS.join(', ')} but specified both ${protocol} and ${knownProtocol}`, { nodes: application.sourceAST }));
}

@@ -180,3 +187,3 @@ protocol = knownProtocol;

catch (e) {
errors.push(error_1.ERRORS.SOURCE_API_HTTP_BASE_URL_INVALID.err(`${sourceAPI} http.baseURL ${JSON.stringify(baseURL)} must be valid URL`, { nodes: application.sourceAST }));
errors.push(error_1.ERRORS.SOURCE_API_HTTP_BASE_URL_INVALID.err(`${sourceAPI} http.baseURL ${JSON.stringify(baseURL)} must be valid URL (error: ${e.message})`, { nodes: application.sourceAST }));
}

@@ -187,3 +194,3 @@ validateHTTPHeaders(headers, errors, sourceAPI.name);

else {
errors.push(error_1.ERRORS.SOURCE_API_PROTOCOL_INVALID.err(`${sourceAPI} must specify one of ${KNOWN_SOURCE_PROTOCOLS.join(', ')}`, { nodes: application.sourceAST }));
errors.push(error_1.ERRORS.SOURCE_API_PROTOCOL_INVALID.err(`${sourceAPI} must specify one protocol from the set {${KNOWN_SOURCE_PROTOCOLS.join(',')}}`, { nodes: application.sourceAST }));
}

@@ -199,34 +206,32 @@ });

}
else {
const expectedProtocol = apiNameToProtocol.get(api);
const protocolValue = expectedProtocol && rest[expectedProtocol];
if (expectedProtocol && !protocolValue) {
errors.push(error_1.ERRORS.SOURCE_TYPE_API_ERROR.err(`${sourceType} must specify same ${expectedProtocol} argument as corresponding @sourceAPI for api ${api}`, { nodes: application.sourceAST }));
const expectedProtocol = apiNameToProtocol.get(api) || HTTP_PROTOCOL;
const protocolValue = expectedProtocol && rest[expectedProtocol];
if (expectedProtocol && !protocolValue) {
errors.push(error_1.ERRORS.SOURCE_TYPE_PROTOCOL_INVALID.err(`${sourceType} must specify same ${expectedProtocol} argument as corresponding @sourceAPI for api ${api}`, { nodes: application.sourceAST }));
}
if (protocolValue && expectedProtocol === HTTP_PROTOCOL) {
const { GET, POST, headers, body } = protocolValue;
if ([GET, POST].filter(Boolean).length !== 1) {
errors.push(error_1.ERRORS.SOURCE_TYPE_HTTP_METHOD_INVALID.err(`${sourceType} must specify exactly one of http.GET or http.POST`, { nodes: application.sourceAST }));
}
if (protocolValue && expectedProtocol === HTTP_PROTOCOL) {
const { GET, POST, headers, body } = protocolValue;
if ([GET, POST].filter(Boolean).length !== 1) {
errors.push(error_1.ERRORS.SOURCE_TYPE_HTTP_METHOD_INVALID.err(`${sourceType} must specify exactly one of http.GET or http.POST`, { nodes: application.sourceAST }));
else {
const urlPathTemplate = (GET || POST);
try {
parseURLPathTemplate(urlPathTemplate);
}
else {
const urlPathTemplate = (GET || POST);
try {
parseURLPathTemplate(urlPathTemplate);
}
catch (e) {
errors.push(error_1.ERRORS.SOURCE_TYPE_HTTP_PATH_INVALID.err(`${sourceType} http.GET or http.POST must be valid URL path template`));
}
catch (e) {
errors.push(error_1.ERRORS.SOURCE_TYPE_HTTP_PATH_INVALID.err(`${sourceType} http.GET or http.POST must be valid URL path template (error: ${e.message})`));
}
validateHTTPHeaders(headers, errors, sourceType.name);
if (body) {
if (GET) {
errors.push(error_1.ERRORS.SOURCE_TYPE_HTTP_BODY_INVALID.err(`${sourceType} http.GET cannot specify http.body`, { nodes: application.sourceAST }));
}
try {
parseJSONSelection(body);
}
catch (e) {
errors.push(error_1.ERRORS.SOURCE_TYPE_HTTP_BODY_INVALID.err(`${sourceType} http.body not valid JSONSelection: ${e.message}`, { nodes: application.sourceAST }));
}
}
validateHTTPHeaders(headers, errors, sourceType.name);
if (body) {
if (GET) {
errors.push(error_1.ERRORS.SOURCE_TYPE_HTTP_BODY_INVALID.err(`${sourceType} http.GET cannot specify http.body`, { nodes: application.sourceAST }));
}
try {
parseJSONSelection(body);
}
catch (e) {
errors.push(error_1.ERRORS.SOURCE_TYPE_HTTP_BODY_INVALID.err(`${sourceType} http.body not valid JSONSelection (error: ${e.message})`, { nodes: application.sourceAST }));
}
}

@@ -245,3 +250,3 @@ }

catch (e) {
errors.push(error_1.ERRORS.SOURCE_TYPE_SELECTION_INVALID.err(`${sourceType} selection not valid JSONSelection: ${e.message}`, { nodes: application.sourceAST }));
errors.push(error_1.ERRORS.SOURCE_TYPE_SELECTION_INVALID.err(`${sourceType} selection not valid JSONSelection (error: ${e.message})`, { nodes: application.sourceAST }));
}

@@ -261,35 +266,33 @@ break;

}
else {
const expectedProtocol = apiNameToProtocol.get(api);
const protocolValue = expectedProtocol && rest[expectedProtocol];
if (protocolValue && expectedProtocol === HTTP_PROTOCOL) {
const { GET, POST, PUT, PATCH, DELETE, headers, body, } = protocolValue;
const usedMethods = [GET, POST, PUT, PATCH, DELETE].filter(Boolean);
if (usedMethods.length > 1) {
errors.push(error_1.ERRORS.SOURCE_FIELD_HTTP_METHOD_INVALID.err(`${sourceField} allows at most one of http.{GET,POST,PUT,PATCH,DELETE}`));
const expectedProtocol = apiNameToProtocol.get(api) || HTTP_PROTOCOL;
const protocolValue = expectedProtocol && rest[expectedProtocol];
if (protocolValue && expectedProtocol === HTTP_PROTOCOL) {
const { GET, POST, PUT, PATCH, DELETE, headers, body, } = protocolValue;
const usedMethods = [GET, POST, PUT, PATCH, DELETE].filter(Boolean);
if (usedMethods.length > 1) {
errors.push(error_1.ERRORS.SOURCE_FIELD_HTTP_METHOD_INVALID.err(`${sourceField} allows at most one of http.{GET,POST,PUT,PATCH,DELETE}`));
}
else if (usedMethods.length === 1) {
const urlPathTemplate = usedMethods[0];
try {
parseURLPathTemplate(urlPathTemplate);
}
else if (usedMethods.length === 1) {
const urlPathTemplate = usedMethods[0];
try {
parseURLPathTemplate(urlPathTemplate);
}
catch (e) {
errors.push(error_1.ERRORS.SOURCE_FIELD_HTTP_PATH_INVALID.err(`${sourceField} http.{GET,POST,PUT,PATCH,DELETE} must be valid URL path template`));
}
catch (e) {
errors.push(error_1.ERRORS.SOURCE_FIELD_HTTP_PATH_INVALID.err(`${sourceField} http.{GET,POST,PUT,PATCH,DELETE} must be valid URL path template (error: ${e.message})`));
}
validateHTTPHeaders(headers, errors, sourceField.name);
if (body) {
if (GET) {
errors.push(error_1.ERRORS.SOURCE_FIELD_HTTP_BODY_INVALID.err(`${sourceField} http.GET cannot specify http.body`, { nodes: application.sourceAST }));
}
else if (DELETE) {
errors.push(error_1.ERRORS.SOURCE_FIELD_HTTP_BODY_INVALID.err(`${sourceField} http.DELETE cannot specify http.body`, { nodes: application.sourceAST }));
}
try {
parseJSONSelection(body);
}
catch (e) {
errors.push(error_1.ERRORS.SOURCE_FIELD_HTTP_BODY_INVALID.err(`${sourceField} http.body not valid JSONSelection: ${e.message}`, { nodes: application.sourceAST }));
}
}
validateHTTPHeaders(headers, errors, sourceField.name);
if (body) {
if (GET) {
errors.push(error_1.ERRORS.SOURCE_FIELD_HTTP_BODY_INVALID.err(`${sourceField} http.GET cannot specify http.body`, { nodes: application.sourceAST }));
}
else if (DELETE) {
errors.push(error_1.ERRORS.SOURCE_FIELD_HTTP_BODY_INVALID.err(`${sourceField} http.DELETE cannot specify http.body`, { nodes: application.sourceAST }));
}
try {
parseJSONSelection(body);
}
catch (e) {
errors.push(error_1.ERRORS.SOURCE_FIELD_HTTP_BODY_INVALID.err(`${sourceField} http.body not valid JSONSelection (error: ${e.message})`, { nodes: application.sourceAST }));
}
}

@@ -302,7 +305,7 @@ }

catch (e) {
errors.push(error_1.ERRORS.SOURCE_FIELD_SELECTION_INVALID.err(`${sourceField} selection not valid JSONSelection: ${e.message}`, { nodes: application.sourceAST }));
errors.push(error_1.ERRORS.SOURCE_FIELD_SELECTION_INVALID.err(`${sourceField} selection not valid JSONSelection (error: ${e.message})`, { nodes: application.sourceAST }));
}
}
const fieldParent = application.parent;
if (((_a = fieldParent.sourceAST) === null || _a === void 0 ? void 0 : _a.kind) !== "FieldDefinition") {
if (((_a = fieldParent.sourceAST) === null || _a === void 0 ? void 0 : _a.kind) !== graphql_1.Kind.FIELD_DEFINITION) {
errors.push(error_1.ERRORS.SOURCE_FIELD_NOT_ON_ROOT_OR_ENTITY_FIELD.err(`${sourceField} must be applied to field`, { nodes: application.sourceAST }));

@@ -312,3 +315,3 @@ }

const typeGrandparent = fieldParent.parent;
if (((_b = typeGrandparent.sourceAST) === null || _b === void 0 ? void 0 : _b.kind) !== "ObjectTypeDefinition") {
if (((_b = typeGrandparent.sourceAST) === null || _b === void 0 ? void 0 : _b.kind) !== graphql_1.Kind.OBJECT_TYPE_DEFINITION) {
errors.push(error_1.ERRORS.SOURCE_FIELD_NOT_ON_ROOT_OR_ENTITY_FIELD.err(`${sourceField} must be applied to field of object type`, { nodes: application.sourceAST }));

@@ -329,2 +332,5 @@ }

exports.SourceSpecDefinition = SourceSpecDefinition;
function isValidSourceAPIName(name) {
return /^[a-z-_][a-z0-9-_]*$/i.test(name);
}
function isValidHTTPHeaderName(name) {

@@ -340,7 +346,10 @@ return /^[a-zA-Z0-9-_]+$/.test(name);

if (!isValidHTTPHeaderName(name)) {
errors.push(error_1.ERRORS.SOURCE_HTTP_HEADERS_INVALID.err(`${directiveName} headers[${i}].name == ${JSON.stringify(name)} is not valid HTTP header name`));
errors.push(error_1.ERRORS.SOURCE_HTTP_HEADERS_INVALID.err(`${directiveName} header ${JSON.stringify(headers[i])} specifies invalid name`));
}
if (!as === !value) {
errors.push(error_1.ERRORS.SOURCE_HTTP_HEADERS_INVALID.err(`${directiveName} headers[${i}] must specify exactly one of as or value`));
if (as && !isValidHTTPHeaderName(as)) {
errors.push(error_1.ERRORS.SOURCE_HTTP_HEADERS_INVALID.err(`${directiveName} header ${JSON.stringify(headers[i])} specifies invalid 'as' name`));
}
if (as && value) {
errors.push(error_1.ERRORS.SOURCE_HTTP_HEADERS_INVALID.err(`${directiveName} header ${JSON.stringify(headers[i])} should specify at most one of 'as' or 'value'`));
}
});

@@ -347,0 +356,0 @@ }

{
"name": "@apollo/federation-internals",
"version": "2.7.0",
"version": "2.7.1",
"description": "Apollo Federation internal utilities",

@@ -5,0 +5,0 @@ "main": "dist/index.js",

@@ -564,2 +564,8 @@ import { ASTNode, GraphQLError, GraphQLErrorOptions, GraphQLFormattedError } from "graphql";

const SOURCE_FEDERATION_VERSION_REQUIRED = makeCodeDefinition(
'SOURCE_FEDERATION_VERSION_REQUIRED',
'Schemas using `@source{API,Type,Field}` directives must @link-import v2.7 or later of federation',
{ addedIn: '2.7.1' },
);
const SOURCE_API_NAME_INVALID = makeCodeDefinition(

@@ -761,2 +767,3 @@ 'SOURCE_API_NAME_INVALID',

// Errors related to @sourceAPI, @sourceType, and/or @sourceField
SOURCE_FEDERATION_VERSION_REQUIRED,
SOURCE_API_NAME_INVALID,

@@ -763,0 +770,0 @@ SOURCE_API_PROTOCOL_INVALID,

@@ -1,2 +0,2 @@

import { DirectiveLocation, GraphQLError, assertName } from 'graphql';
import { DirectiveLocation, GraphQLError, Kind } from 'graphql';
import { FeatureDefinition, FeatureDefinitions, FeatureUrl, FeatureVersion, LinkDirectiveArgs } from "./coreSpec";

@@ -19,3 +19,3 @@ import {

export class SourceSpecDefinition extends FeatureDefinition {
constructor(version: FeatureVersion, minimumFederationVersion?: FeatureVersion) {
constructor(version: FeatureVersion, readonly minimumFederationVersion: FeatureVersion) {
super(new FeatureUrl(sourceIdentity, 'source', version), minimumFederationVersion);

@@ -151,3 +151,3 @@

private getSourceDirectives(schema: Schema) {
private getSourceDirectives(schema: Schema, errors: GraphQLError[]) {
const result: {

@@ -159,6 +159,9 @@ sourceAPI?: DirectiveDefinition<SourceAPIDirectiveArgs>;

let federationVersion: FeatureVersion | undefined;
schema.schemaDefinition.appliedDirectivesOf<LinkDirectiveArgs>('link')
.forEach(linkDirective => {
const { url, import: imports } = linkDirective.arguments();
if (imports && FeatureUrl.maybeParse(url)?.identity === sourceIdentity) {
const featureUrl = FeatureUrl.maybeParse(url);
if (imports && featureUrl && featureUrl.identity === sourceIdentity) {
imports.forEach(nameOrRename => {

@@ -178,4 +181,21 @@ const originalName = typeof nameOrRename === 'string' ? nameOrRename : nameOrRename.name;

}
if (featureUrl && featureUrl.name === 'federation') {
federationVersion = featureUrl.version;
}
});
if (result.sourceAPI || result.sourceType || result.sourceField) {
// Since this subgraph uses at least one of the @source{API,Type,Field}
// directives, it must also use v2.7 or later of federation.
if (!federationVersion || federationVersion.lt(this.minimumFederationVersion)) {
errors.push(ERRORS.SOURCE_FEDERATION_VERSION_REQUIRED.err(
`Schemas that @link to ${
sourceIdentity
} must also @link to federation version ${
this.minimumFederationVersion
} or later (found ${federationVersion})`,
));
}
}
return result;

@@ -185,2 +205,3 @@ }

override validateSubgraphSchema(schema: Schema): GraphQLError[] {
const errors = super.validateSubgraphSchema(schema);
const {

@@ -190,3 +211,3 @@ sourceAPI,

sourceField,
} = this.getSourceDirectives(schema);
} = this.getSourceDirectives(schema, errors);

@@ -200,3 +221,2 @@ if (!(sourceAPI || sourceType || sourceField)) {

const apiNameToProtocol = new Map<string, ProtocolName>();
const errors: GraphQLError[] = [];

@@ -226,5 +246,7 @@ if (sourceAPI) {

if (apiNameToProtocol.has(name)) {
if (!isValidSourceAPIName(name)) {
errors.push(ERRORS.SOURCE_API_NAME_INVALID.err(
`${sourceAPI} must specify unique name`,
`${sourceAPI}(name: ${
JSON.stringify(name)
}) must specify name using only [a-zA-Z0-9-_] characters`,
{ nodes: application.sourceAST },

@@ -234,9 +256,5 @@ ));

try {
assertName(name);
} catch (e) {
if (apiNameToProtocol.has(name)) {
errors.push(ERRORS.SOURCE_API_NAME_INVALID.err(
`${sourceAPI}(name: ${
JSON.stringify(name)
}) must specify valid GraphQL name`,
`${sourceAPI} must specify unique name (${JSON.stringify(name)} reused)`,
{ nodes: application.sourceAST },

@@ -251,3 +269,5 @@ ));

errors.push(ERRORS.SOURCE_API_PROTOCOL_INVALID.err(
`${sourceAPI} must specify only one of ${KNOWN_SOURCE_PROTOCOLS.join(', ')}`,
`${sourceAPI} must specify only one of ${
KNOWN_SOURCE_PROTOCOLS.join(', ')
} but specified both ${protocol} and ${knownProtocol}`,
{ nodes: application.sourceAST },

@@ -271,3 +291,3 @@ ));

errors.push(ERRORS.SOURCE_API_HTTP_BASE_URL_INVALID.err(
`${sourceAPI} http.baseURL ${JSON.stringify(baseURL)} must be valid URL`,
`${sourceAPI} http.baseURL ${JSON.stringify(baseURL)} must be valid URL (error: ${e.message})`,
{ nodes: application.sourceAST },

@@ -281,3 +301,3 @@ ));

errors.push(ERRORS.SOURCE_API_PROTOCOL_INVALID.err(
`${sourceAPI} must specify one of ${KNOWN_SOURCE_PROTOCOLS.join(', ')}`,
`${sourceAPI} must specify one protocol from the set {${KNOWN_SOURCE_PROTOCOLS.join(',')}}`,
{ nodes: application.sourceAST },

@@ -301,54 +321,54 @@ ));

));
} else {
const expectedProtocol = apiNameToProtocol.get(api);
const protocolValue = expectedProtocol && rest[expectedProtocol];
if (expectedProtocol && !protocolValue) {
errors.push(ERRORS.SOURCE_TYPE_API_ERROR.err(
`${sourceType} must specify same ${
expectedProtocol
} argument as corresponding @sourceAPI for api ${api}`,
}
const expectedProtocol = apiNameToProtocol.get(api) || HTTP_PROTOCOL;
const protocolValue = expectedProtocol && rest[expectedProtocol];
if (expectedProtocol && !protocolValue) {
errors.push(ERRORS.SOURCE_TYPE_PROTOCOL_INVALID.err(
`${sourceType} must specify same ${
expectedProtocol
} argument as corresponding @sourceAPI for api ${api}`,
{ nodes: application.sourceAST },
));
}
if (protocolValue && expectedProtocol === HTTP_PROTOCOL) {
const { GET, POST, headers, body } = protocolValue as HTTPSourceType;
if ([GET, POST].filter(Boolean).length !== 1) {
errors.push(ERRORS.SOURCE_TYPE_HTTP_METHOD_INVALID.err(
`${sourceType} must specify exactly one of http.GET or http.POST`,
{ nodes: application.sourceAST },
));
} else {
const urlPathTemplate = (GET || POST)!;
try {
// TODO Validate URL path template uses only available @key fields
// of the type.
parseURLPathTemplate(urlPathTemplate);
} catch (e) {
errors.push(ERRORS.SOURCE_TYPE_HTTP_PATH_INVALID.err(
`${sourceType} http.GET or http.POST must be valid URL path template (error: ${e.message})`
));
}
}
if (protocolValue && expectedProtocol === HTTP_PROTOCOL) {
const { GET, POST, headers, body } = protocolValue as HTTPSourceType;
validateHTTPHeaders(headers, errors, sourceType.name);
if ([GET, POST].filter(Boolean).length !== 1) {
errors.push(ERRORS.SOURCE_TYPE_HTTP_METHOD_INVALID.err(
`${sourceType} must specify exactly one of http.GET or http.POST`,
if (body) {
if (GET) {
errors.push(ERRORS.SOURCE_TYPE_HTTP_BODY_INVALID.err(
`${sourceType} http.GET cannot specify http.body`,
{ nodes: application.sourceAST },
));
} else {
const urlPathTemplate = (GET || POST)!;
try {
// TODO Validate URL path template uses only available @key fields
// of the type.
parseURLPathTemplate(urlPathTemplate);
} catch (e) {
errors.push(ERRORS.SOURCE_TYPE_HTTP_PATH_INVALID.err(
`${sourceType} http.GET or http.POST must be valid URL path template`
));
}
}
validateHTTPHeaders(headers, errors, sourceType.name);
if (body) {
if (GET) {
errors.push(ERRORS.SOURCE_TYPE_HTTP_BODY_INVALID.err(
`${sourceType} http.GET cannot specify http.body`,
{ nodes: application.sourceAST },
));
}
try {
parseJSONSelection(body);
// TODO Validate body selection matches the available fields.
} catch (e) {
errors.push(ERRORS.SOURCE_TYPE_HTTP_BODY_INVALID.err(
`${sourceType} http.body not valid JSONSelection: ${e.message}`,
{ nodes: application.sourceAST },
));
}
try {
parseJSONSelection(body);
// TODO Validate body selection matches the available fields.
} catch (e) {
errors.push(ERRORS.SOURCE_TYPE_HTTP_BODY_INVALID.err(
`${sourceType} http.body not valid JSONSelection (error: ${e.message})`,
{ nodes: application.sourceAST },
));
}

@@ -373,3 +393,3 @@ }

errors.push(ERRORS.SOURCE_TYPE_SELECTION_INVALID.err(
`${sourceType} selection not valid JSONSelection: ${e.message}`,
`${sourceType} selection not valid JSONSelection (error: ${e.message})`,
{ nodes: application.sourceAST },

@@ -400,55 +420,55 @@ ));

));
} else {
const expectedProtocol = apiNameToProtocol.get(api);
const protocolValue = expectedProtocol && rest[expectedProtocol];
if (protocolValue && expectedProtocol === HTTP_PROTOCOL) {
const {
GET, POST, PUT, PATCH, DELETE,
headers,
body,
} = protocolValue as HTTPSourceField;
}
const usedMethods = [GET, POST, PUT, PATCH, DELETE].filter(Boolean);
if (usedMethods.length > 1) {
errors.push(ERRORS.SOURCE_FIELD_HTTP_METHOD_INVALID.err(
`${sourceField} allows at most one of http.{GET,POST,PUT,PATCH,DELETE}`,
const expectedProtocol = apiNameToProtocol.get(api) || HTTP_PROTOCOL;
const protocolValue = expectedProtocol && rest[expectedProtocol];
if (protocolValue && expectedProtocol === HTTP_PROTOCOL) {
const {
GET, POST, PUT, PATCH, DELETE,
headers,
body,
} = protocolValue as HTTPSourceField;
const usedMethods = [GET, POST, PUT, PATCH, DELETE].filter(Boolean);
if (usedMethods.length > 1) {
errors.push(ERRORS.SOURCE_FIELD_HTTP_METHOD_INVALID.err(
`${sourceField} allows at most one of http.{GET,POST,PUT,PATCH,DELETE}`,
));
} else if (usedMethods.length === 1) {
const urlPathTemplate = usedMethods[0]!;
try {
// TODO Validate URL path template uses only available fields of
// the type and/or argument names of the field.
parseURLPathTemplate(urlPathTemplate);
} catch (e) {
errors.push(ERRORS.SOURCE_FIELD_HTTP_PATH_INVALID.err(
`${sourceField} http.{GET,POST,PUT,PATCH,DELETE} must be valid URL path template (error: ${e.message})`
));
} else if (usedMethods.length === 1) {
const urlPathTemplate = usedMethods[0]!;
try {
// TODO Validate URL path template uses only available fields of
// the type and/or argument names of the field.
parseURLPathTemplate(urlPathTemplate);
} catch (e) {
errors.push(ERRORS.SOURCE_FIELD_HTTP_PATH_INVALID.err(
`${sourceField} http.{GET,POST,PUT,PATCH,DELETE} must be valid URL path template`
));
}
}
}
validateHTTPHeaders(headers, errors, sourceField.name);
validateHTTPHeaders(headers, errors, sourceField.name);
if (body) {
if (GET) {
errors.push(ERRORS.SOURCE_FIELD_HTTP_BODY_INVALID.err(
`${sourceField} http.GET cannot specify http.body`,
{ nodes: application.sourceAST },
));
} else if (DELETE) {
errors.push(ERRORS.SOURCE_FIELD_HTTP_BODY_INVALID.err(
`${sourceField} http.DELETE cannot specify http.body`,
{ nodes: application.sourceAST },
));
}
if (body) {
if (GET) {
errors.push(ERRORS.SOURCE_FIELD_HTTP_BODY_INVALID.err(
`${sourceField} http.GET cannot specify http.body`,
{ nodes: application.sourceAST },
));
} else if (DELETE) {
errors.push(ERRORS.SOURCE_FIELD_HTTP_BODY_INVALID.err(
`${sourceField} http.DELETE cannot specify http.body`,
{ nodes: application.sourceAST },
));
}
try {
parseJSONSelection(body);
// TODO Validate body string matches the available fields of the
// parent type and/or argument names of the field.
} catch (e) {
errors.push(ERRORS.SOURCE_FIELD_HTTP_BODY_INVALID.err(
`${sourceField} http.body not valid JSONSelection: ${e.message}`,
{ nodes: application.sourceAST },
));
}
try {
parseJSONSelection(body);
// TODO Validate body string matches the available fields of the
// parent type and/or argument names of the field.
} catch (e) {
errors.push(ERRORS.SOURCE_FIELD_HTTP_BODY_INVALID.err(
`${sourceField} http.body not valid JSONSelection (error: ${e.message})`,
{ nodes: application.sourceAST },
));
}

@@ -465,3 +485,3 @@ }

errors.push(ERRORS.SOURCE_FIELD_SELECTION_INVALID.err(
`${sourceField} selection not valid JSONSelection: ${e.message}`,
`${sourceField} selection not valid JSONSelection (error: ${e.message})`,
{ nodes: application.sourceAST },

@@ -475,3 +495,3 @@ ));

const fieldParent = application.parent;
if (fieldParent.sourceAST?.kind !== "FieldDefinition") {
if (fieldParent.sourceAST?.kind !== Kind.FIELD_DEFINITION) {
errors.push(ERRORS.SOURCE_FIELD_NOT_ON_ROOT_OR_ENTITY_FIELD.err(

@@ -483,3 +503,3 @@ `${sourceField} must be applied to field`,

const typeGrandparent = fieldParent.parent as SchemaElement<any, any>;
if (typeGrandparent.sourceAST?.kind !== "ObjectTypeDefinition") {
if (typeGrandparent.sourceAST?.kind !== Kind.OBJECT_TYPE_DEFINITION) {
errors.push(ERRORS.SOURCE_FIELD_NOT_ON_ROOT_OR_ENTITY_FIELD.err(

@@ -507,2 +527,6 @@ `${sourceField} must be applied to field of object type`,

function isValidSourceAPIName(name: string): boolean {
return /^[a-z-_][a-z0-9-_]*$/i.test(name);
}
function isValidHTTPHeaderName(name: string): boolean {

@@ -526,14 +550,18 @@ // https://developers.cloudflare.com/rules/transform/request-header-modification/reference/header-format/

errors.push(ERRORS.SOURCE_HTTP_HEADERS_INVALID.err(
`${directiveName} headers[${i}].name == ${
JSON.stringify(name)
} is not valid HTTP header name`,
`${directiveName} header ${JSON.stringify(headers[i])} specifies invalid name`,
));
}
if (!as === !value) {
if (as && !isValidHTTPHeaderName(as)) {
errors.push(ERRORS.SOURCE_HTTP_HEADERS_INVALID.err(
`${directiveName} headers[${i}] must specify exactly one of as or value`,
`${directiveName} header ${JSON.stringify(headers[i])} specifies invalid 'as' name`,
));
}
if (as && value) {
errors.push(ERRORS.SOURCE_HTTP_HEADERS_INVALID.err(
`${directiveName} header ${JSON.stringify(headers[i])} should specify at most one of 'as' or 'value'`,
));
}
// TODO Validate value is valid HTTP header value?

@@ -540,0 +568,0 @@ });

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc