diff --git a/src/extension/TypeHooks.ts b/src/extension/TypeHooks.ts index 174b38157..5560f6f4e 100644 --- a/src/extension/TypeHooks.ts +++ b/src/extension/TypeHooks.ts @@ -47,8 +47,12 @@ export namespace States { export type Empty = TypeHooksEmpty } -export interface TypeHooksBuilderCallback<$TypeHooks extends TypeHooks> { - (builder: TypeHooksBuilder): TypeHooksBuilder<$TypeHooks> +// todo: type-level only, so can be a proxy that allows anything. +export const typeHooksBuilder: TypeHooksBuilder = { + requestResultDataTypes: () => typeHooksBuilder as any, + onRequestResult: () => typeHooksBuilder as any, + onRequestDocumentRootType: () => typeHooksBuilder as any, + type: null as any, } export interface TypeHooksBuilder<$TypeHooks extends TypeHooks = TypeHooksEmpty> { diff --git a/src/extension/builder.ts b/src/extension/builder.ts index 954d086b9..da96680de 100644 --- a/src/extension/builder.ts +++ b/src/extension/builder.ts @@ -8,16 +8,12 @@ export type BuilderExtension< & { type: $BuilderExtension } export namespace BuilderExtension { - export interface Creator { + export interface Create { <$BuilderExtension extends ExtensionChainable>( interceptor: Interceptor, ): BuilderExtension<$BuilderExtension> } - export const create: Creator = identity as any - - export interface CreatorCallback<$BuilderExtension extends BuilderExtension | undefined> { - (creator: Creator): $BuilderExtension - } + export const create: Create = identity as any export type Interceptor = ( input: { diff --git a/src/extension/extension.ts b/src/extension/extension.ts index 89ea26095..d72406d3c 100644 --- a/src/extension/extension.ts +++ b/src/extension/extension.ts @@ -8,8 +8,7 @@ import type { RequestPipelineBaseInterceptor } from '../requestPipeline/RequestP import type { Transport } from '../types/Transport.js' import type { Extension } from './__.js' import { BuilderExtension } from './builder.js' -import type { TypeHooks, TypeHooksEmpty } from './TypeHooks.js' -import type { TypeHooksBuilderCallback } from './TypeHooks.js' +import { type TypeHooks, type TypeHooksBuilder, typeHooksBuilder, type TypeHooksEmpty } from './TypeHooks.js' export * from './context.js' export * as TypeHooks from './TypeHooks.js' @@ -50,10 +49,10 @@ export const create = < name: $Name normalizeConfig?: (...args: $ConfigInputParameters) => $Config custom?: $Custom - create: (params: { config: $Config }) => { - builder?: BuilderExtension.CreatorCallback<$BuilderExtension> // | $BuilderExtension // todo + create: (parameters: { config: $Config; builder: BuilderExtension.Create; typeHooks: TypeHooksBuilder }) => { + builder?: $BuilderExtension + typeHooks?: TypeHooksBuilder<$TypeHooks> onRequest?: RequestPipelineBaseInterceptor - typeHooks?: TypeHooksBuilderCallback<$TypeHooks> | $TypeHooks transport?: ( OverloadBuilder: Transport.Builder.Create, ) => $TransportCallbackResult @@ -81,8 +80,12 @@ export const create = < > => { const extensionConstructor = (input?: object) => { const config: $Config = ((definitionInput.normalizeConfig as any)?.(input) ?? {}) as any // eslint-disable-line - const extensionBuilder = definitionInput.create({ config }) - const builder = extensionBuilder.builder?.(BuilderExtension.create) + const extensionBuilder = definitionInput.create({ + config, + builder: BuilderExtension.create, + typeHooks: typeHooksBuilder, + }) + const builder = extensionBuilder.builder const overload = extensionBuilder.transport?.((name) => Anyware.Overload.create({ discriminant: [`transportType`, name] }) )?.type diff --git a/src/extensions/Introspection/Introspection.ts b/src/extensions/Introspection/Introspection.ts index d01b21c1b..4f0b38793 100644 --- a/src/extensions/Introspection/Introspection.ts +++ b/src/extensions/Introspection/Introspection.ts @@ -27,49 +27,44 @@ export const Introspection = create({ const config = createConfig(input) return config }, - // todo consider this API: - // create: ({ config, typeHooks }) => { - // return { - // typeHooks: typeHooks<{ ... }>, - create: ({ config }) => { + create: ({ config, builder, typeHooks }) => { return { - typeHooks: $ => $.requestResultDataTypes(), - builder: (builder) => - builder(({ path, property, client }) => { - if (!(path.length === 0 && property === `introspect`)) return - const clientCatching = client.with({ output: { envelope: false, errors: { execution: `return` } } }) + typeHooks: typeHooks.requestResultDataTypes(), + builder: builder(({ path, property, client }) => { + if (!(path.length === 0 && property === `introspect`)) return + const clientCatching = client.with({ output: { envelope: false, errors: { execution: `return` } } }) - return async () => { - let introspectionQueryDocument = getIntrospectionQuery(config.options) - // @ts-expect-error fixme - const result = await clientCatching.gql(introspectionQueryDocument).send() - const featuresDropped: string[] = [] - const enabledKnownPotentiallyUnsupportedFeatures = knownPotentiallyUnsupportedFeatures.filter(_ => - config.options[_] !== false - ) + return async () => { + let introspectionQueryDocument = getIntrospectionQuery(config.options) + // @ts-expect-error fixme + const result = await clientCatching.gql(introspectionQueryDocument).send() + const featuresDropped: string[] = [] + const enabledKnownPotentiallyUnsupportedFeatures = knownPotentiallyUnsupportedFeatures.filter(_ => + config.options[_] !== false + ) - // Try to find a working introspection query. - if (result instanceof Error) { - for (const feature of enabledKnownPotentiallyUnsupportedFeatures) { - featuresDropped.push(feature) - introspectionQueryDocument = getIntrospectionQuery({ - ...config.options, - [feature]: false, - }) - // @ts-expect-error fixme - const result = await clientCatching.gql(introspectionQueryDocument).send() - if (!(result instanceof Error)) break - } + // Try to find a working introspection query. + if (result instanceof Error) { + for (const feature of enabledKnownPotentiallyUnsupportedFeatures) { + featuresDropped.push(feature) + introspectionQueryDocument = getIntrospectionQuery({ + ...config.options, + [feature]: false, + }) + // @ts-expect-error fixme + const result = await clientCatching.gql(introspectionQueryDocument).send() + if (!(result instanceof Error)) break } - - // Send the query again with the host configuration for output. - // TODO rather than having to make this query again expose a way to send a value through the output handler here. - // TODO expose the featuresDropped info on the envelope so that upstream can communicate to users what happened - // finally at runtime. - // @ts-expect-error fixme - return await client.gql(introspectionQueryDocument).send() } - }), + + // Send the query again with the host configuration for output. + // TODO rather than having to make this query again expose a way to send a value through the output handler here. + // TODO expose the featuresDropped info on the envelope so that upstream can communicate to users what happened + // finally at runtime. + // @ts-expect-error fixme + return await client.gql(introspectionQueryDocument).send() + } + }), } }, }) diff --git a/src/extensions/SchemaErrors/runtime.ts b/src/extensions/SchemaErrors/runtime.ts index aa9f54165..018570958 100644 --- a/src/extensions/SchemaErrors/runtime.ts +++ b/src/extensions/SchemaErrors/runtime.ts @@ -23,8 +23,11 @@ export interface SchemaErrors extends Extension { export const SchemaErrors: () => SchemaErrors = Extension.create({ name: `SchemaErrors`, - create() { + create({ typeHooks }) { return { + typeHooks: typeHooks + .onRequestDocumentRootType() + .onRequestResult(), async onRequest({ pack }) { const state = pack.input.state const sddm = state.schemaMap @@ -82,10 +85,6 @@ export const SchemaErrors: () => SchemaErrors = Extension.create({ return result }, - typeHooks: ($) => - $ - .onRequestDocumentRootType() - .onRequestResult(), } }, }) diff --git a/src/extensions/Throws/Throws.ts b/src/extensions/Throws/Throws.ts index d03ccdc23..7294d0844 100644 --- a/src/extensions/Throws/Throws.ts +++ b/src/extensions/Throws/Throws.ts @@ -5,27 +5,26 @@ import type { ConfigManager } from '../../lib/config-manager/__.js' export const Throws = create({ name: `Throws`, - create: () => { + create: ({ builder }) => { return { - builder: (create) => - create(({ client, property, path }) => { - if (property !== `throws` || path.length !== 0) return undefined + builder: builder(({ client, property, path }) => { + if (property !== `throws` || path.length !== 0) return undefined - // todo redesign input to allow to force throw always - // todo pull pre-configured config from core - const throwsifiedInput: ConfigInit = { - output: { - envelope: { - enabled: client._.output.envelope.enabled, - // @ts-expect-error - errors: { execution: false, other: false, schema: false }, - }, + // todo redesign input to allow to force throw always + // todo pull pre-configured config from core + const throwsifiedInput: ConfigInit = { + output: { + envelope: { + enabled: client._.output.envelope.enabled, // @ts-expect-error - errors: { execution: `throw`, other: `throw`, schema: `throw` }, + errors: { execution: false, other: false, schema: false }, }, - } - return () => client.with(throwsifiedInput) - }), + // @ts-expect-error + errors: { execution: `throw`, other: `throw`, schema: `throw` }, + }, + } + return () => client.with(throwsifiedInput) + }), } }, })