import Ajv, { ErrorObject as AjvErrorObject } from 'ajv' import * as http from 'node:http' import * as http2 from 'node:http2' import * as https from 'node:https' import { Socket } from 'node:net' import { expectAssignable, expectError, expectNotAssignable, expectType } from 'tsd' import fastify, { ConnectionError, FastifyBaseLogger, FastifyError, FastifyErrorCodes, FastifyInstance, FastifyPlugin, FastifyPluginAsync, FastifyPluginCallback, InjectOptions, LightMyRequestCallback, LightMyRequestChain, LightMyRequestResponse, RawRequestDefaultExpression, RouteGenericInterface, SafePromiseLike } from '../../fastify' import { Bindings, ChildLoggerOptions } from '../../types/logger' // FastifyInstance // http server expectError< FastifyInstance & Promise> >(fastify()) expectAssignable< FastifyInstance & PromiseLike> >(fastify()) expectType< FastifyInstance & SafePromiseLike> >(fastify()) expectType< FastifyInstance & SafePromiseLike> >(fastify({})) expectType< FastifyInstance & SafePromiseLike> >(fastify({ http: {} })) // https server expectType< FastifyInstance & SafePromiseLike> >(fastify({ https: {} })) expectType< FastifyInstance & SafePromiseLike> >(fastify({ https: null })) // http2 server expectType< FastifyInstance & SafePromiseLike> >(fastify({ http2: true, http2SessionTimeout: 1000 })) expectType< FastifyInstance & SafePromiseLike> >(fastify({ http2: true, https: {}, http2SessionTimeout: 1000 })) expectType(fastify({ http2: true, https: {} }).inject()) expectType< FastifyInstance & SafePromiseLike> >(fastify({ schemaController: {} })) expectType< FastifyInstance & SafePromiseLike> >( fastify({ schemaController: { compilersFactory: {} } }) ) expectError(fastify({ http2: false })) // http2 option must be true expectError(fastify({ http2: false })) // http2 option must be true expectError( fastify({ schemaController: { bucket: () => ({}) // cannot be empty } }) ) // light-my-request expectAssignable({ query: '' }) fastify({ http2: true, https: {} }).inject().then((resp) => { expectAssignable(resp) }) const lightMyRequestCallback: LightMyRequestCallback = ( err: Error | undefined, response: LightMyRequestResponse | undefined ) => { if (err) throw err } fastify({ http2: true, https: {} }).inject({}, lightMyRequestCallback) // server options expectAssignable< FastifyInstance >(fastify({ http2: true })) expectAssignable(fastify({ ignoreTrailingSlash: true })) expectAssignable(fastify({ ignoreDuplicateSlashes: true })) expectAssignable(fastify({ connectionTimeout: 1000 })) expectAssignable(fastify({ forceCloseConnections: true })) expectAssignable(fastify({ keepAliveTimeout: 1000 })) expectAssignable(fastify({ pluginTimeout: 1000 })) expectAssignable(fastify({ bodyLimit: 100 })) expectAssignable(fastify({ handlerTimeout: 5000 })) expectAssignable(fastify({ maxParamLength: 100 })) expectAssignable(fastify({ disableRequestLogging: true })) expectAssignable(fastify({ disableRequestLogging: (req) => req.url?.includes('/health') ?? false })) expectAssignable(fastify({ requestIdLogLabel: 'request-id' })) expectAssignable(fastify({ onProtoPoisoning: 'error' })) expectAssignable(fastify({ onConstructorPoisoning: 'error' })) expectAssignable(fastify({ serializerOpts: { rounding: 'ceil' } })) expectAssignable( fastify({ serializerOpts: { ajv: { missingRefs: 'ignore' } } }) ) expectAssignable(fastify({ serializerOpts: { schema: {} } })) expectAssignable(fastify({ serializerOpts: { otherProp: {} } })) expectAssignable< FastifyInstance >(fastify({ logger: true })) expectAssignable< FastifyInstance >(fastify({ logger: true })) expectAssignable>(fastify({ logger: { level: 'info', genReqId: () => 'request-id', serializers: { req: () => { return { method: 'GET', url: '/', version: '1.0.0', host: 'localhost', remoteAddress: '127.0.0.1', remotePort: 3000 } }, res: () => { return { statusCode: 200 } }, err: () => { return { type: 'Error', message: 'foo', stack: '' } } } } })) const customLogger = { level: 'info', info: () => { }, warn: () => { }, error: () => { }, fatal: () => { }, trace: () => { }, debug: () => { }, child: () => customLogger } expectAssignable< FastifyInstance >(fastify({ logger: customLogger })) expectAssignable(fastify({ serverFactory: () => http.createServer() })) expectAssignable(fastify({ caseSensitive: true })) expectAssignable(fastify({ requestIdHeader: 'request-id' })) expectAssignable(fastify({ requestIdHeader: false })) expectAssignable(fastify({ genReqId: (req) => { expectType(req) return 'foo' } })) expectAssignable(fastify({ trustProxy: true })) expectAssignable(fastify({ querystringParser: () => ({ foo: 'bar' }) })) expectAssignable(fastify({ querystringParser: () => ({ foo: { bar: 'fuzz' } }) })) expectAssignable(fastify({ querystringParser: () => ({ foo: ['bar', 'fuzz'] }) })) expectAssignable(fastify({ constraints: {} })) expectAssignable(fastify({ constraints: { version: { name: 'version', storage: () => ({ get: () => () => { }, set: () => { }, del: () => { }, empty: () => { } }), validate () { }, deriveConstraint: () => 'foo' }, host: { name: 'host', storage: () => ({ get: () => () => { }, set: () => { }, del: () => { }, empty: () => { } }), validate () { }, deriveConstraint: () => 'foo' }, withObjectValue: { name: 'withObjectValue', storage: () => ({ get: () => () => { }, set: () => { }, del: () => { }, empty: () => { } }), validate () { }, deriveConstraint: () => { } } } })) expectAssignable(fastify({ return503OnClosing: true })) expectAssignable(fastify({ ajv: { customOptions: { removeAdditional: 'all' }, plugins: [(ajv: Ajv): Ajv => ajv] } })) expectAssignable(fastify({ ajv: { plugins: [[(ajv: Ajv): Ajv => ajv, ['keyword1', 'keyword2']]] } })) expectError(fastify({ ajv: { customOptions: { removeAdditional: 'all' }, plugins: [ () => { // error, plugins always return the Ajv instance fluently } ] } })) expectAssignable(fastify({ ajv: { onCreate: (ajvInstance) => { expectType(ajvInstance) return ajvInstance } } })) expectAssignable(fastify({ frameworkErrors: () => { } })) expectAssignable(fastify({ rewriteUrl: function (req) { this.log.debug('rewrite url') return req.url === '/hi' ? '/hello' : req.url! } })) expectAssignable(fastify({ schemaErrorFormatter: (errors, dataVar) => { console.log( errors[0].keyword.toLowerCase(), errors[0].message?.toLowerCase(), errors[0].params, errors[0].instancePath.toLowerCase(), errors[0].schemaPath.toLowerCase() ) return new Error() } })) expectAssignable(fastify({ clientErrorHandler: (err, socket) => { expectType(err) expectType(socket) } })) expectAssignable(fastify({ childLoggerFactory: function ( this: FastifyInstance, logger: FastifyBaseLogger, bindings: Bindings, opts: ChildLoggerOptions, req: RawRequestDefaultExpression ) { expectType(logger) expectType(bindings) expectType(opts) expectType(req) expectAssignable(this) return logger.child(bindings, opts) } })) // Thenable expectAssignable>(fastify({ return503OnClosing: true })) fastify().then(fastifyInstance => expectAssignable(fastifyInstance)) expectAssignable(async () => { }) expectAssignable(() => { }) expectAssignable(() => { }) const ajvErrorObject: AjvErrorObject = { keyword: '', instancePath: '', schemaPath: '', params: {}, message: '' } expectNotAssignable({ keyword: '', instancePath: '', schemaPath: '', params: '', message: '' }) expectAssignable([ajvErrorObject]) expectAssignable('body') expectAssignable('headers') expectAssignable('params') expectAssignable('querystring') const routeGeneric: RouteGenericInterface = {} expectType(routeGeneric.Body) expectType(routeGeneric.Headers) expectType(routeGeneric.Params) expectType(routeGeneric.Querystring) expectType(routeGeneric.Reply) // ErrorCodes expectType(fastify.errorCodes) fastify({ allowUnsafeRegex: true }) fastify({ allowUnsafeRegex: false }) expectError(fastify({ allowUnsafeRegex: 'invalid' })) expectAssignable(fastify({ allowErrorHandlerOverride: true })) expectAssignable(fastify({ allowErrorHandlerOverride: false }))