Skip to content

Commit

Permalink
chore: add typescript declarations
Browse files Browse the repository at this point in the history
  • Loading branch information
HW13 committed Feb 7, 2024
1 parent 7d7b8e7 commit 9698436
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 9 deletions.
12 changes: 11 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,15 @@
"node": {
"version": "^20.x"
}
}
},
"overrides": [{
"files": ["*.ts"],
"extends": [
"@autotelic/eslint-config-js",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"]
}]
}
4 changes: 4 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

node_modules/.bin/lint-staged
48 changes: 48 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { FastifyPluginAsync, FastifyReply } from 'fastify'

declare namespace fastifyQueue {
export type QueueInitializer<ValueType = unknown, ReturnType = unknown, KeyType = PropertyKey> = (
key: KeyType,
value: ValueType,
reply: FastifyReply
) => ReturnType | PromiseLike<ReturnType>

export type QueueResolver<ValueType = unknown, ReturnType = unknown, KeyType = PropertyKey> = (
key: KeyType,
value: ValueType,
reply: FastifyReply
) => ReturnType | PromiseLike<ReturnType>

export type OnQueueResolved<ValueType = unknown, KeyType = PropertyKey> = (
resolvedQueue: Map<KeyType, ValueType>,
reply: FastifyReply
) => void | Promise<void>

export type QueueInstance <InputType = unknown, KeyType = PropertyKey> = {
add(key: KeyType, value: InputType): void
resolve(cb?: OnQueueResolved): Promise<void>
get contents(): Map<KeyType, PromiseLike<InputType>>
}

export type QueuePluginOptions = {
initializer?: QueueInitializer
resolver?: QueueResolver
onResolved?: OnQueueResolved
onError?(e: unknown): void
queueName?: string
concurrency?: number
stopOnError?: boolean
}

const fastifyQueue: FastifyPluginAsync<QueuePluginOptions>

export { fastifyQueue as default }
}

declare module 'fastify' {
interface FastifyReply {
queue: fastifyQueue.QueueInstance
}
}

