Skip to content

Commit

Permalink
feat(extension-system): inject builders (#1298)
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonkuhrt authored Dec 28, 2024
1 parent 0787747 commit 9870f55
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 75 deletions.
8 changes: 6 additions & 2 deletions src/extension/TypeHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down
8 changes: 2 additions & 6 deletions src/extension/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
17 changes: 10 additions & 7 deletions src/extension/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
71 changes: 33 additions & 38 deletions src/extensions/Introspection/Introspection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<IntrospectionQuery>(),
builder: (builder) =>
builder<BuilderExtension>(({ path, property, client }) => {
if (!(path.length === 0 && property === `introspect`)) return
const clientCatching = client.with({ output: { envelope: false, errors: { execution: `return` } } })
typeHooks: typeHooks.requestResultDataTypes<IntrospectionQuery>(),
builder: builder<BuilderExtension>(({ 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()
}
}),
}
},
})
Expand Down
9 changes: 4 additions & 5 deletions src/extensions/SchemaErrors/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ export interface SchemaErrors extends Extension {

export const SchemaErrors: () => SchemaErrors = Extension.create({
name: `SchemaErrors`,
create() {
create({ typeHooks }) {
return {
typeHooks: typeHooks
.onRequestDocumentRootType<OnRequestDocumentRootType_>()
.onRequestResult<OnRequestResult_>(),
async onRequest({ pack }) {
const state = pack.input.state
const sddm = state.schemaMap
Expand Down Expand Up @@ -82,10 +85,6 @@ export const SchemaErrors: () => SchemaErrors = Extension.create({

return result
},
typeHooks: ($) =>
$
.onRequestDocumentRootType<OnRequestDocumentRootType_>()
.onRequestResult<OnRequestResult_>(),
}
},
})
Expand Down
33 changes: 16 additions & 17 deletions src/extensions/Throws/Throws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<BuilderExtension>(({ client, property, path }) => {
if (property !== `throws` || path.length !== 0) return undefined
builder: builder<BuilderExtension>(({ 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)
}),
}
},
})
Expand Down

0 comments on commit 9870f55

Please sign in to comment.