@segment/analytics-node
Version:
https://www.npmjs.com/package/@segment/analytics-node
78 lines (66 loc) • 2.02 kB
text/typescript
/**
* use non-native event emitter for the benefit of non-node runtimes like CF workers.
*/
import { Emitter } from '@segment/analytics-generic-utils'
import { detectRuntime } from './env'
/**
* adapted from: https://www.npmjs.com/package/node-abort-controller
*/
export class AbortSignal {
onabort: globalThis.AbortSignal['onabort'] = null
aborted = false
eventEmitter = new Emitter()
toString() {
return '[object AbortSignal]'
}
get [Symbol.toStringTag]() {
return 'AbortSignal'
}
removeEventListener(...args: Parameters<Emitter['off']>) {
this.eventEmitter.off(...args)
}
addEventListener(...args: Parameters<Emitter['on']>) {
this.eventEmitter.on(...args)
}
dispatchEvent(type: string) {
const event = { type, target: this }
const handlerName = `on${type}`
if (typeof (this as any)[handlerName] === 'function') {
;(this as any)[handlerName](event)
}
this.eventEmitter.emit(type, event)
}
}
/**
* This polyfill is only neccessary to support versions of node < 14.17.
* Can be removed once node 14 support is dropped.
*/
export class AbortController {
signal = new AbortSignal()
abort() {
if (this.signal.aborted) return
this.signal.aborted = true
this.signal.dispatchEvent('abort')
}
toString() {
return '[object AbortController]'
}
get [Symbol.toStringTag]() {
return 'AbortController'
}
}
/**
* @param timeoutMs - Set a request timeout, after which the request is cancelled.
*/
export const abortSignalAfterTimeout = (timeoutMs: number) => {
if (detectRuntime() === 'cloudflare-worker') {
return [] // TODO: this is broken in cloudflare workers, otherwise results in "A hanging Promise was canceled..." error.
}
const ac = new (globalThis.AbortController || AbortController)()
const timeoutId = setTimeout(() => {
ac.abort()
}, timeoutMs)
// Allow Node.js processes to exit early if only the timeout is running
timeoutId?.unref?.()
return [ac.signal, timeoutId] as const
}