@apollo/federation-internals
Version:
Apollo Federation internal utilities
78 lines (69 loc) • 2.93 kB
text/typescript
import { DirectiveLocation } from "graphql";
import {
CorePurpose,
FeatureDefinition,
FeatureDefinitions,
FeatureUrl,
FeatureVersion,
} from "./coreSpec";
import {DirectiveDefinition, ListType, NonNullType, Schema} from "../definitions";
import { createDirectiveSpecification, createScalarTypeSpecification } from "../directiveAndTypeSpecification";
import { registerKnownFeature } from "../knownCoreFeatures";
import { ARGUMENT_COMPOSITION_STRATEGIES } from "../argumentCompositionStrategies";
import { assert } from "../utils";
export enum PolicyTypeName {
POLICY = 'Policy',
}
export class PolicySpecDefinition extends FeatureDefinition {
public static readonly directiveName = "policy";
public static readonly identity =
`https://specs.apollo.dev/${PolicySpecDefinition.directiveName}`;
constructor(version: FeatureVersion) {
super(
new FeatureUrl(
PolicySpecDefinition.identity,
PolicySpecDefinition.directiveName,
version,
)
);
this.registerType(createScalarTypeSpecification({ name: PolicyTypeName.POLICY }));
// WARNING: we cannot declare staticArgumentTransform() as access control merge logic needs to propagate
// requirements upwards/downwards between types and interfaces. We hijack the merge process by providing
// implementations/interfaces as "additional sources". This means that we cannot apply staticArgumentTransform()
// as subgraph index index will be wrong/undefined.
this.registerDirective(createDirectiveSpecification({
name: PolicySpecDefinition.directiveName,
args: [{
name: 'policies',
type: (schema, feature) => {
assert(feature, "Shouldn't be added without being attached to a @link spec");
const policyName = feature.typeNameInSchema(PolicyTypeName.POLICY);
const PolicyType = schema.type(policyName);
assert(PolicyType, () => `Expected "${policyName}" to be defined`);
return new NonNullType(new ListType(new NonNullType(new ListType(new NonNullType(PolicyType)))));
},
compositionStrategy: ARGUMENT_COMPOSITION_STRATEGIES.DNF_CONJUNCTION,
}],
locations: [
DirectiveLocation.FIELD_DEFINITION,
DirectiveLocation.OBJECT,
DirectiveLocation.INTERFACE,
DirectiveLocation.SCALAR,
DirectiveLocation.ENUM,
],
composes: true,
supergraphSpecification: () => POLICY_VERSIONS.latest(),
}));
}
policyDirective(schema: Schema): DirectiveDefinition<{policies: string[][]}> | undefined {
return this.directive(schema, PolicySpecDefinition.directiveName);
}
get defaultCorePurpose(): CorePurpose {
return 'SECURITY';
}
}
export const POLICY_VERSIONS =
new FeatureDefinitions<PolicySpecDefinition>(
PolicySpecDefinition.identity
).add(new PolicySpecDefinition(new FeatureVersion(0, 1)));
registerKnownFeature(POLICY_VERSIONS);