The @provides directive is used to annotate the expected returned fieldset from a field on a base type that is guaranteed to be selectable by the gateway. Given the following example:
+
When fetching Review.product from the Reviews service, it is possible to request the name with the expectation that the Reviews service can provide it when going from review to product. Product.name is an external field on an external type which is why the local type extension of Product and annotation of name is required.
The @requires directive is used to annotate the required input fieldset from a base type for a resolver. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. For example:
+
In this case, the Reviews service adds new capabilities to the User type by providing a list of reviews related to a user. In order to fetch these reviews, the Reviews service needs to know the email of the User from the Users service in order to look up the reviews. This means the reviews field / resolver requires the email field from the base User type.
The @external directive is used to mark a field as owned by another service. This allows service A to use fields from service B while also knowing at runtime the types of that field. For example:
+
This type extension in the Reviews service extends the User type from the Users service. It extends it for the purpose of adding a new field called reviews, which returns a list of Reviews.
+
+
+
diff --git a/.graphs/https/specs.apollo.dev/inaccessible/v1.0.graphql b/.graphs/https/specs.apollo.dev/inaccessible/v1.0.graphql
new file mode 100644
index 0000000..74310b2
--- /dev/null
+++ b/.graphs/https/specs.apollo.dev/inaccessible/v1.0.graphql
@@ -0,0 +1,127 @@
+extend schema @id(url: "https://specs.apollo.dev/inaccessible/v1.0")
+
+extend schema @id(url: "https://specs.apollo.dev/inaccessible/v1.0")
+
+"""
+The {@inaccessible} directive removes definitions from a schema's API.
+
+```raw html
+
+
Status
Release
+
Version
0.1
+
+
+
+```
+
+This document defines a [core feature](https://specs.apollo.dev/core) named `inaccessible` for removing fields and types from a core schema. "Types" will be used throughout this document to refer to Object, Interface, and Union types in GraphQL.
+
+This specification provides machinery to remove fields and types in a *core schema* which have the `@inaccessible` directive applied.
+
+# How to read this document
+
+This document uses [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt) guidance regarding normative terms: MUST / MUST NOT / REQUIRED / SHALL / SHALL NOT / SHOULD / SHOULD NOT / RECOMMENDED / MAY / OPTIONAL.
+
+# Definitions
+
+## Processor
+
+This specification makes references to **Processors**. Processors are described in the [Actors section of the `@core` spec](https://specs.apollo.dev/core/v0.2/#sec-Actors) as an actor which can perform transformations on a core schema. In the case of `@inaccessible`, the Processor will be expected to remove various parts of a core schema.
+
+# Example: Sensitive User Data
+
+*This section is non-normative.*
+
+We'll refer to this example of a core schema with sensitive user data throughout the document:
+
+:::[example](./schema.graphql) -- Core schema example
+
+The schema above contains both a field (`User.id`) and type (`BankAccount`) that are marked as `@inaccessible`. These symbols should be omitted from the processed schema anywhere they would appear. When the processed schema below is generated from this core schema, notice what has been removed:
+* `User.id` field
+* `BankAccount` type
+* `User.bankAccount` field (because it _returns_ the `BankAccount` type)
+* `Account` union's `BankAccount` type
+
+:::[example](./processedSchema.graphql) -- Core schema after processing
+
+# Overview
+
+*This section is non-normative.* It describes the motivation behind the directives defined by this specification.
+
+A core schema which has been processed according to the inaccessible spec is a queryable graph, intended to be served by a [Data Core](https://specs.apollo.dev/core/v0.2/#sec-Actors). Various use cases require that fields and types should not be visible to or queried for by clients. The `@inaccessible` directive fulfills this requirement, providing schema authors a mechanism to specify which fields and types should be omitted from the processed schema.
+
+# Basic Requirements
+
+Schemas using the `inaccessible` core feature must be valid [core schema documents](https://specs.apollo.dev/core/v0.2) with *@core directives* referencing the `core` specification and this specification.
+
+Here is an example `@core` usage:
+
+:::[example](./coreDirectives.graphql) -- required @core directives
+
+As described in the [core schema specification](https://specs.apollo.dev/core/v0.2/#sec-Prefixing), your schema may prefix the `@inaccessible` directive by including an `as` argument to the `@core` directive which references this specification. All references to `@inaccessible` in this specification MUST be interpreted as referring to names with the appropriate prefix chosen within your schema.
+
+In order to use the directive described by this specification, GraphQL requires you to include the definition in your schema.
+
+## Producer Responsibilities
+
+[Producers](https://specs.apollo.dev/core/v0.2/#sec-Actors) MUST include a definition of the directive compatible with the above definition and all usages in the document.
+
+## Processor Responsibilities
+
+The Processor is responsible for removing all inaccessible elements from the schema output. Note in the `InaccessibleRemoval` algorithm below that because a Union can belong to another Union's set of types, the removal of a Union type may have an upwards "cascading" effect, causing other Unions to become candidates for removal.
+
+# Algorithms
+
+## Is Inaccessible?
+
+Return true if the named element {element} is inaccessible.
+
+IsInaccessible(document, element) :
+ 1. If {IsMarkedInaccessible(document, element)}, **Return** {true}
+ 2. If {element} is a FieldDefinition,
+ 1. Let {parent} be the parent definition for {element}
+ 2. If {IsMarkedInaccessible(document, parent)}, **Return** {true}
+ 3. **Return** {false}
+
+Return true iff the named element {element} is marked as inaccessible.
+
+IsMarkedInaccessible(document, element) :
+ 1. Let {assignments} be the result of assigning features via {AssignFeatures(document)}
+ 2. For each Directive {d} on {element},
+ 1. If {assignments}`[`{element}`]` is a Directive whose `feature` argument is this spec, **Return** {true}
+ 3. **Return** {false}
+
+## Remove Inaccessible Elements
+
+Given a schema document, return the set of all schema elements which should be removed in the API.
+
+RemoveInaccessible(document) :
+ 1. For each named schema element {e} defined in the {document},
+ 1. If {IsInaccessible(document, e)} is {true}, {Remove(document, e)}
+
+Remove(document, element) :
+ 1. If {element} is a Field or Input Field,
+ 1. Delete the definition of {element} in {document}
+ 2. Let {parent} be the parent type of {f} in {document}
+ 2. If {parent} has no fields, {Remove(document, parent)}
+ 2. If {element} is a type:
+ 1. Delete all definitions and extensions of {element} in {document}
+ 2. If {element} is an output type (object, interface, union, or scalar):
+ 1. For each Field {f} in {document} where {f} has a Return Type of {element}, {Remove(document, f)}
+ 3. If {element} is an input type (input object, enum, or scalar):
+ 1. For each Field {f} in {document} where {f} has any argument of type {element}, {Remove(document, f)}
+ 2. For each input object type {t} in {document},
+ 1. For each input field {f} of {t} where the type of {f} is {element}, {Remove(document, f)}
+ 4. If {element} is an Object or Union type,
+ 2. For each Union {u} in {document} where {element} is a member of {u},
+ 1. Delete {element} as member of {u}
+ 2. If {u} has no members, {Remove(document, u)}
+ 5. If {element} is an Interface type,
+ 3. For each Object or Interface type {t} which implements {element} in {document},
+ 1. Delete {element} as an interface conformance of {t}
+"""
+schema {
+ query: Query
+}
+
+directive @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION
\ No newline at end of file
diff --git a/.graphs/https/specs.apollo.dev/inaccessible/v1.0.html b/.graphs/https/specs.apollo.dev/inaccessible/v1.0.html
new file mode 100644
index 0000000..7046f85
--- /dev/null
+++ b/.graphs/https/specs.apollo.dev/inaccessible/v1.0.html
@@ -0,0 +1,1555 @@
+
+
+
+
+inaccessible v1.0
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+Core schemas provide tools for linking definitions from different GraphQL schemas together into one.
+
+```graphql example -- linking a directive from another schema
+extend schema
+ # 👇🏽 schemas are identified by a url
+ @link(url: "https://internal.example.com/admin")
+
+type Query {
+ allUsers: [User] @admin__adminOnly # 👈🏽 remote identifier, namespaced
+}
+```
+
+```graphql example -- importing a directive from another schema
+extend schema
+ # specific definitions can be imported 👇🏽
+ @link(url: "https://internal.example.com/admin", import: ["@adminOnly"])
+
+type Query {
+ allUsers: [User] @adminOnly # 👈🏽 remote identifier, imported
+}
+```
+
+This document introduces a set of conventions for linking and namespacing within GraphQL schemas. Core schemas are not a new kind of document and do not introduce any new syntax—they are just GraphQL schemas which can be interpreted according to the conventions outlined in this doc.
+
+# Renaming {@link}
+
+It is possible to rename {@link} with the same {@link.as} mechanism used for all links:
+
+```graphql example -- Renaming {@link} to {@linkOther}
+schema
+ @linkOther(url: "https://specs.apollo.dev/link/v1.0", import: [{name: "@link", as: "@linkOther"}])
+ @linkOther(url: "https://example.com/example/v1.0")
+{
+ query: Query
+}
+
+type SomeType {
+ field: Int @example
+}
+```
+
+# Prefixing
+
+With the exception of a single root directive, core feature specifications MUST prefix all schema elements they introduce. The prefix:
+ 1. MUST match the name of the feature as derived from the feature's specification URL,
+ 2. MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name), and
+ 3. MUST NOT contain the core namespace separator, which is two underscores ({"__"}), and
+ 4. MUST NOT end with an underscore (which would create ambiguity between whether {"x___y"} is prefix `x_` for element `y` or prefix `x` for element `_y`).
+
+Prefixed names consist of the name of the feature, followed by two underscores, followed by the name of the element, which can be any valid [GraphQL name](https://spec.graphql.org/draft/#Name). For instance, the `core` specification (which you are currently reading) introduces an element named [{@link}](#@link), and the `join` specification introduces an element named {@join__field} (among others).
+
+Note that both parts must be valid GraphQL names, and GraphQL names cannot start with digits, so core feature specifications cannot introduce names like `@feature__24hours`.
+
+A feature's *root directive* is an exception to the prefixing requirements. Feature specifications MAY introduce a single directive which carries only the name of the feature, with no prefix required. For example, the `core` specification introduces a {@link} directive. This directive has the same name as the feature ("`core`"), and so requires no prefix.
+
+```graphql example -- Using the @link directive without changing the prefix
+schema
+ @link(url: "https://specs.apollo.dev/link/v1.0", import: ["@link"])
+ @link(url: "https://spec.example.com/example/v1.0") {
+ query: Query
+}
+
+type User {
+ name: String @example(data: ITEM)
+}
+
+# An enum used to provide structured data to the example spec.
+# It is prefixed with the name of the spec.
+enum example__Data {
+ ITEM
+}
+
+directive @example(data: example__Data) on FIELD_DEFINITION
+
+directive @link(url: String!, as: String) repeatable on SCHEMA
+```
+
+The prefix MUST NOT be elided within documentation; definitions of schema elements provided within the spec MUST include the feature's name as a prefix.
+
+## Elements which must be prefixed
+
+Feature specs MUST prefix the following schema elements:
+ - the names of any object types, interfaces, unions, enums, or input object types defined by the feature
+ - the names of any directives introduced in the spec, with the exception of the *root directive*, which must have the same name as the feature
+
+:::[example](prefixing.graphql) -- Prefixing
+
+# Versioning
+
+VersionTag : "v" Version
+
+Version : Major "." Minor
+
+Major : NumericIdentifier
+
+Minor : NumericIdentifier
+
+NumericIdentifier : "0"
+ | PositiveDigit Digit*
+
+Digit : "0" | PositiveDigit
+
+PositiveDigit : "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
+
+Specs are versioned with a **subset** of a [Semantic Version Number](https://semver.org/spec/v2.0.0.html) containing only the major and minor parts. Thus, specifications SHOULD provide a version of the form `v`{Major}`.`{Minor}, where both integers >= 0.
+
+```text example -- Valid version tags
+v2.2
+v1.0
+v1.1
+v0.1
+```
+
+As specified by semver, spec authors SHOULD increment the:
+
+{++
+
+- MAJOR version when you make incompatible API changes,
+- MINOR version when you add functionality in a backwards compatible manner
+
+++}
+
+Patch and pre-release qualifiers are judged to be not particularly meaningful in the context of core features, which are (by definition) interfaces rather than implementations. The patch component of a semver denotes a bug fix which is backwards compatible—that is, a change to the implementation which does not affect the interface. Patch-level changes in the version of a spec denote wording clarifications which do not require implementation changes. As such, it is not important to track them for the purposes of version resolution.
+
+As with [semver](https://semver.org/spec/v2.0.0.html), the `0.x` version series is special: there is no expectation of compatibility between versions `0.x` and `0.y`. For example, a processor must not activate implementation `0.4` to satisfy a requested version of `0.2`.
+
+## Satisfaction
+
+Given a version {requested} by a document and an {available} version of an implementation, the following algorithm will determine if the {available} version can satisfy the {requested} version:
+
+Satisfies(requested, available) :
+ 1. If {requested}.{Major} ≠ {available}.{Major}, return {false}
+ 2. If {requested}.{Major} = 0, return {requested}.{Minor} = {available}.{Minor}
+ 3. Return {requested}.{Minor} <= {available}.{Minor}
+
+## Referencing versions and activating implementations
+
+Schema documents MUST reference a feature version which supports all the schema elements and behaviors required by the document. As a practical matter, authors will generally prefer to reference a version they have reason to believe is supported by the most processors; depending on context, this might be an old stable version with a low major version, or a new less-deprecated version with a large major version.
+
+If a processor chooses to activate support for a feature, the processor MUST activate an implementation which can [satisfy](#sec-Satisfaction) the version required by the document.
+
+
+# Processing Schemas
+
+```mermaid diagram
+graph LR
+ schema(["📄 Input Schema"]):::file-->proc("🤖 Processor")
+ proc-->output(["📄 Output Schema"]):::file
+ classDef file fill:none,color:#22262E;
+ style proc fill:none,stroke:fuchsia,color:fuchsia;
+```
+
+A common use case is that of a processor which consumes a valid input schema and generates an output schema.
+
+The general guidance for processor behavior is: don't react to what you don't understand.
+
+Specifically, processors:
+ - SHOULD pass through {@link} directives which reference unknown feature URLs
+ - SHOULD pass through prefixed directives, types, and other schema elements
+ - SHOULD pass through directives which are not [associated with](#AssignFeatures) a {@link} feature
+
+Processors MAY accept configuration which overrides these default behaviors.
+
+Additionally, processors which prepare the schema for final public consumption MAY choose to eliminate all unknown directives and prefixed types in order to hide schema implementation details within the published schema. This will impair the operation of tooling which relies on these directives—such tools will not be able to run on the output schema, so the benefits and costs of this kind of information hiding should be weighed carefully on a case-by-case basis.
+
+# Validations & Algorithms
+
+This section lays out algorithms for processing core schemas.
+
+Algorithms described in this section may produce *validation failures* if a document does not conform to the requirements core schema document. Validation failures SHOULD halt processing. Some consumers, such as authoring tools, MAY attempt to continue processing in the presence of validation failures, but their behavior in such cases is unspecified.
+
+## Bootstrapping
+
+Determine the name of the core specification within the document.
+
+It is possible to [rename the core feature](#sec-Renaming-core-itself) within a document. This process determines the actual name for the core feature if one is present.
+
+- **Fails** the *Has Schema* validation if there are no SchemaDefinitions in the document
+- **Fails** the *Has Core Feature* validation if the `core` feature itself is not referenced with a {@link} directive within the document
+- **Fails** the *Bootstrap Core Feature Listed First* validation if the reference to the `core` feature is not the first {@link} directive on the document's SchemaDefinition
+- **Fails** the *Core Directive Incorrect Definition* validation if the {@link} directive definition does not *match* the directive as defined by this specification.
+
+For the purposes of this algorithm, a directive's definition in a schema *matches* a definition provided in this specification if:
+- Its arguments have the specified names, types, and default values (or lack thereof)
+- It is defined as `repeatable` if and only if the specification's definition defines it as `repeatable`
+- The set of locations it belongs to is the same set of locations in the specification's definition.
+
+The following aspects may differ between the definition in the schema and the definition in the specification without preventing the definitions from *matching*:
+- The name of the directive (due to [prefixing](#sec-Prefixing))
+- The order of arguments
+- The order of locations
+- The directive's description string
+- Argument description strings
+- Directives applied to argument definitions
+
+Bootstrap(document) :
+1. Let {schema} be the only SchemaDefinition in {document}. (Note that legal GraphQL documents [must include at most one SchemaDefinition](http://spec.graphql.org/draft/#sec-Root-Operation-Types).)
+ 1. ...if no SchemaDefinitions are present in {document}, the ***Has Schema* validation fails**.
+1. For each directive {d} on {schema},
+ 1. If {d} has a [`url:`](#@link/feature) argument which [parses as a feature URL](#@link/feature), *and* whose identity is {"https://specs.apollo.dev/core/"} *and* whose version is {"v0.1"}, *and either* {d} has an [`as:`](#@link/as) argument whose value is equal to {d}'s name *or* {d} does not have an [`as:`](#@link/as) argument and {d}'s name is `core`:
+ - If any directive on {schema} listed before {d} has the same name as {d}, the ***Bootstrap Core Feature Listed First* validation fails**.
+ - If the definition of the directive {d} does not *match* the [definition of {@link} in this specification](#@link), the ***Core Directive Incorrect Definition* validation fails**.
+ - Otherwise, **Return** {d}'s name.
+- If no matching directive was found, the ***Has Core Feature* validation fails**.
+
+## Feature Collection
+
+Collect a map of ({featureName}: `String`) -> `Directive`, where `Directive` is a {@link} Directive which introduces the feature named {featureName} into the document.
+
+- **Fails** the *Name Uniqueness* validation if feature names are not unique within the document.
+- **Fails** *Invalid Feature URL* validation for any invalid feature URLs.
+
+CollectFeatures(document) :
+ - Let {coreName} be the name of the core feature found via {Bootstrap(document)}
+ - Let {features} be a map of {featureName}: `String` -> `Directive`, initially empty.
+ - For each directive {d} named {coreName} on the SchemaDefinition within {document},
+ - Let {specifiedFeatureName} and {version} be the result of parsing {d}'s `url:` argument according to the [specified rules for feature URLs](#@link/feature)
+ - If the `url:` is not present or fails to parse:
+ - The ***Invalid Feature URL* validation fails** for {d},
+ - Let {featureName} be the {d}'s [`as:`](#@link/as) argument or, if the argument is not present, {specifiedFeatureName}
+ - If {featureName} exists within {features}, the ***Name Uniqueness* validation fails**.
+ - Insert {featureName} => {d} into {features}
+ - **Return** {features}
+
+
+Prefixes, whether implicit or explicit, must be unique within a document. Valid:
+
+:::[example](prefixing.graphql#schema[0]) -- Unique prefixes
+
+It is also valid to reference multiple versions of the same spec under different prefixes:
+
+:::[example](prefix-uniqueness.graphql#schema[0]) -- Explicit prefixes allow multiple versions of the same spec to coexist within a Document
+
+Without the explicit [`as:`](#@link/as), the above would be invalid:
+
+:::[counter-example](prefix-uniqueness.graphql#schema[1]) -- Non-unique prefixes with multiple versions of the same spec
+
+Different specs with the same prefix are also invalid:
+
+:::[counter-example](prefix-uniqueness.graphql#schema[2]) -- Different specs with non-unique prefixes
+
+## Assign Features
+
+Create a map of {element}: *Any Named Element* -> {feature}: `Directive` | {null}, associating every named schema element within the document with a feature directive, or {null} if it is not associated with a feature.
+
+AssignFeatures(document) :
+ - Let {features} be the result of collecting features via {CollectFeatures(document)}
+ - Let {assignments} be a map of ({element}: *Any Named Element*) -> {feature}: `Directive` | {null}, initally empty
+ - For each named schema element {e} within the {document}
+ - Let {name} be the name of the {e}
+ - If {e} is a Directive and {name} is a key within {features},
+ - Insert {e} => {features}`[`{name}`]` into {assignments}
+ - **Continue** to next {e}
+ - If {name} begins with {"__"},
+ - Insert {e} => {null} into {assignments}
+ - **Continue** to next {e}
+ - If {name} contains the substring {"__"},
+ - Partition {name} into `[`{prefix}, {base}`]` at the first {"__"} (that is, find the shortest {prefix} and longest {base} such that {name} = {prefix} + {"__"} + {base})
+ - If {prefix} exists within {features}, insert {e} => {features}`[`{prefix}`]` into {assignments}
+ - Else, insert {e} => {null} into {assignments}
+ - **Continue** to next {e}
+ - Insert {e} => {null} into {assignments}
+ - **Return** {assignments}
+
+## Is In API?
+
+Determine if any schema element is included in the [API](#sec-Parts-of-a-Core-Schema) described by the core schema. A schema element is any part of a GraphQL document using type system definitions that has a [name](https://spec.graphql.org/draft/#Name).
+
+IsInAPI(element) :
+ - Let {assignments} be the result of assigning features to elements via {AssignFeatures(document)}
+ - If {assignments}`[`{element}`]` is {null}, **Return** {true}
+ - Else, **Return** {false}
+
+Note: Later versions of this specification may add other ways to affect the behavior of this algorithm, but those mechanisms will only be enabled if you reference those hypothetical versions of this specification.
+
+## Is Affected By Feature?
+
+Determine if a schema element is *affected* by a given feature.
+
+IsAffected(element, feature):
+ - Let {assignments} be the result of assigning features to elements via {AssignFeatures(document)}
+ - For each directive {d} on {element}, If {assignments}`[`{d}`]` is {feature}, **Return** {true}
+ - If {element} is a FieldDefinition,
+ - Let {parent} be the parent ObjectDefinition or InterfaceDefinition for {element}
+ - If {IsAffected(parent, feature)}, **Return** {true}
+ - For each argument type {a} declared on {element},
+ - Let {t} be the InputDefinition, EnumDefinition, or ScalarDefinition for argument {a}
+ - If {IsAffected(t, feature)}, **Return** {true}
+ - Let {return} be the ObjectDefinition, InterfaceDefinition, or UnionDefinition for {element}'s return type
+ - If {IsAffected(return, feature)}, **Return** {true}
+ - If {element} is an InputDefinition,
+ - For each InputFieldDefinition {field} within {element},
+ - Let {t} be the InputDefinition, EnumDefinition, or ScalarDefinition for the type of {field}
+ - If {IsAffected(t, feature)}, **Return** {true}
+ - If {element} is an EnumDefinition,
+ - For each EnumValueDefinition {value} in {element},
+ - If {IsAffected(value, feature)}, **Return** {true}
+"""
+schema {
+ query: Query
+}
+
+"""Link a foreign schema by its URL."""
+directive @link(
+ """
+ The foreign schema's URL.
+
+ Link URLs serve two main purposes:
+ - Providing a unique identifier for the foreign schema
+ - Directing human readers to documentation about the foreign schema
+
+ Link URLs SHOULD be [RFC 3986 URLs](https://tools.ietf.org/html/rfc3986). When viewed, the URL SHOULD provide schema documentation in some human-readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
+
+ Link URLs MAY contain information about the spec's [name](#sec-Prefixing) and [version](#sec-Versioning):
+
+ ```html diagram -- Basic anatomy of a link URL
+
+ https://spec.example.com/a/b/c/mySchema/v1.0
+
+ ```
+
+ The final two segments of the URL's [path](https://tools.ietf.org/html/rfc3986#section-3.3) MAY contain the schema's name and a [version tag](#sec-Versioning), in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid {VersionTag}. To be recognized as a name, the penultimate path component MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name) which does not include the namespace separator ({"__"}).
+
+ Empty final path components (that is, trailing slashes) and any URL components which have not been assigned a meaning (such as the fragment and query) MUST be ignored.
+
+ ```html diagram -- Ignoring meaningless parts of a URL
+
+ https://example.com/exampleSchema/v1.0/?key=val&k2=v2#frag
+
+ ```
+
+ All of these are valid arguments to `url`, and their interpretations:
+
+ | url | normalized url | name | version |
+ | ------------------------------------------------- | ------------------------------------------ | ------- | -------- |
+ | https://spec.example.com/a/b/mySchema/v1.0/ | https://spec.example.com/a/b/mySchema/v1.0 | mySchema | v1.0 |
+ | https://spec.example.com | https://spec.example.com | *(null)* | *(null)* |
+ | https://spec.example.com/mySchema/v0.1?q=v#frag | https://spec.example.com/mySchema/v0.1 | mySchema | v0.1 |
+ | https://spec.example.com/v1.0 | https://spec.example.com/v1.0 | *(null)* | v1.0 |
+ | https://spec.example.com/vX | https://spec.example.com/vX | vX | *(null)* |
+
+ If `name` is present, that [namespace prefix](#sec-Prefixing) will automatically be linked to the URL. If a `name` is not present, then elements of the foreign schema must be [`imported`](#@link/import) in order to be referenced.
+ """
+ url: String!
+ """
+ Change the [namespace prefix](#sec-Prefixing) assigned to this schema.
+
+ The name must be a valid GraphQL identifier, and must not contain the namespace separator ({"__"}).
+
+ By default, {@link} will assign a prefix based on the `name` extracted from the URL. If no `name` is present, a prefix will not be assigned.
+
+ Providing [`as:`](#@link/as) overrides the default behavior: the foreign schema will be assigned the provided prefix, regardless of the `name` present in the URL (or the lack of one).
+
+ ```graphql example -- Using {@link}(url:, as:) to use a feature with a custom name
+ schema
+ @link(url: "https://specs.apollo.dev/link/v1.0")
+ @link(url: "https://spec.example.com/example/v1.0", as: "eg")
+ {
+ query: Query
+ }
+
+ type User {
+ # Specifying `as: "eg"` transforms @example into @eg
+ name: String @eg(data: ITEM)
+ }
+
+ # Additional specified schema elements must have their prefixes set
+ # to the new name.
+ enum eg__Data {
+ ITEM
+ }
+
+ # Name transformation must also be applied to definitions pulled in from
+ # specifications.
+ directive @eg(data: eg__Data) on FIELD_DEFINITION
+
+ directive @link(url: String!, as: String) repeatable on SCHEMA
+ ```
+ """
+ as: String
+ """Import definitions into the local namespace."""
+ import: [Import]
+ """
+ An optional [purpose](#Purpose) for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
+
+ By default, {@link}s SHOULD fail open. This means that {@link}s to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
+
+ This behavior is different for {@link}s with a specified purpose:
+ - `SECURITY` links convey metadata necessary to compute the API schema and securely resolve fields within it
+ - `EXECUTION` links convey metadata necessary to correctly resolve fields within the schema
+ """
+ for: Purpose
+) repeatable on SCHEMA
+
+"""TK describe an import"""
+scalar Import
+
+"""
+The role of a feature referenced with {@link}.
+
+This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail-open behavior of core schema consumers is undesirable.
+
+Note we'll refer to directives from features which are `for: SECURITY` or `for: EXECUTION` as "`SECURITY` directives" and "`EXECUTION` directives", respectively.
+"""
+enum Purpose {
+ """
+ `SECURITY` links provide metadata necessary to securely resolve fields. For instance, a hypothetical {auth} feature may provide an {@auth} directive to flag fields which require authorization. If a data core does not support the {auth} feature and serves those fields anyway, these fields will be accessible without authorization, compromising security.
+
+ Security-conscious consumers MUST NOT serve a field if:
+ - the schema definition has **any** unsupported SECURITY directives,
+ - the field's parent type definition has **any** unsupported SECURITY directives,
+ - the field's return type definition has **any** unsupported SECURITY directives, or
+ - the field definition has **any** unsupported SECURITY directives
+
+ Such fields are *not securely resolvable*. Security-conscious consumers MAY serve schemas with fields which are not securely resolvable. However, they MUST remove such fields from the schema before serving it.
+
+ Less security-conscious consumers MAY choose to relax these requirements. For instance, servers may provide a development mode in which unknown SECURITY directives are ignored, perhaps with a warning. Such software may also provide a way to explicitly disable some or all SECURITY links during development.
+
+ More security-conscious consumers MAY choose to enhance these requirements. For instance, production servers MAY adopt a policy of entirely rejecting any schema which contains ANY unsupported SECURITY links, even if those links are never used to annotate the schema.
+ """
+ SECURITY
+ """
+ `EXECUTION` features provide metadata necessary to correctly resolve fields. For instance, a hypothetical {ts} feature may provide a `@ts__resolvers` annotation which references a TypeScript module of field resolvers. A consumer which does not support the {ts} feature will be unable to correctly resolve such fields.
+
+ Consumers MUST NOT serve a field if:
+ - the schema's definition has **any** unsupported EXECUTION directives,
+ - the field's parent type definition has **any** unsupported EXECUTION directives,
+ - the field's return type definition has **any** unsupported EXECUTION directives, or
+ - the field definition has **any** unsupported EXECUTION directives
+
+ Such fields are *unresolvable*. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION features, even if those features are never used in the schema.
+ """
+ EXECUTION
+}
\ No newline at end of file
diff --git a/.graphs/https/specs.apollo.dev/link/v1.0.html b/.graphs/https/specs.apollo.dev/link/v1.0.html
new file mode 100644
index 0000000..e1373f6
--- /dev/null
+++ b/.graphs/https/specs.apollo.dev/link/v1.0.html
@@ -0,0 +1,2124 @@
+
+
+
+
+link v1.0
+
+
+
+
+
+
+
+
+
+
link v1.0
+
+
+
Status
Draft
+
Version
2.0
+
+
+
+
Core schemas provide tools for linking definitions from different GraphQL schemas together into one.
+
This document introduces a set of conventions for linking and namespacing within GraphQL schemas. Core schemas are not a new kind of document and do not introduce any new syntax—they are just GraphQL schemas which can be interpreted according to the conventions outlined in this doc.
MUST NOT contain the core namespace separator, which is two underscores ("__"), and
+
MUST NOT end with an underscore (which would create ambiguity between whether "x___y" is prefix x_ for element y or prefix x for element _y).
+
+
Prefixed names consist of the name of the feature, followed by two underscores, followed by the name of the element, which can be any valid GraphQL name. For instance, the core specification (which you are currently reading) introduces an element named @link, and the join specification introduces an element named @join__field (among others).
+
+Note
+that both parts must be valid GraphQL names, and GraphQL names cannot start with digits, so core feature specifications cannot introduce names like @feature__24hours.
+
A feature’s root directive is an exception to the prefixing requirements. Feature specifications MAY introduce a single directive which carries only the name of the feature, with no prefix required. For example, the core specification introduces a @link directive. This directive has the same name as the feature (”core”), and so requires no prefix.
+
The prefix MUST NOT be elided within documentation; definitions of schema elements provided within the spec MUST include the feature’s name as a prefix.
Specs are versioned with a subset of a Semantic Version Number containing only the major and minor parts. Thus, specifications SHOULD provide a version of the form vMajor.Minor, where both integers ≥ 0.
+
As specified by semver, spec authors SHOULD increment the:
+
+
MAJOR version when you make incompatible API changes,
+
MINOR version when you add functionality in a backwards compatible manner
+
+
+
Patch and pre‐release qualifiers are judged to be not particularly meaningful in the context of core features, which are (by definition) interfaces rather than implementations. The patch component of a semver denotes a bug fix which is backwards compatible—that is, a change to the implementation which does not affect the interface. Patch‐level changes in the version of a spec denote wording clarifications which do not require implementation changes. As such, it is not important to track them for the purposes of version resolution.
+
As with semver, the 0.x version series is special: there is no expectation of compatibility between versions 0.x and 0.y. For example, a processor must not activate implementation 0.4 to satisfy a requested version of 0.2.
Given a version requested by a document and an available version of an implementation, the following algorithm will determine if the available version can satisfy the requested version:
3.2Referencing versions and activating implementations
+
Schema documents MUST reference a feature version which supports all the schema elements and behaviors required by the document. As a practical matter, authors will generally prefer to reference a version they have reason to believe is supported by the most processors; depending on context, this might be an old stable version with a low major version, or a new less‐deprecated version with a large major version.
+
If a processor chooses to activate support for a feature, the processor MUST activate an implementation which can satisfy the version required by the document.
Processors MAY accept configuration which overrides these default behaviors.
+
Additionally, processors which prepare the schema for final public consumption MAY choose to eliminate all unknown directives and prefixed types in order to hide schema implementation details within the published schema. This will impair the operation of tooling which relies on these directives—such tools will not be able to run on the output schema, so the benefits and costs of this kind of information hiding should be weighed carefully on a case‐by‐case basis.
This section lays out algorithms for processing core schemas.
+
Algorithms described in this section may produce validation failures if a document does not conform to the requirements core schema document. Validation failures SHOULD halt processing. Some consumers, such as authoring tools, MAY attempt to continue processing in the presence of validation failures, but their behavior in such cases is unspecified.
Determine the name of the core specification within the document.
+
It is possible to rename the core feature within a document. This process determines the actual name for the core feature if one is present.
+
+
Fails the Has Schema validation if there are no SchemaDefinitions in the document
+
Fails the Has Core Feature validation if the core feature itself is not referenced with a @link directive within the document
+
Fails the Bootstrap Core Feature Listed First validation if the reference to the core feature is not the first @link directive on the document’s SchemaDefinition
+
Fails the Core Directive Incorrect Definition validation if the @link directive definition does not match the directive as defined by this specification.
+
+
For the purposes of this algorithm, a directive’s definition in a schema matches a definition provided in this specification if:
+
+
Its arguments have the specified names, types, and default values (or lack thereof)
+
It is defined as repeatable if and only if the specification’s definition defines it as repeatable
+
The set of locations it belongs to is the same set of locations in the specification’s definition.
+
+
The following aspects may differ between the definition in the schema and the definition in the specification without preventing the definitions from matching:
...if no SchemaDefinitions are present in document, the Has Schema validation fails.
+
+
+
For each directive d on schema,
+
If d has a url: argument which parses as a feature URL, and whose identity is "https://specs.apollo.dev/core/"and whose version is "v0.1", and eitherd has an as: argument whose value is equal to d‘s name ord does not have an as: argument and d‘s name is core:
+
If any directive on schema listed before d has the same name as d, the Bootstrap Core Feature Listed First validation fails.
Collect a map of (featureName: String) → Directive, where Directive is a @link Directive which introduces the feature named featureName into the document.
+
+
Fails the Name Uniqueness validation if feature names are not unique within the document.
+
FailsInvalid Feature URL validation for any invalid feature URLs.
Create a map of element: Any Named Element → feature: Directive | null, associating every named schema element within the document with a feature directive, or null if it is not associated with a feature.
Determine if any schema element is included in the API described by the core schema. A schema element is any part of a GraphQL document using type system definitions that has a name.
Let assignments be the result of assigning features to elements via AssignFeatures(document)
+
If assignments[element] is null, Returntrue
+
Else, Returnfalse
+
+
+
+Note
+Later versions of this specification may add other ways to affect the behavior of this algorithm, but those mechanisms will only be enabled if you reference those hypothetical versions of this specification.
Providing a unique identifier for the foreign schema
+
Directing human readers to documentation about the foreign schema
+
+
Link URLs SHOULD be RFC 3986 URLs. When viewed, the URL SHOULD provide schema documentation in some human‐readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
+
Link URLs MAY contain information about the spec’s name and version:
+
The final two segments of the URL’s pathMAY contain the schema’s name and a version tag, in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid VersionTag. To be recognized as a name, the penultimate path component MUST be a valid GraphQL name which does not include the namespace separator ("__").
+
Empty final path components (that is, trailing slashes) and any URL components which have not been assigned a meaning (such as the fragment and query) MUST be ignored.
+
All of these are valid arguments to url, and their interpretations:
+
+
+
url
+
normalized url
+
name
+
version
+
+
+
+
https://spec.example.com/a/b/mySchema/v1.0/
https://spec.example.com/a/b/mySchema/v1.0
mySchema
v1.0
+
+
https://spec.example.com
https://spec.example.com
(null)
(null)
+
+
https://spec.example.com/mySchema/v0.1?q=v#frag
https://spec.example.com/mySchema/v0.1
mySchema
v0.1
+
+
https://spec.example.com/v1.0
https://spec.example.com/v1.0
(null)
v1.0
+
+
https://spec.example.com/vX
https://spec.example.com/vX
vX
(null)
+
+
+
If name is present, that namespace prefix will automatically be linked to the URL. If a name is not present, then elements of the foreign schema must be imported in order to be referenced.
The name must be a valid GraphQL identifier, and must not contain the namespace separator ("__").
+
By default, @link will assign a prefix based on the name extracted from the URL. If no name is present, a prefix will not be assigned.
+
Providing as: overrides the default behavior: the foreign schema will be assigned the provided prefix, regardless of the name present in the URL (or the lack of one).
An optional purpose for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
+
By default, @links SHOULD fail open. This means that @links to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
+
This behavior is different for @links with a specified purpose:
+
+
SECURITY links convey metadata necessary to compute the API schema and securely resolve fields within it
+
EXECUTION links convey metadata necessary to correctly resolve fields within the schema
This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail‐open behavior of core schema consumers is undesirable.
+
+Note
+we’ll refer to directives from features which are for: SECURITY or for: EXECUTION as “SECURITY directives” and “EXECUTION directives”, respectively.
+
+
+
diff --git a/load.js b/.graphs/https/specs.apollo.dev/load.js
similarity index 100%
rename from load.js
rename to .graphs/https/specs.apollo.dev/load.js
diff --git a/main.js b/.graphs/https/specs.apollo.dev/main.js
similarity index 100%
rename from main.js
rename to .graphs/https/specs.apollo.dev/main.js
diff --git a/markdown.js b/.graphs/https/specs.apollo.dev/markdown.js
similarity index 100%
rename from markdown.js
rename to .graphs/https/specs.apollo.dev/markdown.js
diff --git a/mermaid.js b/.graphs/https/specs.apollo.dev/mermaid.js
similarity index 100%
rename from mermaid.js
rename to .graphs/https/specs.apollo.dev/mermaid.js
diff --git a/query.js b/.graphs/https/specs.apollo.dev/query.js
similarity index 100%
rename from query.js
rename to .graphs/https/specs.apollo.dev/query.js
diff --git a/rendering.js b/.graphs/https/specs.apollo.dev/rendering.js
similarity index 100%
rename from rendering.js
rename to .graphs/https/specs.apollo.dev/rendering.js
diff --git a/toc.js b/.graphs/https/specs.apollo.dev/toc.js
similarity index 100%
rename from toc.js
rename to .graphs/https/specs.apollo.dev/toc.js
diff --git a/federation/v2.0.graphql b/federation/v2.0.graphql
new file mode 100644
index 0000000..ec8415a
--- /dev/null
+++ b/federation/v2.0.graphql
@@ -0,0 +1,86 @@
+@id(url: "https://specs.apollo.dev/federation/v2.0")
+
+### `@key`
+
+"""
+The `@key` directive is used to indicate a combination of fields that can be used to uniquely identify and fetch an object or interface.
+
+```graphql example -- using {@key}
+type Product @key(fields: "upc") {
+ upc: UPC!
+ name: String
+}
+```
+
+Multiple keys can be defined on a single object type:
+
+```graphql example -- defining multiple {@key}s
+type Product @key(fields: "upc") @key(fields: "sku") {
+ upc: UPC!
+ sku: SKU!
+ name: String
+}
+```
+
+Note: Repeated directives (in this case, `@key`, used multiple times) require support by the underlying GraphQL implementation.
+"""
+directive @key(fields: FieldSet!) repeatable on OBJECT | INTERFACE
+
+
+### `@provides`
+
+"""
+The `@provides` directive is used to annotate the expected returned fieldset from a field on a base type that is guaranteed to be selectable by the gateway. Given the following example:
+
+```graphql example -- using {@provides}
+type Review @key(fields: "id") {
+ product: Product @provides(fields: "name")
+}
+
+extend type Product @key(fields: "upc") {
+ upc: String @external
+ name: String @external
+}
+```
+
+When fetching `Review.product` from the Reviews service, it is possible to request the `name` with the expectation that the Reviews service can provide it when going from review to product. `Product.name` is an external field on an external type which is why the local type extension of `Product` and annotation of `name` is required.
+"""
+directive @provides(fields: FieldSet!) on FIELD_DEFINITION
+
+### `@requires`
+
+"""
+The `@requires` directive is used to annotate the required input fieldset from a base type for a resolver. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. For example:
+
+```graphql example -- using {@requires}
+# extended from the Users service
+extend type User @key(fields: "id") {
+ id: ID! @external
+ email: String @external
+ reviews: [Review] @requires(fields: "email")
+}
+```
+
+In this case, the Reviews service adds new capabilities to the `User` type by providing a list of `reviews` related to a user. In order to fetch these reviews, the Reviews service needs to know the `email` of the `User` from the Users service in order to look up the reviews. This means the `reviews` field / resolver *requires* the `email` field from the base `User` type.
+"""
+directive @requires(fields: FieldSet!) on FIELD_DEFINITION
+
+
+### `@external`
+
+"""
+The `@external` directive is used to mark a field as owned by another service. This allows service A to use fields from service B while also knowing at runtime the types of that field. For example:
+
+```graphql example -- using {@external}
+# extended from the Users service
+extend type User @key(fields: "email") {
+ email: String @external
+ reviews: [Review]
+}
+```
+
+This type extension in the Reviews service extends the `User` type from the Users service. It extends it for the purpose of adding a new field called `reviews`, which returns a list of `Review`s.
+"""
+directive @external on FIELD_DEFINITION
+
+scalar FieldSet
\ No newline at end of file
diff --git a/graphs.json b/graphs.json
new file mode 100644
index 0000000..54e3bb7
--- /dev/null
+++ b/graphs.json
@@ -0,0 +1,3 @@
+{
+ "styles": ["./apollo-colors.css", "./apollo-light.css", "./anatomy.css"]
+}
\ No newline at end of file
diff --git a/inaccessible/coreDirectives.graphql b/inaccessible/coreDirectives.graphql
new file mode 100644
index 0000000..3b17e1c
--- /dev/null
+++ b/inaccessible/coreDirectives.graphql
@@ -0,0 +1,5 @@
+schema
+ @core(feature: "https://specs.apollo.dev/core/v0.2")
+ @core(feature: "https://specs.apollo.dev/inaccessible/v0.1") {
+ query: Query
+}
\ No newline at end of file
diff --git a/inaccessible/inaccessible.spec.graphql b/inaccessible/inaccessible.spec.graphql
new file mode 100644
index 0000000..2b2d73f
--- /dev/null
+++ b/inaccessible/inaccessible.spec.graphql
@@ -0,0 +1,124 @@
+@id(url: "https://specs.apollo.dev/inaccessible/v1.0")
+
+"""
+The {@inaccessible} directive removes definitions from a schema's API.
+
+```raw html
+
+
Status
Release
+
Version
0.1
+
+
+
+```
+
+This document defines a [core feature](https://specs.apollo.dev/core) named `inaccessible` for removing fields and types from a core schema. "Types" will be used throughout this document to refer to Object, Interface, and Union types in GraphQL.
+
+This specification provides machinery to remove fields and types in a *core schema* which have the `@inaccessible` directive applied.
+
+# How to read this document
+
+This document uses [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt) guidance regarding normative terms: MUST / MUST NOT / REQUIRED / SHALL / SHALL NOT / SHOULD / SHOULD NOT / RECOMMENDED / MAY / OPTIONAL.
+
+# Definitions
+
+## Processor
+
+This specification makes references to **Processors**. Processors are described in the [Actors section of the `@core` spec](https://specs.apollo.dev/core/v0.2/#sec-Actors) as an actor which can perform transformations on a core schema. In the case of `@inaccessible`, the Processor will be expected to remove various parts of a core schema.
+
+# Example: Sensitive User Data
+
+*This section is non-normative.*
+
+We'll refer to this example of a core schema with sensitive user data throughout the document:
+
+:::[example](./schema.graphql) -- Core schema example
+
+The schema above contains both a field (`User.id`) and type (`BankAccount`) that are marked as `@inaccessible`. These symbols should be omitted from the processed schema anywhere they would appear. When the processed schema below is generated from this core schema, notice what has been removed:
+* `User.id` field
+* `BankAccount` type
+* `User.bankAccount` field (because it _returns_ the `BankAccount` type)
+* `Account` union's `BankAccount` type
+
+:::[example](./processedSchema.graphql) -- Core schema after processing
+
+# Overview
+
+*This section is non-normative.* It describes the motivation behind the directives defined by this specification.
+
+A core schema which has been processed according to the inaccessible spec is a queryable graph, intended to be served by a [Data Core](https://specs.apollo.dev/core/v0.2/#sec-Actors). Various use cases require that fields and types should not be visible to or queried for by clients. The `@inaccessible` directive fulfills this requirement, providing schema authors a mechanism to specify which fields and types should be omitted from the processed schema.
+
+# Basic Requirements
+
+Schemas using the `inaccessible` core feature must be valid [core schema documents](https://specs.apollo.dev/core/v0.2) with *@core directives* referencing the `core` specification and this specification.
+
+Here is an example `@core` usage:
+
+:::[example](./coreDirectives.graphql) -- required @core directives
+
+As described in the [core schema specification](https://specs.apollo.dev/core/v0.2/#sec-Prefixing), your schema may prefix the `@inaccessible` directive by including an `as` argument to the `@core` directive which references this specification. All references to `@inaccessible` in this specification MUST be interpreted as referring to names with the appropriate prefix chosen within your schema.
+
+In order to use the directive described by this specification, GraphQL requires you to include the definition in your schema.
+
+## Producer Responsibilities
+
+[Producers](https://specs.apollo.dev/core/v0.2/#sec-Actors) MUST include a definition of the directive compatible with the above definition and all usages in the document.
+
+## Processor Responsibilities
+
+The Processor is responsible for removing all inaccessible elements from the schema output. Note in the `InaccessibleRemoval` algorithm below that because a Union can belong to another Union's set of types, the removal of a Union type may have an upwards "cascading" effect, causing other Unions to become candidates for removal.
+
+# Algorithms
+
+## Is Inaccessible?
+
+Return true if the named element {element} is inaccessible.
+
+IsInaccessible(document, element) :
+ 1. If {IsMarkedInaccessible(document, element)}, **Return** {true}
+ 2. If {element} is a FieldDefinition,
+ 1. Let {parent} be the parent definition for {element}
+ 2. If {IsMarkedInaccessible(document, parent)}, **Return** {true}
+ 3. **Return** {false}
+
+Return true iff the named element {element} is marked as inaccessible.
+
+IsMarkedInaccessible(document, element) :
+ 1. Let {assignments} be the result of assigning features via {AssignFeatures(document)}
+ 2. For each Directive {d} on {element},
+ 1. If {assignments}`[`{element}`]` is a Directive whose `feature` argument is this spec, **Return** {true}
+ 3. **Return** {false}
+
+## Remove Inaccessible Elements
+
+Given a schema document, return the set of all schema elements which should be removed in the API.
+
+RemoveInaccessible(document) :
+ 1. For each named schema element {e} defined in the {document},
+ 1. If {IsInaccessible(document, e)} is {true}, {Remove(document, e)}
+
+Remove(document, element) :
+ 1. If {element} is a Field or Input Field,
+ 1. Delete the definition of {element} in {document}
+ 2. Let {parent} be the parent type of {f} in {document}
+ 2. If {parent} has no fields, {Remove(document, parent)}
+ 2. If {element} is a type:
+ 1. Delete all definitions and extensions of {element} in {document}
+ 2. If {element} is an output type (object, interface, union, or scalar):
+ 1. For each Field {f} in {document} where {f} has a Return Type of {element}, {Remove(document, f)}
+ 3. If {element} is an input type (input object, enum, or scalar):
+ 1. For each Field {f} in {document} where {f} has any argument of type {element}, {Remove(document, f)}
+ 2. For each input object type {t} in {document},
+ 1. For each input field {f} of {t} where the type of {f} is {element}, {Remove(document, f)}
+ 4. If {element} is an Object or Union type,
+ 2. For each Union {u} in {document} where {element} is a member of {u},
+ 1. Delete {element} as member of {u}
+ 2. If {u} has no members, {Remove(document, u)}
+ 5. If {element} is an Interface type,
+ 3. For each Object or Interface type {t} which implements {element} in {document},
+ 1. Delete {element} as an interface conformance of {t}
+"""
+schema { query: Query }
+
+
+directive @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION
\ No newline at end of file
diff --git a/inaccessible/processedSchema.graphql b/inaccessible/processedSchema.graphql
new file mode 100644
index 0000000..159c330
--- /dev/null
+++ b/inaccessible/processedSchema.graphql
@@ -0,0 +1,28 @@
+directive @core(as: String, feature: String!, for: core__Purpose) repeatable on SCHEMA
+
+enum core__Purpose {
+ EXECUTION
+ SECURITY
+}
+
+schema
+ @core(feature: "https://specs.apollo.dev/core/v0.2")
+{
+ query: Query
+}
+
+type Query {
+ user(id: String!): User
+}
+
+type User {
+ name: String!
+ email: String!
+ accounts: [Account]
+}
+
+type ForumAccount {
+ handle: String!
+}
+
+union Account = ForumAccount
\ No newline at end of file
diff --git a/inaccessible/schema.graphql b/inaccessible/schema.graphql
new file mode 100644
index 0000000..96d9f7f
--- /dev/null
+++ b/inaccessible/schema.graphql
@@ -0,0 +1,38 @@
+directive @link(as: String, url: String!, for: link__Purpose) repeatable on SCHEMA
+directive @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION
+
+enum link__Purpose {
+ EXECUTION
+ SECURITY
+}
+
+schema
+ @link(url: "https://specs.apollo.dev/link/v0.2")
+ @link(url: "https://specs.apollo.dev/inaccessible/v0.1", for: SECURITY)
+{
+ query: Query
+}
+
+type Query {
+ user(id: String!): User
+}
+
+type User {
+ id: String! @inaccessible
+ name: String!
+ email: String!
+ bankAccount: BankAccount
+ accounts: [Account]
+}
+
+type BankAccount @inaccessible {
+ id: String!
+ accountNumber: String!
+}
+
+type ForumAccount {
+ handle: String!
+}
+
+union Account = BankAccount | ForumAccount
+
diff --git a/inaccessible/spec.md b/inaccessible/spec.md
new file mode 100644
index 0000000..55fc482
--- /dev/null
+++ b/inaccessible/spec.md
@@ -0,0 +1,121 @@
+# Inaccessible
+
+
for removing fields and types from a core schema
+
+```raw html
+
+
Status
Release
+
Version
0.1
+
+
+
+```
+
+This document defines a [core feature](https://specs.apollo.dev/core) named `inaccessible` for removing fields and types from a core schema. "Types" will be used throughout this document to refer to Object, Interface, and Union types in GraphQL.
+
+This specification provides machinery to remove fields and types in a *core schema* which have the `@inaccessible` directive applied.
+
+# How to read this document
+
+This document uses [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt) guidance regarding normative terms: MUST / MUST NOT / REQUIRED / SHALL / SHALL NOT / SHOULD / SHOULD NOT / RECOMMENDED / MAY / OPTIONAL.
+
+# Definitions
+
+## Processor
+
+This specification makes references to **Processors**. Processors are described in the [Actors section of the `@core` spec](https://specs.apollo.dev/core/v0.2/#sec-Actors) as an actor which can perform transformations on a core schema. In the case of `@inaccessible`, the Processor will be expected to remove various parts of a core schema.
+
+# Example: Sensitive User Data
+
+*This section is non-normative.*
+
+We'll refer to this example of a core schema with sensitive user data throughout the document:
+
+:::[example](./schema.graphql) -- Core schema example
+
+The schema above contains both a field (`User.id`) and type (`BankAccount`) that are marked as `@inaccessible`. These symbols should be omitted from the processed schema anywhere they would appear. When the processed schema below is generated from this core schema, notice what has been removed:
+* `User.id` field
+* `BankAccount` type
+* `User.bankAccount` field (because it _returns_ the `BankAccount` type)
+* `Account` union's `BankAccount` type
+
+:::[example](./processedSchema.graphql) -- Core schema after processing
+
+# Overview
+
+*This section is non-normative.* It describes the motivation behind the directives defined by this specification.
+
+A core schema which has been processed according to the inaccessible spec is a queryable graph, intended to be served by a [Data Core](https://specs.apollo.dev/core/v0.2/#sec-Actors). Various use cases require that fields and types should not be visible to or queried for by clients. The `@inaccessible` directive fulfills this requirement, providing schema authors a mechanism to specify which fields and types should be omitted from the processed schema.
+
+# Basic Requirements
+
+Schemas using the `inaccessible` core feature must be valid [core schema documents](https://specs.apollo.dev/core/v0.2) with *@core directives* referencing the `core` specification and this specification.
+
+Here is an example `@core` usage:
+
+:::[example](./coreDirectives.graphql) -- required @core directives
+
+As described in the [core schema specification](https://specs.apollo.dev/core/v0.2/#sec-Prefixing), your schema may prefix the `@inaccessible` directive by including an `as` argument to the `@core` directive which references this specification. All references to `@inaccessible` in this specification MUST be interpreted as referring to names with the appropriate prefix chosen within your schema.
+
+In order to use the directive described by this specification, GraphQL requires you to include the definition in your schema.
+
+:::[definition](inaccessible.spec.graphql)
+
+## Producer Responsibilities
+
+[Producers](https://specs.apollo.dev/core/v0.2/#sec-Actors) MUST include a definition of the directive compatible with the above definition and all usages in the document.
+
+## Processor Responsibilities
+
+The Processor is responsible for removing all inaccessible elements from the schema output. Note in the `InaccessibleRemoval` algorithm below that because a Union can belong to another Union's set of types, the removal of a Union type may have an upwards "cascading" effect, causing other Unions to become candidates for removal.
+
+# Algorithms
+
+## Is Inaccessible?
+
+Return true if the named element {element} is inaccessible.
+
+IsInaccessible(document, element) :
+ 1. If {IsMarkedInaccessible(document, element)}, **Return** {true}
+ 2. If {element} is a FieldDefinition,
+ 1. Let {parent} be the parent definition for {element}
+ 2. If {IsMarkedInaccessible(document, parent)}, **Return** {true}
+ 3. **Return** {false}
+
+Return true iff the named element {element} is marked as inaccessible.
+
+IsMarkedInaccessible(document, element) :
+ 1. Let {assignments} be the result of assigning features via {AssignFeatures(document)}
+ 2. For each Directive {d} on {element},
+ 1. If {assignments}`[`{element}`]` is a Directive whose `feature` argument is this spec, **Return** {true}
+ 3. **Return** {false}
+
+## Remove Inaccessible Elements
+
+Given a schema document, return the set of all schema elements which should be removed in the API.
+
+RemoveInaccessible(document) :
+ 1. For each named schema element {e} defined in the {document},
+ 1. If {IsInaccessible(document, e)} is {true}, {Remove(document, e)}
+
+Remove(document, element) :
+ 1. If {element} is a Field or Input Field,
+ 1. Delete the definition of {element} in {document}
+ 2. Let {parent} be the parent type of {f} in {document}
+ 2. If {parent} has no fields, {Remove(document, parent)}
+ 2. If {element} is a type:
+ 1. Delete all definitions and extensions of {element} in {document}
+ 2. If {element} is an output type (object, interface, union, or scalar):
+ 1. For each Field {f} in {document} where {f} has a Return Type of {element}, {Remove(document, f)}
+ 3. If {element} is an input type (input object, enum, or scalar):
+ 1. For each Field {f} in {document} where {f} has any argument of type {element}, {Remove(document, f)}
+ 2. For each input object type {t} in {document},
+ 1. For each input field {f} of {t} where the type of {f} is {element}, {Remove(document, f)}
+ 4. If {element} is an Object or Union type,
+ 2. For each Union {u} in {document} where {element} is a member of {u},
+ 1. Delete {element} as member of {u}
+ 2. If {u} has no members, {Remove(document, u)}
+ 5. If {element} is an Interface type,
+ 3. For each Object or Interface type {t} which implements {element} in {document},
+ 1. Delete {element} as an interface conformance of {t}
+
diff --git a/link/basic.graphql b/link/basic.graphql
new file mode 100644
index 0000000..38e6671
--- /dev/null
+++ b/link/basic.graphql
@@ -0,0 +1,14 @@
+schema
+ @link(url: "https://specs.apollo.dev/core/v0.1")
+ @link(url: "https://specs.example.com/example/v1.0")
+{
+ query: Query
+}
+
+type Query {
+ field: Int @example
+}
+
+directive @example on FIELD_DEFINITION
+
+directive @link(url: String!, as: String) repeatable on SCHEMA
diff --git a/link/link-v1.0.graphql b/link/link-v1.0.graphql
new file mode 100644
index 0000000..11709de
--- /dev/null
+++ b/link/link-v1.0.graphql
@@ -0,0 +1,456 @@
+@id(url: "https://specs.apollo.dev/link/v1.0")
+
+"""
+```raw html
+
+
Status
Draft
+
Version
2.0
+
+
+
+```
+
+Core schemas provide tools for linking definitions from different GraphQL schemas together into one.
+
+```graphql example -- linking a directive from another schema
+extend schema
+ # 👇🏽 schemas are identified by a url
+ @link(url: "https://internal.example.com/admin")
+
+type Query {
+ allUsers: [User] @admin__adminOnly # 👈🏽 remote identifier, namespaced
+}
+```
+
+```graphql example -- importing a directive from another schema
+extend schema
+ # specific definitions can be imported 👇🏽
+ @link(url: "https://internal.example.com/admin", import: ["@adminOnly"])
+
+type Query {
+ allUsers: [User] @adminOnly # 👈🏽 remote identifier, imported
+}
+```
+
+This document introduces a set of conventions for linking and namespacing within GraphQL schemas. Core schemas are not a new kind of document and do not introduce any new syntax—they are just GraphQL schemas which can be interpreted according to the conventions outlined in this doc.
+
+# Renaming {@link}
+
+It is possible to rename {@link} with the same {@link.as} mechanism used for all links:
+
+```graphql example -- Renaming {@link} to {@linkOther}
+schema
+ @linkOther(url: "https://specs.apollo.dev/link/v1.0", import: [{name: "@link", as: "@linkOther"}])
+ @linkOther(url: "https://example.com/example/v1.0")
+{
+ query: Query
+}
+
+type SomeType {
+ field: Int @example
+}
+```
+
+# Prefixing
+
+With the exception of a single root directive, core feature specifications MUST prefix all schema elements they introduce. The prefix:
+ 1. MUST match the name of the feature as derived from the feature's specification URL,
+ 2. MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name), and
+ 3. MUST NOT contain the core namespace separator, which is two underscores ({"__"}), and
+ 4. MUST NOT end with an underscore (which would create ambiguity between whether {"x___y"} is prefix `x_` for element `y` or prefix `x` for element `_y`).
+
+Prefixed names consist of the name of the feature, followed by two underscores, followed by the name of the element, which can be any valid [GraphQL name](https://spec.graphql.org/draft/#Name). For instance, the `core` specification (which you are currently reading) introduces an element named [{@link}](#@link), and the `join` specification introduces an element named {@join__field} (among others).
+
+Note that both parts must be valid GraphQL names, and GraphQL names cannot start with digits, so core feature specifications cannot introduce names like `@feature__24hours`.
+
+A feature's *root directive* is an exception to the prefixing requirements. Feature specifications MAY introduce a single directive which carries only the name of the feature, with no prefix required. For example, the `core` specification introduces a {@link} directive. This directive has the same name as the feature ("`core`"), and so requires no prefix.
+
+```graphql example -- Using the @link directive without changing the prefix
+schema
+ @link(url: "https://specs.apollo.dev/link/v1.0", import: ["@link"])
+ @link(url: "https://spec.example.com/example/v1.0") {
+ query: Query
+}
+
+type User {
+ name: String @example(data: ITEM)
+}
+
+# An enum used to provide structured data to the example spec.
+# It is prefixed with the name of the spec.
+enum example__Data {
+ ITEM
+}
+
+directive @example(data: example__Data) on FIELD_DEFINITION
+
+directive @link(url: String!, as: String) repeatable on SCHEMA
+```
+
+The prefix MUST NOT be elided within documentation; definitions of schema elements provided within the spec MUST include the feature's name as a prefix.
+
+## Elements which must be prefixed
+
+Feature specs MUST prefix the following schema elements:
+ - the names of any object types, interfaces, unions, enums, or input object types defined by the feature
+ - the names of any directives introduced in the spec, with the exception of the *root directive*, which must have the same name as the feature
+
+:::[example](prefixing.graphql) -- Prefixing
+
+# Versioning
+
+VersionTag : "v" Version
+
+Version : Major "." Minor
+
+Major : NumericIdentifier
+
+Minor : NumericIdentifier
+
+NumericIdentifier : "0"
+ | PositiveDigit Digit*
+
+Digit : "0" | PositiveDigit
+
+PositiveDigit : "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
+
+Specs are versioned with a **subset** of a [Semantic Version Number](https://semver.org/spec/v2.0.0.html) containing only the major and minor parts. Thus, specifications SHOULD provide a version of the form `v`{Major}`.`{Minor}, where both integers >= 0.
+
+```text example -- Valid version tags
+v2.2
+v1.0
+v1.1
+v0.1
+```
+
+As specified by semver, spec authors SHOULD increment the:
+
+{++
+
+- MAJOR version when you make incompatible API changes,
+- MINOR version when you add functionality in a backwards compatible manner
+
+++}
+
+Patch and pre-release qualifiers are judged to be not particularly meaningful in the context of core features, which are (by definition) interfaces rather than implementations. The patch component of a semver denotes a bug fix which is backwards compatible—that is, a change to the implementation which does not affect the interface. Patch-level changes in the version of a spec denote wording clarifications which do not require implementation changes. As such, it is not important to track them for the purposes of version resolution.
+
+As with [semver](https://semver.org/spec/v2.0.0.html), the `0.x` version series is special: there is no expectation of compatibility between versions `0.x` and `0.y`. For example, a processor must not activate implementation `0.4` to satisfy a requested version of `0.2`.
+
+## Satisfaction
+
+Given a version {requested} by a document and an {available} version of an implementation, the following algorithm will determine if the {available} version can satisfy the {requested} version:
+
+Satisfies(requested, available) :
+ 1. If {requested}.{Major} ≠ {available}.{Major}, return {false}
+ 2. If {requested}.{Major} = 0, return {requested}.{Minor} = {available}.{Minor}
+ 3. Return {requested}.{Minor} <= {available}.{Minor}
+
+## Referencing versions and activating implementations
+
+Schema documents MUST reference a feature version which supports all the schema elements and behaviors required by the document. As a practical matter, authors will generally prefer to reference a version they have reason to believe is supported by the most processors; depending on context, this might be an old stable version with a low major version, or a new less-deprecated version with a large major version.
+
+If a processor chooses to activate support for a feature, the processor MUST activate an implementation which can [satisfy](#sec-Satisfaction) the version required by the document.
+
+
+# Processing Schemas
+
+```mermaid diagram
+graph LR
+ schema(["📄 Input Schema"]):::file-->proc("🤖 Processor")
+ proc-->output(["📄 Output Schema"]):::file
+ classDef file fill:none,color:#22262E;
+ style proc fill:none,stroke:fuchsia,color:fuchsia;
+```
+
+A common use case is that of a processor which consumes a valid input schema and generates an output schema.
+
+The general guidance for processor behavior is: don't react to what you don't understand.
+
+Specifically, processors:
+ - SHOULD pass through {@link} directives which reference unknown feature URLs
+ - SHOULD pass through prefixed directives, types, and other schema elements
+ - SHOULD pass through directives which are not [associated with](#AssignFeatures) a {@link} feature
+
+Processors MAY accept configuration which overrides these default behaviors.
+
+Additionally, processors which prepare the schema for final public consumption MAY choose to eliminate all unknown directives and prefixed types in order to hide schema implementation details within the published schema. This will impair the operation of tooling which relies on these directives—such tools will not be able to run on the output schema, so the benefits and costs of this kind of information hiding should be weighed carefully on a case-by-case basis.
+
+# Validations & Algorithms
+
+This section lays out algorithms for processing core schemas.
+
+Algorithms described in this section may produce *validation failures* if a document does not conform to the requirements core schema document. Validation failures SHOULD halt processing. Some consumers, such as authoring tools, MAY attempt to continue processing in the presence of validation failures, but their behavior in such cases is unspecified.
+
+## Bootstrapping
+
+Determine the name of the core specification within the document.
+
+It is possible to [rename the core feature](#sec-Renaming-core-itself) within a document. This process determines the actual name for the core feature if one is present.
+
+- **Fails** the *Has Schema* validation if there are no SchemaDefinitions in the document
+- **Fails** the *Has Core Feature* validation if the `core` feature itself is not referenced with a {@link} directive within the document
+- **Fails** the *Bootstrap Core Feature Listed First* validation if the reference to the `core` feature is not the first {@link} directive on the document's SchemaDefinition
+- **Fails** the *Core Directive Incorrect Definition* validation if the {@link} directive definition does not *match* the directive as defined by this specification.
+
+For the purposes of this algorithm, a directive's definition in a schema *matches* a definition provided in this specification if:
+- Its arguments have the specified names, types, and default values (or lack thereof)
+- It is defined as `repeatable` if and only if the specification's definition defines it as `repeatable`
+- The set of locations it belongs to is the same set of locations in the specification's definition.
+
+The following aspects may differ between the definition in the schema and the definition in the specification without preventing the definitions from *matching*:
+- The name of the directive (due to [prefixing](#sec-Prefixing))
+- The order of arguments
+- The order of locations
+- The directive's description string
+- Argument description strings
+- Directives applied to argument definitions
+
+Bootstrap(document) :
+1. Let {schema} be the only SchemaDefinition in {document}. (Note that legal GraphQL documents [must include at most one SchemaDefinition](http://spec.graphql.org/draft/#sec-Root-Operation-Types).)
+ 1. ...if no SchemaDefinitions are present in {document}, the ***Has Schema* validation fails**.
+1. For each directive {d} on {schema},
+ 1. If {d} has a [`url:`](#@link/feature) argument which [parses as a feature URL](#@link/feature), *and* whose identity is {"https://specs.apollo.dev/core/"} *and* whose version is {"v0.1"}, *and either* {d} has an [`as:`](#@link/as) argument whose value is equal to {d}'s name *or* {d} does not have an [`as:`](#@link/as) argument and {d}'s name is `core`:
+ - If any directive on {schema} listed before {d} has the same name as {d}, the ***Bootstrap Core Feature Listed First* validation fails**.
+ - If the definition of the directive {d} does not *match* the [definition of {@link} in this specification](#@link), the ***Core Directive Incorrect Definition* validation fails**.
+ - Otherwise, **Return** {d}'s name.
+- If no matching directive was found, the ***Has Core Feature* validation fails**.
+
+## Feature Collection
+
+Collect a map of ({featureName}: `String`) -> `Directive`, where `Directive` is a {@link} Directive which introduces the feature named {featureName} into the document.
+
+- **Fails** the *Name Uniqueness* validation if feature names are not unique within the document.
+- **Fails** *Invalid Feature URL* validation for any invalid feature URLs.
+
+CollectFeatures(document) :
+ - Let {coreName} be the name of the core feature found via {Bootstrap(document)}
+ - Let {features} be a map of {featureName}: `String` -> `Directive`, initially empty.
+ - For each directive {d} named {coreName} on the SchemaDefinition within {document},
+ - Let {specifiedFeatureName} and {version} be the result of parsing {d}'s `url:` argument according to the [specified rules for feature URLs](#@link/feature)
+ - If the `url:` is not present or fails to parse:
+ - The ***Invalid Feature URL* validation fails** for {d},
+ - Let {featureName} be the {d}'s [`as:`](#@link/as) argument or, if the argument is not present, {specifiedFeatureName}
+ - If {featureName} exists within {features}, the ***Name Uniqueness* validation fails**.
+ - Insert {featureName} => {d} into {features}
+ - **Return** {features}
+
+
+Prefixes, whether implicit or explicit, must be unique within a document. Valid:
+
+:::[example](prefixing.graphql#schema[0]) -- Unique prefixes
+
+It is also valid to reference multiple versions of the same spec under different prefixes:
+
+:::[example](prefix-uniqueness.graphql#schema[0]) -- Explicit prefixes allow multiple versions of the same spec to coexist within a Document
+
+Without the explicit [`as:`](#@link/as), the above would be invalid:
+
+:::[counter-example](prefix-uniqueness.graphql#schema[1]) -- Non-unique prefixes with multiple versions of the same spec
+
+Different specs with the same prefix are also invalid:
+
+:::[counter-example](prefix-uniqueness.graphql#schema[2]) -- Different specs with non-unique prefixes
+
+## Assign Features
+
+Create a map of {element}: *Any Named Element* -> {feature}: `Directive` | {null}, associating every named schema element within the document with a feature directive, or {null} if it is not associated with a feature.
+
+AssignFeatures(document) :
+ - Let {features} be the result of collecting features via {CollectFeatures(document)}
+ - Let {assignments} be a map of ({element}: *Any Named Element*) -> {feature}: `Directive` | {null}, initally empty
+ - For each named schema element {e} within the {document}
+ - Let {name} be the name of the {e}
+ - If {e} is a Directive and {name} is a key within {features},
+ - Insert {e} => {features}`[`{name}`]` into {assignments}
+ - **Continue** to next {e}
+ - If {name} begins with {"__"},
+ - Insert {e} => {null} into {assignments}
+ - **Continue** to next {e}
+ - If {name} contains the substring {"__"},
+ - Partition {name} into `[`{prefix}, {base}`]` at the first {"__"} (that is, find the shortest {prefix} and longest {base} such that {name} = {prefix} + {"__"} + {base})
+ - If {prefix} exists within {features}, insert {e} => {features}`[`{prefix}`]` into {assignments}
+ - Else, insert {e} => {null} into {assignments}
+ - **Continue** to next {e}
+ - Insert {e} => {null} into {assignments}
+ - **Return** {assignments}
+
+## Is In API?
+
+Determine if any schema element is included in the [API](#sec-Parts-of-a-Core-Schema) described by the core schema. A schema element is any part of a GraphQL document using type system definitions that has a [name](https://spec.graphql.org/draft/#Name).
+
+IsInAPI(element) :
+ - Let {assignments} be the result of assigning features to elements via {AssignFeatures(document)}
+ - If {assignments}`[`{element}`]` is {null}, **Return** {true}
+ - Else, **Return** {false}
+
+Note: Later versions of this specification may add other ways to affect the behavior of this algorithm, but those mechanisms will only be enabled if you reference those hypothetical versions of this specification.
+
+## Is Affected By Feature?
+
+Determine if a schema element is *affected* by a given feature.
+
+IsAffected(element, feature):
+ - Let {assignments} be the result of assigning features to elements via {AssignFeatures(document)}
+ - For each directive {d} on {element}, If {assignments}`[`{d}`]` is {feature}, **Return** {true}
+ - If {element} is a FieldDefinition,
+ - Let {parent} be the parent ObjectDefinition or InterfaceDefinition for {element}
+ - If {IsAffected(parent, feature)}, **Return** {true}
+ - For each argument type {a} declared on {element},
+ - Let {t} be the InputDefinition, EnumDefinition, or ScalarDefinition for argument {a}
+ - If {IsAffected(t, feature)}, **Return** {true}
+ - Let {return} be the ObjectDefinition, InterfaceDefinition, or UnionDefinition for {element}'s return type
+ - If {IsAffected(return, feature)}, **Return** {true}
+ - If {element} is an InputDefinition,
+ - For each InputFieldDefinition {field} within {element},
+ - Let {t} be the InputDefinition, EnumDefinition, or ScalarDefinition for the type of {field}
+ - If {IsAffected(t, feature)}, **Return** {true}
+ - If {element} is an EnumDefinition,
+ - For each EnumValueDefinition {value} in {element},
+ - If {IsAffected(value, feature)}, **Return** {true}
+"""
+schema
+{ query: Query }
+
+
+"""
+Link a foreign schema by its URL.
+"""
+directive @link(
+ """
+ The foreign schema's URL.
+
+ Link URLs serve two main purposes:
+ - Providing a unique identifier for the foreign schema
+ - Directing human readers to documentation about the foreign schema
+
+ Link URLs SHOULD be [RFC 3986 URLs](https://tools.ietf.org/html/rfc3986). When viewed, the URL SHOULD provide schema documentation in some human-readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
+
+ Link URLs MAY contain information about the spec's [name](#sec-Prefixing) and [version](#sec-Versioning):
+
+ ```html diagram -- Basic anatomy of a link URL
+
+ https://spec.example.com/a/b/c/mySchema/v1.0
+
+ ```
+
+ The final two segments of the URL's [path](https://tools.ietf.org/html/rfc3986#section-3.3) MAY contain the schema's name and a [version tag](#sec-Versioning), in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid {VersionTag}. To be recognized as a name, the penultimate path component MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name) which does not include the namespace separator ({"__"}).
+
+ Empty final path components (that is, trailing slashes) and any URL components which have not been assigned a meaning (such as the fragment and query) MUST be ignored.
+
+ ```html diagram -- Ignoring meaningless parts of a URL
+
+ https://example.com/exampleSchema/v1.0/?key=val&k2=v2#frag
+
+ ```
+
+ All of these are valid arguments to `url`, and their interpretations:
+
+ | url | normalized url | name | version |
+ | ------------------------------------------------- | ------------------------------------------ | ------- | -------- |
+ | https://spec.example.com/a/b/mySchema/v1.0/ | https://spec.example.com/a/b/mySchema/v1.0 | mySchema | v1.0 |
+ | https://spec.example.com | https://spec.example.com | *(null)* | *(null)* |
+ | https://spec.example.com/mySchema/v0.1?q=v#frag | https://spec.example.com/mySchema/v0.1 | mySchema | v0.1 |
+ | https://spec.example.com/v1.0 | https://spec.example.com/v1.0 | *(null)* | v1.0 |
+ | https://spec.example.com/vX | https://spec.example.com/vX | vX | *(null)* |
+
+ If `name` is present, that [namespace prefix](#sec-Prefixing) will automatically be linked to the URL. If a `name` is not present, then elements of the foreign schema must be [`imported`](#@link/import) in order to be referenced.
+ """
+ url: String!,
+
+ """
+ Change the [namespace prefix](#sec-Prefixing) assigned to this schema.
+
+ The name must be a valid GraphQL identifier, and must not contain the namespace separator ({"__"}).
+
+ By default, {@link} will assign a prefix based on the `name` extracted from the URL. If no `name` is present, a prefix will not be assigned.
+
+ Providing [`as:`](#@link/as) overrides the default behavior: the foreign schema will be assigned the provided prefix, regardless of the `name` present in the URL (or the lack of one).
+
+ ```graphql example -- Using {@link}(url:, as:) to use a feature with a custom name
+ schema
+ @link(url: "https://specs.apollo.dev/link/v1.0")
+ @link(url: "https://spec.example.com/example/v1.0", as: "eg")
+ {
+ query: Query
+ }
+
+ type User {
+ # Specifying `as: "eg"` transforms @example into @eg
+ name: String @eg(data: ITEM)
+ }
+
+ # Additional specified schema elements must have their prefixes set
+ # to the new name.
+ enum eg__Data {
+ ITEM
+ }
+
+ # Name transformation must also be applied to definitions pulled in from
+ # specifications.
+ directive @eg(data: eg__Data) on FIELD_DEFINITION
+
+ directive @link(url: String!, as: String) repeatable on SCHEMA
+ ```
+ """
+ as: String,
+
+ """
+ Import definitions into the local namespace.
+ """
+ import: [Import],
+
+ """
+ An optional [purpose](#Purpose) for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
+
+ By default, {@link}s SHOULD fail open. This means that {@link}s to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
+
+ This behavior is different for {@link}s with a specified purpose:
+ - `SECURITY` links convey metadata necessary to compute the API schema and securely resolve fields within it
+ - `EXECUTION` links convey metadata necessary to correctly resolve fields within the schema
+ """
+ for: Purpose)
+ repeatable on SCHEMA
+
+"""
+TK describe an import
+"""
+scalar Import
+
+"""
+The role of a feature referenced with {@link}.
+
+This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail-open behavior of core schema consumers is undesirable.
+
+Note we'll refer to directives from features which are `for: SECURITY` or `for: EXECUTION` as "`SECURITY` directives" and "`EXECUTION` directives", respectively.
+"""
+enum Purpose {
+ """
+ `SECURITY` links provide metadata necessary to securely resolve fields. For instance, a hypothetical {auth} feature may provide an {@auth} directive to flag fields which require authorization. If a data core does not support the {auth} feature and serves those fields anyway, these fields will be accessible without authorization, compromising security.
+
+ Security-conscious consumers MUST NOT serve a field if:
+ - the schema definition has **any** unsupported SECURITY directives,
+ - the field's parent type definition has **any** unsupported SECURITY directives,
+ - the field's return type definition has **any** unsupported SECURITY directives, or
+ - the field definition has **any** unsupported SECURITY directives
+
+ Such fields are *not securely resolvable*. Security-conscious consumers MAY serve schemas with fields which are not securely resolvable. However, they MUST remove such fields from the schema before serving it.
+
+ Less security-conscious consumers MAY choose to relax these requirements. For instance, servers may provide a development mode in which unknown SECURITY directives are ignored, perhaps with a warning. Such software may also provide a way to explicitly disable some or all SECURITY links during development.
+
+ More security-conscious consumers MAY choose to enhance these requirements. For instance, production servers MAY adopt a policy of entirely rejecting any schema which contains ANY unsupported SECURITY links, even if those links are never used to annotate the schema.
+ """
+ SECURITY
+
+ """
+ `EXECUTION` features provide metadata necessary to correctly resolve fields. For instance, a hypothetical {ts} feature may provide a `@ts__resolvers` annotation which references a TypeScript module of field resolvers. A consumer which does not support the {ts} feature will be unable to correctly resolve such fields.
+
+ Consumers MUST NOT serve a field if:
+ - the schema's definition has **any** unsupported EXECUTION directives,
+ - the field's parent type definition has **any** unsupported EXECUTION directives,
+ - the field's return type definition has **any** unsupported EXECUTION directives, or
+ - the field definition has **any** unsupported EXECUTION directives
+
+ Such fields are *unresolvable*. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION features, even if those features are never used in the schema.
+ """
+ EXECUTION
+}
diff --git a/link/prefix-uniqueness.graphql b/link/prefix-uniqueness.graphql
new file mode 100644
index 0000000..e065e52
--- /dev/null
+++ b/link/prefix-uniqueness.graphql
@@ -0,0 +1,25 @@
+schema
+ @link(url: "https://specs.apollo.dev/core/v0.1")
+ @link(url: "https://specs.example.com/A/1.0") # name is A
+ @link(url: "https://specs.example.com/A/2.0", as: "A2") # name is A2
+{
+ query: Query
+}
+
+schema
+ @link(url: "https://specs.apollo.dev/core/v0.1")
+ @link(url: "https://specs.example.com/A/1.0") # name is A
+ @link(url: "https://specs.example.com/A/2.0") # name is A
+{
+ query: Query
+}
+
+schema
+ @link(url: "https://specs.apollo.dev/core/v0.1")
+ @link(url: "https://specs.example.com/A/1.0") # name is A
+ @link(url: "https://www.specs.com/specA/1.1", as: "A") # name is A
+{
+ query: Query
+}
+
+directive @link(url: String!, as: String) repeatable on SCHEMA
diff --git a/link/prefixing.graphql b/link/prefixing.graphql
new file mode 100644
index 0000000..11c5229
--- /dev/null
+++ b/link/prefixing.graphql
@@ -0,0 +1,46 @@
+schema
+ @link(url: "https://specs.apollo.dev/core/v0.1")
+ @link(url: "https://spec.example.com/foreignA/v1.0")
+ @link(url: "https://spec.example.com/foreignB/v2.0", as: "B") {
+ query: Query
+}
+
+"""
+foreignA__SomeType is a type defined by feature A.
+"""
+type foreignA__SomeType {
+ """
+ nativeField is a field defined by foreignA on a type also defined
+ by foreignA (namely foreignA__SomeType)
+ """
+ nativeField: Int @foreignA__fieldDirective
+}
+
+"""
+foreignA__SomeInput is an input specified by feature A
+"""
+input foreignA__SomeInput {
+ """
+ nativeInputField is defined by foreignA
+ """
+ nativeInputField: Int
+}
+
+"""
+foreignA__Items is specified by feature A
+"""
+enum foreignA__Items { ONE, TWO, THREE @B }
+
+"""
+@B is the root directive defined by foreignB
+
+Root directives are named after their feature
+"""
+directive @B on ENUM_VALUE
+
+"""
+@foreignA__fieldDirective is a non-root (prefixed) directive defined by foreignA
+"""
+directive @foreignA__fieldDirective on FIELD_DEFINITION
+
+directive @link(url: String!, as: String) repeatable on SCHEMA
diff --git a/netlify.toml b/netlify.toml
index 940c346..c5ba547 100644
--- a/netlify.toml
+++ b/netlify.toml
@@ -3,6 +3,6 @@
[build]
# This site has no build step at the moment. We just publish the contents.
- publish = "/"
+ publish = "/.graphs/https/specs.apollo.dev"
# Redirects are handled in the ./_redirects file, which has a simple format
diff --git a/package-lock.json b/package-lock.json
index 7b5c7e3..78a52dc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,8 +1,2430 @@
{
"name": "@apollo/specs.apollo.dev",
"version": "1.0.0",
- "lockfileVersion": 1,
+ "lockfileVersion": 2,
"requires": true,
+ "packages": {
+ "": {
+ "name": "@apollo/specs.apollo.dev",
+ "version": "1.0.0",
+ "license": "ISC",
+ "dependencies": {
+ "commonmark": "^0.29.3"
+ },
+ "bin": {
+ "specs.apollo.dev": "bin/library"
+ },
+ "devDependencies": {
+ "express": "^4.17.1",
+ "http-server": "^0.12.3",
+ "jsdom": "^16.4.0",
+ "puppeteer": "^5.5.0"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "14.14.10",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.10.tgz",
+ "integrity": "sha512-J32dgx2hw8vXrSbu4ZlVhn1Nm3GbeCFNw2FWL8S5QKucHGY0cyNwjdQdO+KMBZ4wpmC7KhLCiNsdk1RFRIYUQQ==",
+ "dev": true,
+ "optional": true
+ },
+ "node_modules/@types/yauzl": {
+ "version": "2.9.1",
+ "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz",
+ "integrity": "sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/abab": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz",
+ "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==",
+ "dev": true
+ },
+ "node_modules/accepts": {
+ "version": "1.3.7",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
+ "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
+ "dev": true,
+ "dependencies": {
+ "mime-types": "~2.1.24",
+ "negotiator": "0.6.2"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "7.4.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
+ "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+ "dev": true,
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-globals": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz",
+ "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==",
+ "dev": true,
+ "dependencies": {
+ "acorn": "^7.1.1",
+ "acorn-walk": "^7.1.1"
+ }
+ },
+ "node_modules/acorn-walk": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
+ "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/agent-base": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz",
+ "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6.0.0"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=",
+ "dev": true
+ },
+ "node_modules/asn1": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
+ "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+ "dev": true,
+ "dependencies": {
+ "safer-buffer": "~2.1.0"
+ }
+ },
+ "node_modules/assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/async": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
+ "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
+ "dev": true,
+ "dependencies": {
+ "lodash": "^4.17.14"
+ }
+ },
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
+ "dev": true
+ },
+ "node_modules/aws-sign2": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/aws4": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
+ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
+ "dev": true
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+ "dev": true
+ },
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/basic-auth": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz",
+ "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/bcrypt-pbkdf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+ "dev": true,
+ "dependencies": {
+ "tweetnacl": "^0.14.3"
+ }
+ },
+ "node_modules/bl": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz",
+ "integrity": "sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==",
+ "dev": true,
+ "dependencies": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
+ }
+ },
+ "node_modules/bl/node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "node_modules/body-parser": {
+ "version": "1.19.0",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
+ "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
+ "dev": true,
+ "dependencies": {
+ "bytes": "3.1.0",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "on-finished": "~2.3.0",
+ "qs": "6.7.0",
+ "raw-body": "2.4.0",
+ "type-is": "~1.6.17"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/body-parser/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/body-parser/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "node_modules/body-parser/node_modules/qs": {
+ "version": "6.7.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+ "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/browser-process-hrtime": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz",
+ "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==",
+ "dev": true
+ },
+ "node_modules/buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "node_modules/buffer-crc32": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+ "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/bytes": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+ "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
+ "dev": true
+ },
+ "node_modules/chownr": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
+ "dev": true
+ },
+ "node_modules/colors": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
+ "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.1.90"
+ }
+ },
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "dev": true,
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/commonmark": {
+ "version": "0.29.3",
+ "resolved": "https://registry.npmjs.org/commonmark/-/commonmark-0.29.3.tgz",
+ "integrity": "sha512-fvt/NdOFKaL2gyhltSy6BC4LxbbxbnPxBMl923ittqO/JBM0wQHaoYZliE4tp26cRxX/ZZtRsJlZzQrVdUkXAA==",
+ "dependencies": {
+ "entities": "~2.0",
+ "mdurl": "~1.0.1",
+ "minimist": ">=1.2.2",
+ "string.prototype.repeat": "^0.2.0"
+ },
+ "bin": {
+ "commonmark": "bin/commonmark"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+ "dev": true
+ },
+ "node_modules/content-disposition": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
+ "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "5.1.2"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
+ "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=",
+ "dev": true
+ },
+ "node_modules/core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+ "dev": true
+ },
+ "node_modules/corser": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz",
+ "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/cssom": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz",
+ "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==",
+ "dev": true
+ },
+ "node_modules/cssstyle": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz",
+ "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==",
+ "dev": true,
+ "dependencies": {
+ "cssom": "~0.3.6"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cssstyle/node_modules/cssom": {
+ "version": "0.3.8",
+ "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz",
+ "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==",
+ "dev": true
+ },
+ "node_modules/dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+ "dev": true,
+ "dependencies": {
+ "assert-plus": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/data-urls": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz",
+ "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==",
+ "dev": true,
+ "dependencies": {
+ "abab": "^2.0.3",
+ "whatwg-mimetype": "^2.3.0",
+ "whatwg-url": "^8.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/debug": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+ "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)",
+ "dev": true,
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/decimal.js": {
+ "version": "10.2.1",
+ "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz",
+ "integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==",
+ "dev": true
+ },
+ "node_modules/deep-is": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
+ "dev": true
+ },
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/depd": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/destroy": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=",
+ "dev": true
+ },
+ "node_modules/devtools-protocol": {
+ "version": "0.0.818844",
+ "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.818844.tgz",
+ "integrity": "sha512-AD1hi7iVJ8OD0aMLQU5VK0XH9LDlA1+BcPIgrAxPfaibx2DbWucuyOhc4oyQCbnvDDO68nN6/LcKfqTP343Jjg==",
+ "dev": true
+ },
+ "node_modules/domexception": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz",
+ "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==",
+ "dev": true,
+ "dependencies": {
+ "webidl-conversions": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/domexception/node_modules/webidl-conversions": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz",
+ "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ecc-jsbn": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+ "dev": true,
+ "dependencies": {
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
+ "node_modules/ecstatic": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz",
+ "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==",
+ "deprecated": "This package is unmaintained and deprecated. See the GH Issue 259.",
+ "dev": true,
+ "dependencies": {
+ "he": "^1.1.1",
+ "mime": "^1.6.0",
+ "minimist": "^1.1.0",
+ "url-join": "^2.0.5"
+ },
+ "bin": {
+ "ecstatic": "lib/ecstatic.js"
+ }
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
+ "dev": true
+ },
+ "node_modules/encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/end-of-stream": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.4.0"
+ }
+ },
+ "node_modules/entities": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz",
+ "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ=="
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
+ "dev": true
+ },
+ "node_modules/escodegen": {
+ "version": "1.14.3",
+ "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz",
+ "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==",
+ "dev": true,
+ "dependencies": {
+ "esprima": "^4.0.1",
+ "estraverse": "^4.2.0",
+ "esutils": "^2.0.2",
+ "optionator": "^0.8.1"
+ },
+ "bin": {
+ "escodegen": "bin/escodegen.js",
+ "esgenerate": "bin/esgenerate.js"
+ },
+ "engines": {
+ "node": ">=4.0"
+ },
+ "optionalDependencies": {
+ "source-map": "~0.6.1"
+ }
+ },
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true,
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/eventemitter3": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
+ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
+ "dev": true
+ },
+ "node_modules/express": {
+ "version": "4.17.1",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
+ "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
+ "dev": true,
+ "dependencies": {
+ "accepts": "~1.3.7",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.19.0",
+ "content-disposition": "0.5.3",
+ "content-type": "~1.0.4",
+ "cookie": "0.4.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "~1.1.2",
+ "fresh": "0.5.2",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.5",
+ "qs": "6.7.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.1.2",
+ "send": "0.17.1",
+ "serve-static": "1.14.1",
+ "setprototypeof": "1.1.1",
+ "statuses": "~1.5.0",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/express/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/express/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "node_modules/express/node_modules/qs": {
+ "version": "6.7.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+ "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "dev": true
+ },
+ "node_modules/extract-zip": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
+ "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^4.1.1",
+ "get-stream": "^5.1.0",
+ "yauzl": "^2.10.0"
+ },
+ "bin": {
+ "extract-zip": "cli.js"
+ },
+ "engines": {
+ "node": ">= 10.17.0"
+ },
+ "optionalDependencies": {
+ "@types/yauzl": "^2.9.1"
+ }
+ },
+ "node_modules/extract-zip/node_modules/debug": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+ "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/extsprintf": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
+ "dev": true,
+ "engines": [
+ "node >=0.6.0"
+ ]
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+ "dev": true
+ },
+ "node_modules/fd-slicer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+ "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
+ "dev": true,
+ "dependencies": {
+ "pend": "~1.2.0"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+ "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+ "dev": true,
+ "dependencies": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "statuses": "~1.5.0",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/finalhandler/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/finalhandler/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "node_modules/find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/follow-redirects": {
+ "version": "1.13.0",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz",
+ "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/form-data": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+ "dev": true,
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 0.12"
+ }
+ },
+ "node_modules/forwarded": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
+ "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fs-constants": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
+ "dev": true
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "dev": true
+ },
+ "node_modules/get-stream": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+ "dev": true,
+ "dependencies": {
+ "pump": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+ "dev": true,
+ "dependencies": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "node_modules/glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/har-schema": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/har-validator": {
+ "version": "5.1.5",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
+ "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
+ "deprecated": "this library is no longer supported",
+ "dev": true,
+ "dependencies": {
+ "ajv": "^6.12.3",
+ "har-schema": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+ "dev": true,
+ "bin": {
+ "he": "bin/he"
+ }
+ },
+ "node_modules/html-encoding-sniffer": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz",
+ "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==",
+ "dev": true,
+ "dependencies": {
+ "whatwg-encoding": "^1.0.5"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/http-errors": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
+ "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
+ "dev": true,
+ "dependencies": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.1.1",
+ "statuses": ">= 1.5.0 < 2",
+ "toidentifier": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/http-proxy": {
+ "version": "1.18.1",
+ "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
+ "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
+ "dev": true,
+ "dependencies": {
+ "eventemitter3": "^4.0.0",
+ "follow-redirects": "^1.0.0",
+ "requires-port": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/http-server": {
+ "version": "0.12.3",
+ "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.3.tgz",
+ "integrity": "sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA==",
+ "dev": true,
+ "dependencies": {
+ "basic-auth": "^1.0.3",
+ "colors": "^1.4.0",
+ "corser": "^2.0.1",
+ "ecstatic": "^3.3.2",
+ "http-proxy": "^1.18.0",
+ "minimist": "^1.2.5",
+ "opener": "^1.5.1",
+ "portfinder": "^1.0.25",
+ "secure-compare": "3.0.1",
+ "union": "~0.5.0"
+ },
+ "bin": {
+ "hs": "bin/http-server",
+ "http-server": "bin/http-server"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/http-signature": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+ "dev": true,
+ "dependencies": {
+ "assert-plus": "^1.0.0",
+ "jsprim": "^1.2.2",
+ "sshpk": "^1.7.0"
+ },
+ "engines": {
+ "node": ">=0.8",
+ "npm": ">=1.3.7"
+ }
+ },
+ "node_modules/https-proxy-agent": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz",
+ "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==",
+ "dev": true,
+ "dependencies": {
+ "agent-base": "5",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6.0.0"
+ }
+ },
+ "node_modules/https-proxy-agent/node_modules/debug": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+ "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dev": true,
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+ "dev": true
+ },
+ "node_modules/ip-regex": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
+ "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/is-potential-custom-element-name": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz",
+ "integrity": "sha1-DFLlS8yjkbssSUsh6GJtczbG45c=",
+ "dev": true
+ },
+ "node_modules/is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
+ "dev": true
+ },
+ "node_modules/isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
+ "dev": true
+ },
+ "node_modules/jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+ "dev": true
+ },
+ "node_modules/jsdom": {
+ "version": "16.4.0",
+ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.4.0.tgz",
+ "integrity": "sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w==",
+ "dev": true,
+ "dependencies": {
+ "abab": "^2.0.3",
+ "acorn": "^7.1.1",
+ "acorn-globals": "^6.0.0",
+ "cssom": "^0.4.4",
+ "cssstyle": "^2.2.0",
+ "data-urls": "^2.0.0",
+ "decimal.js": "^10.2.0",
+ "domexception": "^2.0.1",
+ "escodegen": "^1.14.1",
+ "html-encoding-sniffer": "^2.0.1",
+ "is-potential-custom-element-name": "^1.0.0",
+ "nwsapi": "^2.2.0",
+ "parse5": "5.1.1",
+ "request": "^2.88.2",
+ "request-promise-native": "^1.0.8",
+ "saxes": "^5.0.0",
+ "symbol-tree": "^3.2.4",
+ "tough-cookie": "^3.0.1",
+ "w3c-hr-time": "^1.0.2",
+ "w3c-xmlserializer": "^2.0.0",
+ "webidl-conversions": "^6.1.0",
+ "whatwg-encoding": "^1.0.5",
+ "whatwg-mimetype": "^2.3.0",
+ "whatwg-url": "^8.0.0",
+ "ws": "^7.2.3",
+ "xml-name-validator": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "canvas": "^2.5.0"
+ },
+ "peerDependenciesMeta": {
+ "canvas": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/json-schema": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
+ "dev": true
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "node_modules/json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
+ "dev": true
+ },
+ "node_modules/jsprim": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+ "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+ "dev": true,
+ "engines": [
+ "node >=0.6.0"
+ ],
+ "dependencies": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.2.3",
+ "verror": "1.10.0"
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.17.20",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
+ "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
+ "dev": true
+ },
+ "node_modules/lodash.sortby": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
+ "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
+ "dev": true
+ },
+ "node_modules/mdurl": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
+ "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4="
+ },
+ "node_modules/media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
+ "dev": true
+ },
+ "node_modules/methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "dev": true,
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.44.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
+ "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.27",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
+ "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
+ "dev": true,
+ "dependencies": {
+ "mime-db": "1.44.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
+ },
+ "node_modules/mkdirp": {
+ "version": "0.5.5",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
+ "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+ "dev": true,
+ "dependencies": {
+ "minimist": "^1.2.5"
+ },
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ }
+ },
+ "node_modules/mkdirp-classic": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
+ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
+ "dev": true
+ },
+ "node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "node_modules/negotiator": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
+ "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/node-fetch": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
+ "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==",
+ "dev": true,
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ }
+ },
+ "node_modules/nwsapi": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz",
+ "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==",
+ "dev": true
+ },
+ "node_modules/oauth-sign": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "dev": true,
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "dev": true,
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/opener": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
+ "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==",
+ "dev": true,
+ "bin": {
+ "opener": "bin/opener-bin.js"
+ }
+ },
+ "node_modules/optionator": {
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
+ "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+ "dev": true,
+ "dependencies": {
+ "deep-is": "~0.1.3",
+ "fast-levenshtein": "~2.0.6",
+ "levn": "~0.3.0",
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2",
+ "word-wrap": "~1.2.3"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parse5": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
+ "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==",
+ "dev": true
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=",
+ "dev": true
+ },
+ "node_modules/pend": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+ "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
+ "dev": true
+ },
+ "node_modules/performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
+ "dev": true
+ },
+ "node_modules/pkg-dir": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+ "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+ "dev": true,
+ "dependencies": {
+ "find-up": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/portfinder": {
+ "version": "1.0.28",
+ "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
+ "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==",
+ "dev": true,
+ "dependencies": {
+ "async": "^2.6.2",
+ "debug": "^3.1.1",
+ "mkdirp": "^0.5.5"
+ },
+ "engines": {
+ "node": ">= 0.12.0"
+ }
+ },
+ "node_modules/prelude-ls": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/proxy-addr": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
+ "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
+ "dev": true,
+ "dependencies": {
+ "forwarded": "~0.1.2",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+ "dev": true
+ },
+ "node_modules/psl": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
+ "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==",
+ "dev": true
+ },
+ "node_modules/pump": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+ "dev": true,
+ "dependencies": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/puppeteer": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-5.5.0.tgz",
+ "integrity": "sha512-OM8ZvTXAhfgFA7wBIIGlPQzvyEETzDjeRa4mZRCRHxYL+GNH5WAuYUQdja3rpWZvkX/JKqmuVgbsxDNsDFjMEg==",
+ "deprecated": "Version no longer supported. Upgrade to @latest",
+ "dev": true,
+ "hasInstallScript": true,
+ "dependencies": {
+ "debug": "^4.1.0",
+ "devtools-protocol": "0.0.818844",
+ "extract-zip": "^2.0.0",
+ "https-proxy-agent": "^4.0.0",
+ "node-fetch": "^2.6.1",
+ "pkg-dir": "^4.2.0",
+ "progress": "^2.0.1",
+ "proxy-from-env": "^1.0.0",
+ "rimraf": "^3.0.2",
+ "tar-fs": "^2.0.0",
+ "unbzip2-stream": "^1.3.3",
+ "ws": "^7.2.3"
+ },
+ "engines": {
+ "node": ">=10.18.1"
+ }
+ },
+ "node_modules/puppeteer/node_modules/debug": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+ "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.9.4",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz",
+ "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
+ "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
+ "dev": true,
+ "dependencies": {
+ "bytes": "3.1.0",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/request": {
+ "version": "2.88.2",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
+ "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
+ "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142",
+ "dev": true,
+ "dependencies": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.8.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.6",
+ "extend": "~3.0.2",
+ "forever-agent": "~0.6.1",
+ "form-data": "~2.3.2",
+ "har-validator": "~5.1.3",
+ "http-signature": "~1.2.0",
+ "is-typedarray": "~1.0.0",
+ "isstream": "~0.1.2",
+ "json-stringify-safe": "~5.0.1",
+ "mime-types": "~2.1.19",
+ "oauth-sign": "~0.9.0",
+ "performance-now": "^2.1.0",
+ "qs": "~6.5.2",
+ "safe-buffer": "^5.1.2",
+ "tough-cookie": "~2.5.0",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^3.3.2"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/request-promise-core": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz",
+ "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==",
+ "dev": true,
+ "dependencies": {
+ "lodash": "^4.17.19"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "peerDependencies": {
+ "request": "^2.34"
+ }
+ },
+ "node_modules/request-promise-native": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz",
+ "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==",
+ "deprecated": "request-promise-native has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142",
+ "dev": true,
+ "dependencies": {
+ "request-promise-core": "1.1.4",
+ "stealthy-require": "^1.1.1",
+ "tough-cookie": "^2.3.3"
+ },
+ "engines": {
+ "node": ">=0.12.0"
+ },
+ "peerDependencies": {
+ "request": "^2.34"
+ }
+ },
+ "node_modules/request-promise-native/node_modules/tough-cookie": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+ "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+ "dev": true,
+ "dependencies": {
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/request/node_modules/qs": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/request/node_modules/tough-cookie": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+ "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+ "dev": true,
+ "dependencies": {
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
+ "dev": true
+ },
+ "node_modules/rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "dev": true
+ },
+ "node_modules/saxes": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz",
+ "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==",
+ "dev": true,
+ "dependencies": {
+ "xmlchars": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/secure-compare": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz",
+ "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=",
+ "dev": true
+ },
+ "node_modules/send": {
+ "version": "0.17.1",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
+ "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
+ "dev": true,
+ "dependencies": {
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "destroy": "~1.0.4",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "~1.7.2",
+ "mime": "1.6.0",
+ "ms": "2.1.1",
+ "on-finished": "~2.3.0",
+ "range-parser": "~1.2.1",
+ "statuses": "~1.5.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/send/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/send/node_modules/debug/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "node_modules/send/node_modules/ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
+ "dev": true
+ },
+ "node_modules/serve-static": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
+ "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
+ "dev": true,
+ "dependencies": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.17.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
+ "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==",
+ "dev": true
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/sshpk": {
+ "version": "1.16.1",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
+ "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
+ "dev": true,
+ "dependencies": {
+ "asn1": "~0.2.3",
+ "assert-plus": "^1.0.0",
+ "bcrypt-pbkdf": "^1.0.0",
+ "dashdash": "^1.12.0",
+ "ecc-jsbn": "~0.1.1",
+ "getpass": "^0.1.1",
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.0.2",
+ "tweetnacl": "~0.14.0"
+ },
+ "bin": {
+ "sshpk-conv": "bin/sshpk-conv",
+ "sshpk-sign": "bin/sshpk-sign",
+ "sshpk-verify": "bin/sshpk-verify"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/statuses": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/stealthy-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
+ "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "node_modules/string_decoder/node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/string.prototype.repeat": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-0.2.0.tgz",
+ "integrity": "sha1-q6Nt4I3O5qWjN9SbLqHaGyj8Ds8="
+ },
+ "node_modules/symbol-tree": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
+ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
+ "dev": true
+ },
+ "node_modules/tar-fs": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
+ "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
+ "dev": true,
+ "dependencies": {
+ "chownr": "^1.1.1",
+ "mkdirp-classic": "^0.5.2",
+ "pump": "^3.0.0",
+ "tar-stream": "^2.1.4"
+ }
+ },
+ "node_modules/tar-stream": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.4.tgz",
+ "integrity": "sha512-o3pS2zlG4gxr67GmFYBLlq+dM8gyRGUOvsrHclSkvtVtQbjV0s/+ZE8OpICbaj8clrX3tjeHngYGP7rweaBnuw==",
+ "dev": true,
+ "dependencies": {
+ "bl": "^4.0.3",
+ "end-of-stream": "^1.4.1",
+ "fs-constants": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+ "dev": true
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
+ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/tough-cookie": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz",
+ "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==",
+ "dev": true,
+ "dependencies": {
+ "ip-regex": "^2.1.0",
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tr46": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz",
+ "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==",
+ "dev": true,
+ "dependencies": {
+ "punycode": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+ "dev": true
+ },
+ "node_modules/type-check": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "dev": true,
+ "dependencies": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/unbzip2-stream": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz",
+ "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==",
+ "dev": true,
+ "dependencies": {
+ "buffer": "^5.2.1",
+ "through": "^2.3.8"
+ }
+ },
+ "node_modules/union": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz",
+ "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==",
+ "dev": true,
+ "dependencies": {
+ "qs": "^6.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz",
+ "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==",
+ "dev": true,
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/url-join": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz",
+ "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=",
+ "dev": true
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+ "dev": true
+ },
+ "node_modules/utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/uuid": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
+ "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
+ "dev": true,
+ "bin": {
+ "uuid": "bin/uuid"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/verror": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+ "dev": true,
+ "engines": [
+ "node >=0.6.0"
+ ],
+ "dependencies": {
+ "assert-plus": "^1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "^1.2.0"
+ }
+ },
+ "node_modules/w3c-hr-time": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
+ "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==",
+ "dev": true,
+ "dependencies": {
+ "browser-process-hrtime": "^1.0.0"
+ }
+ },
+ "node_modules/w3c-xmlserializer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz",
+ "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==",
+ "dev": true,
+ "dependencies": {
+ "xml-name-validator": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/webidl-conversions": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz",
+ "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==",
+ "dev": true,
+ "engines": {
+ "node": ">=10.4"
+ }
+ },
+ "node_modules/whatwg-encoding": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz",
+ "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==",
+ "dev": true,
+ "dependencies": {
+ "iconv-lite": "0.4.24"
+ }
+ },
+ "node_modules/whatwg-mimetype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz",
+ "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==",
+ "dev": true
+ },
+ "node_modules/whatwg-url": {
+ "version": "8.4.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.4.0.tgz",
+ "integrity": "sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw==",
+ "dev": true,
+ "dependencies": {
+ "lodash.sortby": "^4.7.0",
+ "tr46": "^2.0.2",
+ "webidl-conversions": "^6.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "dev": true
+ },
+ "node_modules/ws": {
+ "version": "7.4.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.0.tgz",
+ "integrity": "sha512-kyFwXuV/5ymf+IXhS6f0+eAFvydbaBW3zjpT6hUdAh/hbVjTIB5EHBGi0bPoCLSK2wcuz3BrEkB9LrYv1Nm4NQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.3.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": "^5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/xml-name-validator": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
+ "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==",
+ "dev": true
+ },
+ "node_modules/xmlchars": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
+ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
+ "dev": true
+ },
+ "node_modules/yauzl": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
+ "dev": true,
+ "dependencies": {
+ "buffer-crc32": "~0.2.3",
+ "fd-slicer": "~1.1.0"
+ }
+ }
+ },
"dependencies": {
"@types/node": {
"version": "14.14.10",
@@ -1609,11 +4031,6 @@
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=",
"dev": true
},
- "string.prototype.repeat": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-0.2.0.tgz",
- "integrity": "sha1-q6Nt4I3O5qWjN9SbLqHaGyj8Ds8="
- },
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@@ -1631,6 +4048,11 @@
}
}
},
+ "string.prototype.repeat": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-0.2.0.tgz",
+ "integrity": "sha1-q6Nt4I3O5qWjN9SbLqHaGyj8Ds8="
+ },
"symbol-tree": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
@@ -1869,7 +4291,8 @@
"version": "7.4.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.0.tgz",
"integrity": "sha512-kyFwXuV/5ymf+IXhS6f0+eAFvydbaBW3zjpT6hUdAh/hbVjTIB5EHBGi0bPoCLSK2wcuz3BrEkB9LrYv1Nm4NQ==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"xml-name-validator": {
"version": "3.0.0",
diff --git a/package.json b/package.json
index a6b48f6..512d65e 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,6 @@
"version": "1.0.0",
"description": "Apollo Specifications Library",
"main": "index.js",
- "type": "module",
"bin": "./bin/library",
"scripts": {
"start": "http-server -c-1"
From 5824fd05c472b6d9a6875a75e2a9ec12b51bbb4e Mon Sep 17 00:00:00 2001
From: Ashi Krishnan
Date: Wed, 20 Apr 2022 16:53:09 -0400
Subject: [PATCH 02/13] correct id for inaccessible v0.1
---
.../{v1.0.graphql => v0.1.graphql} | 4 +-
.../inaccessible/{v1.0.html => v0.1.html} | 6 +-
inaccessible/inaccessible.spec.graphql | 2 +-
inaccessible/spec.md | 117 ------------------
4 files changed, 6 insertions(+), 123 deletions(-)
rename .graphs/https/specs.apollo.dev/inaccessible/{v1.0.graphql => v0.1.graphql} (97%)
rename .graphs/https/specs.apollo.dev/inaccessible/{v1.0.html => v0.1.html} (99%)
diff --git a/.graphs/https/specs.apollo.dev/inaccessible/v1.0.graphql b/.graphs/https/specs.apollo.dev/inaccessible/v0.1.graphql
similarity index 97%
rename from .graphs/https/specs.apollo.dev/inaccessible/v1.0.graphql
rename to .graphs/https/specs.apollo.dev/inaccessible/v0.1.graphql
index 74310b2..9c3021a 100644
--- a/.graphs/https/specs.apollo.dev/inaccessible/v1.0.graphql
+++ b/.graphs/https/specs.apollo.dev/inaccessible/v0.1.graphql
@@ -1,6 +1,6 @@
-extend schema @id(url: "https://specs.apollo.dev/inaccessible/v1.0")
+extend schema @id(url: "https://specs.apollo.dev/inaccessible/v0.1")
-extend schema @id(url: "https://specs.apollo.dev/inaccessible/v1.0")
+extend schema @id(url: "https://specs.apollo.dev/inaccessible/v0.1")
"""
The {@inaccessible} directive removes definitions from a schema's API.
diff --git a/.graphs/https/specs.apollo.dev/inaccessible/v1.0.html b/.graphs/https/specs.apollo.dev/inaccessible/v0.1.html
similarity index 99%
rename from .graphs/https/specs.apollo.dev/inaccessible/v1.0.html
rename to .graphs/https/specs.apollo.dev/inaccessible/v0.1.html
index 7046f85..d99adfc 100644
--- a/.graphs/https/specs.apollo.dev/inaccessible/v1.0.html
+++ b/.graphs/https/specs.apollo.dev/inaccessible/v0.1.html
@@ -2,7 +2,7 @@
-inaccessible v1.0
+inaccessible v0.1
+
+
+
+
+
+
+
+
+
```raw html
@@ -61,4 +59,139 @@ schema {
query: Query
}
-directive @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION
\ No newline at end of file
+directive @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION
+
+"""Link a foreign schema by its URL."""
+directive @link(
+ """
+ The foreign schema's URL.
+
+ Link URLs serve two main purposes:
+ - Providing a unique identifier for the foreign schema
+ - Directing human readers to documentation about the foreign schema
+
+ Link URLs SHOULD be [RFC 3986 URLs](https://tools.ietf.org/html/rfc3986). When viewed, the URL SHOULD provide schema documentation in some human-readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
+
+ Link URLs MAY contain information about the spec's [name](#sec-Prefixing) and [version](#sec-Versioning):
+
+ ```html diagram -- Basic anatomy of a link URL
+
+ https://spec.example.com/a/b/c/mySchema/v1.0
+
+ ```
+
+ The final two segments of the URL's [path](https://tools.ietf.org/html/rfc3986#section-3.3) MAY contain the schema's name and a [version tag](#sec-Versioning), in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid {VersionTag}. To be recognized as a name, the penultimate path component MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name) which does not include the namespace separator ({"__"}).
+
+ Empty final path components (that is, trailing slashes) and any URL components which have not been assigned a meaning (such as the fragment and query) MUST be ignored.
+
+ ```html diagram -- Ignoring meaningless parts of a URL
+
+ https://example.com/exampleSchema/v1.0/?key=val&k2=v2#frag
+
+ ```
+
+ All of these are valid arguments to `url`, and their interpretations:
+
+ | url | normalized url | name | version |
+ | ------------------------------------------------- | ------------------------------------------ | ------- | -------- |
+ | https://spec.example.com/a/b/mySchema/v1.0/ | https://spec.example.com/a/b/mySchema/v1.0 | mySchema | v1.0 |
+ | https://spec.example.com | https://spec.example.com | *(null)* | *(null)* |
+ | https://spec.example.com/mySchema/v0.1?q=v#frag | https://spec.example.com/mySchema/v0.1 | mySchema | v0.1 |
+ | https://spec.example.com/v1.0 | https://spec.example.com/v1.0 | *(null)* | v1.0 |
+ | https://spec.example.com/vX | https://spec.example.com/vX | vX | *(null)* |
+
+ If `name` is present, that [namespace prefix](#sec-Prefixing) will automatically be linked to the URL. If a `name` is not present, then elements of the foreign schema must be [`imported`](#@link/import) in order to be referenced.
+ """
+ url: String!
+ """
+ Change the [namespace prefix](#sec-Prefixing) assigned to this schema.
+
+ The name must be a valid GraphQL identifier, and must not contain the namespace separator ({"__"}).
+
+ By default, {@link} will assign a prefix based on the `name` extracted from the URL. If no `name` is present, a prefix will not be assigned.
+
+ Providing [`as:`](#@link/as) overrides the default behavior: the foreign schema will be assigned the provided prefix, regardless of the `name` present in the URL (or the lack of one).
+
+ ```graphql example -- Using {@link}(url:, as:) to use a feature with a custom name
+ schema
+ @link(url: "https://specs.apollo.dev/link/v1.0")
+ @link(url: "https://spec.example.com/example/v1.0", as: "eg")
+ {
+ query: Query
+ }
+
+ type User {
+ # Specifying `as: "eg"` transforms @example into @eg
+ name: String @eg(data: ITEM)
+ }
+
+ # Additional specified schema elements must have their prefixes set
+ # to the new name.
+ enum eg__Data {
+ ITEM
+ }
+
+ # Name transformation must also be applied to definitions pulled in from
+ # specifications.
+ directive @eg(data: eg__Data) on FIELD_DEFINITION
+
+ directive @link(url: String!, as: String) repeatable on SCHEMA
+ ```
+ """
+ as: String
+ """Import definitions into the local namespace."""
+ import: [Import]
+ """
+ An optional [purpose](#Purpose) for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
+
+ By default, {@link}s SHOULD fail open. This means that {@link}s to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
+
+ This behavior is different for {@link}s with a specified purpose:
+ - `SECURITY` links convey metadata necessary to compute the API schema and securely resolve fields within it
+ - `EXECUTION` links convey metadata necessary to correctly resolve fields within the schema
+ """
+ for: Purpose
+) repeatable on SCHEMA
+
+"""TK describe an import"""
+scalar Import
+
+"""
+The role of a feature referenced with {@link}.
+
+This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail-open behavior of core schema consumers is undesirable.
+
+Note we'll refer to directives from features which are `for: SECURITY` or `for: EXECUTION` as "`SECURITY` directives" and "`EXECUTION` directives", respectively.
+"""
+enum Purpose {
+ """
+ `SECURITY` links provide metadata necessary to securely resolve fields. For instance, a hypothetical {auth} feature may provide an {@auth} directive to flag fields which require authorization. If a data core does not support the {auth} feature and serves those fields anyway, these fields will be accessible without authorization, compromising security.
+
+ Security-conscious consumers MUST NOT serve a field if:
+ - the schema definition has **any** unsupported SECURITY directives,
+ - the field's parent type definition has **any** unsupported SECURITY directives,
+ - the field's return type definition has **any** unsupported SECURITY directives, or
+ - the field definition has **any** unsupported SECURITY directives
+
+ Such fields are *not securely resolvable*. Security-conscious consumers MAY serve schemas with fields which are not securely resolvable. However, they MUST remove such fields from the schema before serving it.
+
+ Less security-conscious consumers MAY choose to relax these requirements. For instance, servers may provide a development mode in which unknown SECURITY directives are ignored, perhaps with a warning. Such software may also provide a way to explicitly disable some or all SECURITY links during development.
+
+ More security-conscious consumers MAY choose to enhance these requirements. For instance, production servers MAY adopt a policy of entirely rejecting any schema which contains ANY unsupported SECURITY links, even if those links are never used to annotate the schema.
+ """
+ SECURITY
+ """
+ `EXECUTION` features provide metadata necessary to correctly resolve fields. For instance, a hypothetical {ts} feature may provide a `@ts__resolvers` annotation which references a TypeScript module of field resolvers. A consumer which does not support the {ts} feature will be unable to correctly resolve such fields.
+
+ Consumers MUST NOT serve a field if:
+ - the schema's definition has **any** unsupported EXECUTION directives,
+ - the field's parent type definition has **any** unsupported EXECUTION directives,
+ - the field's return type definition has **any** unsupported EXECUTION directives, or
+ - the field definition has **any** unsupported EXECUTION directives
+
+ Such fields are *unresolvable*. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION features, even if those features are never used in the schema.
+ """
+ EXECUTION
+}
+
+directive @id__(url: String!) on SCHEMA
\ No newline at end of file
diff --git a/.graphs/https/specs.apollo.dev/inaccessible/v0.1.html b/.graphs/https/specs.apollo.dev/inaccessible/v0.1.html
index 557c6a7..4d5ecc6 100644
--- a/.graphs/https/specs.apollo.dev/inaccessible/v0.1.html
+++ b/.graphs/https/specs.apollo.dev/inaccessible/v0.1.html
@@ -1533,46 +1533,44 @@
inaccessible v0.1
+
+
for removing elements from a core schema
+
+
Status
Release
+
Version
0.1
+
+
+
+
This document defines the @inaccessible directive, which marks schema elements which should not be accessible in the public‐facing schema. This version of the spec supports Object, Interface, and Union types.
This document defines the @inaccessible directive, which marks schema elements which should not be accessible in the public‐facing schema. This version of the spec supports Object, Interface, and Union types.
This specification makes references to Processors. Processors are described in the Actors section of the @core spec as an actor which can perform transformations on a core schema. In the case of @inaccessible, the Processor will be expected to remove various parts of a core schema.
@@ -69,7 +69,7 @@ A feature's *root directive* is an exception to the prefixing requirements. Feat
```graphql example -- Using the @link directive without changing the prefix
schema
- @link(url: "https://specs.apollo.dev/link/v1.0", import: ["@link"])
+ @link(url: "https://specs.apollo.dev/link/v1.0")
@link(url: "https://spec.example.com/example/v1.0") {
query: Query
}
@@ -95,7 +95,7 @@ The prefix MUST NOT be elided within documentation; definitions of schema elemen
Feature specs MUST prefix the following schema elements:
- the names of any object types, interfaces, unions, enums, or input object types defined by the feature
- - the names of any directives introduced in the spec, with the exception of the *root directive*, which must have the same name as the feature
+ - the names of any directives introduced in the schema, with the exception of the *root directive*, which must have the same name as the schema
:::[example](prefixing.graphql) -- Prefixing
@@ -134,7 +134,7 @@ As specified by semver, spec authors SHOULD increment the:
++}
-Patch and pre-release qualifiers are judged to be not particularly meaningful in the context of core features, which are (by definition) interfaces rather than implementations. The patch component of a semver denotes a bug fix which is backwards compatible—that is, a change to the implementation which does not affect the interface. Patch-level changes in the version of a spec denote wording clarifications which do not require implementation changes. As such, it is not important to track them for the purposes of version resolution.
+Patch and pre-release qualifiers are judged to be not particularly meaningful in the context of GraphQL schemas, which are (by definition) interfaces rather than implementations. The patch component of a semver denotes a bug fix which is backwards compatible—that is, a change to the implementation which does not affect the interface. Patch-level changes in the version of a spec denote wording clarifications which do not require implementation changes. As such, it is not important to track them for the purposes of version resolution.
As with [semver](https://semver.org/spec/v2.0.0.html), the `0.x` version series is special: there is no expectation of compatibility between versions `0.x` and `0.y`. For example, a processor must not activate implementation `0.4` to satisfy a requested version of `0.2`.
@@ -445,4 +445,139 @@ enum Purpose {
Such fields are *unresolvable*. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION features, even if those features are never used in the schema.
"""
EXECUTION
-}
\ No newline at end of file
+}
+
+"""Link a foreign schema by its URL."""
+directive @link(
+ """
+ The foreign schema's URL.
+
+ Link URLs serve two main purposes:
+ - Providing a unique identifier for the foreign schema
+ - Directing human readers to documentation about the foreign schema
+
+ Link URLs SHOULD be [RFC 3986 URLs](https://tools.ietf.org/html/rfc3986). When viewed, the URL SHOULD provide schema documentation in some human-readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
+
+ Link URLs MAY contain information about the spec's [name](#sec-Prefixing) and [version](#sec-Versioning):
+
+ ```html diagram -- Basic anatomy of a link URL
+
+ https://spec.example.com/a/b/c/mySchema/v1.0
+
+ ```
+
+ The final two segments of the URL's [path](https://tools.ietf.org/html/rfc3986#section-3.3) MAY contain the schema's name and a [version tag](#sec-Versioning), in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid {VersionTag}. To be recognized as a name, the penultimate path component MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name) which does not include the namespace separator ({"__"}).
+
+ Empty final path components (that is, trailing slashes) and any URL components which have not been assigned a meaning (such as the fragment and query) MUST be ignored.
+
+ ```html diagram -- Ignoring meaningless parts of a URL
+
+ https://example.com/exampleSchema/v1.0/?key=val&k2=v2#frag
+
+ ```
+
+ All of these are valid arguments to `url`, and their interpretations:
+
+ | url | normalized url | name | version |
+ | ------------------------------------------------- | ------------------------------------------ | ------- | -------- |
+ | https://spec.example.com/a/b/mySchema/v1.0/ | https://spec.example.com/a/b/mySchema/v1.0 | mySchema | v1.0 |
+ | https://spec.example.com | https://spec.example.com | *(null)* | *(null)* |
+ | https://spec.example.com/mySchema/v0.1?q=v#frag | https://spec.example.com/mySchema/v0.1 | mySchema | v0.1 |
+ | https://spec.example.com/v1.0 | https://spec.example.com/v1.0 | *(null)* | v1.0 |
+ | https://spec.example.com/vX | https://spec.example.com/vX | vX | *(null)* |
+
+ If `name` is present, that [namespace prefix](#sec-Prefixing) will automatically be linked to the URL. If a `name` is not present, then elements of the foreign schema must be [`imported`](#@link/import) in order to be referenced.
+ """
+ url: String!
+ """
+ Change the [namespace prefix](#sec-Prefixing) assigned to this schema.
+
+ The name must be a valid GraphQL identifier, and must not contain the namespace separator ({"__"}).
+
+ By default, {@link} will assign a prefix based on the `name` extracted from the URL. If no `name` is present, a prefix will not be assigned.
+
+ Providing [`as:`](#@link/as) overrides the default behavior: the foreign schema will be assigned the provided prefix, regardless of the `name` present in the URL (or the lack of one).
+
+ ```graphql example -- Using {@link}(url:, as:) to use a feature with a custom name
+ schema
+ @link(url: "https://specs.apollo.dev/link/v1.0")
+ @link(url: "https://spec.example.com/example/v1.0", as: "eg")
+ {
+ query: Query
+ }
+
+ type User {
+ # Specifying `as: "eg"` transforms @example into @eg
+ name: String @eg(data: ITEM)
+ }
+
+ # Additional specified schema elements must have their prefixes set
+ # to the new name.
+ enum eg__Data {
+ ITEM
+ }
+
+ # Name transformation must also be applied to definitions pulled in from
+ # specifications.
+ directive @eg(data: eg__Data) on FIELD_DEFINITION
+
+ directive @link(url: String!, as: String) repeatable on SCHEMA
+ ```
+ """
+ as: String
+ """Import definitions into the local namespace."""
+ import: [Import]
+ """
+ An optional [purpose](#Purpose) for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
+
+ By default, {@link}s SHOULD fail open. This means that {@link}s to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
+
+ This behavior is different for {@link}s with a specified purpose:
+ - `SECURITY` links convey metadata necessary to compute the API schema and securely resolve fields within it
+ - `EXECUTION` links convey metadata necessary to correctly resolve fields within the schema
+ """
+ for: Purpose
+) repeatable on SCHEMA
+
+"""TK describe an import"""
+scalar Import
+
+"""
+The role of a feature referenced with {@link}.
+
+This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail-open behavior of core schema consumers is undesirable.
+
+Note we'll refer to directives from features which are `for: SECURITY` or `for: EXECUTION` as "`SECURITY` directives" and "`EXECUTION` directives", respectively.
+"""
+enum Purpose {
+ """
+ `SECURITY` links provide metadata necessary to securely resolve fields. For instance, a hypothetical {auth} feature may provide an {@auth} directive to flag fields which require authorization. If a data core does not support the {auth} feature and serves those fields anyway, these fields will be accessible without authorization, compromising security.
+
+ Security-conscious consumers MUST NOT serve a field if:
+ - the schema definition has **any** unsupported SECURITY directives,
+ - the field's parent type definition has **any** unsupported SECURITY directives,
+ - the field's return type definition has **any** unsupported SECURITY directives, or
+ - the field definition has **any** unsupported SECURITY directives
+
+ Such fields are *not securely resolvable*. Security-conscious consumers MAY serve schemas with fields which are not securely resolvable. However, they MUST remove such fields from the schema before serving it.
+
+ Less security-conscious consumers MAY choose to relax these requirements. For instance, servers may provide a development mode in which unknown SECURITY directives are ignored, perhaps with a warning. Such software may also provide a way to explicitly disable some or all SECURITY links during development.
+
+ More security-conscious consumers MAY choose to enhance these requirements. For instance, production servers MAY adopt a policy of entirely rejecting any schema which contains ANY unsupported SECURITY links, even if those links are never used to annotate the schema.
+ """
+ SECURITY
+ """
+ `EXECUTION` features provide metadata necessary to correctly resolve fields. For instance, a hypothetical {ts} feature may provide a `@ts__resolvers` annotation which references a TypeScript module of field resolvers. A consumer which does not support the {ts} feature will be unable to correctly resolve such fields.
+
+ Consumers MUST NOT serve a field if:
+ - the schema's definition has **any** unsupported EXECUTION directives,
+ - the field's parent type definition has **any** unsupported EXECUTION directives,
+ - the field's return type definition has **any** unsupported EXECUTION directives, or
+ - the field definition has **any** unsupported EXECUTION directives
+
+ Such fields are *unresolvable*. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION features, even if those features are never used in the schema.
+ """
+ EXECUTION
+}
+
+directive @id__(url: String!) on SCHEMA
\ No newline at end of file
diff --git a/.graphs/https/specs.apollo.dev/link/v1.0.html b/.graphs/https/specs.apollo.dev/link/v1.0.html
index e1373f6..a958a05 100644
--- a/.graphs/https/specs.apollo.dev/link/v1.0.html
+++ b/.graphs/https/specs.apollo.dev/link/v1.0.html
@@ -1536,7 +1536,7 @@
MAY introduce a single directive which carries only the name of the feature, with no prefix required. For example, the core specification introduces a @link directive. This directive has the same name as the feature (”core”), and so requires no prefix.
semver, the 0.x version series is special: there is no expectation of compatibility between versions 0.x and 0.y. For example, a processor must not activate implementation 0.4 to satisfy a requested version of 0.2.
Providing a unique identifier for the foreign schema
-
Directing human readers to documentation about the foreign schema
-
-
Link URLs SHOULD be RFC 3986 URLs. When viewed, the URL SHOULD provide schema documentation in some human‐readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
-
Link URLs MAY contain information about the spec’s name and version:
-
The final two segments of the URL’s pathMAY contain the schema’s name and a version tag, in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid VersionTag. To be recognized as a name, the penultimate path component MUST be a valid GraphQL name which does not include the namespace separator ("__").
-
Empty final path components (that is, trailing slashes) and any URL components which have not been assigned a meaning (such as the fragment and query) MUST be ignored.
-
All of these are valid arguments to url, and their interpretations:
-
-
-
url
-
normalized url
-
name
-
version
-
-
-
-
https://spec.example.com/a/b/mySchema/v1.0/
https://spec.example.com/a/b/mySchema/v1.0
mySchema
v1.0
-
-
https://spec.example.com
https://spec.example.com
(null)
(null)
-
-
https://spec.example.com/mySchema/v0.1?q=v#frag
https://spec.example.com/mySchema/v0.1
mySchema
v0.1
-
-
https://spec.example.com/v1.0
https://spec.example.com/v1.0
(null)
v1.0
-
-
https://spec.example.com/vX
https://spec.example.com/vX
vX
(null)
-
-
-
If name is present, that namespace prefix will automatically be linked to the URL. If a name is not present, then elements of the foreign schema must be imported in order to be referenced.
The name must be a valid GraphQL identifier, and must not contain the namespace separator ("__").
-
By default, @link will assign a prefix based on the name extracted from the URL. If no name is present, a prefix will not be assigned.
-
Providing as: overrides the default behavior: the foreign schema will be assigned the provided prefix, regardless of the name present in the URL (or the lack of one).
An optional purpose for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
-
By default, @links SHOULD fail open. This means that @links to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
-
This behavior is different for @links with a specified purpose:
-
-
SECURITY links convey metadata necessary to compute the API schema and securely resolve fields within it
-
EXECUTION links convey metadata necessary to correctly resolve fields within the schema
Note
we’ll refer to directives from features which are for: SECURITY or for: EXECUTION as “SECURITY directives” and “EXECUTION directives”, respectively.
This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail‐open behavior of core schema consumers is undesirable.
+
+Note
+we’ll refer to directives from features which are for: SECURITY or for: EXECUTION as “SECURITY directives” and “EXECUTION directives”, respectively.
diff --git a/.graphs/https/specs.apollo.dev/tag/v0.1.graphql b/.graphs/https/specs.apollo.dev/tag/v0.1.graphql
new file mode 100644
index 0000000..bd03b6c
--- /dev/null
+++ b/.graphs/https/specs.apollo.dev/tag/v0.1.graphql
@@ -0,0 +1,147 @@
+extend schema @link(url: "https://specs.apollo.dev/id/v1.0") @id__(url: "https://specs.apollo.dev/tag/v0.1")
+
+extend schema @id__(url: "https://specs.apollo.dev/tag/v0.1")
+
+"""
+Apply an arbitrary piece of string metadata to the target.
+
+The following example demonstrates how team ownership over types and fields can be declaratively expressed via inline metadata. One might imagine a CI workflow which analyzes a schema diff and uses `@tag` names to authorize or require approval for changes to parts of the graph.
+
+:::[example](ownership-example.graphql)
+"""
+directive @tag(name: String!) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION
+
+"""Link a foreign schema by its URL."""
+directive @link(
+ """
+ The foreign schema's URL.
+
+ Link URLs serve two main purposes:
+ - Providing a unique identifier for the foreign schema
+ - Directing human readers to documentation about the foreign schema
+
+ Link URLs SHOULD be [RFC 3986 URLs](https://tools.ietf.org/html/rfc3986). When viewed, the URL SHOULD provide schema documentation in some human-readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
+
+ Link URLs MAY contain information about the spec's [name](#sec-Prefixing) and [version](#sec-Versioning):
+
+ ```html diagram -- Basic anatomy of a link URL
+
+ https://spec.example.com/a/b/c/mySchema/v1.0
+
+ ```
+
+ The final two segments of the URL's [path](https://tools.ietf.org/html/rfc3986#section-3.3) MAY contain the schema's name and a [version tag](#sec-Versioning), in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid {VersionTag}. To be recognized as a name, the penultimate path component MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name) which does not include the namespace separator ({"__"}).
+
+ Empty final path components (that is, trailing slashes) and any URL components which have not been assigned a meaning (such as the fragment and query) MUST be ignored.
+
+ ```html diagram -- Ignoring meaningless parts of a URL
+
+ https://example.com/exampleSchema/v1.0/?key=val&k2=v2#frag
+
+ ```
+
+ All of these are valid arguments to `url`, and their interpretations:
+
+ | url | normalized url | name | version |
+ | ------------------------------------------------- | ------------------------------------------ | ------- | -------- |
+ | https://spec.example.com/a/b/mySchema/v1.0/ | https://spec.example.com/a/b/mySchema/v1.0 | mySchema | v1.0 |
+ | https://spec.example.com | https://spec.example.com | *(null)* | *(null)* |
+ | https://spec.example.com/mySchema/v0.1?q=v#frag | https://spec.example.com/mySchema/v0.1 | mySchema | v0.1 |
+ | https://spec.example.com/v1.0 | https://spec.example.com/v1.0 | *(null)* | v1.0 |
+ | https://spec.example.com/vX | https://spec.example.com/vX | vX | *(null)* |
+
+ If `name` is present, that [namespace prefix](#sec-Prefixing) will automatically be linked to the URL. If a `name` is not present, then elements of the foreign schema must be [`imported`](#@link/import) in order to be referenced.
+ """
+ url: String!
+ """
+ Change the [namespace prefix](#sec-Prefixing) assigned to this schema.
+
+ The name must be a valid GraphQL identifier, and must not contain the namespace separator ({"__"}).
+
+ By default, {@link} will assign a prefix based on the `name` extracted from the URL. If no `name` is present, a prefix will not be assigned.
+
+ Providing [`as:`](#@link/as) overrides the default behavior: the foreign schema will be assigned the provided prefix, regardless of the `name` present in the URL (or the lack of one).
+
+ ```graphql example -- Using {@link}(url:, as:) to use a feature with a custom name
+ schema
+ @link(url: "https://specs.apollo.dev/link/v1.0")
+ @link(url: "https://spec.example.com/example/v1.0", as: "eg")
+ {
+ query: Query
+ }
+
+ type User {
+ # Specifying `as: "eg"` transforms @example into @eg
+ name: String @eg(data: ITEM)
+ }
+
+ # Additional specified schema elements must have their prefixes set
+ # to the new name.
+ enum eg__Data {
+ ITEM
+ }
+
+ # Name transformation must also be applied to definitions pulled in from
+ # specifications.
+ directive @eg(data: eg__Data) on FIELD_DEFINITION
+
+ directive @link(url: String!, as: String) repeatable on SCHEMA
+ ```
+ """
+ as: String
+ """Import definitions into the local namespace."""
+ import: [Import]
+ """
+ An optional [purpose](#Purpose) for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
+
+ By default, {@link}s SHOULD fail open. This means that {@link}s to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
+
+ This behavior is different for {@link}s with a specified purpose:
+ - `SECURITY` links convey metadata necessary to compute the API schema and securely resolve fields within it
+ - `EXECUTION` links convey metadata necessary to correctly resolve fields within the schema
+ """
+ for: Purpose
+) repeatable on SCHEMA
+
+"""TK describe an import"""
+scalar Import
+
+"""
+The role of a feature referenced with {@link}.
+
+This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail-open behavior of core schema consumers is undesirable.
+
+Note we'll refer to directives from features which are `for: SECURITY` or `for: EXECUTION` as "`SECURITY` directives" and "`EXECUTION` directives", respectively.
+"""
+enum Purpose {
+ """
+ `SECURITY` links provide metadata necessary to securely resolve fields. For instance, a hypothetical {auth} feature may provide an {@auth} directive to flag fields which require authorization. If a data core does not support the {auth} feature and serves those fields anyway, these fields will be accessible without authorization, compromising security.
+
+ Security-conscious consumers MUST NOT serve a field if:
+ - the schema definition has **any** unsupported SECURITY directives,
+ - the field's parent type definition has **any** unsupported SECURITY directives,
+ - the field's return type definition has **any** unsupported SECURITY directives, or
+ - the field definition has **any** unsupported SECURITY directives
+
+ Such fields are *not securely resolvable*. Security-conscious consumers MAY serve schemas with fields which are not securely resolvable. However, they MUST remove such fields from the schema before serving it.
+
+ Less security-conscious consumers MAY choose to relax these requirements. For instance, servers may provide a development mode in which unknown SECURITY directives are ignored, perhaps with a warning. Such software may also provide a way to explicitly disable some or all SECURITY links during development.
+
+ More security-conscious consumers MAY choose to enhance these requirements. For instance, production servers MAY adopt a policy of entirely rejecting any schema which contains ANY unsupported SECURITY links, even if those links are never used to annotate the schema.
+ """
+ SECURITY
+ """
+ `EXECUTION` features provide metadata necessary to correctly resolve fields. For instance, a hypothetical {ts} feature may provide a `@ts__resolvers` annotation which references a TypeScript module of field resolvers. A consumer which does not support the {ts} feature will be unable to correctly resolve such fields.
+
+ Consumers MUST NOT serve a field if:
+ - the schema's definition has **any** unsupported EXECUTION directives,
+ - the field's parent type definition has **any** unsupported EXECUTION directives,
+ - the field's return type definition has **any** unsupported EXECUTION directives, or
+ - the field definition has **any** unsupported EXECUTION directives
+
+ Such fields are *unresolvable*. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION features, even if those features are never used in the schema.
+ """
+ EXECUTION
+}
+
+directive @id__(url: String!) on SCHEMA
\ No newline at end of file
diff --git a/.graphs/https/specs.apollo.dev/tag/v0.1.html b/.graphs/https/specs.apollo.dev/tag/v0.1.html
new file mode 100644
index 0000000..3da2eae
--- /dev/null
+++ b/.graphs/https/specs.apollo.dev/tag/v0.1.html
@@ -0,0 +1,1597 @@
+
+
+
+
+tag v0.1
+
+
+
+
+
+
+
+
+
+
Apply an arbitrary piece of string metadata to the target.
+
The following example demonstrates how team ownership over types and fields can be declaratively expressed via inline metadata. One might imagine a CI workflow which analyzes a schema diff and uses @tag names to authorize or require approval for changes to parts of the graph.
+
+
+
diff --git a/id-v1.0.graphql b/id-v1.0.graphql
new file mode 100644
index 0000000..03b8700
--- /dev/null
+++ b/id-v1.0.graphql
@@ -0,0 +1,3 @@
+@id(url: "https://specs.apollo.dev/id/v1.0")
+
+directive @id(url: String!) on SCHEMA
\ No newline at end of file
diff --git a/inaccessible/inaccessible.spec.graphql b/inaccessible/inaccessible-v0.1.graphql
similarity index 99%
rename from inaccessible/inaccessible.spec.graphql
rename to inaccessible/inaccessible-v0.1.graphql
index 6e001de..5f03b6c 100644
--- a/inaccessible/inaccessible.spec.graphql
+++ b/inaccessible/inaccessible-v0.1.graphql
@@ -1,8 +1,6 @@
@id(url: "https://specs.apollo.dev/inaccessible/v0.1")
"""
-# Inaccessible
-
for removing elements from a core schema
```raw html
diff --git a/link/link-v1.0.graphql b/link/link-v1.0.graphql
index 11709de..ad96bbc 100644
--- a/link/link-v1.0.graphql
+++ b/link/link-v1.0.graphql
@@ -4,7 +4,7 @@
```raw html
Status
Draft
-
Version
2.0
+
Version
1.0
@@ -67,7 +67,7 @@ A feature's *root directive* is an exception to the prefixing requirements. Feat
```graphql example -- Using the @link directive without changing the prefix
schema
- @link(url: "https://specs.apollo.dev/link/v1.0", import: ["@link"])
+ @link(url: "https://specs.apollo.dev/link/v1.0")
@link(url: "https://spec.example.com/example/v1.0") {
query: Query
}
@@ -93,7 +93,7 @@ The prefix MUST NOT be elided within documentation; definitions of schema elemen
Feature specs MUST prefix the following schema elements:
- the names of any object types, interfaces, unions, enums, or input object types defined by the feature
- - the names of any directives introduced in the spec, with the exception of the *root directive*, which must have the same name as the feature
+ - the names of any directives introduced in the schema, with the exception of the *root directive*, which must have the same name as the schema
:::[example](prefixing.graphql) -- Prefixing
@@ -132,7 +132,7 @@ As specified by semver, spec authors SHOULD increment the:
++}
-Patch and pre-release qualifiers are judged to be not particularly meaningful in the context of core features, which are (by definition) interfaces rather than implementations. The patch component of a semver denotes a bug fix which is backwards compatible—that is, a change to the implementation which does not affect the interface. Patch-level changes in the version of a spec denote wording clarifications which do not require implementation changes. As such, it is not important to track them for the purposes of version resolution.
+Patch and pre-release qualifiers are judged to be not particularly meaningful in the context of GraphQL schemas, which are (by definition) interfaces rather than implementations. The patch component of a semver denotes a bug fix which is backwards compatible—that is, a change to the implementation which does not affect the interface. Patch-level changes in the version of a spec denote wording clarifications which do not require implementation changes. As such, it is not important to track them for the purposes of version resolution.
As with [semver](https://semver.org/spec/v2.0.0.html), the `0.x` version series is special: there is no expectation of compatibility between versions `0.x` and `0.y`. For example, a processor must not activate implementation `0.4` to satisfy a requested version of `0.2`.
diff --git a/package.json b/package.json
index 512d65e..defe6a9 100644
--- a/package.json
+++ b/package.json
@@ -5,6 +5,7 @@
"main": "index.js",
"bin": "./bin/library",
"scripts": {
+ "build": "graphc",
"start": "http-server -c-1"
},
"keywords": [],
diff --git a/tag/ownership-example.graphql b/tag/ownership-example.graphql
new file mode 100644
index 0000000..57fdeaf
--- /dev/null
+++ b/tag/ownership-example.graphql
@@ -0,0 +1,33 @@
+directive @tag(name: String!) repeatable on
+ | FIELD_DEFINITION
+ | INTERFACE
+ | OBJECT
+ | UNION
+
+schema
+ @core(feature: "https://specs.apollo.dev/core/v0.2")
+ @core(feature: "https://specs.apollo.dev/tag/v0.1") {
+ query: Query
+}
+
+type Query {
+ customer(id: String!): Customer @tag(name: "team-customers")
+ employee(id: String!): Employee @tag(name: "team-admin")
+}
+
+interface User @tag(name: "team-accounts") {
+ id: String!
+ name: String!
+}
+
+type Customer implements User @tag(name: "team-customers") {
+ id: String!
+ name: String!
+ cart: [Product!] @tag(name: "team-shopping-cart")
+}
+
+type Employee implements User @tag(name: "team-admin") {
+ id: String!
+ name: String!
+ ssn: String!
+}
diff --git a/tag/spec.md b/tag/spec.md
new file mode 100644
index 0000000..3bef628
--- /dev/null
+++ b/tag/spec.md
@@ -0,0 +1,42 @@
+# Tag
+
+
for tagging GraphQL schema elements with names
+
+```raw html
+
+
Status
Release
+
Version
0.1
+
+
+
+```
+
+This document defines a [core feature](https://specs.apollo.dev/core) named `tag` for labeling schema elements with arbitrary names (or tags).
+
+This specification provides machinery to apply arbitrary tags to schema elements via the application of `@tag` directive usages. Tags can be applied to field, object, interface, and union definitions.
+
+# How to read this document
+
+This document uses [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt) guidance regarding normative terms: MUST / MUST NOT / REQUIRED / SHALL / SHALL NOT / SHOULD / SHOULD NOT / RECOMMENDED / MAY / OPTIONAL.
+
+## What this document isn't
+
+This document specifies only the definition of the `@tag` directive. Tags have a number of useful applications including metadata and schema processing, none of which are specified within this document.
+
+# Example: Team Ownership Metadata
+
+The following example demonstrates how team ownership over types and fields can be declaratively expressed via inline metadata. One might imagine a CI workflow which analyzes a schema diff and uses `@tag` names to authorize or require approval for changes to parts of the graph.
+
+:::[example](ownership-example.graphql)
+
+# Overview
+
+*This section is non-normative.* It describes the motivation behind the directives defined by this specification.
+
+The `@tag` directive is, in its simplest form, a mechanism for applying arbitrary string metadata to the fields and types of a schema. This metadata is potentially useful throughout the schema's lifecycle, including, but not limited to, processing, static analysis, and documentation.
+
+# Basic Requirements
+
+A schema which implements the `@tag` spec MUST provide a definition which is compatible with the definition below:
+
+:::[definition](spec.graphql)
\ No newline at end of file
diff --git a/tag/tag-v0.1.graphql b/tag/tag-v0.1.graphql
new file mode 100644
index 0000000..7d95e67
--- /dev/null
+++ b/tag/tag-v0.1.graphql
@@ -0,0 +1,14 @@
+@id(url: "https://specs.apollo.dev/tag/v0.1")
+
+"""
+Apply an arbitrary piece of string metadata to the target.
+
+The following example demonstrates how team ownership over types and fields can be declaratively expressed via inline metadata. One might imagine a CI workflow which analyzes a schema diff and uses `@tag` names to authorize or require approval for changes to parts of the graph.
+
+:::[example](ownership-example.graphql)
+"""
+directive @tag(name: String!) repeatable on
+ | FIELD_DEFINITION
+ | INTERFACE
+ | OBJECT
+ | UNION
From 73d7d17fba3f073985f2aa6b26e54e616aae2f5c Mon Sep 17 00:00:00 2001
From: Ashi Krishnan
Date: Fri, 22 Apr 2022 12:17:26 -0400
Subject: [PATCH 05/13] wip
---
.graphs/https/foo/foo.graphql | 149 ++
.graphs/https/foo/foo.html | 1562 +++++++++++++++++
.../https/specs.apollo.dev/id/v1.0.graphql | 2 -
.../specs.apollo.dev/inaccessible/v0.1.html | 4 +-
.../https/specs.apollo.dev/link/v1.0.graphql | 406 +----
.graphs/https/specs.apollo.dev/link/v1.0.html | 553 +-----
build | 5 +
...nk-v1.0.graphql => link-v1.0.spec.graphql} | 0
link/scope.md | 63 +
link/v1.0/algorithms.md | 132 ++
link/{ => v1.0}/basic.graphql | 0
link/v1.0/core-schemas-intro.md | 23 +
link/v1.0/link-v1.0.graphql | 196 +++
link/{ => v1.0}/prefix-uniqueness.graphql | 0
link/{ => v1.0}/prefixing.graphql | 0
link/versioning.md | 54 +
package-lock.json | 170 +-
package.json | 5 +-
tag/ownership-example.graphql | 33 -
tag/spec.md | 42 -
tag/tag-v0.1.graphql | 14 -
tag/v0.1 | 1 +
22 files changed, 2456 insertions(+), 958 deletions(-)
create mode 100644 .graphs/https/foo/foo.graphql
create mode 100644 .graphs/https/foo/foo.html
create mode 100755 build
rename link/{link-v1.0.graphql => link-v1.0.spec.graphql} (100%)
create mode 100644 link/scope.md
create mode 100644 link/v1.0/algorithms.md
rename link/{ => v1.0}/basic.graphql (100%)
create mode 100644 link/v1.0/core-schemas-intro.md
create mode 100644 link/v1.0/link-v1.0.graphql
rename link/{ => v1.0}/prefix-uniqueness.graphql (100%)
rename link/{ => v1.0}/prefixing.graphql (100%)
create mode 100644 link/versioning.md
delete mode 100644 tag/ownership-example.graphql
delete mode 100644 tag/spec.md
delete mode 100644 tag/tag-v0.1.graphql
create mode 160000 tag/v0.1
diff --git a/.graphs/https/foo/foo.graphql b/.graphs/https/foo/foo.graphql
new file mode 100644
index 0000000..ce10c09
--- /dev/null
+++ b/.graphs/https/foo/foo.graphql
@@ -0,0 +1,149 @@
+extend schema @link(url: "https://specs.apollo.dev/id/v1.0")
+
+extend schema @id__(url: "https://foo/foo")
+
+"""
+# hello
+
+a thing
+
+[x](./link/core-schemas-intro.md)
+"""
+schema {
+ query: Query
+}
+
+"""Link a foreign schema by its URL."""
+directive @link(
+ """
+ The foreign schema's URL.
+
+ Link URLs serve two main purposes:
+ - Providing a unique identifier for the foreign schema
+ - Directing human readers to documentation about the foreign schema
+
+ Link URLs SHOULD be [RFC 3986 URLs](https://tools.ietf.org/html/rfc3986). When viewed, the URL SHOULD provide schema documentation in some human-readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
+
+ Link URLs MAY contain information about the spec's [name](#sec-Prefixing) and [version](#sec-Versioning):
+
+ ```html diagram -- Basic anatomy of a link URL
+
+ https://spec.example.com/a/b/c/mySchema/v1.0
+
+ ```
+
+ The final two segments of the URL's [path](https://tools.ietf.org/html/rfc3986#section-3.3) MAY contain the schema's name and a [version tag](#sec-Versioning), in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid {VersionTag}. To be recognized as a name, the penultimate path component MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name) which does not include the namespace separator ({"__"}).
+
+ Empty final path components (that is, trailing slashes) and any URL components which have not been assigned a meaning (such as the fragment and query) MUST be ignored.
+
+ ```html diagram -- Ignoring meaningless parts of a URL
+
+ https://example.com/exampleSchema/v1.0/?key=val&k2=v2#frag
+
+ ```
+
+ All of these are valid arguments to `url`, and their interpretations:
+
+ | url | normalized url | name | version |
+ | ------------------------------------------------- | ------------------------------------------ | ------- | -------- |
+ | https://spec.example.com/a/b/mySchema/v1.0/ | https://spec.example.com/a/b/mySchema/v1.0 | mySchema | v1.0 |
+ | https://spec.example.com | https://spec.example.com | *(null)* | *(null)* |
+ | https://spec.example.com/mySchema/v0.1?q=v#frag | https://spec.example.com/mySchema/v0.1 | mySchema | v0.1 |
+ | https://spec.example.com/v1.0 | https://spec.example.com/v1.0 | *(null)* | v1.0 |
+ | https://spec.example.com/vX | https://spec.example.com/vX | vX | *(null)* |
+
+ If `name` is present, that [namespace prefix](#sec-Prefixing) will automatically be linked to the URL. If a `name` is not present, then elements of the foreign schema must be [`imported`](#@link/import) in order to be referenced.
+ """
+ url: String!
+ """
+ Change the [namespace prefix](#sec-Prefixing) assigned to this schema.
+
+ The name must be a valid GraphQL identifier, and must not contain the namespace separator ({"__"}).
+
+ By default, {@link} will assign a prefix based on the `name` extracted from the URL. If no `name` is present, a prefix will not be assigned.
+
+ Providing [`as:`](#@link/as) overrides the default behavior: the foreign schema will be assigned the provided prefix, regardless of the `name` present in the URL (or the lack of one).
+
+ ```graphql example -- Using {@link}(url:, as:) to use a feature with a custom name
+ schema
+ @link(url: "https://specs.apollo.dev/link/v1.0")
+ @link(url: "https://spec.example.com/example/v1.0", as: "eg")
+ {
+ query: Query
+ }
+
+ type User {
+ # Specifying `as: "eg"` transforms @example into @eg
+ name: String @eg(data: ITEM)
+ }
+
+ # Additional specified schema elements must have their prefixes set
+ # to the new name.
+ enum eg__Data {
+ ITEM
+ }
+
+ # Name transformation must also be applied to definitions pulled in from
+ # specifications.
+ directive @eg(data: eg__Data) on FIELD_DEFINITION
+
+ directive @link(url: String!, as: String) repeatable on SCHEMA
+ ```
+ """
+ as: String
+ """Import definitions into the local namespace."""
+ import: [Import]
+ """
+ An optional [purpose](#Purpose) for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
+
+ By default, {@link}s SHOULD fail open. This means that {@link}s to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
+
+ This behavior is different for {@link}s with a specified purpose:
+ - `SECURITY` links convey metadata necessary to compute the API schema and securely resolve fields within it
+ - `EXECUTION` links convey metadata necessary to correctly resolve fields within the schema
+ """
+ for: Purpose
+) repeatable on SCHEMA
+
+"""TK describe an import"""
+scalar Import
+
+"""
+The role of a feature referenced with {@link}.
+
+This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail-open behavior of core schema consumers is undesirable.
+
+Note we'll refer to directives from features which are `for: SECURITY` or `for: EXECUTION` as "`SECURITY` directives" and "`EXECUTION` directives", respectively.
+"""
+enum Purpose {
+ """
+ `SECURITY` links provide metadata necessary to securely resolve fields. For instance, a hypothetical {auth} feature may provide an {@auth} directive to flag fields which require authorization. If a data core does not support the {auth} feature and serves those fields anyway, these fields will be accessible without authorization, compromising security.
+
+ Security-conscious consumers MUST NOT serve a field if:
+ - the schema definition has **any** unsupported SECURITY directives,
+ - the field's parent type definition has **any** unsupported SECURITY directives,
+ - the field's return type definition has **any** unsupported SECURITY directives, or
+ - the field definition has **any** unsupported SECURITY directives
+
+ Such fields are *not securely resolvable*. Security-conscious consumers MAY serve schemas with fields which are not securely resolvable. However, they MUST remove such fields from the schema before serving it.
+
+ Less security-conscious consumers MAY choose to relax these requirements. For instance, servers may provide a development mode in which unknown SECURITY directives are ignored, perhaps with a warning. Such software may also provide a way to explicitly disable some or all SECURITY links during development.
+
+ More security-conscious consumers MAY choose to enhance these requirements. For instance, production servers MAY adopt a policy of entirely rejecting any schema which contains ANY unsupported SECURITY links, even if those links are never used to annotate the schema.
+ """
+ SECURITY
+ """
+ `EXECUTION` features provide metadata necessary to correctly resolve fields. For instance, a hypothetical {ts} feature may provide a `@ts__resolvers` annotation which references a TypeScript module of field resolvers. A consumer which does not support the {ts} feature will be unable to correctly resolve such fields.
+
+ Consumers MUST NOT serve a field if:
+ - the schema's definition has **any** unsupported EXECUTION directives,
+ - the field's parent type definition has **any** unsupported EXECUTION directives,
+ - the field's return type definition has **any** unsupported EXECUTION directives, or
+ - the field definition has **any** unsupported EXECUTION directives
+
+ Such fields are *unresolvable*. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION features, even if those features are never used in the schema.
+ """
+ EXECUTION
+}
+
+directive @id__(url: String!) on SCHEMA
\ No newline at end of file
diff --git a/.graphs/https/foo/foo.html b/.graphs/https/foo/foo.html
new file mode 100644
index 0000000..e854520
--- /dev/null
+++ b/.graphs/https/foo/foo.html
@@ -0,0 +1,1562 @@
+
+
+
+
+foo
+
+
+
+
+
+
+
+
+
+
This specification makes references to Processors. Processors are described in the Actors section of the @core spec as an actor which can perform transformations on a core schema. In the case of @inaccessible, the Processor will be expected to remove various parts of a core schema.
+
This specification makes references to Processors. Processors are described in the Actors section of the @core spec as an actor which can perform transformations on a core schema. In the case of @inaccessible, the Processor will be expected to remove various parts of a core schema.
diff --git a/.graphs/https/specs.apollo.dev/link/v1.0.graphql b/.graphs/https/specs.apollo.dev/link/v1.0.graphql
index da2c8a9..e04bcfa 100644
--- a/.graphs/https/specs.apollo.dev/link/v1.0.graphql
+++ b/.graphs/https/specs.apollo.dev/link/v1.0.graphql
@@ -12,147 +12,15 @@ extend schema
```
-Core schemas provide tools for linking definitions from different GraphQL schemas together into one.
+[intro to core schemas](core-schemas-intro.md)
-```graphql example -- linking a directive from another schema
-extend schema
- # 👇🏽 schemas are identified by a url
- @link(url: "https://internal.example.com/admin")
-
-type Query {
- allUsers: [User] @admin__adminOnly # 👈🏽 remote identifier, namespaced
-}
-```
-
-```graphql example -- importing a directive from another schema
-extend schema
- # specific definitions can be imported 👇🏽
- @link(url: "https://internal.example.com/admin", import: ["@adminOnly"])
-
-type Query {
- allUsers: [User] @adminOnly # 👈🏽 remote identifier, imported
-}
-```
-
-This document introduces a set of conventions for linking and namespacing within GraphQL schemas. Core schemas are not a new kind of document and do not introduce any new syntax—they are just GraphQL schemas which can be interpreted according to the conventions outlined in this doc.
-
-# Renaming {@link}
-
-It is possible to rename {@link} with the same {@link.as} mechanism used for all links:
-
-```graphql example -- Renaming {@link} to {@linkOther}
-schema
- @linkOther(url: "https://specs.apollo.dev/link/v1.0", import: [{name: "@link", as: "@linkOther"}])
- @linkOther(url: "https://example.com/example/v1.0")
-{
- query: Query
-}
-
-type SomeType {
- field: Int @example
-}
-```
-
-# Prefixing
-
-With the exception of a single root directive, core feature specifications MUST prefix all schema elements they introduce. The prefix:
- 1. MUST match the name of the feature as derived from the feature's specification URL,
- 2. MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name), and
- 3. MUST NOT contain the core namespace separator, which is two underscores ({"__"}), and
- 4. MUST NOT end with an underscore (which would create ambiguity between whether {"x___y"} is prefix `x_` for element `y` or prefix `x` for element `_y`).
-
-Prefixed names consist of the name of the feature, followed by two underscores, followed by the name of the element, which can be any valid [GraphQL name](https://spec.graphql.org/draft/#Name). For instance, the `core` specification (which you are currently reading) introduces an element named [{@link}](#@link), and the `join` specification introduces an element named {@join__field} (among others).
-
-Note that both parts must be valid GraphQL names, and GraphQL names cannot start with digits, so core feature specifications cannot introduce names like `@feature__24hours`.
-
-A feature's *root directive* is an exception to the prefixing requirements. Feature specifications MAY introduce a single directive which carries only the name of the feature, with no prefix required. For example, the `core` specification introduces a {@link} directive. This directive has the same name as the feature ("`core`"), and so requires no prefix.
-
-```graphql example -- Using the @link directive without changing the prefix
-schema
- @link(url: "https://specs.apollo.dev/link/v1.0")
- @link(url: "https://spec.example.com/example/v1.0") {
- query: Query
-}
-
-type User {
- name: String @example(data: ITEM)
-}
+# Scoping
-# An enum used to provide structured data to the example spec.
-# It is prefixed with the name of the spec.
-enum example__Data {
- ITEM
-}
-
-directive @example(data: example__Data) on FIELD_DEFINITION
-
-directive @link(url: String!, as: String) repeatable on SCHEMA
-```
-
-The prefix MUST NOT be elided within documentation; definitions of schema elements provided within the spec MUST include the feature's name as a prefix.
-
-## Elements which must be prefixed
-
-Feature specs MUST prefix the following schema elements:
- - the names of any object types, interfaces, unions, enums, or input object types defined by the feature
- - the names of any directives introduced in the schema, with the exception of the *root directive*, which must have the same name as the schema
-
-:::[example](prefixing.graphql) -- Prefixing
+[scope](../scope.md)
# Versioning
-VersionTag : "v" Version
-
-Version : Major "." Minor
-
-Major : NumericIdentifier
-
-Minor : NumericIdentifier
-
-NumericIdentifier : "0"
- | PositiveDigit Digit*
-
-Digit : "0" | PositiveDigit
-
-PositiveDigit : "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
-
-Specs are versioned with a **subset** of a [Semantic Version Number](https://semver.org/spec/v2.0.0.html) containing only the major and minor parts. Thus, specifications SHOULD provide a version of the form `v`{Major}`.`{Minor}, where both integers >= 0.
-
-```text example -- Valid version tags
-v2.2
-v1.0
-v1.1
-v0.1
-```
-
-As specified by semver, spec authors SHOULD increment the:
-
-{++
-
-- MAJOR version when you make incompatible API changes,
-- MINOR version when you add functionality in a backwards compatible manner
-
-++}
-
-Patch and pre-release qualifiers are judged to be not particularly meaningful in the context of GraphQL schemas, which are (by definition) interfaces rather than implementations. The patch component of a semver denotes a bug fix which is backwards compatible—that is, a change to the implementation which does not affect the interface. Patch-level changes in the version of a spec denote wording clarifications which do not require implementation changes. As such, it is not important to track them for the purposes of version resolution.
-
-As with [semver](https://semver.org/spec/v2.0.0.html), the `0.x` version series is special: there is no expectation of compatibility between versions `0.x` and `0.y`. For example, a processor must not activate implementation `0.4` to satisfy a requested version of `0.2`.
-
-## Satisfaction
-
-Given a version {requested} by a document and an {available} version of an implementation, the following algorithm will determine if the {available} version can satisfy the {requested} version:
-
-Satisfies(requested, available) :
- 1. If {requested}.{Major} ≠ {available}.{Major}, return {false}
- 2. If {requested}.{Major} = 0, return {requested}.{Minor} = {available}.{Minor}
- 3. Return {requested}.{Minor} <= {available}.{Minor}
-
-## Referencing versions and activating implementations
-
-Schema documents MUST reference a feature version which supports all the schema elements and behaviors required by the document. As a practical matter, authors will generally prefer to reference a version they have reason to believe is supported by the most processors; depending on context, this might be an old stable version with a low major version, or a new less-deprecated version with a large major version.
-
-If a processor chooses to activate support for a feature, the processor MUST activate an implementation which can [satisfy](#sec-Satisfaction) the version required by the document.
-
+[Versioning](../versioning.md)
# Processing Schemas
@@ -177,138 +45,9 @@ Processors MAY accept configuration which overrides these default behaviors.
Additionally, processors which prepare the schema for final public consumption MAY choose to eliminate all unknown directives and prefixed types in order to hide schema implementation details within the published schema. This will impair the operation of tooling which relies on these directives—such tools will not be able to run on the output schema, so the benefits and costs of this kind of information hiding should be weighed carefully on a case-by-case basis.
-# Validations & Algorithms
-
-This section lays out algorithms for processing core schemas.
-
-Algorithms described in this section may produce *validation failures* if a document does not conform to the requirements core schema document. Validation failures SHOULD halt processing. Some consumers, such as authoring tools, MAY attempt to continue processing in the presence of validation failures, but their behavior in such cases is unspecified.
-
-## Bootstrapping
-
-Determine the name of the core specification within the document.
-
-It is possible to [rename the core feature](#sec-Renaming-core-itself) within a document. This process determines the actual name for the core feature if one is present.
-
-- **Fails** the *Has Schema* validation if there are no SchemaDefinitions in the document
-- **Fails** the *Has Core Feature* validation if the `core` feature itself is not referenced with a {@link} directive within the document
-- **Fails** the *Bootstrap Core Feature Listed First* validation if the reference to the `core` feature is not the first {@link} directive on the document's SchemaDefinition
-- **Fails** the *Core Directive Incorrect Definition* validation if the {@link} directive definition does not *match* the directive as defined by this specification.
-
-For the purposes of this algorithm, a directive's definition in a schema *matches* a definition provided in this specification if:
-- Its arguments have the specified names, types, and default values (or lack thereof)
-- It is defined as `repeatable` if and only if the specification's definition defines it as `repeatable`
-- The set of locations it belongs to is the same set of locations in the specification's definition.
-
-The following aspects may differ between the definition in the schema and the definition in the specification without preventing the definitions from *matching*:
-- The name of the directive (due to [prefixing](#sec-Prefixing))
-- The order of arguments
-- The order of locations
-- The directive's description string
-- Argument description strings
-- Directives applied to argument definitions
-
-Bootstrap(document) :
-1. Let {schema} be the only SchemaDefinition in {document}. (Note that legal GraphQL documents [must include at most one SchemaDefinition](http://spec.graphql.org/draft/#sec-Root-Operation-Types).)
- 1. ...if no SchemaDefinitions are present in {document}, the ***Has Schema* validation fails**.
-1. For each directive {d} on {schema},
- 1. If {d} has a [`url:`](#@link/feature) argument which [parses as a feature URL](#@link/feature), *and* whose identity is {"https://specs.apollo.dev/core/"} *and* whose version is {"v0.1"}, *and either* {d} has an [`as:`](#@link/as) argument whose value is equal to {d}'s name *or* {d} does not have an [`as:`](#@link/as) argument and {d}'s name is `core`:
- - If any directive on {schema} listed before {d} has the same name as {d}, the ***Bootstrap Core Feature Listed First* validation fails**.
- - If the definition of the directive {d} does not *match* the [definition of {@link} in this specification](#@link), the ***Core Directive Incorrect Definition* validation fails**.
- - Otherwise, **Return** {d}'s name.
-- If no matching directive was found, the ***Has Core Feature* validation fails**.
-
-## Feature Collection
-
-Collect a map of ({featureName}: `String`) -> `Directive`, where `Directive` is a {@link} Directive which introduces the feature named {featureName} into the document.
-
-- **Fails** the *Name Uniqueness* validation if feature names are not unique within the document.
-- **Fails** *Invalid Feature URL* validation for any invalid feature URLs.
-
-CollectFeatures(document) :
- - Let {coreName} be the name of the core feature found via {Bootstrap(document)}
- - Let {features} be a map of {featureName}: `String` -> `Directive`, initially empty.
- - For each directive {d} named {coreName} on the SchemaDefinition within {document},
- - Let {specifiedFeatureName} and {version} be the result of parsing {d}'s `url:` argument according to the [specified rules for feature URLs](#@link/feature)
- - If the `url:` is not present or fails to parse:
- - The ***Invalid Feature URL* validation fails** for {d},
- - Let {featureName} be the {d}'s [`as:`](#@link/as) argument or, if the argument is not present, {specifiedFeatureName}
- - If {featureName} exists within {features}, the ***Name Uniqueness* validation fails**.
- - Insert {featureName} => {d} into {features}
- - **Return** {features}
-
-
-Prefixes, whether implicit or explicit, must be unique within a document. Valid:
-
-:::[example](prefixing.graphql#schema[0]) -- Unique prefixes
-
-It is also valid to reference multiple versions of the same spec under different prefixes:
-
-:::[example](prefix-uniqueness.graphql#schema[0]) -- Explicit prefixes allow multiple versions of the same spec to coexist within a Document
-
-Without the explicit [`as:`](#@link/as), the above would be invalid:
-
-:::[counter-example](prefix-uniqueness.graphql#schema[1]) -- Non-unique prefixes with multiple versions of the same spec
-
-Different specs with the same prefix are also invalid:
-
-:::[counter-example](prefix-uniqueness.graphql#schema[2]) -- Different specs with non-unique prefixes
-
-## Assign Features
-
-Create a map of {element}: *Any Named Element* -> {feature}: `Directive` | {null}, associating every named schema element within the document with a feature directive, or {null} if it is not associated with a feature.
-
-AssignFeatures(document) :
- - Let {features} be the result of collecting features via {CollectFeatures(document)}
- - Let {assignments} be a map of ({element}: *Any Named Element*) -> {feature}: `Directive` | {null}, initally empty
- - For each named schema element {e} within the {document}
- - Let {name} be the name of the {e}
- - If {e} is a Directive and {name} is a key within {features},
- - Insert {e} => {features}`[`{name}`]` into {assignments}
- - **Continue** to next {e}
- - If {name} begins with {"__"},
- - Insert {e} => {null} into {assignments}
- - **Continue** to next {e}
- - If {name} contains the substring {"__"},
- - Partition {name} into `[`{prefix}, {base}`]` at the first {"__"} (that is, find the shortest {prefix} and longest {base} such that {name} = {prefix} + {"__"} + {base})
- - If {prefix} exists within {features}, insert {e} => {features}`[`{prefix}`]` into {assignments}
- - Else, insert {e} => {null} into {assignments}
- - **Continue** to next {e}
- - Insert {e} => {null} into {assignments}
- - **Return** {assignments}
-
-## Is In API?
+# Algorithms
-Determine if any schema element is included in the [API](#sec-Parts-of-a-Core-Schema) described by the core schema. A schema element is any part of a GraphQL document using type system definitions that has a [name](https://spec.graphql.org/draft/#Name).
-
-IsInAPI(element) :
- - Let {assignments} be the result of assigning features to elements via {AssignFeatures(document)}
- - If {assignments}`[`{element}`]` is {null}, **Return** {true}
- - Else, **Return** {false}
-
-Note: Later versions of this specification may add other ways to affect the behavior of this algorithm, but those mechanisms will only be enabled if you reference those hypothetical versions of this specification.
-
-## Is Affected By Feature?
-
-Determine if a schema element is *affected* by a given feature.
-
-IsAffected(element, feature):
- - Let {assignments} be the result of assigning features to elements via {AssignFeatures(document)}
- - For each directive {d} on {element}, If {assignments}`[`{d}`]` is {feature}, **Return** {true}
- - If {element} is a FieldDefinition,
- - Let {parent} be the parent ObjectDefinition or InterfaceDefinition for {element}
- - If {IsAffected(parent, feature)}, **Return** {true}
- - For each argument type {a} declared on {element},
- - Let {t} be the InputDefinition, EnumDefinition, or ScalarDefinition for argument {a}
- - If {IsAffected(t, feature)}, **Return** {true}
- - Let {return} be the ObjectDefinition, InterfaceDefinition, or UnionDefinition for {element}'s return type
- - If {IsAffected(return, feature)}, **Return** {true}
- - If {element} is an InputDefinition,
- - For each InputFieldDefinition {field} within {element},
- - Let {t} be the InputDefinition, EnumDefinition, or ScalarDefinition for the type of {field}
- - If {IsAffected(t, feature)}, **Return** {true}
- - If {element} is an EnumDefinition,
- - For each EnumValueDefinition {value} in {element},
- - If {IsAffected(value, feature)}, **Return** {true}
+[Algorithms](algorithms.md)
"""
schema {
query: Query
@@ -447,137 +186,4 @@ enum Purpose {
EXECUTION
}
-"""Link a foreign schema by its URL."""
-directive @link(
- """
- The foreign schema's URL.
-
- Link URLs serve two main purposes:
- - Providing a unique identifier for the foreign schema
- - Directing human readers to documentation about the foreign schema
-
- Link URLs SHOULD be [RFC 3986 URLs](https://tools.ietf.org/html/rfc3986). When viewed, the URL SHOULD provide schema documentation in some human-readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
-
- Link URLs MAY contain information about the spec's [name](#sec-Prefixing) and [version](#sec-Versioning):
-
- ```html diagram -- Basic anatomy of a link URL
-
- https://spec.example.com/a/b/c/mySchema/v1.0
-
- ```
-
- The final two segments of the URL's [path](https://tools.ietf.org/html/rfc3986#section-3.3) MAY contain the schema's name and a [version tag](#sec-Versioning), in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid {VersionTag}. To be recognized as a name, the penultimate path component MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name) which does not include the namespace separator ({"__"}).
-
- Empty final path components (that is, trailing slashes) and any URL components which have not been assigned a meaning (such as the fragment and query) MUST be ignored.
-
- ```html diagram -- Ignoring meaningless parts of a URL
-
- https://example.com/exampleSchema/v1.0/?key=val&k2=v2#frag
-
- ```
-
- All of these are valid arguments to `url`, and their interpretations:
-
- | url | normalized url | name | version |
- | ------------------------------------------------- | ------------------------------------------ | ------- | -------- |
- | https://spec.example.com/a/b/mySchema/v1.0/ | https://spec.example.com/a/b/mySchema/v1.0 | mySchema | v1.0 |
- | https://spec.example.com | https://spec.example.com | *(null)* | *(null)* |
- | https://spec.example.com/mySchema/v0.1?q=v#frag | https://spec.example.com/mySchema/v0.1 | mySchema | v0.1 |
- | https://spec.example.com/v1.0 | https://spec.example.com/v1.0 | *(null)* | v1.0 |
- | https://spec.example.com/vX | https://spec.example.com/vX | vX | *(null)* |
-
- If `name` is present, that [namespace prefix](#sec-Prefixing) will automatically be linked to the URL. If a `name` is not present, then elements of the foreign schema must be [`imported`](#@link/import) in order to be referenced.
- """
- url: String!
- """
- Change the [namespace prefix](#sec-Prefixing) assigned to this schema.
-
- The name must be a valid GraphQL identifier, and must not contain the namespace separator ({"__"}).
-
- By default, {@link} will assign a prefix based on the `name` extracted from the URL. If no `name` is present, a prefix will not be assigned.
-
- Providing [`as:`](#@link/as) overrides the default behavior: the foreign schema will be assigned the provided prefix, regardless of the `name` present in the URL (or the lack of one).
-
- ```graphql example -- Using {@link}(url:, as:) to use a feature with a custom name
- schema
- @link(url: "https://specs.apollo.dev/link/v1.0")
- @link(url: "https://spec.example.com/example/v1.0", as: "eg")
- {
- query: Query
- }
-
- type User {
- # Specifying `as: "eg"` transforms @example into @eg
- name: String @eg(data: ITEM)
- }
-
- # Additional specified schema elements must have their prefixes set
- # to the new name.
- enum eg__Data {
- ITEM
- }
-
- # Name transformation must also be applied to definitions pulled in from
- # specifications.
- directive @eg(data: eg__Data) on FIELD_DEFINITION
-
- directive @link(url: String!, as: String) repeatable on SCHEMA
- ```
- """
- as: String
- """Import definitions into the local namespace."""
- import: [Import]
- """
- An optional [purpose](#Purpose) for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
-
- By default, {@link}s SHOULD fail open. This means that {@link}s to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
-
- This behavior is different for {@link}s with a specified purpose:
- - `SECURITY` links convey metadata necessary to compute the API schema and securely resolve fields within it
- - `EXECUTION` links convey metadata necessary to correctly resolve fields within the schema
- """
- for: Purpose
-) repeatable on SCHEMA
-
-"""TK describe an import"""
-scalar Import
-
-"""
-The role of a feature referenced with {@link}.
-
-This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail-open behavior of core schema consumers is undesirable.
-
-Note we'll refer to directives from features which are `for: SECURITY` or `for: EXECUTION` as "`SECURITY` directives" and "`EXECUTION` directives", respectively.
-"""
-enum Purpose {
- """
- `SECURITY` links provide metadata necessary to securely resolve fields. For instance, a hypothetical {auth} feature may provide an {@auth} directive to flag fields which require authorization. If a data core does not support the {auth} feature and serves those fields anyway, these fields will be accessible without authorization, compromising security.
-
- Security-conscious consumers MUST NOT serve a field if:
- - the schema definition has **any** unsupported SECURITY directives,
- - the field's parent type definition has **any** unsupported SECURITY directives,
- - the field's return type definition has **any** unsupported SECURITY directives, or
- - the field definition has **any** unsupported SECURITY directives
-
- Such fields are *not securely resolvable*. Security-conscious consumers MAY serve schemas with fields which are not securely resolvable. However, they MUST remove such fields from the schema before serving it.
-
- Less security-conscious consumers MAY choose to relax these requirements. For instance, servers may provide a development mode in which unknown SECURITY directives are ignored, perhaps with a warning. Such software may also provide a way to explicitly disable some or all SECURITY links during development.
-
- More security-conscious consumers MAY choose to enhance these requirements. For instance, production servers MAY adopt a policy of entirely rejecting any schema which contains ANY unsupported SECURITY links, even if those links are never used to annotate the schema.
- """
- SECURITY
- """
- `EXECUTION` features provide metadata necessary to correctly resolve fields. For instance, a hypothetical {ts} feature may provide a `@ts__resolvers` annotation which references a TypeScript module of field resolvers. A consumer which does not support the {ts} feature will be unable to correctly resolve such fields.
-
- Consumers MUST NOT serve a field if:
- - the schema's definition has **any** unsupported EXECUTION directives,
- - the field's parent type definition has **any** unsupported EXECUTION directives,
- - the field's return type definition has **any** unsupported EXECUTION directives, or
- - the field definition has **any** unsupported EXECUTION directives
-
- Such fields are *unresolvable*. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION features, even if those features are never used in the schema.
- """
- EXECUTION
-}
-
directive @id__(url: String!) on SCHEMA
\ No newline at end of file
diff --git a/.graphs/https/specs.apollo.dev/link/v1.0.html b/.graphs/https/specs.apollo.dev/link/v1.0.html
index a958a05..4dcf9f7 100644
--- a/.graphs/https/specs.apollo.dev/link/v1.0.html
+++ b/.graphs/https/specs.apollo.dev/link/v1.0.html
@@ -1533,445 +1533,120 @@
link v1.0
-
-
-
Status
Draft
-
Version
1.0
-
-
-
-
Core schemas provide tools for linking definitions from different GraphQL schemas together into one.
-
This document introduces a set of conventions for linking and namespacing within GraphQL schemas. Core schemas are not a new kind of document and do not introduce any new syntax—they are just GraphQL schemas which can be interpreted according to the conventions outlined in this doc.
Providing a unique identifier for the foreign schema
+
Directing human readers to documentation about the foreign schema
+
+
Link URLs SHOULD be RFC 3986 URLs. When viewed, the URL SHOULD provide schema documentation in some human‐readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
+
Link URLs MAY contain information about the spec’s name and version:
+
The final two segments of the URL’s pathMAY contain the schema’s name and a version tag, in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid VersionTag. To be recognized as a name, the penultimate path component MUST be a valid GraphQL name which does not include the namespace separator ("__").
+
Empty final path components (that is, trailing slashes) and any URL components which have not been assigned a meaning (such as the fragment and query) MUST be ignored.
+
All of these are valid arguments to url, and their interpretations:
+
+
+
url
+
normalized url
+
name
+
version
+
+
+
+
https://spec.example.com/a/b/mySchema/v1.0/
https://spec.example.com/a/b/mySchema/v1.0
mySchema
v1.0
+
+
https://spec.example.com
https://spec.example.com
(null)
(null)
+
+
https://spec.example.com/mySchema/v0.1?q=v#frag
https://spec.example.com/mySchema/v0.1
mySchema
v0.1
+
+
https://spec.example.com/v1.0
https://spec.example.com/v1.0
(null)
v1.0
+
+
https://spec.example.com/vX
https://spec.example.com/vX
vX
(null)
+
+
+
If name is present, that namespace prefix will automatically be linked to the URL. If a name is not present, then elements of the foreign schema must be imported in order to be referenced.
The name must be a valid GraphQL identifier, and must not contain the namespace separator ("__").
+
By default, @link will assign a prefix based on the name extracted from the URL. If no name is present, a prefix will not be assigned.
+
Providing as: overrides the default behavior: the foreign schema will be assigned the provided prefix, regardless of the name present in the URL (or the lack of one).
MUST NOT contain the core namespace separator, which is two underscores ("__"), and
-
MUST NOT end with an underscore (which would create ambiguity between whether "x___y" is prefix x_ for element y or prefix x for element _y).
-
-
Prefixed names consist of the name of the feature, followed by two underscores, followed by the name of the element, which can be any valid GraphQL name. For instance, the core specification (which you are currently reading) introduces an element named @link, and the join specification introduces an element named @join__field (among others).
-
-Note
-that both parts must be valid GraphQL names, and GraphQL names cannot start with digits, so core feature specifications cannot introduce names like @feature__24hours.
-
A feature’s root directive is an exception to the prefixing requirements. Feature specifications MAY introduce a single directive which carries only the name of the feature, with no prefix required. For example, the core specification introduces a @link directive. This directive has the same name as the feature (”core”), and so requires no prefix.
-
The prefix MUST NOT be elided within documentation; definitions of schema elements provided within the spec MUST include the feature’s name as a prefix.
Specs are versioned with a subset of a Semantic Version Number containing only the major and minor parts. Thus, specifications SHOULD provide a version of the form vMajor.Minor, where both integers ≥ 0.
-
As specified by semver, spec authors SHOULD increment the:
-
-
MAJOR version when you make incompatible API changes,
-
MINOR version when you add functionality in a backwards compatible manner
-
-
-
Patch and pre‐release qualifiers are judged to be not particularly meaningful in the context of GraphQL schemas, which are (by definition) interfaces rather than implementations. The patch component of a semver denotes a bug fix which is backwards compatible—that is, a change to the implementation which does not affect the interface. Patch‐level changes in the version of a spec denote wording clarifications which do not require implementation changes. As such, it is not important to track them for the purposes of version resolution.
-
As with semver, the 0.x version series is special: there is no expectation of compatibility between versions 0.x and 0.y. For example, a processor must not activate implementation 0.4 to satisfy a requested version of 0.2.
Given a version requested by a document and an available version of an implementation, the following algorithm will determine if the available version can satisfy the requested version:
3.2Referencing versions and activating implementations
-
Schema documents MUST reference a feature version which supports all the schema elements and behaviors required by the document. As a practical matter, authors will generally prefer to reference a version they have reason to believe is supported by the most processors; depending on context, this might be an old stable version with a low major version, or a new less‐deprecated version with a large major version.
-
If a processor chooses to activate support for a feature, the processor MUST activate an implementation which can satisfy the version required by the document.
Processors MAY accept configuration which overrides these default behaviors.
-
Additionally, processors which prepare the schema for final public consumption MAY choose to eliminate all unknown directives and prefixed types in order to hide schema implementation details within the published schema. This will impair the operation of tooling which relies on these directives—such tools will not be able to run on the output schema, so the benefits and costs of this kind of information hiding should be weighed carefully on a case‐by‐case basis.
This section lays out algorithms for processing core schemas.
-
Algorithms described in this section may produce validation failures if a document does not conform to the requirements core schema document. Validation failures SHOULD halt processing. Some consumers, such as authoring tools, MAY attempt to continue processing in the presence of validation failures, but their behavior in such cases is unspecified.
Determine the name of the core specification within the document.
-
It is possible to rename the core feature within a document. This process determines the actual name for the core feature if one is present.
-
-
Fails the Has Schema validation if there are no SchemaDefinitions in the document
-
Fails the Has Core Feature validation if the core feature itself is not referenced with a @link directive within the document
-
Fails the Bootstrap Core Feature Listed First validation if the reference to the core feature is not the first @link directive on the document’s SchemaDefinition
-
Fails the Core Directive Incorrect Definition validation if the @link directive definition does not match the directive as defined by this specification.
-
-
For the purposes of this algorithm, a directive’s definition in a schema matches a definition provided in this specification if:
-
-
Its arguments have the specified names, types, and default values (or lack thereof)
-
It is defined as repeatable if and only if the specification’s definition defines it as repeatable
-
The set of locations it belongs to is the same set of locations in the specification’s definition.
-
-
The following aspects may differ between the definition in the schema and the definition in the specification without preventing the definitions from matching:
...if no SchemaDefinitions are present in document, the Has Schema validation fails.
-
-
-
For each directive d on schema,
-
If d has a url: argument which parses as a feature URL, and whose identity is "https://specs.apollo.dev/core/"and whose version is "v0.1", and eitherd has an as: argument whose value is equal to d‘s name ord does not have an as: argument and d‘s name is core:
-
If any directive on schema listed before d has the same name as d, the Bootstrap Core Feature Listed First validation fails.
Collect a map of (featureName: String) → Directive, where Directive is a @link Directive which introduces the feature named featureName into the document.
-
-
Fails the Name Uniqueness validation if feature names are not unique within the document.
-
FailsInvalid Feature URL validation for any invalid feature URLs.
Create a map of element: Any Named Element → feature: Directive | null, associating every named schema element within the document with a feature directive, or null if it is not associated with a feature.
Determine if any schema element is included in the API described by the core schema. A schema element is any part of a GraphQL document using type system definitions that has a name.
Let assignments be the result of assigning features to elements via AssignFeatures(document)
-
If assignments[element] is null, Returntrue
-
Else, Returnfalse
-
-
-
-Note
-Later versions of this specification may add other ways to affect the behavior of this algorithm, but those mechanisms will only be enabled if you reference those hypothetical versions of this specification.
An optional purpose for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
+
By default, @links SHOULD fail open. This means that @links to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
+
This behavior is different for @links with a specified purpose:
This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail‐open behavior of core schema consumers is undesirable.
-
-Note
-we’ll refer to directives from features which are for: SECURITY or for: EXECUTION as “SECURITY directives” and “EXECUTION directives”, respectively.
diff --git a/build b/build
new file mode 100755
index 0000000..a4b9d56
--- /dev/null
+++ b/build
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+npx @queerviolet/speck tag/v0.1/tag-v0.1.md > tag/v0.1/index.html
+npx @queerviolet/speck core/v0.1/core-v0.1.md > core/v0.1/index.html
+npx @queerviolet/speck core/v0.2/core-v0.2.md > core/v0.2/index.html
\ No newline at end of file
diff --git a/link/link-v1.0.graphql b/link/link-v1.0.spec.graphql
similarity index 100%
rename from link/link-v1.0.graphql
rename to link/link-v1.0.spec.graphql
diff --git a/link/scope.md b/link/scope.md
new file mode 100644
index 0000000..e844e5e
--- /dev/null
+++ b/link/scope.md
@@ -0,0 +1,63 @@
+
+# Renaming link
+
+It is possible to rename {@link} with the same {@link.as} mechanism used for all links:
+
+```graphql example -- Renaming {@link} to {@linkOther}
+schema
+ @linkOther(url: "https://specs.apollo.dev/link/v1.0", import: [{name: "@link", as: "@linkOther"}])
+ @linkOther(url: "https://example.com/example/v1.0")
+{
+ query: Query
+}
+
+type SomeType {
+ field: Int @example
+}
+```
+
+# Prefixing
+
+With the exception of a single root directive, core feature specifications MUST prefix all schema elements they introduce. The prefix:
+ 1. MUST match the name of the feature as derived from the feature's specification URL,
+ 2. MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name), and
+ 3. MUST NOT contain the core namespace separator, which is two underscores ({"__"}), and
+ 4. MUST NOT end with an underscore (which would create ambiguity between whether {"x___y"} is prefix `x_` for element `y` or prefix `x` for element `_y`).
+
+Prefixed names consist of the name of the feature, followed by two underscores, followed by the name of the element, which can be any valid [GraphQL name](https://spec.graphql.org/draft/#Name). For instance, the `core` specification (which you are currently reading) introduces an element named [{@link}](#@link), and the `join` specification introduces an element named {@join__field} (among others).
+
+Note that both parts must be valid GraphQL names, and GraphQL names cannot start with digits, so core feature specifications cannot introduce names like `@feature__24hours`.
+
+A feature's *root directive* is an exception to the prefixing requirements. Feature specifications MAY introduce a single directive which carries only the name of the feature, with no prefix required. For example, the `core` specification introduces a {@link} directive. This directive has the same name as the feature ("`core`"), and so requires no prefix.
+
+```graphql example -- Using the @link directive without changing the prefix
+schema
+ @link(url: "https://specs.apollo.dev/link/v1.0")
+ @link(url: "https://spec.example.com/example/v1.0") {
+ query: Query
+}
+
+type User {
+ name: String @example(data: ITEM)
+}
+
+# An enum used to provide structured data to the example spec.
+# It is prefixed with the name of the spec.
+enum example__Data {
+ ITEM
+}
+
+directive @example(data: example__Data) on FIELD_DEFINITION
+
+directive @link(url: String!, as: String) repeatable on SCHEMA
+```
+
+The prefix MUST NOT be elided within documentation; definitions of schema elements provided within the spec MUST include the feature's name as a prefix.
+
+## Elements which must be prefixed
+
+Feature specs MUST prefix the following schema elements:
+ - the names of any object types, interfaces, unions, enums, or input object types defined by the feature
+ - the names of any directives introduced in the schema, with the exception of the *root directive*, which must have the same name as the schema
+
+:::[example](prefixing.graphql) -- Prefixing
diff --git a/link/v1.0/algorithms.md b/link/v1.0/algorithms.md
new file mode 100644
index 0000000..1df3ffc
--- /dev/null
+++ b/link/v1.0/algorithms.md
@@ -0,0 +1,132 @@
+# Validations & Algorithms
+
+This section lays out algorithms for processing core schemas.
+
+Algorithms described in this section may produce *validation failures* if a document does not conform to the requirements core schema document. Validation failures SHOULD halt processing. Some consumers, such as authoring tools, MAY attempt to continue processing in the presence of validation failures, but their behavior in such cases is unspecified.
+
+## Bootstrapping
+
+Determine the name of the core specification within the document.
+
+It is possible to [rename the core feature](#sec-Renaming-core-itself) within a document. This process determines the actual name for the core feature if one is present.
+
+- **Fails** the *Has Schema* validation if there are no SchemaDefinitions in the document
+- **Fails** the *Has Core Feature* validation if the `core` feature itself is not referenced with a {@link} directive within the document
+- **Fails** the *Bootstrap Core Feature Listed First* validation if the reference to the `core` feature is not the first {@link} directive on the document's SchemaDefinition
+- **Fails** the *Core Directive Incorrect Definition* validation if the {@link} directive definition does not *match* the directive as defined by this specification.
+
+For the purposes of this algorithm, a directive's definition in a schema *matches* a definition provided in this specification if:
+- Its arguments have the specified names, types, and default values (or lack thereof)
+- It is defined as `repeatable` if and only if the specification's definition defines it as `repeatable`
+- The set of locations it belongs to is the same set of locations in the specification's definition.
+
+The following aspects may differ between the definition in the schema and the definition in the specification without preventing the definitions from *matching*:
+- The name of the directive (due to [prefixing](#sec-Prefixing))
+- The order of arguments
+- The order of locations
+- The directive's description string
+- Argument description strings
+- Directives applied to argument definitions
+
+Bootstrap(document) :
+1. Let {schema} be the only SchemaDefinition in {document}. (Note that legal GraphQL documents [must include at most one SchemaDefinition](http://spec.graphql.org/draft/#sec-Root-Operation-Types).)
+ 1. ...if no SchemaDefinitions are present in {document}, the ***Has Schema* validation fails**.
+1. For each directive {d} on {schema},
+ 1. If {d} has a [`url:`](#@link/feature) argument which [parses as a feature URL](#@link/feature), *and* whose identity is {"https://specs.apollo.dev/core/"} *and* whose version is {"v0.1"}, *and either* {d} has an [`as:`](#@link/as) argument whose value is equal to {d}'s name *or* {d} does not have an [`as:`](#@link/as) argument and {d}'s name is `core`:
+ - If any directive on {schema} listed before {d} has the same name as {d}, the ***Bootstrap Core Feature Listed First* validation fails**.
+ - If the definition of the directive {d} does not *match* the [definition of {@link} in this specification](#@link), the ***Core Directive Incorrect Definition* validation fails**.
+ - Otherwise, **Return** {d}'s name.
+- If no matching directive was found, the ***Has Core Feature* validation fails**.
+
+## Feature Collection
+
+Collect a map of ({featureName}: `String`) -> `Directive`, where `Directive` is a {@link} Directive which introduces the feature named {featureName} into the document.
+
+- **Fails** the *Name Uniqueness* validation if feature names are not unique within the document.
+- **Fails** *Invalid Feature URL* validation for any invalid feature URLs.
+
+CollectFeatures(document) :
+ - Let {coreName} be the name of the core feature found via {Bootstrap(document)}
+ - Let {features} be a map of {featureName}: `String` -> `Directive`, initially empty.
+ - For each directive {d} named {coreName} on the SchemaDefinition within {document},
+ - Let {specifiedFeatureName} and {version} be the result of parsing {d}'s `url:` argument according to the [specified rules for feature URLs](#@link/feature)
+ - If the `url:` is not present or fails to parse:
+ - The ***Invalid Feature URL* validation fails** for {d},
+ - Let {featureName} be the {d}'s [`as:`](#@link/as) argument or, if the argument is not present, {specifiedFeatureName}
+ - If {featureName} exists within {features}, the ***Name Uniqueness* validation fails**.
+ - Insert {featureName} => {d} into {features}
+ - **Return** {features}
+
+
+Prefixes, whether implicit or explicit, must be unique within a document. Valid:
+
+:::[example](prefixing.graphql#schema[0]) -- Unique prefixes
+
+It is also valid to reference multiple versions of the same spec under different prefixes:
+
+:::[example](prefix-uniqueness.graphql#schema[0]) -- Explicit prefixes allow multiple versions of the same spec to coexist within a Document
+
+Without the explicit [`as:`](#@link/as), the above would be invalid:
+
+:::[counter-example](prefix-uniqueness.graphql#schema[1]) -- Non-unique prefixes with multiple versions of the same spec
+
+Different specs with the same prefix are also invalid:
+
+:::[counter-example](prefix-uniqueness.graphql#schema[2]) -- Different specs with non-unique prefixes
+
+## Assign Features
+
+Create a map of {element}: *Any Named Element* -> {feature}: `Directive` | {null}, associating every named schema element within the document with a feature directive, or {null} if it is not associated with a feature.
+
+AssignFeatures(document) :
+ - Let {features} be the result of collecting features via {CollectFeatures(document)}
+ - Let {assignments} be a map of ({element}: *Any Named Element*) -> {feature}: `Directive` | {null}, initally empty
+ - For each named schema element {e} within the {document}
+ - Let {name} be the name of the {e}
+ - If {e} is a Directive and {name} is a key within {features},
+ - Insert {e} => {features}`[`{name}`]` into {assignments}
+ - **Continue** to next {e}
+ - If {name} begins with {"__"},
+ - Insert {e} => {null} into {assignments}
+ - **Continue** to next {e}
+ - If {name} contains the substring {"__"},
+ - Partition {name} into `[`{prefix}, {base}`]` at the first {"__"} (that is, find the shortest {prefix} and longest {base} such that {name} = {prefix} + {"__"} + {base})
+ - If {prefix} exists within {features}, insert {e} => {features}`[`{prefix}`]` into {assignments}
+ - Else, insert {e} => {null} into {assignments}
+ - **Continue** to next {e}
+ - Insert {e} => {null} into {assignments}
+ - **Return** {assignments}
+
+## Is In API?
+
+Determine if any schema element is included in the [API](#sec-Parts-of-a-Core-Schema) described by the core schema. A schema element is any part of a GraphQL document using type system definitions that has a [name](https://spec.graphql.org/draft/#Name).
+
+IsInAPI(element) :
+ - Let {assignments} be the result of assigning features to elements via {AssignFeatures(document)}
+ - If {assignments}`[`{element}`]` is {null}, **Return** {true}
+ - Else, **Return** {false}
+
+Note: Later versions of this specification may add other ways to affect the behavior of this algorithm, but those mechanisms will only be enabled if you reference those hypothetical versions of this specification.
+
+## Is Affected By Feature?
+
+Determine if a schema element is *affected* by a given feature.
+
+IsAffected(element, feature):
+ - Let {assignments} be the result of assigning features to elements via {AssignFeatures(document)}
+ - For each directive {d} on {element}, If {assignments}`[`{d}`]` is {feature}, **Return** {true}
+ - If {element} is a FieldDefinition,
+ - Let {parent} be the parent ObjectDefinition or InterfaceDefinition for {element}
+ - If {IsAffected(parent, feature)}, **Return** {true}
+ - For each argument type {a} declared on {element},
+ - Let {t} be the InputDefinition, EnumDefinition, or ScalarDefinition for argument {a}
+ - If {IsAffected(t, feature)}, **Return** {true}
+ - Let {return} be the ObjectDefinition, InterfaceDefinition, or UnionDefinition for {element}'s return type
+ - If {IsAffected(return, feature)}, **Return** {true}
+ - If {element} is an InputDefinition,
+ - For each InputFieldDefinition {field} within {element},
+ - Let {t} be the InputDefinition, EnumDefinition, or ScalarDefinition for the type of {field}
+ - If {IsAffected(t, feature)}, **Return** {true}
+ - If {element} is an EnumDefinition,
+ - For each EnumValueDefinition {value} in {element},
+ - If {IsAffected(value, feature)}, **Return** {true}
\ No newline at end of file
diff --git a/link/basic.graphql b/link/v1.0/basic.graphql
similarity index 100%
rename from link/basic.graphql
rename to link/v1.0/basic.graphql
diff --git a/link/v1.0/core-schemas-intro.md b/link/v1.0/core-schemas-intro.md
new file mode 100644
index 0000000..da37b5e
--- /dev/null
+++ b/link/v1.0/core-schemas-intro.md
@@ -0,0 +1,23 @@
+Core schemas provide tools for linking definitions from different GraphQL schemas together into one.
+
+```graphql example -- linking a directive from another schema
+extend schema
+ # 👇🏽 schemas are identified by a url
+ @link(url: "https://internal.example.com/admin")
+
+type Query {
+ allUsers: [User] @admin__adminOnly # 👈🏽 remote identifier, namespaced
+}
+```
+
+```graphql example -- importing a directive from another schema
+extend schema
+ # specific definitions can be imported 👇🏽
+ @link(url: "https://internal.example.com/admin", import: ["@adminOnly"])
+
+type Query {
+ allUsers: [User] @adminOnly # 👈🏽 remote identifier, imported
+}
+```
+
+This document introduces a set of conventions for linking and namespacing within GraphQL schemas. Core schemas are not a new kind of document and do not introduce any new syntax—they are just GraphQL schemas which can be interpreted according to the conventions outlined in this doc.
diff --git a/link/v1.0/link-v1.0.graphql b/link/v1.0/link-v1.0.graphql
new file mode 100644
index 0000000..f8de95e
--- /dev/null
+++ b/link/v1.0/link-v1.0.graphql
@@ -0,0 +1,196 @@
+@id(url: "https://specs.apollo.dev/link/v1.0")
+
+"""
+```raw html
+
+
Status
Draft
+
Version
1.0
+
+
+
+```
+
+[intro to core schemas](core-schemas-intro.md)
+
+# Scoping
+
+[scope](../scope.md)
+
+# Versioning
+
+[Versioning](../versioning.md)
+
+# Processing Schemas
+
+```mermaid diagram
+graph LR
+ schema(["📄 Input Schema"]):::file-->proc("🤖 Processor")
+ proc-->output(["📄 Output Schema"]):::file
+ classDef file fill:none,color:#22262E;
+ style proc fill:none,stroke:fuchsia,color:fuchsia;
+```
+
+A common use case is that of a processor which consumes a valid input schema and generates an output schema.
+
+The general guidance for processor behavior is: don't react to what you don't understand.
+
+Specifically, processors:
+ - SHOULD pass through {@link} directives which reference unknown feature URLs
+ - SHOULD pass through prefixed directives, types, and other schema elements
+ - SHOULD pass through directives which are not [associated with](#AssignFeatures) a {@link} feature
+
+Processors MAY accept configuration which overrides these default behaviors.
+
+Additionally, processors which prepare the schema for final public consumption MAY choose to eliminate all unknown directives and prefixed types in order to hide schema implementation details within the published schema. This will impair the operation of tooling which relies on these directives—such tools will not be able to run on the output schema, so the benefits and costs of this kind of information hiding should be weighed carefully on a case-by-case basis.
+
+# Algorithms
+
+[Algorithms](algorithms.md)
+
+"""
+schema
+{ query: Query }
+
+
+"""
+Link a foreign schema by its URL.
+"""
+directive @link(
+ """
+ The foreign schema's URL.
+
+ Link URLs serve two main purposes:
+ - Providing a unique identifier for the foreign schema
+ - Directing human readers to documentation about the foreign schema
+
+ Link URLs SHOULD be [RFC 3986 URLs](https://tools.ietf.org/html/rfc3986). When viewed, the URL SHOULD provide schema documentation in some human-readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
+
+ Link URLs MAY contain information about the spec's [name](#sec-Prefixing) and [version](#sec-Versioning):
+
+ ```html diagram -- Basic anatomy of a link URL
+
+ https://spec.example.com/a/b/c/mySchema/v1.0
+
+ ```
+
+ The final two segments of the URL's [path](https://tools.ietf.org/html/rfc3986#section-3.3) MAY contain the schema's name and a [version tag](#sec-Versioning), in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid {VersionTag}. To be recognized as a name, the penultimate path component MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name) which does not include the namespace separator ({"__"}).
+
+ Empty final path components (that is, trailing slashes) and any URL components which have not been assigned a meaning (such as the fragment and query) MUST be ignored.
+
+ ```html diagram -- Ignoring meaningless parts of a URL
+
+ https://example.com/exampleSchema/v1.0/?key=val&k2=v2#frag
+
+ ```
+
+ All of these are valid arguments to `url`, and their interpretations:
+
+ | url | normalized url | name | version |
+ | ------------------------------------------------- | ------------------------------------------ | ------- | -------- |
+ | https://spec.example.com/a/b/mySchema/v1.0/ | https://spec.example.com/a/b/mySchema/v1.0 | mySchema | v1.0 |
+ | https://spec.example.com | https://spec.example.com | *(null)* | *(null)* |
+ | https://spec.example.com/mySchema/v0.1?q=v#frag | https://spec.example.com/mySchema/v0.1 | mySchema | v0.1 |
+ | https://spec.example.com/v1.0 | https://spec.example.com/v1.0 | *(null)* | v1.0 |
+ | https://spec.example.com/vX | https://spec.example.com/vX | vX | *(null)* |
+
+ If `name` is present, that [namespace prefix](#sec-Prefixing) will automatically be linked to the URL. If a `name` is not present, then elements of the foreign schema must be [`imported`](#@link/import) in order to be referenced.
+ """
+ url: String!,
+
+ """
+ Change the [namespace prefix](#sec-Prefixing) assigned to this schema.
+
+ The name must be a valid GraphQL identifier, and must not contain the namespace separator ({"__"}).
+
+ By default, {@link} will assign a prefix based on the `name` extracted from the URL. If no `name` is present, a prefix will not be assigned.
+
+ Providing [`as:`](#@link/as) overrides the default behavior: the foreign schema will be assigned the provided prefix, regardless of the `name` present in the URL (or the lack of one).
+
+ ```graphql example -- Using {@link}(url:, as:) to use a feature with a custom name
+ schema
+ @link(url: "https://specs.apollo.dev/link/v1.0")
+ @link(url: "https://spec.example.com/example/v1.0", as: "eg")
+ {
+ query: Query
+ }
+
+ type User {
+ # Specifying `as: "eg"` transforms @example into @eg
+ name: String @eg(data: ITEM)
+ }
+
+ # Additional specified schema elements must have their prefixes set
+ # to the new name.
+ enum eg__Data {
+ ITEM
+ }
+
+ # Name transformation must also be applied to definitions pulled in from
+ # specifications.
+ directive @eg(data: eg__Data) on FIELD_DEFINITION
+
+ directive @link(url: String!, as: String) repeatable on SCHEMA
+ ```
+ """
+ as: String,
+
+ """
+ Import definitions into the local namespace.
+ """
+ import: [Import],
+
+ """
+ An optional [purpose](#Purpose) for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
+
+ By default, {@link}s SHOULD fail open. This means that {@link}s to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
+
+ This behavior is different for {@link}s with a specified purpose:
+ - `SECURITY` links convey metadata necessary to compute the API schema and securely resolve fields within it
+ - `EXECUTION` links convey metadata necessary to correctly resolve fields within the schema
+ """
+ for: Purpose)
+ repeatable on SCHEMA
+
+"""
+TK describe an import
+"""
+scalar Import
+
+"""
+The role of a feature referenced with {@link}.
+
+This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail-open behavior of core schema consumers is undesirable.
+
+Note we'll refer to directives from features which are `for: SECURITY` or `for: EXECUTION` as "`SECURITY` directives" and "`EXECUTION` directives", respectively.
+"""
+enum Purpose {
+ """
+ `SECURITY` links provide metadata necessary to securely resolve fields. For instance, a hypothetical {auth} feature may provide an {@auth} directive to flag fields which require authorization. If a data core does not support the {auth} feature and serves those fields anyway, these fields will be accessible without authorization, compromising security.
+
+ Security-conscious consumers MUST NOT serve a field if:
+ - the schema definition has **any** unsupported SECURITY directives,
+ - the field's parent type definition has **any** unsupported SECURITY directives,
+ - the field's return type definition has **any** unsupported SECURITY directives, or
+ - the field definition has **any** unsupported SECURITY directives
+
+ Such fields are *not securely resolvable*. Security-conscious consumers MAY serve schemas with fields which are not securely resolvable. However, they MUST remove such fields from the schema before serving it.
+
+ Less security-conscious consumers MAY choose to relax these requirements. For instance, servers may provide a development mode in which unknown SECURITY directives are ignored, perhaps with a warning. Such software may also provide a way to explicitly disable some or all SECURITY links during development.
+
+ More security-conscious consumers MAY choose to enhance these requirements. For instance, production servers MAY adopt a policy of entirely rejecting any schema which contains ANY unsupported SECURITY links, even if those links are never used to annotate the schema.
+ """
+ SECURITY
+
+ """
+ `EXECUTION` features provide metadata necessary to correctly resolve fields. For instance, a hypothetical {ts} feature may provide a `@ts__resolvers` annotation which references a TypeScript module of field resolvers. A consumer which does not support the {ts} feature will be unable to correctly resolve such fields.
+
+ Consumers MUST NOT serve a field if:
+ - the schema's definition has **any** unsupported EXECUTION directives,
+ - the field's parent type definition has **any** unsupported EXECUTION directives,
+ - the field's return type definition has **any** unsupported EXECUTION directives, or
+ - the field definition has **any** unsupported EXECUTION directives
+
+ Such fields are *unresolvable*. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION features, even if those features are never used in the schema.
+ """
+ EXECUTION
+}
diff --git a/link/prefix-uniqueness.graphql b/link/v1.0/prefix-uniqueness.graphql
similarity index 100%
rename from link/prefix-uniqueness.graphql
rename to link/v1.0/prefix-uniqueness.graphql
diff --git a/link/prefixing.graphql b/link/v1.0/prefixing.graphql
similarity index 100%
rename from link/prefixing.graphql
rename to link/v1.0/prefixing.graphql
diff --git a/link/versioning.md b/link/versioning.md
new file mode 100644
index 0000000..3967380
--- /dev/null
+++ b/link/versioning.md
@@ -0,0 +1,54 @@
+
+# Versioning
+
+VersionTag : "v" Version
+
+Version : Major "." Minor
+
+Major : NumericIdentifier
+
+Minor : NumericIdentifier
+
+NumericIdentifier : "0"
+ | PositiveDigit Digit*
+
+Digit : "0" | PositiveDigit
+
+PositiveDigit : "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
+
+Specs are versioned with a **subset** of a [Semantic Version Number](https://semver.org/spec/v2.0.0.html) containing only the major and minor parts. Thus, specifications SHOULD provide a version of the form `v`{Major}`.`{Minor}, where both integers >= 0.
+
+```text example -- Valid version tags
+v2.2
+v1.0
+v1.1
+v0.1
+```
+
+As specified by semver, spec authors SHOULD increment the:
+
+{++
+
+- MAJOR version when you make incompatible API changes,
+- MINOR version when you add functionality in a backwards compatible manner
+
+++}
+
+Patch and pre-release qualifiers are judged to be not particularly meaningful in the context of GraphQL schemas, which are (by definition) interfaces rather than implementations. The patch component of a semver denotes a bug fix which is backwards compatible—that is, a change to the implementation which does not affect the interface. Patch-level changes in the version of a spec denote wording clarifications which do not require implementation changes. As such, it is not important to track them for the purposes of version resolution.
+
+As with [semver](https://semver.org/spec/v2.0.0.html), the `0.x` version series is special: there is no expectation of compatibility between versions `0.x` and `0.y`. For example, a processor must not activate implementation `0.4` to satisfy a requested version of `0.2`.
+
+## Satisfaction
+
+Given a version {requested} by a document and an {available} version of an implementation, the following algorithm will determine if the {available} version can satisfy the {requested} version:
+
+Satisfies(requested, available) :
+ 1. If {requested}.{Major} ≠ {available}.{Major}, return {false}
+ 2. If {requested}.{Major} = 0, return {requested}.{Minor} = {available}.{Minor}
+ 3. Return {requested}.{Minor} <= {available}.{Minor}
+
+## Referencing versions and activating implementations
+
+Schema documents MUST reference a feature version which supports all the schema elements and behaviors required by the document. As a practical matter, authors will generally prefer to reference a version they have reason to believe is supported by the most processors; depending on context, this might be an old stable version with a low major version, or a new less-deprecated version with a large major version.
+
+If a processor chooses to activate support for a feature, the processor MUST activate an implementation which can [satisfy](#sec-Satisfaction) the version required by the document.
diff --git a/package-lock.json b/package-lock.json
index 78a52dc..8e57ce7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,12 +15,32 @@
"specs.apollo.dev": "bin/library"
},
"devDependencies": {
+ "@queerviolet/speck": "queerviolet/speck",
"express": "^4.17.1",
"http-server": "^0.12.3",
"jsdom": "^16.4.0",
"puppeteer": "^5.5.0"
}
},
+ "node_modules/@queerviolet/speck": {
+ "version": "2.0.2",
+ "resolved": "git+ssh://git@github.com/queerviolet/speck.git#c34a337ff933613b590b01681d44608b4696044b",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "graphql": "^15.5.0",
+ "pegjs": "~0.8.0",
+ "prismjs": "^1.23.0",
+ "terser": "5.5.1"
+ },
+ "bin": {
+ "spec-md": "bin/spec-md"
+ },
+ "engines": {
+ "node": ">=10.14.2"
+ }
+ },
"node_modules/@types/node": {
"version": "14.14.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.10.tgz",
@@ -322,6 +342,12 @@
"node": "*"
}
},
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "dev": true
+ },
"node_modules/bytes": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
@@ -364,6 +390,12 @@
"node": ">= 0.8"
}
},
+ "node_modules/commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true
+ },
"node_modules/commonmark": {
"version": "0.29.3",
"resolved": "https://registry.npmjs.org/commonmark/-/commonmark-0.29.3.tgz",
@@ -992,6 +1024,15 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/graphql": {
+ "version": "15.8.0",
+ "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.8.0.tgz",
+ "integrity": "sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.x"
+ }
+ },
"node_modules/har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
@@ -1599,6 +1640,18 @@
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=",
"dev": true
},
+ "node_modules/pegjs": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/pegjs/-/pegjs-0.8.0.tgz",
+ "integrity": "sha1-l28GfaE+XFsVAcAXklZoolOBFWE=",
+ "dev": true,
+ "bin": {
+ "pegjs": "bin/pegjs"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/pend": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
@@ -1646,6 +1699,15 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/prismjs": {
+ "version": "1.28.0",
+ "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.28.0.tgz",
+ "integrity": "sha512-8aaXdYvl1F7iC7Xm1spqSaY/OJBpYW3v+KJ+F17iYxvdc8sfjW194COK5wVhMZX45tGteiBQgdvD/nhxcRwylw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/progress": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
@@ -2013,11 +2075,20 @@
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
- "optional": true,
"engines": {
"node": ">=0.10.0"
}
},
+ "node_modules/source-map-support": {
+ "version": "0.5.21",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+ "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+ "dev": true,
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
"node_modules/sshpk": {
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
@@ -2129,6 +2200,32 @@
"node": ">=6"
}
},
+ "node_modules/terser": {
+ "version": "5.5.1",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-5.5.1.tgz",
+ "integrity": "sha512-6VGWZNVP2KTUcltUQJ25TtNjx/XgdDsBDKGt8nN0MpydU36LmbPPcMBd2kmtZNNGVVDLg44k7GKeHHj+4zPIBQ==",
+ "dev": true,
+ "dependencies": {
+ "commander": "^2.20.0",
+ "source-map": "~0.7.2",
+ "source-map-support": "~0.5.19"
+ },
+ "bin": {
+ "terser": "bin/terser"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/terser/node_modules/source-map": {
+ "version": "0.7.3",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
+ "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8"
+ }
+ },
"node_modules/through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
@@ -2426,6 +2523,17 @@
}
},
"dependencies": {
+ "@queerviolet/speck": {
+ "version": "git+ssh://git@github.com/queerviolet/speck.git#c34a337ff933613b590b01681d44608b4696044b",
+ "dev": true,
+ "from": "@queerviolet/speck@queerviolet/speck",
+ "requires": {
+ "graphql": "^15.5.0",
+ "pegjs": "~0.8.0",
+ "prismjs": "^1.23.0",
+ "terser": "5.5.1"
+ }
+ },
"@types/node": {
"version": "14.14.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.10.tgz",
@@ -2666,6 +2774,12 @@
"integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
"dev": true
},
+ "buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "dev": true
+ },
"bytes": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
@@ -2699,6 +2813,12 @@
"delayed-stream": "~1.0.0"
}
},
+ "commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true
+ },
"commonmark": {
"version": "0.29.3",
"resolved": "https://registry.npmjs.org/commonmark/-/commonmark-0.29.3.tgz",
@@ -3201,6 +3321,12 @@
"path-is-absolute": "^1.0.0"
}
},
+ "graphql": {
+ "version": "15.8.0",
+ "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.8.0.tgz",
+ "integrity": "sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw==",
+ "dev": true
+ },
"har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
@@ -3663,6 +3789,12 @@
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=",
"dev": true
},
+ "pegjs": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/pegjs/-/pegjs-0.8.0.tgz",
+ "integrity": "sha1-l28GfaE+XFsVAcAXklZoolOBFWE=",
+ "dev": true
+ },
"pend": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
@@ -3701,6 +3833,12 @@
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
"dev": true
},
+ "prismjs": {
+ "version": "1.28.0",
+ "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.28.0.tgz",
+ "integrity": "sha512-8aaXdYvl1F7iC7Xm1spqSaY/OJBpYW3v+KJ+F17iYxvdc8sfjW194COK5wVhMZX45tGteiBQgdvD/nhxcRwylw==",
+ "dev": true
+ },
"progress": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
@@ -3999,8 +4137,17 @@
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ },
+ "source-map-support": {
+ "version": "0.5.21",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+ "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dev": true,
- "optional": true
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
},
"sshpk": {
"version": "1.16.1",
@@ -4084,6 +4231,25 @@
"readable-stream": "^3.1.1"
}
},
+ "terser": {
+ "version": "5.5.1",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-5.5.1.tgz",
+ "integrity": "sha512-6VGWZNVP2KTUcltUQJ25TtNjx/XgdDsBDKGt8nN0MpydU36LmbPPcMBd2kmtZNNGVVDLg44k7GKeHHj+4zPIBQ==",
+ "dev": true,
+ "requires": {
+ "commander": "^2.20.0",
+ "source-map": "~0.7.2",
+ "source-map-support": "~0.5.19"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.7.3",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
+ "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
+ "dev": true
+ }
+ }
+ },
"through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
diff --git a/package.json b/package.json
index defe6a9..f9a8c24 100644
--- a/package.json
+++ b/package.json
@@ -5,7 +5,7 @@
"main": "index.js",
"bin": "./bin/library",
"scripts": {
- "build": "graphc",
+ "build": "./build",
"start": "http-server -c-1"
},
"keywords": [],
@@ -15,7 +15,8 @@
"express": "^4.17.1",
"http-server": "^0.12.3",
"jsdom": "^16.4.0",
- "puppeteer": "^5.5.0"
+ "puppeteer": "^5.5.0",
+ "@queerviolet/speck": "queerviolet/speck"
},
"dependencies": {
"commonmark": "^0.29.3"
diff --git a/tag/ownership-example.graphql b/tag/ownership-example.graphql
deleted file mode 100644
index 57fdeaf..0000000
--- a/tag/ownership-example.graphql
+++ /dev/null
@@ -1,33 +0,0 @@
-directive @tag(name: String!) repeatable on
- | FIELD_DEFINITION
- | INTERFACE
- | OBJECT
- | UNION
-
-schema
- @core(feature: "https://specs.apollo.dev/core/v0.2")
- @core(feature: "https://specs.apollo.dev/tag/v0.1") {
- query: Query
-}
-
-type Query {
- customer(id: String!): Customer @tag(name: "team-customers")
- employee(id: String!): Employee @tag(name: "team-admin")
-}
-
-interface User @tag(name: "team-accounts") {
- id: String!
- name: String!
-}
-
-type Customer implements User @tag(name: "team-customers") {
- id: String!
- name: String!
- cart: [Product!] @tag(name: "team-shopping-cart")
-}
-
-type Employee implements User @tag(name: "team-admin") {
- id: String!
- name: String!
- ssn: String!
-}
diff --git a/tag/spec.md b/tag/spec.md
deleted file mode 100644
index 3bef628..0000000
--- a/tag/spec.md
+++ /dev/null
@@ -1,42 +0,0 @@
-# Tag
-
-
for tagging GraphQL schema elements with names
-
-```raw html
-
-
Status
Release
-
Version
0.1
-
-
-
-```
-
-This document defines a [core feature](https://specs.apollo.dev/core) named `tag` for labeling schema elements with arbitrary names (or tags).
-
-This specification provides machinery to apply arbitrary tags to schema elements via the application of `@tag` directive usages. Tags can be applied to field, object, interface, and union definitions.
-
-# How to read this document
-
-This document uses [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt) guidance regarding normative terms: MUST / MUST NOT / REQUIRED / SHALL / SHALL NOT / SHOULD / SHOULD NOT / RECOMMENDED / MAY / OPTIONAL.
-
-## What this document isn't
-
-This document specifies only the definition of the `@tag` directive. Tags have a number of useful applications including metadata and schema processing, none of which are specified within this document.
-
-# Example: Team Ownership Metadata
-
-The following example demonstrates how team ownership over types and fields can be declaratively expressed via inline metadata. One might imagine a CI workflow which analyzes a schema diff and uses `@tag` names to authorize or require approval for changes to parts of the graph.
-
-:::[example](ownership-example.graphql)
-
-# Overview
-
-*This section is non-normative.* It describes the motivation behind the directives defined by this specification.
-
-The `@tag` directive is, in its simplest form, a mechanism for applying arbitrary string metadata to the fields and types of a schema. This metadata is potentially useful throughout the schema's lifecycle, including, but not limited to, processing, static analysis, and documentation.
-
-# Basic Requirements
-
-A schema which implements the `@tag` spec MUST provide a definition which is compatible with the definition below:
-
-:::[definition](spec.graphql)
\ No newline at end of file
diff --git a/tag/tag-v0.1.graphql b/tag/tag-v0.1.graphql
deleted file mode 100644
index 7d95e67..0000000
--- a/tag/tag-v0.1.graphql
+++ /dev/null
@@ -1,14 +0,0 @@
-@id(url: "https://specs.apollo.dev/tag/v0.1")
-
-"""
-Apply an arbitrary piece of string metadata to the target.
-
-The following example demonstrates how team ownership over types and fields can be declaratively expressed via inline metadata. One might imagine a CI workflow which analyzes a schema diff and uses `@tag` names to authorize or require approval for changes to parts of the graph.
-
-:::[example](ownership-example.graphql)
-"""
-directive @tag(name: String!) repeatable on
- | FIELD_DEFINITION
- | INTERFACE
- | OBJECT
- | UNION
diff --git a/tag/v0.1 b/tag/v0.1
new file mode 160000
index 0000000..7499bee
--- /dev/null
+++ b/tag/v0.1
@@ -0,0 +1 @@
+Subproject commit 7499bee6709a10da5aaad8949fc9a8cd4bd1d57e
From faaf8dda87888fcc0ccd66e4d138cf772929b4d9 Mon Sep 17 00:00:00 2001
From: Ashi Krishnan
Date: Sat, 23 Apr 2022 05:24:24 -0400
Subject: [PATCH 06/13] Draft of link v1.0
---
.graphs/https/foo/foo.graphql | 149 --
.graphs/https/foo/foo.html | 1562 --------------
.graphs/https/specs.apollo.dev/anatomy.css | 56 -
.../https/specs.apollo.dev/apollo-colors.css | 101 -
.../https/specs.apollo.dev/apollo-light.css | 324 ---
.graphs/https/specs.apollo.dev/async.js | 37 -
.graphs/https/specs.apollo.dev/boot.js | 49 -
.../specs.apollo.dev/federation/v2.0.graphql | 213 --
.../https/specs.apollo.dev/id/v1.0.graphql | 5 -
.graphs/https/specs.apollo.dev/id/v1.0.html | 1555 --------------
.../inaccessible/v0.1.graphql | 197 --
.graphs/https/specs.apollo.dev/index.html | 200 --
.graphs/https/specs.apollo.dev/inject-logo.js | 40 -
.graphs/https/specs.apollo.dev/light.css | 610 ------
.../https/specs.apollo.dev/link/v1.0.graphql | 189 --
.graphs/https/specs.apollo.dev/link/v1.0.html | 1684 ---------------
.graphs/https/specs.apollo.dev/load.js | 53 -
.graphs/https/specs.apollo.dev/main.js | 17 -
.graphs/https/specs.apollo.dev/markdown.js | 87 -
.graphs/https/specs.apollo.dev/mermaid.js | 31 -
.graphs/https/specs.apollo.dev/query.js | 13 -
.graphs/https/specs.apollo.dev/rendering.js | 55 -
.../https/specs.apollo.dev/tag/v0.1.graphql | 147 --
.graphs/https/specs.apollo.dev/tag/v0.1.html | 1597 ---------------
.graphs/https/specs.apollo.dev/toc.js | 65 -
build | 11 +-
.../{v2.0.graphql => v2.0/federation-v2.0.md} | 86 +-
.../v2.0.html => federation/v2.0/index.html | 563 +----
inaccessible/spec.md | 4 -
inaccessible/v0.1/.gitignore | 5 +
inaccessible/v0.1/README.md | 32 +
.../{ => v0.1}/coreDirectives.graphql | 0
.../inaccessible-v0.1.md} | 38 +-
inaccessible/v0.1/inaccessible.spec.graphql | 1 +
.../v0.1.html => inaccessible/v0.1/index.html | 590 +-----
inaccessible/v0.1/netlify.toml | 6 +
inaccessible/v0.1/package.json | 19 +
.../{ => v0.1}/processedSchema.graphql | 0
inaccessible/{ => v0.1}/schema.graphql | 10 +-
link/{v1.0 => }/prefixing.graphql | 0
link/scope.md | 5 +-
link/v1.0/index.html | 1809 +++++++++++++++++
link/v1.0/link-v1.0.graphql | 196 --
link/v1.0/link-v1.0.md | 647 ++++++
link/versioning.md | 4 +-
netlify.toml | 2 +-
package-lock.json | 6 +-
package.json | 4 +-
48 files changed, 2764 insertions(+), 10310 deletions(-)
delete mode 100644 .graphs/https/foo/foo.graphql
delete mode 100644 .graphs/https/foo/foo.html
delete mode 100644 .graphs/https/specs.apollo.dev/anatomy.css
delete mode 100644 .graphs/https/specs.apollo.dev/apollo-colors.css
delete mode 100644 .graphs/https/specs.apollo.dev/apollo-light.css
delete mode 100644 .graphs/https/specs.apollo.dev/async.js
delete mode 100644 .graphs/https/specs.apollo.dev/boot.js
delete mode 100644 .graphs/https/specs.apollo.dev/federation/v2.0.graphql
delete mode 100644 .graphs/https/specs.apollo.dev/id/v1.0.graphql
delete mode 100644 .graphs/https/specs.apollo.dev/id/v1.0.html
delete mode 100644 .graphs/https/specs.apollo.dev/inaccessible/v0.1.graphql
delete mode 100644 .graphs/https/specs.apollo.dev/index.html
delete mode 100644 .graphs/https/specs.apollo.dev/inject-logo.js
delete mode 100644 .graphs/https/specs.apollo.dev/light.css
delete mode 100644 .graphs/https/specs.apollo.dev/link/v1.0.graphql
delete mode 100644 .graphs/https/specs.apollo.dev/link/v1.0.html
delete mode 100644 .graphs/https/specs.apollo.dev/load.js
delete mode 100644 .graphs/https/specs.apollo.dev/main.js
delete mode 100644 .graphs/https/specs.apollo.dev/markdown.js
delete mode 100644 .graphs/https/specs.apollo.dev/mermaid.js
delete mode 100644 .graphs/https/specs.apollo.dev/query.js
delete mode 100644 .graphs/https/specs.apollo.dev/rendering.js
delete mode 100644 .graphs/https/specs.apollo.dev/tag/v0.1.graphql
delete mode 100644 .graphs/https/specs.apollo.dev/tag/v0.1.html
delete mode 100644 .graphs/https/specs.apollo.dev/toc.js
rename federation/{v2.0.graphql => v2.0/federation-v2.0.md} (72%)
rename .graphs/https/specs.apollo.dev/federation/v2.0.html => federation/v2.0/index.html (71%)
delete mode 100644 inaccessible/spec.md
create mode 100644 inaccessible/v0.1/.gitignore
create mode 100644 inaccessible/v0.1/README.md
rename inaccessible/{ => v0.1}/coreDirectives.graphql (100%)
rename inaccessible/{inaccessible-v0.1.graphql => v0.1/inaccessible-v0.1.md} (61%)
create mode 100644 inaccessible/v0.1/inaccessible.spec.graphql
rename .graphs/https/specs.apollo.dev/inaccessible/v0.1.html => inaccessible/v0.1/index.html (69%)
create mode 100644 inaccessible/v0.1/netlify.toml
create mode 100644 inaccessible/v0.1/package.json
rename inaccessible/{ => v0.1}/processedSchema.graphql (100%)
rename inaccessible/{ => v0.1}/schema.graphql (60%)
rename link/{v1.0 => }/prefixing.graphql (100%)
create mode 100644 link/v1.0/index.html
delete mode 100644 link/v1.0/link-v1.0.graphql
create mode 100644 link/v1.0/link-v1.0.md
diff --git a/.graphs/https/foo/foo.graphql b/.graphs/https/foo/foo.graphql
deleted file mode 100644
index ce10c09..0000000
--- a/.graphs/https/foo/foo.graphql
+++ /dev/null
@@ -1,149 +0,0 @@
-extend schema @link(url: "https://specs.apollo.dev/id/v1.0")
-
-extend schema @id__(url: "https://foo/foo")
-
-"""
-# hello
-
-a thing
-
-[x](./link/core-schemas-intro.md)
-"""
-schema {
- query: Query
-}
-
-"""Link a foreign schema by its URL."""
-directive @link(
- """
- The foreign schema's URL.
-
- Link URLs serve two main purposes:
- - Providing a unique identifier for the foreign schema
- - Directing human readers to documentation about the foreign schema
-
- Link URLs SHOULD be [RFC 3986 URLs](https://tools.ietf.org/html/rfc3986). When viewed, the URL SHOULD provide schema documentation in some human-readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
-
- Link URLs MAY contain information about the spec's [name](#sec-Prefixing) and [version](#sec-Versioning):
-
- ```html diagram -- Basic anatomy of a link URL
-
- https://spec.example.com/a/b/c/mySchema/v1.0
-
- ```
-
- The final two segments of the URL's [path](https://tools.ietf.org/html/rfc3986#section-3.3) MAY contain the schema's name and a [version tag](#sec-Versioning), in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid {VersionTag}. To be recognized as a name, the penultimate path component MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name) which does not include the namespace separator ({"__"}).
-
- Empty final path components (that is, trailing slashes) and any URL components which have not been assigned a meaning (such as the fragment and query) MUST be ignored.
-
- ```html diagram -- Ignoring meaningless parts of a URL
-
- https://example.com/exampleSchema/v1.0/?key=val&k2=v2#frag
-
- ```
-
- All of these are valid arguments to `url`, and their interpretations:
-
- | url | normalized url | name | version |
- | ------------------------------------------------- | ------------------------------------------ | ------- | -------- |
- | https://spec.example.com/a/b/mySchema/v1.0/ | https://spec.example.com/a/b/mySchema/v1.0 | mySchema | v1.0 |
- | https://spec.example.com | https://spec.example.com | *(null)* | *(null)* |
- | https://spec.example.com/mySchema/v0.1?q=v#frag | https://spec.example.com/mySchema/v0.1 | mySchema | v0.1 |
- | https://spec.example.com/v1.0 | https://spec.example.com/v1.0 | *(null)* | v1.0 |
- | https://spec.example.com/vX | https://spec.example.com/vX | vX | *(null)* |
-
- If `name` is present, that [namespace prefix](#sec-Prefixing) will automatically be linked to the URL. If a `name` is not present, then elements of the foreign schema must be [`imported`](#@link/import) in order to be referenced.
- """
- url: String!
- """
- Change the [namespace prefix](#sec-Prefixing) assigned to this schema.
-
- The name must be a valid GraphQL identifier, and must not contain the namespace separator ({"__"}).
-
- By default, {@link} will assign a prefix based on the `name` extracted from the URL. If no `name` is present, a prefix will not be assigned.
-
- Providing [`as:`](#@link/as) overrides the default behavior: the foreign schema will be assigned the provided prefix, regardless of the `name` present in the URL (or the lack of one).
-
- ```graphql example -- Using {@link}(url:, as:) to use a feature with a custom name
- schema
- @link(url: "https://specs.apollo.dev/link/v1.0")
- @link(url: "https://spec.example.com/example/v1.0", as: "eg")
- {
- query: Query
- }
-
- type User {
- # Specifying `as: "eg"` transforms @example into @eg
- name: String @eg(data: ITEM)
- }
-
- # Additional specified schema elements must have their prefixes set
- # to the new name.
- enum eg__Data {
- ITEM
- }
-
- # Name transformation must also be applied to definitions pulled in from
- # specifications.
- directive @eg(data: eg__Data) on FIELD_DEFINITION
-
- directive @link(url: String!, as: String) repeatable on SCHEMA
- ```
- """
- as: String
- """Import definitions into the local namespace."""
- import: [Import]
- """
- An optional [purpose](#Purpose) for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
-
- By default, {@link}s SHOULD fail open. This means that {@link}s to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
-
- This behavior is different for {@link}s with a specified purpose:
- - `SECURITY` links convey metadata necessary to compute the API schema and securely resolve fields within it
- - `EXECUTION` links convey metadata necessary to correctly resolve fields within the schema
- """
- for: Purpose
-) repeatable on SCHEMA
-
-"""TK describe an import"""
-scalar Import
-
-"""
-The role of a feature referenced with {@link}.
-
-This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail-open behavior of core schema consumers is undesirable.
-
-Note we'll refer to directives from features which are `for: SECURITY` or `for: EXECUTION` as "`SECURITY` directives" and "`EXECUTION` directives", respectively.
-"""
-enum Purpose {
- """
- `SECURITY` links provide metadata necessary to securely resolve fields. For instance, a hypothetical {auth} feature may provide an {@auth} directive to flag fields which require authorization. If a data core does not support the {auth} feature and serves those fields anyway, these fields will be accessible without authorization, compromising security.
-
- Security-conscious consumers MUST NOT serve a field if:
- - the schema definition has **any** unsupported SECURITY directives,
- - the field's parent type definition has **any** unsupported SECURITY directives,
- - the field's return type definition has **any** unsupported SECURITY directives, or
- - the field definition has **any** unsupported SECURITY directives
-
- Such fields are *not securely resolvable*. Security-conscious consumers MAY serve schemas with fields which are not securely resolvable. However, they MUST remove such fields from the schema before serving it.
-
- Less security-conscious consumers MAY choose to relax these requirements. For instance, servers may provide a development mode in which unknown SECURITY directives are ignored, perhaps with a warning. Such software may also provide a way to explicitly disable some or all SECURITY links during development.
-
- More security-conscious consumers MAY choose to enhance these requirements. For instance, production servers MAY adopt a policy of entirely rejecting any schema which contains ANY unsupported SECURITY links, even if those links are never used to annotate the schema.
- """
- SECURITY
- """
- `EXECUTION` features provide metadata necessary to correctly resolve fields. For instance, a hypothetical {ts} feature may provide a `@ts__resolvers` annotation which references a TypeScript module of field resolvers. A consumer which does not support the {ts} feature will be unable to correctly resolve such fields.
-
- Consumers MUST NOT serve a field if:
- - the schema's definition has **any** unsupported EXECUTION directives,
- - the field's parent type definition has **any** unsupported EXECUTION directives,
- - the field's return type definition has **any** unsupported EXECUTION directives, or
- - the field definition has **any** unsupported EXECUTION directives
-
- Such fields are *unresolvable*. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION features, even if those features are never used in the schema.
- """
- EXECUTION
-}
-
-directive @id__(url: String!) on SCHEMA
\ No newline at end of file
diff --git a/.graphs/https/foo/foo.html b/.graphs/https/foo/foo.html
deleted file mode 100644
index e854520..0000000
--- a/.graphs/https/foo/foo.html
+++ /dev/null
@@ -1,1562 +0,0 @@
-
-
-
-
-foo
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.graphs/https/specs.apollo.dev/anatomy.css b/.graphs/https/specs.apollo.dev/anatomy.css
deleted file mode 100644
index 395f659..0000000
--- a/.graphs/https/specs.apollo.dev/anatomy.css
+++ /dev/null
@@ -1,56 +0,0 @@
-@media (min-width: 720px) {
- code.anatomy {
- font-size: 110%;
- }
-}
-
-code.anatomy {
- white-space: inherit;
-}
-
-code.anatomy span {
- position: relative;
- color: var(--color);
-}
-
-.red {
- --color: var(--red-base);
-}
-
-.blue {
- --color: var(--blue-base);
-}
-
-.pink {
- --color: var(--pink-base);
-}
-
-.yellow {
- --color: var(--yellow-base);
-}
-
-.green {
- --color: var(--green-base);
-}
-
-.grey {
- --color: var(--grey-base);
-}
-
-code.anatomy span > aside {
- position: absolute;
- top: 100%;
- left: 0;
- font-size: 50%;
- width: calc(100% - 8px);
- display: block;
- border-bottom: 1px solid var(--color);
- border-left: 1px solid var(--color);
- padding: 4px;
- height: calc(20% + 10px);
-}
-
-code.anatomy span > span > aside {
- height: calc(20% + 5px);
-}
-
diff --git a/.graphs/https/specs.apollo.dev/apollo-colors.css b/.graphs/https/specs.apollo.dev/apollo-colors.css
deleted file mode 100644
index 2793da8..0000000
--- a/.graphs/https/specs.apollo.dev/apollo-colors.css
+++ /dev/null
@@ -1,101 +0,0 @@
-html {
- /** Brand colors **/
- --pink-darkest: rgb(102, 31, 78);
- --pink-darker: rgb(131, 35, 99);
- --pink-dark: rgb(196, 57, 151);
- --pink-base: rgb(242, 92, 193);
- --pink-light: rgb(255, 163, 224);
- --pink-lighter: rgb(255, 212, 241);
- --pink-lightest: rgb(255, 230, 247);
- --teal-darkest: rgb(31, 102, 100);
- --teal-darker: rgb(29, 123, 120);
- --teal-dark: rgb(38, 162, 157);
- --teal-base: rgb(65, 217, 211);
- --teal-light: rgb(139, 246, 242);
- --teal-lighter: rgb(198, 255, 253);
- --teal-lightest: rgb(230, 255, 254);
- --indigo-darkest: rgb(45, 31, 102);
- --indigo-darker: rgb(49, 28, 135);
- --indigo-dark: rgb(63, 32, 186);
- --indigo-base: rgb(113, 86, 217);
- --indigo-light: rgb(173, 155, 246);
- --indigo-lighter: rgb(217, 207, 255);
- --indigo-lightest: rgb(235, 230, 255);
-
- /** Neutrals **/
- --black-darker: rgb(18, 21, 26);
- --black-dark: rgb(20, 23, 28);
- --black-base: rgb(25, 28, 35);
- --black-light: rgb(34, 38, 46);
- --black-lighter: rgb(47, 53, 63);
- --grey-darker: rgb(66, 72, 85);
- --grey-dark: rgb(90, 98, 112);
- --grey-base: rgb(119, 127, 142);
- --grey-light: rgb(149, 157, 170);
- --grey-lighter: rgb(178, 185, 195);
- --silver-darker: rgb(202, 208, 216);
- --silver-dark: rgb(222, 226, 231);
- --silver-base: rgb(235, 238, 240);
- --silver-light: rgb(244, 246, 248);
- --silver-lighter: rgb(252, 253, 255);
-
- /** Interface Colors **/
- --red-darkest: rgb(102, 31, 31);
- --red-darker: rgb(120, 28, 28);
- --red-dark: rgb(156, 35, 35);
- --red-base: rgb(209, 59, 59);
- --red-light: rgb(241, 134, 134);
- --red-lighter: rgb(255, 195, 195);
- --red-lightest: rgb(255, 230, 230);
- --green-darkest: rgb(20, 94, 51);
- --green-darker: rgb(19, 108, 56);
- --green-dark: rgb(28, 132, 72);
- --green-base: rgb(54, 173, 104);
- --green-light: rgb(126, 217, 164);
- --green-lighter: rgb(190, 244, 213);
- --green-lightest: rgb(230, 255, 240);
- --blue-darkest: rgb(22, 60, 102);
- --blue-darker: rgb(15, 65, 122);
- --blue-dark: rgb(16, 83, 160);
- --blue-base: rgb(32, 117, 214);
- --blue-light: rgb(116, 176, 244);
- --blue-lighter: rgb(187, 219, 255);
- --blue-lightest: rgb(240, 247, 255);
-
- /** Alternate Colors **/
- --orange-darkest: rgb(102, 63, 31);
- --orange-darker: rgb(136, 76, 30);
- --orange-dark: rgb(180, 102, 38);
- --orange-base: rgb(245, 145, 64);
- --orange-light: rgb(255, 193, 143);
- --orange-lighter: rgb(255, 226, 202);
- --orange-lightest: rgb(255, 241, 230);
- --yellow-darkest: rgb(102, 80, 31);
- --yellow-darker: rgb(132, 103, 29);
- --yellow-dark: rgb(180, 143, 37);
- --yellow-base: rgb(244, 208, 63);
- --yellow-light: rgb(255, 232, 142);
- --yellow-lighter: rgb(255, 244, 202);
- --yellow-lightest: rgb(255, 250, 230);
- --purple-darkest: rgb(66, 22, 102);
- --purple-darker: rgb(82, 21, 132);
- --purple-dark: rgb(113, 30, 180);
- --purple-base: rgb(162, 61, 245);
- --purple-light: rgb(205, 143, 255);
- --purple-lighter: rgb(232, 204, 255);
- --purple-lightest: rgb(244, 230, 255);
- --blilet-darkest: rgb(27, 34, 64);
- --blilet-darker: rgb(37, 46, 80);
- --blilet-dark: rgb(60, 74, 133);
- --blilet-base: rgb(81, 104, 194);
- --blilet-light: rgb(122, 146, 240);
- --blilet-lighter: rgb(176, 190, 247);
- --blilet-lightest: rgb(230, 235, 255);
- --midnight-darkest: rgb(6, 15, 47);
- --midnight-darker: rgb(27, 34, 64);
- --midnight-dark: rgb(56, 61, 91);
- --midnight-base: rgb(61, 75, 106);
- --midnight-light: rgb(86, 105, 146);
- --midnight-lighter: rgb(121, 143, 187);
- --midnight-lightest: rgb(180, 195, 219);
-}
\ No newline at end of file
diff --git a/.graphs/https/specs.apollo.dev/apollo-light.css b/.graphs/https/specs.apollo.dev/apollo-light.css
deleted file mode 100644
index 9752f31..0000000
--- a/.graphs/https/specs.apollo.dev/apollo-light.css
+++ /dev/null
@@ -1,324 +0,0 @@
-@import url('https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,400;0,700;1,300;1,700&display=swap');
-
-@import "apollo-colors.css";
-@import "anatomy.css";
-
-:root {
- --body-font-family: Source Sans Pro,sans-serif;
- background: var(--body-background-color);
- color: var(--body-text-color);
- --body-background-color: #FFF;
- --body-text-color: var(--grey-dark);
- --button-background-color: var(--grey-darker);
- --highlight-border-color: var(--yellow-base);
- --highlight-background: none;
-}
-
-
-/*** Header ***/
-header > h1 {
- color: var(--black-lighter);
- text-align: center;
- font-size: 250%;
- margin-bottom: 0;
- margin-top: 1em !important;
-}
-
-header h2 {
- font-size: 150%;
- font-style: italic;
- color: var(--black-lighter);
- margin-top: 0;
- text-align: center;
-}
-
-.spec-data {
- margin: auto;
-}
-
-.spec-data td {
- border: 0;
- color: var(--grey-dark);
-}
-
-.spec-data td:first-of-type {
- color: var(--grey-dark);
- font-style: italic;
- text-align: right;
-}
-
-.spec-data td:first-of-type::after {
- content: ": ";
-}
-
-/*** Headers & Text ***/
-
-h1,h2,h3,h4,h5,h6 {
- color: var(--black-lighter);
-}
-
-h1 {
- margin-top: 2rem;
-}
-
-h2 {
- margin-top: 2rem;
-}
-
-a {
- color: var(--indigo-dark);
-}
-
-.spec-note {
- background: none;
- border-color: var(--yellow-base);
-}
-
-.spec-note > a:first-of-type {
- color: var(--yellow-dark);
-}
-
-/*** Table of Contents ***/
-/***** Inline TOC ******/
-.spec-secid a {
- color: var(--indigo-dark);
-}
-
-/***** Sidebar ******/
-.spec-sidebar {
- background: none;
- backdrop-filter: blur(25px);
- box-shadow: none !important;
- left: 0;
-}
-
-@media (min-width: 1220px) {
- .spec-sidebar {
- backdrop-filter: none;
- }
-}
-
-article {
- display: table;
- margin: auto;
- box-sizing: border-box;
- padding-left: 1em;
- padding-right: 1em;
- margin-left: auto;
- margin-right: auto;
-}
-
-p {
- max-width: calc(100vw - 2em);
-}
-
-figure {
- max-width: calc(100vw - 2em);
-}
-
-@media (min-width: 720px) {
- article {
- margin-left: auto;
- }
-}
-
-@media (min-width: 1220px) {
- article {
- padding-left: calc(50vw - var(--sidebar-width) + 5rem);
- margin-left: auto;
- margin-right: calc(50vw - var(--sidebar-width));
- }
-}
-
-@media (min-width: 1500px) {
- article {
- padding-left: calc(50vw - var(--sidebar-width));
- }
-}
-
-body {
- padding: 0 !important;
- margin: 0 !important;
-}
-
-.spec-sidebar .viewing > a::after {
- color: var(--yellow-base)
-}
-
-/*** Figures ***/
-figure {
- border-color: transparent;
-}
-
-.spec-example {
- border-color: var(--indigo-lighter);
-}
-
-.spec-counter-example {
- border-color: var(--red-light);
-}
-
-.spec-counter-example > figcaption > a {
- color: var(--red-light);
-}
-
-.spec-example > figcaption > a {
- color: var(--indigo-light);
-}
-
-.spec-example > pre {
- overflow-y: auto;
- background: none;
-}
-
-.spec-example-num {
- opacity: 1;
-}
-
-/*** Code ***/
-var {
- border: thin solid transparent;
-}
-
-var:hover {
- background: none;
- border-color: var(--highlight-border-color);
-}
-
-code {
- padding: .1em .3em;
- border-radius: .3em;
- font-size: .9em;
- color: var(--pink-base);
- background: var(--silver-base);
-}
-
-.token.operator {
- background: none;
-}
-
-.spec-definition > pre {
- padding: 1rem;
-}
-
-.spec-definition > pre > code {
- font-family: var(--body-font-family);
- font-style: italic;
- font-size: 130%;
- font-weight: bold;
- line-height: 120%;
-}
-
-@media (min-width: 720px) {
- .spec-definition > pre {
- margin-left: 3em;
- transform: scaleX(1.02);
- }
-}
-
-h2.spec-definition-head, h3.spec-definition-head {
- font-size: inherit;
- color: var(--black-darker);
-}
-
-
-/*** Selections ***/
-::selection {
- background-color: var(--yellow-light);
-}
-
-.selection-link,
-.outdated-selection-link {
- box-shadow: 2px 2px 5px var(--body-background-color);
- color: var(--indigo-dark);
-}
-
-.selection-link {
- background-color: var(--indigo-lightest);
- border: thin solid var(--indigo-dark);
-}
-
-.selection-link:hover {
- background-color: var(--indigo-lightest);
- color: var(--indigo-dark);
-}
-
-.outdated-selection-link {
- background-color: var(--midnight-base);
- border: thin solid var(--red-dark);
-}
-
-.outdated-selection-link:hover {
- background-color: var(--red-base);
- color: var(--midnight-dark);
-}
-
-
-/*** Sidebar ***/
-.spec-sidebar-toggle + label[for="spec-sidebar-toggle"] > .spec-sidebar-button {
- color: var(--grey-lighter);
- z-index: 10001;
- left: 0;
- right: auto;
- top: auto;
- bottom: 0;
- border-radius: 50%;
- backdrop-filter: blur(10px);
-}
-
-/*** RFC 2119 Requirements ***/
-.spec-requirement {
- font-weight: bold;
- color: var(--requirement-color);
- --requirement-color: var(--green-light);
- border-radius: 0.2rem;
- transition: color 115ms, background 115ms;
- padding: 0 0.1rem 0.2rem 0.1rem;
-}
-
-.spec-requirement:hover {
- background: var(--requirement-color);
- color: var(--body-background-color);
- text-decoration: none;
-}
-
-.spec-requirement.required {
- --requirement-color: var(--green-base);
-}
-
-.spec-requirement.not.required {
- --requirement-color: var(--red-base);
-}
-
-.spec-requirement.recommended {
- --requirement-color: var(--teal-dark);
-}
-
-.spec-requirement.not.recommended {
- --requirement-color: var(--orange-base);
-}
-
-.spec-requirement.optional {
- --requirement-color: var(--indigo-base);
-}
-
-.spec-toc a:hover {
- opacity: 0.8;
-}
-
-.spec-toc a .spec-secid {
- color: var(--indigo-dark);
-}
-
-.spec-toc .title {
- margin-top: 2em;
-}
-
-.apollo-specs-logo a:hover {
- text-decoration: none;
-}
-
-.spec-sidebar {
- border-right: 1px solid var(--silver-dark);
- overflow-y: auto;
-}
diff --git a/.graphs/https/specs.apollo.dev/async.js b/.graphs/https/specs.apollo.dev/async.js
deleted file mode 100644
index 8712ca1..0000000
--- a/.graphs/https/specs.apollo.dev/async.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * Convert a fallible Promise to an infallible Promise<{ ok?: T, err?: Error }>.
- *
- * @param {Promise} promise
- * @return {Promise<{ ok?: T, err: Error }>}
- */
-export function result(promise) {
- return promise.then(ok => ({ ok }), err => ({ err }))
-}
-
-/**
- * Await a DOM event, then detach the listener.
- *
- * @param {string} event name
- * @param {HTMLElement} listen on
- * @return {Promise}
- */
-export function event(event='load', element=window) {
- return new Promise(resolve => {
- element.addEventListener(event, fire)
-
- function fire(evt) {
- resolve(evt)
- element.removeEventListener(event, fire)
- }
- })
-}
-
-/**
- * Approximate timeout.
- *
- * @param {number} ms
- * @return {Promise}
- */
-export function sleep(ms=1000) {
- return new Promise(resolve => setTimeout(resolve, ms))
-}
diff --git a/.graphs/https/specs.apollo.dev/boot.js b/.graphs/https/specs.apollo.dev/boot.js
deleted file mode 100644
index 1618962..0000000
--- a/.graphs/https/specs.apollo.dev/boot.js
+++ /dev/null
@@ -1,49 +0,0 @@
-window.process = window.process || {env: {}}
-
-document.head.appendChild(Object.assign(
- document.createElement('style'), {
- textContent: `
- body {
- background: #FFF;
- color: rgb(90, 98, 112);
- font-size: 18px;
- }
-
- main[markdown] {
- white-space: pre-line;
- font-family: monospace;
- max-width: 920px;
- margin: auto;
- }
-
- #view {
- display: flex;
- justify-content: center;
- flex-flow: row nowrap;
- }
- `
- })
-)
-
-document.head.appendChild(Object.assign(
- document.createElement('style'), {
- id: '__curtain__',
- textContent: `
- body {
- opacity: 0;
- transition: opacity 1s;
- }
- `
- }
-))
-
-document.head.appendChild(Object.assign(
- document.createElement('script'), {
- type: 'module',
- async: true,
- defer: true,
- src: '/main.js',
- }
-))
-
-setTimeout(() => __curtain__ && __curtain__.remove(), 200)
\ No newline at end of file
diff --git a/.graphs/https/specs.apollo.dev/federation/v2.0.graphql b/.graphs/https/specs.apollo.dev/federation/v2.0.graphql
deleted file mode 100644
index a506049..0000000
--- a/.graphs/https/specs.apollo.dev/federation/v2.0.graphql
+++ /dev/null
@@ -1,213 +0,0 @@
-extend schema @link(url: "https://specs.apollo.dev/id/v1.0")
-
-extend schema @id__(url: "https://specs.apollo.dev/federation/v2.0")
-
-"""
-The `@key` directive is used to indicate a combination of fields that can be used to uniquely identify and fetch an object or interface.
-
-```graphql example -- using {@key}
-type Product @key(fields: "upc") {
- upc: UPC!
- name: String
-}
-```
-
-Multiple keys can be defined on a single object type:
-
-```graphql example -- defining multiple {@key}s
-type Product @key(fields: "upc") @key(fields: "sku") {
- upc: UPC!
- sku: SKU!
- name: String
-}
-```
-
-Note: Repeated directives (in this case, `@key`, used multiple times) require support by the underlying GraphQL implementation.
-"""
-directive @key(fields: FieldSet!) repeatable on OBJECT | INTERFACE
-
-"""
-The `@provides` directive is used to annotate the expected returned fieldset from a field on a base type that is guaranteed to be selectable by the gateway. Given the following example:
-
-```graphql example -- using {@provides}
-type Review @key(fields: "id") {
- product: Product @provides(fields: "name")
-}
-
-extend type Product @key(fields: "upc") {
- upc: String @external
- name: String @external
-}
-```
-
-When fetching `Review.product` from the Reviews service, it is possible to request the `name` with the expectation that the Reviews service can provide it when going from review to product. `Product.name` is an external field on an external type which is why the local type extension of `Product` and annotation of `name` is required.
-"""
-directive @provides(fields: FieldSet!) on FIELD_DEFINITION
-
-"""
-The `@requires` directive is used to annotate the required input fieldset from a base type for a resolver. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. For example:
-
-```graphql example -- using {@requires}
-# extended from the Users service
-extend type User @key(fields: "id") {
- id: ID! @external
- email: String @external
- reviews: [Review] @requires(fields: "email")
-}
-```
-
-In this case, the Reviews service adds new capabilities to the `User` type by providing a list of `reviews` related to a user. In order to fetch these reviews, the Reviews service needs to know the `email` of the `User` from the Users service in order to look up the reviews. This means the `reviews` field / resolver *requires* the `email` field from the base `User` type.
-"""
-directive @requires(fields: FieldSet!) on FIELD_DEFINITION
-
-"""
-The `@external` directive is used to mark a field as owned by another service. This allows service A to use fields from service B while also knowing at runtime the types of that field. For example:
-
-```graphql example -- using {@external}
-# extended from the Users service
-extend type User @key(fields: "email") {
- email: String @external
- reviews: [Review]
-}
-```
-
-This type extension in the Reviews service extends the `User` type from the Users service. It extends it for the purpose of adding a new field called `reviews`, which returns a list of `Review`s.
-"""
-directive @external on FIELD_DEFINITION
-
-scalar FieldSet
-
-"""Link a foreign schema by its URL."""
-directive @link(
- """
- The foreign schema's URL.
-
- Link URLs serve two main purposes:
- - Providing a unique identifier for the foreign schema
- - Directing human readers to documentation about the foreign schema
-
- Link URLs SHOULD be [RFC 3986 URLs](https://tools.ietf.org/html/rfc3986). When viewed, the URL SHOULD provide schema documentation in some human-readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
-
- Link URLs MAY contain information about the spec's [name](#sec-Prefixing) and [version](#sec-Versioning):
-
- ```html diagram -- Basic anatomy of a link URL
-
- https://spec.example.com/a/b/c/mySchema/v1.0
-
- ```
-
- The final two segments of the URL's [path](https://tools.ietf.org/html/rfc3986#section-3.3) MAY contain the schema's name and a [version tag](#sec-Versioning), in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid {VersionTag}. To be recognized as a name, the penultimate path component MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name) which does not include the namespace separator ({"__"}).
-
- Empty final path components (that is, trailing slashes) and any URL components which have not been assigned a meaning (such as the fragment and query) MUST be ignored.
-
- ```html diagram -- Ignoring meaningless parts of a URL
-
- https://example.com/exampleSchema/v1.0/?key=val&k2=v2#frag
-
- ```
-
- All of these are valid arguments to `url`, and their interpretations:
-
- | url | normalized url | name | version |
- | ------------------------------------------------- | ------------------------------------------ | ------- | -------- |
- | https://spec.example.com/a/b/mySchema/v1.0/ | https://spec.example.com/a/b/mySchema/v1.0 | mySchema | v1.0 |
- | https://spec.example.com | https://spec.example.com | *(null)* | *(null)* |
- | https://spec.example.com/mySchema/v0.1?q=v#frag | https://spec.example.com/mySchema/v0.1 | mySchema | v0.1 |
- | https://spec.example.com/v1.0 | https://spec.example.com/v1.0 | *(null)* | v1.0 |
- | https://spec.example.com/vX | https://spec.example.com/vX | vX | *(null)* |
-
- If `name` is present, that [namespace prefix](#sec-Prefixing) will automatically be linked to the URL. If a `name` is not present, then elements of the foreign schema must be [`imported`](#@link/import) in order to be referenced.
- """
- url: String!
- """
- Change the [namespace prefix](#sec-Prefixing) assigned to this schema.
-
- The name must be a valid GraphQL identifier, and must not contain the namespace separator ({"__"}).
-
- By default, {@link} will assign a prefix based on the `name` extracted from the URL. If no `name` is present, a prefix will not be assigned.
-
- Providing [`as:`](#@link/as) overrides the default behavior: the foreign schema will be assigned the provided prefix, regardless of the `name` present in the URL (or the lack of one).
-
- ```graphql example -- Using {@link}(url:, as:) to use a feature with a custom name
- schema
- @link(url: "https://specs.apollo.dev/link/v1.0")
- @link(url: "https://spec.example.com/example/v1.0", as: "eg")
- {
- query: Query
- }
-
- type User {
- # Specifying `as: "eg"` transforms @example into @eg
- name: String @eg(data: ITEM)
- }
-
- # Additional specified schema elements must have their prefixes set
- # to the new name.
- enum eg__Data {
- ITEM
- }
-
- # Name transformation must also be applied to definitions pulled in from
- # specifications.
- directive @eg(data: eg__Data) on FIELD_DEFINITION
-
- directive @link(url: String!, as: String) repeatable on SCHEMA
- ```
- """
- as: String
- """Import definitions into the local namespace."""
- import: [Import]
- """
- An optional [purpose](#Purpose) for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
-
- By default, {@link}s SHOULD fail open. This means that {@link}s to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
-
- This behavior is different for {@link}s with a specified purpose:
- - `SECURITY` links convey metadata necessary to compute the API schema and securely resolve fields within it
- - `EXECUTION` links convey metadata necessary to correctly resolve fields within the schema
- """
- for: Purpose
-) repeatable on SCHEMA
-
-"""TK describe an import"""
-scalar Import
-
-"""
-The role of a feature referenced with {@link}.
-
-This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail-open behavior of core schema consumers is undesirable.
-
-Note we'll refer to directives from features which are `for: SECURITY` or `for: EXECUTION` as "`SECURITY` directives" and "`EXECUTION` directives", respectively.
-"""
-enum Purpose {
- """
- `SECURITY` links provide metadata necessary to securely resolve fields. For instance, a hypothetical {auth} feature may provide an {@auth} directive to flag fields which require authorization. If a data core does not support the {auth} feature and serves those fields anyway, these fields will be accessible without authorization, compromising security.
-
- Security-conscious consumers MUST NOT serve a field if:
- - the schema definition has **any** unsupported SECURITY directives,
- - the field's parent type definition has **any** unsupported SECURITY directives,
- - the field's return type definition has **any** unsupported SECURITY directives, or
- - the field definition has **any** unsupported SECURITY directives
-
- Such fields are *not securely resolvable*. Security-conscious consumers MAY serve schemas with fields which are not securely resolvable. However, they MUST remove such fields from the schema before serving it.
-
- Less security-conscious consumers MAY choose to relax these requirements. For instance, servers may provide a development mode in which unknown SECURITY directives are ignored, perhaps with a warning. Such software may also provide a way to explicitly disable some or all SECURITY links during development.
-
- More security-conscious consumers MAY choose to enhance these requirements. For instance, production servers MAY adopt a policy of entirely rejecting any schema which contains ANY unsupported SECURITY links, even if those links are never used to annotate the schema.
- """
- SECURITY
- """
- `EXECUTION` features provide metadata necessary to correctly resolve fields. For instance, a hypothetical {ts} feature may provide a `@ts__resolvers` annotation which references a TypeScript module of field resolvers. A consumer which does not support the {ts} feature will be unable to correctly resolve such fields.
-
- Consumers MUST NOT serve a field if:
- - the schema's definition has **any** unsupported EXECUTION directives,
- - the field's parent type definition has **any** unsupported EXECUTION directives,
- - the field's return type definition has **any** unsupported EXECUTION directives, or
- - the field definition has **any** unsupported EXECUTION directives
-
- Such fields are *unresolvable*. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION features, even if those features are never used in the schema.
- """
- EXECUTION
-}
-
-directive @id__(url: String!) on SCHEMA
\ No newline at end of file
diff --git a/.graphs/https/specs.apollo.dev/id/v1.0.graphql b/.graphs/https/specs.apollo.dev/id/v1.0.graphql
deleted file mode 100644
index 261d694..0000000
--- a/.graphs/https/specs.apollo.dev/id/v1.0.graphql
+++ /dev/null
@@ -1,5 +0,0 @@
-extend schema @id(url: "https://specs.apollo.dev/id/v1.0")
-
-extend schema @id(url: "https://specs.apollo.dev/id/v1.0")
-
-directive @id(url: String!) on SCHEMA
\ No newline at end of file
diff --git a/.graphs/https/specs.apollo.dev/id/v1.0.html b/.graphs/https/specs.apollo.dev/id/v1.0.html
deleted file mode 100644
index 6acdda9..0000000
--- a/.graphs/https/specs.apollo.dev/id/v1.0.html
+++ /dev/null
@@ -1,1555 +0,0 @@
-
-
-
-
-id v1.0
-
-
-
-
-
-
-
-
-
-
-
-
-```
-
-This document defines the `@inaccessible` directive, which marks schema elements which should not be accessible in the public-facing schema. This version of the spec supports Object, Interface, and Union types.
-
-# How to read this document
-
-This document uses [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt) guidance regarding normative terms: MUST / MUST NOT / REQUIRED / SHALL / SHALL NOT / SHOULD / SHOULD NOT / RECOMMENDED / MAY / OPTIONAL.
-
-# Definitions
-
-## Processor
-
-This specification makes references to **Processors**. Processors are described in the [Actors section of the `@core` spec](https://specs.apollo.dev/core/v0.2/#sec-Actors) as an actor which can perform transformations on a core schema. In the case of `@inaccessible`, the Processor will be expected to remove various parts of a core schema.
-
-# Example: Sensitive User Data
-
-*This section is non-normative.*
-
-We'll refer to this example of a core schema with sensitive user data throughout the document:
-
-:::[example](./schema.graphql) -- Core schema example
-
-The schema above contains both a field (`User.id`) and type (`BankAccount`) that are marked as `@inaccessible`. These symbols should be omitted from the processed schema anywhere they would appear. When the processed schema below is generated from this core schema, notice what has been removed:
-* `User.id` field
-* `BankAccount` type
-* `User.bankAccount` field
-* `Account` union's `BankAccount` type
-
-:::[example](./processedSchema.graphql) -- Core schema after processing
-
-## Modifications to the API
-
-Within the API,
-
-- Field Definitions marked with `@inaccessible` MUST be excluded
-- Object types marked with `@inaccessible` MUST be excluded
-- Object types marked with `@inaccessible` MUST be excluded from membership in any unions
-- Interfaces marked with `@inaccessible` MUST be excluded
-- Interfaces marked with `@inaccessible` MUST be excluded from the `extends` clause of all other interfaces
-- Union types marked with `@inaccessible` MUST be excluded
-
-Note applying this process may result in an invalid schema. For example, fields which return `@inaccessible` types which are not themselves marked `@inaccessible` will now return an invalid type which is not present in the schema. This is intentional. `@inaccessible` does NOT cascade. If applying `@inaccessible` results in an invalid schema, the serving process SHOULD apply standard polices to determine whether or how to serve it. Generally, invalid schemas SHOULD NOT be served, though some server configurations—particularly those used for development—MAY OPTIONALLY elect to serve such schemas in a degraded mode. The semantics of such a mode are not within the scope of this spec.
-"""
-schema {
- query: Query
-}
-
-directive @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION
-
-"""Link a foreign schema by its URL."""
-directive @link(
- """
- The foreign schema's URL.
-
- Link URLs serve two main purposes:
- - Providing a unique identifier for the foreign schema
- - Directing human readers to documentation about the foreign schema
-
- Link URLs SHOULD be [RFC 3986 URLs](https://tools.ietf.org/html/rfc3986). When viewed, the URL SHOULD provide schema documentation in some human-readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
-
- Link URLs MAY contain information about the spec's [name](#sec-Prefixing) and [version](#sec-Versioning):
-
- ```html diagram -- Basic anatomy of a link URL
-
- https://spec.example.com/a/b/c/mySchema/v1.0
-
- ```
-
- The final two segments of the URL's [path](https://tools.ietf.org/html/rfc3986#section-3.3) MAY contain the schema's name and a [version tag](#sec-Versioning), in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid {VersionTag}. To be recognized as a name, the penultimate path component MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name) which does not include the namespace separator ({"__"}).
-
- Empty final path components (that is, trailing slashes) and any URL components which have not been assigned a meaning (such as the fragment and query) MUST be ignored.
-
- ```html diagram -- Ignoring meaningless parts of a URL
-
- https://example.com/exampleSchema/v1.0/?key=val&k2=v2#frag
-
- ```
-
- All of these are valid arguments to `url`, and their interpretations:
-
- | url | normalized url | name | version |
- | ------------------------------------------------- | ------------------------------------------ | ------- | -------- |
- | https://spec.example.com/a/b/mySchema/v1.0/ | https://spec.example.com/a/b/mySchema/v1.0 | mySchema | v1.0 |
- | https://spec.example.com | https://spec.example.com | *(null)* | *(null)* |
- | https://spec.example.com/mySchema/v0.1?q=v#frag | https://spec.example.com/mySchema/v0.1 | mySchema | v0.1 |
- | https://spec.example.com/v1.0 | https://spec.example.com/v1.0 | *(null)* | v1.0 |
- | https://spec.example.com/vX | https://spec.example.com/vX | vX | *(null)* |
-
- If `name` is present, that [namespace prefix](#sec-Prefixing) will automatically be linked to the URL. If a `name` is not present, then elements of the foreign schema must be [`imported`](#@link/import) in order to be referenced.
- """
- url: String!
- """
- Change the [namespace prefix](#sec-Prefixing) assigned to this schema.
-
- The name must be a valid GraphQL identifier, and must not contain the namespace separator ({"__"}).
-
- By default, {@link} will assign a prefix based on the `name` extracted from the URL. If no `name` is present, a prefix will not be assigned.
-
- Providing [`as:`](#@link/as) overrides the default behavior: the foreign schema will be assigned the provided prefix, regardless of the `name` present in the URL (or the lack of one).
-
- ```graphql example -- Using {@link}(url:, as:) to use a feature with a custom name
- schema
- @link(url: "https://specs.apollo.dev/link/v1.0")
- @link(url: "https://spec.example.com/example/v1.0", as: "eg")
- {
- query: Query
- }
-
- type User {
- # Specifying `as: "eg"` transforms @example into @eg
- name: String @eg(data: ITEM)
- }
-
- # Additional specified schema elements must have their prefixes set
- # to the new name.
- enum eg__Data {
- ITEM
- }
-
- # Name transformation must also be applied to definitions pulled in from
- # specifications.
- directive @eg(data: eg__Data) on FIELD_DEFINITION
-
- directive @link(url: String!, as: String) repeatable on SCHEMA
- ```
- """
- as: String
- """Import definitions into the local namespace."""
- import: [Import]
- """
- An optional [purpose](#Purpose) for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
-
- By default, {@link}s SHOULD fail open. This means that {@link}s to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
-
- This behavior is different for {@link}s with a specified purpose:
- - `SECURITY` links convey metadata necessary to compute the API schema and securely resolve fields within it
- - `EXECUTION` links convey metadata necessary to correctly resolve fields within the schema
- """
- for: Purpose
-) repeatable on SCHEMA
-
-"""TK describe an import"""
-scalar Import
-
-"""
-The role of a feature referenced with {@link}.
-
-This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail-open behavior of core schema consumers is undesirable.
-
-Note we'll refer to directives from features which are `for: SECURITY` or `for: EXECUTION` as "`SECURITY` directives" and "`EXECUTION` directives", respectively.
-"""
-enum Purpose {
- """
- `SECURITY` links provide metadata necessary to securely resolve fields. For instance, a hypothetical {auth} feature may provide an {@auth} directive to flag fields which require authorization. If a data core does not support the {auth} feature and serves those fields anyway, these fields will be accessible without authorization, compromising security.
-
- Security-conscious consumers MUST NOT serve a field if:
- - the schema definition has **any** unsupported SECURITY directives,
- - the field's parent type definition has **any** unsupported SECURITY directives,
- - the field's return type definition has **any** unsupported SECURITY directives, or
- - the field definition has **any** unsupported SECURITY directives
-
- Such fields are *not securely resolvable*. Security-conscious consumers MAY serve schemas with fields which are not securely resolvable. However, they MUST remove such fields from the schema before serving it.
-
- Less security-conscious consumers MAY choose to relax these requirements. For instance, servers may provide a development mode in which unknown SECURITY directives are ignored, perhaps with a warning. Such software may also provide a way to explicitly disable some or all SECURITY links during development.
-
- More security-conscious consumers MAY choose to enhance these requirements. For instance, production servers MAY adopt a policy of entirely rejecting any schema which contains ANY unsupported SECURITY links, even if those links are never used to annotate the schema.
- """
- SECURITY
- """
- `EXECUTION` features provide metadata necessary to correctly resolve fields. For instance, a hypothetical {ts} feature may provide a `@ts__resolvers` annotation which references a TypeScript module of field resolvers. A consumer which does not support the {ts} feature will be unable to correctly resolve such fields.
-
- Consumers MUST NOT serve a field if:
- - the schema's definition has **any** unsupported EXECUTION directives,
- - the field's parent type definition has **any** unsupported EXECUTION directives,
- - the field's return type definition has **any** unsupported EXECUTION directives, or
- - the field definition has **any** unsupported EXECUTION directives
-
- Such fields are *unresolvable*. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION features, even if those features are never used in the schema.
- """
- EXECUTION
-}
-
-directive @id__(url: String!) on SCHEMA
\ No newline at end of file
diff --git a/.graphs/https/specs.apollo.dev/index.html b/.graphs/https/specs.apollo.dev/index.html
deleted file mode 100644
index 01dc40f..0000000
--- a/.graphs/https/specs.apollo.dev/index.html
+++ /dev/null
@@ -1,200 +0,0 @@
-
-
-
-Technical Specifications
-
-
-
-
- The subset of a [core schema](#def-core-schema) which is used to validate client operations and may be served to clients via introspection. *Contrast: [machinery](#def-machinery)*
-
-
-
core schema, n.
-
- A GraphQL schema document which follows the [core schema specification](/core/). Core schemas provide specified metadata to processors and data cores by referencing features.
-
-
-
machinery, n.
-
- The subset of a [core schema](#def-core-schema) which should *not* be served to clients. Machinery typically consists of specified metadata and definitions to support that metadata which assist processing but which which are not relevant to clients.
-
-
-
join, v.
-
-
-
the act of combining multiple GraphQL schemas into a single schema
-
- "Our API joins our auth, users, and movies graphs."
-
-
-
the act of combining multiple GraphQL *definitions* into a single definition.
-
- "Our API's User type joins fields from the users and movies graphs."
-
-
-
-
-
subgraph, n.
-
- A graph which is [joined](#def-join) into a [supergraph](#def-supergraph).
-
- *aka: federated service graph*
-
-
-
supergraph, n.
-
- A graph which [joins](#def-join) multiple [subgraphs](#def-subgraph) together.
-
-
-
-```
-
-[intro to core schemas](core-schemas-intro.md)
-
-# Scoping
-
-[scope](../scope.md)
-
-# Versioning
-
-[Versioning](../versioning.md)
-
-# Processing Schemas
-
-```mermaid diagram
-graph LR
- schema(["📄 Input Schema"]):::file-->proc("🤖 Processor")
- proc-->output(["📄 Output Schema"]):::file
- classDef file fill:none,color:#22262E;
- style proc fill:none,stroke:fuchsia,color:fuchsia;
-```
-
-A common use case is that of a processor which consumes a valid input schema and generates an output schema.
-
-The general guidance for processor behavior is: don't react to what you don't understand.
-
-Specifically, processors:
- - SHOULD pass through {@link} directives which reference unknown feature URLs
- - SHOULD pass through prefixed directives, types, and other schema elements
- - SHOULD pass through directives which are not [associated with](#AssignFeatures) a {@link} feature
-
-Processors MAY accept configuration which overrides these default behaviors.
-
-Additionally, processors which prepare the schema for final public consumption MAY choose to eliminate all unknown directives and prefixed types in order to hide schema implementation details within the published schema. This will impair the operation of tooling which relies on these directives—such tools will not be able to run on the output schema, so the benefits and costs of this kind of information hiding should be weighed carefully on a case-by-case basis.
-
-# Algorithms
-
-[Algorithms](algorithms.md)
-"""
-schema {
- query: Query
-}
-
-"""Link a foreign schema by its URL."""
-directive @link(
- """
- The foreign schema's URL.
-
- Link URLs serve two main purposes:
- - Providing a unique identifier for the foreign schema
- - Directing human readers to documentation about the foreign schema
-
- Link URLs SHOULD be [RFC 3986 URLs](https://tools.ietf.org/html/rfc3986). When viewed, the URL SHOULD provide schema documentation in some human-readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
-
- Link URLs MAY contain information about the spec's [name](#sec-Prefixing) and [version](#sec-Versioning):
-
- ```html diagram -- Basic anatomy of a link URL
-
- https://spec.example.com/a/b/c/mySchema/v1.0
-
- ```
-
- The final two segments of the URL's [path](https://tools.ietf.org/html/rfc3986#section-3.3) MAY contain the schema's name and a [version tag](#sec-Versioning), in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid {VersionTag}. To be recognized as a name, the penultimate path component MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name) which does not include the namespace separator ({"__"}).
-
- Empty final path components (that is, trailing slashes) and any URL components which have not been assigned a meaning (such as the fragment and query) MUST be ignored.
-
- ```html diagram -- Ignoring meaningless parts of a URL
-
- https://example.com/exampleSchema/v1.0/?key=val&k2=v2#frag
-
- ```
-
- All of these are valid arguments to `url`, and their interpretations:
-
- | url | normalized url | name | version |
- | ------------------------------------------------- | ------------------------------------------ | ------- | -------- |
- | https://spec.example.com/a/b/mySchema/v1.0/ | https://spec.example.com/a/b/mySchema/v1.0 | mySchema | v1.0 |
- | https://spec.example.com | https://spec.example.com | *(null)* | *(null)* |
- | https://spec.example.com/mySchema/v0.1?q=v#frag | https://spec.example.com/mySchema/v0.1 | mySchema | v0.1 |
- | https://spec.example.com/v1.0 | https://spec.example.com/v1.0 | *(null)* | v1.0 |
- | https://spec.example.com/vX | https://spec.example.com/vX | vX | *(null)* |
-
- If `name` is present, that [namespace prefix](#sec-Prefixing) will automatically be linked to the URL. If a `name` is not present, then elements of the foreign schema must be [`imported`](#@link/import) in order to be referenced.
- """
- url: String!
- """
- Change the [namespace prefix](#sec-Prefixing) assigned to this schema.
-
- The name must be a valid GraphQL identifier, and must not contain the namespace separator ({"__"}).
-
- By default, {@link} will assign a prefix based on the `name` extracted from the URL. If no `name` is present, a prefix will not be assigned.
-
- Providing [`as:`](#@link/as) overrides the default behavior: the foreign schema will be assigned the provided prefix, regardless of the `name` present in the URL (or the lack of one).
-
- ```graphql example -- Using {@link}(url:, as:) to use a feature with a custom name
- schema
- @link(url: "https://specs.apollo.dev/link/v1.0")
- @link(url: "https://spec.example.com/example/v1.0", as: "eg")
- {
- query: Query
- }
-
- type User {
- # Specifying `as: "eg"` transforms @example into @eg
- name: String @eg(data: ITEM)
- }
-
- # Additional specified schema elements must have their prefixes set
- # to the new name.
- enum eg__Data {
- ITEM
- }
-
- # Name transformation must also be applied to definitions pulled in from
- # specifications.
- directive @eg(data: eg__Data) on FIELD_DEFINITION
-
- directive @link(url: String!, as: String) repeatable on SCHEMA
- ```
- """
- as: String
- """Import definitions into the local namespace."""
- import: [Import]
- """
- An optional [purpose](#Purpose) for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
-
- By default, {@link}s SHOULD fail open. This means that {@link}s to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
-
- This behavior is different for {@link}s with a specified purpose:
- - `SECURITY` links convey metadata necessary to compute the API schema and securely resolve fields within it
- - `EXECUTION` links convey metadata necessary to correctly resolve fields within the schema
- """
- for: Purpose
-) repeatable on SCHEMA
-
-"""TK describe an import"""
-scalar Import
-
-"""
-The role of a feature referenced with {@link}.
-
-This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail-open behavior of core schema consumers is undesirable.
-
-Note we'll refer to directives from features which are `for: SECURITY` or `for: EXECUTION` as "`SECURITY` directives" and "`EXECUTION` directives", respectively.
-"""
-enum Purpose {
- """
- `SECURITY` links provide metadata necessary to securely resolve fields. For instance, a hypothetical {auth} feature may provide an {@auth} directive to flag fields which require authorization. If a data core does not support the {auth} feature and serves those fields anyway, these fields will be accessible without authorization, compromising security.
-
- Security-conscious consumers MUST NOT serve a field if:
- - the schema definition has **any** unsupported SECURITY directives,
- - the field's parent type definition has **any** unsupported SECURITY directives,
- - the field's return type definition has **any** unsupported SECURITY directives, or
- - the field definition has **any** unsupported SECURITY directives
-
- Such fields are *not securely resolvable*. Security-conscious consumers MAY serve schemas with fields which are not securely resolvable. However, they MUST remove such fields from the schema before serving it.
-
- Less security-conscious consumers MAY choose to relax these requirements. For instance, servers may provide a development mode in which unknown SECURITY directives are ignored, perhaps with a warning. Such software may also provide a way to explicitly disable some or all SECURITY links during development.
-
- More security-conscious consumers MAY choose to enhance these requirements. For instance, production servers MAY adopt a policy of entirely rejecting any schema which contains ANY unsupported SECURITY links, even if those links are never used to annotate the schema.
- """
- SECURITY
- """
- `EXECUTION` features provide metadata necessary to correctly resolve fields. For instance, a hypothetical {ts} feature may provide a `@ts__resolvers` annotation which references a TypeScript module of field resolvers. A consumer which does not support the {ts} feature will be unable to correctly resolve such fields.
-
- Consumers MUST NOT serve a field if:
- - the schema's definition has **any** unsupported EXECUTION directives,
- - the field's parent type definition has **any** unsupported EXECUTION directives,
- - the field's return type definition has **any** unsupported EXECUTION directives, or
- - the field definition has **any** unsupported EXECUTION directives
-
- Such fields are *unresolvable*. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION features, even if those features are never used in the schema.
- """
- EXECUTION
-}
-
-directive @id__(url: String!) on SCHEMA
\ No newline at end of file
diff --git a/.graphs/https/specs.apollo.dev/link/v1.0.html b/.graphs/https/specs.apollo.dev/link/v1.0.html
deleted file mode 100644
index 4dcf9f7..0000000
--- a/.graphs/https/specs.apollo.dev/link/v1.0.html
+++ /dev/null
@@ -1,1684 +0,0 @@
-
-
-
-
-link v1.0
-
-
-
-
-
-
-
-
-
-
Providing a unique identifier for the foreign schema
-
Directing human readers to documentation about the foreign schema
-
-
Link URLs SHOULD be RFC 3986 URLs. When viewed, the URL SHOULD provide schema documentation in some human‐readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
-
Link URLs MAY contain information about the spec’s name and version:
-
The final two segments of the URL’s pathMAY contain the schema’s name and a version tag, in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid VersionTag. To be recognized as a name, the penultimate path component MUST be a valid GraphQL name which does not include the namespace separator ("__").
-
Empty final path components (that is, trailing slashes) and any URL components which have not been assigned a meaning (such as the fragment and query) MUST be ignored.
-
All of these are valid arguments to url, and their interpretations:
-
-
-
url
-
normalized url
-
name
-
version
-
-
-
-
https://spec.example.com/a/b/mySchema/v1.0/
https://spec.example.com/a/b/mySchema/v1.0
mySchema
v1.0
-
-
https://spec.example.com
https://spec.example.com
(null)
(null)
-
-
https://spec.example.com/mySchema/v0.1?q=v#frag
https://spec.example.com/mySchema/v0.1
mySchema
v0.1
-
-
https://spec.example.com/v1.0
https://spec.example.com/v1.0
(null)
v1.0
-
-
https://spec.example.com/vX
https://spec.example.com/vX
vX
(null)
-
-
-
If name is present, that namespace prefix will automatically be linked to the URL. If a name is not present, then elements of the foreign schema must be imported in order to be referenced.
The name must be a valid GraphQL identifier, and must not contain the namespace separator ("__").
-
By default, @link will assign a prefix based on the name extracted from the URL. If no name is present, a prefix will not be assigned.
-
Providing as: overrides the default behavior: the foreign schema will be assigned the provided prefix, regardless of the name present in the URL (or the lack of one).
An optional purpose for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
-
By default, @links SHOULD fail open. This means that @links to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
-
This behavior is different for @links with a specified purpose:
-
-
SECURITY links convey metadata necessary to compute the API schema and securely resolve fields within it
-
EXECUTION links convey metadata necessary to correctly resolve fields within the schema
This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail‐open behavior of core schema consumers is undesirable.
-
-Note
-we’ll refer to directives from features which are for: SECURITY or for: EXECUTION as “SECURITY directives” and “EXECUTION directives”, respectively.
.*)\])|((?[a-z]+)\.(?[a-zA-Z_\-]+)))/
-
-const slugger = new marked.Slugger()
-
-const base = new marked.Renderer
-const renderer = {
- heading(text, level, _raw) {
- const slug = slugger.slug(text)
-
- return `
-
- ${text}
- `;
- },
-
- code(code, lang, escaped) {
- const lines = code.split(/\n/g)
- let classes = {a: [], pre: [], code: [], div: []}
- let attr, caption
- while (attr = (lines[0] || '').match(reAttr)) {
- lines.shift()
- const {tag, class: cssClass} = attr.groups
- if (tag) {
- classes[tag] && classes[tag].push(cssClass)
- } else {
- caption = attr.groups.caption
- }
- }
-
- const slug = slugger.slug(caption || 'code')
- return `
-
- `
- }
-
-};
-
-
-marked.use({ renderer });
-
-function render(md) {
- const container = document.createElement('div')
- container.innerHTML = marked(md)
- return container.childNodes
-}
-
-function processMarkdown() {
- for (const el of document.querySelectorAll('[markdown]')) {
- el.removeAttribute('markdown')
- for (const child of el.childNodes) {
- if (child.nodeType === Node.TEXT_NODE) {
- child.replaceWith(...render(child.textContent))
- }
- }
- }
-}
-
-let Prism = null
-
-export default async function() {
- await go(processMarkdown)
-
- if (location.hash) {
- const name = location.hash.slice(1)
- const viewElement = document.getElementById(name) ||
- document.getElementsByName(name)[0]
- if (viewElement) setTimeout(() => {
- viewElement.scrollIntoViewIfNeeded()
- }, 100)
- }
-}
\ No newline at end of file
diff --git a/.graphs/https/specs.apollo.dev/mermaid.js b/.graphs/https/specs.apollo.dev/mermaid.js
deleted file mode 100644
index 0c3f283..0000000
--- a/.graphs/https/specs.apollo.dev/mermaid.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import {script} from './load.js'
-import {addTask} from './rendering.js'
-
-const init = script('https://unpkg.com/mermaid@^8/dist/mermaid.min.js')
- .then(async () => {
- const mermaid = window.mermaid
- await mermaid.initialize({
- securityLevel: 'loose',
- theme: 'dark',
- startOnLoad: false,
- })
- return mermaid
- })
-
-async function renderMermaids() {
- const done = addTask('mermaid')
- try {
- const mermaid = await init
- // for (const fig of document.querySelectorAll('.mermaid')) {
- // // preserve source
- // fig.__mermaidSrc = fig.__mermaidSrc || fig.textContent
- // }
- await mermaid.init()
- } finally {
- done()
- }
-}
-
-export default function() {
- renderMermaids()
-}
\ No newline at end of file
diff --git a/.graphs/https/specs.apollo.dev/query.js b/.graphs/https/specs.apollo.dev/query.js
deleted file mode 100644
index 0f7137f..0000000
--- a/.graphs/https/specs.apollo.dev/query.js
+++ /dev/null
@@ -1,13 +0,0 @@
-let match
-
-const query = new Map(
- (match = /^\?(?.*)/.exec(location.search))
- ? match.groups.query.split('&')
- .map(pair => {
- const [k, v=true] = pair.split('=').map(decodeURIComponent)
- return [k, v]
- })
- : [])
-
-export default query
-window.__QUERY = query
\ No newline at end of file
diff --git a/.graphs/https/specs.apollo.dev/rendering.js b/.graphs/https/specs.apollo.dev/rendering.js
deleted file mode 100644
index 6c7da8f..0000000
--- a/.graphs/https/specs.apollo.dev/rendering.js
+++ /dev/null
@@ -1,55 +0,0 @@
-const tasks = new Set
-
-let resolveRender = null
-export const done = new Promise(resolve => {
- resolveRender = resolve
-})
-
-const queue = []
-
-export function addTask(data) {
- const task = { data }
- tasks.add(task)
- return () => {
- tasks.delete(task)
- didFinishTask()
- }
-}
-
-export async function go(func, ...args) {
- const task = {func, args}
- const done = addTask(task)
- try {
- return await func.apply(this, args)
- } finally {
- done()
- }
-}
-
-function didFinishTask() {
- if (!tasks.size) {
- if (queue.length) return drain()
- if (typeof window.__didFinishRendering === 'function') {
- return window.__didFinishRendering()
- }
- window.didFinishRendering = true
- resolveRender()
- }
-}
-
-import query from './query.js'
-export function isPre() {
- return !!query.get('prerender')
-}
-
-export function enqueue(func) {
- queue.push(func)
- if (!tasks.size) drain()
-}
-
-async function drain() {
- while (queue.length) {
- await queue.pop()()
- }
- didFinishTask()
-}
\ No newline at end of file
diff --git a/.graphs/https/specs.apollo.dev/tag/v0.1.graphql b/.graphs/https/specs.apollo.dev/tag/v0.1.graphql
deleted file mode 100644
index bd03b6c..0000000
--- a/.graphs/https/specs.apollo.dev/tag/v0.1.graphql
+++ /dev/null
@@ -1,147 +0,0 @@
-extend schema @link(url: "https://specs.apollo.dev/id/v1.0") @id__(url: "https://specs.apollo.dev/tag/v0.1")
-
-extend schema @id__(url: "https://specs.apollo.dev/tag/v0.1")
-
-"""
-Apply an arbitrary piece of string metadata to the target.
-
-The following example demonstrates how team ownership over types and fields can be declaratively expressed via inline metadata. One might imagine a CI workflow which analyzes a schema diff and uses `@tag` names to authorize or require approval for changes to parts of the graph.
-
-:::[example](ownership-example.graphql)
-"""
-directive @tag(name: String!) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION
-
-"""Link a foreign schema by its URL."""
-directive @link(
- """
- The foreign schema's URL.
-
- Link URLs serve two main purposes:
- - Providing a unique identifier for the foreign schema
- - Directing human readers to documentation about the foreign schema
-
- Link URLs SHOULD be [RFC 3986 URLs](https://tools.ietf.org/html/rfc3986). When viewed, the URL SHOULD provide schema documentation in some human-readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
-
- Link URLs MAY contain information about the spec's [name](#sec-Prefixing) and [version](#sec-Versioning):
-
- ```html diagram -- Basic anatomy of a link URL
-
- https://spec.example.com/a/b/c/mySchema/v1.0
-
- ```
-
- The final two segments of the URL's [path](https://tools.ietf.org/html/rfc3986#section-3.3) MAY contain the schema's name and a [version tag](#sec-Versioning), in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid {VersionTag}. To be recognized as a name, the penultimate path component MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name) which does not include the namespace separator ({"__"}).
-
- Empty final path components (that is, trailing slashes) and any URL components which have not been assigned a meaning (such as the fragment and query) MUST be ignored.
-
- ```html diagram -- Ignoring meaningless parts of a URL
-
- https://example.com/exampleSchema/v1.0/?key=val&k2=v2#frag
-
- ```
-
- All of these are valid arguments to `url`, and their interpretations:
-
- | url | normalized url | name | version |
- | ------------------------------------------------- | ------------------------------------------ | ------- | -------- |
- | https://spec.example.com/a/b/mySchema/v1.0/ | https://spec.example.com/a/b/mySchema/v1.0 | mySchema | v1.0 |
- | https://spec.example.com | https://spec.example.com | *(null)* | *(null)* |
- | https://spec.example.com/mySchema/v0.1?q=v#frag | https://spec.example.com/mySchema/v0.1 | mySchema | v0.1 |
- | https://spec.example.com/v1.0 | https://spec.example.com/v1.0 | *(null)* | v1.0 |
- | https://spec.example.com/vX | https://spec.example.com/vX | vX | *(null)* |
-
- If `name` is present, that [namespace prefix](#sec-Prefixing) will automatically be linked to the URL. If a `name` is not present, then elements of the foreign schema must be [`imported`](#@link/import) in order to be referenced.
- """
- url: String!
- """
- Change the [namespace prefix](#sec-Prefixing) assigned to this schema.
-
- The name must be a valid GraphQL identifier, and must not contain the namespace separator ({"__"}).
-
- By default, {@link} will assign a prefix based on the `name` extracted from the URL. If no `name` is present, a prefix will not be assigned.
-
- Providing [`as:`](#@link/as) overrides the default behavior: the foreign schema will be assigned the provided prefix, regardless of the `name` present in the URL (or the lack of one).
-
- ```graphql example -- Using {@link}(url:, as:) to use a feature with a custom name
- schema
- @link(url: "https://specs.apollo.dev/link/v1.0")
- @link(url: "https://spec.example.com/example/v1.0", as: "eg")
- {
- query: Query
- }
-
- type User {
- # Specifying `as: "eg"` transforms @example into @eg
- name: String @eg(data: ITEM)
- }
-
- # Additional specified schema elements must have their prefixes set
- # to the new name.
- enum eg__Data {
- ITEM
- }
-
- # Name transformation must also be applied to definitions pulled in from
- # specifications.
- directive @eg(data: eg__Data) on FIELD_DEFINITION
-
- directive @link(url: String!, as: String) repeatable on SCHEMA
- ```
- """
- as: String
- """Import definitions into the local namespace."""
- import: [Import]
- """
- An optional [purpose](#Purpose) for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
-
- By default, {@link}s SHOULD fail open. This means that {@link}s to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
-
- This behavior is different for {@link}s with a specified purpose:
- - `SECURITY` links convey metadata necessary to compute the API schema and securely resolve fields within it
- - `EXECUTION` links convey metadata necessary to correctly resolve fields within the schema
- """
- for: Purpose
-) repeatable on SCHEMA
-
-"""TK describe an import"""
-scalar Import
-
-"""
-The role of a feature referenced with {@link}.
-
-This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail-open behavior of core schema consumers is undesirable.
-
-Note we'll refer to directives from features which are `for: SECURITY` or `for: EXECUTION` as "`SECURITY` directives" and "`EXECUTION` directives", respectively.
-"""
-enum Purpose {
- """
- `SECURITY` links provide metadata necessary to securely resolve fields. For instance, a hypothetical {auth} feature may provide an {@auth} directive to flag fields which require authorization. If a data core does not support the {auth} feature and serves those fields anyway, these fields will be accessible without authorization, compromising security.
-
- Security-conscious consumers MUST NOT serve a field if:
- - the schema definition has **any** unsupported SECURITY directives,
- - the field's parent type definition has **any** unsupported SECURITY directives,
- - the field's return type definition has **any** unsupported SECURITY directives, or
- - the field definition has **any** unsupported SECURITY directives
-
- Such fields are *not securely resolvable*. Security-conscious consumers MAY serve schemas with fields which are not securely resolvable. However, they MUST remove such fields from the schema before serving it.
-
- Less security-conscious consumers MAY choose to relax these requirements. For instance, servers may provide a development mode in which unknown SECURITY directives are ignored, perhaps with a warning. Such software may also provide a way to explicitly disable some or all SECURITY links during development.
-
- More security-conscious consumers MAY choose to enhance these requirements. For instance, production servers MAY adopt a policy of entirely rejecting any schema which contains ANY unsupported SECURITY links, even if those links are never used to annotate the schema.
- """
- SECURITY
- """
- `EXECUTION` features provide metadata necessary to correctly resolve fields. For instance, a hypothetical {ts} feature may provide a `@ts__resolvers` annotation which references a TypeScript module of field resolvers. A consumer which does not support the {ts} feature will be unable to correctly resolve such fields.
-
- Consumers MUST NOT serve a field if:
- - the schema's definition has **any** unsupported EXECUTION directives,
- - the field's parent type definition has **any** unsupported EXECUTION directives,
- - the field's return type definition has **any** unsupported EXECUTION directives, or
- - the field definition has **any** unsupported EXECUTION directives
-
- Such fields are *unresolvable*. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION features, even if those features are never used in the schema.
- """
- EXECUTION
-}
-
-directive @id__(url: String!) on SCHEMA
\ No newline at end of file
diff --git a/.graphs/https/specs.apollo.dev/tag/v0.1.html b/.graphs/https/specs.apollo.dev/tag/v0.1.html
deleted file mode 100644
index 3da2eae..0000000
--- a/.graphs/https/specs.apollo.dev/tag/v0.1.html
+++ /dev/null
@@ -1,1597 +0,0 @@
-
-
-
-
-tag v0.1
-
-
-
-
-
-
-
-
-
-
Apply an arbitrary piece of string metadata to the target.
-
The following example demonstrates how team ownership over types and fields can be declaratively expressed via inline metadata. One might imagine a CI workflow which analyzes a schema diff and uses @tag names to authorize or require approval for changes to parts of the graph.
+
+
+```
-### `@key`
+#! @key
+
+```graphql definition
+directive @key(fields: FieldSet!) repeatable on OBJECT | INTERFACE
+```
-"""
The `@key` directive is used to indicate a combination of fields that can be used to uniquely identify and fetch an object or interface.
```graphql example -- using {@key}
@@ -23,13 +35,14 @@ type Product @key(fields: "upc") @key(fields: "sku") {
```
Note: Repeated directives (in this case, `@key`, used multiple times) require support by the underlying GraphQL implementation.
-"""
-directive @key(fields: FieldSet!) repeatable on OBJECT | INTERFACE
-### `@provides`
+#! @provides
+
+```graphql definition
+directive @provides(fields: FieldSet!) on FIELD_DEFINITION
+```
-"""
The `@provides` directive is used to annotate the expected returned fieldset from a field on a base type that is guaranteed to be selectable by the gateway. Given the following example:
```graphql example -- using {@provides}
@@ -45,11 +58,13 @@ extend type Product @key(fields: "upc") {
When fetching `Review.product` from the Reviews service, it is possible to request the `name` with the expectation that the Reviews service can provide it when going from review to product. `Product.name` is an external field on an external type which is why the local type extension of `Product` and annotation of `name` is required.
"""
-directive @provides(fields: FieldSet!) on FIELD_DEFINITION
-### `@requires`
+#! @requires
+
+```graphql definition
+directive @requires(fields: FieldSet!) on FIELD_DEFINITION
+```
-"""
The `@requires` directive is used to annotate the required input fieldset from a base type for a resolver. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. For example:
```graphql example -- using {@requires}
@@ -62,13 +77,13 @@ extend type User @key(fields: "id") {
```
In this case, the Reviews service adds new capabilities to the `User` type by providing a list of `reviews` related to a user. In order to fetch these reviews, the Reviews service needs to know the `email` of the `User` from the Users service in order to look up the reviews. This means the `reviews` field / resolver *requires* the `email` field from the base `User` type.
-"""
-directive @requires(fields: FieldSet!) on FIELD_DEFINITION
+#! @external
-### `@external`
+```graphql definition
+directive @external on FIELD_DEFINITION
+```
-"""
The `@external` directive is used to mark a field as owned by another service. This allows service A to use fields from service B while also knowing at runtime the types of that field. For example:
```graphql example -- using {@external}
@@ -80,7 +95,44 @@ extend type User @key(fields: "email") {
```
This type extension in the Reviews service extends the `User` type from the Users service. It extends it for the purpose of adding a new field called `reviews`, which returns a list of `Review`s.
-"""
-directive @external on FIELD_DEFINITION
-scalar FieldSet
\ No newline at end of file
+#! FieldSet
+
+```graphql definition
+scalar FieldSet
+```
+
+A set of fields.
+
+```graphql example -- Using `FieldSet` with a single field in a `@key`
+type User @key(fields: "id") {
+ id: ID! @external
+}
+```
+
+```graphql example -- Using `FieldSet` with a multiple fields
+type User @key(fields: "uid realm") {
+ uid: String
+ realm: String
+}
+```
+
+Deeply nested fields are supported with standard GraphQL syntax
+
+```graphql example -- `FieldSet` with nested fields
+type User @key(fields: "contact { email }") {
+ contact: Contact
+}
+
+type Contact {
+ email: String
+}
+```
+
+Field arguments are not supported.
+
+```graphql counter-example -- `FieldSet` does not support field arguments
+type User @key(fields: "emails(first: 1)") {
+ emails(first: Int): [String]
+}
+```
\ No newline at end of file
diff --git a/.graphs/https/specs.apollo.dev/federation/v2.0.html b/federation/v2.0/index.html
similarity index 71%
rename from .graphs/https/specs.apollo.dev/federation/v2.0.html
rename to federation/v2.0/index.html
index b927d6e..91803ee 100644
--- a/.graphs/https/specs.apollo.dev/federation/v2.0.html
+++ b/federation/v2.0/index.html
@@ -1039,500 +1039,20 @@
cursor: help;
}
-
-
-
+
When fetching Review.product from the Reviews service, it is possible to request the name with the expectation that the Reviews service can provide it when going from review to product. Product.name is an external field on an external type which is why the local type extension of Product and annotation of name is required. “””
The @requires directive is used to annotate the required input fieldset from a base type for a resolver. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. For example:
In this case, the Reviews service adds new capabilities to the User type by providing a list of reviews related to a user. In order to fetch these reviews, the Reviews service needs to know the email of the User from the Users service in order to look up the reviews. This means the reviews field / resolver requires the email field from the base User type.
The @external directive is used to mark a field as owned by another service. This allows service A to use fields from service B while also knowing at runtime the types of that field. For example:
# extended from the Users serviceextendtypeUser@key(fields:"email"){
- email: String @external
- reviews:[Review]
+ email:String@external
+ reviews:[Review]}
This type extension in the Reviews service extends the User type from the Users service. It extends it for the purpose of adding a new field called reviews, which returns a list of Reviews.
-
diff --git a/inaccessible/v0.1/.gitignore b/inaccessible/v0.1/.gitignore
new file mode 100644
index 0000000..64270c5
--- /dev/null
+++ b/inaccessible/v0.1/.gitignore
@@ -0,0 +1,5 @@
+node_modules
+package-lock.json
+.DS_Store
+.dist
+*.swp
diff --git a/inaccessible/v0.1/README.md b/inaccessible/v0.1/README.md
new file mode 100644
index 0000000..4bc07a7
--- /dev/null
+++ b/inaccessible/v0.1/README.md
@@ -0,0 +1,32 @@
+# Spec Template
+
+## Getting Started
+
+1. Click the "Use this template" button on this repository to create a copy of it and name the new repository `specs-{{spec_name}}`, per convention.
+1. Search for usages of `%%SPEC-.*?%%` tokens within this repository and replace them with appropriate names (e.g., `%%SPEC-NAME%%`, `%%SPEC-TITLE%%` and `%%SPEC-VERSION%%`).
+1. Setup the new repository with Netlify (estimated about 5 minutes)
+ 1. Go to [Netlify App](https://app.netlify.com/teams/apollo/sites)
+ 1. Click “New Site From Git” button
+ 1. Choose GitHub
+ 1. Authorize
+ 1. Choose `apollographql` org
+ 1. Search for `specs-{{spec_name}}`
+ 1. It probably won’t come up
+ 1. Choose “Configure Netlify on GitHub”
+ 1. On the “Install Netlify” screen choose `apollographql`
+ 1. Scroll to the bottom of the App page to where you see the option for “Only select repositories” inside “Repository access”
+ 1. Click “Select repositories”
+ 1. Type `specs-{{spec_name}}` again, then click the matching name.
+ 1. Click on “Save”
+ 1. Then, back on Netlify, click on “specs-tag” in the “Continuous Deployment: GitHub App” box.
+ 1. Leave all the defaults as they are and press “Deploy site”
+ 1. Click on “Site Settings”
+ 1. Press “Change Site Name”
+ 1. Type `apollo-specs-{{spec_name}}` as the name and press “Save”
+ 1. The site should now work at `https://apollo-specs-{{spec_name}}.netlify.app/`
+ 1. Click on “Build and Deploy” on the left menu
+ 1. Under “Branches” press “Edit Settings”
+ 1. Change the “Branch deploys” option to “All” and press “Save”
+1. Setup proxying redirects to the new sub-spec site [on the `specs` repo](https://github.com/apollographql/specs/blob/main/_redirects). This will make it available at `https://specs.apollo.dev/{{spec_name}}`.
+1. Run `npm run dev` to watch and rebuild. Just use a browser to view `.dist/index.html` to see the rendered page.
+1. Write the actual specifications. _Use other specifications (like [the `core` specification](https://github.com/apollographql/specs-core)) as your guide._
diff --git a/inaccessible/coreDirectives.graphql b/inaccessible/v0.1/coreDirectives.graphql
similarity index 100%
rename from inaccessible/coreDirectives.graphql
rename to inaccessible/v0.1/coreDirectives.graphql
diff --git a/inaccessible/inaccessible-v0.1.graphql b/inaccessible/v0.1/inaccessible-v0.1.md
similarity index 61%
rename from inaccessible/inaccessible-v0.1.graphql
rename to inaccessible/v0.1/inaccessible-v0.1.md
index 5f03b6c..9156aa0 100644
--- a/inaccessible/inaccessible-v0.1.graphql
+++ b/inaccessible/v0.1/inaccessible-v0.1.md
@@ -1,6 +1,5 @@
-@id(url: "https://specs.apollo.dev/inaccessible/v0.1")
+# Inaccessible
-"""
for removing elements from a core schema
```raw html
@@ -40,9 +39,33 @@ The schema above contains both a field (`User.id`) and type (`BankAccount`) that
:::[example](./processedSchema.graphql) -- Core schema after processing
-## Modifications to the API
+# Overview
-Within the API,
+*This section is non-normative.* It describes the motivation behind the directives defined by this specification.
+
+A core schema which has been processed according to the inaccessible spec is a queryable graph, intended to be served by a [Data Core](https://specs.apollo.dev/core/v0.2/#sec-Actors). Various use cases require that fields and types should not be visible to or queried for by clients. The `@inaccessible` directive fulfills this requirement, providing schema authors a mechanism to specify which fields and types should be omitted from the processed schema.
+
+# Basic Requirements
+
+Schemas using {@inaccessible} must be valid [core schema documents](https://specs.apollo.dev/core/v0.2) and must reference [this specification](#).
+
+Here is an example `@core` usage:
+
+:::[example](./coreDirectives.graphql) -- required @core directives
+
+As described in the [core schema specification](https://specs.apollo.dev/core/v0.2/#sec-Prefixing), your schema may rename the `@inaccessible` directive by including an `as` argument to the `@core` directive which references this specification. All references to `@inaccessible` in this specification MUST be interpreted as referring to names with the appropriate prefix chosen within your schema.
+
+In order to use the directive described by this specification, GraphQL requires you to include the definition in your schema.
+
+:::[definition](inaccessible.spec.graphql)
+
+## Producer Responsibilities
+
+[Producers](https://specs.apollo.dev/core/v0.2/#sec-Actors) MUST include a definition of the directive compatible with the above definition and all usages in the document.
+
+## Processor Responsibilities
+
+The Processor is responsible for excluding all inaccessible elements from the API. Within the API,
- Field Definitions marked with `@inaccessible` MUST be excluded
- Object types marked with `@inaccessible` MUST be excluded
@@ -51,9 +74,4 @@ Within the API,
- Interfaces marked with `@inaccessible` MUST be excluded from the `extends` clause of all other interfaces
- Union types marked with `@inaccessible` MUST be excluded
-Note applying this process may result in an invalid schema. For example, fields which return `@inaccessible` types which are not themselves marked `@inaccessible` will now return an invalid type which is not present in the schema. This is intentional. `@inaccessible` does NOT cascade. If applying `@inaccessible` results in an invalid schema, the serving process SHOULD apply standard polices to determine whether or how to serve it. Generally, invalid schemas SHOULD NOT be served, though some server configurations—particularly those used for development—MAY OPTIONALLY elect to serve such schemas in a degraded mode. The semantics of such a mode are not within the scope of this spec.
-"""
-schema { query: Query }
-
-
-directive @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION
\ No newline at end of file
+Note applying this process may result in an invalid schema. For example, fields which return `@inaccessible` types which are not themselves marked `@inaccessible` will now return an invalid type which is not present in the schema. This is intentional. `@inaccessible` does NOT cascade. If applying `@inaccessible` results in an invalid schema, the serving process SHOULD apply standard polices to determine whether or how to serve it. Generally, invalid schemas SHOULD NOT be served, though some server configurations—particularly those used for development—MAY OPTIONALLY elect to serve such schemas in a degraded mode. The semantics of such a mode are not within the scope of this spec.
\ No newline at end of file
diff --git a/inaccessible/v0.1/inaccessible.spec.graphql b/inaccessible/v0.1/inaccessible.spec.graphql
new file mode 100644
index 0000000..218729f
--- /dev/null
+++ b/inaccessible/v0.1/inaccessible.spec.graphql
@@ -0,0 +1 @@
+directive @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION
\ No newline at end of file
diff --git a/.graphs/https/specs.apollo.dev/inaccessible/v0.1.html b/inaccessible/v0.1/index.html
similarity index 69%
rename from .graphs/https/specs.apollo.dev/inaccessible/v0.1.html
rename to inaccessible/v0.1/index.html
index c35ae64..5482806 100644
--- a/.graphs/https/specs.apollo.dev/inaccessible/v0.1.html
+++ b/inaccessible/v0.1/index.html
@@ -2,7 +2,7 @@
-inaccessible v0.1
+Inaccessible
-
-
-
+
-
The schema above contains both a field (User.id) and type (BankAccount) that are marked as @inaccessible. These symbols should be omitted from the processed schema anywhere they would appear. When the processed schema below is generated from this core schema, notice what has been removed:
This section is non‐normative. It describes the motivation behind the directives defined by this specification.
+
A core schema which has been processed according to the inaccessible spec is a queryable graph, intended to be served by a Data Core. Various use cases require that fields and types should not be visible to or queried for by clients. The @inaccessible directive fulfills this requirement, providing schema authors a mechanism to specify which fields and types should be omitted from the processed schema.
As described in the core schema specification, your schema may rename the @inaccessible directive by including an as argument to the @core directive which references this specification. All references to @inaccessible in this specification MUST be interpreted as referring to names with the appropriate prefix chosen within your schema.
+
In order to use the directive described by this specification, GraphQL requires you to include the definition in your schema.
extendschema
+ # you link @link by @linking link
+ @link(url:"https://specs.apollo.dev/link/v1.0")
+ # 👇🏽 schemas are identified by a url
+ @link(url:"https://internal.example.com/admin")
+
+typeQuery{
+ allUsers:[User]@admin__adminOnly# 👈🏽 remote identifier, namespaced
+}
+
extendschema
+ @link(url:"https://specs.apollo.dev/link/v1.0")
+ # specific definitions can be imported 👇🏽
+ @link(url:"https://internal.example.com/admin",import:["@adminOnly"])
+
+typeQuery{
+ allUsers:[User]@adminOnly# 👈🏽 remote identifier, imported
+}
+
+
This document introduces a set of conventions for linking and namespacing within GraphQL schemas. Core schemas are not a new kind of document and do not introduce any new syntax—they are just GraphQL schemas which can be interpreted according to the conventions outlined in this doc.
Within a core schema document, every top‐level definition and reference (for example, every named type and directive) has a position in the global graph. This position is captured by a global graph reference.
+
A global graph reference (or gref) is a (link url, element) pair.
+
The URL may be null, to represent local definitions within a schema that is not bound to a URL. Otherwise it must be a valid link url in canonical form.
+
The element may be:
+
+
Directive(name) — a directive
+
Type(name) — a named type of any kind
+
Schema(name?) — a further link to yet another schema. name may be null to indicate the schema itself.
+
+
Implementations may represent these internally in a variety of ways. They also have a canonical string form, which is used in Import
+
+
Directive(name) is represented with “@name”
+
Type(name) is simply represented with “name”
+
Schema(name) is represented with “name::”
+
+
Types and directives are separated in this way because that’s how GraphQL does it—you can have a User type and a @User directive in the same schema (though GraphQL naming conventions would suggest againt it).
Since link urls explicitly cannot have fragments, we can represent global graph references as a URL with a fragment. For example, a reference to this document’s @link directive can be rendered as https://specs.apollo.dev/link/v1.0#@link. A reference to this document’s Import scalar can be rendered as https://specs.apollo.dev/link/v1.0#Import.
+
This is particularly convenient for providing links to documentation. We’ll use this form in examples throughout this document.
As mentioned previously, core schemas connect every definition, directive usage, and named type reference with a global graph reference. Taking the example from the introduction:
extendschema
+# 👇🏽 🌍 https://specs.apollo.dev/link/v1.0/#@link
+ @link(url:"https://specs.apollo.dev/link/v1.0")
+
+# 👇🏽 🌍 https://specs.apollo.dev/link/v1.0/#@link
+ @link(url:"https://internal.example.com/admin",import:[{name:"@adminOnly",as:"@admin"}])
+
+# 👇🏽 🌍 #Query (note: this schema has no url, so the url part is null)
+typeQuery{
+ # 👇🏽 🌍 https://internal.example.com/admin#@adminOnly
+ allUsers:[User]@admin
+ # 🖕🏽 🌍 #User
+}
+
+
This indirection is the whole point. A core‐aware security layer scanning the document for fields marked with https://internal.example.com/admin#@adminOnly will find it, regardless of its local name within the document.
+
Attribution functions the same for all references and definitions within the document. For example, if we include a definition of the @admin directive from the example above (as we must, if the schema is to be fully valid) it too will be attributed to the foreign schema:
Using @id is not, strictly speaking, necessary. A URL can be associated with a document in any number of ways (for example, a processor could associate the schema with the URL where it found it. However, using @id makes the document self‐describing; core‐aware processors will correctly attribute definitions and references within such documents, regardless of where they were found.
Core schemas have a document‐wide scope. A document’s scope is a map of Element ⇒ Binding. The scope is constructed from a document’s @link and @id directives and is used to attribute definitions and references within the document.
+
Elements are the same as in global graph references. When used as scope keys, they carry the following meanings:
+
+
Schema(name) — a schema @linked from the document. name can be used as a prefix for definitions and references within the document, and nameMUST either be a valid prefix or null, indicating the present schema.
+
Directive(name) — a directive imported into the document
implicit: Bool — indicating whether the binding was explicitly imported or created implicitly. Implicit bindings may be overwritten by explicit bindings and will not be formed if an explicit binding for the item alreaady exists
+
+
Similar to a gref‘s elements, different types of scoped items can have the same name without conflict. For example, a scope can contain both a type and schema named “User”, although this should generally be avoided if possible.
+
The global graph reference mapped to the target MUST match the item’s type—a scope cannot map a schema to a directive, for instance. The algorithms provided in this document ensure this is always the case.
A @link without any imports introduces two entries into the scope:
+
+
an explicit binding to the foreign schema, and
+
an implicit binding to a directive with the foreign schema’s own name, if its URL has a name. This somewhat‐blessed directive is the schema’s “root directive”
@linking a foreign schema whose URL does not have a name will create a schema binding if and only if as: is specified, and will never create a root directive reference:
Document processors MAY reject schemas with such errors outright.
+
Permissive processors (for example, a language server which wants to provide best‐effort attribution even in the face of document errors) MAY choose to process such documents even in the face of conflicts. Such processors SHOULD include the first (in document order) binding in the scope, and reject subsequent bindings. Such processors SHOULD also provide error messages listing all@links which are in conflict.
It MUST be a valid GraphQL schema. Amongst other things, this means that it MUST contain definitions for all types and directives it references, including those from foreign schemas
+
If it includes any @links, it MUST include a bootstrap link which MUST precede all other @links in the document
+
It MAY include an @id, particularly if other schemas are meant to link to it (e.g. if the document provide directives for use on other schemas)
+
+
Good news: this means that every valid GraphQL schema which does not use @link is automatically a fully valid core schema. Otherwise‐valid schemas which use @link simply have to include a bootstrap to become fully valid core schemas.
+
+Note
+The bootstrap link is required in order to properly identify the version of the link spec in use.
Providing a unique identifier for the foreign schema
+
Directing human readers to documentation about the foreign schema
+
+
Link URLs SHOULD be RFC 3986 URLs. When viewed, the URL SHOULD provide schema documentation in some human‐readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
+
Link URLs MAY contain information about the spec’s name and version:
The final two segments of the URL’s pathMAY contain the schema’s name and a version tag, in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid VersionTag. To be recognized as a name, the penultimate path component MUST be a valid GraphQL name which does not start or end with an underscore (_) and which does not contain the namespace separator (__).
+
Empty final path components (that is, trailing slashes) and any URL components which have not been assigned a meaning (such as the fragment and query) MUST be ignored.
All of these are valid arguments to url, and their interpretations:
+
+
+
url
+
normalized url
+
name
+
version
+
+
+
+
https://spec.example.com/a/b/mySchema/v1.0/
https://spec.example.com/a/b/mySchema/v1.0
mySchema
v1.0
+
+
https://spec.example.com
https://spec.example.com
(null)
(null)
+
+
https://spec.example.com/mySchema/v0.1?q=v#frag
https://spec.example.com/mySchema/v0.1
mySchema
v0.1
+
+
https://spec.example.com/v1.0
https://spec.example.com/v1.0
(null)
v1.0
+
+
https://spec.example.com/vX
https://spec.example.com/vX
vX
(null)
+
+
+
If name is present, that namespace prefix will automatically be linked to the URL. If a name is not present, then elements of the foreign schema must be imported in order to be referenced.
Change the namespace prefix assigned to the foreign schema. The name MUST be a valid GraphQL identifier, MUST NOT contain the namespace separator ("__"), and MUST NOT end with an underscore (which would create ambiguity between whether "x___y" is prefix x_ for element y or prefix x for element _y).
+
By default, @link will assign a prefix based on the name extracted from the URL. If no name is present, a prefix will not be assigned.
+
Providing as: overrides the default behavior: the foreign schema will be bound to the provided name, regardless of the name present in the URL (or the lack of one).
schema
+ @link(url:"https://specs.apollo.dev/link/v1.0")
+ @link(url:"https://spec.example.com/example/v1.0",as:"eg")
+{
+ query:Query
+}
+
+typeUser{
+ # Specifying `as: "eg"` transforms @example into @eg
+ name:String@eg(data:ITEM)
+}
+
+# Additional specified schema elements must have their prefixes set
+# to the new name.
+enumeg__Data{
+ ITEM
+}
+
+# Name transformation must also be applied to definitions pulled in from
+# specifications.
+directive@eg(data:eg__Data)onFIELD_DEFINITION
+
+directive@link(url:String!,as:String)repeatableonSCHEMA
+
An optional purpose for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
+
By default, @links SHOULD fail open. This means that @links to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
+
This behavior is different for @links with a specified purpose:
+
+
SECURITY links convey metadata necessary to compute the API schema and securely resolve fields within it
+
EXECUTION links convey metadata necessary to correctly resolve fields within the schema
This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail‐open behavior of core schema consumers is undesirable.
+
+Note
+we’ll refer to directives from features which are for: SECURITY or for: EXECUTION as “SECURITY directives” and “EXECUTION directives”, respectively.
SECURITY links provide metadata necessary to securely resolve fields. For instance, a hypothetical auth feature may provide an @auth directive to flag fields which require authorization. If a data core does not support the auth feature and serves those fields anyway, these fields will be accessible without authorization, compromising security.
+
Security‐conscious consumers MUST NOT serve a field if:
+
+
the schema definition has any unsupported SECURITY directives,
+
the field’s parent type definition has any unsupported SECURITY directives,
+
the field’s return type definition has any unsupported SECURITY directives, or
+
the field definition has any unsupported SECURITY directives
+
+
Such fields are not securely resolvable. Security‐conscious consumers MAY serve schemas with fields which are not securely resolvable. However, they MUST remove such fields from the schema before serving it.
+
Less security‐conscious consumers MAY choose to relax these requirements. For instance, servers may provide a development mode in which unknown SECURITY directives are ignored, perhaps with a warning. Such software may also provide a way to explicitly disable some or all SECURITY links during development.
+
More security‐conscious consumers MAY choose to enhance these requirements. For instance, production servers MAY adopt a policy of entirely rejecting any schema which contains ANY unsupported SECURITY links, even if those links are never used to annotate the schema.
EXECUTION features provide metadata necessary to correctly resolve fields. For instance, a hypothetical ts feature may provide a @ts__resolvers annotation which references a TypeScript module of field resolvers. A consumer which does not support the ts feature will be unable to correctly resolve such fields.
the schema’s definition has any unsupported EXECUTION directives,
+
the field’s parent type definition has any unsupported EXECUTION directives,
+
the field’s return type definition has any unsupported EXECUTION directives, or
+
the field definition has any unsupported EXECUTION directives
+
+
Such fields are unresolvable. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION features, even if those features are never used in the schema.
Visit every @link and @id within the document to construct the document’s scope.
+
+Note
+This algorithm Reports errors. Depending on their needs, implementations MAY decide to fail immediately in the face of these errors, or may elect to continue processing the document
Emit all scope bindings produced by a @link directive.
+
+Note
+This algorithm is specified as a generator. This is deemed to produce the clearest psuedocode, but implementations may choose other approaches, such as collecting bindings into a list.
Specs are versioned with a subset of a Semantic Version Number containing only the major and minor parts. Thus, specifications SHOULD provide a version of the form vMajor.Minor, where both integers ≥ 0.
As specified by semver, spec authors SHOULD increment the:
+
+
MAJOR version when you make incompatible API changes,
+
MINOR version when you add functionality in a backwards compatible manner
+
+
+
Patch and pre‐release qualifiers are judged to be not particularly meaningful in the context of GraphQL schemas, which are (by definition) interfaces rather than implementations. The patch component of a semver denotes a bug fix which is backwards compatible—that is, a change to the implementation which does not affect the interface. Patch‐level changes in the version of a spec denote wording clarifications which do not require implementation changes. As such, it is not important to track them for the purposes of version resolution.
+
As with semver, the 0.x version series is special: there is no expectation of compatibility between versions 0.x and 0.y. For example, a processor must not activate implementation 0.4 to satisfy a requested version of 0.2.
Given a version requested by a document and an available version of an implementation, the following algorithm will determine if the available version can satisfy the requested version:
-
-
-```
-
-[intro to core schemas](core-schemas-intro.md)
-
-# Scoping
-
-[scope](../scope.md)
-
-# Versioning
-
-[Versioning](../versioning.md)
-
-# Processing Schemas
-
-```mermaid diagram
-graph LR
- schema(["📄 Input Schema"]):::file-->proc("🤖 Processor")
- proc-->output(["📄 Output Schema"]):::file
- classDef file fill:none,color:#22262E;
- style proc fill:none,stroke:fuchsia,color:fuchsia;
-```
-
-A common use case is that of a processor which consumes a valid input schema and generates an output schema.
-
-The general guidance for processor behavior is: don't react to what you don't understand.
-
-Specifically, processors:
- - SHOULD pass through {@link} directives which reference unknown feature URLs
- - SHOULD pass through prefixed directives, types, and other schema elements
- - SHOULD pass through directives which are not [associated with](#AssignFeatures) a {@link} feature
-
-Processors MAY accept configuration which overrides these default behaviors.
-
-Additionally, processors which prepare the schema for final public consumption MAY choose to eliminate all unknown directives and prefixed types in order to hide schema implementation details within the published schema. This will impair the operation of tooling which relies on these directives—such tools will not be able to run on the output schema, so the benefits and costs of this kind of information hiding should be weighed carefully on a case-by-case basis.
-
-# Algorithms
-
-[Algorithms](algorithms.md)
-
-"""
-schema
-{ query: Query }
-
-
-"""
-Link a foreign schema by its URL.
-"""
-directive @link(
- """
- The foreign schema's URL.
-
- Link URLs serve two main purposes:
- - Providing a unique identifier for the foreign schema
- - Directing human readers to documentation about the foreign schema
-
- Link URLs SHOULD be [RFC 3986 URLs](https://tools.ietf.org/html/rfc3986). When viewed, the URL SHOULD provide schema documentation in some human-readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
-
- Link URLs MAY contain information about the spec's [name](#sec-Prefixing) and [version](#sec-Versioning):
-
- ```html diagram -- Basic anatomy of a link URL
-
- https://spec.example.com/a/b/c/mySchema/v1.0
-
- ```
-
- The final two segments of the URL's [path](https://tools.ietf.org/html/rfc3986#section-3.3) MAY contain the schema's name and a [version tag](#sec-Versioning), in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid {VersionTag}. To be recognized as a name, the penultimate path component MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name) which does not include the namespace separator ({"__"}).
-
- Empty final path components (that is, trailing slashes) and any URL components which have not been assigned a meaning (such as the fragment and query) MUST be ignored.
-
- ```html diagram -- Ignoring meaningless parts of a URL
-
- https://example.com/exampleSchema/v1.0/?key=val&k2=v2#frag
-
- ```
-
- All of these are valid arguments to `url`, and their interpretations:
-
- | url | normalized url | name | version |
- | ------------------------------------------------- | ------------------------------------------ | ------- | -------- |
- | https://spec.example.com/a/b/mySchema/v1.0/ | https://spec.example.com/a/b/mySchema/v1.0 | mySchema | v1.0 |
- | https://spec.example.com | https://spec.example.com | *(null)* | *(null)* |
- | https://spec.example.com/mySchema/v0.1?q=v#frag | https://spec.example.com/mySchema/v0.1 | mySchema | v0.1 |
- | https://spec.example.com/v1.0 | https://spec.example.com/v1.0 | *(null)* | v1.0 |
- | https://spec.example.com/vX | https://spec.example.com/vX | vX | *(null)* |
-
- If `name` is present, that [namespace prefix](#sec-Prefixing) will automatically be linked to the URL. If a `name` is not present, then elements of the foreign schema must be [`imported`](#@link/import) in order to be referenced.
- """
- url: String!,
-
- """
- Change the [namespace prefix](#sec-Prefixing) assigned to this schema.
-
- The name must be a valid GraphQL identifier, and must not contain the namespace separator ({"__"}).
-
- By default, {@link} will assign a prefix based on the `name` extracted from the URL. If no `name` is present, a prefix will not be assigned.
-
- Providing [`as:`](#@link/as) overrides the default behavior: the foreign schema will be assigned the provided prefix, regardless of the `name` present in the URL (or the lack of one).
-
- ```graphql example -- Using {@link}(url:, as:) to use a feature with a custom name
- schema
- @link(url: "https://specs.apollo.dev/link/v1.0")
- @link(url: "https://spec.example.com/example/v1.0", as: "eg")
- {
- query: Query
- }
-
- type User {
- # Specifying `as: "eg"` transforms @example into @eg
- name: String @eg(data: ITEM)
- }
-
- # Additional specified schema elements must have their prefixes set
- # to the new name.
- enum eg__Data {
- ITEM
- }
-
- # Name transformation must also be applied to definitions pulled in from
- # specifications.
- directive @eg(data: eg__Data) on FIELD_DEFINITION
-
- directive @link(url: String!, as: String) repeatable on SCHEMA
- ```
- """
- as: String,
-
- """
- Import definitions into the local namespace.
- """
- import: [Import],
-
- """
- An optional [purpose](#Purpose) for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
-
- By default, {@link}s SHOULD fail open. This means that {@link}s to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
-
- This behavior is different for {@link}s with a specified purpose:
- - `SECURITY` links convey metadata necessary to compute the API schema and securely resolve fields within it
- - `EXECUTION` links convey metadata necessary to correctly resolve fields within the schema
- """
- for: Purpose)
- repeatable on SCHEMA
-
-"""
-TK describe an import
-"""
-scalar Import
-
-"""
-The role of a feature referenced with {@link}.
-
-This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail-open behavior of core schema consumers is undesirable.
-
-Note we'll refer to directives from features which are `for: SECURITY` or `for: EXECUTION` as "`SECURITY` directives" and "`EXECUTION` directives", respectively.
-"""
-enum Purpose {
- """
- `SECURITY` links provide metadata necessary to securely resolve fields. For instance, a hypothetical {auth} feature may provide an {@auth} directive to flag fields which require authorization. If a data core does not support the {auth} feature and serves those fields anyway, these fields will be accessible without authorization, compromising security.
-
- Security-conscious consumers MUST NOT serve a field if:
- - the schema definition has **any** unsupported SECURITY directives,
- - the field's parent type definition has **any** unsupported SECURITY directives,
- - the field's return type definition has **any** unsupported SECURITY directives, or
- - the field definition has **any** unsupported SECURITY directives
-
- Such fields are *not securely resolvable*. Security-conscious consumers MAY serve schemas with fields which are not securely resolvable. However, they MUST remove such fields from the schema before serving it.
-
- Less security-conscious consumers MAY choose to relax these requirements. For instance, servers may provide a development mode in which unknown SECURITY directives are ignored, perhaps with a warning. Such software may also provide a way to explicitly disable some or all SECURITY links during development.
-
- More security-conscious consumers MAY choose to enhance these requirements. For instance, production servers MAY adopt a policy of entirely rejecting any schema which contains ANY unsupported SECURITY links, even if those links are never used to annotate the schema.
- """
- SECURITY
-
- """
- `EXECUTION` features provide metadata necessary to correctly resolve fields. For instance, a hypothetical {ts} feature may provide a `@ts__resolvers` annotation which references a TypeScript module of field resolvers. A consumer which does not support the {ts} feature will be unable to correctly resolve such fields.
-
- Consumers MUST NOT serve a field if:
- - the schema's definition has **any** unsupported EXECUTION directives,
- - the field's parent type definition has **any** unsupported EXECUTION directives,
- - the field's return type definition has **any** unsupported EXECUTION directives, or
- - the field definition has **any** unsupported EXECUTION directives
-
- Such fields are *unresolvable*. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION features, even if those features are never used in the schema.
- """
- EXECUTION
-}
diff --git a/link/v1.0/link-v1.0.md b/link/v1.0/link-v1.0.md
new file mode 100644
index 0000000..04f5050
--- /dev/null
+++ b/link/v1.0/link-v1.0.md
@@ -0,0 +1,647 @@
+# link v1.0
+
+```raw html
+
+
Status
Draft
+
Version
1.0
+
+
+
+```
+
+Core schemas provide tools for linking definitions from different GraphQL schemas together into one.
+
+```graphql example -- linking a directive from another schema
+extend schema
+ # you link @link by @linking link
+ @link(url: "https://specs.apollo.dev/link/v1.0")
+ # 👇🏽 schemas are identified by a url
+ @link(url: "https://internal.example.com/admin")
+
+type Query {
+ allUsers: [User] @admin__adminOnly # 👈🏽 remote identifier, namespaced
+}
+```
+
+```graphql example -- importing a directive from another schema
+extend schema
+ @link(url: "https://specs.apollo.dev/link/v1.0")
+ # specific definitions can be imported 👇🏽
+ @link(url: "https://internal.example.com/admin", import: ["@adminOnly"])
+
+type Query {
+ allUsers: [User] @adminOnly # 👈🏽 remote identifier, imported
+}
+```
+
+This document introduces a set of conventions for linking and namespacing within GraphQL schemas. Core schemas are not a new kind of document and do not introduce any new syntax—they are just GraphQL schemas which can be interpreted according to the conventions outlined in this doc.
+
+# Global Graph References
+
+Within a core schema document, every top-level definition and reference (for example, every named type and directive) has a position in the global graph. This position is captured by a *global graph reference*.
+
+A global graph reference (or *gref*) is a (*[link url](#@link/url)*, *element*) pair.
+
+The URL may be {null}, to represent local definitions within a schema that is not bound to a URL. Otherwise it must be a [valid link url in canonical form](#@link/url).
+
+The *element* may be:
+- Directive({name}) — a directive
+- Type({name}) — a named type of any kind
+- Schema({name}?) — a further link to yet another schema. {name} may be {null} to indicate the schema itself.
+
+Implementations may represent these internally in a variety of ways. They also have a canonical string form, which is used in [{Import}](#Import)
+
+- Directive({name}) is represented with "@{name}"
+- Type({name}) is simply represented with "{name}"
+- Schema({name}) is represented with "{name}::"
+
+Types and directives are separated in this way because that's how GraphQL does it—you can have a `User` type and a `@User` directive in the same schema (though GraphQL naming conventions would suggest againt it).
+
+## URL representation
+
+Since [link urls](#Url) explicitly cannot have fragments, we can represent global graph references as a URL with a fragment. For example, a reference to this document's {@link} directive can be rendered as `https://specs.apollo.dev/link/v1.0#@link`. A reference to this document's {Import} scalar can be rendered as `https://specs.apollo.dev/link/v1.0#Import`.
+
+This is particularly convenient for providing links to documentation. We'll use this form in examples throughout this document.
+
+# Attribution
+
+As mentioned [previously](#sec-Global-Graph-References), core schemas connect every definition, directive usage, and named type reference with a global graph reference. Taking the example from the introduction:
+
+```graphql example -- global graph references (shown in URL form)
+extend schema
+# 👇🏽 🌍 https://specs.apollo.dev/link/v1.0/#@link
+ @link(url: "https://specs.apollo.dev/link/v1.0")
+
+# 👇🏽 🌍 https://specs.apollo.dev/link/v1.0/#@link
+ @link(url: "https://internal.example.com/admin")
+
+# 👇🏽 🌍 #Query (note: this schema has no url, so this gref's url part is null)
+type Query {
+ # 👇🏽 🌍 https://internal.example.com/admin#@adminOnly
+ allUsers: [User] @admin__adminOnly
+ # 🖕🏽 🌍 #User
+}
+```
+
+This attribution *does not change* if we [`import`](#@link/import) some names, even renaming them:
+
+```graphql example -- global graph references with imports
+extend schema
+# 👇🏽 🌍 https://specs.apollo.dev/link/v1.0/#@link
+ @link(url: "https://specs.apollo.dev/link/v1.0")
+
+# 👇🏽 🌍 https://specs.apollo.dev/link/v1.0/#@link
+ @link(url: "https://internal.example.com/admin", import: [{ name: "@adminOnly", as: "@admin" }])
+
+# 👇🏽 🌍 #Query (note: this schema has no url, so the url part is null)
+type Query {
+ # 👇🏽 🌍 https://internal.example.com/admin#@adminOnly
+ allUsers: [User] @admin
+ # 🖕🏽 🌍 #User
+}
+```
+
+This indirection is the whole point. A core-aware security layer scanning the document for fields marked with `https://internal.example.com/admin#@adminOnly` will find it, regardless of its local name within the document.
+
+Attribution functions the same for all references and definitions within the document. For example, if we include a definition of the `@admin` directive from the example above (as we must, if the schema is to be fully valid) it too will be attributed to the foreign schema:
+
+```graphql example -- global graph references for definitions
+extend schema
+# 👇🏽 🌍 https://specs.apollo.dev/link/v1.0/#@link
+ @link(url: "https://specs.apollo.dev/link/v1.0")
+
+# 👇🏽 🌍 https://specs.apollo.dev/link/v1.0/#@link
+ @link(url: "https://internal.example.com/admin", import: [{ name: "@adminOnly", as: "@admin" }])
+
+# 👇🏽 🌍 #Query (note: this schema has no url, so the url part is null)
+type Query {
+ # 👇🏽 🌍 https://internal.example.com/admin#@adminOnly
+ allUsers: [User] @admin
+ # 🖕🏽 🌍 #User
+}
+
+# 👇🏽 🌍 https://internal.example.com/admin#@adminOnly
+directive @admin on FIELD_DEFINITION
+```
+
+## Identifying the document's own URL
+
+The document's own URL can be specified with the [`@id` directive](#@id):
+
+```graphql example -- global graph references with {@id}
+extend schema
+# 👇🏽 🌍 https://specs.apollo.dev/link/v1.0/#@id
+ @id(url: "https://api.example.com/myself")
+
+# 👇🏽 🌍 https://specs.apollo.dev/link/v1.0/#@link
+ @link(url: "https://specs.apollo.dev/link/v1.0", import: ["@id"])
+
+# 👇🏽 🌍 https://specs.apollo.dev/link/v1.0/#@link
+ @link(url: "https://internal.example.com/admin", import: [{ name: "@adminOnly", as: "@admin" }])
+
+# 👇🏽 🌍 https://api.example.com/myself#Query
+type Query {
+ # 👇🏽 🌍 https://internal.example.com/admin#@adminOnly
+ allUsers: [User] @admin
+ # 🖕🏽 🌍 https://api.example.com/myself#User
+}
+```
+
+Using `@id` is not, strictly speaking, necessary. A URL can be associated with a document in any number of ways (for example, a processor could associate the schema with the URL where it found it. However, using [{@id}](#@id) makes the document self-describing; core-aware processors will correctly attribute definitions and references within such documents, regardless of where they were found.
+
+# Scope
+
+Core schemas have a document-wide *scope*. A document's scope is a map of {Element} ==> {Binding}. The scope is constructed from a document's [@link](#@link) and [@id](#@id) directives and is used to [attribute](#sec-Attribution) definitions and references within the document.
+
+Elements are the same as in [global graph references](#sec-Global-Graph-References). When used as scope keys, they carry the following meanings:
+- Schema({name}) — a schema {@link}ed from the document. {name} can be used as a [prefix](#sec-Prefixing) for definitions and references within the document, and {name} MUST either be a valid prefix or {null}, indicating the present schema.
+- Directive({name}) — a directive [imported](#@link/import) into the document
+- Type({name}) — a type [imported](#@link/import) into the document
+
+A {Binding} contains:
+- {gref}: GRef — the [global graph reference](#sec-Global-Graph-References) which is the target of the binding
+- {implicit}: Bool — indicating whether the binding was explicitly imported or created implicitly. Implicit bindings may be overwritten by explicit bindings and will not be formed if an explicit binding for the item alreaady exists
+
+Similar to a [gref](#sec-Global-Graph-References)'s elements, different types of scoped items can have the same name without conflict. For example, a scope can contain both a type and schema named "User", although this should generally be avoided if possible.
+
+The [global graph reference](#sec-Global-Graph-References) mapped to the target MUST match the item's type—a scope cannot map a schema to a directive, for instance. The [algorithms](#sec-Algorithms) provided in this document ensure this is always the case.
+
+## Entries added by @link
+
+A {@link} without any imports introduces two entries into the scope:
+1. an explicit binding to the foreign schema, and
+2. an implicit binding to a directive with the foreign schema's own name, if its URL [has a name](#@link/url). This somewhat-blessed directive is the schema's "root directive"
+
+```graphql example -- {@link} bringing a single schema into scope
+ @link(url: "https://example.com/foreignSchema")
+ # 1. Schema("foreignSchema") -> https://example.com/foreignSchema (explicit)
+ # 2. Directive("foreignSchema") -> https://example.com/foreignSchema#@foreignSchema (implicit)
+```
+
+{@link}ing a foreign schema whose URL does not have a name will create a schema binding if and only if [`as:`](#@link/as) is specified, and will never create a root directive reference:
+
+```graphql example -- {@link} bringing a single schema into scope
+ # 👇🏽 url does not have a name
+ @link(url: "https://api.example.com", as: "example")
+ # 1. Schema("example") -> https://example.com#example (explicit)
+```
+
+A {@link} with imports will add these entries to the scope, in addition to entries for each import:
+
+```graphql example -- {@link} importing items into the scope
+ @link(url: "https://example.com/foreignSchema", import: ["SomeType", "@someDirective"])
+ # 1. Schema("foreignSchema") -> https://example.com/foreignSchema (explicit)
+ # 2. Directive("foreignSchema") -> https://example.com/foreignSchema#@foreignSchema (implicit)
+ # 3. Type("SomeType") -> https://example.com/foreignSchema#SomeType (explicit)
+ # 4. Directive("someDirective") -> https://example.com/foreignSchema#@someDirective (explicit)
+```
+
+Specifying [`as:`](#@link/as) changes the names of the scope items, but not their bound grefs:
+
+```graphql example -- {@link} conflicting schema names
+ @link(url: "https://example.com/foreignSchema", as: "other")
+ # 1. Schema("other") -> https://example.com/foreignSchema (explicit)
+ # 2. Directive("other") -> https://example.com/foreignSchema#@foreignSchema (implicit)
+```
+
+It is not an error to overwrite an implicit binding with an explicit one:
+
+```graphql example -- {@link} import overriding an implicit binding
+ @link(url: "https://example.com/foreignSchema")
+ # 1. Schema("foreignSchema") -> https://example.com/foreignSchema (explicit)
+ # 2. Directive("foreignSchema") -> https://example.com/foreignSchema#@foreignSchema (implicit)
+
+ # (2) will be subsequently overwritten:
+ @link(url: "https://other.com/otherSchema, import: ["@foreignSchema"])
+ # 3. Schema("otherSchema") -> https://other.com/otherSchema (explicit)
+ # 4. Directive("otherSchema") -> https://other.com/otherSchema#@otherSchema (implicit)
+ # 5. Directive("foreignSchema") -> https://other.com/otherSchema#@foreignSchema (explicit, overwrites (2))
+```
+
+But it is an error to overwrite an explicit binding, or for two implicit bindings to overlap:
+
+```graphql counter-example -- {@link} conflicting schema names
+ @link(url: "https://example.com/foreignSchema")
+ # 1. Schema("foreignSchema") -> https://example.com/foreignSchema (explicit)
+ # 2. Directive("foreignSchema") -> https://example.com/foreignSchema#@foreignSchema (implicit)
+
+ @link(url: "https://other.com/foreignSchema")
+ # ❌ Schema("foreignSchema") -> https://other.com/foreignSchema (explicit)
+ # (error, conflicts with with (1))
+ # ❌ Directive("foreignSchema") -> https://other.com/otherSchema#otherSchema (implicit)
+ # (error, conflicts with (2))
+```
+
+Document processors MAY reject schemas with such errors outright.
+
+Permissive processors (for example, a language server which wants to provide best-effort attribution even in the face of document errors) MAY choose to process such documents even in the face of conflicts. Such processors SHOULD include the first (in document order) binding in the scope, and reject subsequent bindings. Such processors SHOULD also provide error messages listing *all* {@link}s which are in conflict.
+
+## Entry added by @id
+
+[@id](#@id) adds just one entry into the scope, binding the current document to the given URL:
+
+```graphql example -- {@id} adds a self-binding into the scope
+ @id(url: "https://example.com/myself")
+ # 1. Schema() -> https://example.com/myself (explicit)
+```
+
+## Bootstrapping
+
+Documents can {@link} link itself. Indeed, if they MUST do so if they use [@link](#@link) at all and are intended to be [fully valid](#sec-Fully-Valid-Core-Schemas):
+
+```graphql example -- bootstrapping {@link}
+extend schema
+ @link(url: "https://specs.apollo.dev/link/v1.0")
+```
+
+The bootstrapping {@link} MUST be the first {@link} in the document. Other directives may precede it, including directives which have been {@link}ed.
+
+```graphql example -- bootstrapping {@link} and using {@id} before doing so
+extend schema
+ @id(url: "https://api.example.com")
+ @link(url: "https://specs.apollo.dev/link/v1.0", import: ["@id"])
+```
+
+There is otherwise nothing special or restricted about these "bootstrapping links". Documents MAY rename {@link}—either with [`as:`](#@link/as) or [`import:`](#@link/import) or both:
+
+```graphql example -- bootstrapping {@link} with a different name
+extend schema
+ @core(url: "https://specs.apollo.dev/link/v1.0", as: "core")
+```
+
+```graphql example -- importing {@link} with a different name
+extend schema
+ @core(url: "https://specs.apollo.dev/link/v1.0", import: [{ name: "@link", as: "@core" }])
+```
+
+```graphql example -- importing {@link} and other things simultaneously
+extend schema
+ @id(url: "https://api.example.com")
+ @foo(url: "https://specs.apollo.dev/link/v1.0", import: [
+ {name: "@link", as: "@core"},
+ "@id"
+ ])
+```
+
+# Fully Valid Core Schemas
+
+For a document to be a fully valid core schema:
+
+1. It MUST be a valid GraphQL schema. Amongst other things, this means that it MUST contain definitions for all types and directives it references, including those from foreign schemas
+2. If it includes any {@link}s, it MUST include a [bootstrap link](#sec-Bootstrapping) which MUST precede all other {@link}s in the document
+3. It MAY include an {@id}, particularly if other schemas are meant to link to it (e.g. if the document provide directives for use on other schemas)
+
+Good news: this means that every valid GraphQL schema which *does not* use {@link} is automatically a fully valid core schema. Otherwise-valid schemas which use {@link} simply have to include a [bootstrap](#sec-Bootstrapping) to become fully valid core schemas.
+
+Note: The bootstrap link is required in order to properly identify the [version](#sec-Versioning) of the link spec in use.
+
+# Definitions
+
+##! @link
+
+```graphql definition
+directive @link(url: String!, as: String, import: [Import])
+```
+
+Link a foreign schema by its URL.
+
+###! url: String!
+
+The foreign schema's URL.
+
+Link URLs serve two main purposes:
+ - Providing a unique identifier for the foreign schema
+ - Directing human readers to documentation about the foreign schema
+
+Link URLs SHOULD be [RFC 3986 URLs](https://tools.ietf.org/html/rfc3986). When viewed, the URL SHOULD provide schema documentation in some human-readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
+
+Link URLs MAY contain information about the spec's [name](#sec-Prefixing) and [version](#sec-Versioning):
+
+```html diagram -- Basic anatomy of a link URL
+
+ https://spec.example.com/a/b/c/mySchema/v1.0
+
+```
+
+The final two segments of the URL's [path](https://tools.ietf.org/html/rfc3986#section-3.3) MAY contain the schema's name and a [version tag](#sec-Versioning), in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid {VersionTag}. To be recognized as a name, the penultimate path component MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name) which does not start or end with an underscore (`_`) and which does not contain the namespace separator (`__`).
+
+Empty final path components (that is, trailing slashes) and any URL components which have not been assigned a meaning (such as the fragment and query) MUST be ignored.
+
+```html diagram -- Ignoring meaningless parts of a URL
+
+ https://example.com/exampleSchema/v1.0/?key=val&k2=v2#frag
+
+```
+
+All of these are valid arguments to `url`, and their interpretations:
+
+| url | normalized url | name | version |
+| ------------------------------------------------- | ------------------------------------------ | ------- | -------- |
+| https://spec.example.com/a/b/mySchema/v1.0/ | https://spec.example.com/a/b/mySchema/v1.0 | mySchema | v1.0 |
+| https://spec.example.com | https://spec.example.com | *(null)* | *(null)* |
+| https://spec.example.com/mySchema/v0.1?q=v#frag | https://spec.example.com/mySchema/v0.1 | mySchema | v0.1 |
+| https://spec.example.com/v1.0 | https://spec.example.com/v1.0 | *(null)* | v1.0 |
+| https://spec.example.com/vX | https://spec.example.com/vX | vX | *(null)* |
+
+If `name` is present, that [namespace prefix](#sec-Prefixing) will automatically be linked to the URL. If a `name` is not present, then elements of the foreign schema must be [`imported`](#@link/import) in order to be referenced.
+
+###! as: String
+
+Change the [namespace prefix](#sec-Prefixing) assigned to the foreign schema.
+
+The name MUST be a valid GraphQL identifier, MUST NOT contain the namespace separator ({"__"}), and MUST NOT end with an underscore (which would create ambiguity between whether {"x___y"} is prefix `x_` for element `y` or prefix `x` for element `_y`).
+
+By default, {@link} will assign a prefix based on the `name` extracted from the URL. If no `name` is present, a prefix will not be assigned.
+
+Providing [`as:`](#@link/as) overrides the default behavior: the foreign schema will be bound to the provided name, regardless of the `name` present in the URL (or the lack of one).
+
+```graphql example -- Using {@link}(url:, as:) to link a schema with a custom name
+schema
+ @link(url: "https://specs.apollo.dev/link/v1.0")
+ @link(url: "https://spec.example.com/example/v1.0", as: "eg")
+{
+ query: Query
+}
+
+type User {
+ # Specifying `as: "eg"` transforms @example into @eg
+ name: String @eg(data: ITEM)
+}
+
+# Additional specified schema elements must have their prefixes set
+# to the new name.
+enum eg__Data {
+ ITEM
+}
+
+# Name transformation must also be applied to definitions pulled in from
+# specifications.
+directive @eg(data: eg__Data) on FIELD_DEFINITION
+
+directive @link(url: String!, as: String) repeatable on SCHEMA
+```
+
+###! import: [Import]
+
+A list of names, possibly with aliases, to import from the foreign schema into the document.
+
+See the [Import](#Import) scalar for a description of the format.
+
+###! for: Purpose
+
+An optional [purpose](#Purpose) for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
+
+By default, {@link}s SHOULD fail open. This means that {@link}s to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
+
+This behavior is different for {@link}s with a specified purpose:
+ - `SECURITY` links convey metadata necessary to compute the API schema and securely resolve fields within it
+ - `EXECUTION` links convey metadata necessary to correctly resolve fields within the schema
+
+##! @id
+
+```graphql definition
+directive @id(url: String!) on SCHEMA
+```
+
+Identify the current document by its URL. The URL is interpreted identically to [`@link`'s `url:` argument](#@link/as).
+
+##! Import
+
+```graphql definition
+scalar Import
+```
+
+An element, possibly aliased, to import into the document.
+
+`Import` can take the form of a string:
+
+```graphql example -- import a string name
+ @link(url: "https://specs.apollo.dev/link/v1.0", import: ["@link", "Purpose"])
+```
+
+or an object with `name` and (optionally `as`):
+
+```graphql example -- import an aliased name
+ @link(url: "https://example.com/, import: [{
+ name: "@example",
+ as: "@eg"
+ }, { name: "Purpose", as: "LinkPurpose" }])
+```
+
+`name` and `as` MUST be of the same type:
+
+```graphql counter-example -- incorrectly importing a type as a directive
+ @link(url: "https://example.com/, import: [{
+ name: "SomeType",
+ as: "@someDirective"
+ }])
+```
+
+Imports cannot currently reference transitive schemas:
+
+```graphql counter-example -- incorrectly importing a transitive schema reference
+ @link(url: "https://example.com/, import: "otherSchema::")
+```
+
+Note: Future versions may support this.
+
+##! Purpose
+
+The role of a feature referenced with {@link}.
+
+This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail-open behavior of core schema consumers is undesirable.
+
+Note we'll refer to directives from features which are `for: SECURITY` or `for: EXECUTION` as "`SECURITY` directives" and "`EXECUTION` directives", respectively.
+
+###! SECURITY
+
+`SECURITY` links provide metadata necessary to securely resolve fields. For instance, a hypothetical {auth} feature may provide an {@auth} directive to flag fields which require authorization. If a data core does not support the {auth} feature and serves those fields anyway, these fields will be accessible without authorization, compromising security.
+
+Security-conscious consumers MUST NOT serve a field if:
+ - the schema definition has **any** unsupported SECURITY directives,
+ - the field's parent type definition has **any** unsupported SECURITY directives,
+ - the field's return type definition has **any** unsupported SECURITY directives, or
+ - the field definition has **any** unsupported SECURITY directives
+
+Such fields are *not securely resolvable*. Security-conscious consumers MAY serve schemas with fields which are not securely resolvable. However, they MUST remove such fields from the schema before serving it.
+
+Less security-conscious consumers MAY choose to relax these requirements. For instance, servers may provide a development mode in which unknown SECURITY directives are ignored, perhaps with a warning. Such software may also provide a way to explicitly disable some or all SECURITY links during development.
+
+More security-conscious consumers MAY choose to enhance these requirements. For instance, production servers MAY adopt a policy of entirely rejecting any schema which contains ANY unsupported SECURITY links, even if those links are never used to annotate the schema.
+
+###! EXECUTION
+
+`EXECUTION` features provide metadata necessary to correctly resolve fields. For instance, a hypothetical {ts} feature may provide a `@ts__resolvers` annotation which references a TypeScript module of field resolvers. A consumer which does not support the {ts} feature will be unable to correctly resolve such fields.
+
+Consumers MUST NOT serve a field if:
+ - the schema's definition has **any** unsupported EXECUTION directives,
+ - the field's parent type definition has **any** unsupported EXECUTION directives,
+ - the field's return type definition has **any** unsupported EXECUTION directives, or
+ - the field definition has **any** unsupported EXECUTION directives
+
+Such fields are *unresolvable*. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION features, even if those features are never used in the schema.
+
+# Appendix: Validations & Algorithms
+
+## Construct the document's scope
+
+Visit every {@link} and {@id} within the document to construct the document's scope.
+
+Note: This algorithm **Report**s errors. Depending on their needs, implementations MAY decide to fail immediately in the face of these errors, or may elect to continue processing the document
+
+ConstructScope(document, baseScope) :
+ 1. **Let** {scope} be {baseScope} if provided. Otherwise, it begins as an empty map of {Element} ==> {Binding}
+ 2. **For** each schema definition or schema extension {schemaDef} in {document},
+ 1. **For** each directive {dir} on {schemaDef},
+ 1. **If** {Locate(scope, dir)} is the gref `https://specs.apollo.dev/link/v1.0#@link`...
+ 2. ...or {LocateBound(scope, dir)} is {null} and {IsBootstrap(dir)} **Then**
+ 1. **For each** ({element}, {binding}) **from** {BindingsFromLink(dir)}
+ 1. **If** {binding} is implicit and {element} exists in {scope} and is explicit, **Then Continue**
+ 2. **If** {binding} is implicit and {element} exists in {scope} and is implicit...
+ 3. **Or If** {binding} is explicit and {element} exists in {scope} and is explicit **Then**
+ 1. **Report** ❌ NameConflict
+ 1. **Insert** {element} ==> {binding} **into** {scope}
+ 2. **For** each schema definition or schema extension {schemaDef} in {document},
+ 1. **For** each directive {dir} on {schemaDef},
+ 1. **If** {Locate(scope, dir)} is the gref `https://specs.apollo.dev/link/v1.0#@id`...
+ 1. **If** {directive} does not have a `url` argument or its `url` argument is an [invalid URL](#@link/url)
+ 1. **Fail** ❌ BadId
+ 2. **Let** {url} be the canonical form of {directive}'s `url`
+ 1. **Insert** Schema() ==> Binding(gref: GRef({url}, Schema()), implicit: {false})
+ 3. **Return** {scope}
+
+## Get all bindings from a @link directive
+
+Emit all scope bindings produced by a @link directive.
+
+Note: This algorithm is specified as a generator. This is deemed to produce the clearest psuedocode, but implementations may choose other approaches, such as collecting bindings into a list.
+
+BindingsFromLink(directive) :
+ 1. **If** {directive} does not have a `url` argument or its `url` argument is an [invalid URL](#@link/url)
+ 1. **Fail** ❌ BadLinkUrl
+ 1. **Let** {url} be the canonical form of the {directive}'s `url` argument, with [all meaningless components stripped](#@link/url)
+ 2. **If** {url} does not have a name...
+ 2. ...and {directive} does not have an `as` argument...
+ 3. ...and {directive} does not have an `import` argument or `import` is an empty list **Then**
+ 1. **Fail** ❌ UselessLink
+ 2. **If** {url} has a name, **Then**
+ 1. **Let** {name} be the name extracted from {url}
+ 2. **Let** {localName} be {directive}'s `as` argument if present and valid, otherwise {name}
+ 2. **Emit** the schema binding (Schema({localName}), Binding(gref: GRef({url}, Schema()), implicit: {false}))
+ 2. **Emit** the root directive binding (Directive({localName}), Binding(gref: GRef({url}, Directive({name})), implicit: {true}))
+ 3. ...**Else**
+ 2. **Let** {localName} be {directive}'s `as` argument if present and valid
+ 2. **Emit** the schema binding (Schema({localName}), Binding(gref: GRef({url}, Schema()), implicit: {false}))
+ 4. **For each** {import} **from** {directive}'s `import` argument:
+ 1. **If** {import} is a string directive name starting with `@`,
+ 0. **Let** {name} be the name of the directive specified by {import}
+ 1. **Emit** (Directive({name}), Binding(gref: GRef({url}, Directive({name})), implicit: {false}))
+ 2. **If** {import} is an object,
+ 1. **If** {import} does not have a string-valued `name` field,
+ 1. **Report** ❌ BadImport
+ 2. **Continue**
+ 1. **Let** {name} be the `name` field from {import}
+ 2. **Let** {as} be the `as` field from {import}, if present, otherwise {name}
+ 1. **If** {name} is a string directive name starting with `@`,
+ 1. **If** {as} is not a directive name starting with `@`,
+ 1. **Report** ❌ BadImportTypeMismatch
+ 2. **Continue**
+ 2. ...**Else Emit** (Directive({as}), Binding(gref: GRef({url}, Directive({name})), implicit: {false}))
+ 2. ...**Else If** {name} is a valid GraphQL identifier,
+ 1. **If** {as} is not a valid GraphQL identifier,
+ 1. **Report** ❌ BadImportTypeMismatch
+ 2. **Continue**
+ 3. ...**Else Emit** (Type({as}), Binding(gref: GRef({url}, Type({name})), implicit: {false}))
+
+
+## Detecting a bootstrap directive
+
+Returns {true} if a directive is a [bootstrap](#sec-Bootstrapping). Otherwise, returns {false}.
+
+IsBootstrap(directive) :
+ 1. **If** {directive} does not have a string-valued `url` argument, **Then Return** {false}
+ 2. **Let** {url} be the canonical form of the {directive}'s `url` argument, with [all meaningless components stripped](#@link/url)
+ 3. **If** {url} is `https://specs.apollo.dev/link/v1.0`,
+ 1. **Let** {testScope} be an empty map of {Element} ==> {Binding}
+ 2. **For each** ({element}, {binding}) **from** {BindingsFromLink(directive)}
+ 1. **Insert** {element} ==> {binding} **into** {testScope}
+ 3. **If** {Locate(testScope, directive)} is a binding with the gref `https://specs.apollo.dev/link/v1.0#@link`, **Then**
+ 1. **Return** {true}
+ 4. Otherwise, **Return** {false}
+
+## Locating definitions and references
+
+Locate a definition or reference within the document's scope, returning a gref.
+
+{defOrRef} must be one of:
+- a definition node with a name
+- an extension node with a name
+- a directive
+
+Locate(scope, defOrRef) :
+ 1. **If** {LocateBound(scope, defOrRef)} is not {null} **Then Return** {LocateBound(scope, defOrRef)}
+ 3. **Let** {selfReference} be the item `Schema()`
+ 3. **Let** {myself} be the URL of the schema returned from {Lookup(scope, selfReference)}, or `Schema(null)` if none was found
+ 1. Let {name} be the name of {defOrRef}
+ 4. **If** {defOrRef} is a named type reference, extension, or definition, **Then**
+ 1. **Return** the gref (myself, Type({name}))
+ 5. Otherwise, **Return** the gref (myself, Directive({name}))
+
+LocateBound(scope, defOrRef) :
+ 1. **Let** ({schema}, {element}) be the pair returned from {GetPathFrom(defOrRef)}
+ 2. **If** {schema} is not {null} and exists in {scope}, **Then**
+ 1. Let {foundGraph} be the URL of the binding found by looking up {schema} in {scope}
+ 2. **Return** the gref ({foundGraph}, {element})
+ 3. **If** {schema} is {null} and {element} exists in {scope}, **Then**
+ 1. **Let** {foundElement} be the gref of the binding found by looking up {element} in {scope},
+ 2. **Return** {foundElement}
+ 4. Otherwise, **Return** {null}
+
+# Appendix: Versioning
+
+VersionTag : "v" Version
+
+Version : Major "." Minor
+
+Major : NumericIdentifier
+
+Minor : NumericIdentifier
+
+NumericIdentifier : "0"
+ | PositiveDigit Digit*
+
+Digit : "0" | PositiveDigit
+
+PositiveDigit : "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
+
+Specs are versioned with a **subset** of a [Semantic Version Number](https://semver.org/spec/v2.0.0.html) containing only the major and minor parts. Thus, specifications SHOULD provide a version of the form `v`{Major}`.`{Minor}, where both integers >= 0.
+
+```text example -- Valid version tags
+v2.2
+v1.0
+v1.1
+v0.1
+```
+
+As specified by semver, spec authors SHOULD increment the:
+
+{++
+
+- MAJOR version when you make incompatible API changes,
+- MINOR version when you add functionality in a backwards compatible manner
+
+++}
+
+Patch and pre-release qualifiers are judged to be not particularly meaningful in the context of GraphQL schemas, which are (by definition) interfaces rather than implementations. The patch component of a semver denotes a bug fix which is backwards compatible—that is, a change to the implementation which does not affect the interface. Patch-level changes in the version of a spec denote wording clarifications which do not require implementation changes. As such, it is not important to track them for the purposes of version resolution.
+
+As with [semver](https://semver.org/spec/v2.0.0.html), the `0.x` version series is special: there is no expectation of compatibility between versions `0.x` and `0.y`. For example, a processor must not activate implementation `0.4` to satisfy a requested version of `0.2`.
+
+## Satisfaction
+
+Given a version {requested} by a document and an {available} version of an implementation, the following algorithm will determine if the {available} version can satisfy the {requested} version:
+
+Satisfies(requested, available) :
+ 1. If {requested}.{Major} ≠ {available}.{Major}, return {false}
+ 2. If {requested}.{Major} = 0, return {requested}.{Minor} = {available}.{Minor}
+ 3. Return {requested}.{Minor} <= {available}.{Minor}
+
diff --git a/link/versioning.md b/link/versioning.md
index 3967380..6f76177 100644
--- a/link/versioning.md
+++ b/link/versioning.md
@@ -38,7 +38,7 @@ Patch and pre-release qualifiers are judged to be not particularly meaningful in
As with [semver](https://semver.org/spec/v2.0.0.html), the `0.x` version series is special: there is no expectation of compatibility between versions `0.x` and `0.y`. For example, a processor must not activate implementation `0.4` to satisfy a requested version of `0.2`.
-## Satisfaction
+# Satisfaction
Given a version {requested} by a document and an {available} version of an implementation, the following algorithm will determine if the {available} version can satisfy the {requested} version:
@@ -47,7 +47,7 @@ Satisfies(requested, available) :
2. If {requested}.{Major} = 0, return {requested}.{Minor} = {available}.{Minor}
3. Return {requested}.{Minor} <= {available}.{Minor}
-## Referencing versions and activating implementations
+# Referencing versions and activating implementations
Schema documents MUST reference a feature version which supports all the schema elements and behaviors required by the document. As a practical matter, authors will generally prefer to reference a version they have reason to believe is supported by the most processors; depending on context, this might be an old stable version with a low major version, or a new less-deprecated version with a large major version.
diff --git a/netlify.toml b/netlify.toml
index c5ba547..940c346 100644
--- a/netlify.toml
+++ b/netlify.toml
@@ -3,6 +3,6 @@
[build]
# This site has no build step at the moment. We just publish the contents.
- publish = "/.graphs/https/specs.apollo.dev"
+ publish = "/"
# Redirects are handled in the ./_redirects file, which has a simple format
diff --git a/package-lock.json b/package-lock.json
index 8e57ce7..ede9909 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,7 +15,7 @@
"specs.apollo.dev": "bin/library"
},
"devDependencies": {
- "@queerviolet/speck": "queerviolet/speck",
+ "@queerviolet/speck": "github:queerviolet/speck",
"express": "^4.17.1",
"http-server": "^0.12.3",
"jsdom": "^16.4.0",
@@ -24,7 +24,7 @@
},
"node_modules/@queerviolet/speck": {
"version": "2.0.2",
- "resolved": "git+ssh://git@github.com/queerviolet/speck.git#c34a337ff933613b590b01681d44608b4696044b",
+ "resolved": "git+ssh://git@github.com/queerviolet/speck.git#7ae75598200928362757b15752495a5cf84f66ef",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@@ -2524,7 +2524,7 @@
},
"dependencies": {
"@queerviolet/speck": {
- "version": "git+ssh://git@github.com/queerviolet/speck.git#c34a337ff933613b590b01681d44608b4696044b",
+ "version": "git+ssh://git@github.com/queerviolet/speck.git#7ae75598200928362757b15752495a5cf84f66ef",
"dev": true,
"from": "@queerviolet/speck@queerviolet/speck",
"requires": {
diff --git a/package.json b/package.json
index f9a8c24..ae0f41f 100644
--- a/package.json
+++ b/package.json
@@ -12,11 +12,11 @@
"author": "",
"license": "ISC",
"devDependencies": {
+ "@queerviolet/speck": "github:queerviolet/speck",
"express": "^4.17.1",
"http-server": "^0.12.3",
"jsdom": "^16.4.0",
- "puppeteer": "^5.5.0",
- "@queerviolet/speck": "queerviolet/speck"
+ "puppeteer": "^5.5.0"
},
"dependencies": {
"commonmark": "^0.29.3"
From 39967e9c092b813a65e780f000fb1927de726d48 Mon Sep 17 00:00:00 2001
From: Ashi Krishnan
Date: Sat, 23 Apr 2022 05:34:04 -0400
Subject: [PATCH 07/13] link spec updates
---
.gitignore | 2 -
build | 1 +
core/v0.1/.gitignore | 3 +
core/v0.1/bad-non-unique-prefix-multi.graphql | 9 +
core/v0.1/bad-non-unique-prefix.graphql | 9 +
core/v0.1/basic.graphql | 14 +
core/v0.1/core-v0.1.md | 485 +++++
core/v0.1/good-unique-prefix-multi.graphql | 9 +
core/v0.1/index.html | 1705 +++++++++++++++
core/v0.1/netlify.toml | 6 +
core/v0.1/package.json | 18 +
core/v0.1/prefix-uniqueness.graphql | 25 +
core/v0.1/prefixing.graphql | 46 +
core/v0.2/.gitignore | 3 +
core/v0.2/bad-non-unique-prefix-multi.graphql | 9 +
core/v0.2/bad-non-unique-prefix.graphql | 9 +
core/v0.2/basic.graphql | 14 +
core/v0.2/core-v0.2.md | 577 ++++++
core/v0.2/good-unique-prefix-multi.graphql | 9 +
core/v0.2/index.html | 1829 +++++++++++++++++
core/v0.2/netlify.toml | 6 +
core/v0.2/package.json | 20 +
core/v0.2/prefix-uniqueness.graphql | 25 +
core/v0.2/prefixing.graphql | 46 +
index.html | 1087 ++++++++++
index.md | 20 +
join/v0.1/albums.graphql | 14 +
join/v0.1/auth.graphql | 8 +
join/v0.1/images.graphql | 15 +
join/v0.1/index.html | 1674 +++++++++++++++
join/v0.1/join-v0.1.md | 469 +++++
join/v0.1/package.json | 18 +
join/v0.1/photos.graphql | 62 +
join/v0.1/spec.graphql | 14 +
link/v1.0/index.html | 301 +--
link/v1.0/link-v1.0.md | 105 +-
tag/v0.1 | 1 -
tag/v0.1/index.html | 1155 +++++++++++
tag/v0.1/ownership-example.graphql | 33 +
tag/v0.1/spec.graphql | 5 +
tag/v0.1/tag-v0.1.md | 42 +
41 files changed, 9734 insertions(+), 168 deletions(-)
create mode 100644 core/v0.1/.gitignore
create mode 100644 core/v0.1/bad-non-unique-prefix-multi.graphql
create mode 100644 core/v0.1/bad-non-unique-prefix.graphql
create mode 100644 core/v0.1/basic.graphql
create mode 100644 core/v0.1/core-v0.1.md
create mode 100644 core/v0.1/good-unique-prefix-multi.graphql
create mode 100644 core/v0.1/index.html
create mode 100644 core/v0.1/netlify.toml
create mode 100644 core/v0.1/package.json
create mode 100644 core/v0.1/prefix-uniqueness.graphql
create mode 100644 core/v0.1/prefixing.graphql
create mode 100644 core/v0.2/.gitignore
create mode 100644 core/v0.2/bad-non-unique-prefix-multi.graphql
create mode 100644 core/v0.2/bad-non-unique-prefix.graphql
create mode 100644 core/v0.2/basic.graphql
create mode 100644 core/v0.2/core-v0.2.md
create mode 100644 core/v0.2/good-unique-prefix-multi.graphql
create mode 100644 core/v0.2/index.html
create mode 100644 core/v0.2/netlify.toml
create mode 100644 core/v0.2/package.json
create mode 100644 core/v0.2/prefix-uniqueness.graphql
create mode 100644 core/v0.2/prefixing.graphql
create mode 100644 index.html
create mode 100644 index.md
create mode 100644 join/v0.1/albums.graphql
create mode 100644 join/v0.1/auth.graphql
create mode 100644 join/v0.1/images.graphql
create mode 100644 join/v0.1/index.html
create mode 100644 join/v0.1/join-v0.1.md
create mode 100644 join/v0.1/package.json
create mode 100644 join/v0.1/photos.graphql
create mode 100644 join/v0.1/spec.graphql
delete mode 160000 tag/v0.1
create mode 100644 tag/v0.1/index.html
create mode 100644 tag/v0.1/ownership-example.graphql
create mode 100644 tag/v0.1/spec.graphql
create mode 100644 tag/v0.1/tag-v0.1.md
diff --git a/.gitignore b/.gitignore
index e85ede9..3c3629e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1 @@
node_modules
-core
-join
\ No newline at end of file
diff --git a/build b/build
index e57e384..e7be76f 100755
--- a/build
+++ b/build
@@ -8,3 +8,4 @@ spec-md inaccessible/v0.1/inaccessible-v0.1.md > inaccessible/v0.1/index.html
spec-md link/v1.0/link-v1.0.md > link/v1.0/index.html
spec-md join/v0.1/join-v0.1.md > join/v0.1/index.html
spec-md federation/v2.0/federation-v2.0.md > federation/v2.0/index.html
+spec-md index.md > index.html
\ No newline at end of file
diff --git a/core/v0.1/.gitignore b/core/v0.1/.gitignore
new file mode 100644
index 0000000..b768a31
--- /dev/null
+++ b/core/v0.1/.gitignore
@@ -0,0 +1,3 @@
+node_modules
+.dist
+package-lock.json
\ No newline at end of file
diff --git a/core/v0.1/bad-non-unique-prefix-multi.graphql b/core/v0.1/bad-non-unique-prefix-multi.graphql
new file mode 100644
index 0000000..221f3e4
--- /dev/null
+++ b/core/v0.1/bad-non-unique-prefix-multi.graphql
@@ -0,0 +1,9 @@
+schema
+ @core(feature: "https://specs.apollo.dev/core/v0.1")
+ @core(feature: "https://specs.example.com/A/1.0") # name is A
+ @core(feature: "https://specs.example.com/A/2.0") # name is A
+{
+ query: Query
+}
+
+directive @core(feature: String!, as: String) repeatable on SCHEMA
diff --git a/core/v0.1/bad-non-unique-prefix.graphql b/core/v0.1/bad-non-unique-prefix.graphql
new file mode 100644
index 0000000..749db43
--- /dev/null
+++ b/core/v0.1/bad-non-unique-prefix.graphql
@@ -0,0 +1,9 @@
+schema
+ @core(feature: "https://specs.apollo.dev/core/v0.1")
+ @core(feature: "https://specs.example.com/A/1.0") # name is A
+ @core(feature: "https://www.specs.com/specA/1.1", as: "A") # name is A
+{
+ query: Query
+}
+
+directive @core(feature: String!, as: String) repeatable on SCHEMA
diff --git a/core/v0.1/basic.graphql b/core/v0.1/basic.graphql
new file mode 100644
index 0000000..454191b
--- /dev/null
+++ b/core/v0.1/basic.graphql
@@ -0,0 +1,14 @@
+schema
+ @core(feature: "https://specs.apollo.dev/core/v0.1")
+ @core(feature: "https://specs.example.com/example/v1.0")
+{
+ query: Query
+}
+
+type Query {
+ field: Int @example
+}
+
+directive @example on FIELD_DEFINITION
+
+directive @core(feature: String!, as: String) repeatable on SCHEMA
diff --git a/core/v0.1/core-v0.1.md b/core/v0.1/core-v0.1.md
new file mode 100644
index 0000000..e67f292
--- /dev/null
+++ b/core/v0.1/core-v0.1.md
@@ -0,0 +1,485 @@
+# Core Schemas
+
+
flexible metadata for GraphQL schemas
+
+```raw html
+
+
Status
Release
+
Version
0.1
+
+
+
+```
+
+[GraphQL](https://spec.graphql.org/) provides directives as a means of attaching user-defined metadata to a GraphQL document. Directives are highly flexible, and can be used to suggest behavior and define features of a graph which are not otherwise evident in the schema.
+
+Alas, *GraphQL does not provide a mechanism to globally identify or version directives*. Given a particular directive—e.g. `@join`—processors are expected to know how to interpret the directive based only on its name, definition within the document, and additional configuration from outside the document. This means that programs interpreting these directives have two options:
+
+ 1. rely on a hardcoded interpretation for directives with certain signatures, or
+ 2. accept additional configuration about how to interpret directives in the schema.
+
+The first solution is fragile, particularly as GraphQL has no built-in namespacing mechanisms, so the possibility of name collisions always looms.
+
+The second is unfortunate: GraphQL schemas are generally intended to be self-describing, and requiring additional configuration subtly undermines this guarantee: given just a schema, programs do not necessarily know how to interpret it, and certainly not how to serve it. It also creates the possibility for the schema and configuration to fall out of sync, leading to issues which can manifest late in a deployment pipeline.
+
+Introducing **core schemas**.
+
+
+
+A basic core schema:
+
+:::[example](basic.graphql) -- A basic core schema
+
+**Core schemas** provide a concise mechanism for schema documents to specify the metadata they provide. Metadata is grouped into **features**, which typically define directives and associated types (e.g. scalars and inputs which serve as directive inputs). Additionally, core schemas provide:
+ - [**Flexible namespacing rules.**](#sec-Prefixing) It is always possible to represent any GraphQL schema within a core schema document. Additionally, documents can [choose the names](#@core/as) they use for the features they reference, guaranteeing that namespace collisions can always be resolved.
+ - [**Versioning.**](#sec-Versioning) Feature specifications follow [semver-like semantic versioning principles](#sec-Versioning), which helps schema processors determine if they are able to correctly interpret a document's metadata.
+
+**Core schemas are not a new language.** All core schema documents are valid GraphQL schema documents. However, this specification introduces new requirements, so not all valid GraphQL schemas are valid core schemas.
+
+The broad intention behind core schemas is to provide a *single document* which provides all the necessary configuration for programs that process and serve the schema to GraphQL clients, primarily by following directives in order to determine how to resolve queries made against that schema.
+
+# Parts of a Core Schema
+
+When talking about a core schema, we can broadly break it into two pieces:
+- an **API** consisting of schema elements (objects, interfaces, enums, directives, etc.) which SHOULD be served to clients, and
+- **machinery** containing document metadata. This typically consists of directives and associated input types (such as enums and input objects), but may include any schema element. Machinery MUST NOT be served to clients. Specifically, machinery MUST NOT be included in introspection responses or used to validate or execute queries.
+
+This reflects how core schemas are used: a core schema contains a GraphQL interface (the *API*) along with metadata about how to implement that interface (the *machinery*). Exposing the machinery to clients is unnecessary, and may in some cases constitute a security issue (for example, the machinery for a public-facing graph router will likely reference internal services, possibly exposing network internals which should not be visible to the general public).
+
+A key feature of core schemas is that it is always possible to derive a core schema's API without any knowledge of the features used by the document (with the exception of the `core` feature itself). Specifically, named elements are not included in the API schema if they are named `something__likeThis` or are a directive named `@something`, and `something` is the prefix of a feature declared with {@core}.
+
+A formal description is provided by the [IsInAPI](#sec-Is-In-API-) algorithm.
+
+# Actors
+
+```mermaid diagram -- Actors who may be interested in the core schemas
+graph TB
+ classDef bg fill:none,color:#22262E;
+ author("👩🏽💻 🤖 Author"):::bg-->schema(["☉ Core Schema"]):::bg
+ schema-->proc1("🤖 Processor"):::bg
+ proc1-->output1(["☉ Core Schema[0]"]):::bg
+ output1-->proc2("🤖 Processor"):::bg
+ proc2-->output2(["☉ Core Schema[1]"]):::bg
+ output2-->etc("..."):::bg
+ etc-->final(["☉ Core Schema [final]"]):::bg
+ final-->core("🤖 Data Core"):::bg
+ schema-->reader("👩🏽💻 Reader"):::bg
+ output1-->reader
+ output2-->reader
+ final-->reader
+```
+
+- **Authors (either human or machine)** write an initial core schema as specified in this document, including versioned {@core} requests for all directives they use
+- **Machine processors** can process core schemas and output new core schemas. The versioning of directives and associated schema elements provided by the {@core} allows processors to operate on directives they understand and pass through directives they do not.
+- **Human readers** can examine the core schema at various stages of processing. At any stage, they can examine the {@core} directives and follow URLs to the specification, receiving an explanation of the requirements of the specification and what new directives, types, and other schema objects are available within the document.
+- **Data cores** can then pick up the processed core schema and provide some data-layer service with it. Typically this means serving the schema's API as a GraphQL endpoint, using metadata defined by machinery to inform how it processes operations it receives. However, data cores may perform other tasks described in the core schema, such as routing to backend services, caching commonly-accessed fields and queries, and so on. The term "data core" is intended to capture this multiplicity of possible activities.
+
+# Basic Requirements
+
+Core schemas:
+ 1. MUST be valid GraphQL schema documents,
+ 2. MUST contain exactly one `SchemaDefinition`, and
+ 3. MUST use the {@core} directive on their schema definition to declare any features they reference by using {@core} to reference a [well-formed feature URL](#@core/feature).
+
+The first {@core} directive on the schema MUST reference the core spec itself, i.e. this document.
+
+:::[example](basic.graphql) -- Basic core schema using {@core} and `@example`
+
+## Unspecified directives are passed through by default
+
+Existing schemas likely contain definitions for directives which are not versioned, have no specification document, and are intended mainly to be passed through. This is the default behavior for core schema processors:
+
+```graphql example -- Unspecified directives are passed through
+schema
+ @core(feature: "https://specs.apollo.dev/core/v0.1")
+{
+ query: Query
+}
+
+type SomeType {
+ field: Int @another
+}
+
+# `@another` is unspecified. Core processors will not extract metadata from
+# it, but its definition and all usages within the schema will be exposed
+# in the API.
+directive @another on FIELD_DEFINITION
+
+directive @core(feature: String!, as: String) repeatable on SCHEMA
+```
+
+## Renaming core itself
+
+It is possible to rename the core feature itself with the same [`as:`](#@core/as) mechanism used for all features:
+
+```graphql example -- Renaming {@core} to {@coreSchema}
+schema
+ @coreSchema(feature: "https://specs.apollo.dev/core/v0.1", as: "coreSchema")
+ @coreSchema(feature: "https://example.com/example/v1.0")
+{
+ query: Query
+}
+
+type SomeType {
+ field: Int @example
+}
+
+directive @coreSchema(feature: String!, as: String)
+ repeatable on SCHEMA
+directive @example on FIELD_DEFINITION
+```
+
+# Directive Definitions
+
+All core schemas use the [{@core}](#@core) directive to declare their use of the `core` feature itself as well as any other core features they use.
+
+In order to use these directives in your schema, GraphQL requires you to include their definitions in your schema.
+
+Processors MUST validate that you have defined the directives with the same arguments, locations, and `repeatable` flag as given below. Specifically, the [bootstrapping](#sec-Bootstrapping) algorithm validates that the `@core` directive has a definition matching the definition given below. (The bootstrapping algorithm does not require processors to validate other aspects of the directive declaration such as description strings or argument ordering. The main purpose of this validation is to ensure that directive arguments have the type and default values expected by the specification.)
+
+The following declares the directive defined by this specification. You SHOULD define the directives in your core schema by including the following text in your schema document.
+
+```graphql
+directive @core(feature: String!, as: String) repeatable on SCHEMA
+```
+
+When writing a specification for your own core feature, you SHOULD include a section like this one with sample definitions to copy into schemas, and you SHOULD require processors to validate that directive definitions in documents match your sample definitions.
+
+# Directives
+
+##! @core
+
+Declare a core feature present in this schema.
+
+```graphql definition
+directive @core(
+ feature: String!,
+ as: String)
+ repeatable on SCHEMA
+```
+
+Documents MUST include a definition for the {@core} directive which includes all of the arguments defined above with the same types and default values.
+
+###! feature: String!
+
+A feature URL specifying the directive and associated schema elements. When viewed, the URL SHOULD provide the content of the appropriate version of the specification in some human-readable form. In short, a human reader should be able to click the link and go to the docs for the version in use. There are specific requirements on the format of the URL, but it is not required that the *content* be machine-readable in any particular way.
+
+Feature URLs contain information about the spec's [prefix](#sec-Prefixing) and [version](#sec-Versioning).
+
+Feature URLs serve two main purposes:
+ - Directing human readers to documentation about the feature
+ - Providing tools with information about the specs in use, along with enough information to select and invoke an implementation
+
+Feature URLs SHOULD be [RFC 3986 URLs](https://tools.ietf.org/html/rfc3986). When viewed, the URL SHOULD provide the specification of the selected version of the feature in some human-readable form; a human reader should be able to click the link and go to the correct version of the docs.
+
+Although they are not prohibited from doing so, it's assumed that processors will not load the content of feature URLs. Published specifications are not required to be machine-readable, and [this spec](.) places no requirements on the structure or syntax of the content to be found there.
+
+There are, however, requirements on the structure of the URL itself:
+
+```html diagram -- Basic anatomy of a feature URL
+
+ https://spec.example.com/a/b/c/exampleFeature/v1.0
+
+```
+
+The final two segments of the URL's [path](https://tools.ietf.org/html/rfc3986#section-3.3) MUST contain the feature's name and a [version tag](#sec-Versioning). The content of the URL up to and including the name—but excluding the `/` after the name and the version tag—is the feature's *identity*. Trailing slashes at the end of the URL (ie, after the version tag) should be ignored. For the above example,
+
A global identifier for the feature. Processors can treat this as an opaque string identifying the feature (but not the version of the feature) for purposes of selecting an appropriate implementation. The identity never has a trailing `/`.
+
`name: "exampleFeature"`
+
The feature's name, for purposes of [prefixing](#sec-Prefixing) schema elements it defines.
+
`version: "v1.0"`
+
The tag for the [version](#sec-Versioning) of the feature used to author the document. Processors MUST select an implementation of the feature which can [satisfy](#sec-Satisfaction) the specified version.
+
+
+The version tag MUST be a valid {VersionTag}. The name MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name) which does not include the namespace separator ({"__"}).
+
+#### Ignore meaningless URL components
+
+When extracting the URL's `name` and `version`, processors MUST ignore any url components which are not assigned a meaning. This spec assigns meaning to the final two segments of the [path](https://tools.ietf.org/html/rfc3986#section-3.3). Other URL components—particularly query strings and fragments, if present—MUST be ignored for the purposes of extracting the `name` and `version`.
+
+```html diagram -- Ignoring meaningless parts of a URL
+
+ https://example.com/exampleSpec/v1.0/?key=val&k2=v2#frag
+
+```
+
+#### Why is versioning in the URL, not a directive argument?
+
+The version is in the URL because when a human reader visits the URL, we would like them to be taken to the documentation for the *version of the feature used by this document*. Many text editors will turn URLs into hyperlinks, and it's highly desirable that clicking the link takes the user to the correct version of the docs. Putting the version information in a separate argument to the {@core} directive would prevent this.
+
+###! as: String
+
+Change the [names](#sec-Prefixing) of directives and schema elements from this specification. The specified string MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name) and MUST NOT contain the namespace separator (two underscores, {"__"}) or end with an underscore.
+
+When [`as:`](#@core/as) is provided, processors looking for [prefixed schema elements](#sec-Elements-which-must-be-prefixed) MUST look for elements whose names are the specified name with the prefix replaced with the name provided to the `as:` argument.
+
+```graphql example -- Using {@core}(feature:, as:) to use a feature with a custom name
+schema
+ @core(feature: "https://specs.apollo.dev/core/v0.1")
+ @core(feature: "https://spec.example.com/example/v1.0", as: "eg")
+{
+ query: Query
+}
+
+type User {
+ # Specifying `as: "eg"` transforms @example into @eg
+ name: String @eg(data: ITEM)
+}
+
+# Additional specified schema elements must have their prefixes set
+# to the new name.
+#
+# The spec at https://spec.example.com/example/v1.0 calls this enum
+# `example__Data`, but because of the `as:` argument above, processors
+# will use this `eg__Data` enum instead.
+enum eg__Data {
+ ITEM
+}
+
+# Name transformation must also be applied to definitions pulled in from
+# specifications.
+directive @eg(data: eg__Data) on FIELD_DEFINITION
+
+directive @core(feature: String!, as: String) repeatable on SCHEMA
+```
+
+# Prefixing
+
+With the exception of a single root directive, core feature specifications MUST prefix all schema elements they introduce. The prefix:
+ 1. MUST match the name of the feature as derived from the feature's specification URL,
+ 2. MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name), and
+ 3. MUST NOT contain the core namespace separator, which is two underscores ({"__"}), and
+ 4. MUST NOT end with an underscore (which would create ambiguity between whether {"x___y"} is prefix `x_` for element `y` or prefix `x` for element `_y`).
+
+Prefixed names consist of the name of the feature, followed by two underscores, followed by the name of the element, which can be any valid [GraphQL name](https://spec.graphql.org/draft/#Name). For instance, the `core` specification (which you are currently reading) introduces an element named [{@core}](#@core), and the `join` specification introduces an element named {@join__field} (among others).
+
+Note that both parts must be valid GraphQL names, and GraphQL names cannot start with digits, so core feature specifications cannot introduce names like `@feature__24hours`.
+
+A feature's *root directive* is an exception to the prefixing requirements. Feature specifications MAY introduce a single directive which carries only the name of the feature, with no prefix required. For example, the `core` specification introduces a {@core} directive. This directive has the same name as the feature ("`core`"), and so requires no prefix.
+
+```graphql example -- Using the @core directive without changing the prefix
+schema
+ @core(feature: "https://specs.apollo.dev/core/v0.1")
+ @core(feature: "https://spec.example.com/example/v1.0") {
+ query: Query
+}
+
+type User {
+ name: String @example(data: ITEM)
+}
+
+# An enum used to provide structured data to the example spec.
+# It is prefixed with the name of the spec.
+enum example__Data {
+ ITEM
+}
+
+directive @example(data: example__Data) on FIELD_DEFINITION
+
+directive @core(feature: String!, as: String) repeatable on SCHEMA
+```
+
+The prefix MUST NOT be elided within documentation; definitions of schema elements provided within the spec MUST include the feature's name as a prefix.
+
+## Elements which must be prefixed
+
+Feature specs MUST prefix the following schema elements:
+ - the names of any object types, interfaces, unions, enums, or input object types defined by the feature
+ - the names of any directives introduced in the spec, with the exception of the *root directive*, which must have the same name as the feature
+
+:::[example](prefixing.graphql) -- Prefixing
+
+# Versioning
+
+VersionTag : "v" Version
+
+Version : Major "." Minor
+
+Major : NumericIdentifier
+
+Minor : NumericIdentifier
+
+NumericIdentifier : "0"
+ | PositiveDigit Digit*
+
+Digit : "0" | PositiveDigit
+
+PositiveDigit : "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
+
+Specs are versioned with a **subset** of a [Semantic Version Number](https://semver.org/spec/v2.0.0.html) containing only the major and minor parts. Thus, specifications SHOULD provide a version of the form `v`{Major}`.`{Minor}, where both integers >= 0.
+
+```text example -- Valid version tags
+v2.2
+v1.0
+v1.1
+v0.1
+```
+
+As specified by semver, spec authors SHOULD increment the:
+
+{++
+
+- MAJOR version when you make incompatible API changes,
+- MINOR version when you add functionality in a backwards compatible manner
+
+++}
+
+Patch and pre-release qualifiers are judged to be not particularly meaningful in the context of core features, which are (by definition) interfaces rather than implementations. The patch component of a semver denotes a bug fix which is backwards compatible—that is, a change to the implementation which does not affect the interface. Patch-level changes in the version of a spec denote wording clarifications which do not require implementation changes. As such, it is not important to track them for the purposes of version resolution.
+
+As with [semver](https://semver.org/spec/v2.0.0.html), the `0.x` version series is special: there is no expectation of compatibility between versions `0.x` and `0.y`. For example, a processor must not activate implementation `0.4` to satisfy a requested version of `0.2`.
+
+## Satisfaction
+
+Given a version {requested} by a document and an {available} version of an implementation, the following algorithm will determine if the {available} version can satisfy the {requested} version:
+
+Satisfies(requested, available) :
+ 1. If {requested}.{Major} ≠ {available}.{Major}, return {false}
+ 2. If {requested}.{Major} = 0, return {requested}.{Minor} = {available}.{Minor}
+ 3. Return {requested}.{Minor} <= {available}.{Minor}
+
+## Referencing versions and activating implementations
+
+Schema documents MUST reference a feature version which supports all the schema elements and behaviors required by the document. As a practical matter, authors will generally prefer to reference a version they have reason to believe is supported by the most processors; depending on context, this might be an old stable version with a low major version, or a new less-deprecated version with a large major version.
+
+If a processor chooses to activate support for a feature, the processor MUST activate an implementation which can [satisfy](#sec-Satisfaction) the version required by the document.
+
+
+# Processing Schemas
+
+```mermaid diagram
+graph LR
+ schema(["📄 Input Schema"]):::file-->proc("🤖 Processor")
+ proc-->output(["📄 Output Schema"]):::file
+ classDef file fill:none,color:#22262E;
+ style proc fill:none,stroke:fuchsia,color:fuchsia;
+```
+
+A common use case is that of a processor which consumes a valid input schema and generates an output schema.
+
+The general guidance for processor behavior is: don't react to what you don't understand.
+
+Specifically, processors:
+ - SHOULD pass through {@core} directives which reference unknown feature URLs
+ - SHOULD pass through prefixed directives, types, and other schema elements
+ - SHOULD pass through directives which are not [associated with](#AssignFeatures) a {@core} feature
+
+Processors MAY accept configuration which overrides these default behaviors.
+
+Additionally, processors which prepare the schema for final public consumption MAY choose to eliminate all unknown directives and prefixed types in order to hide schema implementation details within the published schema. This will impair the operation of tooling which relies on these directives—such tools will not be able to run on the output schema, so the benefits and costs of this kind of information hiding should be weighed carefully on a case-by-case basis.
+
+# Validations & Algorithms
+
+This section lays out algorithms for processing core schemas.
+
+Algorithms described in this section may produce *validation failures* if a document does not conform to the requirements core schema document. Validation failures SHOULD halt processing. Some consumers, such as authoring tools, MAY attempt to continue processing in the presence of validation failures, but their behavior in such cases is unspecified.
+
+## Bootstrapping
+
+Determine the name of the core specification within the document.
+
+It is possible to [rename the core feature](#sec-Renaming-core-itself) within a document. This process determines the actual name for the core feature if one is present.
+
+- **Fails** the *Has Schema* validation if there are no SchemaDefinitions in the document
+- **Fails** the *Has Core Feature* validation if the `core` feature itself is not referenced with a {@core} directive within the document
+- **Fails** the *Bootstrap Core Feature Listed First* validation if the reference to the `core` feature is not the first {@core} directive on the document's SchemaDefinition
+- **Fails** the *Core Directive Incorrect Definition* validation if the {@core} directive definition does not *match* the directive as defined by this specification.
+
+For the purposes of this algorithm, a directive's definition in a schema *matches* a definition provided in this specification if:
+- Its arguments have the specified names, types, and default values (or lack thereof)
+- It is defined as `repeatable` if and only if the specification's definition defines it as `repeatable`
+- The set of locations it belongs to is the same set of locations in the specification's definition.
+
+The following aspects may differ between the definition in the schema and the definition in the specification without preventing the definitions from *matching*:
+- The name of the directive (due to [prefixing](#sec-Prefixing))
+- The order of arguments
+- The order of locations
+- The directive's description string
+- Argument description strings
+- Directives applied to argument definitions
+
+Bootstrap(document) :
+1. Let {schema} be the only SchemaDefinition in {document}. (Note that legal GraphQL documents [must include at most one SchemaDefinition](http://spec.graphql.org/draft/#sec-Root-Operation-Types).)
+ 1. ...if no SchemaDefinitions are present in {document}, the ***Has Schema* validation fails**.
+1. For each directive {d} on {schema},
+ 1. If {d} has a [`feature:`](#@core/feature) argument which [parses as a feature URL](#@core/feature), *and* whose identity is {"https://specs.apollo.dev/core/"} *and* whose version is {"v0.1"}, *and either* {d} has an [`as:`](#@core/as) argument whose value is equal to {d}'s name *or* {d} does not have an [`as:`](#@core/as) argument and {d}'s name is `core`:
+ - If any directive on {schema} listed before {d} has the same name as {d}, the ***Bootstrap Core Feature Listed First* validation fails**.
+ - If the definition of the directive {d} does not *match* the [definition of {@core} in this specification](#@core), the ***Core Directive Incorrect Definition* validation fails**.
+ - Otherwise, **Return** {d}'s name.
+- If no matching directive was found, the ***Has Core Feature* validation fails**.
+
+## Feature Collection
+
+Collect a map of ({featureName}: `String`) -> `Directive`, where `Directive` is a {@core} Directive which introduces the feature named {featureName} into the document.
+
+- **Fails** the *Name Uniqueness* validation if feature names are not unique within the document.
+- **Fails** *Invalid Feature URL* validation for any invalid feature URLs.
+
+CollectFeatures(document) :
+ - Let {coreName} be the name of the core feature found via {Bootstrap(document)}
+ - Let {features} be a map of {featureName}: `String` -> `Directive`, initially empty.
+ - For each directive {d} named {coreName} on the SchemaDefinition within {document},
+ - Let {specifiedFeatureName} and {version} be the result of parsing {d}'s `feature:` argument according to the [specified rules for feature URLs](#@core/feature)
+ - If the `feature:` is not present or fails to parse:
+ - The ***Invalid Feature URL* validation fails** for {d},
+ - Let {featureName} be the {d}'s [`as:`](#@core/as) argument or, if the argument is not present, {specifiedFeatureName}
+ - If {featureName} exists within {features}, the ***Name Uniqueness* validation fails**.
+ - Insert {featureName} => {d} into {features}
+ - **Return** {features}
+
+
+Prefixes, whether implicit or explicit, must be unique within a document. Valid:
+
+:::[example](prefixing.graphql#schema[0]) -- Unique prefixes
+
+It is also valid to reference multiple versions of the same spec under different prefixes:
+
+:::[example](prefix-uniqueness.graphql#schema[0]) -- Explicit prefixes allow multiple versions of the same spec to coexist within a Document
+
+Without the explicit [`as:`](#@core/as), the above would be invalid:
+
+:::[counter-example](prefix-uniqueness.graphql#schema[1]) -- Non-unique prefixes with multiple versions of the same spec
+
+Different specs with the same prefix are also invalid:
+
+:::[counter-example](prefix-uniqueness.graphql#schema[2]) -- Different specs with non-unique prefixes
+
+## Assign Features
+
+Create a map of {element}: *Any Named Element* -> {feature}: `Directive` | {null}, associating every named schema element within the document with a feature directive, or {null} if it is not associated with a feature.
+
+AssignFeatures(document) :
+ - Let {features} be the result of collecting features via {CollectFeatures(document)}
+ - Let {assignments} be a map of ({element}: *Any Named Element*) -> {feature}: `Directive` | {null}, initally empty
+ - For each named schema element {e} within the {document}
+ - Let {name} be the name of the {e}
+ - If {e} is a Directive and {name} is a key within {features},
+ - Insert {e} => {features}`[`{name}`]` into {assignments}
+ - **Continue** to next {e}
+ - If {name} begins with {"__"},
+ - Insert {e} => {null} into {assignments}
+ - **Continue** to next {e}
+ - If {name} contains the substring {"__"},
+ - Partition {name} into `[`{prefix}, {base}`]` at the first {"__"} (that is, find the shortest {prefix} and longest {base} such that {name} = {prefix} + {"__"} + {base})
+ - If {prefix} exists within {features}, insert {e} => {features}`[`{prefix}`]` into {assignments}
+ - Else, insert {e} => {null} into {assignments}
+ - **Continue** to next {e}
+ - Insert {e} => {null} into {assignments}
+ - **Return** {assignments}
+
+## Is In API?
+
+Determine if any schema element is included in the [API](#sec-Parts-of-a-Core-Schema) described by the core schema. A schema element is any part of a GraphQL document using type system definitions that has a [name](https://spec.graphql.org/draft/#Name).
+
+IsInAPI(element) :
+ - Let {assignments} be the result of assigning features to elements via {AssignFeatures(document)}
+ - If {assignments}`[`{element}`]` is {null}, **Return** {true}
+ - Else, **Return** {false}
+
+Note: Later versions of this specification may add other ways to affect the behavior of this algorithm, but those mechanisms will only be enabled if you reference those hypothetical versions of this specification.
+
diff --git a/core/v0.1/good-unique-prefix-multi.graphql b/core/v0.1/good-unique-prefix-multi.graphql
new file mode 100644
index 0000000..8eafe08
--- /dev/null
+++ b/core/v0.1/good-unique-prefix-multi.graphql
@@ -0,0 +1,9 @@
+schema
+ @core(feature: "https://specs.apollo.dev/core/v0.1")
+ @core(feature: "https://specs.example.com/A/1.0") # name is A
+ @core(feature: "https://specs.example.com/A/2.0", as: "A2") # name is A2
+{
+ query: Query
+}
+
+directive @core(feature: String!, as: String) repeatable on SCHEMA
diff --git a/core/v0.1/index.html b/core/v0.1/index.html
new file mode 100644
index 0000000..df41bb3
--- /dev/null
+++ b/core/v0.1/index.html
@@ -0,0 +1,1705 @@
+
+
+
+
+Core Schemas
+
+
+
+
+
+
+
+
Core Schemas
+
+
flexible metadata for GraphQL schemas
+
+
Status
Release
+
Version
0.1
+
+
+
+
GraphQL provides directives as a means of attaching user‐defined metadata to a GraphQL document. Directives are highly flexible, and can be used to suggest behavior and define features of a graph which are not otherwise evident in the schema.
+
Alas, GraphQL does not provide a mechanism to globally identify or version directives. Given a particular directive—e.g. @join—processors are expected to know how to interpret the directive based only on its name, definition within the document, and additional configuration from outside the document. This means that programs interpreting these directives have two options:
+
+
rely on a hardcoded interpretation for directives with certain signatures, or
+
accept additional configuration about how to interpret directives in the schema.
+
+
The first solution is fragile, particularly as GraphQL has no built‐in namespacing mechanisms, so the possibility of name collisions always looms.
+
The second is unfortunate: GraphQL schemas are generally intended to be self‐describing, and requiring additional configuration subtly undermines this guarantee: given just a schema, programs do not necessarily know how to interpret it, and certainly not how to serve it. It also creates the possibility for the schema and configuration to fall out of sync, leading to issues which can manifest late in a deployment pipeline.
Core schemas provide a concise mechanism for schema documents to specify the metadata they provide. Metadata is grouped into features, which typically define directives and associated types (e.g. scalars and inputs which serve as directive inputs). Additionally, core schemas provide:
+
+
Flexible namespacing rules. It is always possible to represent any GraphQL schema within a core schema document. Additionally, documents can choose the names they use for the features they reference, guaranteeing that namespace collisions can always be resolved.
Core schemas are not a new language. All core schema documents are valid GraphQL schema documents. However, this specification introduces new requirements, so not all valid GraphQL schemas are valid core schemas.
+
The broad intention behind core schemas is to provide a single document which provides all the necessary configuration for programs that process and serve the schema to GraphQL clients, primarily by following directives in order to determine how to resolve queries made against that schema.
When talking about a core schema, we can broadly break it into two pieces:
+
+
an API consisting of schema elements (objects, interfaces, enums, directives, etc.) which SHOULD be served to clients, and
+
machinery containing document metadata. This typically consists of directives and associated input types (such as enums and input objects), but may include any schema element. Machinery MUST NOT be served to clients. Specifically, machinery MUST NOT be included in introspection responses or used to validate or execute queries.
+
+
This reflects how core schemas are used: a core schema contains a GraphQL interface (the API) along with metadata about how to implement that interface (the machinery). Exposing the machinery to clients is unnecessary, and may in some cases constitute a security issue (for example, the machinery for a public‐facing graph router will likely reference internal services, possibly exposing network internals which should not be visible to the general public).
+
A key feature of core schemas is that it is always possible to derive a core schema’s API without any knowledge of the features used by the document (with the exception of the core feature itself). Specifically, named elements are not included in the API schema if they are named something__likeThis or are a directive named @something, and something is the prefix of a feature declared with @core.
+
A formal description is provided by the IsInAPI algorithm.
Authors (either human or machine) write an initial core schema as specified in this document, including versioned @core requests for all directives they use
+
Machine processors can process core schemas and output new core schemas. The versioning of directives and associated schema elements provided by the @core allows processors to operate on directives they understand and pass through directives they do not.
+
Human readers can examine the core schema at various stages of processing. At any stage, they can examine the @core directives and follow URLs to the specification, receiving an explanation of the requirements of the specification and what new directives, types, and other schema objects are available within the document.
+
Data cores can then pick up the processed core schema and provide some data‐layer service with it. Typically this means serving the schema’s API as a GraphQL endpoint, using metadata defined by machinery to inform how it processes operations it receives. However, data cores may perform other tasks described in the core schema, such as routing to backend services, caching commonly‐accessed fields and queries, and so on. The term “data core” is intended to capture this multiplicity of possible activities.
3.1Unspecified directives are passed through by default
+
Existing schemas likely contain definitions for directives which are not versioned, have no specification document, and are intended mainly to be passed through. This is the default behavior for core schema processors:
schema
+ @core(feature:"https://specs.apollo.dev/core/v0.1")
+{
+ query:Query
+}
+
+typeSomeType{
+ field:Int@another
+}
+
+# `@another` is unspecified. Core processors will not extract metadata from
+# it, but its definition and all usages within the schema will be exposed
+# in the API.
+directive@anotheronFIELD_DEFINITION
+
+directive@core(feature:String!,as:String)repeatableonSCHEMA
+
All core schemas use the @core directive to declare their use of the core feature itself as well as any other core features they use.
+
In order to use these directives in your schema, GraphQL requires you to include their definitions in your schema.
+
Processors MUST validate that you have defined the directives with the same arguments, locations, and repeatable flag as given below. Specifically, the bootstrapping algorithm validates that the @core directive has a definition matching the definition given below. (The bootstrapping algorithm does not require processors to validate other aspects of the directive declaration such as description strings or argument ordering. The main purpose of this validation is to ensure that directive arguments have the type and default values expected by the specification.)
+
The following declares the directive defined by this specification. You SHOULD define the directives in your core schema by including the following text in your schema document.
When writing a specification for your own core feature, you SHOULD include a section like this one with sample definitions to copy into schemas, and you SHOULD require processors to validate that directive definitions in documents match your sample definitions.
A feature URL specifying the directive and associated schema elements. When viewed, the URL SHOULD provide the content of the appropriate version of the specification in some human‐readable form. In short, a human reader should be able to click the link and go to the docs for the version in use. There are specific requirements on the format of the URL, but it is not required that the content be machine‐readable in any particular way.
+
Feature URLs contain information about the spec’s prefix and version.
+
Feature URLs serve two main purposes:
+
+
Directing human readers to documentation about the feature
+
Providing tools with information about the specs in use, along with enough information to select and invoke an implementation
+
+
Feature URLs SHOULD be RFC 3986 URLs. When viewed, the URL SHOULD provide the specification of the selected version of the feature in some human‐readable form; a human reader should be able to click the link and go to the correct version of the docs.
+
Although they are not prohibited from doing so, it’s assumed that processors will not load the content of feature URLs. Published specifications are not required to be machine‐readable, and this spec places no requirements on the structure or syntax of the content to be found there.
+
There are, however, requirements on the structure of the URL itself:
The final two segments of the URL’s pathMUST contain the feature’s name and a version tag. The content of the URL up to and including the name—but excluding the / after the name and the version tag—is the feature’s identity. Trailing slashes at the end of the URL (ie, after the version tag) should be ignored. For the above example,
A global identifier for the feature. Processors can treat this as an opaque string identifying the feature (but not the version of the feature) for purposes of selecting an appropriate implementation. The identity never has a trailing /.
name: "exampleFeature"
The feature’s name, for purposes of prefixing schema elements it defines.
version: "v1.0"
The tag for the version of the feature used to author the document. Processors MUST select an implementation of the feature which can satisfy the specified version.
+
The version tag MUST be a valid VersionTag. The name MUST be a valid GraphQL name which does not include the namespace separator ("__").
When extracting the URL’s name and version, processors MUST ignore any url components which are not assigned a meaning. This spec assigns meaning to the final two segments of the path. Other URL components—particularly query strings and fragments, if present—MUST be ignored for the purposes of extracting the name and version.
5.1.1.2Why is versioning in the URL, not a directive argument?
+
The version is in the URL because when a human reader visits the URL, we would like them to be taken to the documentation for the version of the feature used by this document. Many text editors will turn URLs into hyperlinks, and it’s highly desirable that clicking the link takes the user to the correct version of the docs. Putting the version information in a separate argument to the @core directive would prevent this.
Change the names of directives and schema elements from this specification. The specified string MUST be a valid GraphQL name and MUST NOT contain the namespace separator (two underscores, "__") or end with an underscore.
+
When as: is provided, processors looking for prefixed schema elementsMUST look for elements whose names are the specified name with the prefix replaced with the name provided to the as: argument.
schema
+ @core(feature:"https://specs.apollo.dev/core/v0.1")
+ @core(feature:"https://spec.example.com/example/v1.0",as:"eg")
+{
+ query:Query
+}
+
+typeUser{
+ # Specifying `as: "eg"` transforms @example into @eg
+ name:String@eg(data:ITEM)
+}
+
+# Additional specified schema elements must have their prefixes set
+# to the new name.
+#
+# The spec at https://spec.example.com/example/v1.0 calls this enum
+# `example__Data`, but because of the `as:` argument above, processors
+# will use this `eg__Data` enum instead.
+enumeg__Data{
+ ITEM
+}
+
+# Name transformation must also be applied to definitions pulled in from
+# specifications.
+directive@eg(data:eg__Data)onFIELD_DEFINITION
+
+directive@core(feature:String!,as:String)repeatableonSCHEMA
+
MUST NOT contain the core namespace separator, which is two underscores ("__"), and
+
MUST NOT end with an underscore (which would create ambiguity between whether "x___y" is prefix x_ for element y or prefix x for element _y).
+
+
Prefixed names consist of the name of the feature, followed by two underscores, followed by the name of the element, which can be any valid GraphQL name. For instance, the core specification (which you are currently reading) introduces an element named @core, and the join specification introduces an element named @join__field (among others).
+
+Note
+that both parts must be valid GraphQL names, and GraphQL names cannot start with digits, so core feature specifications cannot introduce names like @feature__24hours.
+
A feature’s root directive is an exception to the prefixing requirements. Feature specifications MAY introduce a single directive which carries only the name of the feature, with no prefix required. For example, the core specification introduces a @core directive. This directive has the same name as the feature (”core”), and so requires no prefix.
schema
+ @core(feature:"https://specs.apollo.dev/core/v0.1")
+ @core(feature:"https://spec.example.com/example/v1.0"){
+ query:Query
+}
+
+typeUser{
+ name:String@example(data:ITEM)
+}
+
+# An enum used to provide structured data to the example spec.
+# It is prefixed with the name of the spec.
+enumexample__Data{
+ ITEM
+}
+
+directive@example(data:example__Data)onFIELD_DEFINITION
+
+directive@core(feature:String!,as:String)repeatableonSCHEMA
+
+
The prefix MUST NOT be elided within documentation; definitions of schema elements provided within the spec MUST include the feature’s name as a prefix.
schema
+ @core(feature:"https://specs.apollo.dev/core/v0.1")
+ @core(feature:"https://spec.example.com/featureA/v1.0")
+ @core(feature:"https://spec.example.com/featureB/v2.0",as:"B"){
+ query:Query
+}
+
+"""
+featureA__SomeType is a type defined by feature A.
+"""
+typefeatureA__SomeType{
+ """
+ nativeField is a field defined by featureA on a type also defined
+ by featureA (namely featureA__SomeType)
+ """
+ nativeField:Int@featureA__fieldDirective
+}
+
+"""
+featureA__SomeInput is an input specified by feature A
+"""
+inputfeatureA__SomeInput{
+ """
+ nativeInputField is defined by featureA
+ """
+ nativeInputField:Int
+}
+
+"""
+featureA__Items is specified by feature A
+"""
+enumfeatureA__Items{ONE,TWO,THREE@B}
+
+"""
+@B is the root directive defined by featureB
+
+Root directives are named after their feature
+"""
+directive@BonENUM_VALUE
+
+"""
+@featureA__fieldDirective is a non-root (prefixed) directive defined by featureA
+"""
+directive@featureA__fieldDirectiveonFIELD_DEFINITION
+
+directive@core(feature:String!,as:String)repeatableonSCHEMA
+
Specs are versioned with a subset of a Semantic Version Number containing only the major and minor parts. Thus, specifications SHOULD provide a version of the form vMajor.Minor, where both integers ≥ 0.
As specified by semver, spec authors SHOULD increment the:
+
+
MAJOR version when you make incompatible API changes,
+
MINOR version when you add functionality in a backwards compatible manner
+
+
+
Patch and pre‐release qualifiers are judged to be not particularly meaningful in the context of core features, which are (by definition) interfaces rather than implementations. The patch component of a semver denotes a bug fix which is backwards compatible—that is, a change to the implementation which does not affect the interface. Patch‐level changes in the version of a spec denote wording clarifications which do not require implementation changes. As such, it is not important to track them for the purposes of version resolution.
+
As with semver, the 0.x version series is special: there is no expectation of compatibility between versions 0.x and 0.y. For example, a processor must not activate implementation 0.4 to satisfy a requested version of 0.2.
Given a version requested by a document and an available version of an implementation, the following algorithm will determine if the available version can satisfy the requested version:
7.2Referencing versions and activating implementations
+
Schema documents MUST reference a feature version which supports all the schema elements and behaviors required by the document. As a practical matter, authors will generally prefer to reference a version they have reason to believe is supported by the most processors; depending on context, this might be an old stable version with a low major version, or a new less‐deprecated version with a large major version.
+
If a processor chooses to activate support for a feature, the processor MUST activate an implementation which can satisfy the version required by the document.
Processors MAY accept configuration which overrides these default behaviors.
+
Additionally, processors which prepare the schema for final public consumption MAY choose to eliminate all unknown directives and prefixed types in order to hide schema implementation details within the published schema. This will impair the operation of tooling which relies on these directives—such tools will not be able to run on the output schema, so the benefits and costs of this kind of information hiding should be weighed carefully on a case‐by‐case basis.
This section lays out algorithms for processing core schemas.
+
Algorithms described in this section may produce validation failures if a document does not conform to the requirements core schema document. Validation failures SHOULD halt processing. Some consumers, such as authoring tools, MAY attempt to continue processing in the presence of validation failures, but their behavior in such cases is unspecified.
Determine the name of the core specification within the document.
+
It is possible to rename the core feature within a document. This process determines the actual name for the core feature if one is present.
+
+
Fails the Has Schema validation if there are no SchemaDefinitions in the document
+
Fails the Has Core Feature validation if the core feature itself is not referenced with a @core directive within the document
+
Fails the Bootstrap Core Feature Listed First validation if the reference to the core feature is not the first @core directive on the document’s SchemaDefinition
+
Fails the Core Directive Incorrect Definition validation if the @core directive definition does not match the directive as defined by this specification.
+
+
For the purposes of this algorithm, a directive’s definition in a schema matches a definition provided in this specification if:
+
+
Its arguments have the specified names, types, and default values (or lack thereof)
+
It is defined as repeatable if and only if the specification’s definition defines it as repeatable
+
The set of locations it belongs to is the same set of locations in the specification’s definition.
+
+
The following aspects may differ between the definition in the schema and the definition in the specification without preventing the definitions from matching:
...if no SchemaDefinitions are present in document, the Has Schema validation fails.
+
+
+
For each directive d on schema,
+
If d has a feature: argument which parses as a feature URL, and whose identity is "https://specs.apollo.dev/core/"and whose version is "v0.1", and eitherd has an as: argument whose value is equal to d‘s name ord does not have an as: argument and d‘s name is core:
+
If any directive on schema listed before d has the same name as d, the Bootstrap Core Feature Listed First validation fails.
Collect a map of (featureName: String) → Directive, where Directive is a @core Directive which introduces the feature named featureName into the document.
+
+
Fails the Name Uniqueness validation if feature names are not unique within the document.
+
FailsInvalid Feature URL validation for any invalid feature URLs.
schema
+ @core(feature:"https://specs.apollo.dev/core/v0.1")
+ @core(feature:"https://specs.example.com/A/1.0")# name is A
+ @core(feature:"https://specs.example.com/A/2.0",as:"A2")# name is A2
+{
+ query:Query
+}
+
Without the explicit as:, the above would be invalid:
schema
+ @core(feature:"https://specs.apollo.dev/core/v0.1")
+ @core(feature:"https://specs.example.com/A/1.0")# name is A
+ @core(feature:"https://specs.example.com/A/2.0")# name is A
+{
+ query:Query
+}
+
Different specs with the same prefix are also invalid:
schema
+ @core(feature:"https://specs.apollo.dev/core/v0.1")
+ @core(feature:"https://specs.example.com/A/1.0")# name is A
+ @core(feature:"https://www.specs.com/specA/1.1",as:"A")# name is A
+{
+ query:Query
+}
Create a map of element: Any Named Element → feature: Directive | null, associating every named schema element within the document with a feature directive, or null if it is not associated with a feature.
Determine if any schema element is included in the API described by the core schema. A schema element is any part of a GraphQL document using type system definitions that has a name.
Let assignments be the result of assigning features to elements via AssignFeatures(document)
+
If assignments[element] is null, Returntrue
+
Else, Returnfalse
+
+
+
+Note
+Later versions of this specification may add other ways to affect the behavior of this algorithm, but those mechanisms will only be enabled if you reference those hypothetical versions of this specification.
+
+
+
diff --git a/core/v0.1/netlify.toml b/core/v0.1/netlify.toml
new file mode 100644
index 0000000..f1a19b0
--- /dev/null
+++ b/core/v0.1/netlify.toml
@@ -0,0 +1,6 @@
+# Netlify Admin: https://app.netlify.com/sites/apollo-specs-core/
+# Docs: https://docs.netlify.com/configure-builds/file-based-configuration/
+
+[build]
+ command = "npm run build"
+ publish = ".dist/"
diff --git a/core/v0.1/package.json b/core/v0.1/package.json
new file mode 100644
index 0000000..03a1ce4
--- /dev/null
+++ b/core/v0.1/package.json
@@ -0,0 +1,18 @@
+{
+ "name": "@apollo/core",
+ "version": "1.0.0",
+ "description": "for GraphQL schemas with extensible metadata",
+ "repository": "https://github.com/apollo-specs/core",
+ "main": "index.js",
+ "scripts": {
+ "build": "rsync -avz --exclude .dist . .dist && spec-md core.spec.md > .dist/index.html"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "devDependencies": {
+ "@queerviolet/speck": "git://github.com/queerviolet/speck.git#main",
+ "chokidar-cli": "^2.1.0",
+ "watch": "^1.0.2"
+ }
+}
diff --git a/core/v0.1/prefix-uniqueness.graphql b/core/v0.1/prefix-uniqueness.graphql
new file mode 100644
index 0000000..a26a309
--- /dev/null
+++ b/core/v0.1/prefix-uniqueness.graphql
@@ -0,0 +1,25 @@
+schema
+ @core(feature: "https://specs.apollo.dev/core/v0.1")
+ @core(feature: "https://specs.example.com/A/1.0") # name is A
+ @core(feature: "https://specs.example.com/A/2.0", as: "A2") # name is A2
+{
+ query: Query
+}
+
+schema
+ @core(feature: "https://specs.apollo.dev/core/v0.1")
+ @core(feature: "https://specs.example.com/A/1.0") # name is A
+ @core(feature: "https://specs.example.com/A/2.0") # name is A
+{
+ query: Query
+}
+
+schema
+ @core(feature: "https://specs.apollo.dev/core/v0.1")
+ @core(feature: "https://specs.example.com/A/1.0") # name is A
+ @core(feature: "https://www.specs.com/specA/1.1", as: "A") # name is A
+{
+ query: Query
+}
+
+directive @core(feature: String!, as: String) repeatable on SCHEMA
diff --git a/core/v0.1/prefixing.graphql b/core/v0.1/prefixing.graphql
new file mode 100644
index 0000000..12c5da7
--- /dev/null
+++ b/core/v0.1/prefixing.graphql
@@ -0,0 +1,46 @@
+schema
+ @core(feature: "https://specs.apollo.dev/core/v0.1")
+ @core(feature: "https://spec.example.com/featureA/v1.0")
+ @core(feature: "https://spec.example.com/featureB/v2.0", as: "B") {
+ query: Query
+}
+
+"""
+featureA__SomeType is a type defined by feature A.
+"""
+type featureA__SomeType {
+ """
+ nativeField is a field defined by featureA on a type also defined
+ by featureA (namely featureA__SomeType)
+ """
+ nativeField: Int @featureA__fieldDirective
+}
+
+"""
+featureA__SomeInput is an input specified by feature A
+"""
+input featureA__SomeInput {
+ """
+ nativeInputField is defined by featureA
+ """
+ nativeInputField: Int
+}
+
+"""
+featureA__Items is specified by feature A
+"""
+enum featureA__Items { ONE, TWO, THREE @B }
+
+"""
+@B is the root directive defined by featureB
+
+Root directives are named after their feature
+"""
+directive @B on ENUM_VALUE
+
+"""
+@featureA__fieldDirective is a non-root (prefixed) directive defined by featureA
+"""
+directive @featureA__fieldDirective on FIELD_DEFINITION
+
+directive @core(feature: String!, as: String) repeatable on SCHEMA
diff --git a/core/v0.2/.gitignore b/core/v0.2/.gitignore
new file mode 100644
index 0000000..b768a31
--- /dev/null
+++ b/core/v0.2/.gitignore
@@ -0,0 +1,3 @@
+node_modules
+.dist
+package-lock.json
\ No newline at end of file
diff --git a/core/v0.2/bad-non-unique-prefix-multi.graphql b/core/v0.2/bad-non-unique-prefix-multi.graphql
new file mode 100644
index 0000000..221f3e4
--- /dev/null
+++ b/core/v0.2/bad-non-unique-prefix-multi.graphql
@@ -0,0 +1,9 @@
+schema
+ @core(feature: "https://specs.apollo.dev/core/v0.1")
+ @core(feature: "https://specs.example.com/A/1.0") # name is A
+ @core(feature: "https://specs.example.com/A/2.0") # name is A
+{
+ query: Query
+}
+
+directive @core(feature: String!, as: String) repeatable on SCHEMA
diff --git a/core/v0.2/bad-non-unique-prefix.graphql b/core/v0.2/bad-non-unique-prefix.graphql
new file mode 100644
index 0000000..749db43
--- /dev/null
+++ b/core/v0.2/bad-non-unique-prefix.graphql
@@ -0,0 +1,9 @@
+schema
+ @core(feature: "https://specs.apollo.dev/core/v0.1")
+ @core(feature: "https://specs.example.com/A/1.0") # name is A
+ @core(feature: "https://www.specs.com/specA/1.1", as: "A") # name is A
+{
+ query: Query
+}
+
+directive @core(feature: String!, as: String) repeatable on SCHEMA
diff --git a/core/v0.2/basic.graphql b/core/v0.2/basic.graphql
new file mode 100644
index 0000000..454191b
--- /dev/null
+++ b/core/v0.2/basic.graphql
@@ -0,0 +1,14 @@
+schema
+ @core(feature: "https://specs.apollo.dev/core/v0.1")
+ @core(feature: "https://specs.example.com/example/v1.0")
+{
+ query: Query
+}
+
+type Query {
+ field: Int @example
+}
+
+directive @example on FIELD_DEFINITION
+
+directive @core(feature: String!, as: String) repeatable on SCHEMA
diff --git a/core/v0.2/core-v0.2.md b/core/v0.2/core-v0.2.md
new file mode 100644
index 0000000..ff1aa04
--- /dev/null
+++ b/core/v0.2/core-v0.2.md
@@ -0,0 +1,577 @@
+# Core Schemas
+
+
flexible metadata for GraphQL schemas
+
+```raw html
+
+
Status
Release
+
Version
0.2
+
+
+
+```
+
+[GraphQL](https://spec.graphql.org/) provides directives as a means of attaching user-defined metadata to a GraphQL document. Directives are highly flexible, and can be used to suggest behavior and define features of a graph which are not otherwise evident in the schema.
+
+Alas, *GraphQL does not provide a mechanism to globally identify or version directives*. Given a particular directive—e.g. `@join`—processors are expected to know how to interpret the directive based only on its name, definition within the document, and additional configuration from outside the document. This means that programs interpreting these directives have two options:
+
+ 1. rely on a hardcoded interpretation for directives with certain signatures, or
+ 2. accept additional configuration about how to interpret directives in the schema.
+
+The first solution is fragile, particularly as GraphQL has no built-in namespacing mechanisms, so the possibility of name collisions always looms.
+
+The second is unfortunate: GraphQL schemas are generally intended to be self-describing, and requiring additional configuration subtly undermines this guarantee: given just a schema, programs do not necessarily know how to interpret it, and certainly not how to serve it. It also creates the possibility for the schema and configuration to fall out of sync, leading to issues which can manifest late in a deployment pipeline.
+
+Introducing **core schemas**.
+
+```html diagram
+
+
+```
+
+A basic core schema:
+
+:::[example](basic.graphql) -- A basic core schema
+
+**Core schemas** provide a concise mechanism for schema documents to specify the metadata they provide. Metadata is grouped into **features**, which typically define directives and associated types (e.g. scalars and inputs which serve as directive inputs). Additionally, core schemas provide:
+ - [**Flexible namespacing rules.**](#sec-Prefixing) It is always possible to represent any GraphQL schema within a core schema document. Additionally, documents can [choose the names](#@core/as) they use for the features they reference, guaranteeing that namespace collisions can always be resolved.
+ - [**Versioning.**](#sec-Versioning) Feature specifications follow [semver-like semantic versioning principles](#sec-Versioning), which helps schema processors determine if they are able to correctly interpret a document's metadata.
+
+**Core schemas are not a new language.** All core schema documents are valid GraphQL schema documents. However, this specification introduces new requirements, so not all valid GraphQL schemas are valid core schemas.
+
+The broad intention behind core schemas is to provide a *single document* which provides all the necessary configuration for programs that process and serve the schema to GraphQL clients, primarily by following directives in order to determine how to resolve queries made against that schema.
+
+# Parts of a Core Schema
+
+When talking about a core schema, we can broadly break it into two pieces:
+- an **API** consisting of schema elements (objects, interfaces, enums, directives, etc.) which SHOULD be served to clients, and
+- **machinery** containing document metadata. This typically consists of directives and associated input types (such as enums and input objects), but may include any schema element. Machinery MUST NOT be served to clients. Specifically, machinery MUST NOT be included in introspection responses or used to validate or execute queries.
+
+This reflects how core schemas are used: a core schema contains a GraphQL interface (the *API*) along with metadata about how to implement that interface (the *machinery*). Exposing the machinery to clients is unnecessary, and may in some cases constitute a security issue (for example, the machinery for a public-facing graph router will likely reference internal services, possibly exposing network internals which should not be visible to the general public).
+
+A key feature of core schemas is that it is always possible to derive a core schema's API without any knowledge of the features used by the document (with the exception of the `core` feature itself). Specifically, named elements are not included in the API schema if they are named `something__likeThis` or are a directive named `@something`, and `something` is the prefix of a feature declared with {@core}.
+
+A formal description is provided by the [IsInAPI](#sec-Is-In-API-) algorithm.
+
+# Actors
+
+```mermaid diagram -- Actors who may be interested in the core schemas
+graph TB
+ classDef bg fill:none,color:#22262E;
+ author("👩🏽💻 🤖 Author"):::bg-->schema(["☉ Core Schema"]):::bg
+ schema-->proc1("🤖 Processor"):::bg
+ proc1-->output1(["☉ Core Schema[0]"]):::bg
+ output1-->proc2("🤖 Processor"):::bg
+ proc2-->output2(["☉ Core Schema[1]"]):::bg
+ output2-->etc("..."):::bg
+ etc-->final(["☉ Core Schema [final]"]):::bg
+ final-->core("🤖 Data Core"):::bg
+ schema-->reader("👩🏽💻 Reader"):::bg
+ output1-->reader
+ output2-->reader
+ final-->reader
+```
+
+- **Authors (either human or machine)** write an initial core schema as specified in this document, including versioned {@core} requests for all directives they use
+- **Machine processors** can process core schemas and output new core schemas. The versioning of directives and associated schema elements provided by the {@core} allows processors to operate on directives they understand and pass through directives they do not.
+- **Human readers** can examine the core schema at various stages of processing. At any stage, they can examine the {@core} directives and follow URLs to the specification, receiving an explanation of the requirements of the specification and what new directives, types, and other schema objects are available within the document.
+- **Data cores** can then pick up the processed core schema and provide some data-layer service with it. Typically this means serving the schema's API as a GraphQL endpoint, using metadata defined by machinery to inform how it processes operations it receives. However, data cores may perform other tasks described in the core schema, such as routing to backend services, caching commonly-accessed fields and queries, and so on. The term "data core" is intended to capture this multiplicity of possible activities.
+
+# Basic Requirements
+
+Core schemas:
+ 1. MUST be valid GraphQL schema documents,
+ 2. MUST contain exactly one `SchemaDefinition`, and
+ 3. MUST use the {@core} directive on their schema definition to declare any features they reference by using {@core} to reference a [well-formed feature URL](#@core/feature).
+
+The first {@core} directive on the schema MUST reference the core spec itself, i.e. this document.
+
+:::[example](basic.graphql) -- Basic core schema using {@core} and `@example`
+
+## Unspecified directives are passed through by default
+
+Existing schemas likely contain definitions for directives which are not versioned, have no specification document, and are intended mainly to be passed through. This is the default behavior for core schema processors:
+
+```graphql example -- Unspecified directives are passed through
+schema
+ @core(feature: "https://specs.apollo.dev/core/v0.1")
+{
+ query: Query
+}
+
+type SomeType {
+ field: Int @another
+}
+
+# `@another` is unspecified. Core processors will not extract metadata from
+# it, but its definition and all usages within the schema will be exposed
+# in the API.
+directive @another on FIELD_DEFINITION
+
+directive @core(feature: String!, as: String) repeatable on SCHEMA
+```
+
+## Renaming core itself
+
+It is possible to rename the core feature itself with the same [`as:`](#@core/as) mechanism used for all features:
+
+```graphql example -- Renaming {@core} to {@coreSchema}
+schema
+ @coreSchema(feature: "https://specs.apollo.dev/core/v0.1", as: "coreSchema")
+ @coreSchema(feature: "https://example.com/example/v1.0")
+{
+ query: Query
+}
+
+type SomeType {
+ field: Int @example
+}
+
+directive @coreSchema(feature: String!, as: String)
+ repeatable on SCHEMA
+directive @example on FIELD_DEFINITION
+```
+
+# Directive Definitions
+
+All core schemas use the [{@core}](#@core) directive to declare their use of the `core` feature itself as well as any other core features they use.
+
+In order to use these directives in your schema, GraphQL requires you to include their definitions in your schema.
+
+Processors MUST validate that you have defined the directives with the same arguments, locations, and `repeatable` flag as given below. Specifically, the [bootstrapping](#sec-Bootstrapping) algorithm validates that the `@core` directive has a definition matching the definition given below. (The bootstrapping algorithm does not require processors to validate other aspects of the directive declaration such as description strings or argument ordering. The main purpose of this validation is to ensure that directive arguments have the type and default values expected by the specification.)
+
+The following declares the directive defined by this specification. You SHOULD define the directives in your core schema by including the following text in your schema document.
+
+```graphql
+directive @core(feature: String!, as: String) repeatable on SCHEMA
+```
+
+When writing a specification for your own core feature, you SHOULD include a section like this one with sample definitions to copy into schemas, and you SHOULD require processors to validate that directive definitions in documents match your sample definitions.
+
+# Directives
+
+##! @core
+
+Declare a core feature present in this schema.
+
+```graphql definition
+directive @core(
+ feature: String!,
+ as: String,
+ for: core__Purpose)
+ repeatable on SCHEMA
+```
+
+Documents MUST include a definition for the {@core} directive which includes all of the arguments defined above with the same types and default values.
+
+###! feature: String!
+
+A feature URL specifying the directive and associated schema elements. When viewed, the URL SHOULD provide the content of the appropriate version of the specification in some human-readable form. In short, a human reader should be able to click the link and go to the docs for the version in use. There are specific requirements on the format of the URL, but it is not required that the *content* be machine-readable in any particular way.
+
+Feature URLs contain information about the spec's [prefix](#sec-Prefixing) and [version](#sec-Versioning).
+
+Feature URLs serve two main purposes:
+ - Directing human readers to documentation about the feature
+ - Providing tools with information about the specs in use, along with enough information to select and invoke an implementation
+
+Feature URLs SHOULD be [RFC 3986 URLs](https://tools.ietf.org/html/rfc3986). When viewed, the URL SHOULD provide the specification of the selected version of the feature in some human-readable form; a human reader should be able to click the link and go to the correct version of the docs.
+
+Although they are not prohibited from doing so, it's assumed that processors will not load the content of feature URLs. Published specifications are not required to be machine-readable, and [this spec](.) places no requirements on the structure or syntax of the content to be found there.
+
+There are, however, requirements on the structure of the URL itself:
+
+```html diagram -- Basic anatomy of a feature URL
+
+ https://spec.example.com/a/b/c/exampleFeature/v1.0
+
+```
+
+The final two segments of the URL's [path](https://tools.ietf.org/html/rfc3986#section-3.3) MUST contain the feature's name and a [version tag](#sec-Versioning). The content of the URL up to and including the name—but excluding the `/` after the name and the version tag—is the feature's *identity*. Trailing slashes at the end of the URL (ie, after the version tag) should be ignored. For the above example,
+
A global identifier for the feature. Processors can treat this as an opaque string identifying the feature (but not the version of the feature) for purposes of selecting an appropriate implementation. The identity never has a trailing `/`.
+
`name: "exampleFeature"`
+
The feature's name, for purposes of [prefixing](#sec-Prefixing) schema elements it defines.
+
`version: "v1.0"`
+
The tag for the [version](#sec-Versioning) of the feature used to author the document. Processors MUST select an implementation of the feature which can [satisfy](#sec-Satisfaction) the specified version.
+
+
+The version tag MUST be a valid {VersionTag}. The name MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name) which does not include the namespace separator ({"__"}).
+
+#### Ignore meaningless URL components
+
+When extracting the URL's `name` and `version`, processors MUST ignore any url components which are not assigned a meaning. This spec assigns meaning to the final two segments of the [path](https://tools.ietf.org/html/rfc3986#section-3.3). Other URL components—particularly query strings and fragments, if present—MUST be ignored for the purposes of extracting the `name` and `version`.
+
+```html diagram -- Ignoring meaningless parts of a URL
+
+ https://example.com/exampleSpec/v1.0/?key=val&k2=v2#frag
+
+```
+
+#### Why is versioning in the URL, not a directive argument?
+
+The version is in the URL because when a human reader visits the URL, we would like them to be taken to the documentation for the *version of the feature used by this document*. Many text editors will turn URLs into hyperlinks, and it's highly desirable that clicking the link takes the user to the correct version of the docs. Putting the version information in a separate argument to the {@core} directive would prevent this.
+
+###! as: String
+
+Change the [names](#sec-Prefixing) of directives and schema elements from this specification. The specified string MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name) and MUST NOT contain the namespace separator (two underscores, {"__"}) or end with an underscore.
+
+When [`as:`](#@core/as) is provided, processors looking for [prefixed schema elements](#sec-Elements-which-must-be-prefixed) MUST look for elements whose names are the specified name with the prefix replaced with the name provided to the `as:` argument.
+
+```graphql example -- Using {@core}(feature:, as:) to use a feature with a custom name
+schema
+ @core(feature: "https://specs.apollo.dev/core/v0.1")
+ @core(feature: "https://spec.example.com/example/v1.0", as: "eg")
+{
+ query: Query
+}
+
+type User {
+ # Specifying `as: "eg"` transforms @example into @eg
+ name: String @eg(data: ITEM)
+}
+
+# Additional specified schema elements must have their prefixes set
+# to the new name.
+#
+# The spec at https://spec.example.com/example/v1.0 calls this enum
+# `example__Data`, but because of the `as:` argument above, processors
+# will use this `eg__Data` enum instead.
+enum eg__Data {
+ ITEM
+}
+
+# Name transformation must also be applied to definitions pulled in from
+# specifications.
+directive @eg(data: eg__Data) on FIELD_DEFINITION
+
+directive @core(feature: String!, as: String) repeatable on SCHEMA
+```
+
+###! for: core__Purpose
+
+An optional [purpose](#core__Purpose) for this feature. This hints to consumers as to whether they can safely ignore metadata from a given feature.
+
+By default, core features SHOULD fail open. This means that an unknown feature SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
+
+This behavior is different for features with a specified purpose:
+ - [`SECURITY`](#core__Purpose/SECURITY) features convey metadata necessary to securely resolve fields within the schema
+ - [`EXECUTION`](#core__Purpose/EXECUTION) features convey metadata necessary to correctly resolve fields within the schema
+
+# Enums
+
+##! core__Purpose
+
+```graphql definition
+enum core__Purpose {
+ SECURITY
+ EXECUTION
+}
+```
+
+The role of a feature referenced with {@core}.
+
+This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail-open behavior of core schema consumers is undesirable.
+
+Note we'll refer to directives from features which are `for: SECURITY` or `for: EXECUTION` as "`SECURITY` directives" and "`EXECUTION` directives", respectively.
+
+###! SECURITY
+
+`SECURITY` features provide metadata necessary to securely resolve fields. For instance, a hypothetical {auth} feature may provide an {@auth} directive to flag fields which require authorization. If a data core does not support the {auth} feature and serves those fields anyway, these fields will be accessible without authorization, compromising security.
+
+Security-conscious consumers MUST NOT serve a field if:
+ - the schema definition has **any** unsupported SECURITY directives,
+ - the field's parent type definition has **any** unsupported SECURITY directives,
+ - the field's return type definition has **any** unsupported SECURITY directives, or
+ - the field definition has **any** unsupported SECURITY directives
+
+Such fields are *not securely resolvable*. Security-conscious consumers MAY serve schemas with fields which are not securely resolvable. However, they MUST remove such fields from the schema before serving it.
+
+Less security-conscious consumers MAY choose to relax these requirements. For instance, servers may provide a development mode in which unknown SECURITY directives are ignored, perhaps with a warning. Such software may also provide a way to explicitly disable some or all SECURITY features during development.
+
+More security-conscious consumers MAY choose to enhance these requirements. For instance, production servers MAY adopt a policy of entirely rejecting any schema which contains ANY unsupported SECURITY features, even if those features are never used to annotate the schema.
+
+###! EXECUTION
+
+`EXECUTION` features provide metadata necessary to correctly resolve fields. For instance, a hypothetical {ts} feature may provide a `@ts__resolvers` annotation which references a TypeScript module of field resolvers. A consumer which does not support the {ts} feature will be unable to correctly resolve such fields.
+
+Consumers MUST NOT serve a field if:
+ - the schema's definition has **any** unsupported EXECUTION directives,
+ - the field's parent type definition has **any** unsupported EXECUTION directives,
+ - the field's return type definition has **any** unsupported EXECUTION directives, or
+ - the field definition has **any** unsupported EXECUTION directives
+
+Such fields are *unresolvable*. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION features, even if those features are never used in the schema.
+
+# Prefixing
+
+With the exception of a single root directive, core feature specifications MUST prefix all schema elements they introduce. The prefix:
+ 1. MUST match the name of the feature as derived from the feature's specification URL,
+ 2. MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name), and
+ 3. MUST NOT contain the core namespace separator, which is two underscores ({"__"}), and
+ 4. MUST NOT end with an underscore (which would create ambiguity between whether {"x___y"} is prefix `x_` for element `y` or prefix `x` for element `_y`).
+
+Prefixed names consist of the name of the feature, followed by two underscores, followed by the name of the element, which can be any valid [GraphQL name](https://spec.graphql.org/draft/#Name). For instance, the `core` specification (which you are currently reading) introduces an element named [{@core}](#@core), and the `join` specification introduces an element named {@join__field} (among others).
+
+Note that both parts must be valid GraphQL names, and GraphQL names cannot start with digits, so core feature specifications cannot introduce names like `@feature__24hours`.
+
+A feature's *root directive* is an exception to the prefixing requirements. Feature specifications MAY introduce a single directive which carries only the name of the feature, with no prefix required. For example, the `core` specification introduces a {@core} directive. This directive has the same name as the feature ("`core`"), and so requires no prefix.
+
+```graphql example -- Using the @core directive without changing the prefix
+schema
+ @core(feature: "https://specs.apollo.dev/core/v0.1")
+ @core(feature: "https://spec.example.com/example/v1.0") {
+ query: Query
+}
+
+type User {
+ name: String @example(data: ITEM)
+}
+
+# An enum used to provide structured data to the example spec.
+# It is prefixed with the name of the spec.
+enum example__Data {
+ ITEM
+}
+
+directive @example(data: example__Data) on FIELD_DEFINITION
+
+directive @core(feature: String!, as: String) repeatable on SCHEMA
+```
+
+The prefix MUST NOT be elided within documentation; definitions of schema elements provided within the spec MUST include the feature's name as a prefix.
+
+## Elements which must be prefixed
+
+Feature specs MUST prefix the following schema elements:
+ - the names of any object types, interfaces, unions, enums, or input object types defined by the feature
+ - the names of any directives introduced in the spec, with the exception of the *root directive*, which must have the same name as the feature
+
+:::[example](prefixing.graphql) -- Prefixing
+
+# Versioning
+
+VersionTag : "v" Version
+
+Version : Major "." Minor
+
+Major : NumericIdentifier
+
+Minor : NumericIdentifier
+
+NumericIdentifier : "0"
+ | PositiveDigit Digit*
+
+Digit : "0" | PositiveDigit
+
+PositiveDigit : "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
+
+Specs are versioned with a **subset** of a [Semantic Version Number](https://semver.org/spec/v2.0.0.html) containing only the major and minor parts. Thus, specifications SHOULD provide a version of the form `v`{Major}`.`{Minor}, where both integers >= 0.
+
+```text example -- Valid version tags
+v2.2
+v1.0
+v1.1
+v0.1
+```
+
+As specified by semver, spec authors SHOULD increment the:
+
+{++
+
+- MAJOR version when you make incompatible API changes,
+- MINOR version when you add functionality in a backwards compatible manner
+
+++}
+
+Patch and pre-release qualifiers are judged to be not particularly meaningful in the context of core features, which are (by definition) interfaces rather than implementations. The patch component of a semver denotes a bug fix which is backwards compatible—that is, a change to the implementation which does not affect the interface. Patch-level changes in the version of a spec denote wording clarifications which do not require implementation changes. As such, it is not important to track them for the purposes of version resolution.
+
+As with [semver](https://semver.org/spec/v2.0.0.html), the `0.x` version series is special: there is no expectation of compatibility between versions `0.x` and `0.y`. For example, a processor must not activate implementation `0.4` to satisfy a requested version of `0.2`.
+
+## Satisfaction
+
+Given a version {requested} by a document and an {available} version of an implementation, the following algorithm will determine if the {available} version can satisfy the {requested} version:
+
+Satisfies(requested, available) :
+ 1. If {requested}.{Major} ≠ {available}.{Major}, return {false}
+ 2. If {requested}.{Major} = 0, return {requested}.{Minor} = {available}.{Minor}
+ 3. Return {requested}.{Minor} <= {available}.{Minor}
+
+## Referencing versions and activating implementations
+
+Schema documents MUST reference a feature version which supports all the schema elements and behaviors required by the document. As a practical matter, authors will generally prefer to reference a version they have reason to believe is supported by the most processors; depending on context, this might be an old stable version with a low major version, or a new less-deprecated version with a large major version.
+
+If a processor chooses to activate support for a feature, the processor MUST activate an implementation which can [satisfy](#sec-Satisfaction) the version required by the document.
+
+
+# Processing Schemas
+
+```mermaid diagram
+graph LR
+ schema(["📄 Input Schema"]):::file-->proc("🤖 Processor")
+ proc-->output(["📄 Output Schema"]):::file
+ classDef file fill:none,color:#22262E;
+ style proc fill:none,stroke:fuchsia,color:fuchsia;
+```
+
+A common use case is that of a processor which consumes a valid input schema and generates an output schema.
+
+The general guidance for processor behavior is: don't react to what you don't understand.
+
+Specifically, processors:
+ - SHOULD pass through {@core} directives which reference unknown feature URLs
+ - SHOULD pass through prefixed directives, types, and other schema elements
+ - SHOULD pass through directives which are not [associated with](#AssignFeatures) a {@core} feature
+
+Processors MAY accept configuration which overrides these default behaviors.
+
+Additionally, processors which prepare the schema for final public consumption MAY choose to eliminate all unknown directives and prefixed types in order to hide schema implementation details within the published schema. This will impair the operation of tooling which relies on these directives—such tools will not be able to run on the output schema, so the benefits and costs of this kind of information hiding should be weighed carefully on a case-by-case basis.
+
+# Validations & Algorithms
+
+This section lays out algorithms for processing core schemas.
+
+Algorithms described in this section may produce *validation failures* if a document does not conform to the requirements core schema document. Validation failures SHOULD halt processing. Some consumers, such as authoring tools, MAY attempt to continue processing in the presence of validation failures, but their behavior in such cases is unspecified.
+
+## Bootstrapping
+
+Determine the name of the core specification within the document.
+
+It is possible to [rename the core feature](#sec-Renaming-core-itself) within a document. This process determines the actual name for the core feature if one is present.
+
+- **Fails** the *Has Schema* validation if there are no SchemaDefinitions in the document
+- **Fails** the *Has Core Feature* validation if the `core` feature itself is not referenced with a {@core} directive within the document
+- **Fails** the *Bootstrap Core Feature Listed First* validation if the reference to the `core` feature is not the first {@core} directive on the document's SchemaDefinition
+- **Fails** the *Core Directive Incorrect Definition* validation if the {@core} directive definition does not *match* the directive as defined by this specification.
+
+For the purposes of this algorithm, a directive's definition in a schema *matches* a definition provided in this specification if:
+- Its arguments have the specified names, types, and default values (or lack thereof)
+- It is defined as `repeatable` if and only if the specification's definition defines it as `repeatable`
+- The set of locations it belongs to is the same set of locations in the specification's definition.
+
+The following aspects may differ between the definition in the schema and the definition in the specification without preventing the definitions from *matching*:
+- The name of the directive (due to [prefixing](#sec-Prefixing))
+- The order of arguments
+- The order of locations
+- The directive's description string
+- Argument description strings
+- Directives applied to argument definitions
+
+Bootstrap(document) :
+1. Let {schema} be the only SchemaDefinition in {document}. (Note that legal GraphQL documents [must include at most one SchemaDefinition](http://spec.graphql.org/draft/#sec-Root-Operation-Types).)
+ 1. ...if no SchemaDefinitions are present in {document}, the ***Has Schema* validation fails**.
+1. For each directive {d} on {schema},
+ 1. If {d} has a [`feature:`](#@core/feature) argument which [parses as a feature URL](#@core/feature), *and* whose identity is {"https://specs.apollo.dev/core/"} *and* whose version is {"v0.1"}, *and either* {d} has an [`as:`](#@core/as) argument whose value is equal to {d}'s name *or* {d} does not have an [`as:`](#@core/as) argument and {d}'s name is `core`:
+ - If any directive on {schema} listed before {d} has the same name as {d}, the ***Bootstrap Core Feature Listed First* validation fails**.
+ - If the definition of the directive {d} does not *match* the [definition of {@core} in this specification](#@core), the ***Core Directive Incorrect Definition* validation fails**.
+ - Otherwise, **Return** {d}'s name.
+- If no matching directive was found, the ***Has Core Feature* validation fails**.
+
+## Feature Collection
+
+Collect a map of ({featureName}: `String`) -> `Directive`, where `Directive` is a {@core} Directive which introduces the feature named {featureName} into the document.
+
+- **Fails** the *Name Uniqueness* validation if feature names are not unique within the document.
+- **Fails** *Invalid Feature URL* validation for any invalid feature URLs.
+
+CollectFeatures(document) :
+ - Let {coreName} be the name of the core feature found via {Bootstrap(document)}
+ - Let {features} be a map of {featureName}: `String` -> `Directive`, initially empty.
+ - For each directive {d} named {coreName} on the SchemaDefinition within {document},
+ - Let {specifiedFeatureName} and {version} be the result of parsing {d}'s `feature:` argument according to the [specified rules for feature URLs](#@core/feature)
+ - If the `feature:` is not present or fails to parse:
+ - The ***Invalid Feature URL* validation fails** for {d},
+ - Let {featureName} be the {d}'s [`as:`](#@core/as) argument or, if the argument is not present, {specifiedFeatureName}
+ - If {featureName} exists within {features}, the ***Name Uniqueness* validation fails**.
+ - Insert {featureName} => {d} into {features}
+ - **Return** {features}
+
+
+Prefixes, whether implicit or explicit, must be unique within a document. Valid:
+
+:::[example](prefixing.graphql#schema[0]) -- Unique prefixes
+
+It is also valid to reference multiple versions of the same spec under different prefixes:
+
+:::[example](prefix-uniqueness.graphql#schema[0]) -- Explicit prefixes allow multiple versions of the same spec to coexist within a Document
+
+Without the explicit [`as:`](#@core/as), the above would be invalid:
+
+:::[counter-example](prefix-uniqueness.graphql#schema[1]) -- Non-unique prefixes with multiple versions of the same spec
+
+Different specs with the same prefix are also invalid:
+
+:::[counter-example](prefix-uniqueness.graphql#schema[2]) -- Different specs with non-unique prefixes
+
+## Assign Features
+
+Create a map of {element}: *Any Named Element* -> {feature}: `Directive` | {null}, associating every named schema element within the document with a feature directive, or {null} if it is not associated with a feature.
+
+AssignFeatures(document) :
+ - Let {features} be the result of collecting features via {CollectFeatures(document)}
+ - Let {assignments} be a map of ({element}: *Any Named Element*) -> {feature}: `Directive` | {null}, initally empty
+ - For each named schema element {e} within the {document}
+ - Let {name} be the name of the {e}
+ - If {e} is a Directive and {name} is a key within {features},
+ - Insert {e} => {features}`[`{name}`]` into {assignments}
+ - **Continue** to next {e}
+ - If {name} begins with {"__"},
+ - Insert {e} => {null} into {assignments}
+ - **Continue** to next {e}
+ - If {name} contains the substring {"__"},
+ - Partition {name} into `[`{prefix}, {base}`]` at the first {"__"} (that is, find the shortest {prefix} and longest {base} such that {name} = {prefix} + {"__"} + {base})
+ - If {prefix} exists within {features}, insert {e} => {features}`[`{prefix}`]` into {assignments}
+ - Else, insert {e} => {null} into {assignments}
+ - **Continue** to next {e}
+ - Insert {e} => {null} into {assignments}
+ - **Return** {assignments}
+
+## Is In API?
+
+Determine if any schema element is included in the [API](#sec-Parts-of-a-Core-Schema) described by the core schema. A schema element is any part of a GraphQL document using type system definitions that has a [name](https://spec.graphql.org/draft/#Name).
+
+IsInAPI(element) :
+ - Let {assignments} be the result of assigning features to elements via {AssignFeatures(document)}
+ - If {assignments}`[`{element}`]` is {null}, **Return** {true}
+ - Else, **Return** {false}
+
+Note: Later versions of this specification may add other ways to affect the behavior of this algorithm, but those mechanisms will only be enabled if you reference those hypothetical versions of this specification.
+
+## Is Affected By Feature?
+
+Determine if a schema element is *affected* by a given feature.
+
+IsAffected(element, feature):
+ - Let {assignments} be the result of assigning features to elements via {AssignFeatures(document)}
+ - For each directive {d} on {element}, If {assignments}`[`{d}`]` is {feature}, **Return** {true}
+ - If {element} is a FieldDefinition,
+ - Let {parent} be the parent ObjectDefinition or InterfaceDefinition for {element}
+ - If {IsAffected(parent, feature)}, **Return** {true}
+ - For each argument type {a} declared on {element},
+ - Let {t} be the InputDefinition, EnumDefinition, or ScalarDefinition for argument {a}
+ - If {IsAffected(t, feature)}, **Return** {true}
+ - Let {return} be the ObjectDefinition, InterfaceDefinition, or UnionDefinition for {element}'s return type
+ - If {IsAffected(return, feature)}, **Return** {true}
+ - If {element} is an InputDefinition,
+ - For each InputFieldDefinition {field} within {element},
+ - Let {t} be the InputDefinition, EnumDefinition, or ScalarDefinition for the type of {field}
+ - If {IsAffected(t, feature)}, **Return** {true}
+ - If {element} is an EnumDefinition,
+ - For each EnumValueDefinition {value} in {element},
+ - If {IsAffected(value, feature)}, **Return** {true}
+
+
+
diff --git a/core/v0.2/good-unique-prefix-multi.graphql b/core/v0.2/good-unique-prefix-multi.graphql
new file mode 100644
index 0000000..8eafe08
--- /dev/null
+++ b/core/v0.2/good-unique-prefix-multi.graphql
@@ -0,0 +1,9 @@
+schema
+ @core(feature: "https://specs.apollo.dev/core/v0.1")
+ @core(feature: "https://specs.example.com/A/1.0") # name is A
+ @core(feature: "https://specs.example.com/A/2.0", as: "A2") # name is A2
+{
+ query: Query
+}
+
+directive @core(feature: String!, as: String) repeatable on SCHEMA
diff --git a/core/v0.2/index.html b/core/v0.2/index.html
new file mode 100644
index 0000000..b981165
--- /dev/null
+++ b/core/v0.2/index.html
@@ -0,0 +1,1829 @@
+
+
+
+
+Core Schemas
+
+
+
+
+
+
+
+
Core Schemas
+
+
flexible metadata for GraphQL schemas
+
+
Status
Release
+
Version
0.2
+
+
+
+
GraphQL provides directives as a means of attaching user‐defined metadata to a GraphQL document. Directives are highly flexible, and can be used to suggest behavior and define features of a graph which are not otherwise evident in the schema.
+
Alas, GraphQL does not provide a mechanism to globally identify or version directives. Given a particular directive—e.g. @join—processors are expected to know how to interpret the directive based only on its name, definition within the document, and additional configuration from outside the document. This means that programs interpreting these directives have two options:
+
+
rely on a hardcoded interpretation for directives with certain signatures, or
+
accept additional configuration about how to interpret directives in the schema.
+
+
The first solution is fragile, particularly as GraphQL has no built‐in namespacing mechanisms, so the possibility of name collisions always looms.
+
The second is unfortunate: GraphQL schemas are generally intended to be self‐describing, and requiring additional configuration subtly undermines this guarantee: given just a schema, programs do not necessarily know how to interpret it, and certainly not how to serve it. It also creates the possibility for the schema and configuration to fall out of sync, leading to issues which can manifest late in a deployment pipeline.
Core schemas provide a concise mechanism for schema documents to specify the metadata they provide. Metadata is grouped into features, which typically define directives and associated types (e.g. scalars and inputs which serve as directive inputs). Additionally, core schemas provide:
+
+
Flexible namespacing rules. It is always possible to represent any GraphQL schema within a core schema document. Additionally, documents can choose the names they use for the features they reference, guaranteeing that namespace collisions can always be resolved.
Core schemas are not a new language. All core schema documents are valid GraphQL schema documents. However, this specification introduces new requirements, so not all valid GraphQL schemas are valid core schemas.
+
The broad intention behind core schemas is to provide a single document which provides all the necessary configuration for programs that process and serve the schema to GraphQL clients, primarily by following directives in order to determine how to resolve queries made against that schema.
When talking about a core schema, we can broadly break it into two pieces:
+
+
an API consisting of schema elements (objects, interfaces, enums, directives, etc.) which SHOULD be served to clients, and
+
machinery containing document metadata. This typically consists of directives and associated input types (such as enums and input objects), but may include any schema element. Machinery MUST NOT be served to clients. Specifically, machinery MUST NOT be included in introspection responses or used to validate or execute queries.
+
+
This reflects how core schemas are used: a core schema contains a GraphQL interface (the API) along with metadata about how to implement that interface (the machinery). Exposing the machinery to clients is unnecessary, and may in some cases constitute a security issue (for example, the machinery for a public‐facing graph router will likely reference internal services, possibly exposing network internals which should not be visible to the general public).
+
A key feature of core schemas is that it is always possible to derive a core schema’s API without any knowledge of the features used by the document (with the exception of the core feature itself). Specifically, named elements are not included in the API schema if they are named something__likeThis or are a directive named @something, and something is the prefix of a feature declared with @core.
+
A formal description is provided by the IsInAPI algorithm.
Authors (either human or machine) write an initial core schema as specified in this document, including versioned @core requests for all directives they use
+
Machine processors can process core schemas and output new core schemas. The versioning of directives and associated schema elements provided by the @core allows processors to operate on directives they understand and pass through directives they do not.
+
Human readers can examine the core schema at various stages of processing. At any stage, they can examine the @core directives and follow URLs to the specification, receiving an explanation of the requirements of the specification and what new directives, types, and other schema objects are available within the document.
+
Data cores can then pick up the processed core schema and provide some data‐layer service with it. Typically this means serving the schema’s API as a GraphQL endpoint, using metadata defined by machinery to inform how it processes operations it receives. However, data cores may perform other tasks described in the core schema, such as routing to backend services, caching commonly‐accessed fields and queries, and so on. The term “data core” is intended to capture this multiplicity of possible activities.
3.1Unspecified directives are passed through by default
+
Existing schemas likely contain definitions for directives which are not versioned, have no specification document, and are intended mainly to be passed through. This is the default behavior for core schema processors:
schema
+ @core(feature:"https://specs.apollo.dev/core/v0.1")
+{
+ query:Query
+}
+
+typeSomeType{
+ field:Int@another
+}
+
+# `@another` is unspecified. Core processors will not extract metadata from
+# it, but its definition and all usages within the schema will be exposed
+# in the API.
+directive@anotheronFIELD_DEFINITION
+
+directive@core(feature:String!,as:String)repeatableonSCHEMA
+
All core schemas use the @core directive to declare their use of the core feature itself as well as any other core features they use.
+
In order to use these directives in your schema, GraphQL requires you to include their definitions in your schema.
+
Processors MUST validate that you have defined the directives with the same arguments, locations, and repeatable flag as given below. Specifically, the bootstrapping algorithm validates that the @core directive has a definition matching the definition given below. (The bootstrapping algorithm does not require processors to validate other aspects of the directive declaration such as description strings or argument ordering. The main purpose of this validation is to ensure that directive arguments have the type and default values expected by the specification.)
+
The following declares the directive defined by this specification. You SHOULD define the directives in your core schema by including the following text in your schema document.
When writing a specification for your own core feature, you SHOULD include a section like this one with sample definitions to copy into schemas, and you SHOULD require processors to validate that directive definitions in documents match your sample definitions.
A feature URL specifying the directive and associated schema elements. When viewed, the URL SHOULD provide the content of the appropriate version of the specification in some human‐readable form. In short, a human reader should be able to click the link and go to the docs for the version in use. There are specific requirements on the format of the URL, but it is not required that the content be machine‐readable in any particular way.
+
Feature URLs contain information about the spec’s prefix and version.
+
Feature URLs serve two main purposes:
+
+
Directing human readers to documentation about the feature
+
Providing tools with information about the specs in use, along with enough information to select and invoke an implementation
+
+
Feature URLs SHOULD be RFC 3986 URLs. When viewed, the URL SHOULD provide the specification of the selected version of the feature in some human‐readable form; a human reader should be able to click the link and go to the correct version of the docs.
+
Although they are not prohibited from doing so, it’s assumed that processors will not load the content of feature URLs. Published specifications are not required to be machine‐readable, and this spec places no requirements on the structure or syntax of the content to be found there.
+
There are, however, requirements on the structure of the URL itself:
The final two segments of the URL’s pathMUST contain the feature’s name and a version tag. The content of the URL up to and including the name—but excluding the / after the name and the version tag—is the feature’s identity. Trailing slashes at the end of the URL (ie, after the version tag) should be ignored. For the above example,
A global identifier for the feature. Processors can treat this as an opaque string identifying the feature (but not the version of the feature) for purposes of selecting an appropriate implementation. The identity never has a trailing /.
name: "exampleFeature"
The feature’s name, for purposes of prefixing schema elements it defines.
version: "v1.0"
The tag for the version of the feature used to author the document. Processors MUST select an implementation of the feature which can satisfy the specified version.
+
The version tag MUST be a valid VersionTag. The name MUST be a valid GraphQL name which does not include the namespace separator ("__").
When extracting the URL’s name and version, processors MUST ignore any url components which are not assigned a meaning. This spec assigns meaning to the final two segments of the path. Other URL components—particularly query strings and fragments, if present—MUST be ignored for the purposes of extracting the name and version.
5.1.1.2Why is versioning in the URL, not a directive argument?
+
The version is in the URL because when a human reader visits the URL, we would like them to be taken to the documentation for the version of the feature used by this document. Many text editors will turn URLs into hyperlinks, and it’s highly desirable that clicking the link takes the user to the correct version of the docs. Putting the version information in a separate argument to the @core directive would prevent this.
Change the names of directives and schema elements from this specification. The specified string MUST be a valid GraphQL name and MUST NOT contain the namespace separator (two underscores, "__") or end with an underscore.
+
When as: is provided, processors looking for prefixed schema elementsMUST look for elements whose names are the specified name with the prefix replaced with the name provided to the as: argument.
schema
+ @core(feature:"https://specs.apollo.dev/core/v0.1")
+ @core(feature:"https://spec.example.com/example/v1.0",as:"eg")
+{
+ query:Query
+}
+
+typeUser{
+ # Specifying `as: "eg"` transforms @example into @eg
+ name:String@eg(data:ITEM)
+}
+
+# Additional specified schema elements must have their prefixes set
+# to the new name.
+#
+# The spec at https://spec.example.com/example/v1.0 calls this enum
+# `example__Data`, but because of the `as:` argument above, processors
+# will use this `eg__Data` enum instead.
+enumeg__Data{
+ ITEM
+}
+
+# Name transformation must also be applied to definitions pulled in from
+# specifications.
+directive@eg(data:eg__Data)onFIELD_DEFINITION
+
+directive@core(feature:String!,as:String)repeatableonSCHEMA
+
An optional purpose for this feature. This hints to consumers as to whether they can safely ignore metadata from a given feature.
+
By default, core features SHOULD fail open. This means that an unknown feature SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
+
This behavior is different for features with a specified purpose:
+
+
SECURITY features convey metadata necessary to securely resolve fields within the schema
+
EXECUTION features convey metadata necessary to correctly resolve fields within the schema
This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail‐open behavior of core schema consumers is undesirable.
+
+Note
+we’ll refer to directives from features which are for: SECURITY or for: EXECUTION as “SECURITY directives” and “EXECUTION directives”, respectively.
SECURITY features provide metadata necessary to securely resolve fields. For instance, a hypothetical auth feature may provide an @auth directive to flag fields which require authorization. If a data core does not support the auth feature and serves those fields anyway, these fields will be accessible without authorization, compromising security.
+
Security‐conscious consumers MUST NOT serve a field if:
+
+
the schema definition has any unsupported SECURITY directives,
+
the field’s parent type definition has any unsupported SECURITY directives,
+
the field’s return type definition has any unsupported SECURITY directives, or
+
the field definition has any unsupported SECURITY directives
+
+
Such fields are not securely resolvable. Security‐conscious consumers MAY serve schemas with fields which are not securely resolvable. However, they MUST remove such fields from the schema before serving it.
+
Less security‐conscious consumers MAY choose to relax these requirements. For instance, servers may provide a development mode in which unknown SECURITY directives are ignored, perhaps with a warning. Such software may also provide a way to explicitly disable some or all SECURITY features during development.
+
More security‐conscious consumers MAY choose to enhance these requirements. For instance, production servers MAY adopt a policy of entirely rejecting any schema which contains ANY unsupported SECURITY features, even if those features are never used to annotate the schema.
EXECUTION features provide metadata necessary to correctly resolve fields. For instance, a hypothetical ts feature may provide a @ts__resolvers annotation which references a TypeScript module of field resolvers. A consumer which does not support the ts feature will be unable to correctly resolve such fields.
the schema’s definition has any unsupported EXECUTION directives,
+
the field’s parent type definition has any unsupported EXECUTION directives,
+
the field’s return type definition has any unsupported EXECUTION directives, or
+
the field definition has any unsupported EXECUTION directives
+
+
Such fields are unresolvable. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION features, even if those features are never used in the schema.
MUST NOT contain the core namespace separator, which is two underscores ("__"), and
+
MUST NOT end with an underscore (which would create ambiguity between whether "x___y" is prefix x_ for element y or prefix x for element _y).
+
+
Prefixed names consist of the name of the feature, followed by two underscores, followed by the name of the element, which can be any valid GraphQL name. For instance, the core specification (which you are currently reading) introduces an element named @core, and the join specification introduces an element named @join__field (among others).
+
+Note
+that both parts must be valid GraphQL names, and GraphQL names cannot start with digits, so core feature specifications cannot introduce names like @feature__24hours.
+
A feature’s root directive is an exception to the prefixing requirements. Feature specifications MAY introduce a single directive which carries only the name of the feature, with no prefix required. For example, the core specification introduces a @core directive. This directive has the same name as the feature (”core”), and so requires no prefix.
schema
+ @core(feature:"https://specs.apollo.dev/core/v0.1")
+ @core(feature:"https://spec.example.com/example/v1.0"){
+ query:Query
+}
+
+typeUser{
+ name:String@example(data:ITEM)
+}
+
+# An enum used to provide structured data to the example spec.
+# It is prefixed with the name of the spec.
+enumexample__Data{
+ ITEM
+}
+
+directive@example(data:example__Data)onFIELD_DEFINITION
+
+directive@core(feature:String!,as:String)repeatableonSCHEMA
+
+
The prefix MUST NOT be elided within documentation; definitions of schema elements provided within the spec MUST include the feature’s name as a prefix.
schema
+ @core(feature:"https://specs.apollo.dev/core/v0.1")
+ @core(feature:"https://spec.example.com/featureA/v1.0")
+ @core(feature:"https://spec.example.com/featureB/v2.0",as:"B"){
+ query:Query
+}
+
+"""
+featureA__SomeType is a type defined by feature A.
+"""
+typefeatureA__SomeType{
+ """
+ nativeField is a field defined by featureA on a type also defined
+ by featureA (namely featureA__SomeType)
+ """
+ nativeField:Int@featureA__fieldDirective
+}
+
+"""
+featureA__SomeInput is an input specified by feature A
+"""
+inputfeatureA__SomeInput{
+ """
+ nativeInputField is defined by featureA
+ """
+ nativeInputField:Int
+}
+
+"""
+featureA__Items is specified by feature A
+"""
+enumfeatureA__Items{ONE,TWO,THREE@B}
+
+"""
+@B is the root directive defined by featureB
+
+Root directives are named after their feature
+"""
+directive@BonENUM_VALUE
+
+"""
+@featureA__fieldDirective is a non-root (prefixed) directive defined by featureA
+"""
+directive@featureA__fieldDirectiveonFIELD_DEFINITION
+
+directive@core(feature:String!,as:String)repeatableonSCHEMA
+
Specs are versioned with a subset of a Semantic Version Number containing only the major and minor parts. Thus, specifications SHOULD provide a version of the form vMajor.Minor, where both integers ≥ 0.
As specified by semver, spec authors SHOULD increment the:
+
+
MAJOR version when you make incompatible API changes,
+
MINOR version when you add functionality in a backwards compatible manner
+
+
+
Patch and pre‐release qualifiers are judged to be not particularly meaningful in the context of core features, which are (by definition) interfaces rather than implementations. The patch component of a semver denotes a bug fix which is backwards compatible—that is, a change to the implementation which does not affect the interface. Patch‐level changes in the version of a spec denote wording clarifications which do not require implementation changes. As such, it is not important to track them for the purposes of version resolution.
+
As with semver, the 0.x version series is special: there is no expectation of compatibility between versions 0.x and 0.y. For example, a processor must not activate implementation 0.4 to satisfy a requested version of 0.2.
Given a version requested by a document and an available version of an implementation, the following algorithm will determine if the available version can satisfy the requested version:
8.2Referencing versions and activating implementations
+
Schema documents MUST reference a feature version which supports all the schema elements and behaviors required by the document. As a practical matter, authors will generally prefer to reference a version they have reason to believe is supported by the most processors; depending on context, this might be an old stable version with a low major version, or a new less‐deprecated version with a large major version.
+
If a processor chooses to activate support for a feature, the processor MUST activate an implementation which can satisfy the version required by the document.
Processors MAY accept configuration which overrides these default behaviors.
+
Additionally, processors which prepare the schema for final public consumption MAY choose to eliminate all unknown directives and prefixed types in order to hide schema implementation details within the published schema. This will impair the operation of tooling which relies on these directives—such tools will not be able to run on the output schema, so the benefits and costs of this kind of information hiding should be weighed carefully on a case‐by‐case basis.
This section lays out algorithms for processing core schemas.
+
Algorithms described in this section may produce validation failures if a document does not conform to the requirements core schema document. Validation failures SHOULD halt processing. Some consumers, such as authoring tools, MAY attempt to continue processing in the presence of validation failures, but their behavior in such cases is unspecified.
Determine the name of the core specification within the document.
+
It is possible to rename the core feature within a document. This process determines the actual name for the core feature if one is present.
+
+
Fails the Has Schema validation if there are no SchemaDefinitions in the document
+
Fails the Has Core Feature validation if the core feature itself is not referenced with a @core directive within the document
+
Fails the Bootstrap Core Feature Listed First validation if the reference to the core feature is not the first @core directive on the document’s SchemaDefinition
+
Fails the Core Directive Incorrect Definition validation if the @core directive definition does not match the directive as defined by this specification.
+
+
For the purposes of this algorithm, a directive’s definition in a schema matches a definition provided in this specification if:
+
+
Its arguments have the specified names, types, and default values (or lack thereof)
+
It is defined as repeatable if and only if the specification’s definition defines it as repeatable
+
The set of locations it belongs to is the same set of locations in the specification’s definition.
+
+
The following aspects may differ between the definition in the schema and the definition in the specification without preventing the definitions from matching:
...if no SchemaDefinitions are present in document, the Has Schema validation fails.
+
+
+
For each directive d on schema,
+
If d has a feature: argument which parses as a feature URL, and whose identity is "https://specs.apollo.dev/core/"and whose version is "v0.1", and eitherd has an as: argument whose value is equal to d‘s name ord does not have an as: argument and d‘s name is core:
+
If any directive on schema listed before d has the same name as d, the Bootstrap Core Feature Listed First validation fails.
Collect a map of (featureName: String) → Directive, where Directive is a @core Directive which introduces the feature named featureName into the document.
+
+
Fails the Name Uniqueness validation if feature names are not unique within the document.
+
FailsInvalid Feature URL validation for any invalid feature URLs.
schema
+ @core(feature:"https://specs.apollo.dev/core/v0.1")
+ @core(feature:"https://specs.example.com/A/1.0")# name is A
+ @core(feature:"https://specs.example.com/A/2.0",as:"A2")# name is A2
+{
+ query:Query
+}
+
Without the explicit as:, the above would be invalid:
schema
+ @core(feature:"https://specs.apollo.dev/core/v0.1")
+ @core(feature:"https://specs.example.com/A/1.0")# name is A
+ @core(feature:"https://specs.example.com/A/2.0")# name is A
+{
+ query:Query
+}
+
Different specs with the same prefix are also invalid:
schema
+ @core(feature:"https://specs.apollo.dev/core/v0.1")
+ @core(feature:"https://specs.example.com/A/1.0")# name is A
+ @core(feature:"https://www.specs.com/specA/1.1",as:"A")# name is A
+{
+ query:Query
+}
Create a map of element: Any Named Element → feature: Directive | null, associating every named schema element within the document with a feature directive, or null if it is not associated with a feature.
Determine if any schema element is included in the API described by the core schema. A schema element is any part of a GraphQL document using type system definitions that has a name.
Let assignments be the result of assigning features to elements via AssignFeatures(document)
+
If assignments[element] is null, Returntrue
+
Else, Returnfalse
+
+
+
+Note
+Later versions of this specification may add other ways to affect the behavior of this algorithm, but those mechanisms will only be enabled if you reference those hypothetical versions of this specification.
link v1.0 provides the foundation of core schemas—GraphQL schemas for the global graph. Core schemas use specified conventions to link definitions from other schemas. All the other specs in this library rely on core schema conventions.
+
join v0.1 describes supergraphs which join types from one or more subgraphs
+
tag v0.1 attaches a single piece of string metadata to various GraphQL definitions (it is mainly used for contracts)
+
+
+
diff --git a/index.md b/index.md
new file mode 100644
index 0000000..cf832e0
--- /dev/null
+++ b/index.md
@@ -0,0 +1,20 @@
+# Apollo Library of Technical Specifications
+
+```raw html
+
+
+
+
+
+
+
+```
+
+# Current Specs
+
+- [link v1.0](link/v1.0) provides the foundation of core schemas—GraphQL schemas for the global graph. Core schemas use [specified conventions](link/v1.0) to link definitions from other schemas. All the other specs in this library rely on core schema conventions.
+- [join v0.1](join/v0.1) describes supergraphs which join types from one or more subgraphs
+- [tag v0.1](tag/v0.1) attaches a single piece of string metadata to various GraphQL definitions (it is mainly used for contracts)
+- [inaccessible v0.1](inaccessible/v0.1) masks fields and types from a graph's public API
+
+
diff --git a/join/v0.1/albums.graphql b/join/v0.1/albums.graphql
new file mode 100644
index 0000000..e9ff385
--- /dev/null
+++ b/join/v0.1/albums.graphql
@@ -0,0 +1,14 @@
+type Album @key(fields: "id") {
+ id: ID!
+ user: User
+ photos: [Image!]
+}
+
+extend type Image {
+ albums: [Album!]
+}
+
+extend type User {
+ albums: [Album!]
+ favorite: Album
+}
\ No newline at end of file
diff --git a/join/v0.1/auth.graphql b/join/v0.1/auth.graphql
new file mode 100644
index 0000000..7a85d3a
--- /dev/null
+++ b/join/v0.1/auth.graphql
@@ -0,0 +1,8 @@
+type User @key(fields: "id") {
+ id: ID!
+ name: String
+}
+
+type Query {
+ me: User
+}
\ No newline at end of file
diff --git a/join/v0.1/images.graphql b/join/v0.1/images.graphql
new file mode 100644
index 0000000..741ec0f
--- /dev/null
+++ b/join/v0.1/images.graphql
@@ -0,0 +1,15 @@
+type Image @key(fields: "url") {
+ url: Url
+ type: MimeType
+}
+
+type Query {
+ images: [Image]
+}
+
+extend type User {
+ favorite: Image
+}
+
+scalar Url
+scalar MimeType
\ No newline at end of file
diff --git a/join/v0.1/index.html b/join/v0.1/index.html
new file mode 100644
index 0000000..478720c
--- /dev/null
+++ b/join/v0.1/index.html
@@ -0,0 +1,1674 @@
+
+
+
+
+Join
+
+
+
+
+
+
+
+
Join
+
+
for defining supergraphs which join multiple subgraphs
This document specifies only the structure and semantics of supergraphs. It’s expected that a supergraph will generally be the output of a compilation process which composes subgraphs. The mechanics of that process are not specified normatively here. Conforming implementations may choose any approach they like, so long as the result conforms to the requirements of this document.
The meaning of the @join__* directives is explored in the Directives section.
+
The example represents one way to compose three input schemas, based on federated composition. These schemas are provided for purposes of illustration only. This spec places no normative requirements on composer input. It does not require that subgraphs use federated composition directives, and it does not place any requirements on how the composer builds a supergraph, except to say that the resulting schema must be a valid supergraph document.
+
The auth subgraph provides the User type and Query.me.
Producers generate supergraphs. This spec places requirements on supergraph producers.
+
Consumers consume supergraphs. This spec places requirements on supergraph consumers.
+
Composers (or compilers) are producers which compose subgraphs into a supergraph. This document places no particular requirements on the composition algorithm, except that it must produce a valid supergraph.
+
Routers are consumers which serve a composed schema as a GraphQL endpoint. This definition is non‐normative.
+
+
Graph routers differ from standard GraphQL endpoints in that they are not expected to resolve fields or communicate with (non‐GraphQL) backend services on their own. Instead, graph routers receive GraphQL requests and service them by performing additional GraphQL requests. This spec provides guidance for implementing routers, but does not require particular implementations of query separation or dispatch, nor does it attempt to normatively separate routers from other supergraph consumers.
+
Routers expose an API schema to clients that is created by transforming the supergraph schema (for example, the join__Graph enum and the directives described in this spec are removed from the API schema). The API schema is used to validate client operations and may be exposed to clients via introspection.
+
+
Endpoints are running servers which can resolve GraphQL queries against a schema. In this version of the spec, endpoints must be URLs, typically http/https URLs.
+
Subgraphs are GraphQL schemas which are composed to form a supergraph. Subgraph names and metadata are declared within the special join__Graph enum.
+
This spec does not place any requirements on subgraph schemas. Generally, they may be of any shape. In particular, subgraph schemas do not need to be supergraphs themselves or to follow this spec in any way; neither is it an error for them to do so. Composers MAY place additional requirements on subgraph schemas to aid in composition; composers SHOULD document any such requirements.
This section is non‐normative. It describes the motivation behind the directives defined by this specification.
+
A supergraph schema describes a GraphQL schema that can be served by a router. The router does not contain logic to resolve any of the schema’s fields; instead, the supergraph schema contains directives starting with @join__ that tell the router which subgraph endpoint can resolve each field, as well as other information needed in order to construct subgraph operations.
+
The directives described in this specification are designed for a particular query planning algorithm, and so there are some restrictions on how they can be combined that originate from the requirements of this algorithm. For example, this specification describes a concept of type ownership which exists not because we believe it describes the ideal method of structuring your subgraphs, but because this query planning algorithm depends on type ownership. We hope that future versions of this specification can relax some of these restrictions.
+
Each supergraph schema contains a list of its included subgraphs. The join__Graph enum represents this list with an enum value for each subgraph. Each enum value is annotated with a @join__graph directive telling the router what endpoint can be used to reach the subgraph, and giving the subgraph a human‐readable name that can be used for purposes such as query plan visualization and server logs.
+
To resolve a field, the router needs to know to which subgraphs it can delegate the field’s resolution. One explicit way to indicate this in a supergraph schema is by annotating the field with a @join__field directive specifying which subgraph should be used to resolve that field. (There are other ways of indicating which subgraphs can resolve a field which will be described later.)
+
In order for the router to send an operation that resolves a given field on a parent object to a subgraph, the operation needs to first resolve the parent object itself. There are several ways to accomplish this, described below. The examples below include abbreviated versions of the supergraph schemas which do not include the schema definition, directive definitions, or the join__Graph definition. This specification does not require the subgraph operations to be the same as those described in these examples; this is just intended to broadly describe the meanings of the directives.
4.2Fields on the same subgraph as the parent operation
+
If a field’s parent field will be resolved by an operation on the same subgraph, then it can be resolved as part of the same operation, by putting it in a nested selection set on the parent field’s subgraph operation. Note that this example contains @join__owner and @join__type directives on an object type; these will be described later.
Sometimes, a subgraph G may be capable of resolving a field that is ordinarily resolved in a different subgraph if the field’s parent object was resolved in G. Consider an example where the Product.priceCents: Int! field is usually resolved by the Products subgraph, which knows the priceCents for every Product in your system. In the Marketing subgraph, there is a Query.todaysPromotion: Product! field. While the Marketing subgraph cannot determine the priceCents of every product in your system, it does know the priceCents of the promoted products, and so the Marketing subgraph can resolve operations like { todaysPromotion { priceCents } }.
+
When this is the case, you can include a provides argument in the @join__field listing these “pre‐calculated” fields. The router can now resolve these fields in the “providing” subgraph instead of in the subgraph that would usually be used to resolve those fields.
Some types have the property that all of their fields can be resolved by any subgraph that can resolve a field returning that type. These types are called value types. (Imagine a type type T { x: Int, y: String } where every resolver for a field of type T actually produces an object like {x: 1, y: "z"}, and the resolvers for the two fields on T just unpack the values already in the object.) In a supergraph schema, a type is a value type if it does not have a @join__owner directive on it.
We’ve finally reached the most interesting case: a field that must be resolved by an operation on a different subgraph from the subgraph on which its parent field was resolved. In order to do this, we need a way to tell the subgraph to resolve that parent object. We do this by defining a special root field in the subgraph’s schema: Query._entities(representations: [_Any!]!): [_Entity]!. This field takes a list of “representations” and returns a list of the same length of the corresponding objects resulting from looking up the representations in an application‐dependent way.
+
What is a representation? A representation is expressed as the scalar type _Any, and can be any JSON object with a top‐level __typename key with a string value. Often, a representation will be something like {__typename: "User", id: "abcdef"}: the type name plus one or more fields that you can use to look up the object in a database.
+
There are several ways that the router can calculate a representation to pass to a subgraph. In this specification, all non‐value types have a specific subgraph referred to as its “owner”, specified via a @join__owner directive on the type. Object types that are not value types are referred to as “entities”; the type _Entity referenced above is a union defined in each subgraph’s schema consisting of the entity types defined by that subgraph. (Only subgraphs which define entities need to define the Query._entities field.) Entity types must also have at least one @join__type directive specifying the owning subgraph along with a key. For each additional subgraph which can resolve fields returning that type, there should be exactly one @join__type directive specifying that subgraph along with a key, which should be identical to one of the keys specified with the owning subgraph.
+
A key is a set of fields on the type (potentially including sub‐selections and inline fragments), specified as a string. If a type T is annotated with @join__type(subgraph: G, key: "a b { c }"), then it must be possible to resolve the full field set provided as a key on subgraph G. Additionally, if you take an object with the structure returned by resolving that field set and add a field __typename: "T", then you should be able to pass the resulting value as a representation to the Query._entities field on subgraph G.
+
In order to resolve a field on an entity on the subgraph that owns its parent type, where that subgraph is different from the subgraph that resolved its parent object, the router first resolves a key for that object on the previous subgraph, and then uses that representation on the owning subgraph.
+
For convenience, you may omit @join__field(graph: A) directives on fields whose parent type is owned by A.
# Supergraph schema
+typeQuery{
+ fieldB:X@join__field(graph:B)
+}
+
+typeX
+ @join__owner(graph:A)
+ # As the owner, A is allowed to have more than one key.
+ @join__type(graph:A,key:"x")
+ @join__type(graph:A,key:"y z")
+ # As non-owners, B and C can only have one key each and
+ # they must match a key from A.
+ @join__type(graph:B,key:"x")
+ @join__type(graph:C,key:"y z")
+{
+ # Because A owns X, we can omit @join__field(graph: A)
+ # from these three fields.
+ x:String
+ y:String
+ z:String
+}
+
+# Operation
+{fieldB{y}}
+# Generated subgraph operations
+## On B. `y` is not available, so we need to fetch B's key for X.
+{fieldB{x}}
+## On A
+## $r = [{__typename: "X", x: "some-x-value"}]
+query($r:[_Any!]!){_entities(representations:$r]){y}}
+
The previous section described how to jump from one subgraph to another in order to resolve a field on the subgraph that owns the field’s parent type. The situation is a bit more complicated when you want to resolve a field on a subgraph that doesn’t own the field’s parent type — what we call an extension field. That’s because we no longer have the guarantee that the subgraph you’re coming from and the subgraph you’re going to share a key in common. In this case, we may need to pass through the owning type.
# Supergraph schema
+typeQuery{
+ fieldB:X@join__field(graph:B)
+}
+
+typeX
+ @join__owner(graph:A)
+ # As the owner, A is allowed to have more than one key.
+ @join__type(graph:A,key:"x")
+ @join__type(graph:A,key:"y z")
+ # As non-owners, B and C can only have one key each and
+ # they must match a key from A.
+ @join__type(graph:B,key:"x")
+ @join__type(graph:C,key:"y z")
+{
+ x:String
+ y:String
+ z:String
+ c:String@join__field(graph:C)
+}
+
+# Operation
+{fieldB{c}}
+# Generated subgraph operations
+## On B. `c` is not available on B, so we need to eventually get over to C.
+## In order to do that, we need `y` and `z`... which aren't available on B
+## either! So we need to take two steps. First we use B's key.
+{fieldB{x}}
+## On A. We use B's key to resolve our `X`, and we extract C's key.
+## $r = [{__typename: "X", x: "some-x-value"}]
+query($r:[_Any!]!){_entities(representations:$r]){yz}}
+## On C. We can finally look up the field we need.
+## $r = [{__typename: "X", y: "some-y-value", z: "some-z-value"}]
+query($r:[_Any!]!){_entities(representations:$r]){c}}
+
+
We only need to do this two‐jump process because the fields needed for C’s key are not available in B; otherwise a single jump would have worked, like in the owned‐field case.
+
Sometimes a particular extension field needs its parent object’s representation to contain more information than its parent type’s key requests. In this case, you can include a requires argument in the field’s @join__field listing those required fields (potentially including sub‐selections). All required fields must be resolvable in the owning subgraph (this restriction is why requires is only allowed on extension fields).
# Supergraph schema
+typeQuery{
+ fieldA:X@join__field(graph:A)
+}
+
+typeX
+ @join__owner(graph:A)
+ @join__type(graph:A,key:"x")
+ @join__type(graph:B,key:"x")
+{
+ x:String
+ y:String
+ z:String@join__field(graph:B,requires:"y")
+}
+
+# Operation
+{fieldA{z}}
+# Generated subgraph operations
+## On A. `x` is included because it is B's key for `X`; `y`
+## is included because of the `requires`.
+{fieldA{xy}}
+## On B..
+## $r = [{__typename: "X", x: "some-x-value", y: "some-y-value"}]
+query($r:[_Any!]!){_entities(representations:$r]){z}}
+
Schemas using the join core feature MUST be valid core schema documents with @core directives referencing the core specification and this specification.
As described in the core schema specification, your schema may use a prefix other than join for all of the directive and enum names defined by this specification by including an as argument to the @core directive which references this specification. All references to directive and enum names in this specification MUST be interpreted as referring to names with the appropriate prefix chosen within your schema.
+
In order to use the directives described by this specification, GraphQL requires you to include their definitions in your schema.
+
Processors MUST validate that you have defined the directives with the same arguments, locations, and repeatable flag as given below.
Processors MUST validate that the schema contains an enum named join__Graph; see its section below for other required properties of this enum.
+
As described in the core specification, all of the directives and enums defined by this schema should be removed from the supergraph’s API schema. For example, the join__Graph enum should not be visible via introspection.
The @join__graph directive MUST be applied to each enum value on join__Graph, and nowhere else. Each application of @join__graphMUST have a distinct value for the name argument; this name is an arbitrary non‐empty string that can be used as a human‐readable identifier which may be used for purposes such as query plan visualization and server logs. The url argument is an endpoint that can resolve GraphQL queries for the subgraph.
Every type with a @join__typeMUST also have a @join__owner directive. Any type with a @join__owner directive MUST have at least one @join__type directive with the same graph as the @join__owner directive (the “owning graph”), and MUST have at most one @join__type directive for each graph value other than the owning graph. Any value that appears as a key in a @join__type directive with a graph value other than the owning graph must also appear as a key in a @join__type directive with graph equal to the owning graph.
The field’s parent type MUST be annotated with a @join__type with the same value of graph as this directive, unless the parent type is a root operation type.
+
If a field is not annotated with @join__field (or if the graph argument is not provided or null) and its parent type is annotated with @join__owner(graph: G), then a processor MUST treat the field as if it is annotated with @join__field(graph: G). If a field is not annotated with @join__field (or if the graph argument is not provided or null) and its parent type is not annotated with @join__owner (ie, the parent type is a value type) then it MUST be resolvable in any subgraph that can resolve values of its parent type.
The requires argument MUST only be specified on fields whose parent type has a @join__owner directive specifying a different graph than this @join__field directive does. All fields (including nested fields) mentioned in this field set must be resolvable in the parent type’s owning subgraph. When constructing a representation for a parent object of this field, a router will include the fields selected in this requires argument in addition to the appropriate key for the parent type.
+
The provides argument specifies fields that can be resolved in operations run on subgraph graph as a nested selection under this field, even if they ordinarily can only be resolved on other subgraphs.
The descriptions of @join__type and @join__field describes requirements on how @join__owner relates to @join__type and the requires argument to @join__field.
+
+Note
+Type ownership is currently slated for removal in a future version of this spec. It is RECOMMENDED that router implementations consider approaches which function in the absence of these restrictions. The overview explains how the current router’s query planning algorithm depends on concept of type ownership.
for defining *supergraphs* which join multiple *subgraphs*
+
+```raw html
+
+
Status
Release
+
Version
0.1
+
+
+
+```
+
+```mermaid diagram -- Schema joining multiple subgraphs
+graph LR
+ classDef bg fill:none,color:#22262E;
+ s1(auth.graphql):::bg-->core(composed schema: photos.graphql)
+ s2(images.graphql):::bg-->core
+ s3(albums.graphql):::bg-->core
+ style core fill:none,stroke:fuchsia,color:fuchsia;
+```
+
+This document defines a [core schema](https://specs.apollo.dev/core/v0.1) named `join` for describing [core schemas](https://specs.apollo.dev/core/v0.1) which **join** multiple **subgraph** schemas into a single **supergraph** schema.
+
+This specification provides machinery to:
+- define [subgraphs](#def-subgraph) with the {join__Graph} enum and the {@join__graph} directive
+- assign fields to subgraphs with the {@join__field} directive
+- declare additional data required and provided by subgraph field resolvers with the `requires` and `provides` arguments to {@join__field}
+- assign [keys and ownership](#sec-Owned-fields-on-owned-types) to types with the {@join__type} and {@join__owner} directives
+
+# How to read this document
+
+This document uses [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt) guidance regarding normative terms: MUST / MUST NOT / REQUIRED / SHALL / SHALL NOT / SHOULD / SHOULD NOT / RECOMMENDED / MAY / OPTIONAL.
+
+## What this document isn't
+
+This document specifies only the structure and semantics of supergraphs. It's expected that a supergraph will generally be the output of a compilation process which composes subgraphs. The mechanics of that process are not specified normatively here. Conforming implementations may choose any approach they like, so long as the result conforms to the requirements of this document.
+
+# Example: Photo Library
+
+*This section is non-normative.*
+
+We'll refer to this example of a photo library throughout the document:
+
+:::[example](./photos.graphql) -- Photos library composed schema
+
+The meaning of the `@join__*` directives is explored in the [Directives](#sec-Directives) section.
+
+The example represents **one way** to compose three input schemas, based on [federated composition](https://www.apollographql.com/docs/federation/federation-spec/). These schemas are provided for purposes of illustration only. This spec places no normative requirements on composer input. It does not require that subgraphs use federated composition directives, and it does not place any requirements on *how* the composer builds a supergraph, except to say that the resulting schema must be a valid supergraph document.
+
+The [auth](./auth.graphql) subgraph provides the `User` type and `Query.me`.
+
+:::[example](auth.graphql) -- Auth schema
+
+The [images](./images.graphql) subgraph provides the `Image` type and `URL` scalar.
+
+:::[example](./images.graphql) -- Images schema
+
+The [albums](./albums.graphql) subgraph provides the `Album` type and extends `User` and `Image` with album information.
+
+:::[example](./albums.graphql) -- Albums schema
+
+
+# Actors
+
+```mermaid diagram -- Actors and roles within an example composition pipeline
+flowchart TB
+ classDef bg fill:#EBE6FF;
+ subgraph A [subgraph A]
+ schemaA([schema A]):::bg
+ style schemaA color:#000
+ endpointA([endpoint A]):::bg
+ style endpointA color:#000
+ end
+ style A fill:#FCFDFF,stroke:#CAD0D8,color:#777F8E;
+ subgraph B [subgraph B]
+ schemaB([schema B]):::bg
+ style schemaB color:#000
+ endpointB([endpoint B]):::bg
+ style endpointB color:#000
+ end
+ style B fill:#FCFDFF,stroke:#CAD0D8,color:#777F8E;
+ subgraph C [subgraph C]
+ schemaC([schema C]):::bg
+ style schemaC color:#000
+ endpointC([endpoint C]):::bg
+ style endpointC color:#000
+ end
+ style C fill:#FCFDFF,stroke:#CAD0D8,color:#777F8E;
+ subgraph producer["Producer ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀"]
+ Composer
+ style Composer color:#000
+ end
+ style producer fill:#FCFDFF,stroke:#CAD0D8,color:#777F8E;
+ supergraph([Supergraph]):::bg
+ style supergraph color:#000
+ subgraph consumer["Consumer ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀"]
+ Router
+ style Router color:#000
+ end
+ style consumer fill:#FCFDFF,stroke:#CAD0D8,color:#777F8E;
+ A-->Composer:::bg
+ B-->Composer:::bg
+ C-->Composer:::bg
+ Composer-->supergraphSchema([Supergraph Schema]):::bg
+ style supergraphSchema color:#000
+ supergraphSchema-->Router:::bg
+ Router-->published([Published Schema]):::bg
+ style published color:#000
+ published-->Clients:::bg
+ style Clients color:#000
+ Clients-->Router:::bg
+```
+
+**Producers** generate supergraphs. This spec places requirements on supergraph producers.
+
+**Consumers** consume supergraphs. This spec places requirements on supergraph consumers.
+
+**Composers** (or **compilers**) are producers which compose subgraphs into a supergraph. This document places no particular requirements on the composition algorithm, except that it must produce a valid supergraph.
+
+**Routers** are consumers which serve a composed schema as a GraphQL endpoint. *This definition is non-normative.*
+ - Graph routers differ from standard GraphQL endpoints in that they are not expected to resolve fields or communicate with (non-GraphQL) backend services on their own. Instead, graph routers receive GraphQL requests and service them by performing additional GraphQL requests. This spec provides guidance for implementing routers, but does not require particular implementations of query separation or dispatch, nor does it attempt to normatively separate routers from other supergraph consumers.
+ - Routers expose an [API schema](https://specs.apollo.dev/core/v0.1/#sec-Parts-of-a-Core-Schema) to clients that is created by transforming the supergraph schema (for example, the {join__Graph} enum and the directives described in this spec are removed from the API schema). The API schema is used to validate client operations and may be exposed to clients via introspection.
+
+**Endpoints** are running servers which can resolve GraphQL queries against a schema. In this version of the spec, endpoints must be URLs, typically http/https URLs.
+
+**Subgraphs** are GraphQL schemas which are composed to form a supergraph. Subgraph names and metadata are declared within the special {join__Graph} enum.
+
+This spec does not place any requirements on subgraph schemas. Generally, they may be of any shape. In particular, subgraph schemas do not need to be supergraphs themselves or to follow this spec in any way; neither is it an error for them to do so. Composers MAY place additional requirements on subgraph schemas to aid in composition; composers SHOULD document any such requirements.
+
+# Overview
+
+*This section is non-normative.* It describes the motivation behind the directives defined by this specification.
+
+A supergraph schema describes a GraphQL schema that can be served by a router. The router does not contain logic to resolve any of the schema's fields; instead, the supergraph schema contains directives starting with {@join__} that tell the router which subgraph endpoint can resolve each field, as well as other information needed in order to construct subgraph operations.
+
+The directives described in this specification are designed for a particular query planning algorithm, and so there are some restrictions on how they can be combined that originate from the requirements of this algorithm. For example, this specification describes a concept of [type ownership](#sec-Owned-fields-on-owned-types) which exists not because we believe it describes the ideal method of structuring your subgraphs, but because this query planning algorithm depends on type ownership. We hope that future versions of this specification can relax some of these restrictions.
+
+Each supergraph schema contains a list of its included subgraphs. The [{join__Graph}](#join__Graph) enum represents this list with an enum value for each subgraph. Each enum value is annotated with a [{@join__graph}](#@join__graph) directive telling the router what endpoint can be used to reach the subgraph, and giving the subgraph a human-readable name that can be used for purposes such as query plan visualization and server logs.
+
+To resolve a field, the router needs to know to which subgraphs it can delegate the field's resolution. One explicit way to indicate this in a supergraph schema is by annotating the field with a [{@join__field}](#@join__field) directive specifying which subgraph should be used to resolve that field. (There are other ways of indicating which subgraphs can resolve a field which will be described later.)
+
+In order for the router to send an operation that resolves a given field on a parent object to a subgraph, the operation needs to first resolve the parent object itself. There are several ways to accomplish this, described below. The examples below include abbreviated versions of the supergraph schemas which do not include the `schema` definition, directive definitions, or the `join__Graph` definition. This specification does not require the subgraph operations to be the same as those described in these examples; this is just intended to broadly describe the meanings of the directives.
+
+## Root fields
+
+If a field appears at the root of the overall operation (query or mutation), then it can be placed at the root of the subgraph operation.
+
+```graphql example -- Root fields
+# Supergraph schema
+type Query {
+ fieldA: String @join__field(graph: A)
+ fieldAlsoFromA: String @join__field(graph: A)
+ fieldB: String @join__field(graph: B)
+}
+
+# Operation
+{ fieldA fieldAlsoFromA fieldB }
+# Generated subgraph operations
+## On A:
+{ fieldA fieldAlsoFromA }
+## On B:
+{ fieldB }
+```
+
+
+## Fields on the same subgraph as the parent operation
+
+If a field's parent field will be resolved by an operation on the same subgraph, then it can be resolved as part of the same operation, by putting it in a nested selection set on the parent field's subgraph operation. Note that this example contains {@join__owner} and {@join__type} directives on an object type; these will be described later.
+
+```graphql example -- Fields on the same subgraph as the parent operation
+# Supergraph schema
+type Query {
+ fieldA: X @join__field(graph: A)
+}
+
+type X @join__owner(graph: A) @join__type(graph: A, key: "nestedFieldA") {
+ nestedFieldA: String @join__field(graph: A)
+}
+
+# Operation
+{ fieldA { nestedFieldA } }
+# Generated subgraph operations
+## On A:
+{ fieldA { nestedFieldA }}
+```
+
+## Fields provided by the parent field
+
+Sometimes, a subgraph {G} may be capable of resolving a field that is ordinarily resolved in a different subgraph if the field's parent object was resolved in {G}. Consider an example where the `Product.priceCents: Int!` field is usually resolved by the Products subgraph, which knows the `priceCents` for every `Product` in your system. In the Marketing subgraph, there is a `Query.todaysPromotion: Product!` field. While the Marketing subgraph cannot determine the `priceCents` of every product in your system, it does know the `priceCents` of the promoted products, and so the Marketing subgraph can resolve operations like `{ todaysPromotion { priceCents } }`.
+
+When this is the case, you can include a `provides` argument in the `@join__field` listing these "pre-calculated" fields. The router can now resolve these fields in the "providing" subgraph instead of in the subgraph that would usually be used to resolve those fields.
+
+```graphql example -- Provided fields
+# Supergraph schema
+type Query {
+ todaysPromotion: Product! @join__field(graph: MARKETING, provides: "priceCents")
+ randomProduct: Product! @join__field(graph: PRODUCTS)
+}
+
+type Product @join__owner(graph: PRODUCTS) @join__type(graph: PRODUCTS, key: "id") {
+ id: ID! @join__field(graph: PRODUCTS)
+ priceCents: Int! @join__field(graph: PRODUCTS)
+}
+
+# Operation showing that `priceCents` is typically resolved on PRODUCTS
+{ randomProduct { priceCents } }
+# Generated subgraph operations
+## On PRODUCTS
+{ randomProduct { priceCents } }
+
+# Operation showing that `provides` allows `priceCents` to be resolved on MARKETING
+{ todaysPromotion { priceCents } }
+# Generated subgraph operations
+## On MARKETING
+{ todaysPromotion { priceCents } }
+```
+
+## Fields on value types
+
+Some types have the property that all of their fields can be resolved by *any* subgraph that can resolve a field returning that type. These types are called *value types*. (Imagine a type `type T { x: Int, y: String }` where every resolver for a field of type `T` actually produces an object like `{x: 1, y: "z"}`, and the resolvers for the two fields on `T` just unpack the values already in the object.) In a supergraph schema, a type is a value type if it does not have a [{@join__owner}](#@join__owner) directive on it.
+
+```graphql example -- Value types
+# Supergraph schema
+type Query {
+ fieldA: X @join__field(graph: A)
+ fieldB: X @join__field(graph: B)
+}
+
+type X {
+ anywhere: String
+}
+
+# Operation
+{ fieldA { anywhere } }
+# Generated subgraph operations
+## On A
+{ fieldA { anywhere } }
+
+# Operation
+{ fieldB { anywhere } }
+# Generated subgraph operations
+## On B
+{ fieldB { anywhere } }
+```
+
+## Owned fields on owned types
+
+We've finally reached the most interesting case: a field that must be resolved by an operation on a different subgraph from the subgraph on which its parent field was resolved. In order to do this, we need a way to tell the subgraph to resolve that parent object. We do this by defining a special root field in the subgraph's schema: `Query._entities(representations: [_Any!]!): [_Entity]!`. This field takes a list of "representations" and returns a list of the same length of the corresponding objects resulting from looking up the representations in an application-dependent way.
+
+What is a representation? A representation is expressed as the scalar type `_Any`, and can be any JSON object with a top-level `__typename` key with a string value. Often, a representation will be something like `{__typename: "User", id: "abcdef"}`: the type name plus one or more fields that you can use to look up the object in a database.
+
+There are several ways that the router can calculate a representation to pass to a subgraph. In this specification, all non-value types have a specific subgraph referred to as its "owner", specified via a `@join__owner` directive on the type. Object types that are not value types are referred to as "entities"; the type `_Entity` referenced above is a union defined in each subgraph's schema consisting of the entity types defined by that subgraph. (Only subgraphs which define entities need to define the `Query._entities` field.) Entity types must also have at least one `@join__type` directive specifying the owning subgraph along with a {key}. For each additional subgraph which can resolve fields returning that type, there should be exactly one `@join__type` directive specifying that subgraph along with a {key}, which should be identical to one of the keys specified with the owning subgraph.
+
+A key is a set of fields on the type (potentially including sub-selections and inline fragments), specified as a string. If a type `T` is annotated with `@join__type(subgraph: G, key: "a b { c }")`, then it must be possible to resolve the full field set provided as a key on subgraph G. Additionally, if you take an object with the structure returned by resolving that field set and add a field `__typename: "T"`, then you should be able to pass the resulting value as a representation to the `Query._entities` field on subgraph G.
+
+In order to resolve a field on an entity on the subgraph that owns its parent type, where that subgraph is different from the subgraph that resolved its parent object, the router first resolves a key for that object on the previous subgraph, and then uses that representation on the owning subgraph.
+
+For convenience, you may omit `@join__field(graph: A)` directives on fields whose parent type is owned by `A`.
+
+```graphql example -- Owned fields on owned types
+# Supergraph schema
+type Query {
+ fieldB: X @join__field(graph: B)
+}
+
+type X
+ @join__owner(graph: A)
+ # As the owner, A is allowed to have more than one key.
+ @join__type(graph: A, key: "x")
+ @join__type(graph: A, key: "y z")
+ # As non-owners, B and C can only have one key each and
+ # they must match a key from A.
+ @join__type(graph: B, key: "x")
+ @join__type(graph: C, key: "y z")
+{
+ # Because A owns X, we can omit @join__field(graph: A)
+ # from these three fields.
+ x: String
+ y: String
+ z: String
+}
+
+# Operation
+{ fieldB { y } }
+# Generated subgraph operations
+## On B. `y` is not available, so we need to fetch B's key for X.
+{ fieldB { x } }
+## On A
+## $r = [{__typename: "X", x: "some-x-value"}]
+query ($r: [_Any!]!) { _entities(representations: $r]) { y } }
+```
+
+## Extension fields on owned types
+
+The previous section described how to jump from one subgraph to another in order to resolve a field on the subgraph that owns the field's parent type. The situation is a bit more complicated when you want to resolve a field on a subgraph that doesn't own the field's parent type — what we call an extension field. That's because we no longer have the guarantee that the subgraph you're coming from and the subgraph you're going to share a key in common. In this case, we may need to pass through the owning type.
+
+```graphql example -- Extension fields on owned types
+# Supergraph schema
+type Query {
+ fieldB: X @join__field(graph: B)
+}
+
+type X
+ @join__owner(graph: A)
+ # As the owner, A is allowed to have more than one key.
+ @join__type(graph: A, key: "x")
+ @join__type(graph: A, key: "y z")
+ # As non-owners, B and C can only have one key each and
+ # they must match a key from A.
+ @join__type(graph: B, key: "x")
+ @join__type(graph: C, key: "y z")
+{
+ x: String
+ y: String
+ z: String
+ c: String @join__field(graph: C)
+}
+
+# Operation
+{ fieldB { c } }
+# Generated subgraph operations
+## On B. `c` is not available on B, so we need to eventually get over to C.
+## In order to do that, we need `y` and `z`... which aren't available on B
+## either! So we need to take two steps. First we use B's key.
+{ fieldB { x } }
+## On A. We use B's key to resolve our `X`, and we extract C's key.
+## $r = [{__typename: "X", x: "some-x-value"}]
+query ($r: [_Any!]!) { _entities(representations: $r]) { y z } }
+## On C. We can finally look up the field we need.
+## $r = [{__typename: "X", y: "some-y-value", z: "some-z-value"}]
+query ($r: [_Any!]!) { _entities(representations: $r]) { c } }
+```
+
+We only need to do this two-jump process because the fields needed for C's key are not available in B; otherwise a single jump would have worked, like in the owned-field case.
+
+Sometimes a particular extension field needs its parent object's representation to contain more information than its parent type's key requests. In this case, you can include a `requires` argument in the field's `@join__field` listing those required fields (potentially including sub-selections). **All required fields must be resolvable in the owning subgraph** (this restriction is why `requires` is only allowed on extension fields).
+
+```graphql example -- Required fields
+# Supergraph schema
+type Query {
+ fieldA: X @join__field(graph: A)
+}
+
+type X
+ @join__owner(graph: A)
+ @join__type(graph: A, key: "x")
+ @join__type(graph: B, key: "x")
+{
+ x: String
+ y: String
+ z: String @join__field(graph: B, requires: "y")
+}
+
+# Operation
+{ fieldA { z } }
+# Generated subgraph operations
+## On A. `x` is included because it is B's key for `X`; `y`
+## is included because of the `requires`.
+{ fieldA { x y } }
+## On B..
+## $r = [{__typename: "X", x: "some-x-value", y: "some-y-value"}]
+query ($r: [_Any!]!) { _entities(representations: $r]) { z } }
+```
+
+# Basic Requirements
+
+Schemas using the `join` core feature MUST be valid [core schema documents](https://specs.apollo.dev/core/v0.1) with {@core} directives referencing the `core` specification and this specification.
+
+:::[example](photos.graphql#schema) -- {@core} directives for supergraphs
+
+As described in the [core schema specification](https://specs.apollo.dev/core/v0.1/#sec-Prefixing), your schema may use a prefix other than `join` for all of the directive and enum names defined by this specification by including an `as` argument to the `@core` directive which references this specification. All references to directive and enum names in this specification MUST be interpreted as referring to names with the appropriate prefix chosen within your schema.
+
+In order to use the directives described by this specification, GraphQL requires you to include their definitions in your schema.
+
+Processors MUST validate that you have defined the directives with the same arguments, locations, and `repeatable` flag as given below.
+
+:::[definition](spec.graphql)
+
+Processors MUST validate that the schema contains an enum named {join__Graph}; see [its section below](#join__Graph) for other required properties of this enum.
+
+As described in the core specification, all of the directives and enums defined by this schema should be removed from the supergraph's [API schema](https://specs.apollo.dev/core/v0.1/#sec-Parts-of-a-Core-Schema). For example, the {join__Graph} enum should not be visible via introspection.
+
+# Enums
+
+##! join__Graph
+
+Enumerate subgraphs.
+
+```graphql definition
+enum join__Graph
+```
+
+Documents MUST define a {join__Graph} enum. Each enum value describes a subgraph. Each enum value MUST have a [{@join__graph}](#@join__graph) directive applied to it.
+
+:::[example](photos.graphql#join__Graph) -- Using join__Graph to define subgraphs and their endpoints
+
+The {join__Graph} enum is used as input to the [{@join__owner}](#@join__owner), [{@join__field}](#@join__field), and [{@join__type}](#@join__type) directives.
+
+# Directives
+
+##! @join__graph
+
+Declare subgraph metadata on {join__Graph} enum values.
+
+```graphql definition
+directive @join__graph(name: String!, url: String!) on ENUM_VALUE
+```
+
+:::[example](photos.graphql#join__Graph) -- Using {@join__graph} to declare subgraph metadata on the {join__Graph} enum values.
+
+The {@join__graph} directive MUST be applied to each enum value on {join__Graph}, and nowhere else. Each application of {@join__graph} MUST have a distinct value for the `name` argument; this name is an arbitrary non-empty string that can be used as a human-readable identifier which may be used for purposes such as query plan visualization and server logs. The `url` argument is an endpoint that can resolve GraphQL queries for the subgraph.
+
+##! @join__type
+
+Declares an entity key for a type on a subgraph.
+
+```graphql definition
+directive @join__type(
+ graph: join__Graph!
+ key: String!
+) repeatable on OBJECT | INTERFACE
+```
+
+When this directive is placed on a type `T`, it means that subgraph `graph` MUST be able to:
+- Resolve selections on objects of the given type that contain the field set in `key`
+- Use `Query._entities` to resolve representations of objects containing `__typename: "T"` and the fields from the field set in `key`
+
+:::[example](photos.graphql#Image) -- Using {@join__type} to specify subgraph keys
+
+Every type with a {@join__type} MUST also have a [{@join__owner}](#@join__owner) directive. Any type with a [{@join__owner}](#@join__owner) directive MUST have at least one {@join__type} directive with the same `graph` as the [{@join__owner}](#@join__owner) directive (the "owning graph"), and MUST have at most one {@join__type} directive for each `graph` value other than the owning graph. Any value that appears as a `key` in a {@join__type} directive with a `graph` value other than the owning graph must also appear as a `key` in a {@join__type} directive with `graph` equal to the owning graph.
+
+##! @join__field
+
+Specify the graph that can resolve the field.
+
+```graphql definition
+directive @join__field(
+ graph: join__Graph
+ requires: String
+ provides: String
+) on FIELD_DEFINITION
+```
+
+The field's parent type MUST be annotated with a {@join__type} with the same value of `graph` as this directive, unless the parent type is a [root operation type](http://spec.graphql.org/draft/#sec-Root-Operation-Types).
+
+If a field is not annotated with {@join__field} (or if the `graph` argument is not provided or `null`) and its parent type is annotated with `@join__owner(graph: G)`, then a processor MUST treat the field as if it is annotated with `@join__field(graph: G)`. If a field is not annotated with {@join__field} (or if the `graph` argument is not provided or `null`) and its parent type is not annotated with {@join__owner} (ie, the parent type is a value type) then it MUST be resolvable in any subgraph that can resolve values of its parent type.
+
+:::[example](photos.graphql#User...Image) -- Using {@join__field} to join fields to subgraphs
+
+Every field on a root operation type MUST be annotated with {@join__field}.
+
+:::[example](photos.graphql#Query) -- {@join__field} on root fields
+
+The `requires` argument MUST only be specified on fields whose parent type has a [{@join__owner}](#@join__owner) directive specifying a different `graph` than this {@join__field} directive does. All fields (including nested fields) mentioned in this field set must be resolvable in the parent type's owning subgraph. When constructing a representation for a parent object of this field, a router will include the fields selected in this `requires` argument in addition to the appropriate `key` for the parent type.
+
+The `provides` argument specifies fields that can be resolved in operations run on subgraph `graph` as a nested selection under this field, even if they ordinarily can only be resolved on other subgraphs.
+
+##! @join__owner
+
+Specify the graph which owns the object type.
+
+```graphql definition
+directive @join__owner(graph: join__Graph!) on OBJECT
+```
+
+The descriptions of [{@join__type}](#@join__type) and [{@join__field}](#@join__field) describes requirements on how {@join__owner} relates to {@join__type} and the `requires` argument to {@join__field}.
+
+Note: Type ownership is currently slated for removal in a future version of this spec. It is RECOMMENDED that router implementations consider approaches which function in the absence of these restrictions. The [overview](#sec-Owned-fields-on-owned-types) explains how the current router's query planning algorithm depends on concept of type ownership.
diff --git a/join/v0.1/package.json b/join/v0.1/package.json
new file mode 100644
index 0000000..d7e225f
--- /dev/null
+++ b/join/v0.1/package.json
@@ -0,0 +1,18 @@
+{
+ "name": "csdl",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "build": "rsync -avz --exclude .dist . .dist && spec-md spec.md > .dist/index.html",
+ "dev": "npm run build || true && chokidar '**/*' -i '.dist' -c 'npm run build'"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "@queerviolet/speck": "git://github.com/queerviolet/speck.git#main",
+ "chokidar-cli": "^2.1.0",
+ "watch": "^1.0.2"
+ }
+}
diff --git a/join/v0.1/photos.graphql b/join/v0.1/photos.graphql
new file mode 100644
index 0000000..2eb8e3c
--- /dev/null
+++ b/join/v0.1/photos.graphql
@@ -0,0 +1,62 @@
+schema
+ @core(feature: "https://specs.apollo.dev/core/v1.0")
+ @core(feature: "https://specs.apollo.dev/join/v1.0") {
+ query: Query
+}
+
+directive @core(feature: String!) repeatable on SCHEMA
+
+directive @join__owner(graph: join__Graph!) on OBJECT
+
+directive @join__type(
+ graph: join__Graph!
+ key: String!
+) repeatable on OBJECT | INTERFACE
+
+directive @join__field(
+ graph: join__Graph
+ requires: String
+ provides: String
+) on FIELD_DEFINITION
+
+directive @join__graph(name: String!, url: String!) on ENUM_VALUE
+
+enum join__Graph {
+ AUTH @join__graph(name: "auth", url: "https://auth.api.com")
+ ALBUMS @join__graph(name: "albums", url: "https://albums.api.com")
+ IMAGES @join__graph(name: "images", url: "https://images.api.com")
+}
+
+type Query {
+ me: User @join__field(graph: AUTH)
+ images: [Image] @join__field(graph: IMAGES)
+}
+
+type User
+ @join__owner(graph: AUTH)
+ @join__type(graph: AUTH, key: "id")
+ @join__type(graph: ALBUMS, key: "id") {
+ id: ID! @join__field(graph: AUTH)
+ name: String @join__field(graph: AUTH)
+ albums: [Album!] @join__field(graph: ALBUMS)
+}
+
+type Album
+ @join__owner(graph: ALBUMS)
+ @join__type(graph: ALBUMS, key: "id") {
+ id: ID!
+ user: User
+ photos: [Image!]
+}
+
+type Image
+ @join__owner(graph: IMAGES)
+ @join__type(graph: ALBUMS, key: "url")
+ @join__type(graph: IMAGES, key: "url") {
+ url: Url @join__field(graph: IMAGES)
+ type: MimeType @join__field(graph: IMAGES)
+ albums: [Album!] @join__field(graph: ALBUMS)
+}
+
+scalar Url
+scalar MimeType
diff --git a/join/v0.1/spec.graphql b/join/v0.1/spec.graphql
new file mode 100644
index 0000000..876f2ad
--- /dev/null
+++ b/join/v0.1/spec.graphql
@@ -0,0 +1,14 @@
+directive @join__owner(graph: join__Graph!) on OBJECT
+
+directive @join__type(
+ graph: join__Graph!,
+ key: String!,
+) repeatable on OBJECT | INTERFACE
+
+directive @join__field(
+ graph: join__Graph,
+ requires: String,
+ provides: String,
+) on FIELD_DEFINITION
+
+directive @join__graph(name: String!, url: String!) on ENUM_VALUE
diff --git a/link/v1.0/index.html b/link/v1.0/index.html
index 3625bac..60b93f9 100644
--- a/link/v1.0/index.html
+++ b/link/v1.0/index.html
@@ -1054,9 +1054,9 @@
link v1.0
Core schemas provide tools for linking definitions from different GraphQL schemas together into one.
extendschema
- # you link @link by @linking link
+ # 👇🏽 first, link @link from this url@link(url:"https://specs.apollo.dev/link/v1.0")
- # 👇🏽 schemas are identified by a url
+ # 👇🏽 link other schemas by their urls@link(url:"https://internal.example.com/admin")typeQuery{
@@ -1088,36 +1088,39 @@
Elements are the same as in global graph references. When used as scope keys, they carry the following meanings:
-
Schema(name) — a schema @linked from the document. name can be used as a prefix for definitions and references within the document, and nameMUST either be a valid prefix or null, indicating the present schema.
+
Schema(name) — a schema @linked from the document. name can be used as a prefix for definitions and references within the document, and nameMUST either be a valid prefix or null, indicating the present schema.
Directive(name) — a directive imported into the document
implicit: Bool — indicating whether the binding was explicitly imported or created implicitly. Implicit bindings may be overwritten by explicit bindings and will not be formed if an explicit binding for the item alreaady exists
+
implicit: Bool — indicating whether the binding was explicitly imported or created implicitly. Implicit bindings are “soft”—they may be overwritten by explicit bindings and will not be formed if an explicit binding for the item alreaady exists.
Similar to a gref‘s elements, different types of scoped items can have the same name without conflict. For example, a scope can contain both a type and schema named “User”, although this should generally be avoided if possible.
The global graph reference mapped to the target MUST match the item’s type—a scope cannot map a schema to a directive, for instance. The algorithms provided in this document ensure this is always the case.
@@ -1246,46 +1249,46 @@
has a name. This somewhat‐blessed directive is the schema’s “root directive”
@linking a foreign schema whose URL does not have a name will create a schema binding if and only if as: is specified, and will never create a root directive reference:
Within a core schema, type names and directives which begin with a valid namespace identifier followed by two underscores (__) will be attributed to the foreign schema bound to that name in the document scope if one exists.
extendschema
+ @link(url:"https://specs.apollo.dev/link/v1.0")
+# 1. Schema("link") -> "https://specs.apollo.dev/link/v1.0" (explicit)
+# 2. Directive("link") -> "https://specs.apollo.dev/link/v1.0#@link" (implicit)
+
+# 👇🏽 🌍 #myOwn__Purpose (note, this document has no @id, so the url of this gref is null)
+enummyOwn__Purpose{SECURITYEXECUTION}
+
extendschema
+ @id(url:"https://api.example.com")
+ @link(url:"https://specs.apollo.dev/link/v1.0",import:["@id"]
+
+# 👇🏽 🌍 https://api.example.com#myOwn__Purpose (note, this document has no @id, so the url of this gref is null)
+enummyOwn__Purpose{SECURITYEXECUTION}
+
+
+Note
+GraphQL name conventions strongly suggest against such naming. But amongst the core schema design principles is universality—the ability to represent and link any arbitrary set of GraphQL schemas, no matter how weird the names in them are.
It MUST be a valid GraphQL schema. Amongst other things, this means that it MUST contain definitions for all types and directives it references, including those from foreign schemas
@@ -1338,15 +1372,15 @@
Note
The bootstrap link is required in order to properly identify the version of the link spec in use.
SHOULD be RFC 3986 URLs. When viewed, the URL SHOULD provide schema documentation in some human‐readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
-
Link URLs MAY contain information about the spec’s name and version:
+
Link URLs MAY contain information about the spec’s name and version:
namespace prefix will automatically be linked to the URL. If a name is not present, then elements of the foreign schema must be imported in order to be referenced.
+
If name is present, that namespace prefix will automatically be linked to the URL. If a name is not present, then elements of the foreign schema must be imported in order to be referenced.
Change the namespace prefix assigned to the foreign schema. The name MUST be a valid GraphQL identifier, MUST NOT contain the namespace separator ("__"), and MUST NOT end with an underscore (which would create ambiguity between whether "x___y" is prefix x_ for element y or prefix x for element _y).
Change the namespace prefix assigned to the foreign schema. The name MUST be a valid GraphQL identifier, MUST NOT contain the namespace separator ("__"), and MUST NOT end with an underscore (which would create ambiguity between whether "x___y" is prefix x_ for element y or prefix x for element _y).
By default, @link will assign a prefix based on the name extracted from the URL. If no name is present, a prefix will not be assigned.
Providing as: overrides the default behavior: the foreign schema will be bound to the provided name, regardless of the name present in the URL (or the lack of one).
An optional purpose for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
-
By default, @links SHOULD fail open. This means that @links to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
+
By default, @links SHOULD fail open. This means that @links to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown links and serve or process the rest of the schema normally.
This behavior is different for @links with a specified purpose:
SECURITY links convey metadata necessary to compute the API schema and securely resolve fields within it
This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail‐open behavior of core schema consumers is undesirable.
-
-Note
-we’ll refer to directives from features which are for: SECURITY or for: EXECUTION as “SECURITY directives” and “EXECUTION directives”, respectively.
SECURITY links provide metadata necessary to securely resolve fields. For instance, a hypothetical auth feature may provide an @auth directive to flag fields which require authorization. If a data core does not support the auth feature and serves those fields anyway, these fields will be accessible without authorization, compromising security.
This is not intended to be an exhaustive list of all the purposes a foreign schema or its metadata might serve. Rather, it is intended to capture cases where the default fail‐open behavior of core schema consumers is undesirable.
+
+Note
+we’ll refer to directives from links which are for: SECURITY or for: EXECUTION as “SECURITY directives” and “EXECUTION directives”, respectively.
SECURITY links provide metadata necessary to securely resolve fields. For instance, a hypothetical auth schema may provide an @auth directive to flag fields which require authorization. If a data core does not support the auth schemas and serves those fields anyway, these fields will be accessible without authorization, compromising security.
Security‐conscious consumers MUST NOT serve a field if:
the schema definition has any unsupported SECURITY directives,
@@ -1486,9 +1520,9 @@
MAY choose to relax these requirements. For instance, servers may provide a development mode in which unknown SECURITY directives are ignored, perhaps with a warning. Such software may also provide a way to explicitly disable some or all SECURITY links during development.
More security‐conscious consumers MAY choose to enhance these requirements. For instance, production servers MAY adopt a policy of entirely rejecting any schema which contains ANY unsupported SECURITY links, even if those links are never used to annotate the schema.
EXECUTION features provide metadata necessary to correctly resolve fields. For instance, a hypothetical ts feature may provide a @ts__resolvers annotation which references a TypeScript module of field resolvers. A consumer which does not support the ts feature will be unable to correctly resolve such fields.
EXECUTION schemas provide metadata necessary to correctly resolve fields. For instance, a hypothetical ts schemas may provide a @ts__resolvers annotation which references a TypeScript module of field resolvers. A consumer which does not support the ts schemas will be unable to correctly resolve such fields.
the schema’s definition has any unsupported EXECUTION directives,
@@ -1496,14 +1530,14 @@
MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION features, even if those features are never used in the schema.
+
Such fields are unresolvable. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION schemas, even if those schemas are never used in the schema.
Specs are versioned with a subset of a Semantic Version Number containing only the major and minor parts. Thus, specifications SHOULD provide a version of the form vMajor.Minor, where both integers ≥ 0.
semver, the 0.x version series is special: there is no expectation of compatibility between versions 0.x and 0.y. For example, a processor must not activate implementation 0.4 to satisfy a requested version of 0.2.
-
-
Given a version requested by a document and an available version of an implementation, the following algorithm will determine if the available version can satisfy the requested version:
diff --git a/link/v1.0/link-v1.0.md b/link/v1.0/link-v1.0.md
index 04f5050..010dba6 100644
--- a/link/v1.0/link-v1.0.md
+++ b/link/v1.0/link-v1.0.md
@@ -13,9 +13,9 @@ Core schemas provide tools for linking definitions from different GraphQL schema
```graphql example -- linking a directive from another schema
extend schema
- # you link @link by @linking link
+ # 👇🏽 first, link @link from this url
@link(url: "https://specs.apollo.dev/link/v1.0")
- # 👇🏽 schemas are identified by a url
+ # 👇🏽 link other schemas by their urls
@link(url: "https://internal.example.com/admin")
type Query {
@@ -154,13 +154,13 @@ Using `@id` is not, strictly speaking, necessary. A URL can be associated with a
Core schemas have a document-wide *scope*. A document's scope is a map of {Element} ==> {Binding}. The scope is constructed from a document's [@link](#@link) and [@id](#@id) directives and is used to [attribute](#sec-Attribution) definitions and references within the document.
Elements are the same as in [global graph references](#sec-Global-Graph-References). When used as scope keys, they carry the following meanings:
-- Schema({name}) — a schema {@link}ed from the document. {name} can be used as a [prefix](#sec-Prefixing) for definitions and references within the document, and {name} MUST either be a valid prefix or {null}, indicating the present schema.
+- Schema({name}) — a schema {@link}ed from the document. {name} can be used as a [prefix](#sec-Name-Conventions) for definitions and references within the document, and {name} MUST either be a valid prefix or {null}, indicating the present schema.
- Directive({name}) — a directive [imported](#@link/import) into the document
- Type({name}) — a type [imported](#@link/import) into the document
A {Binding} contains:
- {gref}: GRef — the [global graph reference](#sec-Global-Graph-References) which is the target of the binding
-- {implicit}: Bool — indicating whether the binding was explicitly imported or created implicitly. Implicit bindings may be overwritten by explicit bindings and will not be formed if an explicit binding for the item alreaady exists
+- {implicit}: Bool — indicating whether the binding was explicitly imported or created implicitly. Implicit bindings are "soft"—they may be overwritten by explicit bindings and will not be formed if an explicit binding for the item alreaady exists.
Similar to a [gref](#sec-Global-Graph-References)'s elements, different types of scoped items can have the same name without conflict. For example, a scope can contain both a type and schema named "User", although this should generally be avoided if possible.
@@ -174,8 +174,8 @@ A {@link} without any imports introduces two entries into the scope:
```graphql example -- {@link} bringing a single schema into scope
@link(url: "https://example.com/foreignSchema")
- # 1. Schema("foreignSchema") -> https://example.com/foreignSchema (explicit)
- # 2. Directive("foreignSchema") -> https://example.com/foreignSchema#@foreignSchema (implicit)
+ # 1. foreignSchema:: -> https://example.com/foreignSchema (explicit)
+ # 2. @foreignSchema -> https://example.com/foreignSchema#@foreignSchema (implicit)
```
{@link}ing a foreign schema whose URL does not have a name will create a schema binding if and only if [`as:`](#@link/as) is specified, and will never create a root directive reference:
@@ -183,52 +183,52 @@ A {@link} without any imports introduces two entries into the scope:
```graphql example -- {@link} bringing a single schema into scope
# 👇🏽 url does not have a name
@link(url: "https://api.example.com", as: "example")
- # 1. Schema("example") -> https://example.com#example (explicit)
+ # 1. example:: -> https://example.com#example (explicit)
```
A {@link} with imports will add these entries to the scope, in addition to entries for each import:
```graphql example -- {@link} importing items into the scope
@link(url: "https://example.com/foreignSchema", import: ["SomeType", "@someDirective"])
- # 1. Schema("foreignSchema") -> https://example.com/foreignSchema (explicit)
- # 2. Directive("foreignSchema") -> https://example.com/foreignSchema#@foreignSchema (implicit)
- # 3. Type("SomeType") -> https://example.com/foreignSchema#SomeType (explicit)
- # 4. Directive("someDirective") -> https://example.com/foreignSchema#@someDirective (explicit)
+ # 1. foreignSchema:: -> https://example.com/foreignSchema (explicit)
+ # 2. @foreignSchema -> https://example.com/foreignSchema#@foreignSchema (implicit)
+ # 3. SomeType -> https://example.com/foreignSchema#SomeType (explicit)
+ # 4. @someDirective -> https://example.com/foreignSchema#@someDirective (explicit)
```
Specifying [`as:`](#@link/as) changes the names of the scope items, but not their bound grefs:
```graphql example -- {@link} conflicting schema names
@link(url: "https://example.com/foreignSchema", as: "other")
- # 1. Schema("other") -> https://example.com/foreignSchema (explicit)
- # 2. Directive("other") -> https://example.com/foreignSchema#@foreignSchema (implicit)
+ # 1. other:: -> https://example.com/foreignSchema (explicit)
+ # 2. @other -> https://example.com/foreignSchema#@foreignSchema (implicit)
```
It is not an error to overwrite an implicit binding with an explicit one:
```graphql example -- {@link} import overriding an implicit binding
@link(url: "https://example.com/foreignSchema")
- # 1. Schema("foreignSchema") -> https://example.com/foreignSchema (explicit)
- # 2. Directive("foreignSchema") -> https://example.com/foreignSchema#@foreignSchema (implicit)
+ # 1. foreignSchema:: -> https://example.com/foreignSchema (explicit)
+ # 2. @foreignSchema -> https://example.com/foreignSchema#@foreignSchema (implicit)
# (2) will be subsequently overwritten:
@link(url: "https://other.com/otherSchema, import: ["@foreignSchema"])
- # 3. Schema("otherSchema") -> https://other.com/otherSchema (explicit)
- # 4. Directive("otherSchema") -> https://other.com/otherSchema#@otherSchema (implicit)
- # 5. Directive("foreignSchema") -> https://other.com/otherSchema#@foreignSchema (explicit, overwrites (2))
+ # 3. otherSchema:: -> https://other.com/otherSchema (explicit)
+ # 4. @otherSchema -> https://other.com/otherSchema#@otherSchema (implicit)
+ # 5. @foreignSchema -> https://other.com/otherSchema#@foreignSchema (explicit, overwrites (2))
```
But it is an error to overwrite an explicit binding, or for two implicit bindings to overlap:
```graphql counter-example -- {@link} conflicting schema names
@link(url: "https://example.com/foreignSchema")
- # 1. Schema("foreignSchema") -> https://example.com/foreignSchema (explicit)
- # 2. Directive("foreignSchema") -> https://example.com/foreignSchema#@foreignSchema (implicit)
+ # 1. foreignSchema:: -> https://example.com/foreignSchema (explicit)
+ # 2. @foreignSchema -> https://example.com/foreignSchema#@foreignSchema (implicit)
@link(url: "https://other.com/foreignSchema")
- # ❌ Schema("foreignSchema") -> https://other.com/foreignSchema (explicit)
+ # ❌ foreignSchema:: -> https://other.com/foreignSchema (explicit)
# (error, conflicts with with (1))
- # ❌ Directive("foreignSchema") -> https://other.com/otherSchema#otherSchema (implicit)
+ # ❌ @foreignSchema -> https://other.com/otherSchema#otherSchema (implicit)
# (error, conflicts with (2))
```
@@ -245,6 +245,43 @@ Permissive processors (for example, a language server which wants to provide bes
# 1. Schema() -> https://example.com/myself (explicit)
```
+# Name Conventions
+
+Within a core schema, type names and directives which begin with a valid namespace identifier followed by two underscores (`__`) will be [attributed](#sec-Attribution) to the foreign schema bound to that name in the document [scope](#sec-Scope) if one exists.
+
+```graphql example -- using a prefixed name
+extend schema
+ @link(url: "https://specs.apollo.dev/link/v1.0")
+# 1. Schema("link") -> "https://specs.apollo.dev/link/v1.0" (explicit)
+# 2. Directive("link") -> "https://specs.apollo.dev/link/v1.0#@link" (implicit)
+
+# 👇🏽 🌍 https://specs.apollo.dev/link/v1.0/#Purpose
+enum link__Purpose { SECURITY EXECUTION }
+```
+
+If no schema has been linked to that name, it is interpreted as a local name:
+
+```graphql example -- a strange local name
+extend schema
+ @link(url: "https://specs.apollo.dev/link/v1.0")
+# 1. Schema("link") -> "https://specs.apollo.dev/link/v1.0" (explicit)
+# 2. Directive("link") -> "https://specs.apollo.dev/link/v1.0#@link" (implicit)
+
+# 👇🏽 🌍 #myOwn__Purpose (note, this document has no @id, so the url of this gref is null)
+enum myOwn__Purpose { SECURITY EXECUTION }
+```
+
+```graphql example -- a strange local name in a document with an id
+extend schema
+ @id(url: "https://api.example.com")
+ @link(url: "https://specs.apollo.dev/link/v1.0", import: ["@id"]
+
+# 👇🏽 🌍 https://api.example.com#myOwn__Purpose (note, this document has no @id, so the url of this gref is null)
+enum myOwn__Purpose { SECURITY EXECUTION }
+```
+
+Note: GraphQL name conventions strongly suggest against such naming. But amongst the core schema design principles is *universality*—the ability to represent and link *any arbitrary* set of GraphQL schemas, no matter how weird the names in them are.
+
## Bootstrapping
Documents can {@link} link itself. Indeed, if they MUST do so if they use [@link](#@link) at all and are intended to be [fully valid](#sec-Fully-Valid-Core-Schemas):
@@ -315,7 +352,7 @@ Link URLs serve two main purposes:
Link URLs SHOULD be [RFC 3986 URLs](https://tools.ietf.org/html/rfc3986). When viewed, the URL SHOULD provide schema documentation in some human-readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
-Link URLs MAY contain information about the spec's [name](#sec-Prefixing) and [version](#sec-Versioning):
+Link URLs MAY contain information about the spec's [name](#sec-Name-Conventions) and [version](#sec-Versioning):
```html diagram -- Basic anatomy of a link URL
@@ -343,11 +380,11 @@ All of these are valid arguments to `url`, and their interpretations:
| https://spec.example.com/v1.0 | https://spec.example.com/v1.0 | *(null)* | v1.0 |
| https://spec.example.com/vX | https://spec.example.com/vX | vX | *(null)* |
-If `name` is present, that [namespace prefix](#sec-Prefixing) will automatically be linked to the URL. If a `name` is not present, then elements of the foreign schema must be [`imported`](#@link/import) in order to be referenced.
+If `name` is present, that [namespace prefix](#sec-Name-Conventions) will automatically be linked to the URL. If a `name` is not present, then elements of the foreign schema must be [`imported`](#@link/import) in order to be referenced.
###! as: String
-Change the [namespace prefix](#sec-Prefixing) assigned to the foreign schema.
+Change the [namespace prefix](#sec-Name-Conventions) assigned to the foreign schema.
The name MUST be a valid GraphQL identifier, MUST NOT contain the namespace separator ({"__"}), and MUST NOT end with an underscore (which would create ambiguity between whether {"x___y"} is prefix `x_` for element `y` or prefix `x` for element `_y`).
@@ -391,7 +428,7 @@ See the [Import](#Import) scalar for a description of the format.
An optional [purpose](#Purpose) for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
-By default, {@link}s SHOULD fail open. This means that {@link}s to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
+By default, {@link}s SHOULD fail open. This means that {@link}s to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown links and serve or process the rest of the schema normally.
This behavior is different for {@link}s with a specified purpose:
- `SECURITY` links convey metadata necessary to compute the API schema and securely resolve fields within it
@@ -440,22 +477,22 @@ or an object with `name` and (optionally `as`):
Imports cannot currently reference transitive schemas:
```graphql counter-example -- incorrectly importing a transitive schema reference
- @link(url: "https://example.com/, import: "otherSchema::")
+ @link(url: "https://example.com/, import: ["otherSchema::"])
```
Note: Future versions may support this.
##! Purpose
-The role of a feature referenced with {@link}.
+The role of a schema referenced with {@link}.
-This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail-open behavior of core schema consumers is undesirable.
+This is not intended to be an exhaustive list of all the purposes a foreign schema or its metadata might serve. Rather, it is intended to capture cases where the default fail-open behavior of core schema consumers is undesirable.
-Note we'll refer to directives from features which are `for: SECURITY` or `for: EXECUTION` as "`SECURITY` directives" and "`EXECUTION` directives", respectively.
+Note we'll refer to directives from links which are `for: SECURITY` or `for: EXECUTION` as "`SECURITY` directives" and "`EXECUTION` directives", respectively.
###! SECURITY
-`SECURITY` links provide metadata necessary to securely resolve fields. For instance, a hypothetical {auth} feature may provide an {@auth} directive to flag fields which require authorization. If a data core does not support the {auth} feature and serves those fields anyway, these fields will be accessible without authorization, compromising security.
+`SECURITY` links provide metadata necessary to securely resolve fields. For instance, a hypothetical {auth} schema may provide an {@auth} directive to flag fields which require authorization. If a data core does not support the {auth} schemas and serves those fields anyway, these fields will be accessible without authorization, compromising security.
Security-conscious consumers MUST NOT serve a field if:
- the schema definition has **any** unsupported SECURITY directives,
@@ -471,7 +508,7 @@ More security-conscious consumers MAY choose to enhance these requirements. For
###! EXECUTION
-`EXECUTION` features provide metadata necessary to correctly resolve fields. For instance, a hypothetical {ts} feature may provide a `@ts__resolvers` annotation which references a TypeScript module of field resolvers. A consumer which does not support the {ts} feature will be unable to correctly resolve such fields.
+`EXECUTION` schemas provide metadata necessary to correctly resolve fields. For instance, a hypothetical {ts} schemas may provide a `@ts__resolvers` annotation which references a TypeScript module of field resolvers. A consumer which does not support the {ts} schemas will be unable to correctly resolve such fields.
Consumers MUST NOT serve a field if:
- the schema's definition has **any** unsupported EXECUTION directives,
@@ -479,7 +516,7 @@ Consumers MUST NOT serve a field if:
- the field's return type definition has **any** unsupported EXECUTION directives, or
- the field definition has **any** unsupported EXECUTION directives
-Such fields are *unresolvable*. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION features, even if those features are never used in the schema.
+Such fields are *unresolvable*. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION schemas, even if those schemas are never used in the schema.
# Appendix: Validations & Algorithms
@@ -551,7 +588,7 @@ BindingsFromLink(directive) :
1. **If** {as} is not a valid GraphQL identifier,
1. **Report** ❌ BadImportTypeMismatch
2. **Continue**
- 3. ...**Else Emit** (Type({as}), Binding(gref: GRef({url}, Type({name})), implicit: {false}))
+ 2. ...**Else Emit** (Type({as}), Binding(gref: GRef({url}, Type({name})), implicit: {false}))
## Detecting a bootstrap directive
diff --git a/tag/v0.1 b/tag/v0.1
deleted file mode 160000
index 7499bee..0000000
--- a/tag/v0.1
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 7499bee6709a10da5aaad8949fc9a8cd4bd1d57e
diff --git a/tag/v0.1/index.html b/tag/v0.1/index.html
new file mode 100644
index 0000000..a7ee498
--- /dev/null
+++ b/tag/v0.1/index.html
@@ -0,0 +1,1155 @@
+
+
+
+
+Tag
+
+
+
+
+
+
+
+
Tag
+
+
for tagging GraphQL schema elements with names
+
+
Status
Release
+
Version
0.1
+
+
+
+
This document defines a core feature named tag for labeling schema elements with arbitrary names (or tags).
+
This specification provides machinery to apply arbitrary tags to schema elements via the application of @tag directive usages. Tags can be applied to field, object, interface, and union definitions.
This document specifies only the definition of the @tag directive. Tags have a number of useful applications including metadata and schema processing, none of which are specified within this document.
The following example demonstrates how team ownership over types and fields can be declaratively expressed via inline metadata. One might imagine a CI workflow which analyzes a schema diff and uses @tag names to authorize or require approval for changes to parts of the graph.
This section is non‐normative. It describes the motivation behind the directives defined by this specification.
+
The @tag directive is, in its simplest form, a mechanism for applying arbitrary string metadata to the fields and types of a schema. This metadata is potentially useful throughout the schema’s lifecycle, including, but not limited to, processing, static analysis, and documentation.
+
+
+```
+
+This document defines a [core feature](https://specs.apollo.dev/core) named `tag` for labeling schema elements with arbitrary names (or tags).
+
+This specification provides machinery to apply arbitrary tags to schema elements via the application of `@tag` directive usages. Tags can be applied to field, object, interface, and union definitions.
+
+# How to read this document
+
+This document uses [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt) guidance regarding normative terms: MUST / MUST NOT / REQUIRED / SHALL / SHALL NOT / SHOULD / SHOULD NOT / RECOMMENDED / MAY / OPTIONAL.
+
+## What this document isn't
+
+This document specifies only the definition of the `@tag` directive. Tags have a number of useful applications including metadata and schema processing, none of which are specified within this document.
+
+# Example: Team Ownership Metadata
+
+The following example demonstrates how team ownership over types and fields can be declaratively expressed via inline metadata. One might imagine a CI workflow which analyzes a schema diff and uses `@tag` names to authorize or require approval for changes to parts of the graph.
+
+:::[example](ownership-example.graphql)
+
+# Overview
+
+*This section is non-normative.* It describes the motivation behind the directives defined by this specification.
+
+The `@tag` directive is, in its simplest form, a mechanism for applying arbitrary string metadata to the fields and types of a schema. This metadata is potentially useful throughout the schema's lifecycle, including, but not limited to, processing, static analysis, and documentation.
+
+# Basic Requirements
+
+A schema which implements the `@tag` spec MUST provide a definition which is compatible with the definition below:
+
+:::[definition](spec.graphql)
\ No newline at end of file
From f8487fb362378be1b3c7fe361c3cd493dd1a8394 Mon Sep 17 00:00:00 2001
From: Ashi Krishnan
Date: Mon, 25 Apr 2022 16:55:09 -0400
Subject: [PATCH 08/13] add GetPath algorithm
---
link/v1.0/index.html | 54 +++++++++++++++++++++++++++++-------------
link/v1.0/link-v1.0.md | 41 ++++++++++++++++++++++++--------
2 files changed, 68 insertions(+), 27 deletions(-)
diff --git a/link/v1.0/index.html b/link/v1.0/index.html
index 60b93f9..5a59a41 100644
--- a/link/v1.0/index.html
+++ b/link/v1.0/index.html
@@ -1112,8 +1112,8 @@
@id(url:"https://api.example.com")@link(url:"https://specs.apollo.dev/link/v1.0",import:["@id"]
-# 👇🏽 🌍 https://api.example.com#myOwn__Purpose (note, this document has no @id, so the url of this gref is null)
+# 👇🏽 🌍 https://api.example.com#myOwn__PurposeenummyOwn__Purpose{SECURITYEXECUTION}
The bootstrapping @linkMUST be the first @link in the document. Other directives may precede it, including directives which have been @linked.
+
The @link directive for @link itself—the “bootstrap”—MUST be the first @link in the document. Other directives may precede it, including directives which have been @linked.
LocateBound(scope, defOrRef) returns the binding for defOrRef if one is specified in scope, otherwise null. It does not resolve local names to the local document.
diff --git a/link/v1.0/link-v1.0.md b/link/v1.0/link-v1.0.md
index 010dba6..adaab96 100644
--- a/link/v1.0/link-v1.0.md
+++ b/link/v1.0/link-v1.0.md
@@ -276,7 +276,7 @@ extend schema
@id(url: "https://api.example.com")
@link(url: "https://specs.apollo.dev/link/v1.0", import: ["@id"]
-# 👇🏽 🌍 https://api.example.com#myOwn__Purpose (note, this document has no @id, so the url of this gref is null)
+# 👇🏽 🌍 https://api.example.com#myOwn__Purpose
enum myOwn__Purpose { SECURITY EXECUTION }
```
@@ -291,7 +291,7 @@ extend schema
@link(url: "https://specs.apollo.dev/link/v1.0")
```
-The bootstrapping {@link} MUST be the first {@link} in the document. Other directives may precede it, including directives which have been {@link}ed.
+The {@link} directive for {@link} itself—the "bootstrap"—MUST be the first {@link} in the document. Other directives may precede it, including directives which have been {@link}ed.
```graphql example -- bootstrapping {@link} and using {@id} before doing so
extend schema
@@ -299,7 +299,7 @@ extend schema
@link(url: "https://specs.apollo.dev/link/v1.0", import: ["@id"])
```
-There is otherwise nothing special or restricted about these "bootstrapping links". Documents MAY rename {@link}—either with [`as:`](#@link/as) or [`import:`](#@link/import) or both:
+There is otherwise nothing special or restricted about bootstraps. Documents MAY use them to rename {@link}—either with [`as:`](#@link/as) or [`import:`](#@link/import) or both:
```graphql example -- bootstrapping {@link} with a different name
extend schema
@@ -518,9 +518,9 @@ Consumers MUST NOT serve a field if:
Such fields are *unresolvable*. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION schemas, even if those schemas are never used in the schema.
-# Appendix: Validations & Algorithms
+# Validations & Algorithms
-## Construct the document's scope
+## Constructing the document's scope
Visit every {@link} and {@id} within the document to construct the document's scope.
@@ -608,7 +608,7 @@ IsBootstrap(directive) :
## Locating definitions and references
-Locate a definition or reference within the document's scope, returning a gref.
+{Locate} a definition or reference within the document's scope, returning a global graph reference.
{defOrRef} must be one of:
- a definition node with a name
@@ -621,19 +621,40 @@ Locate(scope, defOrRef) :
3. **Let** {myself} be the URL of the schema returned from {Lookup(scope, selfReference)}, or `Schema(null)` if none was found
1. Let {name} be the name of {defOrRef}
4. **If** {defOrRef} is a named type reference, extension, or definition, **Then**
- 1. **Return** the gref (myself, Type({name}))
- 5. Otherwise, **Return** the gref (myself, Directive({name}))
+ 1. **Return** GRef(myself, Type({name}))
+ 5. Otherwise, **Return** GRef(myself, Directive({name}))
+
+{LocateBound(scope, defOrRef)} returns the binding for {defOrRef} if one is specified
+in {scope}, otherwise {null}. It does not resolve local names to the local document.
LocateBound(scope, defOrRef) :
- 1. **Let** ({schema}, {element}) be the pair returned from {GetPathFrom(defOrRef)}
+ 1. **Let** ({schema}, {element}) be the pair returned from {GetPath(defOrRef)}
2. **If** {schema} is not {null} and exists in {scope}, **Then**
1. Let {foundGraph} be the URL of the binding found by looking up {schema} in {scope}
- 2. **Return** the gref ({foundGraph}, {element})
+ 2. **Return** GRef({foundGraph}, {element})
3. **If** {schema} is {null} and {element} exists in {scope}, **Then**
1. **Let** {foundElement} be the gref of the binding found by looking up {element} in {scope},
2. **Return** {foundElement}
4. Otherwise, **Return** {null}
+{GetPath(node)} [parses the name](#sec-Name-Conventions) of {node} and returns a (schema, element) pair.
+
+{node} must have a name.
+
+{schema} will be the {Schema} element parsed from the name, or {null} if {node}'s name does not have a prefix.
+{element} may be any type of {Element}.
+
+GetPath(node) :
+ 1. **If** {node}'s Name contains the namespace separator {"__"}, **Then**
+ 1. **Let** {prefix} be the part of {node}'s Name up to the first instance of the namespace separator {"__"}
+ 2. **Let** {base} be the part of {node}'s Name after the first instance of the namespace separator {"__"}
+ 2. ...**Else**,
+ 1. **Let** {prefix} be {null}
+ 2. **Let** {base} be Name
+ 3. **If** {node} is a Directive, **Then Return** (Schema({prefix}), Directive({base}))
+ 4. ...**Else Return** (Schema({prefix}), Type({base}))
+
+
# Appendix: Versioning
VersionTag : "v" Version
From e701f8865f6963a0eb989b4914d27cf732051a3d Mon Sep 17 00:00:00 2001
From: Ashi Krishnan
Date: Mon, 25 Apr 2022 17:00:08 -0400
Subject: [PATCH 09/13] tweak algorithms
---
link/v1.0/index.html | 17 ++++++++++-------
link/v1.0/link-v1.0.md | 15 ++++++++-------
2 files changed, 18 insertions(+), 14 deletions(-)
diff --git a/link/v1.0/index.html b/link/v1.0/index.html
index 5a59a41..d0e4e68 100644
--- a/link/v1.0/index.html
+++ b/link/v1.0/index.html
@@ -1690,14 +1690,14 @@
Letmyself be the URL of the schema returned from Lookup(scope, selfReference), or Schema(null) if none was found
-
Let name be the name of defOrRef
-
IfdefOrRef is a named type reference, extension, or definition, Then
-
Return GRef(myself, Type(name))
+
LetselfReference be the element Schema()
+
Letmyself be the URL of the schema returned from Lookup(scope, selfReference), or null if none was found
+
Let name be the Name of defOrRef
+
IfdefOrRef is a Directive or DirectiveDefinition Then
+
Return GRef(myself, Directive(name))
-
Otherwise, Return GRef(myself, Directive(name))
+
Otherwise, Return GRef(myself, Type(name))
LocateBound(scope, defOrRef) returns the binding for defOrRef if one is specified in scope, otherwise null. It does not resolve local names to the local document.
diff --git a/link/v1.0/link-v1.0.md b/link/v1.0/link-v1.0.md
index adaab96..f59f57f 100644
--- a/link/v1.0/link-v1.0.md
+++ b/link/v1.0/link-v1.0.md
@@ -617,12 +617,12 @@ IsBootstrap(directive) :
Locate(scope, defOrRef) :
1. **If** {LocateBound(scope, defOrRef)} is not {null} **Then Return** {LocateBound(scope, defOrRef)}
- 3. **Let** {selfReference} be the item `Schema()`
- 3. **Let** {myself} be the URL of the schema returned from {Lookup(scope, selfReference)}, or `Schema(null)` if none was found
- 1. Let {name} be the name of {defOrRef}
- 4. **If** {defOrRef} is a named type reference, extension, or definition, **Then**
- 1. **Return** GRef(myself, Type({name}))
- 5. Otherwise, **Return** GRef(myself, Directive({name}))
+ 3. **Let** {selfReference} be the element `Schema()`
+ 3. **Let** {myself} be the URL of the schema returned from {Lookup(scope, selfReference)}, or {null} if none was found
+ 1. Let {name} be the Name of {defOrRef}
+ 4. **If** {defOrRef} is a Directive or DirectiveDefinition **Then**
+ 1. **Return** GRef(myself, Directive({name}))
+ 5. Otherwise, **Return** GRef(myself, Type({name}))
{LocateBound(scope, defOrRef)} returns the binding for {defOrRef} if one is specified
in {scope}, otherwise {null}. It does not resolve local names to the local document.
@@ -651,7 +651,8 @@ GetPath(node) :
2. ...**Else**,
1. **Let** {prefix} be {null}
2. **Let** {base} be Name
- 3. **If** {node} is a Directive, **Then Return** (Schema({prefix}), Directive({base}))
+ 3. **If** {node} is a Directive or DirectiveDefinition, **Then**
+ 1. **Return** (Schema({prefix}), Directive({base}))
4. ...**Else Return** (Schema({prefix}), Type({base}))
From cbd9e6af1e68a46c245ae097b452fddd4ba6e71f Mon Sep 17 00:00:00 2001
From: Ashi Krishnan
Date: Mon, 25 Apr 2022 18:07:22 -0400
Subject: [PATCH 10/13] federation FieldSet to _FieldSet
---
federation/v2.0/federation-v2.0.md | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/federation/v2.0/federation-v2.0.md b/federation/v2.0/federation-v2.0.md
index 7f3eee7..73fd8f0 100644
--- a/federation/v2.0/federation-v2.0.md
+++ b/federation/v2.0/federation-v2.0.md
@@ -96,21 +96,21 @@ extend type User @key(fields: "email") {
This type extension in the Reviews service extends the `User` type from the Users service. It extends it for the purpose of adding a new field called `reviews`, which returns a list of `Review`s.
-#! FieldSet
+#! _FieldSet
```graphql definition
-scalar FieldSet
+scalar _FieldSet
```
A set of fields.
-```graphql example -- Using `FieldSet` with a single field in a `@key`
+```graphql example -- Using `_FieldSet` with a single field in a `@key`
type User @key(fields: "id") {
id: ID! @external
}
```
-```graphql example -- Using `FieldSet` with a multiple fields
+```graphql example -- Using `_FieldSet` with a multiple fields
type User @key(fields: "uid realm") {
uid: String
realm: String
@@ -119,7 +119,7 @@ type User @key(fields: "uid realm") {
Deeply nested fields are supported with standard GraphQL syntax
-```graphql example -- `FieldSet` with nested fields
+```graphql example -- `_FieldSet` with nested fields
type User @key(fields: "contact { email }") {
contact: Contact
}
@@ -131,7 +131,7 @@ type Contact {
Field arguments are not supported.
-```graphql counter-example -- `FieldSet` does not support field arguments
+```graphql counter-example -- `_FieldSet` does not support field arguments
type User @key(fields: "emails(first: 1)") {
emails(first: Int): [String]
}
From 9540775a9bcbfda750ef0e3a96a70b8d65c175fb Mon Sep 17 00:00:00 2001
From: Ashi Krishnan
Date: Tue, 26 Apr 2022 17:43:07 -0400
Subject: [PATCH 11/13] Add canonical schema for federation, join, link, and
historical cores. Redirect federation spec to fedeation docs.
---
_redirects | 3 +
core/v0.1/core-v0.1.graphql | 5 +
core/v0.1/core-v0.1.md | 7 +-
core/v0.1/index.html | 149 +++--
core/v0.2/core-v0.2.graphql | 7 +
core/v0.2/core-v0.2.md | 16 +-
core/v0.2/index.html | 187 +++---
federation/v2.0/federation-v2.0.graphql | 13 +
federation/v2.0/federation-v2.0.md | 63 +-
federation/v2.0/index.html | 117 ++--
inaccessible/v0.1/index.html | 52 +-
join/v0.1/index.html | 284 ++++-----
link/link-v1.0.spec.graphql | 456 --------------
link/prefixing.graphql | 46 --
link/v1.0/algorithms.md | 132 -----
link/v1.0/basic.graphql | 14 -
link/v1.0/core-schemas-intro.md | 23 -
link/v1.0/index.html | 752 +++---------------------
link/v1.0/link-v1.0.graphql | 20 +
link/v1.0/link-v1.0.md | 565 +-----------------
link/v1.0/prefix-uniqueness.graphql | 25 -
tag/v0.1/index.html | 26 +-
22 files changed, 636 insertions(+), 2326 deletions(-)
create mode 100644 core/v0.1/core-v0.1.graphql
create mode 100644 core/v0.2/core-v0.2.graphql
create mode 100644 federation/v2.0/federation-v2.0.graphql
delete mode 100644 link/link-v1.0.spec.graphql
delete mode 100644 link/prefixing.graphql
delete mode 100644 link/v1.0/algorithms.md
delete mode 100644 link/v1.0/basic.graphql
delete mode 100644 link/v1.0/core-schemas-intro.md
create mode 100644 link/v1.0/link-v1.0.graphql
delete mode 100644 link/v1.0/prefix-uniqueness.graphql
diff --git a/_redirects b/_redirects
index 6aa21dd..a992c8e 100644
--- a/_redirects
+++ b/_redirects
@@ -19,6 +19,9 @@
# This represents the official release. It redirects to the branch release below.
/core/ /core/v0.2/ 302!
+# Federation 2.0 spec
+/federation/v2.0/* https://www.apollographql.com/docs/federation/federation-spec/:splat 302!
+
# This represents what's on "main" but acts as work in progress.
/core/draft/* https://apollo-specs-core.netlify.app/:splat 200!
diff --git a/core/v0.1/core-v0.1.graphql b/core/v0.1/core-v0.1.graphql
new file mode 100644
index 0000000..0252eea
--- /dev/null
+++ b/core/v0.1/core-v0.1.graphql
@@ -0,0 +1,5 @@
+directive @core(
+ feature: String!,
+ as: String)
+ repeatable on SCHEMA
+
diff --git a/core/v0.1/core-v0.1.md b/core/v0.1/core-v0.1.md
index e67f292..b21756d 100644
--- a/core/v0.1/core-v0.1.md
+++ b/core/v0.1/core-v0.1.md
@@ -156,12 +156,7 @@ When writing a specification for your own core feature, you SHOULD include a sec
Declare a core feature present in this schema.
-```graphql definition
-directive @core(
- feature: String!,
- as: String)
- repeatable on SCHEMA
-```
+:::[definition](./core-v0.1.graphql#@core)
Documents MUST include a definition for the {@core} directive which includes all of the arguments defined above with the same types and default values.
diff --git a/core/v0.1/index.html b/core/v0.1/index.html
index df41bb3..4fa072d 100644
--- a/core/v0.1/index.html
+++ b/core/v0.1/index.html
@@ -1072,16 +1072,16 @@
Core schemas provide a concise mechanism for schema documents to specify the metadata they provide. Metadata is grouped into features, which typically define directives and associated types (e.g. scalars and inputs which serve as directive inputs). Additionally, core schemas provide:
MUST NOT be served to clients. Specifically, machinery MUST NOT be included in introspection responses or used to validate or execute queries.
This reflects how core schemas are used: a core schema contains a GraphQL interface (the API) along with metadata about how to implement that interface (the machinery). Exposing the machinery to clients is unnecessary, and may in some cases constitute a security issue (for example, the machinery for a public‐facing graph router will likely reference internal services, possibly exposing network internals which should not be visible to the general public).
-
A key feature of core schemas is that it is always possible to derive a core schema’s API without any knowledge of the features used by the document (with the exception of the core feature itself). Specifically, named elements are not included in the API schema if they are named something__likeThis or are a directive named @something, and something is the prefix of a feature declared with @core.
+
A key feature of core schemas is that it is always possible to derive a core schema’s API without any knowledge of the features used by the document (with the exception of the core feature itself). Specifically, named elements are not included in the API schema if they are named something__likeThis or are a directive named @something, and something is the prefix of a feature declared with @core.
A formal description is provided by the IsInAPI algorithm.
Authors (either human or machine) write an initial core schema as specified in this document, including versioned @core requests for all directives they use
-
Machine processors can process core schemas and output new core schemas. The versioning of directives and associated schema elements provided by the @core allows processors to operate on directives they understand and pass through directives they do not.
-
Human readers can examine the core schema at various stages of processing. At any stage, they can examine the @core directives and follow URLs to the specification, receiving an explanation of the requirements of the specification and what new directives, types, and other schema objects are available within the document.
+
Authors (either human or machine) write an initial core schema as specified in this document, including versioned @core requests for all directives they use
+
Machine processors can process core schemas and output new core schemas. The versioning of directives and associated schema elements provided by the @core allows processors to operate on directives they understand and pass through directives they do not.
+
Human readers can examine the core schema at various stages of processing. At any stage, they can examine the @core directives and follow URLs to the specification, receiving an explanation of the requirements of the specification and what new directives, types, and other schema objects are available within the document.
Data cores can then pick up the processed core schema and provide some data‐layer service with it. Typically this means serving the schema’s API as a GraphQL endpoint, using metadata defined by machinery to inform how it processes operations it receives. However, data cores may perform other tasks described in the core schema, such as routing to backend services, caching commonly‐accessed fields and queries, and so on. The term “data core” is intended to capture this multiplicity of possible activities.
schema@core(feature:"https://specs.apollo.dev/core/v0.1"){
- query:Query
+ query: Query
}typeSomeType{
- field:Int@another
+ field: Int @another}# `@another` is unspecified. Core processors will not extract metadata from# it, but its definition and all usages within the schema will be exposed# in the API.
-directive@anotheronFIELD_DEFINITION
+directive@anotheronFIELD_DEFINITION
-directive@core(feature:String!,as:String)repeatableonSCHEMA
+directive@core(feature: String!,as: String)repeatableonSCHEMA
All core schemas use the @core directive to declare their use of the core feature itself as well as any other core features they use.
+
All core schemas use the @core directive to declare their use of the core feature itself as well as any other core features they use.
In order to use these directives in your schema, GraphQL requires you to include their definitions in your schema.
Processors MUST validate that you have defined the directives with the same arguments, locations, and repeatable flag as given below. Specifically, the bootstrapping algorithm validates that the @core directive has a definition matching the definition given below. (The bootstrapping algorithm does not require processors to validate other aspects of the directive declaration such as description strings or argument ordering. The main purpose of this validation is to ensure that directive arguments have the type and default values expected by the specification.)
The following declares the directive defined by this specification. You SHOULD define the directives in your core schema by including the following text in your schema document.
When writing a specification for your own core feature, you SHOULD include a section like this one with sample definitions to copy into schemas, and you SHOULD require processors to validate that directive definitions in documents match your sample definitions.
A feature URL specifying the directive and associated schema elements. When viewed, the URL SHOULD provide the content of the appropriate version of the specification in some human‐readable form. In short, a human reader should be able to click the link and go to the docs for the version in use. There are specific requirements on the format of the URL, but it is not required that the content be machine‐readable in any particular way.
Feature URLs contain information about the spec’s prefix and version.
Feature URLs serve two main purposes:
@@ -1281,23 +1280,23 @@
5.1.1.2Why is versioning in the URL, not a directive argument?
-
The version is in the URL because when a human reader visits the URL, we would like them to be taken to the documentation for the version of the feature used by this document. Many text editors will turn URLs into hyperlinks, and it’s highly desirable that clicking the link takes the user to the correct version of the docs. Putting the version information in a separate argument to the @core directive would prevent this.
+
The version is in the URL because when a human reader visits the URL, we would like them to be taken to the documentation for the version of the feature used by this document. Many text editors will turn URLs into hyperlinks, and it’s highly desirable that clicking the link takes the user to the correct version of the docs. Putting the version information in a separate argument to the @core directive would prevent this.
Change the names of directives and schema elements from this specification. The specified string MUST be a valid GraphQL name and MUST NOT contain the namespace separator (two underscores, "__") or end with an underscore.
When as: is provided, processors looking for prefixed schema elementsMUST look for elements whose names are the specified name with the prefix replaced with the name provided to the as: argument.
schema@core(feature:"https://specs.apollo.dev/core/v0.1")@core(feature:"https://spec.example.com/example/v1.0",as:"eg"){
- query:Query
+ query: Query
}typeUser{# Specifying `as: "eg"` transforms @example into @eg
- name:String@eg(data:ITEM)
+ name: String @eg(data:ITEM)}# Additional specified schema elements must have their prefixes set
@@ -1306,15 +1305,15 @@
# The spec at https://spec.example.com/example/v1.0 calls this enum# `example__Data`, but because of the `as:` argument above, processors# will use this `eg__Data` enum instead.
-enumeg__Data{
+enumeg__Data{ITEM}# Name transformation must also be applied to definitions pulled in from# specifications.
-directive@eg(data:eg__Data)onFIELD_DEFINITION
+directive@eg(data: eg__Data)onFIELD_DEFINITION
-directive@core(feature:String!,as:String)repeatableonSCHEMA
+directive@core(feature: String!,as: String)repeatableonSCHEMA
@@ -1328,30 +1327,30 @@
MUST NOT contain the core namespace separator, which is two underscores ("__"), and
MUST NOT end with an underscore (which would create ambiguity between whether "x___y" is prefix x_ for element y or prefix x for element _y).
-
Prefixed names consist of the name of the feature, followed by two underscores, followed by the name of the element, which can be any valid GraphQL name. For instance, the core specification (which you are currently reading) introduces an element named @core, and the join specification introduces an element named @join__field (among others).
+
Prefixed names consist of the name of the feature, followed by two underscores, followed by the name of the element, which can be any valid GraphQL name. For instance, the core specification (which you are currently reading) introduces an element named @core, and the join specification introduces an element named @join__field (among others).
Note
that both parts must be valid GraphQL names, and GraphQL names cannot start with digits, so core feature specifications cannot introduce names like @feature__24hours.
-
A feature’s root directive is an exception to the prefixing requirements. Feature specifications MAY introduce a single directive which carries only the name of the feature, with no prefix required. For example, the core specification introduces a @core directive. This directive has the same name as the feature (”core”), and so requires no prefix.
+
A feature’s root directive is an exception to the prefixing requirements. Feature specifications MAY introduce a single directive which carries only the name of the feature, with no prefix required. For example, the core specification introduces a @core directive. This directive has the same name as the feature (”core”), and so requires no prefix.
schema@core(feature:"https://specs.apollo.dev/core/v0.1")@core(feature:"https://spec.example.com/example/v1.0"){
- query:Query
+ query: Query
}typeUser{
- name:String@example(data:ITEM)
+ name: String @example(data:ITEM)}# An enum used to provide structured data to the example spec.# It is prefixed with the name of the spec.
-enumexample__Data{
+enumexample__Data{ITEM}
-directive@example(data:example__Data)onFIELD_DEFINITION
+directive@example(data: example__Data)onFIELD_DEFINITION
-directive@core(feature:String!,as:String)repeatableonSCHEMA
+directive@core(feature: String!,as: String)repeatableonSCHEMA
The prefix MUST NOT be elided within documentation; definitions of schema elements provided within the spec MUST include the feature’s name as a prefix.
@@ -1365,48 +1364,48 @@
@core(feature:"https://specs.apollo.dev/core/v0.1")@core(feature:"https://spec.example.com/featureA/v1.0")@core(feature:"https://spec.example.com/featureB/v2.0",as:"B"){
- query:Query
+ query: Query
}"""
featureA__SomeType is a type defined by feature A.
"""
-typefeatureA__SomeType{
+typefeatureA__SomeType{"""
nativeField is a field defined by featureA on a type also defined
by featureA (namely featureA__SomeType)
"""
- nativeField:Int@featureA__fieldDirective
+ nativeField: Int @featureA__fieldDirective}"""
featureA__SomeInput is an input specified by feature A
"""
-inputfeatureA__SomeInput{
+input featureA__SomeInput {"""
nativeInputField is defined by featureA
"""
- nativeInputField:Int
+ nativeInputField: Int
}"""
featureA__Items is specified by feature A
"""
-enumfeatureA__Items{ONE,TWO,THREE@B}
+enumfeatureA__Items{ONE,TWO,THREE@B}"""
@B is the root directive defined by featureB
Root directives are named after their feature
"""
-directive@BonENUM_VALUE
+directive@BonENUM_VALUE"""
@featureA__fieldDirective is a non-root (prefixed) directive defined by featureA
"""
-directive@featureA__fieldDirectiveonFIELD_DEFINITION
+directive@featureA__fieldDirectiveonFIELD_DEFINITION
-directive@core(feature:String!,as:String)repeatableonSCHEMA
+directive@core(feature: String!,as: String)repeatableonSCHEMA
@@ -1475,9 +1474,9 @@
SHOULD pass through @core directives which reference unknown feature URLs
+
SHOULD pass through @core directives which reference unknown feature URLs
SHOULD pass through prefixed directives, types, and other schema elements
Processors MAY accept configuration which overrides these default behaviors.
Additionally, processors which prepare the schema for final public consumption MAY choose to eliminate all unknown directives and prefixed types in order to hide schema implementation details within the published schema. This will impair the operation of tooling which relies on these directives—such tools will not be able to run on the output schema, so the benefits and costs of this kind of information hiding should be weighed carefully on a case‐by‐case basis.
@@ -1492,9 +1491,9 @@
rename the core feature within a document. This process determines the actual name for the core feature if one is present.
Fails the Has Schema validation if there are no SchemaDefinitions in the document
-
Fails the Has Core Feature validation if the core feature itself is not referenced with a @core directive within the document
-
Fails the Bootstrap Core Feature Listed First validation if the reference to the core feature is not the first @core directive on the document’s SchemaDefinition
-
Fails the Core Directive Incorrect Definition validation if the @core directive definition does not match the directive as defined by this specification.
+
Fails the Has Core Feature validation if the core feature itself is not referenced with a @core directive within the document
+
Fails the Bootstrap Core Feature Listed First validation if the reference to the core feature is not the first @core directive on the document’s SchemaDefinition
+
Fails the Core Directive Incorrect Definition validation if the @core directive definition does not match the directive as defined by this specification.
For the purposes of this algorithm, a directive’s definition in a schema matches a definition provided in this specification if:
If d has a feature: argument which parses as a feature URL, and whose identity is "https://specs.apollo.dev/core/"and whose version is "v0.1", and eitherd has an as: argument whose value is equal to d‘s name ord does not have an as: argument and d‘s name is core:
If any directive on schema listed before d has the same name as d, the Bootstrap Core Feature Listed First validation fails.
Collect a map of (featureName: String) → Directive, where Directive is a @core Directive which introduces the feature named featureName into the document.
+
Collect a map of (featureName: String) → Directive, where Directive is a @core Directive which introduces the feature named featureName into the document.
Fails the Name Uniqueness validation if feature names are not unique within the document.
FailsInvalid Feature URL validation for any invalid feature URLs.
@core(feature:"https://specs.example.com/A/1.0")# name is A@core(feature:"https://specs.example.com/A/2.0",as:"A2")# name is A2{
- query:Query
+ query: Query
}
Without the explicit as:, the above would be invalid:
@core(feature:"https://specs.example.com/A/1.0")# name is A@core(feature:"https://www.specs.com/specA/1.1",as:"A")# name is A{
- query:Query
+ query: Query
}
diff --git a/core/v0.2/core-v0.2.graphql b/core/v0.2/core-v0.2.graphql
new file mode 100644
index 0000000..89e02ca
--- /dev/null
+++ b/core/v0.2/core-v0.2.graphql
@@ -0,0 +1,7 @@
+directive @core(
+ feature: String!,
+ as: String,
+ for: Purpose)
+ repeatable on SCHEMA
+
+enum Purpose { SECURITY EXECUTION }
\ No newline at end of file
diff --git a/core/v0.2/core-v0.2.md b/core/v0.2/core-v0.2.md
index ff1aa04..9ba8b86 100644
--- a/core/v0.2/core-v0.2.md
+++ b/core/v0.2/core-v0.2.md
@@ -167,13 +167,7 @@ When writing a specification for your own core feature, you SHOULD include a sec
Declare a core feature present in this schema.
-```graphql definition
-directive @core(
- feature: String!,
- as: String,
- for: core__Purpose)
- repeatable on SCHEMA
-```
+:::[definition](./core-v0.2.graphql#@core)
Documents MUST include a definition for the {@core} directive which includes all of the arguments defined above with the same types and default values.
@@ -261,15 +255,15 @@ directive @eg(data: eg__Data) on FIELD_DEFINITION
directive @core(feature: String!, as: String) repeatable on SCHEMA
```
-###! for: core__Purpose
+###! for: Purpose
-An optional [purpose](#core__Purpose) for this feature. This hints to consumers as to whether they can safely ignore metadata from a given feature.
+An optional [purpose](#Purpose) for this feature. This hints to consumers as to whether they can safely ignore metadata from a given feature.
By default, core features SHOULD fail open. This means that an unknown feature SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
This behavior is different for features with a specified purpose:
- - [`SECURITY`](#core__Purpose/SECURITY) features convey metadata necessary to securely resolve fields within the schema
- - [`EXECUTION`](#core__Purpose/EXECUTION) features convey metadata necessary to correctly resolve fields within the schema
+ - [`SECURITY`](#Purpose.SECURITY) features convey metadata necessary to securely resolve fields within the schema
+ - [`EXECUTION`](#Purpose.EXECUTION) features convey metadata necessary to correctly resolve fields within the schema
# Enums
diff --git a/core/v0.2/index.html b/core/v0.2/index.html
index b981165..2e53055 100644
--- a/core/v0.2/index.html
+++ b/core/v0.2/index.html
@@ -1082,16 +1082,16 @@
Core schemas provide a concise mechanism for schema documents to specify the metadata they provide. Metadata is grouped into features, which typically define directives and associated types (e.g. scalars and inputs which serve as directive inputs). Additionally, core schemas provide:
MUST NOT be served to clients. Specifically, machinery MUST NOT be included in introspection responses or used to validate or execute queries.
This reflects how core schemas are used: a core schema contains a GraphQL interface (the API) along with metadata about how to implement that interface (the machinery). Exposing the machinery to clients is unnecessary, and may in some cases constitute a security issue (for example, the machinery for a public‐facing graph router will likely reference internal services, possibly exposing network internals which should not be visible to the general public).
-
A key feature of core schemas is that it is always possible to derive a core schema’s API without any knowledge of the features used by the document (with the exception of the core feature itself). Specifically, named elements are not included in the API schema if they are named something__likeThis or are a directive named @something, and something is the prefix of a feature declared with @core.
+
A key feature of core schemas is that it is always possible to derive a core schema’s API without any knowledge of the features used by the document (with the exception of the core feature itself). Specifically, named elements are not included in the API schema if they are named something__likeThis or are a directive named @something, and something is the prefix of a feature declared with @core.
A formal description is provided by the IsInAPI algorithm.
Authors (either human or machine) write an initial core schema as specified in this document, including versioned @core requests for all directives they use
-
Machine processors can process core schemas and output new core schemas. The versioning of directives and associated schema elements provided by the @core allows processors to operate on directives they understand and pass through directives they do not.
-
Human readers can examine the core schema at various stages of processing. At any stage, they can examine the @core directives and follow URLs to the specification, receiving an explanation of the requirements of the specification and what new directives, types, and other schema objects are available within the document.
+
Authors (either human or machine) write an initial core schema as specified in this document, including versioned @core requests for all directives they use
+
Machine processors can process core schemas and output new core schemas. The versioning of directives and associated schema elements provided by the @core allows processors to operate on directives they understand and pass through directives they do not.
+
Human readers can examine the core schema at various stages of processing. At any stage, they can examine the @core directives and follow URLs to the specification, receiving an explanation of the requirements of the specification and what new directives, types, and other schema objects are available within the document.
Data cores can then pick up the processed core schema and provide some data‐layer service with it. Typically this means serving the schema’s API as a GraphQL endpoint, using metadata defined by machinery to inform how it processes operations it receives. However, data cores may perform other tasks described in the core schema, such as routing to backend services, caching commonly‐accessed fields and queries, and so on. The term “data core” is intended to capture this multiplicity of possible activities.
schema@core(feature:"https://specs.apollo.dev/core/v0.1"){
- query:Query
+ query: Query
}typeSomeType{
- field:Int@another
+ field: Int @another}# `@another` is unspecified. Core processors will not extract metadata from# it, but its definition and all usages within the schema will be exposed# in the API.
-directive@anotheronFIELD_DEFINITION
+directive@anotheronFIELD_DEFINITION
-directive@core(feature:String!,as:String)repeatableonSCHEMA
+directive@core(feature: String!,as: String)repeatableonSCHEMA
All core schemas use the @core directive to declare their use of the core feature itself as well as any other core features they use.
+
All core schemas use the @core directive to declare their use of the core feature itself as well as any other core features they use.
In order to use these directives in your schema, GraphQL requires you to include their definitions in your schema.
Processors MUST validate that you have defined the directives with the same arguments, locations, and repeatable flag as given below. Specifically, the bootstrapping algorithm validates that the @core directive has a definition matching the definition given below. (The bootstrapping algorithm does not require processors to validate other aspects of the directive declaration such as description strings or argument ordering. The main purpose of this validation is to ensure that directive arguments have the type and default values expected by the specification.)
The following declares the directive defined by this specification. You SHOULD define the directives in your core schema by including the following text in your schema document.
When writing a specification for your own core feature, you SHOULD include a section like this one with sample definitions to copy into schemas, and you SHOULD require processors to validate that directive definitions in documents match your sample definitions.
A feature URL specifying the directive and associated schema elements. When viewed, the URL SHOULD provide the content of the appropriate version of the specification in some human‐readable form. In short, a human reader should be able to click the link and go to the docs for the version in use. There are specific requirements on the format of the URL, but it is not required that the content be machine‐readable in any particular way.
Feature URLs contain information about the spec’s prefix and version.
Feature URLs serve two main purposes:
@@ -1302,23 +1301,23 @@
5.1.1.2Why is versioning in the URL, not a directive argument?
-
The version is in the URL because when a human reader visits the URL, we would like them to be taken to the documentation for the version of the feature used by this document. Many text editors will turn URLs into hyperlinks, and it’s highly desirable that clicking the link takes the user to the correct version of the docs. Putting the version information in a separate argument to the @core directive would prevent this.
+
The version is in the URL because when a human reader visits the URL, we would like them to be taken to the documentation for the version of the feature used by this document. Many text editors will turn URLs into hyperlinks, and it’s highly desirable that clicking the link takes the user to the correct version of the docs. Putting the version information in a separate argument to the @core directive would prevent this.
Change the names of directives and schema elements from this specification. The specified string MUST be a valid GraphQL name and MUST NOT contain the namespace separator (two underscores, "__") or end with an underscore.
When as: is provided, processors looking for prefixed schema elementsMUST look for elements whose names are the specified name with the prefix replaced with the name provided to the as: argument.
schema@core(feature:"https://specs.apollo.dev/core/v0.1")@core(feature:"https://spec.example.com/example/v1.0",as:"eg"){
- query:Query
+ query: Query
}typeUser{# Specifying `as: "eg"` transforms @example into @eg
- name:String@eg(data:ITEM)
+ name: String @eg(data:ITEM)}# Additional specified schema elements must have their prefixes set
@@ -1327,25 +1326,25 @@
# The spec at https://spec.example.com/example/v1.0 calls this enum# `example__Data`, but because of the `as:` argument above, processors# will use this `eg__Data` enum instead.
-enumeg__Data{
+enumeg__Data{ITEM}# Name transformation must also be applied to definitions pulled in from# specifications.
-directive@eg(data:eg__Data)onFIELD_DEFINITION
+directive@eg(data: eg__Data)onFIELD_DEFINITION
-directive@core(feature:String!,as:String)repeatableonSCHEMA
+directive@core(feature: String!,as: String)repeatableonSCHEMA
An optional purpose for this feature. This hints to consumers as to whether they can safely ignore metadata from a given feature.
By default, core features SHOULD fail open. This means that an unknown feature SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
This behavior is different for features with a specified purpose:
-
SECURITY features convey metadata necessary to securely resolve fields within the schema
-
EXECUTION features convey metadata necessary to correctly resolve fields within the schema
+
SECURITY features convey metadata necessary to securely resolve fields within the schema
+
EXECUTION features convey metadata necessary to correctly resolve fields within the schema
This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail‐open behavior of core schema consumers is undesirable.
Note
we’ll refer to directives from features which are for: SECURITY or for: EXECUTION as “SECURITY directives” and “EXECUTION directives”, respectively.
SECURITY features provide metadata necessary to securely resolve fields. For instance, a hypothetical auth feature may provide an @auth directive to flag fields which require authorization. If a data core does not support the auth feature and serves those fields anyway, these fields will be accessible without authorization, compromising security.
SECURITY features provide metadata necessary to securely resolve fields. For instance, a hypothetical auth feature may provide an @auth directive to flag fields which require authorization. If a data core does not support the auth feature and serves those fields anyway, these fields will be accessible without authorization, compromising security.
Security‐conscious consumers MUST NOT serve a field if:
the schema definition has any unsupported SECURITY directives,
@@ -1378,8 +1377,8 @@
MAY choose to relax these requirements. For instance, servers may provide a development mode in which unknown SECURITY directives are ignored, perhaps with a warning. Such software may also provide a way to explicitly disable some or all SECURITY features during development.
More security‐conscious consumers MAY choose to enhance these requirements. For instance, production servers MAY adopt a policy of entirely rejecting any schema which contains ANY unsupported SECURITY features, even if those features are never used to annotate the schema.
EXECUTION features provide metadata necessary to correctly resolve fields. For instance, a hypothetical ts feature may provide a @ts__resolvers annotation which references a TypeScript module of field resolvers. A consumer which does not support the ts feature will be unable to correctly resolve such fields.
MUST NOT contain the core namespace separator, which is two underscores ("__"), and
MUST NOT end with an underscore (which would create ambiguity between whether "x___y" is prefix x_ for element y or prefix x for element _y).
-
Prefixed names consist of the name of the feature, followed by two underscores, followed by the name of the element, which can be any valid GraphQL name. For instance, the core specification (which you are currently reading) introduces an element named @core, and the join specification introduces an element named @join__field (among others).
+
Prefixed names consist of the name of the feature, followed by two underscores, followed by the name of the element, which can be any valid GraphQL name. For instance, the core specification (which you are currently reading) introduces an element named @core, and the join specification introduces an element named @join__field (among others).
Note
that both parts must be valid GraphQL names, and GraphQL names cannot start with digits, so core feature specifications cannot introduce names like @feature__24hours.
-
A feature’s root directive is an exception to the prefixing requirements. Feature specifications MAY introduce a single directive which carries only the name of the feature, with no prefix required. For example, the core specification introduces a @core directive. This directive has the same name as the feature (”core”), and so requires no prefix.
+
A feature’s root directive is an exception to the prefixing requirements. Feature specifications MAY introduce a single directive which carries only the name of the feature, with no prefix required. For example, the core specification introduces a @core directive. This directive has the same name as the feature (”core”), and so requires no prefix.
schema@core(feature:"https://specs.apollo.dev/core/v0.1")@core(feature:"https://spec.example.com/example/v1.0"){
- query:Query
+ query: Query
}typeUser{
- name:String@example(data:ITEM)
+ name: String @example(data:ITEM)}# An enum used to provide structured data to the example spec.# It is prefixed with the name of the spec.
-enumexample__Data{
+enumexample__Data{ITEM}
-directive@example(data:example__Data)onFIELD_DEFINITION
+directive@example(data: example__Data)onFIELD_DEFINITION
-directive@core(feature:String!,as:String)repeatableonSCHEMA
+directive@core(feature: String!,as: String)repeatableonSCHEMA
The prefix MUST NOT be elided within documentation; definitions of schema elements provided within the spec MUST include the feature’s name as a prefix.
@@ -1438,48 +1437,48 @@
@core(feature:"https://specs.apollo.dev/core/v0.1")@core(feature:"https://spec.example.com/featureA/v1.0")@core(feature:"https://spec.example.com/featureB/v2.0",as:"B"){
- query:Query
+ query: Query
}"""
featureA__SomeType is a type defined by feature A.
"""
-typefeatureA__SomeType{
+typefeatureA__SomeType{"""
nativeField is a field defined by featureA on a type also defined
by featureA (namely featureA__SomeType)
"""
- nativeField:Int@featureA__fieldDirective
+ nativeField: Int @featureA__fieldDirective}"""
featureA__SomeInput is an input specified by feature A
"""
-inputfeatureA__SomeInput{
+input featureA__SomeInput {"""
nativeInputField is defined by featureA
"""
- nativeInputField:Int
+ nativeInputField: Int
}"""
featureA__Items is specified by feature A
"""
-enumfeatureA__Items{ONE,TWO,THREE@B}
+enumfeatureA__Items{ONE,TWO,THREE@B}"""
@B is the root directive defined by featureB
Root directives are named after their feature
"""
-directive@BonENUM_VALUE
+directive@BonENUM_VALUE"""
@featureA__fieldDirective is a non-root (prefixed) directive defined by featureA
"""
-directive@featureA__fieldDirectiveonFIELD_DEFINITION
+directive@featureA__fieldDirectiveonFIELD_DEFINITION
-directive@core(feature:String!,as:String)repeatableonSCHEMA
+directive@core(feature: String!,as: String)repeatableonSCHEMA
@@ -1548,9 +1547,9 @@
SHOULD pass through @core directives which reference unknown feature URLs
+
SHOULD pass through @core directives which reference unknown feature URLs
SHOULD pass through prefixed directives, types, and other schema elements
Processors MAY accept configuration which overrides these default behaviors.
Additionally, processors which prepare the schema for final public consumption MAY choose to eliminate all unknown directives and prefixed types in order to hide schema implementation details within the published schema. This will impair the operation of tooling which relies on these directives—such tools will not be able to run on the output schema, so the benefits and costs of this kind of information hiding should be weighed carefully on a case‐by‐case basis.
@@ -1565,9 +1564,9 @@
rename the core feature within a document. This process determines the actual name for the core feature if one is present.
Fails the Has Schema validation if there are no SchemaDefinitions in the document
-
Fails the Has Core Feature validation if the core feature itself is not referenced with a @core directive within the document
-
Fails the Bootstrap Core Feature Listed First validation if the reference to the core feature is not the first @core directive on the document’s SchemaDefinition
-
Fails the Core Directive Incorrect Definition validation if the @core directive definition does not match the directive as defined by this specification.
+
Fails the Has Core Feature validation if the core feature itself is not referenced with a @core directive within the document
+
Fails the Bootstrap Core Feature Listed First validation if the reference to the core feature is not the first @core directive on the document’s SchemaDefinition
+
Fails the Core Directive Incorrect Definition validation if the @core directive definition does not match the directive as defined by this specification.
For the purposes of this algorithm, a directive’s definition in a schema matches a definition provided in this specification if:
If d has a feature: argument which parses as a feature URL, and whose identity is "https://specs.apollo.dev/core/"and whose version is "v0.1", and eitherd has an as: argument whose value is equal to d‘s name ord does not have an as: argument and d‘s name is core:
If any directive on schema listed before d has the same name as d, the Bootstrap Core Feature Listed First validation fails.
Collect a map of (featureName: String) → Directive, where Directive is a @core Directive which introduces the feature named featureName into the document.
+
Collect a map of (featureName: String) → Directive, where Directive is a @core Directive which introduces the feature named featureName into the document.
Fails the Name Uniqueness validation if feature names are not unique within the document.
FailsInvalid Feature URL validation for any invalid feature URLs.
@core(feature:"https://specs.example.com/A/1.0")# name is A@core(feature:"https://specs.example.com/A/2.0",as:"A2")# name is A2{
- query:Query
+ query: Query
}
Without the explicit as:, the above would be invalid:
@core(feature:"https://specs.example.com/A/1.0")# name is A@core(feature:"https://www.specs.com/specA/1.1",as:"A")# name is A{
- query:Query
+ query: Query
}
diff --git a/federation/v2.0/federation-v2.0.graphql b/federation/v2.0/federation-v2.0.graphql
new file mode 100644
index 0000000..ee73717
--- /dev/null
+++ b/federation/v2.0/federation-v2.0.graphql
@@ -0,0 +1,13 @@
+directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE
+directive @requires(fields: FieldSet!) on FIELD_DEFINITION
+directive @provides(fields: FieldSet!) on FIELD_DEFINITION
+directive @external on OBJECT | FIELD_DEFINITION
+directive @shareable on FIELD_DEFINITION | OBJECT
+directive @extends on OBJECT | INTERFACE
+directive @override(from: String!) on FIELD_DEFINITION
+directive @inaccessible on
+ | FIELD_DEFINITION
+ | OBJECT
+ | INTERFACE
+ | UNION
+scalar _FieldSet
\ No newline at end of file
diff --git a/federation/v2.0/federation-v2.0.md b/federation/v2.0/federation-v2.0.md
index 73fd8f0..e1277a6 100644
--- a/federation/v2.0/federation-v2.0.md
+++ b/federation/v2.0/federation-v2.0.md
@@ -11,9 +11,7 @@
#! @key
-```graphql definition
-directive @key(fields: FieldSet!) repeatable on OBJECT | INTERFACE
-```
+:::[definition](./federation-v2.0.graphql#@key)
The `@key` directive is used to indicate a combination of fields that can be used to uniquely identify and fetch an object or interface.
@@ -39,9 +37,7 @@ Note: Repeated directives (in this case, `@key`, used multiple times) require su
#! @provides
-```graphql definition
-directive @provides(fields: FieldSet!) on FIELD_DEFINITION
-```
+:::[definition](./federation-v2.0.graphql#@provides)
The `@provides` directive is used to annotate the expected returned fieldset from a field on a base type that is guaranteed to be selectable by the gateway. Given the following example:
@@ -61,9 +57,7 @@ When fetching `Review.product` from the Reviews service, it is possible to reque
#! @requires
-```graphql definition
-directive @requires(fields: FieldSet!) on FIELD_DEFINITION
-```
+:::[definition](./federation-v2.0.graphql#@requires)
The `@requires` directive is used to annotate the required input fieldset from a base type for a resolver. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. For example:
@@ -80,9 +74,7 @@ In this case, the Reviews service adds new capabilities to the `User` type by pr
#! @external
-```graphql definition
-directive @external on FIELD_DEFINITION
-```
+:::[definition](./federation-v2.0.graphql#@external)
The `@external` directive is used to mark a field as owned by another service. This allows service A to use fields from service B while also knowing at runtime the types of that field. For example:
@@ -96,12 +88,53 @@ extend type User @key(fields: "email") {
This type extension in the Reviews service extends the `User` type from the Users service. It extends it for the purpose of adding a new field called `reviews`, which returns a list of `Review`s.
-#! _FieldSet
+#! @shareable
+
+:::[definition](./federation-v2.0.graphql#@shareable)
+
+The `@shareable` directive is used to indicate that a field can be resolved by multiple subgraphs. Any subgraph that includes a shareable field can potentially resolve a query for that field. To successfully compose, a field must have the same shareability mode (either shareable or non-shareable) across all subgraphs.
-```graphql definition
-scalar _FieldSet
+Any field using the [`@key` directive](#key) is automatically shareable. Adding the `@shareable` directive to an object is equivalent to marking each field on the object `@shareable`.
+
+```graphql example -- using {@shareable}
+type Product @key(fields: "upc") {
+ upc: UPC! # shareable because upc is a key field
+ name: String # non-shareable
+ description: String @shareable # shareable
+}
+
+type User @key(fields: "email") @shareable {
+ email: String # shareable because User is marked shareable
+ name: String # shareable because User is marked shareable
+}
```
+#! @override
+
+:::[definition](./federation-v2.0.graphql#@override)
+
+The `@override` directive is used to indicate that the current subgraph is taking responsibility for resolving the marked field _away_ from the subgraph specified in the `from` argument.
+
+The following example will result in all query plans made to resolve `User.name` to be directed to SubgraphB.
+
+```graphql example -- using {@override}
+# in SubgraphA
+type User @key(fields: "id") {
+ id: ID!
+ name: String
+}
+
+# in SubgraphB
+type User @key(fields: "id") {
+ id: ID!
+ name: String @override(from: "SubgraphA")
+}
+```
+
+#! _FieldSet
+
+:::[definition](./federation-v2.0.graphql#@_FieldSet)
+
A set of fields.
```graphql example -- Using `_FieldSet` with a single field in a `@key`
diff --git a/federation/v2.0/index.html b/federation/v2.0/index.html
index 91803ee..3cee4bc 100644
--- a/federation/v2.0/index.html
+++ b/federation/v2.0/index.html
@@ -1060,25 +1060,26 @@
The @provides directive is used to annotate the expected returned fieldset from a field on a base type that is guaranteed to be selectable by the gateway. Given the following example:
When fetching Review.product from the Reviews service, it is possible to request the name with the expectation that the Reviews service can provide it when going from review to product. Product.name is an external field on an external type which is why the local type extension of Product and annotation of name is required. “””
The @requires directive is used to annotate the required input fieldset from a base type for a resolver. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. For example:
In this case, the Reviews service adds new capabilities to the User type by providing a list of reviews related to a user. In order to fetch these reviews, the Reviews service needs to know the email of the User from the Users service in order to look up the reviews. This means the reviews field / resolver requires the email field from the base User type.
The @external directive is used to mark a field as owned by another service. This allows service A to use fields from service B while also knowing at runtime the types of that field. For example:
# extended from the Users serviceextendtypeUser@key(fields:"email"){
- email:String@external
- reviews:[Review]
+ email: String @external
+ reviews:[Review]}
This type extension in the Reviews service extends the User type from the Users service. It extends it for the purpose of adding a new field called reviews, which returns a list of Reviews.
The @shareable directive is used to indicate that a field can be resolved by multiple subgraphs. Any subgraph that includes a shareable field can potentially resolve a query for that field. To successfully compose, a field must have the same shareability mode (either shareable or non‐shareable) across all subgraphs.
+
Any field using the @key directive is automatically shareable. Adding the @shareable directive to an object is equivalent to marking each field on the object @shareable.
typeProduct@key(fields:"upc"){
+ upc:UPC!# shareable because upc is a key field
+ name: String # non-shareable
+ description: String @shareable# shareable
+}
+
+typeUser@key(fields:"email")@shareable{
+ email: String # shareable because User is marked shareable
+ name: String # shareable because User is marked shareable
+}
The @override directive is used to indicate that the current subgraph is taking responsibility for resolving the marked field away from the subgraph specified in the from argument.
+
The following example will result in all query plans made to resolve User.name to be directed to SubgraphB.
The schema above contains both a field (User.id) and type (BankAccount) that are marked as @inaccessible. These symbols should be omitted from the processed schema anywhere they would appear. When the processed schema below is generated from this core schema, notice what has been removed:
As described in the core schema specification, your schema may rename the @inaccessible directive by including an as argument to the @core directive which references this specification. All references to @inaccessible in this specification MUST be interpreted as referring to names with the appropriate prefix chosen within your schema.
In order to use the directive described by this specification, GraphQL requires you to include the definition in your schema.
This section is non‐normative. It describes the motivation behind the directives defined by this specification.
-
A supergraph schema describes a GraphQL schema that can be served by a router. The router does not contain logic to resolve any of the schema’s fields; instead, the supergraph schema contains directives starting with @join__ that tell the router which subgraph endpoint can resolve each field, as well as other information needed in order to construct subgraph operations.
+
A supergraph schema describes a GraphQL schema that can be served by a router. The router does not contain logic to resolve any of the schema’s fields; instead, the supergraph schema contains directives starting with @join__ that tell the router which subgraph endpoint can resolve each field, as well as other information needed in order to construct subgraph operations.
The directives described in this specification are designed for a particular query planning algorithm, and so there are some restrictions on how they can be combined that originate from the requirements of this algorithm. For example, this specification describes a concept of type ownership which exists not because we believe it describes the ideal method of structuring your subgraphs, but because this query planning algorithm depends on type ownership. We hope that future versions of this specification can relax some of these restrictions.
-
Each supergraph schema contains a list of its included subgraphs. The join__Graph enum represents this list with an enum value for each subgraph. Each enum value is annotated with a @join__graph directive telling the router what endpoint can be used to reach the subgraph, and giving the subgraph a human‐readable name that can be used for purposes such as query plan visualization and server logs.
-
To resolve a field, the router needs to know to which subgraphs it can delegate the field’s resolution. One explicit way to indicate this in a supergraph schema is by annotating the field with a @join__field directive specifying which subgraph should be used to resolve that field. (There are other ways of indicating which subgraphs can resolve a field which will be described later.)
+
Each supergraph schema contains a list of its included subgraphs. The join__Graph enum represents this list with an enum value for each subgraph. Each enum value is annotated with a @join__graph directive telling the router what endpoint can be used to reach the subgraph, and giving the subgraph a human‐readable name that can be used for purposes such as query plan visualization and server logs.
+
To resolve a field, the router needs to know to which subgraphs it can delegate the field’s resolution. One explicit way to indicate this in a supergraph schema is by annotating the field with a @join__field directive specifying which subgraph should be used to resolve that field. (There are other ways of indicating which subgraphs can resolve a field which will be described later.)
In order for the router to send an operation that resolves a given field on a parent object to a subgraph, the operation needs to first resolve the parent object itself. There are several ways to accomplish this, described below. The examples below include abbreviated versions of the supergraph schemas which do not include the schema definition, directive definitions, or the join__Graph definition. This specification does not require the subgraph operations to be the same as those described in these examples; this is just intended to broadly describe the meanings of the directives.
4.2Fields on the same subgraph as the parent operation
-
If a field’s parent field will be resolved by an operation on the same subgraph, then it can be resolved as part of the same operation, by putting it in a nested selection set on the parent field’s subgraph operation. Note that this example contains @join__owner and @join__type directives on an object type; these will be described later.
+
If a field’s parent field will be resolved by an operation on the same subgraph, then it can be resolved as part of the same operation, by putting it in a nested selection set on the parent field’s subgraph operation. Note that this example contains @join__owner and @join__type directives on an object type; these will be described later.
Some types have the property that all of their fields can be resolved by any subgraph that can resolve a field returning that type. These types are called value types. (Imagine a type type T { x: Int, y: String } where every resolver for a field of type T actually produces an object like {x: 1, y: "z"}, and the resolvers for the two fields on T just unpack the values already in the object.) In a supergraph schema, a type is a value type if it does not have a @join__owner directive on it.
+
Some types have the property that all of their fields can be resolved by any subgraph that can resolve a field returning that type. These types are called value types. (Imagine a type type T { x: Int, y: String } where every resolver for a field of type T actually produces an object like {x: 1, y: "z"}, and the resolvers for the two fields on T just unpack the values already in the object.) In a supergraph schema, a type is a value type if it does not have a @join__owner directive on it.
fieldB:X@join__field(graph:B)}
-typeX
+typeX@join__owner(graph:A)# As the owner, A is allowed to have more than one key.@join__type(graph:A,key:"x")
@@ -1404,19 +1404,19 @@
{# Because A owns X, we can omit @join__field(graph: A)# from these three fields.
- x:String
- y:String
- z:String
+ x: String
+ y: String
+ z: String
}# Operation
-{fieldB{y}}
+{ fieldB { y }}# Generated subgraph operations## On B. `y` is not available, so we need to fetch B's key for X.
-{fieldB{x}}
+{ fieldB { x }}## On A## $r = [{__typename: "X", x: "some-x-value"}]
-query($r:[_Any!]!){_entities(representations:$r]){y}}
+query($r:[_Any!]!){ _entities(representations:$r]){ y }}
@@ -1427,7 +1427,7 @@
fieldB:X@join__field(graph:B)}
-typeX
+typeX@join__owner(graph:A)# As the owner, A is allowed to have more than one key.@join__type(graph:A,key:"x")
@@ -1437,25 +1437,25 @@
@join__type(graph:B,key:"x")@join__type(graph:C,key:"y z"){
- x:String
- y:String
- z:String
- c:String@join__field(graph:C)
+ x: String
+ y: String
+ z: String
+ c: String @join__field(graph:C)}# Operation
-{fieldB{c}}
+{ fieldB { c }}# Generated subgraph operations## On B. `c` is not available on B, so we need to eventually get over to C.## In order to do that, we need `y` and `z`... which aren't available on B## either! So we need to take two steps. First we use B's key.
-{fieldB{x}}
+{ fieldB { x }}## On A. We use B's key to resolve our `X`, and we extract C's key.## $r = [{__typename: "X", x: "some-x-value"}]
-query($r:[_Any!]!){_entities(representations:$r]){yz}}
+query($r:[_Any!]!){ _entities(representations:$r]){ y z }}## On C. We can finally look up the field we need.## $r = [{__typename: "X", y: "some-y-value", z: "some-z-value"}]
-query($r:[_Any!]!){_entities(representations:$r]){c}}
+query($r:[_Any!]!){ _entities(representations:$r]){ c }}
We only need to do this two‐jump process because the fields needed for C’s key are not available in B; otherwise a single jump would have worked, like in the owned‐field case.
Sometimes a particular extension field needs its parent object’s representation to contain more information than its parent type’s key requests. In this case, you can include a requires argument in the field’s @join__field listing those required fields (potentially including sub‐selections). All required fields must be resolvable in the owning subgraph (this restriction is why requires is only allowed on extension fields).
@@ -1464,53 +1464,53 @@
fieldA:X@join__field(graph:A)}
-typeX
+typeX@join__owner(graph:A)@join__type(graph:A,key:"x")@join__type(graph:B,key:"x"){
- x:String
- y:String
- z:String@join__field(graph:B,requires:"y")
+ x: String
+ y: String
+ z: String @join__field(graph:B,requires:"y")}# Operation
-{fieldA{z}}
+{ fieldA { z }}# Generated subgraph operations## On A. `x` is included because it is B's key for `X`; `y`## is included because of the `requires`.
-{fieldA{xy}}
+{ fieldA { x y }}## On B..## $r = [{__typename: "X", x: "some-x-value", y: "some-y-value"}]
-query($r:[_Any!]!){_entities(representations:$r]){z}}
+query($r:[_Any!]!){ _entities(representations:$r]){ z }}
Schemas using the join core feature MUST be valid core schema documents with @core directives referencing the core specification and this specification.
Schemas using the join core feature MUST be valid core schema documents with @core directives referencing the core specification and this specification.
As described in the core schema specification, your schema may use a prefix other than join for all of the directive and enum names defined by this specification by including an as argument to the @core directive which references this specification. All references to directive and enum names in this specification MUST be interpreted as referring to names with the appropriate prefix chosen within your schema.
In order to use the directives described by this specification, GraphQL requires you to include their definitions in your schema.
Processors MUST validate that you have defined the directives with the same arguments, locations, and repeatable flag as given below.
Processors MUST validate that the schema contains an enum named join__Graph; see its section below for other required properties of this enum.
As described in the core specification, all of the directives and enums defined by this schema should be removed from the supergraph’s API schema. For example, the join__Graph enum should not be visible via introspection.
The @join__graph directive MUST be applied to each enum value on join__Graph, and nowhere else. Each application of @join__graphMUST have a distinct value for the name argument; this name is an arbitrary non‐empty string that can be used as a human‐readable identifier which may be used for purposes such as query plan visualization and server logs. The url argument is an endpoint that can resolve GraphQL queries for the subgraph.
+
The @join__graph directive MUST be applied to each enum value on join__Graph, and nowhere else. Each application of @join__graphMUST have a distinct value for the name argument; this name is an arbitrary non‐empty string that can be used as a human‐readable identifier which may be used for purposes such as query plan visualization and server logs. The url argument is an endpoint that can resolve GraphQL queries for the subgraph.
Every type with a @join__typeMUST also have a @join__owner directive. Any type with a @join__owner directive MUST have at least one @join__type directive with the same graph as the @join__owner directive (the “owning graph”), and MUST have at most one @join__type directive for each graph value other than the owning graph. Any value that appears as a key in a @join__type directive with a graph value other than the owning graph must also appear as a key in a @join__type directive with graph equal to the owning graph.
+
Every type with a @join__typeMUST also have a @join__owner directive. Any type with a @join__owner directive MUST have at least one @join__type directive with the same graph as the @join__owner directive (the “owning graph”), and MUST have at most one @join__type directive for each graph value other than the owning graph. Any value that appears as a key in a @join__type directive with a graph value other than the owning graph must also appear as a key in a @join__type directive with graph equal to the owning graph.
The field’s parent type MUST be annotated with a @join__type with the same value of graph as this directive, unless the parent type is a root operation type.
-
If a field is not annotated with @join__field (or if the graph argument is not provided or null) and its parent type is annotated with @join__owner(graph: G), then a processor MUST treat the field as if it is annotated with @join__field(graph: G). If a field is not annotated with @join__field (or if the graph argument is not provided or null) and its parent type is not annotated with @join__owner (ie, the parent type is a value type) then it MUST be resolvable in any subgraph that can resolve values of its parent type.
The field’s parent type MUST be annotated with a @join__type with the same value of graph as this directive, unless the parent type is a root operation type.
+
If a field is not annotated with @join__field (or if the graph argument is not provided or null) and its parent type is annotated with @join__owner(graph: G), then a processor MUST treat the field as if it is annotated with @join__field(graph: G). If a field is not annotated with @join__field (or if the graph argument is not provided or null) and its parent type is not annotated with @join__owner (ie, the parent type is a value type) then it MUST be resolvable in any subgraph that can resolve values of its parent type.
typeQuery{
+ me: User @join__field(graph:AUTH)
+ images:[Image]@join__field(graph:IMAGES)}
-
The requires argument MUST only be specified on fields whose parent type has a @join__owner directive specifying a different graph than this @join__field directive does. All fields (including nested fields) mentioned in this field set must be resolvable in the parent type’s owning subgraph. When constructing a representation for a parent object of this field, a router will include the fields selected in this requires argument in addition to the appropriate key for the parent type.
+
The requires argument MUST only be specified on fields whose parent type has a @join__owner directive specifying a different graph than this @join__field directive does. All fields (including nested fields) mentioned in this field set must be resolvable in the parent type’s owning subgraph. When constructing a representation for a parent object of this field, a router will include the fields selected in this requires argument in addition to the appropriate key for the parent type.
The provides argument specifies fields that can be resolved in operations run on subgraph graph as a nested selection under this field, even if they ordinarily can only be resolved on other subgraphs.
The descriptions of @join__type and @join__field describes requirements on how @join__owner relates to @join__type and the requires argument to @join__field.
+
The descriptions of @join__type and @join__field describes requirements on how @join__owner relates to @join__type and the requires argument to @join__field.
Note
Type ownership is currently slated for removal in a future version of this spec. It is RECOMMENDED that router implementations consider approaches which function in the absence of these restrictions. The overview explains how the current router’s query planning algorithm depends on concept of type ownership.
-
-
-```
-
-Core schemas provide tools for linking definitions from different GraphQL schemas together into one.
-
-```graphql example -- linking a directive from another schema
-extend schema
- # 👇🏽 schemas are identified by a url
- @link(url: "https://internal.example.com/admin")
-
-type Query {
- allUsers: [User] @admin__adminOnly # 👈🏽 remote identifier, namespaced
-}
-```
-
-```graphql example -- importing a directive from another schema
-extend schema
- # specific definitions can be imported 👇🏽
- @link(url: "https://internal.example.com/admin", import: ["@adminOnly"])
-
-type Query {
- allUsers: [User] @adminOnly # 👈🏽 remote identifier, imported
-}
-```
-
-This document introduces a set of conventions for linking and namespacing within GraphQL schemas. Core schemas are not a new kind of document and do not introduce any new syntax—they are just GraphQL schemas which can be interpreted according to the conventions outlined in this doc.
-
-# Renaming {@link}
-
-It is possible to rename {@link} with the same {@link.as} mechanism used for all links:
-
-```graphql example -- Renaming {@link} to {@linkOther}
-schema
- @linkOther(url: "https://specs.apollo.dev/link/v1.0", import: [{name: "@link", as: "@linkOther"}])
- @linkOther(url: "https://example.com/example/v1.0")
-{
- query: Query
-}
-
-type SomeType {
- field: Int @example
-}
-```
-
-# Prefixing
-
-With the exception of a single root directive, core feature specifications MUST prefix all schema elements they introduce. The prefix:
- 1. MUST match the name of the feature as derived from the feature's specification URL,
- 2. MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name), and
- 3. MUST NOT contain the core namespace separator, which is two underscores ({"__"}), and
- 4. MUST NOT end with an underscore (which would create ambiguity between whether {"x___y"} is prefix `x_` for element `y` or prefix `x` for element `_y`).
-
-Prefixed names consist of the name of the feature, followed by two underscores, followed by the name of the element, which can be any valid [GraphQL name](https://spec.graphql.org/draft/#Name). For instance, the `core` specification (which you are currently reading) introduces an element named [{@link}](#@link), and the `join` specification introduces an element named {@join__field} (among others).
-
-Note that both parts must be valid GraphQL names, and GraphQL names cannot start with digits, so core feature specifications cannot introduce names like `@feature__24hours`.
-
-A feature's *root directive* is an exception to the prefixing requirements. Feature specifications MAY introduce a single directive which carries only the name of the feature, with no prefix required. For example, the `core` specification introduces a {@link} directive. This directive has the same name as the feature ("`core`"), and so requires no prefix.
-
-```graphql example -- Using the @link directive without changing the prefix
-schema
- @link(url: "https://specs.apollo.dev/link/v1.0")
- @link(url: "https://spec.example.com/example/v1.0") {
- query: Query
-}
-
-type User {
- name: String @example(data: ITEM)
-}
-
-# An enum used to provide structured data to the example spec.
-# It is prefixed with the name of the spec.
-enum example__Data {
- ITEM
-}
-
-directive @example(data: example__Data) on FIELD_DEFINITION
-
-directive @link(url: String!, as: String) repeatable on SCHEMA
-```
-
-The prefix MUST NOT be elided within documentation; definitions of schema elements provided within the spec MUST include the feature's name as a prefix.
-
-## Elements which must be prefixed
-
-Feature specs MUST prefix the following schema elements:
- - the names of any object types, interfaces, unions, enums, or input object types defined by the feature
- - the names of any directives introduced in the schema, with the exception of the *root directive*, which must have the same name as the schema
-
-:::[example](prefixing.graphql) -- Prefixing
-
-# Versioning
-
-VersionTag : "v" Version
-
-Version : Major "." Minor
-
-Major : NumericIdentifier
-
-Minor : NumericIdentifier
-
-NumericIdentifier : "0"
- | PositiveDigit Digit*
-
-Digit : "0" | PositiveDigit
-
-PositiveDigit : "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
-
-Specs are versioned with a **subset** of a [Semantic Version Number](https://semver.org/spec/v2.0.0.html) containing only the major and minor parts. Thus, specifications SHOULD provide a version of the form `v`{Major}`.`{Minor}, where both integers >= 0.
-
-```text example -- Valid version tags
-v2.2
-v1.0
-v1.1
-v0.1
-```
-
-As specified by semver, spec authors SHOULD increment the:
-
-{++
-
-- MAJOR version when you make incompatible API changes,
-- MINOR version when you add functionality in a backwards compatible manner
-
-++}
-
-Patch and pre-release qualifiers are judged to be not particularly meaningful in the context of GraphQL schemas, which are (by definition) interfaces rather than implementations. The patch component of a semver denotes a bug fix which is backwards compatible—that is, a change to the implementation which does not affect the interface. Patch-level changes in the version of a spec denote wording clarifications which do not require implementation changes. As such, it is not important to track them for the purposes of version resolution.
-
-As with [semver](https://semver.org/spec/v2.0.0.html), the `0.x` version series is special: there is no expectation of compatibility between versions `0.x` and `0.y`. For example, a processor must not activate implementation `0.4` to satisfy a requested version of `0.2`.
-
-## Satisfaction
-
-Given a version {requested} by a document and an {available} version of an implementation, the following algorithm will determine if the {available} version can satisfy the {requested} version:
-
-Satisfies(requested, available) :
- 1. If {requested}.{Major} ≠ {available}.{Major}, return {false}
- 2. If {requested}.{Major} = 0, return {requested}.{Minor} = {available}.{Minor}
- 3. Return {requested}.{Minor} <= {available}.{Minor}
-
-## Referencing versions and activating implementations
-
-Schema documents MUST reference a feature version which supports all the schema elements and behaviors required by the document. As a practical matter, authors will generally prefer to reference a version they have reason to believe is supported by the most processors; depending on context, this might be an old stable version with a low major version, or a new less-deprecated version with a large major version.
-
-If a processor chooses to activate support for a feature, the processor MUST activate an implementation which can [satisfy](#sec-Satisfaction) the version required by the document.
-
-
-# Processing Schemas
-
-```mermaid diagram
-graph LR
- schema(["📄 Input Schema"]):::file-->proc("🤖 Processor")
- proc-->output(["📄 Output Schema"]):::file
- classDef file fill:none,color:#22262E;
- style proc fill:none,stroke:fuchsia,color:fuchsia;
-```
-
-A common use case is that of a processor which consumes a valid input schema and generates an output schema.
-
-The general guidance for processor behavior is: don't react to what you don't understand.
-
-Specifically, processors:
- - SHOULD pass through {@link} directives which reference unknown feature URLs
- - SHOULD pass through prefixed directives, types, and other schema elements
- - SHOULD pass through directives which are not [associated with](#AssignFeatures) a {@link} feature
-
-Processors MAY accept configuration which overrides these default behaviors.
-
-Additionally, processors which prepare the schema for final public consumption MAY choose to eliminate all unknown directives and prefixed types in order to hide schema implementation details within the published schema. This will impair the operation of tooling which relies on these directives—such tools will not be able to run on the output schema, so the benefits and costs of this kind of information hiding should be weighed carefully on a case-by-case basis.
-
-# Validations & Algorithms
-
-This section lays out algorithms for processing core schemas.
-
-Algorithms described in this section may produce *validation failures* if a document does not conform to the requirements core schema document. Validation failures SHOULD halt processing. Some consumers, such as authoring tools, MAY attempt to continue processing in the presence of validation failures, but their behavior in such cases is unspecified.
-
-## Bootstrapping
-
-Determine the name of the core specification within the document.
-
-It is possible to [rename the core feature](#sec-Renaming-core-itself) within a document. This process determines the actual name for the core feature if one is present.
-
-- **Fails** the *Has Schema* validation if there are no SchemaDefinitions in the document
-- **Fails** the *Has Core Feature* validation if the `core` feature itself is not referenced with a {@link} directive within the document
-- **Fails** the *Bootstrap Core Feature Listed First* validation if the reference to the `core` feature is not the first {@link} directive on the document's SchemaDefinition
-- **Fails** the *Core Directive Incorrect Definition* validation if the {@link} directive definition does not *match* the directive as defined by this specification.
-
-For the purposes of this algorithm, a directive's definition in a schema *matches* a definition provided in this specification if:
-- Its arguments have the specified names, types, and default values (or lack thereof)
-- It is defined as `repeatable` if and only if the specification's definition defines it as `repeatable`
-- The set of locations it belongs to is the same set of locations in the specification's definition.
-
-The following aspects may differ between the definition in the schema and the definition in the specification without preventing the definitions from *matching*:
-- The name of the directive (due to [prefixing](#sec-Prefixing))
-- The order of arguments
-- The order of locations
-- The directive's description string
-- Argument description strings
-- Directives applied to argument definitions
-
-Bootstrap(document) :
-1. Let {schema} be the only SchemaDefinition in {document}. (Note that legal GraphQL documents [must include at most one SchemaDefinition](http://spec.graphql.org/draft/#sec-Root-Operation-Types).)
- 1. ...if no SchemaDefinitions are present in {document}, the ***Has Schema* validation fails**.
-1. For each directive {d} on {schema},
- 1. If {d} has a [`url:`](#@link/feature) argument which [parses as a feature URL](#@link/feature), *and* whose identity is {"https://specs.apollo.dev/core/"} *and* whose version is {"v0.1"}, *and either* {d} has an [`as:`](#@link/as) argument whose value is equal to {d}'s name *or* {d} does not have an [`as:`](#@link/as) argument and {d}'s name is `core`:
- - If any directive on {schema} listed before {d} has the same name as {d}, the ***Bootstrap Core Feature Listed First* validation fails**.
- - If the definition of the directive {d} does not *match* the [definition of {@link} in this specification](#@link), the ***Core Directive Incorrect Definition* validation fails**.
- - Otherwise, **Return** {d}'s name.
-- If no matching directive was found, the ***Has Core Feature* validation fails**.
-
-## Feature Collection
-
-Collect a map of ({featureName}: `String`) -> `Directive`, where `Directive` is a {@link} Directive which introduces the feature named {featureName} into the document.
-
-- **Fails** the *Name Uniqueness* validation if feature names are not unique within the document.
-- **Fails** *Invalid Feature URL* validation for any invalid feature URLs.
-
-CollectFeatures(document) :
- - Let {coreName} be the name of the core feature found via {Bootstrap(document)}
- - Let {features} be a map of {featureName}: `String` -> `Directive`, initially empty.
- - For each directive {d} named {coreName} on the SchemaDefinition within {document},
- - Let {specifiedFeatureName} and {version} be the result of parsing {d}'s `url:` argument according to the [specified rules for feature URLs](#@link/feature)
- - If the `url:` is not present or fails to parse:
- - The ***Invalid Feature URL* validation fails** for {d},
- - Let {featureName} be the {d}'s [`as:`](#@link/as) argument or, if the argument is not present, {specifiedFeatureName}
- - If {featureName} exists within {features}, the ***Name Uniqueness* validation fails**.
- - Insert {featureName} => {d} into {features}
- - **Return** {features}
-
-
-Prefixes, whether implicit or explicit, must be unique within a document. Valid:
-
-:::[example](prefixing.graphql#schema[0]) -- Unique prefixes
-
-It is also valid to reference multiple versions of the same spec under different prefixes:
-
-:::[example](prefix-uniqueness.graphql#schema[0]) -- Explicit prefixes allow multiple versions of the same spec to coexist within a Document
-
-Without the explicit [`as:`](#@link/as), the above would be invalid:
-
-:::[counter-example](prefix-uniqueness.graphql#schema[1]) -- Non-unique prefixes with multiple versions of the same spec
-
-Different specs with the same prefix are also invalid:
-
-:::[counter-example](prefix-uniqueness.graphql#schema[2]) -- Different specs with non-unique prefixes
-
-## Assign Features
-
-Create a map of {element}: *Any Named Element* -> {feature}: `Directive` | {null}, associating every named schema element within the document with a feature directive, or {null} if it is not associated with a feature.
-
-AssignFeatures(document) :
- - Let {features} be the result of collecting features via {CollectFeatures(document)}
- - Let {assignments} be a map of ({element}: *Any Named Element*) -> {feature}: `Directive` | {null}, initally empty
- - For each named schema element {e} within the {document}
- - Let {name} be the name of the {e}
- - If {e} is a Directive and {name} is a key within {features},
- - Insert {e} => {features}`[`{name}`]` into {assignments}
- - **Continue** to next {e}
- - If {name} begins with {"__"},
- - Insert {e} => {null} into {assignments}
- - **Continue** to next {e}
- - If {name} contains the substring {"__"},
- - Partition {name} into `[`{prefix}, {base}`]` at the first {"__"} (that is, find the shortest {prefix} and longest {base} such that {name} = {prefix} + {"__"} + {base})
- - If {prefix} exists within {features}, insert {e} => {features}`[`{prefix}`]` into {assignments}
- - Else, insert {e} => {null} into {assignments}
- - **Continue** to next {e}
- - Insert {e} => {null} into {assignments}
- - **Return** {assignments}
-
-## Is In API?
-
-Determine if any schema element is included in the [API](#sec-Parts-of-a-Core-Schema) described by the core schema. A schema element is any part of a GraphQL document using type system definitions that has a [name](https://spec.graphql.org/draft/#Name).
-
-IsInAPI(element) :
- - Let {assignments} be the result of assigning features to elements via {AssignFeatures(document)}
- - If {assignments}`[`{element}`]` is {null}, **Return** {true}
- - Else, **Return** {false}
-
-Note: Later versions of this specification may add other ways to affect the behavior of this algorithm, but those mechanisms will only be enabled if you reference those hypothetical versions of this specification.
-
-## Is Affected By Feature?
-
-Determine if a schema element is *affected* by a given feature.
-
-IsAffected(element, feature):
- - Let {assignments} be the result of assigning features to elements via {AssignFeatures(document)}
- - For each directive {d} on {element}, If {assignments}`[`{d}`]` is {feature}, **Return** {true}
- - If {element} is a FieldDefinition,
- - Let {parent} be the parent ObjectDefinition or InterfaceDefinition for {element}
- - If {IsAffected(parent, feature)}, **Return** {true}
- - For each argument type {a} declared on {element},
- - Let {t} be the InputDefinition, EnumDefinition, or ScalarDefinition for argument {a}
- - If {IsAffected(t, feature)}, **Return** {true}
- - Let {return} be the ObjectDefinition, InterfaceDefinition, or UnionDefinition for {element}'s return type
- - If {IsAffected(return, feature)}, **Return** {true}
- - If {element} is an InputDefinition,
- - For each InputFieldDefinition {field} within {element},
- - Let {t} be the InputDefinition, EnumDefinition, or ScalarDefinition for the type of {field}
- - If {IsAffected(t, feature)}, **Return** {true}
- - If {element} is an EnumDefinition,
- - For each EnumValueDefinition {value} in {element},
- - If {IsAffected(value, feature)}, **Return** {true}
-"""
-schema
-{ query: Query }
-
-
-"""
-Link a foreign schema by its URL.
-"""
-directive @link(
- """
- The foreign schema's URL.
-
- Link URLs serve two main purposes:
- - Providing a unique identifier for the foreign schema
- - Directing human readers to documentation about the foreign schema
-
- Link URLs SHOULD be [RFC 3986 URLs](https://tools.ietf.org/html/rfc3986). When viewed, the URL SHOULD provide schema documentation in some human-readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
-
- Link URLs MAY contain information about the spec's [name](#sec-Prefixing) and [version](#sec-Versioning):
-
- ```html diagram -- Basic anatomy of a link URL
-
- https://spec.example.com/a/b/c/mySchema/v1.0
-
- ```
-
- The final two segments of the URL's [path](https://tools.ietf.org/html/rfc3986#section-3.3) MAY contain the schema's name and a [version tag](#sec-Versioning), in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid {VersionTag}. To be recognized as a name, the penultimate path component MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name) which does not include the namespace separator ({"__"}).
-
- Empty final path components (that is, trailing slashes) and any URL components which have not been assigned a meaning (such as the fragment and query) MUST be ignored.
-
- ```html diagram -- Ignoring meaningless parts of a URL
-
- https://example.com/exampleSchema/v1.0/?key=val&k2=v2#frag
-
- ```
-
- All of these are valid arguments to `url`, and their interpretations:
-
- | url | normalized url | name | version |
- | ------------------------------------------------- | ------------------------------------------ | ------- | -------- |
- | https://spec.example.com/a/b/mySchema/v1.0/ | https://spec.example.com/a/b/mySchema/v1.0 | mySchema | v1.0 |
- | https://spec.example.com | https://spec.example.com | *(null)* | *(null)* |
- | https://spec.example.com/mySchema/v0.1?q=v#frag | https://spec.example.com/mySchema/v0.1 | mySchema | v0.1 |
- | https://spec.example.com/v1.0 | https://spec.example.com/v1.0 | *(null)* | v1.0 |
- | https://spec.example.com/vX | https://spec.example.com/vX | vX | *(null)* |
-
- If `name` is present, that [namespace prefix](#sec-Prefixing) will automatically be linked to the URL. If a `name` is not present, then elements of the foreign schema must be [`imported`](#@link/import) in order to be referenced.
- """
- url: String!,
-
- """
- Change the [namespace prefix](#sec-Prefixing) assigned to this schema.
-
- The name must be a valid GraphQL identifier, and must not contain the namespace separator ({"__"}).
-
- By default, {@link} will assign a prefix based on the `name` extracted from the URL. If no `name` is present, a prefix will not be assigned.
-
- Providing [`as:`](#@link/as) overrides the default behavior: the foreign schema will be assigned the provided prefix, regardless of the `name` present in the URL (or the lack of one).
-
- ```graphql example -- Using {@link}(url:, as:) to use a feature with a custom name
- schema
- @link(url: "https://specs.apollo.dev/link/v1.0")
- @link(url: "https://spec.example.com/example/v1.0", as: "eg")
- {
- query: Query
- }
-
- type User {
- # Specifying `as: "eg"` transforms @example into @eg
- name: String @eg(data: ITEM)
- }
-
- # Additional specified schema elements must have their prefixes set
- # to the new name.
- enum eg__Data {
- ITEM
- }
-
- # Name transformation must also be applied to definitions pulled in from
- # specifications.
- directive @eg(data: eg__Data) on FIELD_DEFINITION
-
- directive @link(url: String!, as: String) repeatable on SCHEMA
- ```
- """
- as: String,
-
- """
- Import definitions into the local namespace.
- """
- import: [Import],
-
- """
- An optional [purpose](#Purpose) for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
-
- By default, {@link}s SHOULD fail open. This means that {@link}s to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown feature metadata and serve or process the rest of the schema normally.
-
- This behavior is different for {@link}s with a specified purpose:
- - `SECURITY` links convey metadata necessary to compute the API schema and securely resolve fields within it
- - `EXECUTION` links convey metadata necessary to correctly resolve fields within the schema
- """
- for: Purpose)
- repeatable on SCHEMA
-
-"""
-TK describe an import
-"""
-scalar Import
-
-"""
-The role of a feature referenced with {@link}.
-
-This is not intended to be an exhaustive list of all the purposes a feature might serve. Rather, it is intended to capture cases where the default fail-open behavior of core schema consumers is undesirable.
-
-Note we'll refer to directives from features which are `for: SECURITY` or `for: EXECUTION` as "`SECURITY` directives" and "`EXECUTION` directives", respectively.
-"""
-enum Purpose {
- """
- `SECURITY` links provide metadata necessary to securely resolve fields. For instance, a hypothetical {auth} feature may provide an {@auth} directive to flag fields which require authorization. If a data core does not support the {auth} feature and serves those fields anyway, these fields will be accessible without authorization, compromising security.
-
- Security-conscious consumers MUST NOT serve a field if:
- - the schema definition has **any** unsupported SECURITY directives,
- - the field's parent type definition has **any** unsupported SECURITY directives,
- - the field's return type definition has **any** unsupported SECURITY directives, or
- - the field definition has **any** unsupported SECURITY directives
-
- Such fields are *not securely resolvable*. Security-conscious consumers MAY serve schemas with fields which are not securely resolvable. However, they MUST remove such fields from the schema before serving it.
-
- Less security-conscious consumers MAY choose to relax these requirements. For instance, servers may provide a development mode in which unknown SECURITY directives are ignored, perhaps with a warning. Such software may also provide a way to explicitly disable some or all SECURITY links during development.
-
- More security-conscious consumers MAY choose to enhance these requirements. For instance, production servers MAY adopt a policy of entirely rejecting any schema which contains ANY unsupported SECURITY links, even if those links are never used to annotate the schema.
- """
- SECURITY
-
- """
- `EXECUTION` features provide metadata necessary to correctly resolve fields. For instance, a hypothetical {ts} feature may provide a `@ts__resolvers` annotation which references a TypeScript module of field resolvers. A consumer which does not support the {ts} feature will be unable to correctly resolve such fields.
-
- Consumers MUST NOT serve a field if:
- - the schema's definition has **any** unsupported EXECUTION directives,
- - the field's parent type definition has **any** unsupported EXECUTION directives,
- - the field's return type definition has **any** unsupported EXECUTION directives, or
- - the field definition has **any** unsupported EXECUTION directives
-
- Such fields are *unresolvable*. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION features, even if those features are never used in the schema.
- """
- EXECUTION
-}
diff --git a/link/prefixing.graphql b/link/prefixing.graphql
deleted file mode 100644
index 11c5229..0000000
--- a/link/prefixing.graphql
+++ /dev/null
@@ -1,46 +0,0 @@
-schema
- @link(url: "https://specs.apollo.dev/core/v0.1")
- @link(url: "https://spec.example.com/foreignA/v1.0")
- @link(url: "https://spec.example.com/foreignB/v2.0", as: "B") {
- query: Query
-}
-
-"""
-foreignA__SomeType is a type defined by feature A.
-"""
-type foreignA__SomeType {
- """
- nativeField is a field defined by foreignA on a type also defined
- by foreignA (namely foreignA__SomeType)
- """
- nativeField: Int @foreignA__fieldDirective
-}
-
-"""
-foreignA__SomeInput is an input specified by feature A
-"""
-input foreignA__SomeInput {
- """
- nativeInputField is defined by foreignA
- """
- nativeInputField: Int
-}
-
-"""
-foreignA__Items is specified by feature A
-"""
-enum foreignA__Items { ONE, TWO, THREE @B }
-
-"""
-@B is the root directive defined by foreignB
-
-Root directives are named after their feature
-"""
-directive @B on ENUM_VALUE
-
-"""
-@foreignA__fieldDirective is a non-root (prefixed) directive defined by foreignA
-"""
-directive @foreignA__fieldDirective on FIELD_DEFINITION
-
-directive @link(url: String!, as: String) repeatable on SCHEMA
diff --git a/link/v1.0/algorithms.md b/link/v1.0/algorithms.md
deleted file mode 100644
index 1df3ffc..0000000
--- a/link/v1.0/algorithms.md
+++ /dev/null
@@ -1,132 +0,0 @@
-# Validations & Algorithms
-
-This section lays out algorithms for processing core schemas.
-
-Algorithms described in this section may produce *validation failures* if a document does not conform to the requirements core schema document. Validation failures SHOULD halt processing. Some consumers, such as authoring tools, MAY attempt to continue processing in the presence of validation failures, but their behavior in such cases is unspecified.
-
-## Bootstrapping
-
-Determine the name of the core specification within the document.
-
-It is possible to [rename the core feature](#sec-Renaming-core-itself) within a document. This process determines the actual name for the core feature if one is present.
-
-- **Fails** the *Has Schema* validation if there are no SchemaDefinitions in the document
-- **Fails** the *Has Core Feature* validation if the `core` feature itself is not referenced with a {@link} directive within the document
-- **Fails** the *Bootstrap Core Feature Listed First* validation if the reference to the `core` feature is not the first {@link} directive on the document's SchemaDefinition
-- **Fails** the *Core Directive Incorrect Definition* validation if the {@link} directive definition does not *match* the directive as defined by this specification.
-
-For the purposes of this algorithm, a directive's definition in a schema *matches* a definition provided in this specification if:
-- Its arguments have the specified names, types, and default values (or lack thereof)
-- It is defined as `repeatable` if and only if the specification's definition defines it as `repeatable`
-- The set of locations it belongs to is the same set of locations in the specification's definition.
-
-The following aspects may differ between the definition in the schema and the definition in the specification without preventing the definitions from *matching*:
-- The name of the directive (due to [prefixing](#sec-Prefixing))
-- The order of arguments
-- The order of locations
-- The directive's description string
-- Argument description strings
-- Directives applied to argument definitions
-
-Bootstrap(document) :
-1. Let {schema} be the only SchemaDefinition in {document}. (Note that legal GraphQL documents [must include at most one SchemaDefinition](http://spec.graphql.org/draft/#sec-Root-Operation-Types).)
- 1. ...if no SchemaDefinitions are present in {document}, the ***Has Schema* validation fails**.
-1. For each directive {d} on {schema},
- 1. If {d} has a [`url:`](#@link/feature) argument which [parses as a feature URL](#@link/feature), *and* whose identity is {"https://specs.apollo.dev/core/"} *and* whose version is {"v0.1"}, *and either* {d} has an [`as:`](#@link/as) argument whose value is equal to {d}'s name *or* {d} does not have an [`as:`](#@link/as) argument and {d}'s name is `core`:
- - If any directive on {schema} listed before {d} has the same name as {d}, the ***Bootstrap Core Feature Listed First* validation fails**.
- - If the definition of the directive {d} does not *match* the [definition of {@link} in this specification](#@link), the ***Core Directive Incorrect Definition* validation fails**.
- - Otherwise, **Return** {d}'s name.
-- If no matching directive was found, the ***Has Core Feature* validation fails**.
-
-## Feature Collection
-
-Collect a map of ({featureName}: `String`) -> `Directive`, where `Directive` is a {@link} Directive which introduces the feature named {featureName} into the document.
-
-- **Fails** the *Name Uniqueness* validation if feature names are not unique within the document.
-- **Fails** *Invalid Feature URL* validation for any invalid feature URLs.
-
-CollectFeatures(document) :
- - Let {coreName} be the name of the core feature found via {Bootstrap(document)}
- - Let {features} be a map of {featureName}: `String` -> `Directive`, initially empty.
- - For each directive {d} named {coreName} on the SchemaDefinition within {document},
- - Let {specifiedFeatureName} and {version} be the result of parsing {d}'s `url:` argument according to the [specified rules for feature URLs](#@link/feature)
- - If the `url:` is not present or fails to parse:
- - The ***Invalid Feature URL* validation fails** for {d},
- - Let {featureName} be the {d}'s [`as:`](#@link/as) argument or, if the argument is not present, {specifiedFeatureName}
- - If {featureName} exists within {features}, the ***Name Uniqueness* validation fails**.
- - Insert {featureName} => {d} into {features}
- - **Return** {features}
-
-
-Prefixes, whether implicit or explicit, must be unique within a document. Valid:
-
-:::[example](prefixing.graphql#schema[0]) -- Unique prefixes
-
-It is also valid to reference multiple versions of the same spec under different prefixes:
-
-:::[example](prefix-uniqueness.graphql#schema[0]) -- Explicit prefixes allow multiple versions of the same spec to coexist within a Document
-
-Without the explicit [`as:`](#@link/as), the above would be invalid:
-
-:::[counter-example](prefix-uniqueness.graphql#schema[1]) -- Non-unique prefixes with multiple versions of the same spec
-
-Different specs with the same prefix are also invalid:
-
-:::[counter-example](prefix-uniqueness.graphql#schema[2]) -- Different specs with non-unique prefixes
-
-## Assign Features
-
-Create a map of {element}: *Any Named Element* -> {feature}: `Directive` | {null}, associating every named schema element within the document with a feature directive, or {null} if it is not associated with a feature.
-
-AssignFeatures(document) :
- - Let {features} be the result of collecting features via {CollectFeatures(document)}
- - Let {assignments} be a map of ({element}: *Any Named Element*) -> {feature}: `Directive` | {null}, initally empty
- - For each named schema element {e} within the {document}
- - Let {name} be the name of the {e}
- - If {e} is a Directive and {name} is a key within {features},
- - Insert {e} => {features}`[`{name}`]` into {assignments}
- - **Continue** to next {e}
- - If {name} begins with {"__"},
- - Insert {e} => {null} into {assignments}
- - **Continue** to next {e}
- - If {name} contains the substring {"__"},
- - Partition {name} into `[`{prefix}, {base}`]` at the first {"__"} (that is, find the shortest {prefix} and longest {base} such that {name} = {prefix} + {"__"} + {base})
- - If {prefix} exists within {features}, insert {e} => {features}`[`{prefix}`]` into {assignments}
- - Else, insert {e} => {null} into {assignments}
- - **Continue** to next {e}
- - Insert {e} => {null} into {assignments}
- - **Return** {assignments}
-
-## Is In API?
-
-Determine if any schema element is included in the [API](#sec-Parts-of-a-Core-Schema) described by the core schema. A schema element is any part of a GraphQL document using type system definitions that has a [name](https://spec.graphql.org/draft/#Name).
-
-IsInAPI(element) :
- - Let {assignments} be the result of assigning features to elements via {AssignFeatures(document)}
- - If {assignments}`[`{element}`]` is {null}, **Return** {true}
- - Else, **Return** {false}
-
-Note: Later versions of this specification may add other ways to affect the behavior of this algorithm, but those mechanisms will only be enabled if you reference those hypothetical versions of this specification.
-
-## Is Affected By Feature?
-
-Determine if a schema element is *affected* by a given feature.
-
-IsAffected(element, feature):
- - Let {assignments} be the result of assigning features to elements via {AssignFeatures(document)}
- - For each directive {d} on {element}, If {assignments}`[`{d}`]` is {feature}, **Return** {true}
- - If {element} is a FieldDefinition,
- - Let {parent} be the parent ObjectDefinition or InterfaceDefinition for {element}
- - If {IsAffected(parent, feature)}, **Return** {true}
- - For each argument type {a} declared on {element},
- - Let {t} be the InputDefinition, EnumDefinition, or ScalarDefinition for argument {a}
- - If {IsAffected(t, feature)}, **Return** {true}
- - Let {return} be the ObjectDefinition, InterfaceDefinition, or UnionDefinition for {element}'s return type
- - If {IsAffected(return, feature)}, **Return** {true}
- - If {element} is an InputDefinition,
- - For each InputFieldDefinition {field} within {element},
- - Let {t} be the InputDefinition, EnumDefinition, or ScalarDefinition for the type of {field}
- - If {IsAffected(t, feature)}, **Return** {true}
- - If {element} is an EnumDefinition,
- - For each EnumValueDefinition {value} in {element},
- - If {IsAffected(value, feature)}, **Return** {true}
\ No newline at end of file
diff --git a/link/v1.0/basic.graphql b/link/v1.0/basic.graphql
deleted file mode 100644
index 38e6671..0000000
--- a/link/v1.0/basic.graphql
+++ /dev/null
@@ -1,14 +0,0 @@
-schema
- @link(url: "https://specs.apollo.dev/core/v0.1")
- @link(url: "https://specs.example.com/example/v1.0")
-{
- query: Query
-}
-
-type Query {
- field: Int @example
-}
-
-directive @example on FIELD_DEFINITION
-
-directive @link(url: String!, as: String) repeatable on SCHEMA
diff --git a/link/v1.0/core-schemas-intro.md b/link/v1.0/core-schemas-intro.md
deleted file mode 100644
index da37b5e..0000000
--- a/link/v1.0/core-schemas-intro.md
+++ /dev/null
@@ -1,23 +0,0 @@
-Core schemas provide tools for linking definitions from different GraphQL schemas together into one.
-
-```graphql example -- linking a directive from another schema
-extend schema
- # 👇🏽 schemas are identified by a url
- @link(url: "https://internal.example.com/admin")
-
-type Query {
- allUsers: [User] @admin__adminOnly # 👈🏽 remote identifier, namespaced
-}
-```
-
-```graphql example -- importing a directive from another schema
-extend schema
- # specific definitions can be imported 👇🏽
- @link(url: "https://internal.example.com/admin", import: ["@adminOnly"])
-
-type Query {
- allUsers: [User] @adminOnly # 👈🏽 remote identifier, imported
-}
-```
-
-This document introduces a set of conventions for linking and namespacing within GraphQL schemas. Core schemas are not a new kind of document and do not introduce any new syntax—they are just GraphQL schemas which can be interpreted according to the conventions outlined in this doc.
diff --git a/link/v1.0/index.html b/link/v1.0/index.html
index d0e4e68..b757a98 100644
--- a/link/v1.0/index.html
+++ b/link/v1.0/index.html
@@ -1046,341 +1046,48 @@
link v1.0
+
for linking core schemas together
Status
Draft
Version
1.0
-
-
-
Core schemas provide tools for linking definitions from different GraphQL schemas together into one.
extendschema
- # 👇🏽 first, link @link from this url
- @link(url:"https://specs.apollo.dev/link/v1.0")
- # 👇🏽 link other schemas by their urls
- @link(url:"https://internal.example.com/admin")
-
-typeQuery{
- allUsers:[User]@admin__adminOnly# 👈🏽 remote identifier, namespaced
-}
-
extendschema
- @link(url:"https://specs.apollo.dev/link/v1.0")
- # specific definitions can be imported 👇🏽
- @link(url:"https://internal.example.com/admin",import:["@adminOnly"])
-
-typeQuery{
- allUsers:[User]@adminOnly# 👈🏽 remote identifier, imported
-}
-
-
This document introduces a set of conventions for linking and namespacing within GraphQL schemas. Core schemas are not a new kind of document and do not introduce any new syntax—they are just GraphQL schemas which can be interpreted according to the conventions outlined in this doc.
+
+
+
This schema defines @link, the fundamental linking directive in core schemas.
+
See the core schema spec for more details on a document’s Scope and how link and @id interact with it.
Within a core schema document, every top‐level definition and reference (for example, every named type and directive) has a position in the global graph. This position is captured by a global graph reference.
-
A global graph reference (or gref) is a (link url, element) pair.
-
The URL may be null, to represent local definitions within a schema that is not bound to a URL. Otherwise it must be a valid link url in canonical form.
-
The element may be:
-
-
Directive(name) — a directive
-
Type(name) — a named type of any kind
-
Schema(name?) — a further link to yet another schema. name may be null to indicate the schema itself.
-
-
Implementations may represent these internally in a variety of ways. They also have a canonical string form, which is used in Import
-
-
Directive(name) is represented with “@name”
-
Type(name) is simply represented with “name”
-
Schema(name) is represented with “name::”
-
-
Types and directives are separated in this way because that’s how GraphQL does it—you can have a User type and a @User directive in the same schema (though GraphQL naming conventions would suggest againt it).
Since link urls explicitly cannot have fragments, we can represent global graph references as a URL with a fragment. For example, a reference to this document’s @link directive can be rendered as https://specs.apollo.dev/link/v1.0#@link. A reference to this document’s Import scalar can be rendered as https://specs.apollo.dev/link/v1.0#Import.
-
This is particularly convenient for providing links to documentation. We’ll use this form in examples throughout this document.
As mentioned previously, core schemas connect every definition, directive usage, and named type reference with a global graph reference. Taking the example from the introduction:
extendschema
-# 👇🏽 🌍 https://specs.apollo.dev/link/v1.0/#@link
- @link(url:"https://specs.apollo.dev/link/v1.0")
-
-# 👇🏽 🌍 https://specs.apollo.dev/link/v1.0/#@link
- @link(url:"https://internal.example.com/admin",import:[{name:"@adminOnly",as:"@admin"}])
-
-# 👇🏽 🌍 #Query (note: this schema has no url, so the url part is null)
-typeQuery{
- # 👇🏽 🌍 https://internal.example.com/admin#@adminOnly
- allUsers:[User]@admin
- # 🖕🏽 🌍 #User
-}
-
-
This indirection is the whole point. A core‐aware security layer scanning the document for fields marked with https://internal.example.com/admin#@adminOnly will find it, regardless of its local name within the document.
-
Attribution functions the same for all references and definitions within the document. For example, if we include a definition of the @admin directive from the example above (as we must, if the schema is to be fully valid) it too will be attributed to the foreign schema:
Using @id is not, strictly speaking, necessary. A URL can be associated with a document in any number of ways (for example, a processor could associate the schema with the URL where it found it. However, using @id makes the document self‐describing; core‐aware processors will correctly attribute definitions and references within such documents, regardless of where they were found.
Core schemas have a document‐wide scope. A document’s scope is a map of Element ⇒ Binding. The scope is constructed from a document’s @link and @id directives and is used to attribute definitions and references within the document.
-
Elements are the same as in global graph references. When used as scope keys, they carry the following meanings:
-
-
Schema(name) — a schema @linked from the document. name can be used as a prefix for definitions and references within the document, and nameMUST either be a valid prefix or null, indicating the present schema.
-
Directive(name) — a directive imported into the document
implicit: Bool — indicating whether the binding was explicitly imported or created implicitly. Implicit bindings are “soft”—they may be overwritten by explicit bindings and will not be formed if an explicit binding for the item alreaady exists.
-
-
Similar to a gref‘s elements, different types of scoped items can have the same name without conflict. For example, a scope can contain both a type and schema named “User”, although this should generally be avoided if possible.
-
The global graph reference mapped to the target MUST match the item’s type—a scope cannot map a schema to a directive, for instance. The algorithms provided in this document ensure this is always the case.
A @link without any imports introduces two entries into the scope:
-
-
an explicit binding to the foreign schema, and
-
an implicit binding to a directive with the foreign schema’s own name, if its URL has a name. This somewhat‐blessed directive is the schema’s “root directive”
@linking a foreign schema whose URL does not have a name will create a schema binding if and only if as: is specified, and will never create a root directive reference:
Document processors MAY reject schemas with such errors outright.
-
Permissive processors (for example, a language server which wants to provide best‐effort attribution even in the face of document errors) MAY choose to process such documents even in the face of conflicts. Such processors SHOULD include the first (in document order) binding in the scope, and reject subsequent bindings. Such processors SHOULD also provide error messages listing all@links which are in conflict.
Within a core schema, type names and directives which begin with a valid namespace identifier followed by two underscores (__) will be attributed to the foreign schema bound to that name in the document scope if one exists.
extendschema
- @link(url:"https://specs.apollo.dev/link/v1.0")
-# 1. Schema("link") -> "https://specs.apollo.dev/link/v1.0" (explicit)
-# 2. Directive("link") -> "https://specs.apollo.dev/link/v1.0#@link" (implicit)
-
-# 👇🏽 🌍 #myOwn__Purpose (note, this document has no @id, so the url of this gref is null)
-enummyOwn__Purpose{SECURITYEXECUTION}
-
-Note
-GraphQL name conventions strongly suggest against such naming. But amongst the core schema design principles is universality—the ability to represent and link any arbitrary set of GraphQL schemas, no matter how weird the names in them are.
The @link directive for @link itself—the “bootstrap”—MUST be the first @link in the document. Other directives may precede it, including directives which have been @linked.
It MUST be a valid GraphQL schema. Amongst other things, this means that it MUST contain definitions for all types and directives it references, including those from foreign schemas
-
If it includes any @links, it MUST include a bootstrap link which MUST precede all other @links in the document
-
It MAY include an @id, particularly if other schemas are meant to link to it (e.g. if the document provide directives for use on other schemas)
-
-
Good news: this means that every valid GraphQL schema which does not use @link is automatically a fully valid core schema. Otherwise‐valid schemas which use @link simply have to include a bootstrap to become fully valid core schemas.
-
-Note
-The bootstrap link is required in order to properly identify the version of the link spec in use.
be RFC 3986 URLs. When viewed, the URL SHOULD provide schema documentation in some human‐readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
-
Link URLs MAY contain information about the spec’s name and version:
+
Link URLs MAY contain information about the spec’s name and version:
The final two segments of the URL’s pathMAY contain the schema’s name and a version tag, in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid VersionTag. To be recognized as a name, the penultimate path component MUST be a valid GraphQL name which does not start or end with an underscore (_) and which does not contain the namespace separator (__).
+
The final two segments of the URL’s pathMAY contain the schema’s name and a version tag, in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid VersionTag. To be recognized as a name, the penultimate path component MUST be a valid GraphQL name which does not start or end with an underscore (_) and which does not contain the namespace separator (__).
Empty final path components (that is, trailing slashes) and any URL components which have not been assigned a meaning (such as the fragment and query) MUST be ignored.
namespace prefix will automatically be linked to the URL. If a name is not present, then elements of the foreign schema must be imported in order to be referenced.
+
If name is present, that namespace prefix will automatically be linked to the URL. If a name is not present, then elements of the foreign schema must be imported in order to be referenced.
Change the namespace prefix assigned to the foreign schema. The name MUST be a valid GraphQL identifier, MUST NOT contain the namespace separator ("__"), and MUST NOT end with an underscore (which would create ambiguity between whether "x___y" is prefix x_ for element y or prefix x for element _y).
-
By default, @link will assign a prefix based on the name extracted from the URL. If no name is present, a prefix will not be assigned.
-
Providing as: overrides the default behavior: the foreign schema will be bound to the provided name, regardless of the name present in the URL (or the lack of one).
Change the namespace prefix assigned to the foreign schema. The name MUST be a valid GraphQL identifier, MUST NOT contain the namespace separator ("__"), and MUST NOT end with an underscore (which would create ambiguity between whether "x___y" is prefix x_ for element y or prefix x for element _y).
+
By default, @link will assign a prefix based on the name extracted from the URL. If no name is present, a prefix will not be assigned.
+
Providing as: overrides the default behavior: the foreign schema will be bound to the provided name, regardless of the name present in the URL (or the lack of one).
schema@link(url:"https://specs.apollo.dev/link/v1.0")@link(url:"https://spec.example.com/example/v1.0",as:"eg"){
- query:Query
+ query: Query
}typeUser{# Specifying `as: "eg"` transforms @example into @eg
- name:String@eg(data:ITEM)
+ name: String @eg(data:ITEM)}# Additional specified schema elements must have their prefixes set# to the new name.
-enumeg__Data{
+enumeg__Data{ITEM}# Name transformation must also be applied to definitions pulled in from# specifications.
-directive@eg(data:eg__Data)onFIELD_DEFINITION
+directive@eg(data: eg__Data)onFIELD_DEFINITION
-directive@link(url:String!,as:String)repeatableonSCHEMA
+directive@link(url: String!,as: String)repeatableonSCHEMA
An optional purpose for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
-
By default, @links SHOULD fail open. This means that @links to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown links and serve or process the rest of the schema normally.
-
This behavior is different for @links with a specified purpose:
+
By default, @links SHOULD fail open. This means that @links to unknown schemas SHOULD NOT prevent a schema from being served or processed. Instead, consumers SHOULD ignore unknown links and serve or process the rest of the schema normally.
+
This behavior is different for @links with a specified purpose:
SECURITY links convey metadata necessary to compute the API schema and securely resolve fields within it
EXECUTION links convey metadata necessary to correctly resolve fields within the schema
This is not intended to be an exhaustive list of all the purposes a foreign schema or its metadata might serve. Rather, it is intended to capture cases where the default fail‐open behavior of core schema consumers is undesirable.
Note
we’ll refer to directives from links which are for: SECURITY or for: EXECUTION as “SECURITY directives” and “EXECUTION directives”, respectively.
SECURITY links provide metadata necessary to securely resolve fields. For instance, a hypothetical auth schema may provide an @auth directive to flag fields which require authorization. If a data core does not support the auth schemas and serves those fields anyway, these fields will be accessible without authorization, compromising security.
SECURITY links provide metadata necessary to securely resolve fields. For instance, a hypothetical auth schema may provide an @auth directive to flag fields which require authorization. If a data core does not support the auth schemas and serves those fields anyway, these fields will be accessible without authorization, compromising security.
Security‐conscious consumers MUST NOT serve a field if:
the schema definition has any unsupported SECURITY directives,
@@ -1520,8 +1228,8 @@
MAY choose to relax these requirements. For instance, servers may provide a development mode in which unknown SECURITY directives are ignored, perhaps with a warning. Such software may also provide a way to explicitly disable some or all SECURITY links during development.
More security‐conscious consumers MAY choose to enhance these requirements. For instance, production servers MAY adopt a policy of entirely rejecting any schema which contains ANY unsupported SECURITY links, even if those links are never used to annotate the schema.
EXECUTION schemas provide metadata necessary to correctly resolve fields. For instance, a hypothetical ts schemas may provide a @ts__resolvers annotation which references a TypeScript module of field resolvers. A consumer which does not support the ts schemas will be unable to correctly resolve such fields.
MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION schemas, even if those schemas are never used in the schema.
Visit every @link and @id within the document to construct the document’s scope.
-
-Note
-This algorithm Reports errors. Depending on their needs, implementations MAY decide to fail immediately in the face of these errors, or may elect to continue processing the document
Emit all scope bindings produced by a @link directive.
-
-Note
-This algorithm is specified as a generator. This is deemed to produce the clearest psuedocode, but implementations may choose other approaches, such as collecting bindings into a list.
Letmyself be the URL of the schema returned from Lookup(scope, selfReference), or null if none was found
-
Let name be the Name of defOrRef
-
IfdefOrRef is a Directive or DirectiveDefinition Then
-
Return GRef(myself, Directive(name))
-
-
-
Otherwise, Return GRef(myself, Type(name))
-
-
-
LocateBound(scope, defOrRef) returns the binding for defOrRef if one is specified in scope, otherwise null. It does not resolve local names to the local document.
Specs are versioned with a subset of a Semantic Version Number containing only the major and minor parts. Thus, specifications SHOULD provide a version of the form vMajor.Minor, where both integers ≥ 0.
As specified by semver, spec authors SHOULD increment the:
-
-
MAJOR version when you make incompatible API changes,
-
MINOR version when you add functionality in a backwards compatible manner
-
-
-
Patch and pre‐release qualifiers are judged to be not particularly meaningful in the context of GraphQL schemas, which are (by definition) interfaces rather than implementations. The patch component of a semver denotes a bug fix which is backwards compatible—that is, a change to the implementation which does not affect the interface. Patch‐level changes in the version of a spec denote wording clarifications which do not require implementation changes. As such, it is not important to track them for the purposes of version resolution.
-
As with semver, the 0.x version series is special: there is no expectation of compatibility between versions 0.x and 0.y. For example, a processor must not activate implementation 0.4 to satisfy a requested version of 0.2.
Given a version requested by a document and an available version of an implementation, the following algorithm will determine if the available version can satisfy the requested version:
-
-
+
+
```
-Core schemas provide tools for linking definitions from different GraphQL schemas together into one.
+This schema defines [{@link}](#@link), the fundamental linking directive in [core schemas](/core/v1.0).
-```graphql example -- linking a directive from another schema
-extend schema
- # 👇🏽 first, link @link from this url
- @link(url: "https://specs.apollo.dev/link/v1.0")
- # 👇🏽 link other schemas by their urls
- @link(url: "https://internal.example.com/admin")
-
-type Query {
- allUsers: [User] @admin__adminOnly # 👈🏽 remote identifier, namespaced
-}
-```
-
-```graphql example -- importing a directive from another schema
-extend schema
- @link(url: "https://specs.apollo.dev/link/v1.0")
- # specific definitions can be imported 👇🏽
- @link(url: "https://internal.example.com/admin", import: ["@adminOnly"])
-
-type Query {
- allUsers: [User] @adminOnly # 👈🏽 remote identifier, imported
-}
-```
-
-This document introduces a set of conventions for linking and namespacing within GraphQL schemas. Core schemas are not a new kind of document and do not introduce any new syntax—they are just GraphQL schemas which can be interpreted according to the conventions outlined in this doc.
-
-# Global Graph References
-
-Within a core schema document, every top-level definition and reference (for example, every named type and directive) has a position in the global graph. This position is captured by a *global graph reference*.
-
-A global graph reference (or *gref*) is a (*[link url](#@link/url)*, *element*) pair.
-
-The URL may be {null}, to represent local definitions within a schema that is not bound to a URL. Otherwise it must be a [valid link url in canonical form](#@link/url).
-
-The *element* may be:
-- Directive({name}) — a directive
-- Type({name}) — a named type of any kind
-- Schema({name}?) — a further link to yet another schema. {name} may be {null} to indicate the schema itself.
-
-Implementations may represent these internally in a variety of ways. They also have a canonical string form, which is used in [{Import}](#Import)
-
-- Directive({name}) is represented with "@{name}"
-- Type({name}) is simply represented with "{name}"
-- Schema({name}) is represented with "{name}::"
-
-Types and directives are separated in this way because that's how GraphQL does it—you can have a `User` type and a `@User` directive in the same schema (though GraphQL naming conventions would suggest againt it).
-
-## URL representation
-
-Since [link urls](#Url) explicitly cannot have fragments, we can represent global graph references as a URL with a fragment. For example, a reference to this document's {@link} directive can be rendered as `https://specs.apollo.dev/link/v1.0#@link`. A reference to this document's {Import} scalar can be rendered as `https://specs.apollo.dev/link/v1.0#Import`.
-
-This is particularly convenient for providing links to documentation. We'll use this form in examples throughout this document.
-
-# Attribution
-
-As mentioned [previously](#sec-Global-Graph-References), core schemas connect every definition, directive usage, and named type reference with a global graph reference. Taking the example from the introduction:
-
-```graphql example -- global graph references (shown in URL form)
-extend schema
-# 👇🏽 🌍 https://specs.apollo.dev/link/v1.0/#@link
- @link(url: "https://specs.apollo.dev/link/v1.0")
-
-# 👇🏽 🌍 https://specs.apollo.dev/link/v1.0/#@link
- @link(url: "https://internal.example.com/admin")
-
-# 👇🏽 🌍 #Query (note: this schema has no url, so this gref's url part is null)
-type Query {
- # 👇🏽 🌍 https://internal.example.com/admin#@adminOnly
- allUsers: [User] @admin__adminOnly
- # 🖕🏽 🌍 #User
-}
-```
-
-This attribution *does not change* if we [`import`](#@link/import) some names, even renaming them:
-
-```graphql example -- global graph references with imports
-extend schema
-# 👇🏽 🌍 https://specs.apollo.dev/link/v1.0/#@link
- @link(url: "https://specs.apollo.dev/link/v1.0")
-
-# 👇🏽 🌍 https://specs.apollo.dev/link/v1.0/#@link
- @link(url: "https://internal.example.com/admin", import: [{ name: "@adminOnly", as: "@admin" }])
-
-# 👇🏽 🌍 #Query (note: this schema has no url, so the url part is null)
-type Query {
- # 👇🏽 🌍 https://internal.example.com/admin#@adminOnly
- allUsers: [User] @admin
- # 🖕🏽 🌍 #User
-}
-```
-
-This indirection is the whole point. A core-aware security layer scanning the document for fields marked with `https://internal.example.com/admin#@adminOnly` will find it, regardless of its local name within the document.
-
-Attribution functions the same for all references and definitions within the document. For example, if we include a definition of the `@admin` directive from the example above (as we must, if the schema is to be fully valid) it too will be attributed to the foreign schema:
-
-```graphql example -- global graph references for definitions
-extend schema
-# 👇🏽 🌍 https://specs.apollo.dev/link/v1.0/#@link
- @link(url: "https://specs.apollo.dev/link/v1.0")
-
-# 👇🏽 🌍 https://specs.apollo.dev/link/v1.0/#@link
- @link(url: "https://internal.example.com/admin", import: [{ name: "@adminOnly", as: "@admin" }])
-
-# 👇🏽 🌍 #Query (note: this schema has no url, so the url part is null)
-type Query {
- # 👇🏽 🌍 https://internal.example.com/admin#@adminOnly
- allUsers: [User] @admin
- # 🖕🏽 🌍 #User
-}
-
-# 👇🏽 🌍 https://internal.example.com/admin#@adminOnly
-directive @admin on FIELD_DEFINITION
-```
-
-## Identifying the document's own URL
-
-The document's own URL can be specified with the [`@id` directive](#@id):
-
-```graphql example -- global graph references with {@id}
-extend schema
-# 👇🏽 🌍 https://specs.apollo.dev/link/v1.0/#@id
- @id(url: "https://api.example.com/myself")
-
-# 👇🏽 🌍 https://specs.apollo.dev/link/v1.0/#@link
- @link(url: "https://specs.apollo.dev/link/v1.0", import: ["@id"])
-
-# 👇🏽 🌍 https://specs.apollo.dev/link/v1.0/#@link
- @link(url: "https://internal.example.com/admin", import: [{ name: "@adminOnly", as: "@admin" }])
-
-# 👇🏽 🌍 https://api.example.com/myself#Query
-type Query {
- # 👇🏽 🌍 https://internal.example.com/admin#@adminOnly
- allUsers: [User] @admin
- # 🖕🏽 🌍 https://api.example.com/myself#User
-}
-```
+See the [core schema spec](/core/v1.0) for more details on a document's [Scope](../core/v1.0#sec-Scope) and how {link} and {@id} interact with it.
-Using `@id` is not, strictly speaking, necessary. A URL can be associated with a document in any number of ways (for example, a processor could associate the schema with the URL where it found it. However, using [{@id}](#@id) makes the document self-describing; core-aware processors will correctly attribute definitions and references within such documents, regardless of where they were found.
+#! @link
-# Scope
-
-Core schemas have a document-wide *scope*. A document's scope is a map of {Element} ==> {Binding}. The scope is constructed from a document's [@link](#@link) and [@id](#@id) directives and is used to [attribute](#sec-Attribution) definitions and references within the document.
-
-Elements are the same as in [global graph references](#sec-Global-Graph-References). When used as scope keys, they carry the following meanings:
-- Schema({name}) — a schema {@link}ed from the document. {name} can be used as a [prefix](#sec-Name-Conventions) for definitions and references within the document, and {name} MUST either be a valid prefix or {null}, indicating the present schema.
-- Directive({name}) — a directive [imported](#@link/import) into the document
-- Type({name}) — a type [imported](#@link/import) into the document
-
-A {Binding} contains:
-- {gref}: GRef — the [global graph reference](#sec-Global-Graph-References) which is the target of the binding
-- {implicit}: Bool — indicating whether the binding was explicitly imported or created implicitly. Implicit bindings are "soft"—they may be overwritten by explicit bindings and will not be formed if an explicit binding for the item alreaady exists.
-
-Similar to a [gref](#sec-Global-Graph-References)'s elements, different types of scoped items can have the same name without conflict. For example, a scope can contain both a type and schema named "User", although this should generally be avoided if possible.
-
-The [global graph reference](#sec-Global-Graph-References) mapped to the target MUST match the item's type—a scope cannot map a schema to a directive, for instance. The [algorithms](#sec-Algorithms) provided in this document ensure this is always the case.
-
-## Entries added by @link
-
-A {@link} without any imports introduces two entries into the scope:
-1. an explicit binding to the foreign schema, and
-2. an implicit binding to a directive with the foreign schema's own name, if its URL [has a name](#@link/url). This somewhat-blessed directive is the schema's "root directive"
-
-```graphql example -- {@link} bringing a single schema into scope
- @link(url: "https://example.com/foreignSchema")
- # 1. foreignSchema:: -> https://example.com/foreignSchema (explicit)
- # 2. @foreignSchema -> https://example.com/foreignSchema#@foreignSchema (implicit)
-```
-
-{@link}ing a foreign schema whose URL does not have a name will create a schema binding if and only if [`as:`](#@link/as) is specified, and will never create a root directive reference:
-
-```graphql example -- {@link} bringing a single schema into scope
- # 👇🏽 url does not have a name
- @link(url: "https://api.example.com", as: "example")
- # 1. example:: -> https://example.com#example (explicit)
-```
-
-A {@link} with imports will add these entries to the scope, in addition to entries for each import:
-
-```graphql example -- {@link} importing items into the scope
- @link(url: "https://example.com/foreignSchema", import: ["SomeType", "@someDirective"])
- # 1. foreignSchema:: -> https://example.com/foreignSchema (explicit)
- # 2. @foreignSchema -> https://example.com/foreignSchema#@foreignSchema (implicit)
- # 3. SomeType -> https://example.com/foreignSchema#SomeType (explicit)
- # 4. @someDirective -> https://example.com/foreignSchema#@someDirective (explicit)
-```
-
-Specifying [`as:`](#@link/as) changes the names of the scope items, but not their bound grefs:
-
-```graphql example -- {@link} conflicting schema names
- @link(url: "https://example.com/foreignSchema", as: "other")
- # 1. other:: -> https://example.com/foreignSchema (explicit)
- # 2. @other -> https://example.com/foreignSchema#@foreignSchema (implicit)
-```
-
-It is not an error to overwrite an implicit binding with an explicit one:
-
-```graphql example -- {@link} import overriding an implicit binding
- @link(url: "https://example.com/foreignSchema")
- # 1. foreignSchema:: -> https://example.com/foreignSchema (explicit)
- # 2. @foreignSchema -> https://example.com/foreignSchema#@foreignSchema (implicit)
-
- # (2) will be subsequently overwritten:
- @link(url: "https://other.com/otherSchema, import: ["@foreignSchema"])
- # 3. otherSchema:: -> https://other.com/otherSchema (explicit)
- # 4. @otherSchema -> https://other.com/otherSchema#@otherSchema (implicit)
- # 5. @foreignSchema -> https://other.com/otherSchema#@foreignSchema (explicit, overwrites (2))
-```
-
-But it is an error to overwrite an explicit binding, or for two implicit bindings to overlap:
-
-```graphql counter-example -- {@link} conflicting schema names
- @link(url: "https://example.com/foreignSchema")
- # 1. foreignSchema:: -> https://example.com/foreignSchema (explicit)
- # 2. @foreignSchema -> https://example.com/foreignSchema#@foreignSchema (implicit)
-
- @link(url: "https://other.com/foreignSchema")
- # ❌ foreignSchema:: -> https://other.com/foreignSchema (explicit)
- # (error, conflicts with with (1))
- # ❌ @foreignSchema -> https://other.com/otherSchema#otherSchema (implicit)
- # (error, conflicts with (2))
-```
-
-Document processors MAY reject schemas with such errors outright.
-
-Permissive processors (for example, a language server which wants to provide best-effort attribution even in the face of document errors) MAY choose to process such documents even in the face of conflicts. Such processors SHOULD include the first (in document order) binding in the scope, and reject subsequent bindings. Such processors SHOULD also provide error messages listing *all* {@link}s which are in conflict.
-
-## Entry added by @id
-
-[@id](#@id) adds just one entry into the scope, binding the current document to the given URL:
-
-```graphql example -- {@id} adds a self-binding into the scope
- @id(url: "https://example.com/myself")
- # 1. Schema() -> https://example.com/myself (explicit)
-```
-
-# Name Conventions
-
-Within a core schema, type names and directives which begin with a valid namespace identifier followed by two underscores (`__`) will be [attributed](#sec-Attribution) to the foreign schema bound to that name in the document [scope](#sec-Scope) if one exists.
-
-```graphql example -- using a prefixed name
-extend schema
- @link(url: "https://specs.apollo.dev/link/v1.0")
-# 1. Schema("link") -> "https://specs.apollo.dev/link/v1.0" (explicit)
-# 2. Directive("link") -> "https://specs.apollo.dev/link/v1.0#@link" (implicit)
-
-# 👇🏽 🌍 https://specs.apollo.dev/link/v1.0/#Purpose
-enum link__Purpose { SECURITY EXECUTION }
-```
-
-If no schema has been linked to that name, it is interpreted as a local name:
-
-```graphql example -- a strange local name
-extend schema
- @link(url: "https://specs.apollo.dev/link/v1.0")
-# 1. Schema("link") -> "https://specs.apollo.dev/link/v1.0" (explicit)
-# 2. Directive("link") -> "https://specs.apollo.dev/link/v1.0#@link" (implicit)
-
-# 👇🏽 🌍 #myOwn__Purpose (note, this document has no @id, so the url of this gref is null)
-enum myOwn__Purpose { SECURITY EXECUTION }
-```
-
-```graphql example -- a strange local name in a document with an id
-extend schema
- @id(url: "https://api.example.com")
- @link(url: "https://specs.apollo.dev/link/v1.0", import: ["@id"]
-
-# 👇🏽 🌍 https://api.example.com#myOwn__Purpose
-enum myOwn__Purpose { SECURITY EXECUTION }
-```
-
-Note: GraphQL name conventions strongly suggest against such naming. But amongst the core schema design principles is *universality*—the ability to represent and link *any arbitrary* set of GraphQL schemas, no matter how weird the names in them are.
-
-## Bootstrapping
-
-Documents can {@link} link itself. Indeed, if they MUST do so if they use [@link](#@link) at all and are intended to be [fully valid](#sec-Fully-Valid-Core-Schemas):
-
-```graphql example -- bootstrapping {@link}
-extend schema
- @link(url: "https://specs.apollo.dev/link/v1.0")
-```
-
-The {@link} directive for {@link} itself—the "bootstrap"—MUST be the first {@link} in the document. Other directives may precede it, including directives which have been {@link}ed.
-
-```graphql example -- bootstrapping {@link} and using {@id} before doing so
-extend schema
- @id(url: "https://api.example.com")
- @link(url: "https://specs.apollo.dev/link/v1.0", import: ["@id"])
-```
-
-There is otherwise nothing special or restricted about bootstraps. Documents MAY use them to rename {@link}—either with [`as:`](#@link/as) or [`import:`](#@link/import) or both:
-
-```graphql example -- bootstrapping {@link} with a different name
-extend schema
- @core(url: "https://specs.apollo.dev/link/v1.0", as: "core")
-```
-
-```graphql example -- importing {@link} with a different name
-extend schema
- @core(url: "https://specs.apollo.dev/link/v1.0", import: [{ name: "@link", as: "@core" }])
-```
-
-```graphql example -- importing {@link} and other things simultaneously
-extend schema
- @id(url: "https://api.example.com")
- @foo(url: "https://specs.apollo.dev/link/v1.0", import: [
- {name: "@link", as: "@core"},
- "@id"
- ])
-```
-
-# Fully Valid Core Schemas
-
-For a document to be a fully valid core schema:
-
-1. It MUST be a valid GraphQL schema. Amongst other things, this means that it MUST contain definitions for all types and directives it references, including those from foreign schemas
-2. If it includes any {@link}s, it MUST include a [bootstrap link](#sec-Bootstrapping) which MUST precede all other {@link}s in the document
-3. It MAY include an {@id}, particularly if other schemas are meant to link to it (e.g. if the document provide directives for use on other schemas)
-
-Good news: this means that every valid GraphQL schema which *does not* use {@link} is automatically a fully valid core schema. Otherwise-valid schemas which use {@link} simply have to include a [bootstrap](#sec-Bootstrapping) to become fully valid core schemas.
-
-Note: The bootstrap link is required in order to properly identify the [version](#sec-Versioning) of the link spec in use.
-
-# Definitions
-
-##! @link
-
-```graphql definition
-directive @link(url: String!, as: String, import: [Import])
-```
+:::[definition](./link-v1.0.graphql#@link)
Link a foreign schema by its URL.
-###! url: String!
+{@link} [introduces one or more items](/core/v1.0#sec-Entries-added-by-@link) into the document's [Scope](#core/Scope).
+
+##! url: String!
The foreign schema's URL.
@@ -352,7 +32,7 @@ Link URLs serve two main purposes:
Link URLs SHOULD be [RFC 3986 URLs](https://tools.ietf.org/html/rfc3986). When viewed, the URL SHOULD provide schema documentation in some human-readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
-Link URLs MAY contain information about the spec's [name](#sec-Name-Conventions) and [version](#sec-Versioning):
+Link URLs MAY contain information about the spec's [name](#Name-Conventions) and [version](#Versioning):
```html diagram -- Basic anatomy of a link URL
@@ -360,7 +40,7 @@ Link URLs MAY contain information about the spec's [name](#sec-Name-Conventions)
```
-The final two segments of the URL's [path](https://tools.ietf.org/html/rfc3986#section-3.3) MAY contain the schema's name and a [version tag](#sec-Versioning), in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid {VersionTag}. To be recognized as a name, the penultimate path component MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name) which does not start or end with an underscore (`_`) and which does not contain the namespace separator (`__`).
+The final two segments of the URL's [path](https://tools.ietf.org/html/rfc3986#section-3.3) MAY contain the schema's name and a [version tag](#Versioning), in that order. Both are optional. To be recognized as a version tag, the final path component MUST be a valid {VersionTag}. To be recognized as a name, the penultimate path component MUST be a valid [GraphQL name](https://spec.graphql.org/draft/#Name) which does not start or end with an underscore (`_`) and which does not contain the namespace separator (`__`).
Empty final path components (that is, trailing slashes) and any URL components which have not been assigned a meaning (such as the fragment and query) MUST be ignored.
@@ -380,17 +60,17 @@ All of these are valid arguments to `url`, and their interpretations:
| https://spec.example.com/v1.0 | https://spec.example.com/v1.0 | *(null)* | v1.0 |
| https://spec.example.com/vX | https://spec.example.com/vX | vX | *(null)* |
-If `name` is present, that [namespace prefix](#sec-Name-Conventions) will automatically be linked to the URL. If a `name` is not present, then elements of the foreign schema must be [`imported`](#@link/import) in order to be referenced.
+If `name` is present, that [namespace prefix](#core/Name-Conventions) will automatically be linked to the URL. If a `name` is not present, then elements of the foreign schema must be [`imported`](#@link.import) in order to be referenced.
-###! as: String
+##! as: String
-Change the [namespace prefix](#sec-Name-Conventions) assigned to the foreign schema.
+Change the [namespace prefix](#Name-Conventions) assigned to the foreign schema.
The name MUST be a valid GraphQL identifier, MUST NOT contain the namespace separator ({"__"}), and MUST NOT end with an underscore (which would create ambiguity between whether {"x___y"} is prefix `x_` for element `y` or prefix `x` for element `_y`).
By default, {@link} will assign a prefix based on the `name` extracted from the URL. If no `name` is present, a prefix will not be assigned.
-Providing [`as:`](#@link/as) overrides the default behavior: the foreign schema will be bound to the provided name, regardless of the `name` present in the URL (or the lack of one).
+Providing [`as:`](#@link.as) overrides the default behavior: the foreign schema will be bound to the provided name, regardless of the `name` present in the URL (or the lack of one).
```graphql example -- Using {@link}(url:, as:) to link a schema with a custom name
schema
@@ -418,13 +98,13 @@ directive @eg(data: eg__Data) on FIELD_DEFINITION
directive @link(url: String!, as: String) repeatable on SCHEMA
```
-###! import: [Import]
+##! import: [Import]
A list of names, possibly with aliases, to import from the foreign schema into the document.
See the [Import](#Import) scalar for a description of the format.
-###! for: Purpose
+##! for: Purpose
An optional [purpose](#Purpose) for this link. This hints to consumers as to whether they can safely ignore metadata described by a foreign schema.
@@ -434,15 +114,15 @@ This behavior is different for {@link}s with a specified purpose:
- `SECURITY` links convey metadata necessary to compute the API schema and securely resolve fields within it
- `EXECUTION` links convey metadata necessary to correctly resolve fields within the schema
-##! @id
+#! @id
-```graphql definition
-directive @id(url: String!) on SCHEMA
-```
+:::[definition](./link-v1.0.graphql#@id)
+
+Identify the current document by its URL. The URL is interpreted identically to [`@link`'s `url:` argument](#@link.as).
-Identify the current document by its URL. The URL is interpreted identically to [`@link`'s `url:` argument](#@link/as).
+{@id} [introduces an item](/core/v1.0#sec-Entry-added-by-@id) into the document's [Scope](#Scope).
-##! Import
+#! Import
```graphql definition
scalar Import
@@ -450,7 +130,7 @@ scalar Import
An element, possibly aliased, to import into the document.
-`Import` can take the form of a string:
+{Import} can take the form of a string:
```graphql example -- import a string name
@link(url: "https://specs.apollo.dev/link/v1.0", import: ["@link", "Purpose"])
@@ -482,15 +162,15 @@ Imports cannot currently reference transitive schemas:
Note: Future versions may support this.
-##! Purpose
+#! Purpose
-The role of a schema referenced with {@link}.
+The role of a {@link}ed schema.
This is not intended to be an exhaustive list of all the purposes a foreign schema or its metadata might serve. Rather, it is intended to capture cases where the default fail-open behavior of core schema consumers is undesirable.
Note we'll refer to directives from links which are `for: SECURITY` or `for: EXECUTION` as "`SECURITY` directives" and "`EXECUTION` directives", respectively.
-###! SECURITY
+##! SECURITY
`SECURITY` links provide metadata necessary to securely resolve fields. For instance, a hypothetical {auth} schema may provide an {@auth} directive to flag fields which require authorization. If a data core does not support the {auth} schemas and serves those fields anyway, these fields will be accessible without authorization, compromising security.
@@ -506,7 +186,7 @@ Less security-conscious consumers MAY choose to relax these requirements. For in
More security-conscious consumers MAY choose to enhance these requirements. For instance, production servers MAY adopt a policy of entirely rejecting any schema which contains ANY unsupported SECURITY links, even if those links are never used to annotate the schema.
-###! EXECUTION
+##! EXECUTION
`EXECUTION` schemas provide metadata necessary to correctly resolve fields. For instance, a hypothetical {ts} schemas may provide a `@ts__resolvers` annotation which references a TypeScript module of field resolvers. A consumer which does not support the {ts} schemas will be unable to correctly resolve such fields.
@@ -517,190 +197,3 @@ Consumers MUST NOT serve a field if:
- the field definition has **any** unsupported EXECUTION directives
Such fields are *unresolvable*. Consumers MAY attempt to serve schemas with unresolvable fields. Depending on the needs of the consumer, unresolvable fields MAY be removed from the schema prior to serving, or they MAY produce runtime errors if a query attempts to resolve them. Consumers MAY implement stricter policies, wholly refusing to serve schemas with unresolvable fields, or even refusing to serve schemas with any unsupported EXECUTION schemas, even if those schemas are never used in the schema.
-
-# Validations & Algorithms
-
-## Constructing the document's scope
-
-Visit every {@link} and {@id} within the document to construct the document's scope.
-
-Note: This algorithm **Report**s errors. Depending on their needs, implementations MAY decide to fail immediately in the face of these errors, or may elect to continue processing the document
-
-ConstructScope(document, baseScope) :
- 1. **Let** {scope} be {baseScope} if provided. Otherwise, it begins as an empty map of {Element} ==> {Binding}
- 2. **For** each schema definition or schema extension {schemaDef} in {document},
- 1. **For** each directive {dir} on {schemaDef},
- 1. **If** {Locate(scope, dir)} is the gref `https://specs.apollo.dev/link/v1.0#@link`...
- 2. ...or {LocateBound(scope, dir)} is {null} and {IsBootstrap(dir)} **Then**
- 1. **For each** ({element}, {binding}) **from** {BindingsFromLink(dir)}
- 1. **If** {binding} is implicit and {element} exists in {scope} and is explicit, **Then Continue**
- 2. **If** {binding} is implicit and {element} exists in {scope} and is implicit...
- 3. **Or If** {binding} is explicit and {element} exists in {scope} and is explicit **Then**
- 1. **Report** ❌ NameConflict
- 1. **Insert** {element} ==> {binding} **into** {scope}
- 2. **For** each schema definition or schema extension {schemaDef} in {document},
- 1. **For** each directive {dir} on {schemaDef},
- 1. **If** {Locate(scope, dir)} is the gref `https://specs.apollo.dev/link/v1.0#@id`...
- 1. **If** {directive} does not have a `url` argument or its `url` argument is an [invalid URL](#@link/url)
- 1. **Fail** ❌ BadId
- 2. **Let** {url} be the canonical form of {directive}'s `url`
- 1. **Insert** Schema() ==> Binding(gref: GRef({url}, Schema()), implicit: {false})
- 3. **Return** {scope}
-
-## Get all bindings from a @link directive
-
-Emit all scope bindings produced by a @link directive.
-
-Note: This algorithm is specified as a generator. This is deemed to produce the clearest psuedocode, but implementations may choose other approaches, such as collecting bindings into a list.
-
-BindingsFromLink(directive) :
- 1. **If** {directive} does not have a `url` argument or its `url` argument is an [invalid URL](#@link/url)
- 1. **Fail** ❌ BadLinkUrl
- 1. **Let** {url} be the canonical form of the {directive}'s `url` argument, with [all meaningless components stripped](#@link/url)
- 2. **If** {url} does not have a name...
- 2. ...and {directive} does not have an `as` argument...
- 3. ...and {directive} does not have an `import` argument or `import` is an empty list **Then**
- 1. **Fail** ❌ UselessLink
- 2. **If** {url} has a name, **Then**
- 1. **Let** {name} be the name extracted from {url}
- 2. **Let** {localName} be {directive}'s `as` argument if present and valid, otherwise {name}
- 2. **Emit** the schema binding (Schema({localName}), Binding(gref: GRef({url}, Schema()), implicit: {false}))
- 2. **Emit** the root directive binding (Directive({localName}), Binding(gref: GRef({url}, Directive({name})), implicit: {true}))
- 3. ...**Else**
- 2. **Let** {localName} be {directive}'s `as` argument if present and valid
- 2. **Emit** the schema binding (Schema({localName}), Binding(gref: GRef({url}, Schema()), implicit: {false}))
- 4. **For each** {import} **from** {directive}'s `import` argument:
- 1. **If** {import} is a string directive name starting with `@`,
- 0. **Let** {name} be the name of the directive specified by {import}
- 1. **Emit** (Directive({name}), Binding(gref: GRef({url}, Directive({name})), implicit: {false}))
- 2. **If** {import} is an object,
- 1. **If** {import} does not have a string-valued `name` field,
- 1. **Report** ❌ BadImport
- 2. **Continue**
- 1. **Let** {name} be the `name` field from {import}
- 2. **Let** {as} be the `as` field from {import}, if present, otherwise {name}
- 1. **If** {name} is a string directive name starting with `@`,
- 1. **If** {as} is not a directive name starting with `@`,
- 1. **Report** ❌ BadImportTypeMismatch
- 2. **Continue**
- 2. ...**Else Emit** (Directive({as}), Binding(gref: GRef({url}, Directive({name})), implicit: {false}))
- 2. ...**Else If** {name} is a valid GraphQL identifier,
- 1. **If** {as} is not a valid GraphQL identifier,
- 1. **Report** ❌ BadImportTypeMismatch
- 2. **Continue**
- 2. ...**Else Emit** (Type({as}), Binding(gref: GRef({url}, Type({name})), implicit: {false}))
-
-
-## Detecting a bootstrap directive
-
-Returns {true} if a directive is a [bootstrap](#sec-Bootstrapping). Otherwise, returns {false}.
-
-IsBootstrap(directive) :
- 1. **If** {directive} does not have a string-valued `url` argument, **Then Return** {false}
- 2. **Let** {url} be the canonical form of the {directive}'s `url` argument, with [all meaningless components stripped](#@link/url)
- 3. **If** {url} is `https://specs.apollo.dev/link/v1.0`,
- 1. **Let** {testScope} be an empty map of {Element} ==> {Binding}
- 2. **For each** ({element}, {binding}) **from** {BindingsFromLink(directive)}
- 1. **Insert** {element} ==> {binding} **into** {testScope}
- 3. **If** {Locate(testScope, directive)} is a binding with the gref `https://specs.apollo.dev/link/v1.0#@link`, **Then**
- 1. **Return** {true}
- 4. Otherwise, **Return** {false}
-
-## Locating definitions and references
-
-{Locate} a definition or reference within the document's scope, returning a global graph reference.
-
-{defOrRef} must be one of:
-- a definition node with a name
-- an extension node with a name
-- a directive
-
-Locate(scope, defOrRef) :
- 1. **If** {LocateBound(scope, defOrRef)} is not {null} **Then Return** {LocateBound(scope, defOrRef)}
- 3. **Let** {selfReference} be the element `Schema()`
- 3. **Let** {myself} be the URL of the schema returned from {Lookup(scope, selfReference)}, or {null} if none was found
- 1. Let {name} be the Name of {defOrRef}
- 4. **If** {defOrRef} is a Directive or DirectiveDefinition **Then**
- 1. **Return** GRef(myself, Directive({name}))
- 5. Otherwise, **Return** GRef(myself, Type({name}))
-
-{LocateBound(scope, defOrRef)} returns the binding for {defOrRef} if one is specified
-in {scope}, otherwise {null}. It does not resolve local names to the local document.
-
-LocateBound(scope, defOrRef) :
- 1. **Let** ({schema}, {element}) be the pair returned from {GetPath(defOrRef)}
- 2. **If** {schema} is not {null} and exists in {scope}, **Then**
- 1. Let {foundGraph} be the URL of the binding found by looking up {schema} in {scope}
- 2. **Return** GRef({foundGraph}, {element})
- 3. **If** {schema} is {null} and {element} exists in {scope}, **Then**
- 1. **Let** {foundElement} be the gref of the binding found by looking up {element} in {scope},
- 2. **Return** {foundElement}
- 4. Otherwise, **Return** {null}
-
-{GetPath(node)} [parses the name](#sec-Name-Conventions) of {node} and returns a (schema, element) pair.
-
-{node} must have a name.
-
-{schema} will be the {Schema} element parsed from the name, or {null} if {node}'s name does not have a prefix.
-{element} may be any type of {Element}.
-
-GetPath(node) :
- 1. **If** {node}'s Name contains the namespace separator {"__"}, **Then**
- 1. **Let** {prefix} be the part of {node}'s Name up to the first instance of the namespace separator {"__"}
- 2. **Let** {base} be the part of {node}'s Name after the first instance of the namespace separator {"__"}
- 2. ...**Else**,
- 1. **Let** {prefix} be {null}
- 2. **Let** {base} be Name
- 3. **If** {node} is a Directive or DirectiveDefinition, **Then**
- 1. **Return** (Schema({prefix}), Directive({base}))
- 4. ...**Else Return** (Schema({prefix}), Type({base}))
-
-
-# Appendix: Versioning
-
-VersionTag : "v" Version
-
-Version : Major "." Minor
-
-Major : NumericIdentifier
-
-Minor : NumericIdentifier
-
-NumericIdentifier : "0"
- | PositiveDigit Digit*
-
-Digit : "0" | PositiveDigit
-
-PositiveDigit : "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
-
-Specs are versioned with a **subset** of a [Semantic Version Number](https://semver.org/spec/v2.0.0.html) containing only the major and minor parts. Thus, specifications SHOULD provide a version of the form `v`{Major}`.`{Minor}, where both integers >= 0.
-
-```text example -- Valid version tags
-v2.2
-v1.0
-v1.1
-v0.1
-```
-
-As specified by semver, spec authors SHOULD increment the:
-
-{++
-
-- MAJOR version when you make incompatible API changes,
-- MINOR version when you add functionality in a backwards compatible manner
-
-++}
-
-Patch and pre-release qualifiers are judged to be not particularly meaningful in the context of GraphQL schemas, which are (by definition) interfaces rather than implementations. The patch component of a semver denotes a bug fix which is backwards compatible—that is, a change to the implementation which does not affect the interface. Patch-level changes in the version of a spec denote wording clarifications which do not require implementation changes. As such, it is not important to track them for the purposes of version resolution.
-
-As with [semver](https://semver.org/spec/v2.0.0.html), the `0.x` version series is special: there is no expectation of compatibility between versions `0.x` and `0.y`. For example, a processor must not activate implementation `0.4` to satisfy a requested version of `0.2`.
-
-## Satisfaction
-
-Given a version {requested} by a document and an {available} version of an implementation, the following algorithm will determine if the {available} version can satisfy the {requested} version:
-
-Satisfies(requested, available) :
- 1. If {requested}.{Major} ≠ {available}.{Major}, return {false}
- 2. If {requested}.{Major} = 0, return {requested}.{Minor} = {available}.{Minor}
- 3. Return {requested}.{Minor} <= {available}.{Minor}
-
diff --git a/link/v1.0/prefix-uniqueness.graphql b/link/v1.0/prefix-uniqueness.graphql
deleted file mode 100644
index e065e52..0000000
--- a/link/v1.0/prefix-uniqueness.graphql
+++ /dev/null
@@ -1,25 +0,0 @@
-schema
- @link(url: "https://specs.apollo.dev/core/v0.1")
- @link(url: "https://specs.example.com/A/1.0") # name is A
- @link(url: "https://specs.example.com/A/2.0", as: "A2") # name is A2
-{
- query: Query
-}
-
-schema
- @link(url: "https://specs.apollo.dev/core/v0.1")
- @link(url: "https://specs.example.com/A/1.0") # name is A
- @link(url: "https://specs.example.com/A/2.0") # name is A
-{
- query: Query
-}
-
-schema
- @link(url: "https://specs.apollo.dev/core/v0.1")
- @link(url: "https://specs.example.com/A/1.0") # name is A
- @link(url: "https://www.specs.com/specA/1.1", as: "A") # name is A
-{
- query: Query
-}
-
-directive @link(url: String!, as: String) repeatable on SCHEMA
diff --git a/tag/v0.1/index.html b/tag/v0.1/index.html
index a7ee498..2cdc1c8 100644
--- a/tag/v0.1/index.html
+++ b/tag/v0.1/index.html
@@ -1080,7 +1080,7 @@
The following example demonstrates how team ownership over types and fields can be declaratively expressed via inline metadata. One might imagine a CI workflow which analyzes a schema diff and uses @tag names to authorize or require approval for changes to parts of the graph.
A schema which implements the @tag spec MUST provide a definition which is compatible with the definition below:
-
directive@tag(name:String!)repeatableon
+
directive@tag(name: String!)repeatableon|FIELD_DEFINITION|INTERFACE|OBJECT
From cb16358645ccc7f11c4ff61c68c593216e110e90 Mon Sep 17 00:00:00 2001
From: Ashi Krishnan
Date: Tue, 26 Apr 2022 17:48:42 -0400
Subject: [PATCH 12/13] serve graphql schemas atop redirects
---
_redirects | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/_redirects b/_redirects
index a992c8e..f920c97 100644
--- a/_redirects
+++ b/_redirects
@@ -20,7 +20,7 @@
/core/ /core/v0.2/ 302!
# Federation 2.0 spec
-/federation/v2.0/* https://www.apollographql.com/docs/federation/federation-spec/:splat 302!
+/federation/v2.0/* https://www.apollographql.com/docs/federation/federation-spec/:splat 302
# This represents what's on "main" but acts as work in progress.
/core/draft/* https://apollo-specs-core.netlify.app/:splat 200!
From cd50674b4c982766f2e62ee0a00dc04fecf95f42 Mon Sep 17 00:00:00 2001
From: Ashi Krishnan
Date: Thu, 28 Apr 2022 17:12:10 -0400
Subject: [PATCH 13/13] specify link behavior in the face of invalid URLs
---
link/v1.0/link-v1.0.md | 46 +++++++++++++++++++++++++-----------------
1 file changed, 28 insertions(+), 18 deletions(-)
diff --git a/link/v1.0/link-v1.0.md b/link/v1.0/link-v1.0.md
index 9281c90..9009152 100644
--- a/link/v1.0/link-v1.0.md
+++ b/link/v1.0/link-v1.0.md
@@ -1,7 +1,7 @@
# link v1.0
```raw html
-
for linking core schemas together
+
for linking schemas together
Status
Draft
Version
1.0
@@ -10,17 +10,31 @@
```
-This schema defines [{@link}](#@link), the fundamental linking directive in [core schemas](/core/v1.0).
-
-See the [core schema spec](/core/v1.0) for more details on a document's [Scope](../core/v1.0#sec-Scope) and how {link} and {@id} interact with it.
+{@link} other schemas by their URL and [`import:`](#@link.import) definitions from them.
#! @link
:::[definition](./link-v1.0.graphql#@link)
-Link a foreign schema by its URL.
-
-{@link} [introduces one or more items](/core/v1.0#sec-Entries-added-by-@link) into the document's [Scope](#core/Scope).
+Link a foreign schema and optionally import definitions.
+
+```graphql example -- {@link} usage
+extend schema
+ @link(url: "https://example.com/otherSchema",
+ # @link infers a name from the URL 🖕🏽
+ # (use as: to set it explicitly)
+ import: ["SomeType", "@someDirective", {
+ name: "@someRenamedDirective",
+ as: "@renamed"
+ }])
+
+type Query
+ # 👇🏽 imported definitions are available by their name
+ @someDirective
+ @renamed
+ # 👇🏽 non-imported definitions are available with prefixes
+ @otherSchema__nonImportedDirective
+```
##! url: String!
@@ -32,7 +46,9 @@ Link URLs serve two main purposes:
Link URLs SHOULD be [RFC 3986 URLs](https://tools.ietf.org/html/rfc3986). When viewed, the URL SHOULD provide schema documentation in some human-readable form—a human reader should be able to click the link and go to the correct version of the docs. This is not an absolute functional requirement—as far as the core schema machinery is concerned, the URL is simply a globally unique namespace identifier with a particular form.
-Link URLs MAY contain information about the spec's [name](#Name-Conventions) and [version](#Versioning):
+If [`url:`](#@link.url) is not a valid [RFC 3986](https://tools.ietf.org/html/rfc3986) url, then it MUST be treated as an opaque identifier for the foreign schema. Such non-URL inputs to [`url:`](#@link.url) SHOULD NOT have [name](#Name-Conventions) and [version](#Versioning) information extracted from them—both are {null}.
+
+Link URLs which *are* [valid urls](https://tools.ietf.org/html/rfc3986) MAY contain information about the spec's [name](#Name-Conventions) and [version](#Versioning):
```html diagram -- Basic anatomy of a link URL
@@ -100,9 +116,11 @@ directive @link(url: String!, as: String) repeatable on SCHEMA
##! import: [Import]
-A list of names, possibly with aliases, to import from the foreign schema into the document.
+A list of elements, possibly with aliases, to import from the foreign schema into the document.
+
+Importing an element gives it a local, non-namespaced name.
-See the [Import](#Import) scalar for a description of the format.
+See the [Import](#Import) scalar for a description of the argument format.
##! for: Purpose
@@ -114,14 +132,6 @@ This behavior is different for {@link}s with a specified purpose:
- `SECURITY` links convey metadata necessary to compute the API schema and securely resolve fields within it
- `EXECUTION` links convey metadata necessary to correctly resolve fields within the schema
-#! @id
-
-:::[definition](./link-v1.0.graphql#@id)
-
-Identify the current document by its URL. The URL is interpreted identically to [`@link`'s `url:` argument](#@link.as).
-
-{@id} [introduces an item](/core/v1.0#sec-Entry-added-by-@id) into the document's [Scope](#Scope).
-
#! Import
```graphql definition