Skip to content

feat: add types #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npm run test:ci
npm run test
4 changes: 4 additions & 0 deletions .husky/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npm run test:ci
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ When the `close` event is triggered, the plugin will check if the [`AbortSignal`

Is guaranteed that one and just one `AbortController` and `AbortSignal` will be made per request.

If the request was not aborted during its lifetime, the plugin will remove the `AbortController` and `AbortSignal` from the cache. This by scheduling a callback on the hook `onResponse`.
If the request was not aborted during its lifetime, the plugin will remove the `AbortController` and `AbortSignal` from the cache. This by scheduling a hook-handler on the hook `onResponse`.

If the request aborted, the same hook will be used for cleaning resources.

A [`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) is used under the hood for caching, ensuring that the `AbortController` and `AbortSignal` instances can be unliked if not needed anymore, and for instance GC'ed.
A [`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) is used under the hood for caching, ensuring that the `AbortController` and `AbortSignal` instances can be unlinked if not needed anymore, and for instance GC'ed.

## Setup

Expand Down
33 changes: 33 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1,34 @@
/// <reference types="node" />
import { FastifyPluginCallback } from 'fastify'
import { FastifyError } from '@fastify/error'

export interface FastifyRacingSignal extends AbortSignal {
then: (
onFulfilled?: (value: AbortEvent) => void | PromiseLike<unknown>,
onRejected?: (reason: Error | FastifyError) => void | PromiseLike<unknown>
) => void | Promise<unknown>
}

export interface AbortEvent {
type: 'abort' | string
reason?: FastifyError | Error
}

export interface FastifyRacingOptions {
handleError?: boolean
onRequestClosed?: ((evt: AbortEvent) => void) | null
}

declare module 'fastify' {
interface FastifyRequest {
race(cb: FastifyRacingOptions['onRequestClosed']): void
race(opts: Omit<FastifyRacingOptions, 'onRequestClosed'>): FastifyRacingSignal
race(opts: Omit<FastifyRacingOptions, 'onRequestClosed'>): Promise<AbortEvent>
race(): FastifyRacingSignal
race(): Promise<AbortEvent>
}
}

declare const FastifyRacing: FastifyPluginCallback<FastifyRacingOptions>

export default FastifyRacing
243 changes: 220 additions & 23 deletions test/index.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,223 @@
/// <reference types="node" />
import { FastifyPluginCallback } from 'fastify';
import { FastifyError } from '@fastify/error';


interface AbortEvent {
type: 'abort' | string;
reason?: FastifyError | Error
}

interface FastifyRacing {
handleError?: boolean;
onRequestClosed?: (evt: AbortEvent) => void;
}

declare module 'fastify' {
interface FastifyInstance {
race(cb: FastifyRacing['onRequestClosed']): void
race(opts: Omit<FastifyRacing, 'onRequestClosed'>): Promise<AbortEvent>
race(): Promise<AbortEvent>
import { expectType } from 'tsd'

import fastify from 'fastify'
import plugin, { AbortEvent, FastifyRacingSignal } from '..'

const serverHttp = fastify()

serverHttp.register(plugin)

serverHttp.register(plugin, {
handleError: true,
onRequestClosed: null
})

serverHttp.get(
'/',
{
preHandler: async (request, _reply) => {
const signal = request.race()
const signal2 = request.race({
handleError: true
})
const event = await request.race()
const event2 = await request.race({
handleError: true
})

const asVoid = request.race(evt => {
expectType<AbortEvent>(evt)
})

expectType<void>(asVoid)
expectType<FastifyRacingSignal>(signal)
expectType<AbortEvent>(event)
expectType<FastifyRacingSignal>(signal2)
expectType<AbortEvent>(event2)
}
},
async (request, reply) => {
const signal = request.race()
const signal2 = request.race({
handleError: true
})
const event = await request.race()
const event2 = await request.race({
handleError: true
})

const asVoid = request.race(evt => {
expectType<AbortEvent>(evt)
})

expectType<void>(asVoid)
expectType<FastifyRacingSignal>(signal)
expectType<AbortEvent>(event)
expectType<FastifyRacingSignal>(signal2)
expectType<AbortEvent>(event2)
}
)

// -> Second level
serverHttp.register(
function (fastifyInstance, opts, done) {
fastifyInstance.register(plugin)

fastifyInstance.get(
'/',
{
preHandler: async (request, _reply) => {
const signal = request.race()
const signal2 = request.race({
handleError: true
})
const event = await request.race()
const event2 = await request.race({
handleError: true
})
const asVoid = request.race(evt => {
expectType<AbortEvent>(evt)
})

expectType<void>(asVoid)
expectType<FastifyRacingSignal>(signal)
expectType<AbortEvent>(event)
expectType<FastifyRacingSignal>(signal2)
expectType<AbortEvent>(event2)
}
},
async (request, reply) => {
const signal = request.race()
const signal2 = request.race({
handleError: true
})
const event = await request.race()
const event2 = await request.race({
handleError: true
})

const asVoid = request.race(evt => {
expectType<AbortEvent>(evt)
})

expectType<void>(asVoid)
expectType<FastifyRacingSignal>(signal)
expectType<AbortEvent>(event)
expectType<FastifyRacingSignal>(signal2)
expectType<AbortEvent>(event2)
}
)

done()
},
{ prefix: '/api' }
)

const serverHttp2 = fastify({ http2: true })

serverHttp2.register(plugin, {
handleError: true,
onRequestClosed: null
})

serverHttp2.get(
'/',
{
preHandler: async (request, _reply) => {
const signal = request.race()
const signal2 = request.race({
handleError: true
})
const event = await request.race()
const event2 = await request.race({
handleError: true
})

const asVoid = request.race(evt => {
expectType<AbortEvent>(evt)
})

expectType<void>(asVoid)
expectType<FastifyRacingSignal>(signal)
expectType<AbortEvent>(event)
expectType<FastifyRacingSignal>(signal2)
expectType<AbortEvent>(event2)
}
},
async (request, reply) => {
const signal = request.race()
const signal2 = request.race({
handleError: true
})
const event = await request.race()
const event2 = await request.race({
handleError: true
})

const asVoid = request.race(evt => {
expectType<AbortEvent>(evt)
})

expectType<void>(asVoid)
expectType<FastifyRacingSignal>(signal)
expectType<AbortEvent>(event)
expectType<FastifyRacingSignal>(signal2)
expectType<AbortEvent>(event2)
}
}
)

// -> First plugin
serverHttp2.register(
function (fastifyInstance, opts, done) {
fastifyInstance.register(plugin)

fastifyInstance.get(
'/',
{
preHandler: async (request, _reply) => {
const signal = request.race()
const signal2 = request.race({
handleError: true
})
const event = await request.race()
const event2 = await request.race({
handleError: true
})

const asVoid = request.race(evt => {
expectType<AbortEvent>(evt)
})

expectType<void>(asVoid)
expectType<FastifyRacingSignal>(signal)
expectType<AbortEvent>(event)
expectType<FastifyRacingSignal>(signal2)
expectType<AbortEvent>(event2)
}
},
async (request, reply) => {
const signal = request.race()
const signal2 = request.race({
handleError: true
})
const event = await request.race()
const event2 = await request.race({
handleError: true
})

const asVoid = request.race(evt => {
expectType<AbortEvent>(evt)
})

declare const FastifyRacing: FastifyPluginCallback<FastifyRacing>;
expectType<void>(asVoid)
expectType<FastifyRacingSignal>(signal)
expectType<AbortEvent>(event)
expectType<FastifyRacingSignal>(signal2)
expectType<AbortEvent>(event2)
}
)

export default FastifyRacing;
done()
},
{ prefix: '/api' }
)