export = fastifyQueue
20 changes: 15 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "0.1.2",
"description": "an async queue for fastify",
"type": "module",
"types": "index.d.ts",
"keywords": [
"fastify",
"plugin",
Expand All @@ -11,29 +12,38 @@
"bugs": {
"url": "https://github.com/autotelic/fastify-queue/issues"
},
"files": [],
"files": [
"index.d.ts"
],
"homepage": "https://github.com/autotelic/fastify-queue#readme",
"license": "MIT",
"main": "index.js",
"scripts": {
"fix": "npm run lint -- --fix",
"lint": "eslint .",
"test": "tap --show-full-coverage",
"validate": "npm run lint && npm run test"
"test": "tap ./test/*.test.js --show-full-coverage",
"tsd": "tsd --files ./test/index.test-d.ts",
"validate": "npm run lint && npm run test && npm run tsd",
"prepare": "husky || true"
},
"devDependencies": {
"@autotelic/eslint-config-js": "^0.3.0",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"eslint": "^8.56.0",
"fastify": "^4.26.0",
"husky": "^9.0.10",
"lint-staged": "^15.2.2",
"tap": "^18.7.0"
"tap": "^18.7.0",
"tsd": "^0.30.4",
"typescript": "^5.3.3"
},
"dependencies": {
"fastify-plugin": "^4.5.1",
"p-props": "^6.0.0"
},
"lint-staged": {
"*.{js}": [
"*.{js,ts}": [
"npm run fix"
]
}
Expand Down
103 changes: 103 additions & 0 deletions test/index.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import fastify, { FastifyReply } from 'fastify'
// eslint-disable-next-line import/no-unresolved
import { expectAssignable, expectType } from 'tsd'

import type {
OnQueueResolved,
QueueInitializer,
QueueInstance,
QueuePluginOptions,
QueueResolver
} from '..'

fastify().get('/', async (req, reply) => {
expectType<QueueInstance>(reply.queue)

const getBar = async () => 'bar'
expectAssignable<void>(reply.queue.add('foo', getBar()))

expectType<Map<PropertyKey, PromiseLike<unknown>>>(reply.queue.contents)

expectAssignable<void>(
await reply.queue.resolve()
)

expectAssignable<void>(
await reply.queue.resolve(
(resolved, reply) => {
expectAssignable<Map<PropertyKey, unknown>>(resolved)
expectAssignable<FastifyReply>(reply)
}
)
)
})

expectType(<QueuePluginOptions>({}))

expectType(<QueuePluginOptions>({
initializer: (key, value, reply) => {
expectAssignable<PropertyKey>(key)
expectAssignable<unknown>(value)
expectAssignable<FastifyReply>(reply)
},
resolver: (key, value, reply) => {
expectAssignable<PropertyKey>(key)
expectAssignable<unknown>(value)
expectAssignable<FastifyReply>(reply)
},
onResolved: (resolved, reply) => {
expectAssignable<Map<PropertyKey, unknown>>(resolved)
expectAssignable<FastifyReply>(reply)
},
onError: (e) => e,
queueName: 'myQueue',
concurrency: 9,
stopOnError: true
}))

expectType(<QueuePluginOptions>({
initializer: async (key, value, reply) => {
expectAssignable<PropertyKey>(key)
expectAssignable<unknown>(value)
expectAssignable<FastifyReply>(reply)
},
resolver: async (key, value, reply) => {
expectAssignable<PropertyKey>(key)
expectAssignable<unknown>(value)
expectAssignable<FastifyReply>(reply)
},
onResolved: async (resolved, reply) => {
expectAssignable<Map<PropertyKey, unknown>>(resolved)
expectAssignable<FastifyReply>(reply)
}
}))

type KeyType = string
type ValueType = string[]
type ReturnType = Promise<Record<string, string>>

const initializer: QueueInitializer<ValueType, ReturnType, KeyType> = async (key, value, reply) => {
expectAssignable<KeyType>(key)
expectAssignable<ValueType>(value)
expectAssignable<FastifyReply>(reply)
return { foo: 'bar' }
}

const resolver: QueueResolver<ValueType, ReturnType, KeyType> = async (key, value, reply) => {
expectAssignable<KeyType>(key)
expectAssignable<ValueType>(value)
expectAssignable<FastifyReply>(reply)
return { bar: 'baz' }
}

const onResolved: OnQueueResolved<ValueType, KeyType> = async (resolved, reply) => {
expectAssignable<Map<KeyType, ValueType>>(resolved)
expectAssignable<FastifyReply>(reply)
}

expectType(<QueuePluginOptions>({
initializer,
resolver,
onResolved
}))
12 changes: 9 additions & 3 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,18 @@ test('error handling', async ({ equal, same }) => {
test('manually resolving queue', async ({ equal, same }) => {
const routeHandler = async (req, reply) => {
same(reply.queue.contents, new Map())
reply.queue.add('foo', 'bar')
same(reply.queue.contents, new Map([['foo', 'bar']]))
const bar = new Promise((resolve) => resolve('bar'))
reply.queue.add('foo', bar)
same(reply.queue.contents, new Map([['foo', bar]]))
await reply.queue.resolve()
return {}
}

let onResolvedCalls = 0
const onResolved = () => {
let resolvedQueue

const onResolved = (queue) => {
resolvedQueue = queue
onResolvedCalls++
}
const app = buildApp(routeHandler, { onResolved })
Expand All @@ -123,6 +128,7 @@ test('manually resolving queue', async ({ equal, same }) => {
// payloads to accumulate.
await asyncTimeout(60)
equal(onResolvedCalls, 1, 'onResponse hook should not call resolve if queue has already resolved.')
same(resolvedQueue, new Map([['foo', 'bar']]))
})

test('skipped onRequest hook', async ({ equal, same }) => {
Expand Down

0 comments on commit 9698436

Please sign in to comment.