Skip to content

Commit

Permalink
[ts] update debounce hook
Browse files Browse the repository at this point in the history
  • Loading branch information
mrhyde committed Dec 22, 2024
1 parent f2b7de9 commit 7e7c966
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 53 deletions.
84 changes: 43 additions & 41 deletions packages/ryanair/source/client/hooks/debounce.ts
Original file line number Diff line number Diff line change
@@ -1,58 +1,60 @@
/* eslint-disable @stylistic/indent */
import type { BeforeRequestHook, ExtendOptions, InitHook, Options, OptionsInit } from 'got'
import type { BeforeRequestHook, ExtendOptions, Options } from 'got'
import { randomInt } from 'node:crypto'
import { setTimeout } from 'node:timers/promises'

const crypto = await import('node:crypto')

export type Debounce = {
debounce?:
| {
queue: Promise<void>
duration: [number, number] | number
}
| undefined
export type DebounceOptions = {
/**
* Time to wait between requests in milliseconds
* Can be a fixed number or a range [min, max] for random delays
*/
duration: number | [number, number]
}

export type OptionsWithDebounce = {
context: Debounce & Record<string, unknown>
} & Options
let globalQueue = Promise.resolve()

/**
* Merge the debounce properties into the options instance
* Creates a delay between API requests using a global queue
*
* @param raw - Plain request options, right before their normalization.
* @param options - The `Got` options object.
* @param duration - Fixed delay in ms or [min, max] range for random delay
*/
const initOptionsHook: InitHook = (raw: Debounce & OptionsInit, options: Options) => {
if (raw.debounce) {
options.context['debounce'] = {
queue: Promise.resolve(),
duration: raw.debounce
}
raw.debounce = undefined
}
const debounceRequest = async (duration: number | [number, number]): Promise<void> => {
const timeout = Array.isArray(duration) ? randomInt(...duration) : duration

const previous = globalQueue

globalQueue = (async () => {
await previous
await setTimeout(timeout)
})()

await globalQueue
}

/**
* Debounce hook used as a BeforeRequestHook.
* Hook that runs before each request to enforce delay between API calls
*
* @param options - The `Got` options object with debounce properties.
* @param options - Got request options containing debounce configuration
*/
const debounceHook: BeforeRequestHook = async (options: OptionsWithDebounce) => {
if (!options.context.debounce) return
const { debounce } = options.context
const timeout = Array.isArray(debounce.duration) ? crypto.randomInt(...debounce.duration) : debounce.duration
const previous = debounce.queue
debounce.queue = (async () => {
await previous
await setTimeout(timeout)
})()
await debounce.queue
const beforeRequestHook: BeforeRequestHook = async (options: Options): Promise<void> => {
const debounceOpts = options.context['debounce'] as DebounceOptions | undefined

if (!debounceOpts?.duration) {
return
}

await debounceRequest(debounceOpts.duration)
}

export const debounce: ExtendOptions = {
/**
* Creates a Got extension that adds request debouncing functionality
*
* @param duration - Fixed delay in ms or [min, max] range for random delay
*/
export const debounce = (duration: number | [number, number]): ExtendOptions => ({
hooks: {
init: [initOptionsHook],
beforeRequest: [debounceHook]
beforeRequest: [beforeRequestHook]
},
context: {
debounce: { duration }
}
}
})
21 changes: 9 additions & 12 deletions packages/ryanair/source/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,12 @@ export const DELAY_MS: number | [number, number] = 500
* @returns A promise that resolves with the response data or rejects with an error
*/

export const get = got
.extend({
headers: {
Cookie:
'rid.sig=jyna6R42wntYgoTpqvxHMK7H+KyM6xLed+9I3KsvYZaVt7P36AL6zp9dGFPu5uVxaIiFpNXrszr+LfNCdY3IT3oCSYLeNv/ujtjsDqOzkY66AL3V6kH2vsK+au12X21HkZ4S8GaG8CoBmm/m0rLsOKYkxtw+U3+ejBaPc15jJjKXnc3owMBg82SNbqyKjVd6Z6qcsoE25p3RmlcaHuHC3GBf1yIGtlqeQun3Mj0vmSURVPQBjK65pge2zGBymoORV6PsmZ0Nabv73gS2VkhG+Eccz5iSIRPrZm5cloi/941TFo8oiXdyqvTMx/ozox2fkvaKB2vd/goSx543TxPdKoGKRLaDY3FoIepe6I46UFvXEZYszzugXHYRnp0lbIn/HPyvHH/iW/TXRrqsELQabKd1hH+Ut1ZgpfsKEtwDVyL7mVvi1qEOqHddSVKCN/439KxQqi9K03dQDm+knQaLRpzZL8EYqCeSaosMOeEhc2CAYWLW2D5jH5iTot0YiyaN3QJFE59H3MYDpGjoZfTfen83yVSpT8DBahOOr6Eibv62bKQXBxel5kIm75dZB26iUzmkBs1Iags291UJ8wpu/GtBD1rghlZoRJt9u3ASkAj3P85dBcV8MwGykVWJ4mCO; mkt=/gb/en/; .AspNetCore.Session=CfDJ8NJy2CjeBXdEiTlIkEo9jP1x6eP6igWNkoeL9uCto1qdz97HQLRlCAJWIhw97YY5uemEBnTrcLNnoB7lqKOnEJRzF%2F4yhGKN9A5COUteaQmZduO6o2whfYqdyD1Qd%2B%2BH6EXjFP4cd0DtvPDwguugs%2Bc684C2CSfw16lyvYFtSkvU; fr-correlation-id=b8d2a2fe-383b-44fa-8c4a-ba6cab8c994d; rid=034ed121-51ec-4cac-9196-97a50ee42d2c; RY_COOKIE_CONSENT=true; STORAGE_PREFERENCES={"STRICTLY_NECESSARY":true,"PERFORMANCE":false,"FUNCTIONAL":false,"TARGETING":false,"SOCIAL_MEDIA":false,"PIXEL":false,"GANALYTICS":true,"__VERSION":2}; myRyanairID='
},
resolveBodyOnly: true,
responseType: 'json'
})
.extend(debounce)
// @ts-expect-error debounce property is set by the initHook applied above
.extend({ debounce: DELAY_MS })
export const get = got.extend({
headers: {
Cookie:
'rid.sig=jyna6R42wntYgoTpqvxHMK7H+KyM6xLed+9I3KsvYZaVt7P36AL6zp9dGFPu5uVxaIiFpNXrszr+LfNCdY3IT3oCSYLeNv/ujtjsDqOzkY66AL3V6kH2vsK+au12X21HkZ4S8GaG8CoBmm/m0rLsOKYkxtw+U3+ejBaPc15jJjKXnc3owMBg82SNbqyKjVd6Z6qcsoE25p3RmlcaHuHC3GBf1yIGtlqeQun3Mj0vmSURVPQBjK65pge2zGBymoORV6PsmZ0Nabv73gS2VkhG+Eccz5iSIRPrZm5cloi/941TFo8oiXdyqvTMx/ozox2fkvaKB2vd/goSx543TxPdKoGKRLaDY3FoIepe6I46UFvXEZYszzugXHYRnp0lbIn/HPyvHH/iW/TXRrqsELQabKd1hH+Ut1ZgpfsKEtwDVyL7mVvi1qEOqHddSVKCN/439KxQqi9K03dQDm+knQaLRpzZL8EYqCeSaosMOeEhc2CAYWLW2D5jH5iTot0YiyaN3QJFE59H3MYDpGjoZfTfen83yVSpT8DBahOOr6Eibv62bKQXBxel5kIm75dZB26iUzmkBs1Iags291UJ8wpu/GtBD1rghlZoRJt9u3ASkAj3P85dBcV8MwGykVWJ4mCO; mkt=/gb/en/; .AspNetCore.Session=CfDJ8NJy2CjeBXdEiTlIkEo9jP1x6eP6igWNkoeL9uCto1qdz97HQLRlCAJWIhw97YY5uemEBnTrcLNnoB7lqKOnEJRzF%2F4yhGKN9A5COUteaQmZduO6o2whfYqdyD1Qd%2B%2BH6EXjFP4cd0DtvPDwguugs%2Bc684C2CSfw16lyvYFtSkvU; fr-correlation-id=b8d2a2fe-383b-44fa-8c4a-ba6cab8c994d; rid=034ed121-51ec-4cac-9196-97a50ee42d2c; RY_COOKIE_CONSENT=true; STORAGE_PREFERENCES={"STRICTLY_NECESSARY":true,"PERFORMANCE":false,"FUNCTIONAL":false,"TARGETING":false,"SOCIAL_MEDIA":false,"PIXEL":false,"GANALYTICS":true,"__VERSION":2}; myRyanairID='
},
resolveBodyOnly: true,
responseType: 'json',
...debounce(DELAY_MS)
})

0 comments on commit 7e7c966

Please sign in to comment.