Skip to content

Commit

Permalink
feat: add types (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
metcoder95 authored May 17, 2022
1 parent a093f8a commit 035c117
Show file tree
Hide file tree
Showing 5 changed files with 260 additions and 26 deletions.
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' }
)

0 comments on commit 035c117

Please # to comment.