+++ /dev/null
-docs/
-dist/
-lib/
-outputs/
+++ /dev/null
-const { defineConfig } = require('eslint-define-config')
-
-module.exports = defineConfig({
- root: true,
- env: {
- es2022: true,
- node: true,
- mocha: true
- },
- parserOptions: {
- sourceType: 'module',
- ecmaVersion: 2022
- },
- plugins: ['simple-import-sort', 'promise', 'spellcheck'],
- extends: [
- 'eslint:recommended',
- 'plugin:import/recommended',
- 'plugin:promise/recommended'
- ],
- settings: {
- 'import/resolver': {
- typescript: {
- project: './tsconfig.json'
- }
- }
- },
- rules: {
- 'simple-import-sort/imports': 'error',
- 'simple-import-sort/exports': 'error',
-
- 'spellcheck/spell-checker': [
- 'warn',
- {
- skipWords: [
- 'argv',
- 'axios',
- 'benoit',
- 'bmf',
- 'browserslist',
- 'builtins',
- 'christopher',
- 'cjs',
- 'cloneable',
- 'comparator',
- 'cpu',
- 'cpus',
- 'cryptographically',
- 'ctx',
- 'decrement',
- 'deprecations',
- 'deque',
- 'dequeue',
- 'dequeued',
- 'deregisters',
- 'dts',
- 'ecma',
- 'elu',
- 'enqueue',
- 'enum',
- 'errored',
- 'esm',
- 'fastify',
- 'fibonacci',
- 'fp',
- 'fs',
- 'func',
- 'idx',
- 'inheritDoc',
- 'javascript',
- 'jsdoc',
- 'linebreak',
- 'localhost',
- 'microjob',
- 'mjs',
- 'nodemailer',
- 'npx',
- 'num',
- 'os',
- 'perf',
- 'piscina',
- 'pnpm',
- 'poolifier',
- 'prepend',
- 'prepends',
- 'positionals',
- 'readdir',
- 'readonly',
- 'req',
- 'resize',
- 'sinon',
- 'smtp',
- 'threadjs',
- 'threadwork',
- 'tinypool',
- 'tld',
- 'tos',
- 'tsconfig',
- 'tsdoc',
- 'typedoc',
- 'unlink',
- 'unref',
- 'utf8',
- 'workerpool',
- 'ws',
- 'wss',
- 'wwr'
- ],
- skipIfMatch: ['^@.*', '^plugin:.*']
- }
- ]
- },
- overrides: [
- {
- files: ['**/*.ts'],
- plugins: ['@typescript-eslint', 'eslint-plugin-tsdoc'],
- parser: '@typescript-eslint/parser',
- parserOptions: {
- project: './tsconfig.json'
- },
- extends: [
- 'plugin:@typescript-eslint/strict-type-checked',
- 'plugin:@typescript-eslint/stylistic-type-checked',
- 'plugin:import/typescript',
- 'love'
- ],
- rules: {
- 'operator-linebreak': 'off',
- 'tsdoc/syntax': 'warn'
- }
- },
- {
- files: ['examples/typescript/**/*.ts'],
- rules: {
- 'import/no-unresolved': [
- 'error',
- {
- ignore: [
- '^axios$',
- '^express$',
- '^fastify$',
- '^fastify-plugin$',
- '^node-fetch$',
- '^nodemailer$',
- '^poolifier$',
- '^ws$'
- ]
- }
- ],
- '@typescript-eslint/no-unsafe-argument': 'off',
- '@typescript-eslint/no-unsafe-call': 'off',
- '@typescript-eslint/no-unsafe-return': 'off',
- '@typescript-eslint/no-unsafe-assignment': 'off',
- '@typescript-eslint/no-unsafe-member-access': 'off',
- '@typescript-eslint/no-unnecessary-type-assertion': 'off',
- '@typescript-eslint/no-redundant-type-constituents': 'off',
- '@typescript-eslint/strict-boolean-expressions': 'off',
- '@typescript-eslint/return-await': 'off',
- '@typescript-eslint/no-non-null-assertion': 'off'
- }
- },
- {
- files: ['**/*.cjs', '**/*.js', '**/*.mjs'],
- plugins: ['jsdoc'],
- extends: ['plugin:n/recommended', 'plugin:jsdoc/recommended', 'standard']
- },
- {
- files: ['tests/**/*.cjs', 'tests/**/*.js', 'tests/**/*.mjs'],
- rules: {
- 'jsdoc/require-jsdoc': 'off'
- }
- },
- {
- files: [
- 'benchmarks/**/*.cjs',
- 'benchmarks/**/*.js',
- 'benchmarks/**/*.mjs'
- ],
- rules: {
- 'jsdoc/require-jsdoc': 'off'
- }
- },
- {
- files: ['examples/javascript/**/*.cjs', 'examples/javascript/**/*.js'],
- rules: {
- 'jsdoc/require-jsdoc': 'off'
- }
- }
- ]
-})
export default {
'**/*.{ts,tsx,js,jsx,cjs,mjs}': [
'biome format --write',
- 'eslint --cache --fix'
+ 'eslint --cache --fix',
],
'**/*.json': ['biome format --write'],
- '**/*.{md,yml,yaml}': ['prettier --cache --write']
+ '**/*.{md,yml,yaml}': ['prettier --cache --write'],
}
"mochawesome",
"MYBENCH",
"nanothreads",
+ "neostandard",
"npmjs",
"nproc",
"octocat",
"tinypool",
"trimmable",
"tsdoc",
+ "tseslint",
"typedoc",
"workerpool"
],
jsonIntegerSerialization: 'jsonIntegerSerialization',
fibonacci: 'fibonacci',
factorial: 'factorial',
- readWriteFiles: 'readWriteFiles'
+ readWriteFiles: 'readWriteFiles',
}
module.exports = { TaskFunctions }
mkdirSync,
readFileSync,
rmSync,
- writeFileSync
+ writeFileSync,
} = require('node:fs')
const { TaskFunctions } = require('./benchmarks-types.cjs')
const jsonIntegerSerialization = n => {
for (let i = 0; i < n; i++) {
const o = {
- a: i
+ a: i,
}
JSON.stringify(o)
}
}
/**
- * @param {number} n - The number of fibonacci numbers to generate.
- * @returns {number} - The nth fibonacci number.
+ * @param n - The number of fibonacci numbers to generate.
+ * @returns - The nth fibonacci number.
*/
const fibonacci = n => {
n = BigInt(n)
}
/**
- * @param {number} n - The number to calculate the factorial of.
- * @returns {number} - The factorial of n.
+ * @param n - The number to calculate the factorial of.
+ * @returns - The factorial of n.
*/
const factorial = n => {
if (n === 0 || n === 1) {
const filePath = `${baseDirectory}/${i}`
writeFileSync(filePath, i.toString(), {
encoding: 'utf8',
- flag: 'a'
+ flag: 'a',
})
readFileSync(filePath, 'utf8')
}
}
module.exports = {
- executeTaskFunction
+ executeTaskFunction,
}
Measurements,
PoolTypes,
WorkerChoiceStrategies,
- WorkerTypes
+ WorkerTypes,
} from '../lib/index.mjs'
import { executeTaskFunction } from './benchmarks-utils.cjs'
async () => {
await runPoolifierPool(pool, {
taskExecutions,
- workerData
+ workerData,
})
},
{
before: () => {
pool.setWorkerChoiceStrategy(workerChoiceStrategy, {
- measurement
+ measurement,
})
pool.enableTasksQueue(enableTasksQueue)
strictEqual(
pool.opts.workerChoiceStrategyOptions.measurement,
measurement
)
- }
+ },
}
)
})
async () => {
await runPoolifierPool(pool, {
taskExecutions,
- workerData
+ workerData,
})
},
{
workerChoiceStrategy
)
strictEqual(pool.opts.enableTasksQueue, enableTasksQueue)
- }
+ },
}
)
})
latency: {
value: stats?.avg,
lower_value: stats?.min,
- upper_value: stats?.max
+ upper_value: stats?.max,
},
throughput: {
- value: stats?.iter
- }
- }
+ value: stats?.iter,
+ },
+ },
}
})
.reduce((obj, item) => Object.assign(obj, item), {})
import {
availableParallelism,
PoolTypes,
- WorkerTypes
+ WorkerTypes,
} from '../../lib/index.mjs'
import { TaskFunctions } from '../benchmarks-types.cjs'
import {
convertTatamiNgToBmf,
- runPoolifierBenchmarkTatamiNg
+ runPoolifierBenchmarkTatamiNg,
} from '../benchmarks-utils.mjs'
const poolSize = availableParallelism()
const taskExecutions = 1
const workerData = {
function: TaskFunctions.factorial,
- taskSize: 1000
+ taskSize: 1000,
}
const benchmarkReportFile = 'benchmark-report.json'
let benchmarkReport
options: {
type: {
type: 'string',
- short: 't'
- }
+ short: 't',
+ },
},
strict: true,
- allowPositionals: true
+ allowPositionals: true,
}).values.type
) {
case 'tatami-ng':
poolSize,
{
taskExecutions,
- workerData
+ workerData,
}
)
)
poolSize,
{
taskExecutions,
- workerData
+ workerData,
}
)
- )
+ ),
}
benchmarkReport = {
...benchmarkReport,
poolSize,
{
taskExecutions,
- workerData
+ workerData,
}
)
- )
+ ),
}
benchmarkReport = {
...benchmarkReport,
poolSize,
{
taskExecutions,
- workerData
+ workerData,
}
)
- )
+ ),
}
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
env.CI != null &&
writeFileSync(benchmarkReportFile, JSON.stringify(benchmarkReport))
break
data.function = data.function || TaskFunctions.factorial
data.debug = data.debug || false
const res = executeTaskFunction(data)
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
data.debug === true && console.debug(`This is the main thread ${isPrimary}`)
return res
}
data.function = data.function || TaskFunctions.factorial
data.debug = data.debug || false
const res = executeTaskFunction(data)
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
data.debug === true &&
console.debug(`This is the main thread ${isMainThread}`)
return res
import { bench, group, run } from 'tatami-ng'
+/**
+ *
+ * @param numberOfWorkers
+ * @param maxNumberOfTasksPerWorker
+ */
function generateRandomTasksMap (
numberOfWorkers,
maxNumberOfTasksPerWorker = 10
const tasksMap = generateRandomTasksMap(60, 20)
+/**
+ *
+ * @param tasksMap
+ */
function loopSelect (tasksMap) {
let minKey
let minValue = Number.POSITIVE_INFINITY
return [minKey, minValue]
}
+/**
+ *
+ * @param tasksMap
+ */
function arraySortSelect (tasksMap) {
const tasksArray = Array.from(tasksMap)
return tasksArray.sort((a, b) => {
return randomInt(leftIndex, rightIndex)
}
+/**
+ *
+ * @param array
+ * @param index1
+ * @param index2
+ */
function swap (array, index1, index2) {
const tmp = array[index1]
array[index1] = array[index2]
array[index2] = tmp
}
+/**
+ *
+ * @param array
+ * @param leftIndex
+ * @param rightIndex
+ * @param pivotIndex
+ * @param compare
+ */
function partition (
array,
leftIndex,
return storeIndex
}
+/**
+ *
+ * @param array
+ * @param k
+ * @param leftIndex
+ * @param rightIndex
+ * @param compare
+ * @param pivotIndexSelect
+ */
function selectLoop (
array,
k,
}
}
+/**
+ *
+ * @param array
+ * @param k
+ * @param leftIndex
+ * @param rightIndex
+ * @param compare
+ * @param pivotIndexSelect
+ */
function selectRecursion (
array,
k,
}
}
+/**
+ *
+ * @param tasksMap
+ */
function quickSelectLoop (tasksMap) {
const tasksArray = Array.from(tasksMap)
})
}
+/**
+ *
+ * @param tasksMap
+ */
function quickSelectLoopRandomPivot (tasksMap) {
const tasksArray = Array.from(tasksMap)
)
}
+/**
+ *
+ * @param tasksMap
+ */
function quickSelectRecursion (tasksMap) {
const tasksArray = Array.from(tasksMap)
})
}
+/**
+ *
+ * @param tasksMap
+ */
function quickSelectRecursionRandomPivot (tasksMap) {
const tasksArray = Array.from(tasksMap)
import { bench, group, run } from 'tatami-ng'
+/**
+ *
+ * @param numberOfWorkers
+ */
function generateWorkersArray (numberOfWorkers) {
return [...Array(numberOfWorkers).keys()]
}
let nextWorkerIndex
+/**
+ *
+ */
function roundRobinTernaryOffByOne () {
nextWorkerIndex =
workers.length - 1 === nextWorkerIndex ? 0 : nextWorkerIndex + 1
return workers[nextWorkerIndex]
}
+/**
+ *
+ */
function roundRobinTernaryWithNegation () {
nextWorkerIndex =
!nextWorkerIndex || workers.length - 1 === nextWorkerIndex
return workers[nextWorkerIndex]
}
+/**
+ *
+ */
function roundRobinTernaryWithPreChoosing () {
const chosenWorker = workers[nextWorkerIndex]
nextWorkerIndex =
return chosenWorker
}
+/**
+ *
+ */
function roundRobinIncrementModulo () {
const chosenWorker = workers[nextWorkerIndex]
nextWorkerIndex++
const {
DynamicThreadPool,
PoolEvents,
- availableParallelism
+ availableParallelism,
} = require('poolifier')
const pool = new DynamicThreadPool(
'./yourWorker.js',
{
onlineHandler: () => console.info('worker is online'),
- errorHandler: e => console.error(e)
+ errorHandler: e => console.error(e),
}
)
let poolFull = 0
const {
FixedThreadPool,
PoolEvents,
- availableParallelism
+ availableParallelism,
} = require('poolifier')
const pool = new FixedThreadPool(availableParallelism(), './yourWorker.cjs', {
onlineHandler: () => console.info('worker is online'),
- errorHandler: e => console.error(e)
+ errorHandler: e => console.error(e),
})
let poolReady = 0
let poolBusy = 0
'./multiFunctionWorker.cjs',
{
onlineHandler: () => console.info('worker is online'),
- errorHandler: e => console.error(e)
+ errorHandler: e => console.error(e),
}
)
'use strict'
const { ThreadWorker } = require('poolifier')
+/**
+ *
+ * @param data
+ */
function fn0 (data) {
console.info('Executing fn0')
return { data: `fn0 input text was '${data.text}'` }
}
+/**
+ *
+ * @param data
+ */
function fn1 (data) {
console.info('Executing fn1')
return { data: `fn1 input text was '${data.text}'` }
'use strict'
const { ThreadWorker } = require('poolifier')
+/**
+ *
+ */
function yourFunction () {
for (let i = 0; i <= 1000; i++) {
const o = {
- a: i
+ a: i,
}
JSON.stringify(o)
}
{
enableTasksQueue: true,
tasksQueueOptions: {
- concurrency: 8
+ concurrency: 8,
},
errorHandler: (e: Error) => {
console.error('Thread worker error:', e)
- }
+ },
}
)
import type { AxiosRequestConfig } from 'axios'
import type {
RequestInfo as NodeFetchRequestInfo,
- RequestInit as NodeFetchRequestInit
+ RequestInit as NodeFetchRequestInit,
} from 'node-fetch'
export interface WorkerData {
import axios from 'axios'
import nodeFetch, {
type RequestInfo as NodeFetchRequestInfo,
- type ResponseInit as NodeFetchRequestInit
+ type ResponseInit as NodeFetchRequestInit,
} from 'node-fetch'
import { ThreadWorker } from 'poolifier'
super({
node_fetch: async (workerData?: WorkerData) => {
const response = await nodeFetch(
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
workerData!.input as URL | NodeFetchRequestInfo,
workerData?.init as NodeFetchRequestInit
)
// The response is not structured-cloneable, so we return the response text body instead.
return {
- text: await response.text()
+ text: await response.text(),
}
},
fetch: async (workerData?: WorkerData) => {
const response = await fetch(
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
workerData!.input as URL | RequestInfo,
workerData?.init as RequestInit
)
// The response is not structured-cloneable, so we return the response text body instead.
return {
- text: await response.text()
+ text: await response.text(),
}
},
axios: async (workerData?: WorkerData) => {
const response = await axios({
method: 'get',
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
url: workerData!.input as string,
- ...workerData?.axiosRequestConfig
+ ...workerData?.axiosRequestConfig,
})
return {
- text: response.data
+ text: response.data,
}
- }
+ },
})
}
}
dir: './dist',
sourcemap: true,
entryFileNames: '[name].cjs',
- chunkFileNames: '[name]-[hash].cjs'
+ chunkFileNames: '[name]-[hash].cjs',
},
{
format: 'esm',
dir: './dist',
- sourcemap: true
- }
+ sourcemap: true,
+ },
],
external: ['express', /^node:*/, 'poolifier'],
plugins: [
typescript(),
del({
- targets: ['./dist/*']
- })
- ]
+ targets: ['./dist/*'],
+ }),
+ ],
})
},
errorHandler: (e: Error) => {
console.error('Cluster worker error:', e)
- }
+ },
}
)
private static readonly startExpress = (
workerData?: WorkerData
): WorkerResponse => {
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const { port } = workerData!
const application: Express = express()
const { number } = req.params
res
.send({
- number: ExpressWorker.factorial(Number.parseInt(number)).toString()
+ number: ExpressWorker.factorial(Number.parseInt(number)).toString(),
})
.end()
})
})
return {
status: true,
- port: listenerPort ?? port
+ port: listenerPort ?? port,
}
}
super(ExpressWorker.startExpress, {
killHandler: () => {
ExpressWorker.server.close()
- }
+ },
})
}
}
input: [
'./src/main.ts',
'./src/express-worker.ts',
- './src/request-handler-worker.ts'
+ './src/request-handler-worker.ts',
],
strictDeprecations: true,
output: [
dir: './dist',
sourcemap: true,
entryFileNames: '[name].cjs',
- chunkFileNames: '[name]-[hash].cjs'
+ chunkFileNames: '[name]-[hash].cjs',
},
{
format: 'esm',
dir: './dist',
- sourcemap: true
- }
+ sourcemap: true,
+ },
],
external: ['express', /^node:*/, 'poolifier'],
plugins: [
typescript(),
del({
- targets: ['./dist/*']
- })
- ]
+ targets: ['./dist/*'],
+ }),
+ ],
})
import {
availableParallelism,
ClusterWorker,
- DynamicThreadPool
+ DynamicThreadPool,
} from 'poolifier'
import type {
ClusterWorkerResponse,
DataPayload,
ThreadWorkerData,
- ThreadWorkerResponse
+ ThreadWorkerResponse,
} from './types.js'
const emptyFunction = (): void => {
}
class ExpressWorker extends ClusterWorker<
-ClusterWorkerData,
-ClusterWorkerResponse
+ ClusterWorkerData,
+ ClusterWorkerResponse
> {
private static server: Server
private static requestHandlerPool: DynamicThreadPool<
- ThreadWorkerData<DataPayload>,
- ThreadWorkerResponse<DataPayload>
+ ThreadWorkerData<DataPayload>,
+ ThreadWorkerResponse<DataPayload>
>
private static readonly startExpress = (
workerData?: ClusterWorkerData
): ClusterWorkerResponse => {
const { port, workerFile, minWorkers, maxWorkers, ...poolOptions } =
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
workerData!
ExpressWorker.requestHandlerPool = new DynamicThreadPool<
- ThreadWorkerData<DataPayload>,
- ThreadWorkerResponse<DataPayload>
+ ThreadWorkerData<DataPayload>,
+ ThreadWorkerResponse<DataPayload>
>(
minWorkers ?? 1,
maxWorkers ?? availableParallelism(),
})
return {
status: true,
- port: listenerPort ?? port
+ port: listenerPort ?? port,
}
}
killHandler: async () => {
await ExpressWorker.requestHandlerPool.destroy()
ExpressWorker.server.close()
- }
+ },
})
}
}
workerFile: requestHandlerWorkerFile,
enableTasksQueue: true,
tasksQueueOptions: {
- concurrency: 8
+ concurrency: 8,
},
errorHandler: (e: Error) => {
console.error('Thread worker error:', e)
- }
+ },
})
.then(response => {
if (response.status) {
},
errorHandler: (e: Error) => {
console.error('Cluster worker error:', e)
- }
+ },
}
)
import type {
DataPayload,
ThreadWorkerData,
- ThreadWorkerResponse
+ ThreadWorkerResponse,
} from './types.js'
class RequestHandlerWorker<
return {
data: {
number: RequestHandlerWorker.factorial(
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
workerData!.data.number!
- ).toString()
- }
+ ).toString(),
+ },
} as unknown as Response
- }
+ },
})
}
}
export const requestHandlerWorker = new RequestHandlerWorker<
-ThreadWorkerData<DataPayload>,
-ThreadWorkerResponse<DataPayload>
+ ThreadWorkerData<DataPayload>,
+ ThreadWorkerResponse<DataPayload>
>()
)
export const requestHandlerPool = new DynamicThreadPool<
-WorkerData<BodyPayload>,
-WorkerResponse<BodyPayload>
+ WorkerData<BodyPayload>,
+ WorkerResponse<BodyPayload>
>(1, availableParallelism(), workerFile, {
enableTasksQueue: true,
tasksQueueOptions: {
- concurrency: 8
+ concurrency: 8,
},
errorHandler: (e: Error) => {
console.error('Thread worker error:', e)
- }
+ },
})
return {
body: {
number: RequestHandlerWorker.factorial(
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
workerData!.body.number!
- ).toString()
- }
+ ).toString(),
+ },
} as unknown as Response
- }
+ },
})
}
}
export const requestHandlerWorker = new RequestHandlerWorker<
-WorkerData<BodyPayload>,
-WorkerResponse<BodyPayload>
+ WorkerData<BodyPayload>,
+ WorkerResponse<BodyPayload>
>()
dir: './dist',
sourcemap: true,
entryFileNames: '[name].cjs',
- chunkFileNames: '[name]-[hash].cjs'
+ chunkFileNames: '[name]-[hash].cjs',
},
{
format: 'esm',
dir: './dist',
- sourcemap: true
- }
+ sourcemap: true,
+ },
],
external: ['fastify', /^node:*/, 'poolifier'],
plugins: [
typescript(),
del({
- targets: ['./dist/*']
- })
- ]
+ targets: ['./dist/*'],
+ }),
+ ],
})
},
errorHandler: (e: Error) => {
console.error('Cluster worker error:', e)
- }
+ },
}
)
private static readonly startFastify = async (
workerData?: WorkerData
): Promise<WorkerResponse> => {
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const { port } = workerData!
FastifyWorker.fastify = Fastify({
- logger: true
+ logger: true,
})
FastifyWorker.fastify.all('/api/echo', request => {
await FastifyWorker.fastify.listen({ port })
return {
status: true,
- port: (FastifyWorker.fastify.server.address() as AddressInfo).port
+ port: (FastifyWorker.fastify.server.address() as AddressInfo).port,
}
}
super(FastifyWorker.startFastify, {
killHandler: async () => {
await FastifyWorker.fastify.close()
- }
+ },
})
}
}
input: [
'./src/main.ts',
'./src/fastify-worker.ts',
- './src/request-handler-worker.ts'
+ './src/request-handler-worker.ts',
],
strictDeprecations: true,
output: [
dir: './dist',
sourcemap: true,
entryFileNames: '[name].cjs',
- chunkFileNames: '[name]-[hash].cjs'
+ chunkFileNames: '[name]-[hash].cjs',
},
{
format: 'esm',
dir: './dist',
- sourcemap: true
- }
+ sourcemap: true,
+ },
],
external: ['fastify', 'fastify-plugin', /^node:*/, 'poolifier'],
plugins: [
typescript(),
del({
- targets: ['./dist/*']
- })
- ]
+ targets: ['./dist/*'],
+ }),
+ ],
})
import type {
FastifyPoolifierOptions,
ThreadWorkerData,
- ThreadWorkerResponse
+ ThreadWorkerResponse,
} from './types.js'
const fastifyPoolifierPlugin: FastifyPluginCallback<FastifyPoolifierOptions> = (
options = {
...{
minWorkers: 1,
- maxWorkers: availableParallelism()
+ maxWorkers: availableParallelism(),
},
- ...options
+ ...options,
}
const { workerFile, minWorkers, maxWorkers, ...poolOptions } = options
const pool = new DynamicThreadPool<ThreadWorkerData, ThreadWorkerResponse>(
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
minWorkers!,
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
maxWorkers!,
workerFile,
poolOptions
export const fastifyPoolifier = fp(fastifyPoolifierPlugin, {
fastify: '4.x',
- name: 'fastify-poolifier'
+ name: 'fastify-poolifier',
})
import type { ClusterWorkerData, ClusterWorkerResponse } from './types.js'
class FastifyWorker extends ClusterWorker<
-ClusterWorkerData,
-ClusterWorkerResponse
+ ClusterWorkerData,
+ ClusterWorkerResponse
> {
private static fastify: FastifyInstance
private static readonly startFastify = async (
workerData?: ClusterWorkerData
): Promise<ClusterWorkerResponse> => {
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const { port, ...fastifyPoolifierOptions } = workerData!
FastifyWorker.fastify = Fastify({
- logger: true
+ logger: true,
})
await FastifyWorker.fastify.register(
await FastifyWorker.fastify.listen({ port })
return {
status: true,
- port: (FastifyWorker.fastify.server.address() as AddressInfo).port
+ port: (FastifyWorker.fastify.server.address() as AddressInfo).port,
}
}
killHandler: async () => {
await FastifyWorker.fastify.pool.destroy()
await FastifyWorker.fastify.close()
- }
+ },
})
}
}
: Math.round(availableParallelism() / 4),
enableTasksQueue: true,
tasksQueueOptions: {
- concurrency: 8
+ concurrency: 8,
},
errorHandler: (e: Error) => {
console.error('Thread worker error', e)
- }
+ },
})
.then(response => {
if (response.status) {
},
errorHandler: (e: Error) => {
console.error('Cluster worker error:', e)
- }
+ },
}
)
import type {
DataPayload,
ThreadWorkerData,
- ThreadWorkerResponse
+ ThreadWorkerResponse,
} from './types.js'
class RequestHandlerWorker<
return {
data: {
number: RequestHandlerWorker.factorial(
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
workerData!.data.number!
- ).toString()
- }
+ ).toString(),
+ },
} as unknown as Response
- }
+ },
})
}
}
export const requestHandlerWorker = new RequestHandlerWorker<
-ThreadWorkerData<DataPayload>,
-ThreadWorkerResponse<DataPayload>
+ ThreadWorkerData<DataPayload>,
+ ThreadWorkerResponse<DataPayload>
>()
import type {
FastifyPoolifierOptions,
WorkerData,
- WorkerResponse
+ WorkerResponse,
} from './types.js'
const fastifyPoolifierPlugin: FastifyPluginCallback<FastifyPoolifierOptions> = (
options = {
...{
minWorkers: 1,
- maxWorkers: availableParallelism()
+ maxWorkers: availableParallelism(),
},
- ...options
+ ...options,
}
const { workerFile, minWorkers, maxWorkers, ...poolOptions } = options
const pool = new DynamicThreadPool<WorkerData, WorkerResponse>(
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
minWorkers!,
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
maxWorkers!,
workerFile,
poolOptions
export const fastifyPoolifier = fp(fastifyPoolifierPlugin, {
fastify: '4.x',
- name: 'fastify-poolifier'
+ name: 'fastify-poolifier',
})
const port = 8080
const fastify = Fastify({
- logger: true
+ logger: true,
})
const workerFile = join(
workerFile,
enableTasksQueue: true,
tasksQueueOptions: {
- concurrency: 8
+ concurrency: 8,
},
errorHandler: (e: Error) => {
fastify.log.error('Thread worker error:', e)
- }
+ },
})
fastify.all('/api/echo', async request => {
return {
body: {
number: RequestHandlerWorker.factorial(
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
workerData!.body.number!
- ).toString()
- }
+ ).toString(),
+ },
} as unknown as Response
- }
+ },
})
}
}
export const requestHandlerWorker = new RequestHandlerWorker<
-WorkerData<BodyPayload>,
-WorkerResponse<BodyPayload>
+ WorkerData<BodyPayload>,
+ WorkerResponse<BodyPayload>
>()
import {
availableParallelism,
DynamicThreadPool,
- FixedThreadPool
+ FixedThreadPool,
} from 'poolifier'
import type { MyData, MyResponse } from './worker.js'
},
errorHandler: (e: Error) => {
console.error(e)
- }
+ },
}
)
},
errorHandler: (e: Error) => {
console.error(e)
- }
+ },
}
)
await dynamicPool.execute()
-// eslint-disable-next-line @typescript-eslint/no-misused-promises
setTimeout(async () => {
await fixedPool.destroy()
await dynamicPool.destroy()
secure: true,
auth: {
user: 'REPLACE-WITH-YOUR-ALIAS@DOMAIN.TLD',
- pass: 'REPLACE-WITH-YOUR-GENERATED-PASSWORD'
- }
+ pass: 'REPLACE-WITH-YOUR-GENERATED-PASSWORD',
+ },
},
mail: {
from: '"Foo" <foo@domain.tld>',
to,
subject: 'Hello',
text: 'Hello world?',
- html: '<b>Hello world?</b>'
- }
+ html: '<b>Hello world?</b>',
+ },
})
)
}
)
export const smtpClientPool = new DynamicThreadPool<
-WorkerData,
-SMTPTransport.SentMessageInfo
+ WorkerData,
+ SMTPTransport.SentMessageInfo
>(0, availableParallelism(), workerFile, {
enableTasksQueue: true,
tasksQueueOptions: {
- concurrency: 8
+ concurrency: 8,
},
errorHandler: (e: Error) => {
console.error('Thread worker error:', e)
- }
+ },
})
import type { WorkerData } from './types.js'
class SmtpClientWorker extends ThreadWorker<
-WorkerData,
-SMTPTransport.SentMessageInfo
+ WorkerData,
+ SMTPTransport.SentMessageInfo
> {
public constructor () {
super({
nodemailer: async (workerData?: WorkerData) => {
return await createTransport(workerData?.smtpTransport).sendMail(
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
workerData!.mail
)
- }
+ },
})
}
}
-// eslint-disable-next-line import/no-unresolved, n/no-missing-import
import { WebSocket } from 'ws'
const ws = new WebSocket('ws://localhost:8080')
dir: './dist',
sourcemap: true,
entryFileNames: '[name].cjs',
- chunkFileNames: '[name]-[hash].cjs'
+ chunkFileNames: '[name]-[hash].cjs',
},
{
format: 'esm',
dir: './dist',
- sourcemap: true
- }
+ sourcemap: true,
+ },
],
external: [/^node:*/, 'poolifier', 'ws'],
plugins: [
typescript(),
del({
- targets: ['./dist/*']
- })
- ]
+ targets: ['./dist/*'],
+ }),
+ ],
})
},
errorHandler: (e: Error) => {
console.error('Cluster worker error', e)
- }
+ },
}
)
type MessagePayload,
MessageType,
type WorkerData,
- type WorkerResponse
+ type WorkerResponse,
} from './types.js'
class WebSocketServerWorker extends ClusterWorker<WorkerData, WorkerResponse> {
private static readonly startWebSocketServer = (
workerData?: WorkerData
): WorkerResponse => {
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const { port } = workerData!
WebSocketServerWorker.wss = new WebSocketServer({ port }, () => {
ws.on('error', console.error)
ws.on('message', (message: RawData) => {
const { type, data } = JSON.parse(
- // eslint-disable-next-line @typescript-eslint/no-base-to-string
message.toString()
) as MessagePayload<DataPayload>
switch (type) {
ws.send(
JSON.stringify({
type: MessageType.echo,
- data
+ data,
})
)
break
{
type: MessageType.factorial,
data: {
- number: WebSocketServerWorker.factorial(data.number!)
- }
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ number: WebSocketServerWorker.factorial(data.number!),
+ },
},
(_, v) => (typeof v === 'bigint' ? v.toString() : v)
)
})
return {
status: true,
- port: WebSocketServerWorker.wss.options.port
+ port: WebSocketServerWorker.wss.options.port,
}
}
super(WebSocketServerWorker.startWebSocketServer, {
killHandler: () => {
WebSocketServerWorker.wss.close()
- }
+ },
})
}
}
-// eslint-disable-next-line import/no-unresolved, n/no-missing-import
import { WebSocket } from 'ws'
const ws = new WebSocket('ws://localhost:8080')
input: [
'./src/main.ts',
'./src/websocket-server-worker.ts',
- './src/request-handler-worker.ts'
+ './src/request-handler-worker.ts',
],
strictDeprecations: true,
output: [
dir: './dist',
sourcemap: true,
entryFileNames: '[name].cjs',
- chunkFileNames: '[name]-[hash].cjs'
+ chunkFileNames: '[name]-[hash].cjs',
},
{
format: 'esm',
dir: './dist',
- sourcemap: true
- }
+ sourcemap: true,
+ },
],
external: [/^node:*/, 'poolifier', 'ws'],
plugins: [
typescript(),
del({
- targets: ['./dist/*']
- })
- ]
+ targets: ['./dist/*'],
+ }),
+ ],
})
workerFile: requestHandlerWorkerFile,
enableTasksQueue: true,
tasksQueueOptions: {
- concurrency: 8
+ concurrency: 8,
},
errorHandler: (e: Error) => {
console.error('Thread worker error:', e)
- }
+ },
})
.then(response => {
if (response.status) {
},
errorHandler: (e: Error) => {
console.error('Cluster worker error', e)
- }
+ },
}
)
import type {
DataPayload,
ThreadWorkerData,
- ThreadWorkerResponse
+ ThreadWorkerResponse,
} from './types.js'
class RequestHandlerWorker<
factorial: (workerData?: Data) => {
return {
data: {
- number: RequestHandlerWorker.factorial(workerData!.data.number!)
- }
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ number: RequestHandlerWorker.factorial(workerData!.data.number!),
+ },
} as unknown as Response
- }
+ },
})
}
}
export const requestHandlerWorker = new RequestHandlerWorker<
-ThreadWorkerData<DataPayload>,
-ThreadWorkerResponse<DataPayload>
+ ThreadWorkerData<DataPayload>,
+ ThreadWorkerResponse<DataPayload>
>()
import {
availableParallelism,
ClusterWorker,
- DynamicThreadPool
+ DynamicThreadPool,
} from 'poolifier'
import { type RawData, WebSocketServer } from 'ws'
type MessagePayload,
MessageType,
type ThreadWorkerData,
- type ThreadWorkerResponse
+ type ThreadWorkerResponse,
} from './types.js'
const emptyFunction = (): void => {
}
class WebSocketServerWorker extends ClusterWorker<
-ClusterWorkerData,
-ClusterWorkerResponse
+ ClusterWorkerData,
+ ClusterWorkerResponse
> {
private static wss: WebSocketServer
private static requestHandlerPool: DynamicThreadPool<
- ThreadWorkerData<DataPayload>,
- ThreadWorkerResponse<DataPayload>
+ ThreadWorkerData<DataPayload>,
+ ThreadWorkerResponse<DataPayload>
>
private static readonly startWebSocketServer = (
workerData?: ClusterWorkerData
): ClusterWorkerResponse => {
const { port, workerFile, minWorkers, maxWorkers, ...poolOptions } =
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
workerData!
WebSocketServerWorker.requestHandlerPool = new DynamicThreadPool<
- ThreadWorkerData<DataPayload>,
- ThreadWorkerResponse<DataPayload>
+ ThreadWorkerData<DataPayload>,
+ ThreadWorkerResponse<DataPayload>
>(
minWorkers ?? 1,
maxWorkers ?? availableParallelism(),
ws.on('error', console.error)
ws.on('message', (message: RawData) => {
const { type, data } = JSON.parse(
- // eslint-disable-next-line @typescript-eslint/no-base-to-string
message.toString()
) as MessagePayload<DataPayload>
switch (type) {
ws.send(
JSON.stringify({
type: MessageType.echo,
- data: response.data
+ data: response.data,
})
)
return undefined
JSON.stringify(
{
type: MessageType.factorial,
- data: response.data
+ data: response.data,
},
(_, v) => (typeof v === 'bigint' ? v.toString() : v)
)
})
return {
status: true,
- port: WebSocketServerWorker.wss.options.port
+ port: WebSocketServerWorker.wss.options.port,
}
}
killHandler: async () => {
await WebSocketServerWorker.requestHandlerPool.destroy()
WebSocketServerWorker.wss.close()
- }
+ },
})
}
}
-// eslint-disable-next-line import/no-unresolved, n/no-missing-import
import { WebSocket } from 'ws'
const ws = new WebSocket('ws://localhost:8080')
ws.on('error', console.error)
ws.on('message', (message: RawData) => {
const { type, data } = JSON.parse(
- // eslint-disable-next-line @typescript-eslint/no-base-to-string
message.toString()
) as MessagePayload<DataPayload>
switch (type) {
ws.send(
JSON.stringify({
type: MessageType.echo,
- data: response.data
+ data: response.data,
})
)
return undefined
JSON.stringify(
{
type: MessageType.factorial,
- data: response.data
+ data: response.data,
},
(_, v) => (typeof v === 'bigint' ? v.toString() : v)
)
)
export const requestHandlerPool = new DynamicThreadPool<
-WorkerData<DataPayload>,
-WorkerResponse<DataPayload>
+ WorkerData<DataPayload>,
+ WorkerResponse<DataPayload>
>(1, availableParallelism(), workerFile, {
enableTasksQueue: true,
tasksQueueOptions: {
- concurrency: 8
+ concurrency: 8,
},
errorHandler: (e: Error) => {
console.error('Thread worker error:', e)
- }
+ },
})
factorial: (workerData?: Data) => {
return {
data: {
- number: RequestHandlerWorker.factorial(workerData!.data.number!)
- }
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ number: RequestHandlerWorker.factorial(workerData!.data.number!),
+ },
} as unknown as Response
- }
+ },
})
}
}
export const requestHandlerWorker = new RequestHandlerWorker<
-WorkerData<DataPayload>,
-WorkerResponse<DataPayload>
+ WorkerData<DataPayload>,
+ WorkerResponse<DataPayload>
>()
class MyThreadWorker extends ThreadWorker<MyData, MyResponse> {
constructor () {
super(async (data?: MyData) => await this.process(data), {
- maxInactiveTime: 60000
+ maxInactiveTime: 60000,
})
}
"@biomejs/biome": "^1.7.3",
"@commitlint/cli": "^19.3.0",
"@commitlint/config-conventional": "^19.2.2",
+ "@cspell/eslint-plugin": "^8.8.3",
+ "@eslint/js": "^9.3.0",
"@release-it/bumper": "^6.0.1",
"@release-it/keep-a-changelog": "^5.0.0",
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^11.1.6",
"@types/node": "^20.12.13",
- "@typescript-eslint/eslint-plugin": "^7.11.0",
- "@typescript-eslint/parser": "^7.11.0",
"c8": "^9.1.0",
"cross-env": "^7.0.3",
- "eslint": "^8.57.0",
- "eslint-config-love": "^47.0.0",
- "eslint-config-standard": "^17.1.0",
+ "eslint": "^9.3.0",
"eslint-define-config": "^2.1.0",
- "eslint-import-resolver-typescript": "^3.6.1",
- "eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsdoc": "^48.2.7",
"eslint-plugin-n": "^17.7.0",
- "eslint-plugin-promise": "^6.2.0",
"eslint-plugin-simple-import-sort": "^12.1.0",
- "eslint-plugin-spellcheck": "^0.0.20",
- "eslint-plugin-tsdoc": "^0.3.0",
"expect": "^29.7.0",
+ "globals": "^15.3.0",
"husky": "^9.0.11",
"lint-staged": "^15.2.5",
"mocha": "^10.4.0",
"mochawesome": "^7.1.3",
+ "neostandard": "^0.5.1",
"prettier": "^3.2.5",
"release-it": "^17.3.0",
"rollup": "^4.18.0",
'@commitlint/config-conventional':
specifier: ^19.2.2
version: 19.2.2
+ '@cspell/eslint-plugin':
+ specifier: ^8.8.3
+ version: 8.8.3(eslint@9.3.0)
+ '@eslint/js':
+ specifier: ^9.3.0
+ version: 9.3.0
'@release-it/bumper':
specifier: ^6.0.1
version: 6.0.1(release-it@17.3.0(typescript@5.4.5))
'@types/node':
specifier: ^20.12.13
version: 20.12.13
- '@typescript-eslint/eslint-plugin':
- specifier: ^7.11.0
- version: 7.11.0(@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
- '@typescript-eslint/parser':
- specifier: ^7.11.0
- version: 7.11.0(eslint@8.57.0)(typescript@5.4.5)
c8:
specifier: ^9.1.0
version: 9.1.0
specifier: ^7.0.3
version: 7.0.3
eslint:
- specifier: ^8.57.0
- version: 8.57.0
- eslint-config-love:
- specifier: ^47.0.0
- version: 47.0.0(@typescript-eslint/eslint-plugin@7.11.0(@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0))(eslint-plugin-n@17.7.0(eslint@8.57.0))(eslint-plugin-promise@6.2.0(eslint@8.57.0))(eslint@8.57.0)(typescript@5.4.5)
- eslint-config-standard:
- specifier: ^17.1.0
- version: 17.1.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0))(eslint-plugin-n@17.7.0(eslint@8.57.0))(eslint-plugin-promise@6.2.0(eslint@8.57.0))(eslint@8.57.0)
+ specifier: ^9.3.0
+ version: 9.3.0
eslint-define-config:
specifier: ^2.1.0
version: 2.1.0
- eslint-import-resolver-typescript:
- specifier: ^3.6.1
- version: 3.6.1(@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0)
- eslint-plugin-import:
- specifier: ^2.29.1
- version: 2.29.1(@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
eslint-plugin-jsdoc:
specifier: ^48.2.7
- version: 48.2.7(eslint@8.57.0)
+ version: 48.2.7(eslint@9.3.0)
eslint-plugin-n:
specifier: ^17.7.0
- version: 17.7.0(eslint@8.57.0)
- eslint-plugin-promise:
- specifier: ^6.2.0
- version: 6.2.0(eslint@8.57.0)
+ version: 17.7.0(eslint@9.3.0)
eslint-plugin-simple-import-sort:
specifier: ^12.1.0
- version: 12.1.0(eslint@8.57.0)
- eslint-plugin-spellcheck:
- specifier: ^0.0.20
- version: 0.0.20(eslint@8.57.0)
- eslint-plugin-tsdoc:
- specifier: ^0.3.0
- version: 0.3.0
+ version: 12.1.0(eslint@9.3.0)
expect:
specifier: ^29.7.0
version: 29.7.0
+ globals:
+ specifier: ^15.3.0
+ version: 15.3.0
husky:
specifier: ^9.0.11
version: 9.0.11
mochawesome:
specifier: ^7.1.3
version: 7.1.3(mocha@10.4.0)
+ neostandard:
+ specifier: ^0.5.1
+ version: 0.5.1(@typescript-eslint/parser@8.0.0-alpha.23(eslint@9.3.0)(typescript@5.4.5))(eslint@9.3.0)(typescript@5.4.5)
prettier:
specifier: ^3.2.5
version: 3.2.5
resolution: {integrity: sha512-tpyc+7i6bPG9mvaBbtKUeghfyZSDgWquIDfMgqYtTbmZ9Y9VzEm2je9EYcQ0aoz5o7NvGS+rcDec93yO08MHYA==}
engines: {node: '>=v18'}
+ '@cspell/cspell-bundled-dicts@8.8.3':
+ resolution: {integrity: sha512-nRa30TQwE4R5xcM6CBibM2l7D359ympexjm7OrykzYmStIiiudDIsuNOIXGBrDouxRFgKGAa/ETo1g+Pxz7kNA==}
+ engines: {node: '>=18'}
+
+ '@cspell/cspell-pipe@8.8.3':
+ resolution: {integrity: sha512-tzngpFKXeUsdTZEErffTlwUnPIKYgyRKy0YTrD77EkhyDSbUnaS8JWqtGZbKV7iQ+R4CL7tiaubPjUzkbWj+kQ==}
+ engines: {node: '>=18'}
+
+ '@cspell/cspell-resolver@8.8.3':
+ resolution: {integrity: sha512-pMOB2MJYeria0DeW1dsehRPIHLzoOXCm1Cdjp1kRZ931PbqNCYaE/GM6laWpUTAbS9Ly2tv4g0jK3PUH8ZTtJA==}
+ engines: {node: '>=18'}
+
+ '@cspell/cspell-service-bus@8.8.3':
+ resolution: {integrity: sha512-QVKe/JZvoTaaBAMXG40HjZib1g6rGgxk03e070GmdfCiMRUCWFtK+9DKVYJfSqjQhzj/eDCrq8aWplHWy66umg==}
+ engines: {node: '>=18'}
+
+ '@cspell/cspell-types@8.8.3':
+ resolution: {integrity: sha512-31wYSBPinhqKi9TSzPg50fWHJmMQwD1d5p26yM/NAfNQvjAfBQlrg4pqix8pxOJkAK5W/TnoaVXjzJ5XCg6arQ==}
+ engines: {node: '>=18'}
+
+ '@cspell/dict-ada@4.0.2':
+ resolution: {integrity: sha512-0kENOWQeHjUlfyId/aCM/mKXtkEgV0Zu2RhUXCBr4hHo9F9vph+Uu8Ww2b0i5a4ZixoIkudGA+eJvyxrG1jUpA==}
+
+ '@cspell/dict-aws@4.0.2':
+ resolution: {integrity: sha512-aNGHWSV7dRLTIn8WJemzLoMF62qOaiUQlgnsCwH5fRCD/00gsWCwg106pnbkmK4AyabyxzneOV4dfecDJWkSxw==}
+
+ '@cspell/dict-bash@4.1.3':
+ resolution: {integrity: sha512-tOdI3QVJDbQSwPjUkOiQFhYcu2eedmX/PtEpVWg0aFps/r6AyjUQINtTgpqMYnYuq8O1QUIQqnpx21aovcgZCw==}
+
+ '@cspell/dict-companies@3.1.2':
+ resolution: {integrity: sha512-OwR5i1xbYuJX7FtHQySmTy3iJtPV1rZQ3jFCxFGwrA1xRQ4rtRcDQ+sTXBCIAoJHkXa84f9J3zsngOKmMGyS/w==}
+
+ '@cspell/dict-cpp@5.1.8':
+ resolution: {integrity: sha512-X5uq0uRqN6cyOZOZV1YKi6g8sBtd0+VoF5NbDWURahGR8TRsiztH0sNqs0IB3X0dW4GakU+n9SXcuEmxynkSsw==}
+
+ '@cspell/dict-cryptocurrencies@5.0.0':
+ resolution: {integrity: sha512-Z4ARIw5+bvmShL+4ZrhDzGhnc9znaAGHOEMaB/GURdS/jdoreEDY34wdN0NtdLHDO5KO7GduZnZyqGdRoiSmYA==}
+
+ '@cspell/dict-csharp@4.0.2':
+ resolution: {integrity: sha512-1JMofhLK+4p4KairF75D3A924m5ERMgd1GvzhwK2geuYgd2ZKuGW72gvXpIV7aGf52E3Uu1kDXxxGAiZ5uVG7g==}
+
+ '@cspell/dict-css@4.0.12':
+ resolution: {integrity: sha512-vGBgPM92MkHQF5/2jsWcnaahOZ+C6OE/fPvd5ScBP72oFY9tn5GLuomcyO0z8vWCr2e0nUSX1OGimPtcQAlvSw==}
+
+ '@cspell/dict-dart@2.0.3':
+ resolution: {integrity: sha512-cLkwo1KT5CJY5N5RJVHks2genFkNCl/WLfj+0fFjqNR+tk3tBI1LY7ldr9piCtSFSm4x9pO1x6IV3kRUY1lLiw==}
+
+ '@cspell/dict-data-science@1.0.11':
+ resolution: {integrity: sha512-TaHAZRVe0Zlcc3C23StZqqbzC0NrodRwoSAc8dis+5qLeLLnOCtagYQeROQvDlcDg3X/VVEO9Whh4W/z4PAmYQ==}
+
+ '@cspell/dict-django@4.1.0':
+ resolution: {integrity: sha512-bKJ4gPyrf+1c78Z0Oc4trEB9MuhcB+Yg+uTTWsvhY6O2ncFYbB/LbEZfqhfmmuK/XJJixXfI1laF2zicyf+l0w==}
+
+ '@cspell/dict-docker@1.1.7':
+ resolution: {integrity: sha512-XlXHAr822euV36GGsl2J1CkBIVg3fZ6879ZOg5dxTIssuhUOCiV2BuzKZmt6aIFmcdPmR14+9i9Xq+3zuxeX0A==}
+
+ '@cspell/dict-dotnet@5.0.2':
+ resolution: {integrity: sha512-UD/pO2A2zia/YZJ8Kck/F6YyDSpCMq0YvItpd4YbtDVzPREfTZ48FjZsbYi4Jhzwfvc6o8R56JusAE58P+4sNQ==}
+
+ '@cspell/dict-elixir@4.0.3':
+ resolution: {integrity: sha512-g+uKLWvOp9IEZvrIvBPTr/oaO6619uH/wyqypqvwpmnmpjcfi8+/hqZH8YNKt15oviK8k4CkINIqNhyndG9d9Q==}
+
+ '@cspell/dict-en-common-misspellings@2.0.1':
+ resolution: {integrity: sha512-uWaP8UG4uvcPyqaG0FzPKCm5kfmhsiiQ45Fs6b3/AEAqfq7Fj1JW0+S3qRt85FQA9SoU6gUJCz9wkK/Ylh7m5A==}
+
+ '@cspell/dict-en-gb@1.1.33':
+ resolution: {integrity: sha512-tKSSUf9BJEV+GJQAYGw5e+ouhEe2ZXE620S7BLKe3ZmpnjlNG9JqlnaBhkIMxKnNFkLY2BP/EARzw31AZnOv4g==}
+
+ '@cspell/dict-en_us@4.3.21':
+ resolution: {integrity: sha512-Bzoo2aS4Pej/MGIFlATpp0wMt9IzVHrhDjdV7FgkAIXbjrOn67ojbTxCgWs8AuCNVfK8lBYGEvs5+ElH1msF8w==}
+
+ '@cspell/dict-filetypes@3.0.4':
+ resolution: {integrity: sha512-IBi8eIVdykoGgIv5wQhOURi5lmCNJq0we6DvqKoPQJHthXbgsuO1qrHSiUVydMiQl/XvcnUWTMeAlVUlUClnVg==}
+
+ '@cspell/dict-fonts@4.0.0':
+ resolution: {integrity: sha512-t9V4GeN/m517UZn63kZPUYP3OQg5f0OBLSd3Md5CU3eH1IFogSvTzHHnz4Wqqbv8NNRiBZ3HfdY/pqREZ6br3Q==}
+
+ '@cspell/dict-fsharp@1.0.1':
+ resolution: {integrity: sha512-23xyPcD+j+NnqOjRHgW3IU7Li912SX9wmeefcY0QxukbAxJ/vAN4rBpjSwwYZeQPAn3fxdfdNZs03fg+UM+4yQ==}
+
+ '@cspell/dict-fullstack@3.1.8':
+ resolution: {integrity: sha512-YRlZupL7uqMCtEBK0bDP9BrcPnjDhz7m4GBqCc1EYqfXauHbLmDT8ELha7T/E7wsFKniHSjzwDZzhNXo2lusRQ==}
+
+ '@cspell/dict-gaming-terms@1.0.5':
+ resolution: {integrity: sha512-C3riccZDD3d9caJQQs1+MPfrUrQ+0KHdlj9iUR1QD92FgTOF6UxoBpvHUUZ9YSezslcmpFQK4xQQ5FUGS7uWfw==}
+
+ '@cspell/dict-git@3.0.0':
+ resolution: {integrity: sha512-simGS/lIiXbEaqJu9E2VPoYW1OTC2xrwPPXNXFMa2uo/50av56qOuaxDrZ5eH1LidFXwoc8HROCHYeKoNrDLSw==}
+
+ '@cspell/dict-golang@6.0.9':
+ resolution: {integrity: sha512-etDt2WQauyEQDA+qPS5QtkYTb2I9l5IfQftAllVoB1aOrT6bxxpHvMEpJ0Hsn/vezxrCqa/BmtUbRxllIxIuSg==}
+
+ '@cspell/dict-google@1.0.1':
+ resolution: {integrity: sha512-dQr4M3n95uOhtloNSgB9tYYGXGGEGEykkFyRtfcp5pFuEecYUa0BSgtlGKx9RXVtJtKgR+yFT/a5uQSlt8WjqQ==}
+
+ '@cspell/dict-haskell@4.0.1':
+ resolution: {integrity: sha512-uRrl65mGrOmwT7NxspB4xKXFUenNC7IikmpRZW8Uzqbqcu7ZRCUfstuVH7T1rmjRgRkjcIjE4PC11luDou4wEQ==}
+
+ '@cspell/dict-html-symbol-entities@4.0.0':
+ resolution: {integrity: sha512-HGRu+48ErJjoweR5IbcixxETRewrBb0uxQBd6xFGcxbEYCX8CnQFTAmKI5xNaIt2PKaZiJH3ijodGSqbKdsxhw==}
+
+ '@cspell/dict-html@4.0.5':
+ resolution: {integrity: sha512-p0brEnRybzSSWi8sGbuVEf7jSTDmXPx7XhQUb5bgG6b54uj+Z0Qf0V2n8b/LWwIPJNd1GygaO9l8k3HTCy1h4w==}
+
+ '@cspell/dict-java@5.0.6':
+ resolution: {integrity: sha512-kdE4AHHHrixyZ5p6zyms1SLoYpaJarPxrz8Tveo6gddszBVVwIUZ+JkQE1bWNLK740GWzIXdkznpUfw1hP9nXw==}
+
+ '@cspell/dict-julia@1.0.1':
+ resolution: {integrity: sha512-4JsCLCRhhLMLiaHpmR7zHFjj1qOauzDI5ZzCNQS31TUMfsOo26jAKDfo0jljFAKgw5M2fEG7sKr8IlPpQAYrmQ==}
+
+ '@cspell/dict-k8s@1.0.5':
+ resolution: {integrity: sha512-Cj+/ZV4S+MKlwfocSJZqe/2UAd/sY8YtlZjbK25VN1nCnrsKrBjfkX29vclwSj1U9aJg4Z9jw/uMjoaKu9ZrpQ==}
+
+ '@cspell/dict-latex@4.0.0':
+ resolution: {integrity: sha512-LPY4y6D5oI7D3d+5JMJHK/wxYTQa2lJMSNxps2JtuF8hbAnBQb3igoWEjEbIbRRH1XBM0X8dQqemnjQNCiAtxQ==}
+
+ '@cspell/dict-lorem-ipsum@4.0.0':
+ resolution: {integrity: sha512-1l3yjfNvMzZPibW8A7mQU4kTozwVZVw0AvFEdy+NcqtbxH+TvbSkNMqROOFWrkD2PjnKG0+Ea0tHI2Pi6Gchnw==}
+
+ '@cspell/dict-lua@4.0.3':
+ resolution: {integrity: sha512-lDHKjsrrbqPaea13+G9s0rtXjMO06gPXPYRjRYawbNmo4E/e3XFfVzeci3OQDQNDmf2cPOwt9Ef5lu2lDmwfJg==}
+
+ '@cspell/dict-makefile@1.0.0':
+ resolution: {integrity: sha512-3W9tHPcSbJa6s0bcqWo6VisEDTSN5zOtDbnPabF7rbyjRpNo0uHXHRJQF8gAbFzoTzBBhgkTmrfSiuyQm7vBUQ==}
+
+ '@cspell/dict-monkeyc@1.0.6':
+ resolution: {integrity: sha512-oO8ZDu/FtZ55aq9Mb67HtaCnsLn59xvhO/t2mLLTHAp667hJFxpp7bCtr2zOrR1NELzFXmKln/2lw/PvxMSvrA==}
+
+ '@cspell/dict-node@5.0.1':
+ resolution: {integrity: sha512-lax/jGz9h3Dv83v8LHa5G0bf6wm8YVRMzbjJPG/9rp7cAGPtdrga+XANFq+B7bY5+jiSA3zvj10LUFCFjnnCCg==}
+
+ '@cspell/dict-npm@5.0.16':
+ resolution: {integrity: sha512-ZWPnLAziEcSCvV0c8k9Qj88pfMu+wZwM5Qks87ShsfBgI8uLZ9tGHravA7gmjH1Gd7Bgxy2ulvXtSqIWPh1lew==}
+
+ '@cspell/dict-php@4.0.7':
+ resolution: {integrity: sha512-SUCOBfRDDFz1E2jnAZIIuy8BNbCc8i+VkiL9g4HH9tTN6Nlww5Uz2pMqYS6rZQkXuubqsbkbPlsRiuseEnTmYA==}
+
+ '@cspell/dict-powershell@5.0.4':
+ resolution: {integrity: sha512-eosDShapDgBWN9ULF7+sRNdUtzRnUdsfEdBSchDm8FZA4HOqxUSZy3b/cX/Rdw0Fnw0AKgk0kzgXw7tS6vwJMQ==}
+
+ '@cspell/dict-public-licenses@2.0.7':
+ resolution: {integrity: sha512-KlBXuGcN3LE7tQi/GEqKiDewWGGuopiAD0zRK1QilOx5Co8XAvs044gk4MNIQftc8r0nHeUI+irJKLGcR36DIQ==}
+
+ '@cspell/dict-python@4.1.11':
+ resolution: {integrity: sha512-XG+v3PumfzUW38huSbfT15Vqt3ihNb462ulfXifpQllPok5OWynhszCLCRQjQReV+dgz784ST4ggRxW452/kVg==}
+
+ '@cspell/dict-r@2.0.1':
+ resolution: {integrity: sha512-KCmKaeYMLm2Ip79mlYPc8p+B2uzwBp4KMkzeLd5E6jUlCL93Y5Nvq68wV5fRLDRTf7N1LvofkVFWfDcednFOgA==}
+
+ '@cspell/dict-ruby@5.0.2':
+ resolution: {integrity: sha512-cIh8KTjpldzFzKGgrqUX4bFyav5lC52hXDKo4LbRuMVncs3zg4hcSf4HtURY+f2AfEZzN6ZKzXafQpThq3dl2g==}
+
+ '@cspell/dict-rust@4.0.3':
+ resolution: {integrity: sha512-8DFCzkFQ+2k3fDaezWc/D+0AyiBBiOGYfSDUfrTNU7wpvUvJ6cRcAUshMI/cn2QW/mmxTspRgVlXsE6GUMz00Q==}
+
+ '@cspell/dict-scala@5.0.2':
+ resolution: {integrity: sha512-v97ClgidZt99JUm7OjhQugDHmhx4U8fcgunHvD/BsXWjXNj4cTr0m0YjofyZoL44WpICsNuFV9F/sv9OM5HUEw==}
+
+ '@cspell/dict-software-terms@3.4.0':
+ resolution: {integrity: sha512-RfrSrvKBaUZ1q3R6eksWe+SMUDNFzAthqXGJuZeylZBO3LdaYdhRDcqFzeMwksfCYjvBYeJ1Ady6NSpdXzESjQ==}
+
+ '@cspell/dict-sql@2.1.3':
+ resolution: {integrity: sha512-SEyTNKJrjqD6PAzZ9WpdSu6P7wgdNtGV2RV8Kpuw1x6bV+YsSptuClYG+JSdRExBTE6LwIe1bTklejUp3ZP8TQ==}
+
+ '@cspell/dict-svelte@1.0.2':
+ resolution: {integrity: sha512-rPJmnn/GsDs0btNvrRBciOhngKV98yZ9SHmg8qI6HLS8hZKvcXc0LMsf9LLuMK1TmS2+WQFAan6qeqg6bBxL2Q==}
+
+ '@cspell/dict-swift@2.0.1':
+ resolution: {integrity: sha512-gxrCMUOndOk7xZFmXNtkCEeroZRnS2VbeaIPiymGRHj5H+qfTAzAKxtv7jJbVA3YYvEzWcVE2oKDP4wcbhIERw==}
+
+ '@cspell/dict-terraform@1.0.0':
+ resolution: {integrity: sha512-Ak+vy4HP/bOgzf06BAMC30+ZvL9mzv21xLM2XtfnBLTDJGdxlk/nK0U6QT8VfFLqJ0ZZSpyOxGsUebWDCTr/zQ==}
+
+ '@cspell/dict-typescript@3.1.5':
+ resolution: {integrity: sha512-EkIwwNV/xqEoBPJml2S16RXj65h1kvly8dfDLgXerrKw6puybZdvAHerAph6/uPTYdtLcsPyJYkPt5ISOJYrtw==}
+
+ '@cspell/dict-vue@3.0.0':
+ resolution: {integrity: sha512-niiEMPWPV9IeRBRzZ0TBZmNnkK3olkOPYxC1Ny2AX4TGlYRajcW0WUtoSHmvvjZNfWLSg2L6ruiBeuPSbjnG6A==}
+
+ '@cspell/dynamic-import@8.8.3':
+ resolution: {integrity: sha512-qpxGC2hGVfbSaLJkaEu//rqbgAOjYnMlbxD75Fk9ny96sr+ZI1YC0nmUErWlgXSbtjVY/DHCOu26Usweo5iRgA==}
+ engines: {node: '>=18.0'}
+
+ '@cspell/eslint-plugin@8.8.3':
+ resolution: {integrity: sha512-N32SkoOa9DoUkfhsaGHg2mZHYUx8Tt0M4d34UAnbbqYEFwYP6wfrAzMhX35vicX1kh1KHeoSUsr5PukUhx8GzQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ eslint: ^7 || ^8 || ^9
+
+ '@cspell/strong-weak-map@8.8.3':
+ resolution: {integrity: sha512-y/pL7Zex8iHQ54qDYvg9oCiCgfZ9DAUTOI/VtPFVC+42JqLx6YufYxJS2uAsFlfAXIPiRV8qnnG6BHImD1Ix6g==}
+ engines: {node: '>=18'}
+
'@es-joy/jsdoccomment@0.43.1':
resolution: {integrity: sha512-I238eDtOolvCuvtxrnqtlBaw0BwdQuYqK7eA6XIonicMdOOOb75mqdIzkGDUbS04+1Di007rgm9snFRNeVrOog==}
engines: {node: '>=16'}
resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
- '@eslint/eslintrc@2.1.4':
- resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ '@eslint/eslintrc@3.1.0':
+ resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@eslint/js@8.57.0':
- resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ '@eslint/js@9.3.0':
+ resolution: {integrity: sha512-niBqk8iwv96+yuTwjM6bWg8ovzAPF9qkICsGtcoa5/dmqcEMfdwNAX7+/OHcJHc7wj7XqPxH98oAHytFYlw6Sw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@humanwhocodes/config-array@0.11.14':
- resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==}
+ '@humanwhocodes/config-array@0.13.0':
+ resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==}
engines: {node: '>=10.10.0'}
'@humanwhocodes/module-importer@1.0.1':
'@humanwhocodes/object-schema@2.0.3':
resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==}
+ '@humanwhocodes/retry@0.3.0':
+ resolution: {integrity: sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==}
+ engines: {node: '>=18.18'}
+
'@iarna/toml@2.2.5':
resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==}
resolution: {integrity: sha512-/gKJun8NNiWGZJkGzI/Ragc53cOdcLNdzjLaIa+GEjguQs0ulsurx8WN0jijdK9yPqDvziX995sMRLyLt1uZMQ==}
engines: {node: '>= 0.4'}
- '@microsoft/tsdoc-config@0.17.0':
- resolution: {integrity: sha512-v/EYRXnCAIHxOHW+Plb6OWuUoMotxTN0GLatnpOb1xq0KuTNw/WI3pamJx/UbsoJP5k9MCw1QxvvhPcF9pH3Zg==}
-
- '@microsoft/tsdoc@0.15.0':
- resolution: {integrity: sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA==}
-
'@nodelib/fs.scandir@2.1.5':
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
'@octokit/types@13.5.0':
resolution: {integrity: sha512-HdqWTf5Z3qwDVlzCrP8UJquMwunpDiMPt5er+QjGzL4hqr/vBVY/MauQgS1xWxCDT1oMx1EULyqxncdCY/NVSQ==}
+ '@pkgr/core@0.1.1':
+ resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==}
+ engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
+
'@pnpm/config.env-replace@1.1.0':
resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==}
engines: {node: '>=12.22.0'}
'@sinonjs/text-encoding@0.7.2':
resolution: {integrity: sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==}
+ '@stylistic/eslint-plugin-js@1.8.1':
+ resolution: {integrity: sha512-c5c2C8Mos5tTQd+NWpqwEu7VT6SSRooAguFPMj1cp2RkTYl1ynKoXo8MWy3k4rkbzoeYHrqC2UlUzsroAN7wtQ==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ peerDependencies:
+ eslint: '>=8.40.0'
+
+ '@stylistic/eslint-plugin-jsx@1.8.1':
+ resolution: {integrity: sha512-k1Eb6rcjMP+mmjvj+vd9y5KUdWn1OBkkPLHXhsrHt5lCDFZxJEs0aVQzE5lpYrtVZVkpc5esTtss/cPJux0lfA==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ peerDependencies:
+ eslint: '>=8.40.0'
+
+ '@stylistic/eslint-plugin-plus@1.8.1':
+ resolution: {integrity: sha512-4+40H3lHYTN8OWz+US8CamVkO+2hxNLp9+CAjorI7top/lHqemhpJvKA1LD9Uh+WMY9DYWiWpL2+SZ2wAXY9fQ==}
+ peerDependencies:
+ eslint: '*'
+
+ '@stylistic/eslint-plugin-ts@1.8.1':
+ resolution: {integrity: sha512-/q1m+ZuO1JHfiSF16EATFzv7XSJkc5W6DocfvH5o9oB6WWYFMF77fVoBWnKT3wGptPOc2hkRupRKhmeFROdfWA==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ peerDependencies:
+ eslint: '>=8.40.0'
+
+ '@stylistic/eslint-plugin@1.8.1':
+ resolution: {integrity: sha512-64My6I7uCcmSQ//427Pfg2vjSf9SDzfsGIWohNFgISMLYdC5BzJqDo647iDDJzSxINh3WTC0Ql46ifiKuOoTyA==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ peerDependencies:
+ eslint: '>=8.40.0'
+
'@szmarczak/http-timer@5.0.1':
resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==}
engines: {node: '>=14.16'}
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
- '@types/json5@0.0.29':
- resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
-
'@types/minimatch@5.1.2':
resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==}
'@types/node@20.12.13':
resolution: {integrity: sha512-gBGeanV41c1L171rR7wjbMiEpEI/l5XFQdLLfhr/REwpgDy/4U8y89+i8kRiLzDyZdOkXh+cRaTetUnCYutoXA==}
+ '@types/semver@7.5.8':
+ resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==}
+
'@types/stack-utils@2.0.3':
resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}
'@types/yargs@17.0.32':
resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==}
- '@typescript-eslint/eslint-plugin@7.11.0':
- resolution: {integrity: sha512-P+qEahbgeHW4JQ/87FuItjBj8O3MYv5gELDzr8QaQ7fsll1gSMTYb6j87MYyxwf3DtD7uGFB9ShwgmCJB5KmaQ==}
- engines: {node: ^18.18.0 || >=20.0.0}
+ '@typescript-eslint/eslint-plugin@8.0.0-alpha.23':
+ resolution: {integrity: sha512-1RvVA8dcAcVo3yco4OGuxWQhlMSmRSz5+8kQnM6mhexbhOlRYUdfokdkJEMFjdN+if3TdlLmZHqvWKTRXkFcLw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
- '@typescript-eslint/parser': ^7.0.0
- eslint: ^8.56.0
+ '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0
+ eslint: ^8.57.0 || ^9.0.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
- '@typescript-eslint/parser@7.11.0':
- resolution: {integrity: sha512-yimw99teuaXVWsBcPO1Ais02kwJ1jmNA1KxE7ng0aT7ndr1pT1wqj0OJnsYVGKKlc4QJai86l/025L6z8CljOg==}
- engines: {node: ^18.18.0 || >=20.0.0}
+ '@typescript-eslint/parser@8.0.0-alpha.23':
+ resolution: {integrity: sha512-vy1+uoRoRNbgeo9up2xT6FZO8gVkTHQVgqEAek4UgFlGq7v5FcXexB5krKT6nuVOkMCKf47R9C6DlPqA8lmCAg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
- eslint: ^8.56.0
+ eslint: ^8.57.0 || ^9.0.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
- '@typescript-eslint/scope-manager@7.11.0':
- resolution: {integrity: sha512-27tGdVEiutD4POirLZX4YzT180vevUURJl4wJGmm6TrQoiYwuxTIY98PBp6L2oN+JQxzE0URvYlzJaBHIekXAw==}
- engines: {node: ^18.18.0 || >=20.0.0}
+ '@typescript-eslint/scope-manager@6.21.0':
+ resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==}
+ engines: {node: ^16.0.0 || >=18.0.0}
- '@typescript-eslint/type-utils@7.11.0':
- resolution: {integrity: sha512-WmppUEgYy+y1NTseNMJ6mCFxt03/7jTOy08bcg7bxJJdsM4nuhnchyBbE8vryveaJUf62noH7LodPSo5Z0WUCg==}
- engines: {node: ^18.18.0 || >=20.0.0}
+ '@typescript-eslint/scope-manager@8.0.0-alpha.23':
+ resolution: {integrity: sha512-36uBn77nnUUCiZZCyQwl0hBjyQv1euVrd0INMDSCv3RxqfB4A9tyzR1GeckJjAYffFCqV5cplXvdAbEJLlHQug==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@typescript-eslint/type-utils@8.0.0-alpha.23':
+ resolution: {integrity: sha512-8Lnp882Bu3ObhadKZmG4XJlY0LTBk1NOWJs4V9YVEDxLCDxVPxSKy2TGmiKlGyMGZyJGBNPlS9+NwODWln79og==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
- eslint: ^8.56.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
+ '@typescript-eslint/types@6.21.0':
+ resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+
'@typescript-eslint/types@7.11.0':
resolution: {integrity: sha512-MPEsDRZTyCiXkD4vd3zywDCifi7tatc4K37KqTprCvaXptP7Xlpdw0NR2hRJTetG5TxbWDB79Ys4kLmHliEo/w==}
engines: {node: ^18.18.0 || >=20.0.0}
- '@typescript-eslint/typescript-estree@7.11.0':
- resolution: {integrity: sha512-cxkhZ2C/iyi3/6U9EPc5y+a6csqHItndvN/CzbNXTNrsC3/ASoYQZEt9uMaEp+xFNjasqQyszp5TumAVKKvJeQ==}
- engines: {node: ^18.18.0 || >=20.0.0}
+ '@typescript-eslint/types@8.0.0-alpha.23':
+ resolution: {integrity: sha512-WU8CewNsW4mPNt4qXaUwqq8WOwI9Ee7CKrMxjHH70v/B0ssiUFdUI8DebJeFUp6snoAdVbeB5yaUJx5iqE9q8w==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@typescript-eslint/typescript-estree@6.21.0':
+ resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==}
+ engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
- '@typescript-eslint/utils@7.11.0':
- resolution: {integrity: sha512-xlAWwPleNRHwF37AhrZurOxA1wyXowW4PqVXZVUNCLjB48CqdPJoJWkrpH2nij9Q3Lb7rtWindtoXwxjxlKKCA==}
- engines: {node: ^18.18.0 || >=20.0.0}
+ '@typescript-eslint/typescript-estree@8.0.0-alpha.23':
+ resolution: {integrity: sha512-pGW2Kbn0GGFJDcH9SoZV3U6Ji9E1wlV+vOdMYaAdcowpS+27cjx/esuVez4+c67cZKz6giUdHSVlnUkxFXg0AQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@typescript-eslint/utils@6.21.0':
+ resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==}
+ engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
- eslint: ^8.56.0
+ eslint: ^7.0.0 || ^8.0.0
- '@typescript-eslint/visitor-keys@7.11.0':
- resolution: {integrity: sha512-7syYk4MzjxTEk0g/w3iqtgxnFQspDJfn6QKD36xMuuhTzjcxY7F8EmBLnALjVyaOF1/bVocu3bS/2/F7rXrveQ==}
- engines: {node: ^18.18.0 || >=20.0.0}
+ '@typescript-eslint/utils@8.0.0-alpha.23':
+ resolution: {integrity: sha512-xSC5+fE/WxYdXJSow3wyJawTKTc3oZonDyH0o/k5da+r171iWFhiUkayK0zQDScEP83VpgkSuwThMUwm9Htkdg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0
- '@ungap/structured-clone@1.2.0':
- resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
+ '@typescript-eslint/visitor-keys@6.21.0':
+ resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+
+ '@typescript-eslint/visitor-keys@8.0.0-alpha.23':
+ resolution: {integrity: sha512-7TGJ++lEfwtsOciFIBDtkDyLMQJMApbam8ErbEHFTBB2En63LOmuBISXLUimLJ+O1WnTP8jf8bixlyrMTzaY7g==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
JSONStream@1.3.5:
resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==}
ajv@6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
- ajv@8.12.0:
- resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==}
-
ajv@8.14.0:
resolution: {integrity: sha512-oYs1UUtO97ZO2lJ4bwnWeQW8/zvOIQLGKcvPTsWmvc2SYgBb+upuNS5NxoLaMU4h8Ju3Nbj6Cq8mD2LQoqVKFA==}
array-ify@1.0.0:
resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==}
- array-includes@3.1.8:
- resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==}
- engines: {node: '>= 0.4'}
+ array-timsort@1.0.3:
+ resolution: {integrity: sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==}
array-union@2.1.0:
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
engines: {node: '>=8'}
- array.prototype.findlastindex@1.2.5:
- resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==}
- engines: {node: '>= 0.4'}
-
- array.prototype.flat@1.3.2:
- resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==}
- engines: {node: '>= 0.4'}
-
- array.prototype.flatmap@1.3.2:
- resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==}
- engines: {node: '>= 0.4'}
-
array.prototype.map@1.0.7:
resolution: {integrity: sha512-XpcFfLoBEAhezrrNw1V+yLXkE7M6uR7xJEsxbG6c/V9v043qurwVJB9r9UTnoSioFDoz1i1VOydpWGmJpfVZbg==}
engines: {node: '>= 0.4'}
resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==}
engines: {node: '>=6'}
+ clear-module@4.1.2:
+ resolution: {integrity: sha512-LWAxzHqdHsAZlPlEyJ2Poz6AIs384mPeqLVCru2p0BrP9G/kVGuhNyZYClLO6cXlnuJjzC8xtsJIuMjKqLXoAw==}
+ engines: {node: '>=8'}
+
cli-boxes@3.0.0:
resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==}
engines: {node: '>=10'}
commander@2.20.3:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
+ comment-json@4.2.3:
+ resolution: {integrity: sha512-SsxdiOf064DWoZLH799Ata6u7iV658A11PlWtZATDlXPpKGJnbJZ5Z24ybixAi+LUUqJ/GKowAejtC5GFUG7Tw==}
+ engines: {node: '>= 6'}
+
comment-parser@1.4.1:
resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==}
engines: {node: '>= 12.0.0'}
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+ core-util-is@1.0.3:
+ resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
+
cosmiconfig-typescript-loader@5.0.0:
resolution: {integrity: sha512-+8cK7jRAReYkMwMiG+bxhcNKiHJDM6bR9FD/nGBXOWdMLuYawjF5cGrtLilJ+LGd3ZjCXnJjR5DkfWPoIVlqJA==}
engines: {node: '>=v16'}
resolution: {integrity: sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==}
engines: {node: '>=12'}
+ cspell-config-lib@8.8.3:
+ resolution: {integrity: sha512-61NKZrzTi9OLEEiZBggLQy9nswgR0gd6bKH06xXFQyRfNpAjaPOzOUFhSSfX1MQX+lQF3KtSYcHpppwbpPsL8w==}
+ engines: {node: '>=18'}
+
+ cspell-dictionary@8.8.3:
+ resolution: {integrity: sha512-g2G3uh8JbuJKAYFdFQENcbTIrK9SJRXBiQ/t+ch+9I/t5HmuGOVe+wxKEM/0c9M2CRLpzJShBvttH9rnw4Yqfg==}
+ engines: {node: '>=18'}
+
+ cspell-glob@8.8.3:
+ resolution: {integrity: sha512-9c4Nw/bIsjKSuBuRrLa1sWtIzbXXvja+FVbUOE9c2IiZfh6K1I+UssiXTbRTMg6qgTdkfT4o3KOcFN0ZcbmCUQ==}
+ engines: {node: '>=18'}
+
+ cspell-grammar@8.8.3:
+ resolution: {integrity: sha512-3RP7xQ/6IiIjbWQDuE+4b0ERKkSWGMY75bd0oEsh5HcFhhOYphmcpxLxRRM/yxYQaYgdvq0QIcwrpanx86KJ7A==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ cspell-io@8.8.3:
+ resolution: {integrity: sha512-vO7BUa6i7tjmQr+9dw/Ic7tm4ECnSUlbuMv0zJs/SIrO9AcID2pCWPeZNZEGAmeutrEOi2iThZ/uS33aCuv7Jw==}
+ engines: {node: '>=18'}
+
+ cspell-lib@8.8.3:
+ resolution: {integrity: sha512-IqtTKBPug5Jzt9T8f/b6qGAbARRR5tpQkLjzsrfLzxM68ery23wEPDtmWToEyc9EslulZGLe0T78XuEU9AMF+g==}
+ engines: {node: '>=18'}
+
+ cspell-trie-lib@8.8.3:
+ resolution: {integrity: sha512-0zrkrhrFLVajwo6++XD9a+r0Olml7UjPgbztjPKbXIJrZCradBF5rvt3wq5mPpsjq2+Dz0z6K5muZpbO+gqapQ==}
+ engines: {node: '>=18'}
+
dargs@8.1.0:
resolution: {integrity: sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==}
engines: {node: '>=12'}
dateformat@4.6.3:
resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==}
- debug@3.2.7:
- resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
- peerDependencies:
- supports-color: '*'
- peerDependenciesMeta:
- supports-color:
- optional: true
-
debug@4.3.4:
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
engines: {node: '>=6.0'}
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
engines: {node: '>=8'}
- doctrine@2.1.0:
- resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
- engines: {node: '>=0.10.0'}
-
- doctrine@3.0.0:
- resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
- engines: {node: '>=6.0.0'}
-
dot-prop@5.3.0:
resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==}
engines: {node: '>=8'}
resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
engines: {node: '>=6'}
+ env-paths@3.0.0:
+ resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
error-ex@1.3.2:
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==}
engines: {node: '>= 0.4'}
- es-shim-unscopables@1.0.2:
- resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==}
-
es-to-primitive@1.2.1:
resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==}
engines: {node: '>= 0.4'}
peerDependencies:
eslint: '>=6.0.0'
- eslint-config-love@47.0.0:
- resolution: {integrity: sha512-wIeJhb4/NF7nE5Ltppg1e9dp1Auxx0+ZPRysrXQ3uBKlW4Nj/UiTZu4r3sKWCxo6HGcRcI4MC1Q5421y3fny2w==}
- peerDependencies:
- '@typescript-eslint/eslint-plugin': ^7.0.1
- eslint: ^8.0.1
- eslint-plugin-import: ^2.25.2
- eslint-plugin-n: '^15.0.0 || ^16.0.0 '
- eslint-plugin-promise: ^6.0.0
- typescript: '*'
-
- eslint-config-standard@17.1.0:
- resolution: {integrity: sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==}
- engines: {node: '>=12.0.0'}
- peerDependencies:
- eslint: ^8.0.1
- eslint-plugin-import: ^2.25.2
- eslint-plugin-n: '^15.0.0 || ^16.0.0 '
- eslint-plugin-promise: ^6.0.0
-
eslint-define-config@2.1.0:
resolution: {integrity: sha512-QUp6pM9pjKEVannNAbSJNeRuYwW3LshejfyBBpjeMGaJjaDUpVps4C6KVR8R7dWZnD3i0synmrE36znjTkJvdQ==}
engines: {node: '>=18.0.0', npm: '>=9.0.0', pnpm: '>=8.6.0'}
- eslint-import-resolver-node@0.3.9:
- resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
-
- eslint-import-resolver-typescript@3.6.1:
- resolution: {integrity: sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==}
- engines: {node: ^14.18.0 || >=16.0.0}
- peerDependencies:
- eslint: '*'
- eslint-plugin-import: '*'
-
- eslint-module-utils@2.8.1:
- resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==}
- engines: {node: '>=4'}
- peerDependencies:
- '@typescript-eslint/parser': '*'
- eslint: '*'
- eslint-import-resolver-node: '*'
- eslint-import-resolver-typescript: '*'
- eslint-import-resolver-webpack: '*'
- peerDependenciesMeta:
- '@typescript-eslint/parser':
- optional: true
- eslint:
- optional: true
- eslint-import-resolver-node:
- optional: true
- eslint-import-resolver-typescript:
- optional: true
- eslint-import-resolver-webpack:
- optional: true
-
eslint-plugin-es-x@7.6.0:
resolution: {integrity: sha512-I0AmeNgevgaTR7y2lrVCJmGYF0rjoznpDvqV/kIkZSZbZ8Rw3eu4cGlvBBULScfkSOCzqKbff5LR4CNrV7mZHA==}
engines: {node: ^14.18.0 || >=16.0.0}
peerDependencies:
eslint: '>=8'
- eslint-plugin-import@2.29.1:
- resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==}
- engines: {node: '>=4'}
- peerDependencies:
- '@typescript-eslint/parser': '*'
- eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
- peerDependenciesMeta:
- '@typescript-eslint/parser':
- optional: true
-
eslint-plugin-jsdoc@48.2.7:
resolution: {integrity: sha512-fYj3roTnkFL9OFFTB129rico8lerC5G8Vp2ZW9SjO9RNWG0exVvI+i/Y8Bpm1ufjR0uvT38xtoab/U0Hp8Ybog==}
engines: {node: '>=18'}
peerDependencies:
eslint: '>=8.23.0'
- eslint-plugin-promise@6.2.0:
- resolution: {integrity: sha512-QmAqwizauvnKOlifxyDj2ObfULpHQawlg/zQdgEixur9vl0CvZGv/LCJV2rtj3210QCoeGBzVMfMXqGAOr/4fA==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
- peerDependencies:
- eslint: ^7.0.0 || ^8.0.0 || ^9.0.0
-
eslint-plugin-simple-import-sort@12.1.0:
resolution: {integrity: sha512-Y2fqAfC11TcG/WP3TrI1Gi3p3nc8XJyEOJYHyEPEGI/UAgNx6akxxlX74p7SbAQdLcgASKhj8M0GKvH3vq/+ig==}
peerDependencies:
eslint: '>=5.0.0'
- eslint-plugin-spellcheck@0.0.20:
- resolution: {integrity: sha512-GJa6vgzWAYqe0elKADAsiBRrhvqBnKyt7tpFSqlCZJsK2W9+K80oMyHhKolA7vJ13H5RCGs5/KCN+mKUyKoAiA==}
- peerDependencies:
- eslint: '>=0.8.0'
-
- eslint-plugin-tsdoc@0.3.0:
- resolution: {integrity: sha512-0MuFdBrrJVBjT/gyhkP2BqpD0np1NxNLfQ38xXDlSs/KVVpKI2A6vN7jx2Rve/CyUsvOsMGwp9KKrinv7q9g3A==}
-
- eslint-scope@7.2.2:
- resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ eslint-scope@8.0.1:
+ resolution: {integrity: sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
eslint-visitor-keys@3.4.3:
resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
- eslint@8.57.0:
- resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==}
- engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ eslint-visitor-keys@4.0.0:
+ resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ eslint@9.3.0:
+ resolution: {integrity: sha512-5Iv4CsZW030lpUqHBapdPo3MJetAPtejVW8B84GIcIIv8+ohFaddXsrn1Gn8uD9ijDb+kcYKFUVmC8qG8B2ORQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
hasBin: true
+ espree@10.0.1:
+ resolution: {integrity: sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
espree@9.6.1:
resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
estree-walker@2.0.2:
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
+ estree-walker@3.0.3:
+ resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
+
esutils@2.0.3:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+ fast-equals@5.0.1:
+ resolution: {integrity: sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==}
+ engines: {node: '>=6.0.0'}
+
fast-glob@3.3.2:
resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
engines: {node: '>=8.6.0'}
resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
engines: {node: ^12.20 || >= 14.13}
- file-entry-cache@6.0.1:
- resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
- engines: {node: ^10.12.0 || >=12.0.0}
+ file-entry-cache@8.0.0:
+ resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
+ engines: {node: '>=16.0.0'}
fill-range@7.1.1:
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
resolution: {integrity: sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==}
engines: {node: '>=18'}
- flat-cache@3.2.0:
- resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==}
- engines: {node: ^10.12.0 || >=12.0.0}
+ flat-cache@4.0.1:
+ resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
+ engines: {node: '>=16'}
flat@5.0.2:
resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==}
functions-have-names@1.2.3:
resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
+ gensequence@7.0.0:
+ resolution: {integrity: sha512-47Frx13aZh01afHJTB3zTtKIlFI6vWY+MYCN9Qpew6i52rfKjnhCF/l1YlC8UmEMvvntZZ6z4PiCcmyuedR2aQ==}
+ engines: {node: '>=18'}
+
get-caller-file@2.0.5:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==}
engines: {node: '>=10'}
- globals@13.24.0:
- resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
- engines: {node: '>=8'}
+ globals@14.0.0:
+ resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
+ engines: {node: '>=18'}
globals@15.3.0:
resolution: {integrity: sha512-cCdyVjIUVTtX8ZsPkq1oCsOsLmGIswqnjZYMJJTGaNApj1yHtLSymKhwH51ttirREn75z3p4k051clwg7rvNKA==}
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
+ has-own-prop@2.0.0:
+ resolution: {integrity: sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==}
+ engines: {node: '>=8'}
+
has-property-descriptors@1.0.2:
resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
engines: {node: '>=16.17.0'}
- hunspell-spellchecker@1.0.2:
- resolution: {integrity: sha512-4DwmFAvlz+ChsqLDsZT2cwBsYNXh+oWboemxXtafwKIyItq52xfR4e4kr017sLAoPaSYVofSOvPUfmOAhXyYvw==}
- hasBin: true
-
husky@9.0.11:
resolution: {integrity: sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw==}
engines: {node: '>=18'}
resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==}
hasBin: true
- jju@1.4.0:
- resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
-
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
json-stringify-safe@5.0.1:
resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==}
- json5@1.0.2:
- resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==}
- hasBin: true
-
jsonc-parser@3.2.1:
resolution: {integrity: sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==}
resolution: {integrity: sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==}
engines: {node: '>=10'}
+ minimatch@9.0.3:
+ resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==}
+ engines: {node: '>=16 || 14 >=14.17'}
+
minimatch@9.0.4:
resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==}
engines: {node: '>=16 || 14 >=14.17'}
natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+ neostandard@0.5.1:
+ resolution: {integrity: sha512-PaeGRlEyc0EQ0a5ORPZurasGhjfdgFB2TLGyTAnl7Vj1xerZ3vgT5NFdbaVAb1PtoT/HOFtOajYAUguNl9hDew==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ hasBin: true
+ peerDependencies:
+ eslint: ^9.0.0
+
netmask@2.0.2:
resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==}
engines: {node: '>= 0.4.0'}
resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==}
engines: {node: '>= 0.4'}
- object.fromentries@2.0.8:
- resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==}
- engines: {node: '>= 0.4'}
-
- object.groupby@1.0.3:
- resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==}
- engines: {node: '>= 0.4'}
-
- object.values@1.2.0:
- resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==}
- engines: {node: '>= 0.4'}
-
once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
+ parent-module@2.0.0:
+ resolution: {integrity: sha512-uo0Z9JJeWzv8BG+tRcapBKNJ0dro9cLyczGzulS6EfeyAdeC9sbojtW6XwvYxJkEne9En+J2XEl4zyglVeIwFg==}
+ engines: {node: '>=8'}
+
parse-json@5.2.0:
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
engines: {node: '>=8'}
resolution: {integrity: sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==}
engines: {node: '>=12'}
+ peowly@1.3.0:
+ resolution: {integrity: sha512-Tvj2QMNEuvL3WmaG4agZ6IGjOLGcvQSQO9TBJFkh9op+tNX3/J3UZtxPQWUA+d+Lki4u8WaNJ0OUwNt1G3GnWg==}
+ engines: {node: '>=18.6.0'}
+
picocolors@1.0.1:
resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
+ picomatch@4.0.2:
+ resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
+ engines: {node: '>=12'}
+
pidtree@0.6.0:
resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==}
engines: {node: '>=0.10'}
engines: {node: ^18.18.0 || ^20.8.0 || ^22.0.0}
hasBin: true
+ repeat-string@1.6.1:
+ resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==}
+ engines: {node: '>=0.10'}
+
require-directory@2.1.1:
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
engines: {node: '>=0.10.0'}
resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
engines: {node: '>=12'}
- strip-bom@3.0.0:
- resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
- engines: {node: '>=4'}
-
strip-final-newline@2.0.0:
resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
engines: {node: '>=6'}
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
+ synckit@0.9.0:
+ resolution: {integrity: sha512-7RnqIMq572L8PeEzKeBINYEJDDxpcH8JEgLwUqBd3TkofhFRbkq4QLR0u+36avGAhCRbk2nnmjcW9SE531hPDg==}
+ engines: {node: ^14.18.0 || >=16.0.0}
+
tapable@2.2.1:
resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
engines: {node: '>=6'}
peerDependencies:
typescript: '>=4.2.0'
- tsconfig-paths@3.15.0:
- resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==}
-
tslib@2.6.2:
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
engines: {node: '>=4'}
- type-fest@0.20.2:
- resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
- engines: {node: '>=10'}
-
type-fest@0.21.3:
resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
engines: {node: '>=10'}
peerDependencies:
typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x
+ typescript-eslint@8.0.0-alpha.23:
+ resolution: {integrity: sha512-9z27xLf8JrrUZKZxHYfKuuw0WWroQ+iOg53EMzBJTr16RrNYMUA5rE4QMZm3J80OTQV2MByLAIN9WnDlNLxLgQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
typescript@5.4.5:
resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==}
engines: {node: '>=14.17'}
resolution: {integrity: sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==}
engines: {node: '>= 0.10'}
+ vscode-languageserver-textdocument@1.0.11:
+ resolution: {integrity: sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==}
+
vscode-oniguruma@1.7.0:
resolution: {integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==}
vscode-textmate@8.0.0:
resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==}
+ vscode-uri@3.0.8:
+ resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==}
+
wcwidth@1.0.1:
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
'@types/conventional-commits-parser': 5.0.0
chalk: 5.3.0
- '@es-joy/jsdoccomment@0.43.1':
+ '@cspell/cspell-bundled-dicts@8.8.3':
+ dependencies:
+ '@cspell/dict-ada': 4.0.2
+ '@cspell/dict-aws': 4.0.2
+ '@cspell/dict-bash': 4.1.3
+ '@cspell/dict-companies': 3.1.2
+ '@cspell/dict-cpp': 5.1.8
+ '@cspell/dict-cryptocurrencies': 5.0.0
+ '@cspell/dict-csharp': 4.0.2
+ '@cspell/dict-css': 4.0.12
+ '@cspell/dict-dart': 2.0.3
+ '@cspell/dict-django': 4.1.0
+ '@cspell/dict-docker': 1.1.7
+ '@cspell/dict-dotnet': 5.0.2
+ '@cspell/dict-elixir': 4.0.3
+ '@cspell/dict-en-common-misspellings': 2.0.1
+ '@cspell/dict-en-gb': 1.1.33
+ '@cspell/dict-en_us': 4.3.21
+ '@cspell/dict-filetypes': 3.0.4
+ '@cspell/dict-fonts': 4.0.0
+ '@cspell/dict-fsharp': 1.0.1
+ '@cspell/dict-fullstack': 3.1.8
+ '@cspell/dict-gaming-terms': 1.0.5
+ '@cspell/dict-git': 3.0.0
+ '@cspell/dict-golang': 6.0.9
+ '@cspell/dict-google': 1.0.1
+ '@cspell/dict-haskell': 4.0.1
+ '@cspell/dict-html': 4.0.5
+ '@cspell/dict-html-symbol-entities': 4.0.0
+ '@cspell/dict-java': 5.0.6
+ '@cspell/dict-julia': 1.0.1
+ '@cspell/dict-k8s': 1.0.5
+ '@cspell/dict-latex': 4.0.0
+ '@cspell/dict-lorem-ipsum': 4.0.0
+ '@cspell/dict-lua': 4.0.3
+ '@cspell/dict-makefile': 1.0.0
+ '@cspell/dict-monkeyc': 1.0.6
+ '@cspell/dict-node': 5.0.1
+ '@cspell/dict-npm': 5.0.16
+ '@cspell/dict-php': 4.0.7
+ '@cspell/dict-powershell': 5.0.4
+ '@cspell/dict-public-licenses': 2.0.7
+ '@cspell/dict-python': 4.1.11
+ '@cspell/dict-r': 2.0.1
+ '@cspell/dict-ruby': 5.0.2
+ '@cspell/dict-rust': 4.0.3
+ '@cspell/dict-scala': 5.0.2
+ '@cspell/dict-software-terms': 3.4.0
+ '@cspell/dict-sql': 2.1.3
+ '@cspell/dict-svelte': 1.0.2
+ '@cspell/dict-swift': 2.0.1
+ '@cspell/dict-terraform': 1.0.0
+ '@cspell/dict-typescript': 3.1.5
+ '@cspell/dict-vue': 3.0.0
+
+ '@cspell/cspell-pipe@8.8.3': {}
+
+ '@cspell/cspell-resolver@8.8.3':
dependencies:
- '@types/eslint': 8.56.10
- '@types/estree': 1.0.5
- '@typescript-eslint/types': 7.11.0
- comment-parser: 1.4.1
- esquery: 1.5.0
- jsdoc-type-pratt-parser: 4.0.0
+ global-directory: 4.0.1
+
+ '@cspell/cspell-service-bus@8.8.3': {}
+
+ '@cspell/cspell-types@8.8.3': {}
+
+ '@cspell/dict-ada@4.0.2': {}
+
+ '@cspell/dict-aws@4.0.2': {}
+
+ '@cspell/dict-bash@4.1.3': {}
+
+ '@cspell/dict-companies@3.1.2': {}
+
+ '@cspell/dict-cpp@5.1.8': {}
+
+ '@cspell/dict-cryptocurrencies@5.0.0': {}
+
+ '@cspell/dict-csharp@4.0.2': {}
+
+ '@cspell/dict-css@4.0.12': {}
+
+ '@cspell/dict-dart@2.0.3': {}
+
+ '@cspell/dict-data-science@1.0.11': {}
+
+ '@cspell/dict-django@4.1.0': {}
+
+ '@cspell/dict-docker@1.1.7': {}
+
+ '@cspell/dict-dotnet@5.0.2': {}
+
+ '@cspell/dict-elixir@4.0.3': {}
+
+ '@cspell/dict-en-common-misspellings@2.0.1': {}
+
+ '@cspell/dict-en-gb@1.1.33': {}
+
+ '@cspell/dict-en_us@4.3.21': {}
+
+ '@cspell/dict-filetypes@3.0.4': {}
+
+ '@cspell/dict-fonts@4.0.0': {}
+
+ '@cspell/dict-fsharp@1.0.1': {}
+
+ '@cspell/dict-fullstack@3.1.8': {}
+
+ '@cspell/dict-gaming-terms@1.0.5': {}
+
+ '@cspell/dict-git@3.0.0': {}
+
+ '@cspell/dict-golang@6.0.9': {}
+
+ '@cspell/dict-google@1.0.1': {}
+
+ '@cspell/dict-haskell@4.0.1': {}
+
+ '@cspell/dict-html-symbol-entities@4.0.0': {}
+
+ '@cspell/dict-html@4.0.5': {}
+
+ '@cspell/dict-java@5.0.6': {}
+
+ '@cspell/dict-julia@1.0.1': {}
+
+ '@cspell/dict-k8s@1.0.5': {}
+
+ '@cspell/dict-latex@4.0.0': {}
+
+ '@cspell/dict-lorem-ipsum@4.0.0': {}
+
+ '@cspell/dict-lua@4.0.3': {}
+
+ '@cspell/dict-makefile@1.0.0': {}
+
+ '@cspell/dict-monkeyc@1.0.6': {}
+
+ '@cspell/dict-node@5.0.1': {}
- '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)':
+ '@cspell/dict-npm@5.0.16': {}
+
+ '@cspell/dict-php@4.0.7': {}
+
+ '@cspell/dict-powershell@5.0.4': {}
+
+ '@cspell/dict-public-licenses@2.0.7': {}
+
+ '@cspell/dict-python@4.1.11':
+ dependencies:
+ '@cspell/dict-data-science': 1.0.11
+
+ '@cspell/dict-r@2.0.1': {}
+
+ '@cspell/dict-ruby@5.0.2': {}
+
+ '@cspell/dict-rust@4.0.3': {}
+
+ '@cspell/dict-scala@5.0.2': {}
+
+ '@cspell/dict-software-terms@3.4.0': {}
+
+ '@cspell/dict-sql@2.1.3': {}
+
+ '@cspell/dict-svelte@1.0.2': {}
+
+ '@cspell/dict-swift@2.0.1': {}
+
+ '@cspell/dict-terraform@1.0.0': {}
+
+ '@cspell/dict-typescript@3.1.5': {}
+
+ '@cspell/dict-vue@3.0.0': {}
+
+ '@cspell/dynamic-import@8.8.3':
+ dependencies:
+ import-meta-resolve: 4.1.0
+
+ '@cspell/eslint-plugin@8.8.3(eslint@9.3.0)':
dependencies:
- eslint: 8.57.0
+ '@cspell/cspell-types': 8.8.3
+ cspell-lib: 8.8.3
+ eslint: 9.3.0
+ estree-walker: 3.0.3
+ synckit: 0.9.0
+
+ '@cspell/strong-weak-map@8.8.3': {}
+
+ '@es-joy/jsdoccomment@0.43.1':
+ dependencies:
+ '@types/eslint': 8.56.10
+ '@types/estree': 1.0.5
+ '@typescript-eslint/types': 7.11.0
+ comment-parser: 1.4.1
+ esquery: 1.5.0
+ jsdoc-type-pratt-parser: 4.0.0
+
+ '@eslint-community/eslint-utils@4.4.0(eslint@9.3.0)':
+ dependencies:
+ eslint: 9.3.0
eslint-visitor-keys: 3.4.3
'@eslint-community/regexpp@4.10.0': {}
- '@eslint/eslintrc@2.1.4':
+ '@eslint/eslintrc@3.1.0':
dependencies:
ajv: 6.12.6
debug: 4.3.4(supports-color@8.1.1)
- espree: 9.6.1
- globals: 13.24.0
+ espree: 10.0.1
+ globals: 14.0.0
ignore: 5.3.1
import-fresh: 3.3.0
js-yaml: 4.1.0
transitivePeerDependencies:
- supports-color
- '@eslint/js@8.57.0': {}
+ '@eslint/js@9.3.0': {}
- '@humanwhocodes/config-array@0.11.14':
+ '@humanwhocodes/config-array@0.13.0':
dependencies:
'@humanwhocodes/object-schema': 2.0.3
debug: 4.3.4(supports-color@8.1.1)
'@humanwhocodes/object-schema@2.0.3': {}
+ '@humanwhocodes/retry@0.3.0': {}
+
'@iarna/toml@2.2.5': {}
'@inquirer/figures@1.0.2': {}
dependencies:
call-bind: 1.0.7
- '@microsoft/tsdoc-config@0.17.0':
- dependencies:
- '@microsoft/tsdoc': 0.15.0
- ajv: 8.12.0
- jju: 1.4.0
- resolve: 1.22.8
-
- '@microsoft/tsdoc@0.15.0': {}
-
'@nodelib/fs.scandir@2.1.5':
dependencies:
'@nodelib/fs.stat': 2.0.5
dependencies:
'@octokit/openapi-types': 22.2.0
+ '@pkgr/core@0.1.1': {}
+
'@pnpm/config.env-replace@1.1.0': {}
'@pnpm/network.ca-file@1.0.2':
'@sinonjs/text-encoding@0.7.2': {}
+ '@stylistic/eslint-plugin-js@1.8.1(eslint@9.3.0)':
+ dependencies:
+ '@types/eslint': 8.56.10
+ acorn: 8.11.3
+ escape-string-regexp: 4.0.0
+ eslint: 9.3.0
+ eslint-visitor-keys: 3.4.3
+ espree: 9.6.1
+
+ '@stylistic/eslint-plugin-jsx@1.8.1(eslint@9.3.0)':
+ dependencies:
+ '@stylistic/eslint-plugin-js': 1.8.1(eslint@9.3.0)
+ '@types/eslint': 8.56.10
+ eslint: 9.3.0
+ estraverse: 5.3.0
+ picomatch: 4.0.2
+
+ '@stylistic/eslint-plugin-plus@1.8.1(eslint@9.3.0)(typescript@5.4.5)':
+ dependencies:
+ '@types/eslint': 8.56.10
+ '@typescript-eslint/utils': 6.21.0(eslint@9.3.0)(typescript@5.4.5)
+ eslint: 9.3.0
+ transitivePeerDependencies:
+ - supports-color
+ - typescript
+
+ '@stylistic/eslint-plugin-ts@1.8.1(eslint@9.3.0)(typescript@5.4.5)':
+ dependencies:
+ '@stylistic/eslint-plugin-js': 1.8.1(eslint@9.3.0)
+ '@types/eslint': 8.56.10
+ '@typescript-eslint/utils': 6.21.0(eslint@9.3.0)(typescript@5.4.5)
+ eslint: 9.3.0
+ transitivePeerDependencies:
+ - supports-color
+ - typescript
+
+ '@stylistic/eslint-plugin@1.8.1(eslint@9.3.0)(typescript@5.4.5)':
+ dependencies:
+ '@stylistic/eslint-plugin-js': 1.8.1(eslint@9.3.0)
+ '@stylistic/eslint-plugin-jsx': 1.8.1(eslint@9.3.0)
+ '@stylistic/eslint-plugin-plus': 1.8.1(eslint@9.3.0)(typescript@5.4.5)
+ '@stylistic/eslint-plugin-ts': 1.8.1(eslint@9.3.0)(typescript@5.4.5)
+ '@types/eslint': 8.56.10
+ eslint: 9.3.0
+ transitivePeerDependencies:
+ - supports-color
+ - typescript
+
'@szmarczak/http-timer@5.0.1':
dependencies:
defer-to-connect: 2.0.1
'@types/json-schema@7.0.15': {}
- '@types/json5@0.0.29': {}
-
'@types/minimatch@5.1.2': {}
'@types/node@20.12.13':
dependencies:
undici-types: 5.26.5
+ '@types/semver@7.5.8': {}
+
'@types/stack-utils@2.0.3': {}
'@types/yargs-parser@21.0.3': {}
dependencies:
'@types/yargs-parser': 21.0.3
- '@typescript-eslint/eslint-plugin@7.11.0(@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)':
+ '@typescript-eslint/eslint-plugin@8.0.0-alpha.23(@typescript-eslint/parser@8.0.0-alpha.23(eslint@9.3.0)(typescript@5.4.5))(eslint@9.3.0)(typescript@5.4.5)':
dependencies:
'@eslint-community/regexpp': 4.10.0
- '@typescript-eslint/parser': 7.11.0(eslint@8.57.0)(typescript@5.4.5)
- '@typescript-eslint/scope-manager': 7.11.0
- '@typescript-eslint/type-utils': 7.11.0(eslint@8.57.0)(typescript@5.4.5)
- '@typescript-eslint/utils': 7.11.0(eslint@8.57.0)(typescript@5.4.5)
- '@typescript-eslint/visitor-keys': 7.11.0
- eslint: 8.57.0
+ '@typescript-eslint/parser': 8.0.0-alpha.23(eslint@9.3.0)(typescript@5.4.5)
+ '@typescript-eslint/scope-manager': 8.0.0-alpha.23
+ '@typescript-eslint/type-utils': 8.0.0-alpha.23(eslint@9.3.0)(typescript@5.4.5)
+ '@typescript-eslint/utils': 8.0.0-alpha.23(eslint@9.3.0)(typescript@5.4.5)
+ '@typescript-eslint/visitor-keys': 8.0.0-alpha.23
+ eslint: 9.3.0
graphemer: 1.4.0
ignore: 5.3.1
natural-compare: 1.4.0
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5)':
+ '@typescript-eslint/parser@8.0.0-alpha.23(eslint@9.3.0)(typescript@5.4.5)':
dependencies:
- '@typescript-eslint/scope-manager': 7.11.0
- '@typescript-eslint/types': 7.11.0
- '@typescript-eslint/typescript-estree': 7.11.0(typescript@5.4.5)
- '@typescript-eslint/visitor-keys': 7.11.0
+ '@typescript-eslint/scope-manager': 8.0.0-alpha.23
+ '@typescript-eslint/types': 8.0.0-alpha.23
+ '@typescript-eslint/typescript-estree': 8.0.0-alpha.23(typescript@5.4.5)
+ '@typescript-eslint/visitor-keys': 8.0.0-alpha.23
debug: 4.3.4(supports-color@8.1.1)
- eslint: 8.57.0
+ eslint: 9.3.0
optionalDependencies:
typescript: 5.4.5
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/scope-manager@7.11.0':
+ '@typescript-eslint/scope-manager@6.21.0':
dependencies:
- '@typescript-eslint/types': 7.11.0
- '@typescript-eslint/visitor-keys': 7.11.0
+ '@typescript-eslint/types': 6.21.0
+ '@typescript-eslint/visitor-keys': 6.21.0
- '@typescript-eslint/type-utils@7.11.0(eslint@8.57.0)(typescript@5.4.5)':
+ '@typescript-eslint/scope-manager@8.0.0-alpha.23':
dependencies:
- '@typescript-eslint/typescript-estree': 7.11.0(typescript@5.4.5)
- '@typescript-eslint/utils': 7.11.0(eslint@8.57.0)(typescript@5.4.5)
+ '@typescript-eslint/types': 8.0.0-alpha.23
+ '@typescript-eslint/visitor-keys': 8.0.0-alpha.23
+
+ '@typescript-eslint/type-utils@8.0.0-alpha.23(eslint@9.3.0)(typescript@5.4.5)':
+ dependencies:
+ '@typescript-eslint/typescript-estree': 8.0.0-alpha.23(typescript@5.4.5)
+ '@typescript-eslint/utils': 8.0.0-alpha.23(eslint@9.3.0)(typescript@5.4.5)
debug: 4.3.4(supports-color@8.1.1)
- eslint: 8.57.0
ts-api-utils: 1.3.0(typescript@5.4.5)
optionalDependencies:
typescript: 5.4.5
transitivePeerDependencies:
+ - eslint
- supports-color
+ '@typescript-eslint/types@6.21.0': {}
+
'@typescript-eslint/types@7.11.0': {}
- '@typescript-eslint/typescript-estree@7.11.0(typescript@5.4.5)':
+ '@typescript-eslint/types@8.0.0-alpha.23': {}
+
+ '@typescript-eslint/typescript-estree@6.21.0(typescript@5.4.5)':
dependencies:
- '@typescript-eslint/types': 7.11.0
- '@typescript-eslint/visitor-keys': 7.11.0
+ '@typescript-eslint/types': 6.21.0
+ '@typescript-eslint/visitor-keys': 6.21.0
+ debug: 4.3.4(supports-color@8.1.1)
+ globby: 11.1.0
+ is-glob: 4.0.3
+ minimatch: 9.0.3
+ semver: 7.6.2
+ ts-api-utils: 1.3.0(typescript@5.4.5)
+ optionalDependencies:
+ typescript: 5.4.5
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/typescript-estree@8.0.0-alpha.23(typescript@5.4.5)':
+ dependencies:
+ '@typescript-eslint/types': 8.0.0-alpha.23
+ '@typescript-eslint/visitor-keys': 8.0.0-alpha.23
debug: 4.3.4(supports-color@8.1.1)
globby: 11.1.0
is-glob: 4.0.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/utils@7.11.0(eslint@8.57.0)(typescript@5.4.5)':
+ '@typescript-eslint/utils@6.21.0(eslint@9.3.0)(typescript@5.4.5)':
dependencies:
- '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
- '@typescript-eslint/scope-manager': 7.11.0
- '@typescript-eslint/types': 7.11.0
- '@typescript-eslint/typescript-estree': 7.11.0(typescript@5.4.5)
- eslint: 8.57.0
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.3.0)
+ '@types/json-schema': 7.0.15
+ '@types/semver': 7.5.8
+ '@typescript-eslint/scope-manager': 6.21.0
+ '@typescript-eslint/types': 6.21.0
+ '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.5)
+ eslint: 9.3.0
+ semver: 7.6.2
transitivePeerDependencies:
- supports-color
- typescript
- '@typescript-eslint/visitor-keys@7.11.0':
+ '@typescript-eslint/utils@8.0.0-alpha.23(eslint@9.3.0)(typescript@5.4.5)':
dependencies:
- '@typescript-eslint/types': 7.11.0
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.3.0)
+ '@typescript-eslint/scope-manager': 8.0.0-alpha.23
+ '@typescript-eslint/types': 8.0.0-alpha.23
+ '@typescript-eslint/typescript-estree': 8.0.0-alpha.23(typescript@5.4.5)
+ eslint: 9.3.0
+ transitivePeerDependencies:
+ - supports-color
+ - typescript
+
+ '@typescript-eslint/visitor-keys@6.21.0':
+ dependencies:
+ '@typescript-eslint/types': 6.21.0
eslint-visitor-keys: 3.4.3
- '@ungap/structured-clone@1.2.0': {}
+ '@typescript-eslint/visitor-keys@8.0.0-alpha.23':
+ dependencies:
+ '@typescript-eslint/types': 8.0.0-alpha.23
+ eslint-visitor-keys: 3.4.3
JSONStream@1.3.5:
dependencies:
json-schema-traverse: 0.4.1
uri-js: 4.4.1
- ajv@8.12.0:
- dependencies:
- fast-deep-equal: 3.1.3
- json-schema-traverse: 1.0.0
- require-from-string: 2.0.2
- uri-js: 4.4.1
-
ajv@8.14.0:
dependencies:
fast-deep-equal: 3.1.3
array-ify@1.0.0: {}
- array-includes@3.1.8:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.1
- es-abstract: 1.23.3
- es-object-atoms: 1.0.0
- get-intrinsic: 1.2.4
- is-string: 1.0.7
+ array-timsort@1.0.3: {}
array-union@2.1.0: {}
- array.prototype.findlastindex@1.2.5:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.1
- es-abstract: 1.23.3
- es-errors: 1.3.0
- es-object-atoms: 1.0.0
- es-shim-unscopables: 1.0.2
-
- array.prototype.flat@1.3.2:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.1
- es-abstract: 1.23.3
- es-shim-unscopables: 1.0.2
-
- array.prototype.flatmap@1.3.2:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.1
- es-abstract: 1.23.3
- es-shim-unscopables: 1.0.2
-
array.prototype.map@1.0.7:
dependencies:
call-bind: 1.0.7
clean-stack@2.2.0: {}
+ clear-module@4.1.2:
+ dependencies:
+ parent-module: 2.0.0
+ resolve-from: 5.0.0
+
cli-boxes@3.0.0: {}
cli-cursor@3.1.0:
commander@2.20.3: {}
+ comment-json@4.2.3:
+ dependencies:
+ array-timsort: 1.0.3
+ core-util-is: 1.0.3
+ esprima: 4.0.1
+ has-own-prop: 2.0.0
+ repeat-string: 1.6.1
+
comment-parser@1.4.1: {}
compare-func@2.0.0:
convert-source-map@2.0.0: {}
+ core-util-is@1.0.3: {}
+
cosmiconfig-typescript-loader@5.0.0(@types/node@20.12.13)(cosmiconfig@9.0.0(typescript@5.4.5))(typescript@5.4.5):
dependencies:
'@types/node': 20.12.13
dependencies:
type-fest: 1.4.0
+ cspell-config-lib@8.8.3:
+ dependencies:
+ '@cspell/cspell-types': 8.8.3
+ comment-json: 4.2.3
+ yaml: 2.4.2
+
+ cspell-dictionary@8.8.3:
+ dependencies:
+ '@cspell/cspell-pipe': 8.8.3
+ '@cspell/cspell-types': 8.8.3
+ cspell-trie-lib: 8.8.3
+ fast-equals: 5.0.1
+ gensequence: 7.0.0
+
+ cspell-glob@8.8.3:
+ dependencies:
+ micromatch: 4.0.7
+
+ cspell-grammar@8.8.3:
+ dependencies:
+ '@cspell/cspell-pipe': 8.8.3
+ '@cspell/cspell-types': 8.8.3
+
+ cspell-io@8.8.3:
+ dependencies:
+ '@cspell/cspell-service-bus': 8.8.3
+
+ cspell-lib@8.8.3:
+ dependencies:
+ '@cspell/cspell-bundled-dicts': 8.8.3
+ '@cspell/cspell-pipe': 8.8.3
+ '@cspell/cspell-resolver': 8.8.3
+ '@cspell/cspell-types': 8.8.3
+ '@cspell/dynamic-import': 8.8.3
+ '@cspell/strong-weak-map': 8.8.3
+ clear-module: 4.1.2
+ comment-json: 4.2.3
+ cspell-config-lib: 8.8.3
+ cspell-dictionary: 8.8.3
+ cspell-glob: 8.8.3
+ cspell-grammar: 8.8.3
+ cspell-io: 8.8.3
+ cspell-trie-lib: 8.8.3
+ env-paths: 3.0.0
+ fast-equals: 5.0.1
+ gensequence: 7.0.0
+ import-fresh: 3.3.0
+ resolve-from: 5.0.0
+ vscode-languageserver-textdocument: 1.0.11
+ vscode-uri: 3.0.8
+ xdg-basedir: 5.1.0
+
+ cspell-trie-lib@8.8.3:
+ dependencies:
+ '@cspell/cspell-pipe': 8.8.3
+ '@cspell/cspell-types': 8.8.3
+ gensequence: 7.0.0
+
dargs@8.1.0: {}
data-uri-to-buffer@4.0.1: {}
dateformat@4.6.3: {}
- debug@3.2.7:
- dependencies:
- ms: 2.1.3
-
debug@4.3.4(supports-color@8.1.1):
dependencies:
ms: 2.1.2
dependencies:
path-type: 4.0.0
- doctrine@2.1.0:
- dependencies:
- esutils: 2.0.3
-
- doctrine@3.0.0:
- dependencies:
- esutils: 2.0.3
-
dot-prop@5.3.0:
dependencies:
is-obj: 2.0.0
env-paths@2.2.1: {}
+ env-paths@3.0.0: {}
+
error-ex@1.3.2:
dependencies:
is-arrayish: 0.2.1
has-tostringtag: 1.0.2
hasown: 2.0.2
- es-shim-unscopables@1.0.2:
- dependencies:
- hasown: 2.0.2
-
es-to-primitive@1.2.1:
dependencies:
is-callable: 1.2.7
optionalDependencies:
source-map: 0.6.1
- eslint-compat-utils@0.5.0(eslint@8.57.0):
+ eslint-compat-utils@0.5.0(eslint@9.3.0):
dependencies:
- eslint: 8.57.0
+ eslint: 9.3.0
semver: 7.6.2
- eslint-config-love@47.0.0(@typescript-eslint/eslint-plugin@7.11.0(@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0))(eslint-plugin-n@17.7.0(eslint@8.57.0))(eslint-plugin-promise@6.2.0(eslint@8.57.0))(eslint@8.57.0)(typescript@5.4.5):
- dependencies:
- '@typescript-eslint/eslint-plugin': 7.11.0(@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
- '@typescript-eslint/parser': 7.11.0(eslint@8.57.0)(typescript@5.4.5)
- eslint: 8.57.0
- eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
- eslint-plugin-n: 17.7.0(eslint@8.57.0)
- eslint-plugin-promise: 6.2.0(eslint@8.57.0)
- typescript: 5.4.5
- transitivePeerDependencies:
- - supports-color
-
- eslint-config-standard@17.1.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0))(eslint-plugin-n@17.7.0(eslint@8.57.0))(eslint-plugin-promise@6.2.0(eslint@8.57.0))(eslint@8.57.0):
- dependencies:
- eslint: 8.57.0
- eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
- eslint-plugin-n: 17.7.0(eslint@8.57.0)
- eslint-plugin-promise: 6.2.0(eslint@8.57.0)
-
eslint-define-config@2.1.0: {}
- eslint-import-resolver-node@0.3.9:
- dependencies:
- debug: 3.2.7
- is-core-module: 2.13.1
- resolve: 1.22.8
- transitivePeerDependencies:
- - supports-color
-
- eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0):
+ eslint-plugin-es-x@7.6.0(eslint@9.3.0):
dependencies:
- debug: 4.3.4(supports-color@8.1.1)
- enhanced-resolve: 5.16.1
- eslint: 8.57.0
- eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0)
- eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
- fast-glob: 3.3.2
- get-tsconfig: 4.7.5
- is-core-module: 2.13.1
- is-glob: 4.0.3
- transitivePeerDependencies:
- - '@typescript-eslint/parser'
- - eslint-import-resolver-node
- - eslint-import-resolver-webpack
- - supports-color
-
- eslint-module-utils@2.8.1(@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0):
- dependencies:
- debug: 3.2.7
- optionalDependencies:
- '@typescript-eslint/parser': 7.11.0(eslint@8.57.0)(typescript@5.4.5)
- eslint: 8.57.0
- eslint-import-resolver-node: 0.3.9
- eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0)
- transitivePeerDependencies:
- - supports-color
-
- eslint-plugin-es-x@7.6.0(eslint@8.57.0):
- dependencies:
- '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.3.0)
'@eslint-community/regexpp': 4.10.0
- eslint: 8.57.0
- eslint-compat-utils: 0.5.0(eslint@8.57.0)
-
- eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0):
- dependencies:
- array-includes: 3.1.8
- array.prototype.findlastindex: 1.2.5
- array.prototype.flat: 1.3.2
- array.prototype.flatmap: 1.3.2
- debug: 3.2.7
- doctrine: 2.1.0
- eslint: 8.57.0
- eslint-import-resolver-node: 0.3.9
- eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0)
- hasown: 2.0.2
- is-core-module: 2.13.1
- is-glob: 4.0.3
- minimatch: 3.1.2
- object.fromentries: 2.0.8
- object.groupby: 1.0.3
- object.values: 1.2.0
- semver: 7.6.2
- tsconfig-paths: 3.15.0
- optionalDependencies:
- '@typescript-eslint/parser': 7.11.0(eslint@8.57.0)(typescript@5.4.5)
- transitivePeerDependencies:
- - eslint-import-resolver-typescript
- - eslint-import-resolver-webpack
- - supports-color
+ eslint: 9.3.0
+ eslint-compat-utils: 0.5.0(eslint@9.3.0)
- eslint-plugin-jsdoc@48.2.7(eslint@8.57.0):
+ eslint-plugin-jsdoc@48.2.7(eslint@9.3.0):
dependencies:
'@es-joy/jsdoccomment': 0.43.1
are-docs-informative: 0.0.2
comment-parser: 1.4.1
debug: 4.3.4(supports-color@8.1.1)
escape-string-regexp: 4.0.0
- eslint: 8.57.0
+ eslint: 9.3.0
esquery: 1.5.0
semver: 7.6.2
spdx-expression-parse: 4.0.0
transitivePeerDependencies:
- supports-color
- eslint-plugin-n@17.7.0(eslint@8.57.0):
+ eslint-plugin-n@17.7.0(eslint@9.3.0):
dependencies:
- '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.3.0)
enhanced-resolve: 5.16.1
- eslint: 8.57.0
- eslint-plugin-es-x: 7.6.0(eslint@8.57.0)
+ eslint: 9.3.0
+ eslint-plugin-es-x: 7.6.0(eslint@9.3.0)
get-tsconfig: 4.7.5
globals: 15.3.0
ignore: 5.3.1
minimatch: 9.0.4
semver: 7.6.2
- eslint-plugin-promise@6.2.0(eslint@8.57.0):
- dependencies:
- eslint: 8.57.0
-
- eslint-plugin-simple-import-sort@12.1.0(eslint@8.57.0):
- dependencies:
- eslint: 8.57.0
-
- eslint-plugin-spellcheck@0.0.20(eslint@8.57.0):
+ eslint-plugin-simple-import-sort@12.1.0(eslint@9.3.0):
dependencies:
- eslint: 8.57.0
- globals: 13.24.0
- hunspell-spellchecker: 1.0.2
- lodash: 4.17.21
+ eslint: 9.3.0
- eslint-plugin-tsdoc@0.3.0:
- dependencies:
- '@microsoft/tsdoc': 0.15.0
- '@microsoft/tsdoc-config': 0.17.0
-
- eslint-scope@7.2.2:
+ eslint-scope@8.0.1:
dependencies:
esrecurse: 4.3.0
estraverse: 5.3.0
eslint-visitor-keys@3.4.3: {}
- eslint@8.57.0:
+ eslint-visitor-keys@4.0.0: {}
+
+ eslint@9.3.0:
dependencies:
- '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.3.0)
'@eslint-community/regexpp': 4.10.0
- '@eslint/eslintrc': 2.1.4
- '@eslint/js': 8.57.0
- '@humanwhocodes/config-array': 0.11.14
+ '@eslint/eslintrc': 3.1.0
+ '@eslint/js': 9.3.0
+ '@humanwhocodes/config-array': 0.13.0
'@humanwhocodes/module-importer': 1.0.1
+ '@humanwhocodes/retry': 0.3.0
'@nodelib/fs.walk': 1.2.8
- '@ungap/structured-clone': 1.2.0
ajv: 6.12.6
chalk: 4.1.2
cross-spawn: 7.0.3
debug: 4.3.4(supports-color@8.1.1)
- doctrine: 3.0.0
escape-string-regexp: 4.0.0
- eslint-scope: 7.2.2
- eslint-visitor-keys: 3.4.3
- espree: 9.6.1
+ eslint-scope: 8.0.1
+ eslint-visitor-keys: 4.0.0
+ espree: 10.0.1
esquery: 1.5.0
esutils: 2.0.3
fast-deep-equal: 3.1.3
- file-entry-cache: 6.0.1
+ file-entry-cache: 8.0.0
find-up: 5.0.0
glob-parent: 6.0.2
- globals: 13.24.0
- graphemer: 1.4.0
ignore: 5.3.1
imurmurhash: 0.1.4
is-glob: 4.0.3
is-path-inside: 3.0.3
- js-yaml: 4.1.0
json-stable-stringify-without-jsonify: 1.0.1
levn: 0.4.1
lodash.merge: 4.6.2
transitivePeerDependencies:
- supports-color
+ espree@10.0.1:
+ dependencies:
+ acorn: 8.11.3
+ acorn-jsx: 5.3.2(acorn@8.11.3)
+ eslint-visitor-keys: 4.0.0
+
espree@9.6.1:
dependencies:
acorn: 8.11.3
estree-walker@2.0.2: {}
+ estree-walker@3.0.3:
+ dependencies:
+ '@types/estree': 1.0.5
+
esutils@2.0.3: {}
eventemitter3@5.0.1: {}
fast-deep-equal@3.1.3: {}
+ fast-equals@5.0.1: {}
+
fast-glob@3.3.2:
dependencies:
'@nodelib/fs.stat': 2.0.5
node-domexception: 1.0.0
web-streams-polyfill: 3.3.3
- file-entry-cache@6.0.1:
+ file-entry-cache@8.0.0:
dependencies:
- flat-cache: 3.2.0
+ flat-cache: 4.0.1
fill-range@7.1.1:
dependencies:
path-exists: 5.0.0
unicorn-magic: 0.1.0
- flat-cache@3.2.0:
+ flat-cache@4.0.1:
dependencies:
flatted: 3.3.1
keyv: 4.5.4
- rimraf: 3.0.2
flat@5.0.2: {}
functions-have-names@1.2.3: {}
+ gensequence@7.0.0: {}
+
get-caller-file@2.0.5: {}
get-east-asian-width@1.2.0: {}
dependencies:
ini: 2.0.0
- globals@13.24.0:
- dependencies:
- type-fest: 0.20.2
+ globals@14.0.0: {}
globals@15.3.0: {}
has-flag@4.0.0: {}
+ has-own-prop@2.0.0: {}
+
has-property-descriptors@1.0.2:
dependencies:
es-define-property: 1.0.0
human-signals@5.0.0: {}
- hunspell-spellchecker@1.0.2: {}
-
husky@9.0.11: {}
iconv-lite@0.4.24:
jiti@1.21.0: {}
- jju@1.4.0: {}
-
js-tokens@4.0.0: {}
js-yaml@4.1.0:
json-stringify-safe@5.0.1: {}
- json5@1.0.2:
- dependencies:
- minimist: 1.2.8
-
jsonc-parser@3.2.1: {}
jsonfile@6.1.0:
dependencies:
brace-expansion: 2.0.1
+ minimatch@9.0.3:
+ dependencies:
+ brace-expansion: 2.0.1
+
minimatch@9.0.4:
dependencies:
brace-expansion: 2.0.1
natural-compare@1.4.0: {}
+ neostandard@0.5.1(@typescript-eslint/parser@8.0.0-alpha.23(eslint@9.3.0)(typescript@5.4.5))(eslint@9.3.0)(typescript@5.4.5):
+ dependencies:
+ '@stylistic/eslint-plugin': 1.8.1(eslint@9.3.0)(typescript@5.4.5)
+ '@typescript-eslint/eslint-plugin': 8.0.0-alpha.23(@typescript-eslint/parser@8.0.0-alpha.23(eslint@9.3.0)(typescript@5.4.5))(eslint@9.3.0)(typescript@5.4.5)
+ '@typescript-eslint/utils': 8.0.0-alpha.23(eslint@9.3.0)(typescript@5.4.5)
+ eslint: 9.3.0
+ eslint-plugin-n: 17.7.0(eslint@9.3.0)
+ globals: 15.3.0
+ peowly: 1.3.0
+ typescript-eslint: 8.0.0-alpha.23(eslint@9.3.0)(typescript@5.4.5)
+ transitivePeerDependencies:
+ - '@typescript-eslint/parser'
+ - supports-color
+ - typescript
+
netmask@2.0.2: {}
new-github-release-url@2.0.0:
has-symbols: 1.0.3
object-keys: 1.1.1
- object.fromentries@2.0.8:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.1
- es-abstract: 1.23.3
- es-object-atoms: 1.0.0
-
- object.groupby@1.0.3:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.1
- es-abstract: 1.23.3
-
- object.values@1.2.0:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.1
- es-object-atoms: 1.0.0
-
once@1.4.0:
dependencies:
wrappy: 1.0.2
dependencies:
callsites: 3.1.0
+ parent-module@2.0.0:
+ dependencies:
+ callsites: 3.1.0
+
parse-json@5.2.0:
dependencies:
'@babel/code-frame': 7.24.6
path-type@5.0.0: {}
+ peowly@1.3.0: {}
+
picocolors@1.0.1: {}
picomatch@2.3.1: {}
+ picomatch@4.0.2: {}
+
pidtree@0.6.0: {}
possible-typed-array-names@1.0.0: {}
- supports-color
- typescript
+ repeat-string@1.6.1: {}
+
require-directory@2.1.1: {}
require-from-string@2.0.2: {}
dependencies:
ansi-regex: 6.0.1
- strip-bom@3.0.0: {}
-
strip-final-newline@2.0.0: {}
strip-final-newline@3.0.0: {}
supports-preserve-symlinks-flag@1.0.0: {}
+ synckit@0.9.0:
+ dependencies:
+ '@pkgr/core': 0.1.1
+ tslib: 2.6.2
+
tapable@2.2.1: {}
tatami-ng@0.4.13(typescript@5.4.5):
dependencies:
typescript: 5.4.5
- tsconfig-paths@3.15.0:
- dependencies:
- '@types/json5': 0.0.29
- json5: 1.0.2
- minimist: 1.2.8
- strip-bom: 3.0.0
-
tslib@2.6.2: {}
type-check@0.4.0:
type-detect@4.0.8: {}
- type-fest@0.20.2: {}
-
type-fest@0.21.3: {}
type-fest@1.4.0: {}
shiki: 0.14.7
typescript: 5.4.5
+ typescript-eslint@8.0.0-alpha.23(eslint@9.3.0)(typescript@5.4.5):
+ dependencies:
+ '@typescript-eslint/eslint-plugin': 8.0.0-alpha.23(@typescript-eslint/parser@8.0.0-alpha.23(eslint@9.3.0)(typescript@5.4.5))(eslint@9.3.0)(typescript@5.4.5)
+ '@typescript-eslint/parser': 8.0.0-alpha.23(eslint@9.3.0)(typescript@5.4.5)
+ '@typescript-eslint/utils': 8.0.0-alpha.23(eslint@9.3.0)(typescript@5.4.5)
+ optionalDependencies:
+ typescript: 5.4.5
+ transitivePeerDependencies:
+ - eslint
+ - supports-color
+
typescript@5.4.5: {}
unbox-primitive@1.0.2:
validator@13.12.0: {}
+ vscode-languageserver-textdocument@1.0.11: {}
+
vscode-oniguruma@1.7.0: {}
vscode-textmate@8.0.0: {}
+ vscode-uri@3.0.8: {}
+
wcwidth@1.0.1:
dependencies:
defaults: 1.0.4
entryFileNames: '[name].cjs',
chunkFileNames: '[name]-[hash].cjs',
preserveModules: true,
- preserveModulesRoot: './src'
+ preserveModulesRoot: './src',
}
: {
file: './lib/index.cjs',
- plugins: [terser({ maxWorkers })]
+ plugins: [terser({ maxWorkers })],
}),
...(sourcemap && {
- sourcemap
- })
+ sourcemap,
+ }),
},
{
format: 'esm',
entryFileNames: '[name].mjs',
chunkFileNames: '[name]-[hash].mjs',
preserveModules: true,
- preserveModulesRoot: './src'
+ preserveModulesRoot: './src',
}
: {
file: './lib/index.mjs',
- plugins: [terser({ maxWorkers })]
+ plugins: [terser({ maxWorkers })],
}),
...(sourcemap && {
- sourcemap
- })
- }
+ sourcemap,
+ }),
+ },
],
external: [/^node:*/],
plugins: [
typescript({
tsconfig: './tsconfig.build.json',
compilerOptions: {
- sourceMap: sourcemap
- }
+ sourceMap: sourcemap,
+ },
}),
del({
- targets: ['./lib/*']
+ targets: ['./lib/*'],
}),
isAnalyzeBuild && analyze(),
- isDocumentationBuild && command('pnpm typedoc')
- ]
+ isDocumentationBuild && command('pnpm typedoc'),
+ ],
},
{
input: './lib/dts/index.d.ts',
dts(),
del({
targets: ['./lib/dts'],
- hook: 'buildEnd'
+ hook: 'buildEnd',
}),
- isAnalyzeBuild && analyze()
- ]
- }
+ isAnalyzeBuild && analyze(),
+ ],
+ },
])
/**
* Circular buffer designed for positive numbers.
- *
* @internal
*/
export class CircularBuffer {
/**
* Checks whether the buffer is empty.
- *
* @returns Whether the buffer is empty.
*/
public empty (): boolean {
/**
* Checks whether the buffer is full.
- *
* @returns Whether the buffer is full.
*/
public full (): boolean {
/**
* Puts number into buffer.
- *
* @param number - Number to put into buffer.
*/
public put (number: number): void {
/**
* Gets number from buffer.
- *
* @returns Number from buffer.
*/
public get (): number | undefined {
/**
* Returns buffer as numbers' array.
- *
* @returns Numbers' array.
*/
public toArray (): number[] {
/**
* Checks the buffer size.
- *
* @param size - Buffer size.
*/
private checkSize (size: number): void {
/**
* Fixed priority queue node.
- *
* @typeParam T - Type of priority queue node data.
* @internal
*/
/**
* Fixed priority queue.
- *
* @typeParam T - Type of fixed priority queue data.
* @internal
*/
export class FixedPriorityQueue<T> {
private start!: number
- private readonly nodeArray: Array<FixedPriorityQueueNode<T>>
+ private readonly nodeArray: FixedPriorityQueueNode<T>[]
/** The fixed priority queue capacity. */
public readonly capacity: number
/** The fixed priority queue size. */
/**
* Constructs a fixed priority queue.
- *
* @param size - Fixed priority queue size. @defaultValue defaultQueueSize
* @param enablePriority - Whether to enable priority. @defaultValue false
* @returns FixedPriorityQueue.
/**
* Checks if the fixed priority queue is empty.
- *
* @returns `true` if the fixed priority queue is empty, `false` otherwise.
*/
public empty (): boolean {
/**
* Checks if the fixed priority queue is full.
- *
* @returns `true` if the fixed priority queue is full, `false` otherwise.
*/
public full (): boolean {
/**
* Enqueue data into the fixed priority queue.
- *
* @param data - Data to enqueue.
* @param priority - Priority of the data. Lower values have higher priority.
* @returns The new size of the priority queue.
/**
* Gets data from the fixed priority queue.
- *
* @param index - The index of the data to get.
* @returns The data at the index or `undefined` if the fixed priority queue is empty or the index is out of bounds.
*/
/**
* Dequeue data from the fixed priority queue.
- *
* @returns The dequeued data or `undefined` if the priority queue is empty.
*/
public dequeue (): T | undefined {
/**
* Returns an iterator for the fixed priority queue.
- *
* @returns An iterator for the fixed priority queue.
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
*/
if (i >= this.size) {
return {
value: undefined,
- done: true
+ done: true,
}
}
const value = this.nodeArray[index].data
}
return {
value,
- done: false
+ done: false,
}
- }
+ },
}
}
/**
* Checks the queue size.
- *
* @param size - Queue size.
*/
private checkSize (size: number): void {
export type { CircularBuffer } from './circular-buffer.js'
export type {
FixedPriorityQueue,
- FixedPriorityQueueNode
+ FixedPriorityQueueNode,
} from './fixed-priority-queue.js'
export type { AbstractPool } from './pools/abstract-pool.js'
export { DynamicClusterPool } from './pools/cluster/dynamic.js'
PoolInfo,
PoolOptions,
PoolType,
- TasksQueueOptions
+ TasksQueueOptions,
} from './pools/pool.js'
export { PoolEvents, PoolTypes } from './pools/pool.js'
export type {
StrategyPolicy,
TaskStatisticsRequirements,
WorkerChoiceStrategy,
- WorkerChoiceStrategyOptions
+ WorkerChoiceStrategyOptions,
} from './pools/selection-strategies/selection-strategies-types.js'
export {
Measurements,
- WorkerChoiceStrategies
+ WorkerChoiceStrategies,
} from './pools/selection-strategies/selection-strategies-types.js'
export type { WorkerChoiceStrategiesContext } from './pools/selection-strategies/worker-choice-strategies-context.js'
export { DynamicThreadPool } from './pools/thread/dynamic.js'
WorkerNodeEventDetail,
WorkerNodeOptions,
WorkerType,
- WorkerUsage
+ WorkerUsage,
} from './pools/worker.js'
export { WorkerTypes } from './pools/worker.js'
export type { PriorityQueue, PriorityQueueNode } from './priority-queue.js'
TaskPerformance,
WorkerError,
WorkerStatistics,
- Writable
+ Writable,
} from './utility-types.js'
export { availableParallelism } from './utils.js'
export type { AbstractWorker } from './worker/abstract-worker.js'
TaskFunctionObject,
TaskFunctionOperationResult,
TaskFunctions,
- TaskSyncFunction
+ TaskSyncFunction,
} from './worker/task-functions.js'
export { ThreadWorker } from './worker/thread-worker.js'
export type {
KillBehavior,
KillHandler,
- WorkerOptions
+ WorkerOptions,
} from './worker/worker-options.js'
export { KillBehaviors } from './worker/worker-options.js'
MessageValue,
PromiseResponseWrapper,
Task,
- TaskFunctionProperties
+ TaskFunctionProperties,
} from '../utility-types.js'
import {
average,
median,
min,
round,
- sleep
+ sleep,
} from '../utils.js'
import type {
TaskFunction,
- TaskFunctionObject
+ TaskFunctionObject,
} from '../worker/task-functions.js'
import { KillBehaviors } from '../worker/worker-options.js'
import {
type PoolOptions,
type PoolType,
PoolTypes,
- type TasksQueueOptions
+ type TasksQueueOptions,
} from './pool.js'
import {
Measurements,
WorkerChoiceStrategies,
type WorkerChoiceStrategy,
- type WorkerChoiceStrategyOptions
+ type WorkerChoiceStrategyOptions,
} from './selection-strategies/selection-strategies-types.js'
import { WorkerChoiceStrategiesContext } from './selection-strategies/worker-choice-strategies-context.js'
import {
updateRunTimeWorkerUsage,
updateTaskStatisticsWorkerUsage,
updateWaitTimeWorkerUsage,
- waitWorkerNodeEvents
+ waitWorkerNodeEvents,
} from './utils.js'
import { version } from './version.js'
import type {
IWorkerNode,
WorkerInfo,
WorkerNodeEventDetail,
- WorkerType
+ WorkerType,
} from './worker.js'
import { WorkerNode } from './worker-node.js'
/**
* Base class that implements some shared logic for all poolifier pools.
- *
* @typeParam Worker - Type of worker which manages this pool.
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
Response = unknown
> implements IPool<Worker, Data, Response> {
/** @inheritDoc */
- public readonly workerNodes: Array<IWorkerNode<Worker, Data>> = []
+ public readonly workerNodes: IWorkerNode<Worker, Data>[] = []
/** @inheritDoc */
public emitter?: EventEmitterAsyncResource
*/
protected promiseResponseMap: Map<
`${string}-${string}-${string}-${string}-${string}`,
- PromiseResponseWrapper<Response>
+ PromiseResponseWrapper<Response>
> = new Map<
`${string}-${string}-${string}-${string}-${string}`,
PromiseResponseWrapper<Response>
- >()
+ >()
/**
* Worker choice strategies context referencing worker choice algorithms implementation.
*/
protected workerChoiceStrategiesContext?: WorkerChoiceStrategiesContext<
- Worker,
- Data,
- Response
+ Worker,
+ Data,
+ Response
>
/**
* - `value`: The task function object.
*/
private readonly taskFunctions: Map<
- string,
- TaskFunctionObject<Data, Response>
+ string,
+ TaskFunctionObject<Data, Response>
>
/**
/**
* Constructs a new poolifier pool.
- *
* @param minimumNumberOfWorkers - Minimum number of workers that this pool manages.
* @param filePath - Path to the worker file.
* @param opts - Options for the pool.
this.initEventEmitter()
}
this.workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext<
- Worker,
- Data,
- Response
+ Worker,
+ Data,
+ Response
>(
this,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
private initEventEmitter (): void {
this.emitter = new EventEmitterAsyncResource({
- name: `poolifier:${this.type}-${this.worker}-pool`
+ name: `poolifier:${this.type}-${this.worker}-pool`,
})
}
.runTime.aggregate === true &&
this.workerChoiceStrategiesContext.getTaskStatisticsRequirements()
.waitTime.aggregate && {
- utilization: round(this.utilization)
+ utilization: round(this.utilization),
}),
workerNodes: this.workerNodes.length,
idleWorkerNodes: this.workerNodes.reduce(
(accumulator, workerNode) =>
workerNode.info.stealing ? accumulator + 1 : accumulator,
0
- )
+ ),
}),
busyWorkerNodes: this.workerNodes.reduce(
(accumulator, _, workerNodeKey) =>
(accumulator, workerNode) =>
accumulator + workerNode.usage.tasks.queued,
0
- )
+ ),
}),
...(this.opts.enableTasksQueue === true && {
maxQueuedTasks: this.workerNodes.reduce(
(accumulator, workerNode) =>
accumulator + (workerNode.usage.tasks.maxQueued ?? 0),
0
- )
+ ),
}),
...(this.opts.enableTasksQueue === true && {
- backPressure: this.hasBackPressure()
+ backPressure: this.hasBackPressure(),
}),
...(this.opts.enableTasksQueue === true && {
stolenTasks: this.workerNodes.reduce(
(accumulator, workerNode) =>
accumulator + workerNode.usage.tasks.stolen,
0
- )
+ ),
}),
failedTasks: this.workerNodes.reduce(
(accumulator, workerNode) =>
[]
)
)
- )
+ ),
}),
...(this.workerChoiceStrategiesContext.getTaskStatisticsRequirements()
.runTime.median && {
[]
)
)
- )
- })
- }
+ ),
+ }),
+ },
}),
...(this.workerChoiceStrategiesContext?.getTaskStatisticsRequirements()
.waitTime.aggregate === true && {
[]
)
)
- )
+ ),
}),
...(this.workerChoiceStrategiesContext.getTaskStatisticsRequirements()
.waitTime.median && {
[]
)
)
- )
- })
- }
+ ),
+ }),
+ },
}),
...(this.workerChoiceStrategiesContext?.getTaskStatisticsRequirements()
.elu.aggregate === true && {
[]
)
)
- )
+ ),
}),
...(this.workerChoiceStrategiesContext.getTaskStatisticsRequirements()
.elu.median && {
[]
)
)
- )
- })
+ ),
+ }),
},
active: {
minimum: round(
[]
)
)
- )
+ ),
}),
...(this.workerChoiceStrategiesContext.getTaskStatisticsRequirements()
.elu.median && {
[]
)
)
- )
- })
+ ),
+ }),
},
utilization: {
average: round(
workerNode => workerNode.usage.elu.utilization ?? 0
)
)
- )
- }
- }
- })
+ ),
+ },
+ },
+ }),
}
}
/**
* The approximate pool utilization.
- *
* @returns The pool utilization.
*/
private get utilization (): number {
/**
* Checks if the worker id sent in the received message from a worker is valid.
- *
* @param message - The received message.
* @throws {@link https://nodejs.org/api/errors.html#class-error} If the worker id is invalid.
*/
/**
* Gets the worker node key given its worker id.
- *
* @param workerId - The worker id.
* @returns The worker node key if the worker id is found in the pool worker nodes, `-1` otherwise.
*/
...getDefaultTasksQueueOptions(
this.maximumNumberOfWorkers ?? this.minimumNumberOfWorkers
),
- ...tasksQueueOptions
+ ...tasksQueueOptions,
}
}
/**
* Whether worker nodes are executing concurrently their tasks quota or not.
- *
* @returns Worker nodes busyness boolean status.
*/
protected internalBusy (): boolean {
const opResult = await this.sendTaskFunctionOperationToWorkers({
taskFunctionOperation: 'add',
taskFunctionProperties: buildTaskFunctionProperties(name, fn),
- taskFunction: fn.taskFunction.toString()
+ taskFunction: fn.taskFunction.toString(),
})
this.taskFunctions.set(name, fn)
this.workerChoiceStrategiesContext?.syncWorkerChoiceStrategies(
taskFunctionProperties: buildTaskFunctionProperties(
name,
this.taskFunctions.get(name)
- )
+ ),
})
for (const workerNode of this.workerNodes) {
workerNode.deleteTaskFunctionWorkerUsage(name)
/**
* Gets task function worker choice strategy, if any.
- *
* @param name - The task function name.
* @returns The task function worker choice strategy if the task function worker choice strategy is defined, `undefined` otherwise.
*/
/**
* Gets worker node task function worker choice strategy, if any.
- *
* @param workerNodeKey - The worker node key.
* @param name - The task function name.
* @returns The worker node task function worker choice strategy if the worker node task function worker choice strategy is defined, `undefined` otherwise.
/**
* Gets worker node task function priority, if any.
- *
* @param workerNodeKey - The worker node key.
* @param name - The task function name.
* @returns The worker node task function priority if the worker node task function priority is defined, `undefined` otherwise.
/**
* Gets the worker choice strategies registered in this pool.
- *
* @returns The worker choice strategies.
*/
private readonly getWorkerChoiceStrategies =
)
.filter(
(strategy: WorkerChoiceStrategy | undefined) => strategy != null
- ) as WorkerChoiceStrategy[])
+ ) as WorkerChoiceStrategy[]),
])
}
taskFunctionProperties: buildTaskFunctionProperties(
name,
this.taskFunctions.get(name)
- )
+ ),
})
}
const workerNodeKey = this.chooseWorkerNode(name)
const task: Task<Data> = {
name: name ?? DEFAULT_TASK_NAME,
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
+
data: data ?? ({} as Data),
priority: this.getWorkerNodeTaskFunctionPriority(workerNodeKey, name),
strategy: this.getWorkerNodeTaskFunctionWorkerChoiceStrategy(
),
transferList,
timestamp,
- taskId: randomUUID()
+ taskId: randomUUID(),
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.promiseResponseMap.set(task.taskId!, {
...(this.emitter != null && {
asyncResource: new AsyncResource('poolifier:task', {
triggerAsyncId: this.emitter.asyncId,
- requireManualDestroy: true
- })
- })
+ requireManualDestroy: true,
+ }),
+ }),
})
if (
this.opts.enableTasksQueue === false ||
/**
* Starts the minimum number of workers.
+ * @param initWorkerNodeUsage
*/
private startMinimumNumberOfWorkers (initWorkerNodeUsage = false): void {
this.startingMinimumNumberOfWorkers = true
private async sendKillMessageToWorker (workerNodeKey: number): Promise<void> {
await new Promise<void>((resolve, reject) => {
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (this.workerNodes[workerNodeKey] == null) {
resolve()
return
/**
* Terminates the worker node given its worker node key.
- *
* @param workerNodeKey - The worker node key.
*/
protected async destroyWorkerNode (workerNodeKey: number): Promise<void> {
/**
* Setup hook to execute code before worker nodes are created in the abstract constructor.
* Can be overridden.
- *
- * @virtual
*/
protected setupHook (): void {
/* Intentionally empty */
/**
* Returns whether the worker is the main worker or not.
- *
* @returns `true` if the worker is the main worker, `false` otherwise.
*/
protected abstract isMain (): boolean
/**
* Hook executed before the worker task execution.
* Can be overridden.
- *
* @param workerNodeKey - The worker node key.
* @param task - The task to execute.
*/
workerNodeKey: number,
task: Task<Data>
): void {
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (this.workerNodes[workerNodeKey]?.usage != null) {
const workerUsage = this.workerNodes[workerNodeKey].usage
++workerUsage.tasks.executing
/**
* Hook executed after the worker task execution.
* Can be overridden.
- *
* @param workerNodeKey - The worker node key.
* @param message - The received message.
*/
message: MessageValue<Response>
): void {
let needWorkerChoiceStrategiesUpdate = false
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
+
if (this.workerNodes[workerNodeKey]?.usage != null) {
const workerUsage = this.workerNodes[workerNodeKey].usage
updateTaskStatisticsWorkerUsage(workerUsage, message)
/**
* Whether the worker node shall update its task function worker usage or not.
- *
* @param workerNodeKey - The worker node key.
* @returns `true` if the worker node shall update its task function worker usage, `false` otherwise.
*/
/**
* Chooses a worker node for the next task.
- *
* @param name - The task function name.
* @returns The chosen worker node key.
*/
/**
* Conditions for dynamic worker creation.
- *
* @returns Whether to create a dynamic worker or not.
*/
protected abstract shallCreateDynamicWorker (): boolean
/**
* Sends a message to worker given its worker node key.
- *
* @param workerNodeKey - The worker node key.
* @param message - The message.
* @param transferList - The optional array of transferable objects.
/**
* Initializes the worker node usage with sensible default values gathered during runtime.
- *
* @param workerNode - The worker node.
*/
private initWorkerNodeUsage (workerNode: IWorkerNode<Worker, Data>): void {
/**
* Creates a new, completely set up worker node.
- *
* @returns New, completely set up worker node key.
*/
protected createAndSetupWorkerNode (): number {
) {
this.redistributeQueuedTasks(this.workerNodes.indexOf(workerNode))
}
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
+
workerNode?.terminate().catch((error: unknown) => {
this.emitter?.emit(PoolEvents.error, error)
})
/**
* Creates a new, completely set up dynamic worker node.
- *
* @returns New, completely set up dynamic worker node key.
*/
protected createAndSetupDynamicWorkerNode (): number {
}
})
this.sendToWorker(workerNodeKey, {
- checkActive: true
+ checkActive: true,
})
if (this.taskFunctions.size > 0) {
for (const [taskFunctionName, taskFunctionObject] of this.taskFunctions) {
taskFunctionName,
taskFunctionObject
),
- taskFunction: taskFunctionObject.taskFunction.toString()
+ taskFunction: taskFunctionObject.taskFunction.toString(),
}).catch((error: unknown) => {
this.emitter?.emit(PoolEvents.error, error)
})
/**
* Registers a listener callback on the worker given its worker node key.
- *
* @param workerNodeKey - The worker node key.
* @param listener - The message listener callback.
*/
/**
* Registers once a listener callback on the worker given its worker node key.
- *
* @param workerNodeKey - The worker node key.
* @param listener - The message listener callback.
*/
/**
* Deregisters a listener callback on the worker given its worker node key.
- *
* @param workerNodeKey - The worker node key.
* @param listener - The message listener callback.
*/
/**
* Method hooked up after a worker node has been newly created.
* Can be overridden.
- *
* @param workerNodeKey - The newly created worker node key.
*/
protected afterWorkerNodeSetup (workerNodeKey: number): void {
/**
* Sends the startup message to worker given its worker node key.
- *
* @param workerNodeKey - The worker node key.
*/
protected abstract sendStartupMessageToWorker (workerNodeKey: number): void
/**
* Sends the statistics message to worker given its worker node key.
- *
* @param workerNodeKey - The worker node key.
*/
private sendStatisticsMessageToWorker (workerNodeKey: number): void {
.runTime.aggregate ?? false,
elu:
this.workerChoiceStrategiesContext?.getTaskStatisticsRequirements()
- .elu.aggregate ?? false
- }
+ .elu.aggregate ?? false,
+ },
})
}
taskName: string
): void {
const workerNode = this.workerNodes[workerNodeKey]
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
+
if (workerNode?.usage != null) {
++workerNode.usage.tasks.stolen
}
previousTaskName?: string
): void {
const workerNode = this.workerNodes[workerNodeKey]
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
+
if (workerNode?.usage != null) {
++workerNode.usage.tasks.sequentiallyStolen
}
taskName: string
): void {
const workerNode = this.workerNodes[workerNodeKey]
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
+
if (workerNode?.usage != null) {
workerNode.usage.tasks.sequentiallyStolen = 0
}
/**
* This method is the message listener registered on each worker.
+ * @param message
*/
protected readonly workerMessageListener = (
message: MessageValue<Response>
this.afterTaskExecutionHook(workerNodeKey, message)
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.promiseResponseMap.delete(taskId!)
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
workerNode?.emit('taskFinished', taskId)
if (
this.opts.enableTasksQueue === true &&
!this.destroying &&
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
workerNode != null
) {
const workerNodeTasksUsage = workerNode.usage.tasks
) {
workerNode.emit('idle', {
workerId,
- workerNodeKey
+ workerNodeKey,
})
}
}
/**
* Gets the worker information given its worker node key.
- *
* @param workerNodeKey - The worker node key.
* @returns The worker information.
*/
/**
* Creates a worker node.
- *
* @returns The created worker node.
*/
private createWorkerNode (): IWorkerNode<Worker, Data> {
this.maximumNumberOfWorkers ?? this.minimumNumberOfWorkers
).size,
tasksQueueBucketSize: defaultBucketSize,
- tasksQueuePriority: this.getTasksQueuePriority()
+ tasksQueuePriority: this.getTasksQueuePriority(),
}
)
// Flag the worker node as ready at pool startup.
/**
* Adds the given worker node in the pool worker nodes.
- *
* @param workerNode - The worker node.
* @returns The added worker node key.
* @throws {@link https://nodejs.org/api/errors.html#class-error} If the added worker node is not found.
/**
* Removes the worker node from the pool worker nodes.
- *
* @param workerNode - The worker node.
*/
private removeWorkerNode (workerNode: IWorkerNode<Worker, Data>): void {
/**
* Executes the given task on the worker given its worker node key.
- *
* @param workerNodeKey - The worker node key.
* @param task - The task to execute.
*/
*
* This cluster pool creates new workers when the others are busy, up to the maximum number of workers.
* When the maximum number of workers is reached and workers are busy, an event is emitted. If you want to listen to this event, use the pool's `emitter`.
- *
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
* @author [Christopher Quadflieg](https://github.com/Shinigami92)
> extends FixedClusterPool<Data, Response> {
/**
* Constructs a new poolifier dynamic cluster pool.
- *
* @param min - Minimum number of workers which are always active.
* @param max - Maximum number of workers that can be created by this pool.
* @param filePath - Path to an implementation of a `ClusterWorker` file, which can be relative or absolute.
/**
* A cluster pool with a fixed number of workers.
- *
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
* @author [Christopher Quadflieg](https://github.com/Shinigami92)
> extends AbstractPool<Worker, Data, Response> {
/**
* Constructs a new poolifier fixed cluster pool.
- *
* @param numberOfWorkers - Number of workers for this pool.
* @param filePath - Path to an implementation of a `ClusterWorker` file, which can be relative or absolute.
* @param opts - Options for this fixed cluster pool.
+ * @param maximumNumberOfWorkers
*/
public constructor (
numberOfWorkers: number,
): void {
this.workerNodes[workerNodeKey]?.worker.send({
...message,
- workerId: this.getWorkerInfo(workerNodeKey)?.id
+ workerId: this.getWorkerInfo(workerNodeKey)?.id,
} satisfies MessageValue<Data>)
}
/** @inheritDoc */
protected sendStartupMessageToWorker (workerNodeKey: number): void {
this.sendToWorker(workerNodeKey, {
- ready: false
+ ready: false,
})
}
import type { TaskFunctionProperties } from '../utility-types.js'
import type {
TaskFunction,
- TaskFunctionObject
+ TaskFunctionObject,
} from '../worker/task-functions.js'
import type {
WorkerChoiceStrategy,
- WorkerChoiceStrategyOptions
+ WorkerChoiceStrategyOptions,
} from './selection-strategies/selection-strategies-types.js'
import type {
ErrorHandler,
IWorkerNode,
MessageHandler,
OnlineHandler,
- WorkerType
+ WorkerType,
} from './worker.js'
/**
/**
* Dynamic pool type.
*/
- dynamic: 'dynamic'
+ dynamic: 'dynamic',
} as const)
/**
destroy: 'destroy',
error: 'error',
taskError: 'taskError',
- backPressure: 'backPressure'
+ backPressure: 'backPressure',
} as const)
/**
export interface TasksQueueOptions {
/**
* Maximum tasks queue size per worker node flagging it as back pressured.
- *
* @defaultValue (pool maximum size)^2
*/
readonly size?: number
/**
* Maximum number of tasks that can be executed concurrently on a worker node.
- *
* @defaultValue 1
*/
readonly concurrency?: number
/**
* Whether to enable task stealing on idle.
- *
* @defaultValue true
*/
readonly taskStealing?: boolean
/**
* Whether to enable tasks stealing under back pressure.
- *
* @defaultValue false
*/
readonly tasksStealingOnBackPressure?: boolean
/**
* Queued tasks finished timeout in milliseconds at worker node termination.
- *
* @defaultValue 2000
*/
readonly tasksFinishedTimeout?: number
/**
* Options for a poolifier pool.
- *
* @typeParam Worker - Type of worker.
*/
export interface PoolOptions<Worker extends IWorker> {
/**
* A function that will listen for online event on each worker.
- *
* @defaultValue `() => {}`
*/
onlineHandler?: OnlineHandler<Worker>
/**
* A function that will listen for message event on each worker.
- *
* @defaultValue `() => {}`
*/
messageHandler?: MessageHandler<Worker>
/**
* A function that will listen for error event on each worker.
- *
* @defaultValue `() => {}`
*/
errorHandler?: ErrorHandler<Worker>
/**
* A function that will listen for exit event on each worker.
- *
* @defaultValue `() => {}`
*/
exitHandler?: ExitHandler<Worker>
/**
* Whether to start the minimum number of workers at pool initialization.
- *
* @defaultValue true
*/
startWorkers?: boolean
/**
* The default worker choice strategy to use in this pool.
- *
* @defaultValue WorkerChoiceStrategies.ROUND_ROBIN
*/
workerChoiceStrategy?: WorkerChoiceStrategy
restartWorkerOnError?: boolean
/**
* Pool events integrated with async resource emission.
- *
* @defaultValue true
*/
enableEvents?: boolean
/**
* Pool worker node tasks queue.
- *
* @defaultValue false
*/
enableTasksQueue?: boolean
tasksQueueOptions?: TasksQueueOptions
/**
* Worker options.
- *
* @see https://nodejs.org/api/worker_threads.html#new-workerfilename-options
*/
workerOptions?: WorkerOptions
/**
* Key/value pairs to add to worker process environment.
- *
* @see https://nodejs.org/api/cluster.html#cluster_cluster_fork_env
*/
env?: Record<string, unknown>
/**
* Cluster settings.
- *
* @see https://nodejs.org/api/cluster.html#cluster_cluster_settings
*/
settings?: ClusterSettings
/**
* Contract definition for a poolifier pool.
- *
* @typeParam Worker - Type of worker which manages this pool.
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
readonly info: PoolInfo
/**
* Pool worker nodes.
- *
* @internal
*/
- readonly workerNodes: Array<IWorkerNode<Worker, Data>>
+ readonly workerNodes: IWorkerNode<Worker, Data>[]
/**
* Pool event emitter integrated with async resource.
* The async tracking tooling identifier is `poolifier:<PoolType>-<WorkerType>-pool`.
readonly emitter?: EventEmitterAsyncResource
/**
* Executes the specified function in the worker constructor with the task data input parameter.
- *
* @param data - The optional task input data for the specified task function. This can only be structured-cloneable data.
* @param name - The optional name of the task function to execute. If not specified, the default task function will be executed.
* @param transferList - An optional array of transferable objects to transfer ownership of. Ownership of the transferred objects is given to the chosen pool's worker_threads worker and they should not be used in the main thread afterwards.
readonly destroy: () => Promise<void>
/**
* Whether the specified task function exists in this pool.
- *
* @param name - The name of the task function.
* @returns `true` if the task function exists, `false` otherwise.
*/
/**
* Adds a task function to this pool.
* If a task function with the same name already exists, it will be overwritten.
- *
* @param name - The name of the task function.
* @param fn - The task function.
* @returns `true` if the task function was added, `false` otherwise.
) => Promise<boolean>
/**
* Removes a task function from this pool.
- *
* @param name - The name of the task function.
* @returns `true` if the task function was removed, `false` otherwise.
*/
readonly removeTaskFunction: (name: string) => Promise<boolean>
/**
* Lists the properties of task functions available in this pool.
- *
* @returns The properties of task functions available in this pool.
*/
readonly listTaskFunctionsProperties: () => TaskFunctionProperties[]
/**
* Sets the default task function in this pool.
- *
* @param name - The name of the task function.
* @returns `true` if the default task function was set, `false` otherwise.
*/
readonly setDefaultTaskFunction: (name: string) => Promise<boolean>
/**
* Sets the default worker choice strategy in this pool.
- *
* @param workerChoiceStrategy - The default worker choice strategy.
* @param workerChoiceStrategyOptions - The worker choice strategy options.
*/
) => void
/**
* Sets the worker choice strategy options in this pool.
- *
* @param workerChoiceStrategyOptions - The worker choice strategy options.
* @returns `true` if the worker choice strategy options were set, `false` otherwise.
*/
) => boolean
/**
* Enables/disables the worker node tasks queue in this pool.
- *
* @param enable - Whether to enable or disable the worker node tasks queue.
* @param tasksQueueOptions - The worker node tasks queue options.
*/
) => void
/**
* Sets the worker node tasks queue options in this pool.
- *
* @param tasksQueueOptions - The worker node tasks queue options.
*/
readonly setTasksQueueOptions: (tasksQueueOptions: TasksQueueOptions) => void
IWorkerChoiceStrategy,
StrategyPolicy,
TaskStatisticsRequirements,
- WorkerChoiceStrategyOptions
+ WorkerChoiceStrategyOptions,
} from './selection-strategies-types.js'
import {
buildWorkerChoiceStrategyOptions,
- toggleMedianMeasurementStatisticsRequirements
+ toggleMedianMeasurementStatisticsRequirements,
} from './selection-strategies-utils.js'
/**
* Worker choice strategy abstract base class.
- *
* @typeParam Worker - Type of worker which manages the strategy.
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
/** @inheritDoc */
public readonly strategyPolicy: StrategyPolicy = {
dynamicWorkerUsage: false,
- dynamicWorkerReady: true
+ dynamicWorkerReady: true,
}
/** @inheritDoc */
public readonly taskStatisticsRequirements: TaskStatisticsRequirements = {
runTime: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS,
waitTime: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS,
- elu: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS
+ elu: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS,
}
/**
* Constructs a worker choice strategy bound to the pool.
- *
* @param pool - The pool instance.
* @param opts - The worker choice strategy options.
*/
/**
* Whether the worker node is ready or not.
- *
* @param workerNodeKey - The worker node key.
* @returns Whether the worker node is ready or not.
*/
* Gets the worker node task runtime.
* If the task statistics require the average runtime, the average runtime is returned.
* If the task statistics require the median runtime, the median runtime is returned.
- *
* @param workerNodeKey - The worker node key.
* @returns The worker node task runtime.
*/
* Gets the worker node task wait time.
* If the task statistics require the average wait time, the average wait time is returned.
* If the task statistics require the median wait time, the median wait time is returned.
- *
* @param workerNodeKey - The worker node key.
* @returns The worker node task wait time.
*/
* Gets the worker node task ELU.
* If the task statistics require the average ELU, the average ELU is returned.
* If the task statistics require the median ELU, the median ELU is returned.
- *
* @param workerNodeKey - The worker node key.
* @returns The worker node task ELU.
*/
/**
* Sets safely the previous worker node key.
- *
* @param workerNodeKey - The worker node key.
*/
protected setPreviousWorkerNodeKey (workerNodeKey: number | undefined): void {
type IWorkerChoiceStrategy,
Measurements,
type TaskStatisticsRequirements,
- type WorkerChoiceStrategyOptions
+ type WorkerChoiceStrategyOptions,
} from './selection-strategies-types.js'
/**
* Selects the next worker with a fair share scheduling algorithm.
* Loosely modeled after the fair queueing algorithm: https://en.wikipedia.org/wiki/Fair_queuing.
- *
* @typeParam Worker - Type of worker which manages the strategy.
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
runTime: {
aggregate: true,
average: true,
- median: false
+ median: false,
},
waitTime: {
aggregate: true,
average: true,
- median: false
+ median: false,
},
elu: {
aggregate: true,
average: true,
- median: false
- }
+ median: false,
+ },
}
/** @inheritDoc */
public update (workerNodeKey: number): boolean {
this.pool.workerNodes[workerNodeKey].strategyData = {
virtualTaskEndTimestamp:
- this.computeWorkerNodeVirtualTaskEndTimestamp(workerNodeKey)
+ this.computeWorkerNodeVirtualTaskEndTimestamp(workerNodeKey),
}
return true
}
if (workerNode.strategyData?.virtualTaskEndTimestamp == null) {
workerNode.strategyData = {
virtualTaskEndTimestamp:
- this.computeWorkerNodeVirtualTaskEndTimestamp(workerNodeKey)
+ this.computeWorkerNodeVirtualTaskEndTimestamp(workerNodeKey),
}
}
return this.isWorkerNodeReady(workerNodeKey) &&
/**
* Computes the worker node key virtual task end timestamp.
- *
* @param workerNodeKey - The worker node key.
* @returns The worker node key virtual task end timestamp.
*/
import type {
IWorkerChoiceStrategy,
TaskStatisticsRequirements,
- WorkerChoiceStrategyOptions
+ WorkerChoiceStrategyOptions,
} from './selection-strategies-types.js'
/**
* Selects the next worker with an interleaved weighted round robin scheduling algorithm.
- *
* @typeParam Worker - Type of worker which manages the strategy.
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
runTime: {
aggregate: true,
average: true,
- median: false
+ median: false,
},
waitTime: {
aggregate: true,
average: true,
- median: false
+ median: false,
},
- elu: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS
+ elu: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS,
}
/**
Object.values(this.opts!.weights!)
.slice()
.sort((a, b) => a - b)
- )
+ ),
]
}
}
import type {
IWorkerChoiceStrategy,
TaskStatisticsRequirements,
- WorkerChoiceStrategyOptions
+ WorkerChoiceStrategyOptions,
} from './selection-strategies-types.js'
/**
* Selects the least busy worker.
- *
* @typeParam Worker - Type of worker which manages the strategy.
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
runTime: {
aggregate: true,
average: false,
- median: false
+ median: false,
},
waitTime: {
aggregate: true,
average: false,
- median: false
+ median: false,
},
- elu: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS
+ elu: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS,
}
/** @inheritDoc */
import type {
IWorkerChoiceStrategy,
TaskStatisticsRequirements,
- WorkerChoiceStrategyOptions
+ WorkerChoiceStrategyOptions,
} from './selection-strategies-types.js'
/**
* Selects the worker with the least ELU.
- *
* @typeParam Worker - Type of worker which manages the strategy.
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
elu: {
aggregate: true,
average: false,
- median: false
- }
+ median: false,
+ },
}
/** @inheritDoc */
import { AbstractWorkerChoiceStrategy } from './abstract-worker-choice-strategy.js'
import type {
IWorkerChoiceStrategy,
- WorkerChoiceStrategyOptions
+ WorkerChoiceStrategyOptions,
} from './selection-strategies-types.js'
/**
* Selects the least used worker.
- *
* @typeParam Worker - Type of worker which manages the strategy.
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
import { AbstractWorkerChoiceStrategy } from './abstract-worker-choice-strategy.js'
import type {
IWorkerChoiceStrategy,
- WorkerChoiceStrategyOptions
+ WorkerChoiceStrategyOptions,
} from './selection-strategies-types.js'
/**
* Selects the next worker in a round robin fashion.
- *
* @typeParam Worker - Type of worker which manages the strategy.
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
WEIGHTED_ROUND_ROBIN: 'WEIGHTED_ROUND_ROBIN',
/**
* Interleaved weighted round robin worker selection strategy.
- *
* @experimental
*/
- INTERLEAVED_WEIGHTED_ROUND_ROBIN: 'INTERLEAVED_WEIGHTED_ROUND_ROBIN'
+ INTERLEAVED_WEIGHTED_ROUND_ROBIN: 'INTERLEAVED_WEIGHTED_ROUND_ROBIN',
} as const)
/**
}> = Object.freeze({
runTime: 'runTime',
waitTime: 'waitTime',
- elu: 'elu'
+ elu: 'elu',
} as const)
/**
readonly measurement?: Measurement
/**
* Runtime options.
- *
* @defaultValue \{ median: false \}
*/
readonly runTime?: MeasurementOptions
/**
* Wait time options.
- *
* @defaultValue \{ median: false \}
*/
readonly waitTime?: MeasurementOptions
/**
* Event loop utilization options.
- *
* @defaultValue \{ median: false \}
*/
readonly elu?: MeasurementOptions
/**
* Worker weights to use for weighted round robin worker selection strategies.
* A weight is tasks maximum execution time in milliseconds for a worker node.
- *
* @defaultValue Weights computed automatically given the CPU performance.
*/
weights?: Record<number, number>
/**
* Measurement statistics requirements.
- *
* @internal
*/
export interface MeasurementStatisticsRequirements {
/**
* Pool worker node worker usage statistics requirements.
- *
* @internal
*/
export interface TaskStatisticsRequirements {
/**
* Strategy policy.
- *
* @internal
*/
export interface StrategyPolicy {
/**
* Worker choice strategy interface.
- *
* @internal
*/
export interface IWorkerChoiceStrategy {
readonly taskStatisticsRequirements: TaskStatisticsRequirements
/**
* Resets strategy internals.
- *
* @returns `true` if the reset is successful, `false` otherwise.
*/
readonly reset: () => boolean
/**
* Updates the worker node key strategy internals.
* This is called after a task has been executed on a worker node.
- *
* @returns `true` if the update is successful, `false` otherwise.
*/
readonly update: (workerNodeKey: number) => boolean
* Chooses a worker node in the pool and returns its key.
* If no worker nodes are not eligible, `undefined` is returned.
* If `undefined` is returned, the caller retry.
- *
* @returns The worker node key or `undefined`.
*/
readonly choose: () => number | undefined
/**
* Removes the worker node key from strategy internals.
- *
* @param workerNodeKey - The worker node key.
* @returns `true` if the worker node key is removed, `false` otherwise.
*/
readonly remove: (workerNodeKey: number) => boolean
/**
* Sets the worker choice strategy options.
- *
* @param opts - The worker choice strategy options.
*/
readonly setOptions: (opts: WorkerChoiceStrategyOptions | undefined) => void
type TaskStatisticsRequirements,
WorkerChoiceStrategies,
type WorkerChoiceStrategy,
- type WorkerChoiceStrategyOptions
+ type WorkerChoiceStrategyOptions,
} from './selection-strategies-types.js'
import { WeightedRoundRobinWorkerChoiceStrategy } from './weighted-round-robin-worker-choice-strategy.js'
import type { WorkerChoiceStrategiesContext } from './worker-choice-strategies-context.js'
const getDefaultWorkerWeight = (): number => {
const currentCpus = cpus()
let estCpuSpeed: number | undefined
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
+
if (currentCpus.every(cpu => cpu.speed == null || cpu.speed === 0)) {
estCpuSpeed = estimatedCpuSpeed()
}
let cpusCycleTimeWeight = 0
for (const cpu of currentCpus) {
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (cpu.speed == null || cpu.speed === 0) {
cpu.speed =
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
currentCpus.find(cpu => cpu.speed != null && cpu.speed !== 0)?.speed ??
estCpuSpeed ??
2000
...{
runTime: { median: false },
waitTime: { median: false },
- elu: { median: false }
+ elu: { median: false },
},
- ...opts
+ ...opts,
}
}
)
return {
dynamicWorkerUsage: policies.some(p => p.dynamicWorkerUsage),
- dynamicWorkerReady: policies.some(p => p.dynamicWorkerReady)
+ dynamicWorkerReady: policies.some(p => p.dynamicWorkerReady),
}
}
runTime: {
aggregate: taskStatisticsRequirements.some(r => r.runTime.aggregate),
average: taskStatisticsRequirements.some(r => r.runTime.average),
- median: taskStatisticsRequirements.some(r => r.runTime.median)
+ median: taskStatisticsRequirements.some(r => r.runTime.median),
},
waitTime: {
aggregate: taskStatisticsRequirements.some(r => r.waitTime.aggregate),
average: taskStatisticsRequirements.some(r => r.waitTime.average),
- median: taskStatisticsRequirements.some(r => r.waitTime.median)
+ median: taskStatisticsRequirements.some(r => r.waitTime.median),
},
elu: {
aggregate: taskStatisticsRequirements.some(r => r.elu.aggregate),
average: taskStatisticsRequirements.some(r => r.elu.average),
- median: taskStatisticsRequirements.some(r => r.elu.median)
- }
+ median: taskStatisticsRequirements.some(r => r.elu.median),
+ },
}
}
))(pool, opts)
default:
throw new Error(
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
`Worker choice strategy '${workerChoiceStrategy}' is not valid`
)
}
import type {
IWorkerChoiceStrategy,
TaskStatisticsRequirements,
- WorkerChoiceStrategyOptions
+ WorkerChoiceStrategyOptions,
} from './selection-strategies-types.js'
/**
* Selects the next worker with a weighted round robin scheduling algorithm.
* Loosely modeled after the weighted round robin queueing algorithm: https://en.wikipedia.org/wiki/Weighted_round_robin.
- *
* @typeParam Worker - Type of worker which manages the strategy.
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
runTime: {
aggregate: true,
average: true,
- median: false
+ median: false,
},
waitTime: {
aggregate: true,
average: true,
- median: false
+ median: false,
},
- elu: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS
+ elu: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS,
}
/**
StrategyPolicy,
TaskStatisticsRequirements,
WorkerChoiceStrategy,
- WorkerChoiceStrategyOptions
+ WorkerChoiceStrategyOptions,
} from './selection-strategies-types.js'
import { WorkerChoiceStrategies } from './selection-strategies-types.js'
import {
buildWorkerChoiceStrategiesPolicy,
buildWorkerChoiceStrategiesTaskStatisticsRequirements,
getWorkerChoiceStrategiesRetries,
- getWorkerChoiceStrategy
+ getWorkerChoiceStrategy,
} from './selection-strategies-utils.js'
/**
* The worker choice strategies context.
- *
* @typeParam Worker - Type of worker.
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
* The worker choice strategies registered in the context.
*/
private readonly workerChoiceStrategies: Map<
- WorkerChoiceStrategy,
- IWorkerChoiceStrategy
+ WorkerChoiceStrategy,
+ IWorkerChoiceStrategy
>
/**
/**
* Worker choice strategies context constructor.
- *
* @param pool - The pool instance.
* @param workerChoiceStrategies - The worker choice strategies. @defaultValue [WorkerChoiceStrategies.ROUND_ROBIN]
* @param opts - The worker choice strategy options.
public constructor (
private readonly pool: IPool<Worker, Data, Response>,
workerChoiceStrategies: WorkerChoiceStrategy[] = [
- WorkerChoiceStrategies.ROUND_ROBIN
+ WorkerChoiceStrategies.ROUND_ROBIN,
],
opts?: WorkerChoiceStrategyOptions
) {
this.execute = this.execute.bind(this)
this.defaultWorkerChoiceStrategy = workerChoiceStrategies[0]
this.workerChoiceStrategies = new Map<
- WorkerChoiceStrategy,
- IWorkerChoiceStrategy
+ WorkerChoiceStrategy,
+ IWorkerChoiceStrategy
>()
for (const workerChoiceStrategy of workerChoiceStrategies) {
this.addWorkerChoiceStrategy(workerChoiceStrategy, this.pool, opts)
/**
* Gets the active worker choice strategies in the context policy.
- *
* @returns The strategies policy.
*/
public getPolicy (): StrategyPolicy {
/**
* Gets the active worker choice strategies in the context task statistics requirements.
- *
* @returns The strategies task statistics requirements.
*/
public getTaskStatisticsRequirements (): TaskStatisticsRequirements {
/**
* Sets the default worker choice strategy to use in the context.
- *
* @param workerChoiceStrategy - The default worker choice strategy to set.
* @param opts - The worker choice strategy options.
*/
/**
* Updates the worker node key in the active worker choice strategies in the context internals.
- *
+ * @param workerNodeKey
* @returns `true` if the update is successful, `false` otherwise.
*/
public update (workerNodeKey: number): boolean {
/**
* Executes the given worker choice strategy in the context algorithm.
- *
* @param workerChoiceStrategy - The worker choice strategy algorithm to execute. @defaultValue this.defaultWorkerChoiceStrategy
* @returns The key of the worker node.
* @throws {@link https://nodejs.org/api/errors.html#class-error} If after computed retries the worker node key is null or undefined.
/**
* Executes the given worker choice strategy.
- *
* @param workerChoiceStrategy - The worker choice strategy.
* @returns The key of the worker node.
* @throws {@link https://nodejs.org/api/errors.html#class-error} If after computed retries the worker node key is null or undefined.
/**
* Removes the worker node key from the active worker choice strategies in the context.
- *
* @param workerNodeKey - The worker node key.
* @returns `true` if the removal is successful, `false` otherwise.
*/
/**
* Sets the active worker choice strategies in the context options.
- *
* @param opts - The worker choice strategy options.
*/
public setOptions (opts: WorkerChoiceStrategyOptions | undefined): void {
/**
* Synchronizes the active worker choice strategies in the context with the given worker choice strategies.
- *
* @param workerChoiceStrategies - The worker choice strategies to synchronize.
* @param opts - The worker choice strategy options.
*/
/**
* Adds a worker choice strategy to the context.
- *
* @param workerChoiceStrategy - The worker choice strategy to add.
+ * @param pool
* @param opts - The worker choice strategy options.
* @returns The worker choice strategies.
*/
/**
* Removes a worker choice strategy from the context.
- *
* @param workerChoiceStrategy - The worker choice strategy to remove.
* @returns `true` if the worker choice strategy is removed, `false` otherwise.
*/
*
* This thread pool creates new threads when the others are busy, up to the maximum number of threads.
* When the maximum number of threads is reached and workers are busy, an event is emitted. If you want to listen to this event, use the pool's `emitter`.
- *
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
* @author [Alessandro Pio Ardizio](https://github.com/pioardi)
> extends FixedThreadPool<Data, Response> {
/**
* Constructs a new poolifier dynamic thread pool.
- *
* @param min - Minimum number of threads which are always active.
* @param max - Maximum number of threads that can be created by this pool.
* @param filePath - Path to an implementation of a `ThreadWorker` file, which can be relative or absolute.
import {
isMainThread,
type TransferListItem,
- type Worker
+ type Worker,
} from 'node:worker_threads'
import type { MessageValue } from '../../utility-types.js'
/**
* A thread pool with a fixed number of threads.
- *
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
* @author [Alessandro Pio Ardizio](https://github.com/pioardi)
> extends AbstractPool<Worker, Data, Response> {
/**
* Constructs a new poolifier fixed thread pool.
- *
* @param numberOfThreads - Number of threads for this pool.
* @param filePath - Path to an implementation of a `ThreadWorker` file, which can be relative or absolute.
* @param opts - Options for this fixed thread pool.
+ * @param maximumNumberOfThreads
*/
public constructor (
numberOfThreads: number,
this.workerNodes[workerNodeKey]?.messageChannel?.port1.postMessage(
{
...message,
- workerId: this.getWorkerInfo(workerNodeKey)?.id
+ workerId: this.getWorkerInfo(workerNodeKey)?.id,
} satisfies MessageValue<Data>,
transferList
)
{
ready: false,
workerId: this.getWorkerInfo(workerNodeKey)?.id,
- port: port2
+ port: port2,
} satisfies MessageValue<Data>,
[port2]
)
import {
SHARE_ENV,
Worker as ThreadWorker,
- type WorkerOptions
+ type WorkerOptions,
} from 'node:worker_threads'
import type { MessageValue, Task } from '../utility-types.js'
import {
type MeasurementStatisticsRequirements,
WorkerChoiceStrategies,
- type WorkerChoiceStrategy
+ type WorkerChoiceStrategy,
} from './selection-strategies/selection-strategies-types.js'
import type { WorkerChoiceStrategiesContext } from './selection-strategies/worker-choice-strategies-context.js'
import {
type WorkerNodeOptions,
type WorkerType,
WorkerTypes,
- type WorkerUsage
+ type WorkerUsage,
} from './worker.js'
/**
{
aggregate: false,
average: false,
- median: false
+ median: false,
}
export const getDefaultTasksQueueOptions = (
concurrency: 1,
taskStealing: true,
tasksStealingOnBackPressure: false,
- tasksFinishedTimeout: 2000
+ tasksFinishedTimeout: 2000,
}
}
/**
* Updates the given measurement statistics.
- *
* @param measurementStatistics - The measurement statistics to update.
* @param measurementRequirements - The measurement statistics requirements.
* @param measurementValue - The measurement value.
}
}
if (env.NODE_ENV === 'test') {
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
exports.updateMeasurementStatistics = updateMeasurementStatistics
}
): void => {
const workerTaskStatistics = workerUsage.tasks
if (
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
workerTaskStatistics.executing != null &&
workerTaskStatistics.executing > 0
) {
export const createWorker = <Worker extends IWorker>(
type: WorkerType,
filePath: string,
- opts: { env?: Record<string, unknown>, workerOptions?: WorkerOptions }
+ opts: { env?: Record<string, unknown>; workerOptions?: WorkerOptions }
): Worker => {
switch (type) {
case WorkerTypes.thread:
return new ThreadWorker(filePath, {
env: SHARE_ENV,
- ...opts.workerOptions
+ ...opts.workerOptions,
}) as unknown as Worker
case WorkerTypes.cluster:
return cluster.fork(opts.env) as unknown as Worker
default:
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
throw new Error(`Unknown worker type '${type}'`)
}
}
/**
* Returns the worker type of the given worker.
- *
* @param worker - The worker to get the type of.
* @returns The worker type of the given worker.
* @internal
/**
* Returns the worker id of the given worker.
- *
* @param worker - The worker to get the id of.
* @returns The worker id of the given worker.
* @internal
checkWorkerNodeArguments,
createWorker,
getWorkerId,
- getWorkerType
+ getWorkerType,
} from './utils.js'
import {
type EventHandler,
type WorkerNodeOptions,
type WorkerType,
WorkerTypes,
- type WorkerUsage
+ type WorkerUsage,
} from './worker.js'
/**
* Worker node.
- *
* @typeParam Worker - Type of worker.
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
*/
/**
* Constructs a new worker node.
- *
* @param type - The worker type.
* @param filePath - Path to the worker file.
* @param opts - The worker node options.
checkWorkerNodeArguments(type, filePath, opts)
this.worker = createWorker<Worker>(type, filePath, {
env: opts.env,
- workerOptions: opts.workerOptions
+ workerOptions: opts.workerOptions,
})
this.info = this.initWorkerInfo(this.worker)
this.usage = this.initWorkerUsage()
dynamic: false,
ready: false,
stealing: false,
- backPressure: false
+ backPressure: false,
}
}
},
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: {
- history: new CircularBuffer(MeasurementHistorySize)
+ history: new CircularBuffer(MeasurementHistorySize),
},
waitTime: {
- history: new CircularBuffer(MeasurementHistorySize)
+ history: new CircularBuffer(MeasurementHistorySize),
},
elu: {
idle: {
- history: new CircularBuffer(MeasurementHistorySize)
+ history: new CircularBuffer(MeasurementHistorySize),
},
active: {
- history: new CircularBuffer(MeasurementHistorySize)
- }
- }
+ history: new CircularBuffer(MeasurementHistorySize),
+ },
+ },
}
}
},
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: {
- history: new CircularBuffer(MeasurementHistorySize)
+ history: new CircularBuffer(MeasurementHistorySize),
},
waitTime: {
- history: new CircularBuffer(MeasurementHistorySize)
+ history: new CircularBuffer(MeasurementHistorySize),
},
elu: {
idle: {
- history: new CircularBuffer(MeasurementHistorySize)
+ history: new CircularBuffer(MeasurementHistorySize),
},
active: {
- history: new CircularBuffer(MeasurementHistorySize)
- }
- }
+ history: new CircularBuffer(MeasurementHistorySize),
+ },
+ },
}
}
}
/**
* Callback invoked when the worker has started successfully.
- *
* @typeParam Worker - Type of worker.
*/
export type OnlineHandler<Worker extends IWorker> = (this: Worker) => void
/**
* Callback invoked if the worker has received a message.
- *
* @typeParam Worker - Type of worker.
*/
export type MessageHandler<Worker extends IWorker> = (
/**
* Callback invoked if the worker raised an error.
- *
* @typeParam Worker - Type of worker.
*/
export type ErrorHandler<Worker extends IWorker> = (
/**
* Callback invoked when the worker exits successfully.
- *
* @typeParam Worker - Type of worker.
*/
export type ExitHandler<Worker extends IWorker> = (
/**
* Worker event handler.
- *
* @typeParam Worker - Type of worker.
*/
export type EventHandler<Worker extends IWorker> =
/**
* Measurement statistics.
- *
* @internal
*/
export interface MeasurementStatistics {
/**
* Event loop utilization measurement statistics.
- *
* @internal
*/
export interface EventLoopUtilizationMeasurementStatistics {
/**
* Task statistics.
- *
* @internal
*/
export interface TaskStatistics {
/**
* Enumeration of worker types.
*/
-export const WorkerTypes: Readonly<{ thread: 'thread', cluster: 'cluster' }> =
+export const WorkerTypes: Readonly<{ thread: 'thread'; cluster: 'cluster' }> =
Object.freeze({
thread: 'thread',
- cluster: 'cluster'
+ cluster: 'cluster',
} as const)
/**
/**
* Worker information.
- *
* @internal
*/
export interface WorkerInfo {
/**
* Worker usage statistics.
- *
* @internal
*/
export interface WorkerUsage {
/**
* Worker choice strategy data.
- *
* @internal
*/
export interface StrategyData {
readonly threadId?: number
/**
* Registers an event handler.
- *
* @param event - The event.
* @param handler - The event handler.
*/
readonly on: (event: string, handler: EventHandler<this>) => this
/**
* Registers once an event handler.
- *
* @param event - The event.
* @param handler - The event handler.
*/
/**
* Worker node options.
- *
* @internal
*/
export interface WorkerNodeOptions {
/**
* Worker node interface.
- *
* @typeParam Worker - Type of worker.
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @internal
tasksQueueBackPressureSize: number
/**
* Sets tasks queue priority.
- *
* @param enablePriority - Whether to enable tasks queue priority.
*/
readonly setTasksQueuePriority: (enablePriority: boolean) => void
/**
* Tasks queue size.
- *
* @returns The tasks queue size.
*/
readonly tasksQueueSize: () => number
/**
* Enqueue task.
- *
* @param task - The task to queue.
* @returns The tasks queue size.
*/
readonly enqueueTask: (task: Task<Data>) => number
/**
* Dequeue task.
- *
* @param bucket - The prioritized bucket to dequeue from. @defaultValue 0
* @returns The dequeued task.
*/
readonly dequeueTask: (bucket?: number) => Task<Data> | undefined
/**
* Dequeue last prioritized task.
- *
* @returns The dequeued task.
*/
readonly dequeueLastPrioritizedTask: () => Task<Data> | undefined
readonly clearTasksQueue: () => void
/**
* Whether the worker node has back pressure (i.e. its tasks queue is full).
- *
* @returns `true` if the worker node has back pressure, `false` otherwise.
*/
readonly hasBackPressure: () => boolean
readonly terminate: () => Promise<void>
/**
* Registers a worker event handler.
- *
* @param event - The event.
* @param handler - The event handler.
*/
) => void
/**
* Registers once a worker event handler.
- *
* @param event - The event.
* @param handler - The event handler.
*/
) => void
/**
* Gets task function worker usage statistics.
- *
* @param name - The task function name.
* @returns The task function worker usage statistics if the task function worker usage statistics are initialized, `undefined` otherwise.
*/
readonly getTaskFunctionWorkerUsage: (name: string) => WorkerUsage | undefined
/**
* Deletes task function worker usage statistics.
- *
* @param name - The task function name.
* @returns `true` if the task function worker usage statistics were deleted, `false` otherwise.
*/
/**
* Worker node event detail.
- *
* @internal
*/
export interface WorkerNodeEventDetail {
/**
* Priority queue node.
- *
* @typeParam T - Type of priority queue node data.
* @internal
*/
/**
* Priority queue.
- *
* @typeParam T - Type of priority queue data.
* @internal
*/
/**
* Constructs a priority queue.
- *
* @param bucketSize - Prioritized bucket size. @defaultValue defaultBucketSize
* @param enablePriority - Whether to enable priority. @defaultValue false
* @returns PriorityQueue.
/**
* Enqueue data into the priority queue.
- *
* @param data - Data to enqueue.
* @param priority - Priority of the data. Lower values have higher priority.
* @returns The new size of the priority queue.
/**
* Dequeue data from the priority queue.
- *
* @param bucket - The prioritized bucket to dequeue from.
* @returns The dequeued data or `undefined` if the priority queue is empty.
*/
/**
* Returns an iterator for the priority queue.
- *
* @returns An iterator for the priority queue.
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
*/
if (value == null) {
return {
value: undefined,
- done: true
+ done: true,
}
}
++index
}
return {
value,
- done: false
+ done: false,
}
- }
+ },
}
}
}
/**
* Worker error.
- *
* @typeParam Data - Type of data sent to the worker triggering an error. This can only be structured-cloneable data.
*/
export interface WorkerError<Data = unknown> {
/**
* Task performance.
- *
* @internal
*/
export interface TaskPerformance {
/**
* Worker task performance statistics computation settings.
- *
* @internal
*/
export interface WorkerStatistics {
/**
* Message object that is passed as a task between main worker and worker.
- *
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @internal
*/
readonly data?: Data
/**
* Task priority. Lower values have higher priority.
- *
* @defaultValue 0
*/
readonly priority?: number
/**
* Message object that is passed between main worker and worker.
- *
* @typeParam Data - Type of data sent to the worker or execution response. This can only be structured-cloneable data.
* @typeParam ErrorData - Type of data sent to the worker triggering an error. This can only be structured-cloneable data.
* @internal
/**
* An object holding the task execution response promise resolve/reject callbacks.
- *
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
* @internal
*/
/**
* Returns safe host OS optimized estimate of the default amount of parallelism a pool should use.
* Always returns a value greater than zero.
- *
* @returns The host OS optimized maximum pool size.
*/
export const availableParallelism = (): number => {
/**
* Sleeps for the given amount of milliseconds.
- *
* @param ms - The amount of milliseconds to sleep.
* @returns A promise that resolves after the given amount of milliseconds.
* @internal
/**
* Computes the retry delay in milliseconds using an exponential back off algorithm.
- *
* @param retryNumber - The number of retries that have already been attempted
* @param delayFactor - The base delay factor in milliseconds
* @returns Delay in milliseconds
/**
* Computes the average of the given data set.
- *
* @param dataSet - Data set.
* @returns The average of the given data set.
* @internal
/**
* Computes the median of the given data set.
- *
* @param dataSet - Data set.
* @returns The median of the given data set.
* @internal
/**
* Rounds the given number to the given scale.
* The rounding is done using the "round half away from zero" method.
- *
* @param num - The number to round.
* @param scale - The scale to round to.
* @returns The rounded number.
/**
* Is the given value a plain object?
- *
* @param value - The value to check.
* @returns `true` if the given value is a plain object, `false` otherwise.
* @internal
/**
* Detects whether the given value is a kill behavior or not.
- *
* @typeParam KB - Which specific KillBehavior type to test against.
* @param killBehavior - Which kind of kill behavior to detect.
* @param value - Unknown value.
/**
* Detects whether the given value is an asynchronous function or not.
- *
* @param fn - Unknown value.
* @returns `true` if `fn` was an asynchronous function, otherwise `false`.
* @internal
/**
* Generates a cryptographically secure random number in the [0,1[ range
- *
* @returns A number in the [0,1[ range
* @internal
*/
/**
* Returns the minimum of the given numbers.
* If no numbers are given, `Number.POSITIVE_INFINITY` is returned.
- *
* @param args - The numbers to get the minimum of.
* @returns The minimum of the given numbers.
* @internal
/**
* Returns the maximum of the given numbers.
* If no numbers are given, `Number.NEGATIVE_INFINITY` is returned.
- *
* @param args - The numbers to get the maximum of.
* @returns The maximum of the given numbers.
* @internal
/**
* Wraps a function so that it can only be called once.
- *
* @param fn - The function to wrap.
* @param context - The context to bind the function to.
* @returns The wrapped function.
- *
* @typeParam A - The function's arguments.
* @typeParam R - The function's return value.
* @typeParam C - The function's context.
): ((...args: A) => R) => {
let result: R
return (...args: A) => {
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (fn != null) {
result = fn.apply<C, A, R>(context, args)
;(fn as unknown as undefined) = (context as unknown as undefined) =
return {
name,
...(taskFunctionObject?.priority != null && {
- priority: taskFunctionObject.priority
+ priority: taskFunctionObject.priority,
}),
...(taskFunctionObject?.strategy != null && {
- strategy: taskFunctionObject.strategy
- })
+ strategy: taskFunctionObject.strategy,
+ }),
}
}
Task,
TaskFunctionProperties,
TaskPerformance,
- WorkerStatistics
+ WorkerStatistics,
} from '../utility-types.js'
import {
buildTaskFunctionProperties,
DEFAULT_TASK_NAME,
EMPTY_FUNCTION,
isAsyncFunction,
- isPlainObject
+ isPlainObject,
} from '../utils.js'
import type {
TaskAsyncFunction,
TaskFunctionObject,
TaskFunctionOperationResult,
TaskFunctions,
- TaskSyncFunction
+ TaskSyncFunction,
} from './task-functions.js'
import {
checkTaskFunctionName,
checkValidTaskFunctionObjectEntry,
- checkValidWorkerOptions
+ checkValidWorkerOptions,
} from './utils.js'
import { KillBehaviors, type WorkerOptions } from './worker-options.js'
/**
* The function to call when the worker is killed.
*/
- killHandler: EMPTY_FUNCTION
+ killHandler: EMPTY_FUNCTION,
}
/**
* Base class that implements some shared logic for all poolifier workers.
- *
* @typeParam MainWorker - Type of main worker.
* @typeParam Data - Type of data this worker receives from pool's execution. This can only be structured-cloneable data.
* @typeParam Response - Type of response the worker sends back to the main worker. This can only be structured-cloneable data.
/**
* Handler id of the `activeInterval` worker activity check.
*/
+ // eslint-disable-next-line no-undef
protected activeInterval?: NodeJS.Timeout
/**
* Constructs a new poolifier worker.
- *
* @param isMain - Whether this is the main worker or not.
* @param mainWorker - Reference to main worker.
* @param taskFunctions - Task function(s) processed by the worker when the pool's `execution` function is invoked. The first function is the default function.
/**
* Checks if the `taskFunctions` parameter is passed to the constructor and valid.
- *
* @param taskFunctions - The task function(s) parameter that should be checked.
*/
private checkTaskFunctions (
taskFunctions:
- | TaskFunction<Data, Response>
- | TaskFunctions<Data, Response>
- | undefined
+ | TaskFunction<Data, Response>
+ | TaskFunctions<Data, Response>
+ | undefined
): void {
if (taskFunctions == null) {
throw new Error('taskFunctions parameter is mandatory')
for (let [name, fnObj] of Object.entries(taskFunctions)) {
if (typeof fnObj === 'function') {
fnObj = { taskFunction: fnObj } satisfies TaskFunctionObject<
- Data,
- Response
+ Data,
+ Response
>
}
checkValidTaskFunctionObjectEntry<Data, Response>(name, fnObj)
/**
* Checks if the worker has a task function with the given name.
- *
* @param name - The name of the task function to check.
* @returns Whether the worker has a task function with the given name or not.
*/
/**
* Adds a task function to the worker.
* If a task function with the same name already exists, it is replaced.
- *
* @param name - The name of the task function to add.
* @param fn - The task function to add.
* @returns Whether the task function was added or not.
/**
* Removes a task function from the worker.
- *
* @param name - The name of the task function to remove.
* @returns Whether the task function existed and was removed or not.
*/
/**
* Lists the properties of the worker's task functions.
- *
* @returns The properties of the worker's task functions.
*/
public listTaskFunctionsProperties (): TaskFunctionProperties[] {
defaultTaskFunctionName,
this.taskFunctions.get(defaultTaskFunctionName)
),
- ...taskFunctionsProperties
+ ...taskFunctionsProperties,
]
}
/**
* Sets the default task function to use in the worker.
- *
* @param name - The name of the task function to use as default task function.
* @returns Whether the default task function was set or not.
*/
/**
* Handles the ready message sent by the main worker.
- *
* @param message - The ready message.
*/
protected abstract handleReadyMessage (message: MessageValue<Data>): void
/**
* Worker message listener.
- *
* @param message - The received message.
*/
protected messageListener (message: MessageValue<Data>): void {
taskFunctionOperation,
taskId,
data,
- kill
+ kill,
} = message
if (statistics != null) {
// Statistics message received
switch (taskFunctionOperation) {
case 'add':
response = this.addTaskFunction(taskFunctionProperties.name, {
- // eslint-disable-next-line @typescript-eslint/no-implied-eval, no-new-func
+ // eslint-disable-next-line no-new-func
taskFunction: new Function(
`return ${taskFunction}`
)() as TaskFunction<Data, Response>,
...(taskFunctionProperties.priority != null && {
- priority: taskFunctionProperties.priority
+ priority: taskFunctionProperties.priority,
}),
...(taskFunctionProperties.strategy != null && {
- strategy: taskFunctionProperties.strategy
- })
+ strategy: taskFunctionProperties.strategy,
+ }),
})
break
case 'remove':
response.error != null && {
workerError: {
name: taskFunctionProperties.name,
- message: this.handleError(response.error as Error | string)
- }
- })
+ message: this.handleError(response.error as Error | string),
+ },
+ }),
})
}
/**
* Handles a kill message sent by the main worker.
- *
* @param message - The kill message.
*/
- protected handleKillMessage (_message: MessageValue<Data>): void {
+ protected handleKillMessage (message: MessageValue<Data>): void {
this.stopCheckActive()
if (isAsyncFunction(this.opts.killHandler)) {
- (this.opts.killHandler() as Promise<void>)
+ ;(this.opts.killHandler() as Promise<void>)
.then(() => {
this.sendToMainWorker({ kill: 'success' })
return undefined
})
} else {
try {
- // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
- this.opts.killHandler?.() as void
+ this.opts.killHandler?.()
this.sendToMainWorker({ kill: 'success' })
} catch {
this.sendToMainWorker({ kill: 'failure' })
/**
* Check if the message worker id is set and matches the worker id.
- *
* @param message - The message to check.
* @throws {@link https://nodejs.org/api/errors.html#class-error} If the message worker id is not set or does not match the worker id.
*/
/**
* Returns the main worker.
- *
* @returns Reference to the main worker.
* @throws {@link https://nodejs.org/api/errors.html#class-error} If the main worker is not set.
*/
/**
* Sends a message to main worker.
- *
* @param message - The response message.
*/
protected abstract sendToMainWorker (
*/
protected sendTaskFunctionsPropertiesToMainWorker (): void {
this.sendToMainWorker({
- taskFunctionsProperties: this.listTaskFunctionsProperties()
+ taskFunctionsProperties: this.listTaskFunctionsProperties(),
})
}
/**
* Handles an error and convert it to a string so it can be sent back to the main worker.
- *
* @param error - The error raised by the worker.
* @returns The error message.
*/
/**
* Runs the given task.
- *
* @param task - The task to execute.
*/
protected readonly run = (task: Task<Data>): void => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
name: name!,
message: `Task function '${name}' not found`,
- data
+ data,
},
- taskId
+ taskId,
})
return
}
/**
* Runs the given task function synchronously.
- *
* @param fn - Task function that will be executed.
* @param task - Input data for the task function.
*/
this.sendToMainWorker({
data: res,
taskPerformance,
- taskId
+ taskId,
})
} catch (error) {
this.sendToMainWorker({
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
name: name!,
message: this.handleError(error as Error | string),
- data
+ data,
},
- taskId
+ taskId,
})
} finally {
this.updateLastTaskTimestamp()
/**
* Runs the given task function asynchronously.
- *
* @param fn - Task function that will be executed.
* @param task - Input data for the task function.
*/
this.sendToMainWorker({
data: res,
taskPerformance,
- taskId
+ taskId,
})
return undefined
})
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
name: name!,
message: this.handleError(error as Error | string),
- data
+ data,
},
- taskId
+ taskId,
})
})
.finally(() => {
name: name ?? DEFAULT_TASK_NAME,
timestamp: performance.now(),
...(this.statistics.elu && {
- elu: performance.eventLoopUtilization()
- })
+ elu: performance.eventLoopUtilization(),
+ }),
}
}
return {
...taskPerformance,
...(this.statistics.runTime && {
- runTime: performance.now() - taskPerformance.timestamp
+ runTime: performance.now() - taskPerformance.timestamp,
}),
...(this.statistics.elu && {
- elu: performance.eventLoopUtilization(taskPerformance.elu)
- })
+ elu: performance.eventLoopUtilization(taskPerformance.elu),
+ }),
}
}
*
* If you use a `DynamicClusterPool` the extra workers that were created will be terminated,
* but the minimum number of workers will be guaranteed.
- *
* @typeParam Data - Type of data this worker receives from pool's execution. This can only be structured-cloneable data.
* @typeParam Response - Type of response the worker sends back to the main worker. This can only be structured-cloneable data.
* @author [Christopher Quadflieg](https://github.com/Shinigami92)
> extends AbstractWorker<Worker, Data, Response> {
/**
* Constructs a new poolifier cluster worker.
- *
* @param taskFunctions - Task function(s) processed by the worker when the pool's `execution` function is invoked.
* @param opts - Options for the worker.
*/
this.getMainWorker().on('message', this.messageListener.bind(this))
this.sendToMainWorker({
ready: true,
- taskFunctionsProperties: this.listTaskFunctionsProperties()
+ taskFunctionsProperties: this.listTaskFunctionsProperties(),
})
} catch {
this.sendToMainWorker({
ready: false,
- taskFunctionsProperties: this.listTaskFunctionsProperties()
+ taskFunctionsProperties: this.listTaskFunctionsProperties(),
})
}
}
): void => {
this.getMainWorker().send({
...message,
- workerId: this.id
+ workerId: this.id,
} satisfies MessageValue<Response>)
}
}
/**
* Task synchronous function that can be executed.
- *
* @param data - Data sent to the worker.
* @returns Execution response.
- *
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
*/
/**
* Task asynchronous function that can be executed.
* This function must return a promise.
- *
* @param data - Data sent to the worker.
* @returns Execution response promise.
- *
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
*/
/**
* Task function that can be executed.
* This function can be synchronous or asynchronous.
- *
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
*/
/**
* Task function object.
- *
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
*/
* Tasks functions that can be executed.
* The key is the name of the task function or task function object.
* The value is the task function or task function object.
- *
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
*/
export type TaskFunctions<Data = unknown, Response = unknown> = Record<
-string,
-TaskFunction<Data, Response> | TaskFunctionObject<Data, Response>
+ string,
+ TaskFunction<Data, Response> | TaskFunctionObject<Data, Response>
>
/**
isMainThread,
type MessagePort,
parentPort,
- threadId
+ threadId,
} from 'node:worker_threads'
import type { MessageValue } from '../utility-types.js'
*
* If you use a `DynamicThreadPool` the extra workers that were created will be terminated,
* but the minimum number of workers will be guaranteed.
- *
* @typeParam Data - Type of data this worker receives from pool's execution. This can only be structured-cloneable data.
* @typeParam Response - Type of response the worker sends back to the main thread. This can only be structured-cloneable data.
* @author [Alessandro Pio Ardizio](https://github.com/pioardi)
/**
* Constructs a new poolifier thread worker.
- *
* @param taskFunctions - Task function(s) processed by the worker when the pool's `execution` function is invoked.
* @param opts - Options for the worker.
*/
this.port.on('message', this.messageListener.bind(this))
this.sendToMainWorker({
ready: true,
- taskFunctionsProperties: this.listTaskFunctionsProperties()
+ taskFunctionsProperties: this.listTaskFunctionsProperties(),
})
} catch {
this.sendToMainWorker({
ready: false,
- taskFunctionsProperties: this.listTaskFunctionsProperties()
+ taskFunctionsProperties: this.listTaskFunctionsProperties(),
})
}
}
): void => {
this.port?.postMessage({
...message,
- workerId: this.id
+ workerId: this.id,
} satisfies MessageValue<Response>)
}
/**
* @inheritDoc
- * @override
*/
protected handleError (error: Error | string): string {
return error as string
import {
checkValidPriority,
- checkValidWorkerChoiceStrategy
+ checkValidWorkerChoiceStrategy,
} from '../pools/utils.js'
import { isPlainObject } from '../utils.js'
import type { TaskFunctionObject } from './task-functions.js'
}
if (typeof fnObj.taskFunction !== 'function') {
throw new TypeError(
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
`taskFunction object 'taskFunction' property '${fnObj.taskFunction}' is not a function`
)
}
/**
* Enumeration of kill behaviors.
*/
-export const KillBehaviors: Readonly<{ SOFT: 'SOFT', HARD: 'HARD' }> =
+export const KillBehaviors: Readonly<{ SOFT: 'SOFT'; HARD: 'HARD' }> =
Object.freeze({
/**
* If `currentTime - lastActiveTime` is greater than `maxInactiveTime` but the worker is stealing tasks or a task is executing or queued, then the worker **wont** be deleted.
/**
* If `currentTime - lastActiveTime` is greater than `maxInactiveTime` but the worker is stealing tasks or a task is executing or queued, then the worker will be deleted.
*/
- HARD: 'HARD'
+ HARD: 'HARD',
} as const)
/**
* - HARD: If `currentTime - lastActiveTime` is greater than `maxInactiveTime` but the worker is stealing tasks or a task is executing or queued, then the worker will be deleted.
*
* This option only apply to the newly created workers.
- *
* @defaultValue KillBehaviors.SOFT
*/
killBehavior?: KillBehavior
* The last active time of your worker will be updated when it terminates a task.
*
* - If `killBehavior` is set to `KillBehaviors.HARD` this value represents also the timeout for the tasks that you submit to the pool,
- * when this timeout expires your tasks is interrupted before completion and removed. The worker is killed if is not part of the minimum size of the pool.
+ * when this timeout expires your tasks is interrupted before completion and removed. The worker is killed if is not part of the minimum size of the pool.
* - If `killBehavior` is set to `KillBehaviors.SOFT` your tasks have no timeout and your workers will not be terminated until your task is completed.
- *
* @defaultValue 60000
*/
maxInactiveTime?: number
/**
* The function to call when a worker is killed.
- *
* @defaultValue `() => {}`
*/
killHandler?: KillHandler
import { CircularBuffer, defaultBufferSize } from '../lib/circular-buffer.cjs'
-describe('Circular buffer test suite', t => {
+describe('Circular buffer test suite', () => {
it('Verify that circular buffer can be instantiated', () => {
const circularBuffer = new CircularBuffer()
expect(circularBuffer).toBeInstanceOf(CircularBuffer)
import {
defaultQueueSize,
- FixedPriorityQueue
+ FixedPriorityQueue,
} from '../lib/fixed-priority-queue.cjs'
describe('Fixed priority queue test suite', () => {
expect(fixedPriorityQueue.size).toBe(1)
expect(rtSize).toBe(fixedPriorityQueue.size)
expect(fixedPriorityQueue.nodeArray).toMatchObject([
- { data: 1, priority: 0 }
+ { data: 1, priority: 0 },
])
expect(fixedPriorityQueue.capacity).toBe(queueSize)
rtSize = fixedPriorityQueue.enqueue(2)
expect(rtSize).toBe(fixedPriorityQueue.size)
expect(fixedPriorityQueue.nodeArray).toMatchObject([
{ data: 1, priority: 0 },
- { data: 2, priority: 0 }
+ { data: 2, priority: 0 },
])
expect(fixedPriorityQueue.capacity).toBe(queueSize)
rtSize = fixedPriorityQueue.enqueue(3)
expect(fixedPriorityQueue.nodeArray).toMatchObject([
{ data: 1, priority: 0 },
{ data: 2, priority: 0 },
- { data: 3, priority: 0 }
+ { data: 3, priority: 0 },
])
expect(fixedPriorityQueue.capacity).toBe(queueSize)
rtSize = fixedPriorityQueue.enqueue(3, -1)
{ data: 3, priority: -1 },
{ data: 1, priority: 0 },
{ data: 2, priority: 0 },
- { data: 3, priority: 0 }
+ { data: 3, priority: 0 },
])
expect(fixedPriorityQueue.capacity).toBe(queueSize)
rtSize = fixedPriorityQueue.enqueue(1, 1)
{ data: 1, priority: 0 },
{ data: 2, priority: 0 },
{ data: 3, priority: 0 },
- { data: 1, priority: 1 }
+ { data: 1, priority: 1 },
])
expect(fixedPriorityQueue.capacity).toBe(queueSize)
expect(() => fixedPriorityQueue.enqueue(4)).toThrow(
expect(fixedPriorityQueue.nodeArray).toMatchObject([
{ data: 2, priority: -1 },
{ data: 1, priority: 0 },
- { data: 3, priority: 0 }
+ { data: 3, priority: 0 },
])
expect(fixedPriorityQueue.capacity).toBe(queueSize)
rtItem = fixedPriorityQueue.dequeue()
expect(fixedPriorityQueue.nodeArray).toMatchObject([
{ data: 2, priority: -1 },
{ data: 1, priority: 0 },
- { data: 3, priority: 0 }
+ { data: 3, priority: 0 },
])
expect(fixedPriorityQueue.capacity).toBe(queueSize)
rtItem = fixedPriorityQueue.dequeue()
expect(fixedPriorityQueue.nodeArray).toMatchObject([
{ data: 2, priority: -1 },
{ data: 1, priority: 0 },
- { data: 3, priority: 0 }
+ { data: 3, priority: 0 },
])
expect(fixedPriorityQueue.capacity).toBe(queueSize)
rtItem = fixedPriorityQueue.dequeue()
expect(fixedPriorityQueue.nodeArray).toMatchObject([
{ data: 2, priority: -1 },
{ data: 1, priority: 0 },
- { data: 3, priority: 0 }
+ { data: 3, priority: 0 },
])
expect(fixedPriorityQueue.capacity).toBe(queueSize)
})
fixedPriorityQueue.size = 2
fixedPriorityQueue.nodeArray = [
{ data: 2, priority: 0 },
- { data: 3, priority: 0 }
+ { data: 3, priority: 0 },
]
fixedPriorityQueue.clear()
expect(fixedPriorityQueue.start).toBe(0)
expect(fixedPriorityQueue.size).toBe(0)
expect(fixedPriorityQueue.nodeArray).toMatchObject([
{ data: 2, priority: 0 },
- { data: 3, priority: 0 }
+ { data: 3, priority: 0 },
])
})
})
PoolEvents,
PoolTypes,
WorkerChoiceStrategies,
- WorkerTypes
+ WorkerTypes,
} from '../../lib/index.cjs'
import { WorkerNode } from '../../lib/pools/worker-node.cjs'
import { defaultBucketSize, PriorityQueue } from '../../lib/priority-queue.cjs'
numberOfWorkers,
'./tests/worker-files/thread/testWorker.mjs',
{
- errorHandler: e => console.error(e)
+ errorHandler: e => console.error(e),
}
)
).toThrow(
enableEvents: true,
restartWorkerOnError: true,
enableTasksQueue: false,
- workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN
+ workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN,
})
for (const [, workerChoiceStrategy] of pool.workerChoiceStrategiesContext
.workerChoiceStrategies) {
elu: { median: false },
weights: expect.objectContaining({
0: expect.any(Number),
- [pool.info.maxSize - 1]: expect.any(Number)
- })
+ [pool.info.maxSize - 1]: expect.any(Number),
+ }),
})
}
await pool.destroy()
workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED,
workerChoiceStrategyOptions: {
runTime: { median: true },
- weights: { 0: 300, 1: 200 }
+ weights: { 0: 300, 1: 200 },
},
enableEvents: false,
restartWorkerOnError: false,
messageHandler: testHandler,
errorHandler: testHandler,
onlineHandler: testHandler,
- exitHandler: testHandler
+ exitHandler: testHandler,
}
)
expect(pool.emitter).toBeUndefined()
size: Math.pow(numberOfWorkers, 2),
taskStealing: true,
tasksStealingOnBackPressure: false,
- tasksFinishedTimeout: 2000
+ tasksFinishedTimeout: 2000,
},
workerChoiceStrategy: WorkerChoiceStrategies.LEAST_USED,
workerChoiceStrategyOptions: {
runTime: { median: true },
- weights: { 0: 300, 1: 200 }
+ weights: { 0: 300, 1: 200 },
},
onlineHandler: testHandler,
messageHandler: testHandler,
errorHandler: testHandler,
- exitHandler: testHandler
+ exitHandler: testHandler,
})
for (const [, workerChoiceStrategy] of pool.workerChoiceStrategiesContext
.workerChoiceStrategies) {
runTime: { median: true },
waitTime: { median: false },
elu: { median: false },
- weights: { 0: 300, 1: 200 }
+ weights: { 0: 300, 1: 200 },
})
}
await pool.destroy()
numberOfWorkers,
'./tests/worker-files/thread/testWorker.mjs',
{
- workerChoiceStrategy: 'invalidStrategy'
+ workerChoiceStrategy: 'invalidStrategy',
}
)
).toThrow(new Error("Invalid worker choice strategy 'invalidStrategy'"))
numberOfWorkers,
'./tests/worker-files/thread/testWorker.mjs',
{
- workerChoiceStrategyOptions: { weights: {} }
+ workerChoiceStrategyOptions: { weights: {} },
}
)
).toThrow(
numberOfWorkers,
'./tests/worker-files/thread/testWorker.mjs',
{
- workerChoiceStrategyOptions: { measurement: 'invalidMeasurement' }
+ workerChoiceStrategyOptions: { measurement: 'invalidMeasurement' },
}
)
).toThrow(
'./tests/worker-files/thread/testWorker.mjs',
{
enableTasksQueue: true,
- tasksQueueOptions: 'invalidTasksQueueOptions'
+ tasksQueueOptions: 'invalidTasksQueueOptions',
}
)
).toThrow(
'./tests/worker-files/thread/testWorker.mjs',
{
enableTasksQueue: true,
- tasksQueueOptions: { concurrency: 0 }
+ tasksQueueOptions: { concurrency: 0 },
}
)
).toThrow(
'./tests/worker-files/thread/testWorker.mjs',
{
enableTasksQueue: true,
- tasksQueueOptions: { concurrency: -1 }
+ tasksQueueOptions: { concurrency: -1 },
}
)
).toThrow(
'./tests/worker-files/thread/testWorker.mjs',
{
enableTasksQueue: true,
- tasksQueueOptions: { concurrency: 0.2 }
+ tasksQueueOptions: { concurrency: 0.2 },
}
)
).toThrow(
'./tests/worker-files/thread/testWorker.mjs',
{
enableTasksQueue: true,
- tasksQueueOptions: { size: 0 }
+ tasksQueueOptions: { size: 0 },
}
)
).toThrow(
'./tests/worker-files/thread/testWorker.mjs',
{
enableTasksQueue: true,
- tasksQueueOptions: { size: -1 }
+ tasksQueueOptions: { size: -1 },
}
)
).toThrow(
'./tests/worker-files/thread/testWorker.mjs',
{
enableTasksQueue: true,
- tasksQueueOptions: { size: 0.2 }
+ tasksQueueOptions: { size: 0.2 },
}
)
).toThrow(
elu: { median: false },
weights: expect.objectContaining({
0: expect.any(Number),
- [pool.info.maxSize - 1]: expect.any(Number)
- })
+ [pool.info.maxSize - 1]: expect.any(Number),
+ }),
})
}
expect(
runTime: {
aggregate: true,
average: true,
- median: false
+ median: false,
},
waitTime: {
aggregate: true,
average: true,
- median: false
+ median: false,
},
elu: {
aggregate: true,
average: true,
- median: false
- }
+ median: false,
+ },
})
pool.setWorkerChoiceStrategyOptions({
runTime: { median: true },
- elu: { median: true }
+ elu: { median: true },
})
expect(pool.opts.workerChoiceStrategyOptions).toStrictEqual({
runTime: { median: true },
- elu: { median: true }
+ elu: { median: true },
})
for (const [, workerChoiceStrategy] of pool.workerChoiceStrategiesContext
.workerChoiceStrategies) {
elu: { median: true },
weights: expect.objectContaining({
0: expect.any(Number),
- [pool.info.maxSize - 1]: expect.any(Number)
- })
+ [pool.info.maxSize - 1]: expect.any(Number),
+ }),
})
}
expect(
runTime: {
aggregate: true,
average: false,
- median: true
+ median: true,
},
waitTime: {
aggregate: true,
average: true,
- median: false
+ median: false,
},
elu: {
aggregate: true,
average: false,
- median: true
- }
+ median: true,
+ },
})
pool.setWorkerChoiceStrategyOptions({
runTime: { median: false },
- elu: { median: false }
+ elu: { median: false },
})
expect(pool.opts.workerChoiceStrategyOptions).toStrictEqual({
runTime: { median: false },
- elu: { median: false }
+ elu: { median: false },
})
for (const [, workerChoiceStrategy] of pool.workerChoiceStrategiesContext
.workerChoiceStrategies) {
elu: { median: false },
weights: expect.objectContaining({
0: expect.any(Number),
- [pool.info.maxSize - 1]: expect.any(Number)
- })
+ [pool.info.maxSize - 1]: expect.any(Number),
+ }),
})
}
expect(
runTime: {
aggregate: true,
average: true,
- median: false
+ median: false,
},
waitTime: {
aggregate: true,
average: true,
- median: false
+ median: false,
},
elu: {
aggregate: true,
average: true,
- median: false
- }
+ median: false,
+ },
})
expect(() =>
pool.setWorkerChoiceStrategyOptions('invalidWorkerChoiceStrategyOptions')
size: Math.pow(numberOfWorkers, 2),
taskStealing: true,
tasksStealingOnBackPressure: false,
- tasksFinishedTimeout: 2000
+ tasksFinishedTimeout: 2000,
})
pool.enableTasksQueue(true, { concurrency: 2 })
expect(pool.opts.enableTasksQueue).toBe(true)
size: Math.pow(numberOfWorkers, 2),
taskStealing: true,
tasksStealingOnBackPressure: false,
- tasksFinishedTimeout: 2000
+ tasksFinishedTimeout: 2000,
})
pool.enableTasksQueue(false)
expect(pool.opts.enableTasksQueue).toBe(false)
size: Math.pow(numberOfWorkers, 2),
taskStealing: true,
tasksStealingOnBackPressure: false,
- tasksFinishedTimeout: 2000
+ tasksFinishedTimeout: 2000,
})
for (const workerNode of pool.workerNodes) {
expect(workerNode.tasksQueueBackPressureSize).toBe(
size: 2,
taskStealing: false,
tasksStealingOnBackPressure: false,
- tasksFinishedTimeout: 3000
+ tasksFinishedTimeout: 3000,
})
expect(pool.opts.tasksQueueOptions).toStrictEqual({
concurrency: 2,
size: 2,
taskStealing: false,
tasksStealingOnBackPressure: false,
- tasksFinishedTimeout: 3000
+ tasksFinishedTimeout: 3000,
})
for (const workerNode of pool.workerNodes) {
expect(workerNode.tasksQueueBackPressureSize).toBe(
pool.setTasksQueueOptions({
concurrency: 1,
taskStealing: true,
- tasksStealingOnBackPressure: true
+ tasksStealingOnBackPressure: true,
})
expect(pool.opts.tasksQueueOptions).toStrictEqual({
concurrency: 1,
size: Math.pow(numberOfWorkers, 2),
taskStealing: true,
tasksStealingOnBackPressure: true,
- tasksFinishedTimeout: 2000
+ tasksFinishedTimeout: 2000,
})
for (const workerNode of pool.workerNodes) {
expect(workerNode.tasksQueueBackPressureSize).toBe(
busyWorkerNodes: 0,
executedTasks: 0,
executingTasks: 0,
- failedTasks: 0
+ failedTasks: 0,
})
await pool.destroy()
pool = new DynamicClusterPool(
busyWorkerNodes: 0,
executedTasks: 0,
executingTasks: 0,
- failedTasks: 0
+ failedTasks: 0,
})
await pool.destroy()
})
maxQueued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
waitTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
elu: {
idle: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
active: {
- history: expect.any(CircularBuffer)
- }
- }
+ history: expect.any(CircularBuffer),
+ },
+ },
})
}
await pool.destroy()
dynamic: false,
ready: true,
stealing: false,
- backPressure: false
+ backPressure: false,
})
}
await pool.destroy()
dynamic: false,
ready: true,
stealing: false,
- backPressure: false
+ backPressure: false,
})
}
await pool.destroy()
numberOfWorkers,
'./tests/worker-files/cluster/testWorker.cjs',
{
- startWorkers: false
+ startWorkers: false,
}
)
expect(pool.info.started).toBe(false)
maxQueued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
waitTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
elu: {
idle: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
active: {
- history: expect.any(CircularBuffer)
- }
- }
+ history: expect.any(CircularBuffer),
+ },
+ },
})
}
await Promise.all(promises)
maxQueued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
waitTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
elu: {
idle: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
active: {
- history: expect.any(CircularBuffer)
- }
- }
+ history: expect.any(CircularBuffer),
+ },
+ },
})
}
await pool.destroy()
maxQueued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
waitTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
elu: {
idle: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
active: {
- history: expect.any(CircularBuffer)
- }
- }
+ history: expect.any(CircularBuffer),
+ },
+ },
})
expect(workerNode.usage.tasks.executed).toBeGreaterThan(0)
expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
maxQueued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
waitTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
elu: {
idle: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
active: {
- history: expect.any(CircularBuffer)
- }
- }
+ history: expect.any(CircularBuffer),
+ },
+ },
})
expect(workerNode.usage.tasks.executed).toBeGreaterThan(0)
expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
busyWorkerNodes: expect.any(Number),
executedTasks: expect.any(Number),
executingTasks: expect.any(Number),
- failedTasks: expect.any(Number)
+ failedTasks: expect.any(Number),
})
await pool.destroy()
})
busyWorkerNodes: expect.any(Number),
executedTasks: expect.any(Number),
executingTasks: expect.any(Number),
- failedTasks: expect.any(Number)
+ failedTasks: expect.any(Number),
})
await pool.destroy()
})
busyWorkerNodes: expect.any(Number),
executedTasks: expect.any(Number),
executingTasks: expect.any(Number),
- failedTasks: expect.any(Number)
+ failedTasks: expect.any(Number),
})
await pool.destroy()
})
numberOfWorkers,
'./tests/worker-files/thread/testWorker.mjs',
{
- enableTasksQueue: true
+ enableTasksQueue: true,
}
)
stub(pool, 'hasBackPressure').returns(true)
queuedTasks: expect.any(Number),
backPressure: true,
stolenTasks: expect.any(Number),
- failedTasks: expect.any(Number)
+ failedTasks: expect.any(Number),
})
expect(pool.hasBackPressure.callCount).toBeGreaterThanOrEqual(7)
await pool.destroy()
'./tests/worker-files/thread/asyncWorker.mjs',
{
enableTasksQueue: true,
- tasksQueueOptions: { tasksFinishedTimeout }
+ tasksQueueOptions: { tasksFinishedTimeout },
}
)
const maxMultiplier = 4
'./tests/worker-files/thread/asyncWorker.mjs',
{
enableTasksQueue: true,
- tasksQueueOptions: { tasksFinishedTimeout }
+ tasksQueueOptions: { tasksFinishedTimeout },
}
)
const maxMultiplier = 4
},
promiseResolve () {
if (executionAsyncId() === taskAsyncId) resolveCalls++
- }
+ },
})
const pool = new FixedThreadPool(
numberOfWorkers,
await expect(
dynamicThreadPool.addTaskFunction('test', {
taskFunction: () => {},
- priority: -21
+ priority: -21,
})
).rejects.toThrow(
new RangeError("Property 'priority' must be between -20 and 19")
await expect(
dynamicThreadPool.addTaskFunction('test', {
taskFunction: () => {},
- priority: 20
+ priority: 20,
})
).rejects.toThrow(
new RangeError("Property 'priority' must be between -20 and 19")
await expect(
dynamicThreadPool.addTaskFunction('test', {
taskFunction: () => {},
- strategy: 'invalidStrategy'
+ strategy: 'invalidStrategy',
})
).rejects.toThrow(
new Error("Invalid worker choice strategy 'invalidStrategy'")
)
expect(dynamicThreadPool.listTaskFunctionsProperties()).toStrictEqual([
{ name: DEFAULT_TASK_NAME },
- { name: 'test' }
+ { name: 'test' },
])
expect([
- ...dynamicThreadPool.workerChoiceStrategiesContext.workerChoiceStrategies.keys()
+ ...dynamicThreadPool.workerChoiceStrategiesContext.workerChoiceStrategies.keys(),
]).toStrictEqual([WorkerChoiceStrategies.ROUND_ROBIN])
const echoTaskFunction = data => {
return data
await expect(
dynamicThreadPool.addTaskFunction('echo', {
taskFunction: echoTaskFunction,
- strategy: WorkerChoiceStrategies.LEAST_ELU
+ strategy: WorkerChoiceStrategies.LEAST_ELU,
})
).resolves.toBe(true)
expect(dynamicThreadPool.taskFunctions.size).toBe(1)
expect(dynamicThreadPool.taskFunctions.get('echo')).toStrictEqual({
taskFunction: echoTaskFunction,
- strategy: WorkerChoiceStrategies.LEAST_ELU
+ strategy: WorkerChoiceStrategies.LEAST_ELU,
})
expect([
- ...dynamicThreadPool.workerChoiceStrategiesContext.workerChoiceStrategies.keys()
+ ...dynamicThreadPool.workerChoiceStrategiesContext.workerChoiceStrategies.keys(),
]).toStrictEqual([
WorkerChoiceStrategies.ROUND_ROBIN,
- WorkerChoiceStrategies.LEAST_ELU
+ WorkerChoiceStrategies.LEAST_ELU,
])
expect(dynamicThreadPool.listTaskFunctionsProperties()).toStrictEqual([
{ name: DEFAULT_TASK_NAME },
{ name: 'test' },
- { name: 'echo', strategy: WorkerChoiceStrategies.LEAST_ELU }
+ { name: 'echo', strategy: WorkerChoiceStrategies.LEAST_ELU },
])
const taskFunctionData = { test: 'test' }
const echoResult = await dynamicThreadPool.execute(taskFunctionData, 'echo')
queued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
waitTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
elu: expect.objectContaining({
idle: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
active: expect.objectContaining({
- history: expect.any(CircularBuffer)
- })
- })
+ history: expect.any(CircularBuffer),
+ }),
+ }),
})
expect(
workerNode.getTaskFunctionWorkerUsage('echo').tasks.executed
await waitPoolEvents(dynamicThreadPool, PoolEvents.ready, 1)
expect(dynamicThreadPool.listTaskFunctionsProperties()).toStrictEqual([
{ name: DEFAULT_TASK_NAME },
- { name: 'test' }
+ { name: 'test' },
])
await expect(dynamicThreadPool.removeTaskFunction('test')).rejects.toThrow(
new Error('Cannot remove a task function not handled on the pool side')
}
await dynamicThreadPool.addTaskFunction('echo', {
taskFunction: echoTaskFunction,
- strategy: WorkerChoiceStrategies.LEAST_ELU
+ strategy: WorkerChoiceStrategies.LEAST_ELU,
})
expect(dynamicThreadPool.taskFunctions.size).toBe(1)
expect(dynamicThreadPool.taskFunctions.get('echo')).toStrictEqual({
taskFunction: echoTaskFunction,
- strategy: WorkerChoiceStrategies.LEAST_ELU
+ strategy: WorkerChoiceStrategies.LEAST_ELU,
})
expect([
- ...dynamicThreadPool.workerChoiceStrategiesContext.workerChoiceStrategies.keys()
+ ...dynamicThreadPool.workerChoiceStrategiesContext.workerChoiceStrategies.keys(),
]).toStrictEqual([
WorkerChoiceStrategies.ROUND_ROBIN,
- WorkerChoiceStrategies.LEAST_ELU
+ WorkerChoiceStrategies.LEAST_ELU,
])
expect(dynamicThreadPool.listTaskFunctionsProperties()).toStrictEqual([
{ name: DEFAULT_TASK_NAME },
{ name: 'test' },
- { name: 'echo', strategy: WorkerChoiceStrategies.LEAST_ELU }
+ { name: 'echo', strategy: WorkerChoiceStrategies.LEAST_ELU },
])
await expect(dynamicThreadPool.removeTaskFunction('echo')).resolves.toBe(
true
expect(dynamicThreadPool.taskFunctions.size).toBe(0)
expect(dynamicThreadPool.taskFunctions.get('echo')).toBeUndefined()
expect([
- ...dynamicThreadPool.workerChoiceStrategiesContext.workerChoiceStrategies.keys()
+ ...dynamicThreadPool.workerChoiceStrategiesContext.workerChoiceStrategies.keys(),
]).toStrictEqual([WorkerChoiceStrategies.ROUND_ROBIN])
expect(dynamicThreadPool.listTaskFunctionsProperties()).toStrictEqual([
{ name: DEFAULT_TASK_NAME },
- { name: 'test' }
+ { name: 'test' },
])
await dynamicThreadPool.destroy()
})
{ name: DEFAULT_TASK_NAME },
{ name: 'jsonIntegerSerialization' },
{ name: 'factorial' },
- { name: 'fibonacci' }
+ { name: 'fibonacci' },
])
await dynamicThreadPool.destroy()
const fixedClusterPool = new FixedClusterPool(
{ name: DEFAULT_TASK_NAME },
{ name: 'jsonIntegerSerialization' },
{ name: 'factorial' },
- { name: 'fibonacci' }
+ { name: 'fibonacci' },
])
await fixedClusterPool.destroy()
})
{ name: DEFAULT_TASK_NAME },
{ name: 'jsonIntegerSerialization' },
{ name: 'factorial' },
- { name: 'fibonacci' }
+ { name: 'fibonacci' },
])
await expect(
dynamicThreadPool.setDefaultTaskFunction('factorial')
{ name: DEFAULT_TASK_NAME },
{ name: 'factorial' },
{ name: 'jsonIntegerSerialization' },
- { name: 'fibonacci' }
+ { name: 'fibonacci' },
])
await expect(
dynamicThreadPool.setDefaultTaskFunction('fibonacci')
{ name: DEFAULT_TASK_NAME },
{ name: 'fibonacci' },
{ name: 'jsonIntegerSerialization' },
- { name: 'factorial' }
+ { name: 'factorial' },
])
await dynamicThreadPool.destroy()
})
{ name: DEFAULT_TASK_NAME },
{ name: 'jsonIntegerSerialization' },
{ name: 'factorial' },
- { name: 'fibonacci' }
+ { name: 'fibonacci' },
])
expect(workerNode.taskFunctionsUsage.size).toBe(3)
expect(workerNode.usage.tasks.executed).toBeGreaterThan(0)
failed: 0,
queued: 0,
sequentiallyStolen: 0,
- stolen: 0
+ stolen: 0,
},
runTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
waitTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
elu: {
idle: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
active: {
- history: expect.any(CircularBuffer)
- }
- }
+ history: expect.any(CircularBuffer),
+ },
+ },
})
expect(
workerNode.getTaskFunctionWorkerUsage(taskFunctionProperties.name)
{ name: DEFAULT_TASK_NAME },
{ name: 'jsonIntegerSerialization' },
{ name: 'factorial' },
- { name: 'fibonacci', priority: -5 }
+ { name: 'fibonacci', priority: -5 },
])
expect(workerNode.taskFunctionsUsage.size).toBe(3)
expect(workerNode.usage.tasks.executed).toBeGreaterThan(0)
failed: 0,
queued: 0,
sequentiallyStolen: 0,
- stolen: 0
+ stolen: 0,
},
runTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
waitTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
elu: {
idle: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
active: {
- history: expect.any(CircularBuffer)
- }
- }
+ history: expect.any(CircularBuffer),
+ },
+ },
})
expect(
workerNode.getTaskFunctionWorkerUsage(taskFunctionProperties.name)
pool.sendTaskFunctionOperationToWorker(workerNodeKey, {
taskFunctionOperation: 'add',
taskFunctionProperties: { name: 'empty' },
- taskFunction: (() => {}).toString()
+ taskFunction: (() => {}).toString(),
})
).resolves.toBe(true)
expect(
).toStrictEqual([
{ name: DEFAULT_TASK_NAME },
{ name: 'test' },
- { name: 'empty' }
+ { name: 'empty' },
])
await pool.destroy()
})
pool.sendTaskFunctionOperationToWorkers({
taskFunctionOperation: 'add',
taskFunctionProperties: { name: 'empty' },
- taskFunction: (() => {}).toString()
+ taskFunction: (() => {}).toString(),
})
).resolves.toBe(true)
for (const workerNode of pool.workerNodes) {
expect(workerNode.info.taskFunctionsProperties).toStrictEqual([
{ name: DEFAULT_TASK_NAME },
{ name: 'test' },
- { name: 'empty' }
+ { name: 'empty' },
])
}
await pool.destroy()
import {
DynamicClusterPool,
PoolEvents,
- WorkerChoiceStrategies
+ WorkerChoiceStrategies,
} from '../../../lib/index.cjs'
import { TaskFunctions } from '../../test-types.cjs'
import { sleep, waitPoolEvents, waitWorkerEvents } from '../../test-utils.cjs'
max,
'./tests/worker-files/cluster/testWorker.cjs',
{
- errorHandler: e => console.error(e)
+ errorHandler: e => console.error(e),
}
)
it('Verify that the function is executed in a worker cluster', async () => {
let result = await pool.execute({
- function: TaskFunctions.fibonacci
+ function: TaskFunctions.fibonacci,
})
expect(result).toBe(354224848179262000000)
result = await pool.execute({
- function: TaskFunctions.factorial
+ function: TaskFunctions.factorial,
})
expect(result).toBe(9.33262154439441e157)
})
pool.emitter.on(PoolEvents.destroy, () => ++poolDestroy)
expect(pool.emitter.eventNames()).toStrictEqual([
PoolEvents.busy,
- PoolEvents.destroy
+ PoolEvents.destroy,
])
await pool.destroy()
const numberOfExitEvents = await exitPromise
expect(pool.started).toBe(false)
expect(pool.emitter.eventNames()).toStrictEqual([
PoolEvents.busy,
- PoolEvents.destroy
+ PoolEvents.destroy,
])
expect(pool.readyEventEmitted).toBe(false)
expect(pool.workerNodes.length).toBe(0)
{
errorHandler: e => console.error(e),
onlineHandler: () => console.info('long executing worker is online'),
- exitHandler: () => console.info('long executing worker exited')
+ exitHandler: () => console.info('long executing worker exited'),
}
)
expect(longRunningPool.workerNodes.length).toBe(min)
{
errorHandler: e => console.error(e),
onlineHandler: () => console.info('long executing worker is online'),
- exitHandler: () => console.info('long executing worker exited')
+ exitHandler: () => console.info('long executing worker exited'),
}
)
expect(longRunningPool.workerNodes.length).toBe(min)
max,
'./tests/worker-files/cluster/testWorker.cjs',
{
- workerChoiceStrategy
+ workerChoiceStrategy,
}
)
expect(pool.starting).toBe(false)
expect(pool.readyEventEmitted).toBe(false)
for (let run = 0; run < 2; run++) {
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
run % 2 !== 0 && pool.enableTasksQueue(true)
const maxMultiplier = 4
const promises = new Set()
numberOfWorkers,
'./tests/worker-files/cluster/testWorker.cjs',
{
- errorHandler: e => console.error(e)
+ errorHandler: e => console.error(e),
}
)
const queuePool = new FixedClusterPool(
{
enableTasksQueue: true,
tasksQueueOptions: {
- concurrency: tasksConcurrency
+ concurrency: tasksConcurrency,
},
- errorHandler: e => console.error(e)
+ errorHandler: e => console.error(e),
}
)
const emptyPool = new FixedClusterPool(
numberOfWorkers,
'./tests/worker-files/cluster/errorWorker.cjs',
{
- errorHandler: e => console.error(e)
+ errorHandler: e => console.error(e),
}
)
const asyncErrorPool = new FixedClusterPool(
numberOfWorkers,
'./tests/worker-files/cluster/asyncErrorWorker.cjs',
{
- errorHandler: e => console.error(e)
+ errorHandler: e => console.error(e),
}
)
const asyncPool = new FixedClusterPool(
it('Verify that the function is executed in a worker cluster', async () => {
let result = await pool.execute({
- function: TaskFunctions.fibonacci
+ function: TaskFunctions.fibonacci,
})
expect(result).toBe(354224848179262000000)
result = await pool.execute({
- function: TaskFunctions.factorial
+ function: TaskFunctions.factorial,
})
expect(result).toBe(9.33262154439441e157)
})
numberOfWorkers,
'./tests/worker-files/cluster/testWorker.cjs',
{
- errorHandler: e => console.error(e)
+ errorHandler: e => console.error(e),
}
)
expect(pool.emitter.eventNames()).toStrictEqual([])
expect(taskError).toStrictEqual({
name: DEFAULT_TASK_NAME,
message: 'Error Message from ClusterWorker',
- data
+ data,
})
expect(
errorPool.workerNodes.some(
taskError = e
})
expect(asyncErrorPool.emitter.eventNames()).toStrictEqual([
- PoolEvents.taskError
+ PoolEvents.taskError,
])
let inError
try {
expect(taskError).toStrictEqual({
name: DEFAULT_TASK_NAME,
message: 'Error Message from ClusterWorker:async',
- data
+ data,
})
expect(
asyncErrorPool.workerNodes.some(
pool.emitter.on(PoolEvents.destroy, () => ++poolDestroy)
expect(pool.emitter.eventNames()).toStrictEqual([
PoolEvents.busy,
- PoolEvents.destroy
+ PoolEvents.destroy,
])
await pool.destroy()
const numberOfExitEvents = await exitPromise
expect(pool.started).toBe(false)
expect(pool.emitter.eventNames()).toStrictEqual([
PoolEvents.busy,
- PoolEvents.destroy
+ PoolEvents.destroy,
])
expect(pool.readyEventEmitted).toBe(false)
expect(pool.workerNodes.length).toBe(0)
expect(pool.opts.settings).toBeUndefined()
expect(cluster.settings).toMatchObject({
exec: workerFilePath,
- silent: false
+ silent: false,
})
await pool.destroy()
pool = new FixedClusterPool(numberOfWorkers, workerFilePath, {
env: { TEST: 'test' },
- settings: { args: ['--use', 'http'], silent: true }
+ settings: { args: ['--use', 'http'], silent: true },
})
expect(pool.opts.env).toStrictEqual({ TEST: 'test' })
expect(pool.opts.settings).toStrictEqual({
args: ['--use', 'http'],
- silent: true
+ silent: true,
})
expect(cluster.settings).toMatchObject({
args: ['--use', 'http'],
silent: true,
- exec: workerFilePath
+ exec: workerFilePath,
})
await pool.destroy()
})
import { FixedClusterPool, FixedThreadPool } from '../../../lib/index.cjs'
import {
buildWorkerChoiceStrategyOptions,
- getWorkerChoiceStrategiesRetries
+ getWorkerChoiceStrategiesRetries,
} from '../../../lib/pools/selection-strategies/selection-strategies-utils.cjs'
describe('Selection strategies utils test suite', () => {
elu: { median: false },
weights: expect.objectContaining({
0: expect.any(Number),
- [pool.info.maxSize - 1]: expect.any(Number)
- })
+ [pool.info.maxSize - 1]: expect.any(Number),
+ }),
})
const workerChoiceStrategyOptions = {
runTime: { median: true },
elu: { median: true },
weights: {
0: 100,
- 1: 100
- }
+ 1: 100,
+ },
}
expect(
buildWorkerChoiceStrategyOptions(pool, workerChoiceStrategyOptions)
elu: { median: true },
weights: {
0: 100,
- 1: 100
- }
+ 1: 100,
+ },
}
expect(
getWorkerChoiceStrategiesRetries(pool, workerChoiceStrategyOptions)
DynamicThreadPool,
FixedClusterPool,
FixedThreadPool,
- WorkerChoiceStrategies
+ WorkerChoiceStrategies,
} from '../../../lib/index.cjs'
describe('Selection strategies test suite', () => {
)
expect(pool.workerChoiceStrategiesContext.getPolicy()).toStrictEqual({
dynamicWorkerUsage: false,
- dynamicWorkerReady: true
+ dynamicWorkerReady: true,
})
await pool.destroy()
pool = new DynamicThreadPool(
)
expect(pool.workerChoiceStrategiesContext.getPolicy()).toStrictEqual({
dynamicWorkerUsage: false,
- dynamicWorkerReady: true
+ dynamicWorkerReady: true,
})
// We need to clean up the resources after our test
await pool.destroy()
runTime: {
aggregate: false,
average: false,
- median: false
+ median: false,
},
waitTime: {
aggregate: false,
average: false,
- median: false
+ median: false,
},
elu: {
aggregate: false,
average: false,
- median: false
- }
+ median: false,
+ },
})
await pool.destroy()
pool = new DynamicThreadPool(
runTime: {
aggregate: false,
average: false,
- median: false
+ median: false,
},
waitTime: {
aggregate: false,
average: false,
- median: false
+ median: false,
},
elu: {
aggregate: false,
average: false,
- median: false
- }
+ median: false,
+ },
})
// We need to clean up the resources after our test
await pool.destroy()
maxQueued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
waitTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
elu: {
idle: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
active: {
- history: expect.any(CircularBuffer)
- }
- }
+ history: expect.any(CircularBuffer),
+ },
+ },
})
}
expect(
maxQueued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
waitTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
elu: {
idle: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
active: {
- history: expect.any(CircularBuffer)
- }
- }
+ history: expect.any(CircularBuffer),
+ },
+ },
})
expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
)
expect(pool.workerChoiceStrategiesContext.getPolicy()).toStrictEqual({
dynamicWorkerUsage: false,
- dynamicWorkerReady: true
+ dynamicWorkerReady: true,
})
await pool.destroy()
pool = new DynamicThreadPool(
)
expect(pool.workerChoiceStrategiesContext.getPolicy()).toStrictEqual({
dynamicWorkerUsage: false,
- dynamicWorkerReady: true
+ dynamicWorkerReady: true,
})
// We need to clean up the resources after our test
await pool.destroy()
runTime: {
aggregate: false,
average: false,
- median: false
+ median: false,
},
waitTime: {
aggregate: false,
average: false,
- median: false
+ median: false,
},
elu: {
aggregate: false,
average: false,
- median: false
- }
+ median: false,
+ },
})
await pool.destroy()
pool = new DynamicThreadPool(
runTime: {
aggregate: false,
average: false,
- median: false
+ median: false,
},
waitTime: {
aggregate: false,
average: false,
- median: false
+ median: false,
},
elu: {
aggregate: false,
average: false,
- median: false
- }
+ median: false,
+ },
})
// We need to clean up the resources after our test
await pool.destroy()
maxQueued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
waitTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
elu: {
idle: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
active: {
- history: expect.any(CircularBuffer)
- }
- }
+ history: expect.any(CircularBuffer),
+ },
+ },
})
expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
maxQueued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
waitTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
elu: {
idle: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
active: {
- history: expect.any(CircularBuffer)
- }
- }
+ history: expect.any(CircularBuffer),
+ },
+ },
})
expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
)
expect(pool.workerChoiceStrategiesContext.getPolicy()).toStrictEqual({
dynamicWorkerUsage: false,
- dynamicWorkerReady: true
+ dynamicWorkerReady: true,
})
await pool.destroy()
pool = new DynamicThreadPool(
)
expect(pool.workerChoiceStrategiesContext.getPolicy()).toStrictEqual({
dynamicWorkerUsage: false,
- dynamicWorkerReady: true
+ dynamicWorkerReady: true,
})
// We need to clean up the resources after our test
await pool.destroy()
runTime: {
aggregate: true,
average: false,
- median: false
+ median: false,
},
waitTime: {
aggregate: true,
average: false,
- median: false
+ median: false,
},
elu: {
aggregate: false,
average: false,
- median: false
- }
+ median: false,
+ },
})
await pool.destroy()
pool = new DynamicThreadPool(
runTime: {
aggregate: true,
average: false,
- median: false
+ median: false,
},
waitTime: {
aggregate: true,
average: false,
- median: false
+ median: false,
},
elu: {
aggregate: false,
average: false,
- median: false
- }
+ median: false,
+ },
})
// We need to clean up the resources after our test
await pool.destroy()
maxQueued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
waitTime: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
elu: {
idle: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
active: {
- history: expect.any(CircularBuffer)
- }
- }
+ history: expect.any(CircularBuffer),
+ },
+ },
})
expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
maxQueued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
waitTime: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
elu: {
idle: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
active: {
- history: expect.any(CircularBuffer)
- }
- }
+ history: expect.any(CircularBuffer),
+ },
+ },
})
expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
)
expect(pool.workerChoiceStrategiesContext.getPolicy()).toStrictEqual({
dynamicWorkerUsage: false,
- dynamicWorkerReady: true
+ dynamicWorkerReady: true,
})
await pool.destroy()
pool = new DynamicThreadPool(
)
expect(pool.workerChoiceStrategiesContext.getPolicy()).toStrictEqual({
dynamicWorkerUsage: false,
- dynamicWorkerReady: true
+ dynamicWorkerReady: true,
})
// We need to clean up the resources after our test
await pool.destroy()
runTime: {
aggregate: false,
average: false,
- median: false
+ median: false,
},
waitTime: {
aggregate: false,
average: false,
- median: false
+ median: false,
},
elu: {
aggregate: true,
average: false,
- median: false
- }
+ median: false,
+ },
})
await pool.destroy()
pool = new DynamicThreadPool(
runTime: {
aggregate: false,
average: false,
- median: false
+ median: false,
},
waitTime: {
aggregate: false,
average: false,
- median: false
+ median: false,
},
elu: {
aggregate: true,
average: false,
- median: false
- }
+ median: false,
+ },
})
// We need to clean up the resources after our test
await pool.destroy()
maxQueued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
waitTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
elu: expect.objectContaining({
idle: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
active: expect.objectContaining({
- history: expect.any(CircularBuffer)
- })
- })
+ history: expect.any(CircularBuffer),
+ }),
+ }),
})
expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
maxQueued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
waitTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
elu: expect.objectContaining({
idle: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
active: expect.objectContaining({
- history: expect.any(CircularBuffer)
- })
- })
+ history: expect.any(CircularBuffer),
+ }),
+ }),
})
expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
)
expect(pool.workerChoiceStrategiesContext.getPolicy()).toStrictEqual({
dynamicWorkerUsage: false,
- dynamicWorkerReady: true
+ dynamicWorkerReady: true,
})
await pool.destroy()
pool = new DynamicThreadPool(
)
expect(pool.workerChoiceStrategiesContext.getPolicy()).toStrictEqual({
dynamicWorkerUsage: false,
- dynamicWorkerReady: true
+ dynamicWorkerReady: true,
})
// We need to clean up the resources after our test
await pool.destroy()
runTime: {
aggregate: true,
average: true,
- median: false
+ median: false,
},
waitTime: {
aggregate: true,
average: true,
- median: false
+ median: false,
},
elu: {
aggregate: true,
average: true,
- median: false
- }
+ median: false,
+ },
})
await pool.destroy()
pool = new DynamicThreadPool(
runTime: {
aggregate: true,
average: true,
- median: false
+ median: false,
},
waitTime: {
aggregate: true,
average: true,
- median: false
+ median: false,
},
elu: {
aggregate: true,
average: true,
- median: false
- }
+ median: false,
+ },
})
// We need to clean up the resources after our test
await pool.destroy()
maxQueued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
waitTime: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
elu: expect.objectContaining({
idle: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
active: expect.objectContaining({
- history: expect.any(CircularBuffer)
- })
- })
+ history: expect.any(CircularBuffer),
+ }),
+ }),
})
expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
maxQueued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
waitTime: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
elu: expect.objectContaining({
idle: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
active: expect.objectContaining({
- history: expect.any(CircularBuffer)
- })
- })
+ history: expect.any(CircularBuffer),
+ }),
+ }),
})
expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
{
workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE,
workerChoiceStrategyOptions: {
- runTime: { median: true }
- }
+ runTime: { median: true },
+ },
}
)
// TODO: Create a better test to cover `FairShareChoiceStrategy#choose`
maxQueued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
waitTime: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
elu: expect.objectContaining({
idle: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
active: expect.objectContaining({
- history: expect.any(CircularBuffer)
- })
- })
+ history: expect.any(CircularBuffer),
+ }),
+ }),
})
expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
)
for (const workerNode of pool.workerNodes) {
workerNode.strategyData = {
- virtualTaskEndTimestamp: performance.now()
+ virtualTaskEndTimestamp: performance.now(),
}
}
pool.setWorkerChoiceStrategy(workerChoiceStrategy)
)
for (const workerNode of pool.workerNodes) {
workerNode.strategyData = {
- virtualTaskEndTimestamp: performance.now()
+ virtualTaskEndTimestamp: performance.now(),
}
}
pool.setWorkerChoiceStrategy(workerChoiceStrategy)
)
expect(pool.workerChoiceStrategiesContext.getPolicy()).toStrictEqual({
dynamicWorkerUsage: false,
- dynamicWorkerReady: true
+ dynamicWorkerReady: true,
})
await pool.destroy()
pool = new DynamicThreadPool(
)
expect(pool.workerChoiceStrategiesContext.getPolicy()).toStrictEqual({
dynamicWorkerUsage: false,
- dynamicWorkerReady: true
+ dynamicWorkerReady: true,
})
// We need to clean up the resources after our test
await pool.destroy()
runTime: {
aggregate: true,
average: true,
- median: false
+ median: false,
},
waitTime: {
aggregate: true,
average: true,
- median: false
+ median: false,
},
elu: {
aggregate: false,
average: false,
- median: false
- }
+ median: false,
+ },
})
await pool.destroy()
pool = new DynamicThreadPool(
runTime: {
aggregate: true,
average: true,
- median: false
+ median: false,
},
waitTime: {
aggregate: true,
average: true,
- median: false
+ median: false,
},
elu: {
aggregate: false,
average: false,
- median: false
- }
+ median: false,
+ },
})
// We need to clean up the resources after our test
await pool.destroy()
maxQueued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
waitTime: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
elu: {
idle: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
active: {
- history: expect.any(CircularBuffer)
- }
- }
+ history: expect.any(CircularBuffer),
+ },
+ },
})
expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
maxQueued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
waitTime: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
elu: {
idle: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
active: {
- history: expect.any(CircularBuffer)
- }
- }
+ history: expect.any(CircularBuffer),
+ },
+ },
})
expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
{
workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN,
workerChoiceStrategyOptions: {
- runTime: { median: true }
- }
+ runTime: { median: true },
+ },
}
)
// TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose`
maxQueued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
waitTime: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
elu: {
idle: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
active: {
- history: expect.any(CircularBuffer)
- }
- }
+ history: expect.any(CircularBuffer),
+ },
+ },
})
expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
)
expect(pool.workerChoiceStrategiesContext.getPolicy()).toStrictEqual({
dynamicWorkerUsage: false,
- dynamicWorkerReady: true
+ dynamicWorkerReady: true,
})
await pool.destroy()
pool = new DynamicThreadPool(
)
expect(pool.workerChoiceStrategiesContext.getPolicy()).toStrictEqual({
dynamicWorkerUsage: false,
- dynamicWorkerReady: true
+ dynamicWorkerReady: true,
})
// We need to clean up the resources after our test
await pool.destroy()
runTime: {
aggregate: true,
average: true,
- median: false
+ median: false,
},
waitTime: {
aggregate: true,
average: true,
- median: false
+ median: false,
},
elu: {
aggregate: false,
average: false,
- median: false
- }
+ median: false,
+ },
})
await pool.destroy()
pool = new DynamicThreadPool(
runTime: {
aggregate: true,
average: true,
- median: false
+ median: false,
},
waitTime: {
aggregate: true,
average: true,
- median: false
+ median: false,
},
elu: {
aggregate: false,
average: false,
- median: false
- }
+ median: false,
+ },
})
// We need to clean up the resources after our test
await pool.destroy()
'./tests/worker-files/thread/testWorker.mjs',
{
workerChoiceStrategy:
- WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
+ WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN,
}
)
// TODO: Create a better test to cover `InterleavedWeightedRoundRobinWorkerChoiceStrategy#choose`
maxQueued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
waitTime: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
elu: {
idle: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
active: {
- history: expect.any(CircularBuffer)
- }
- }
+ history: expect.any(CircularBuffer),
+ },
+ },
})
expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
'./tests/worker-files/thread/testWorker.mjs',
{
workerChoiceStrategy:
- WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
+ WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN,
}
)
// TODO: Create a better test to cover `InterleavedWeightedRoundRobinWorkerChoiceStrategy#choose`
maxQueued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
waitTime: expect.objectContaining({
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
}),
elu: {
idle: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
active: {
- history: expect.any(CircularBuffer)
- }
- }
+ history: expect.any(CircularBuffer),
+ },
+ },
})
expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
import {
DynamicThreadPool,
FixedThreadPool,
- WorkerChoiceStrategies
+ WorkerChoiceStrategies,
} from '../../../lib/index.cjs'
import { FairShareWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/fair-share-worker-choice-strategy.cjs'
import { InterleavedWeightedRoundRobinWorkerChoiceStrategy } from '../../../lib/pools/selection-strategies/interleaved-weighted-round-robin-worker-choice-strategy.cjs'
const workerChoiceStrategyUndefinedStub = createStubInstance(
RoundRobinWorkerChoiceStrategy,
{
- choose: stub().returns(undefined)
+ choose: stub().returns(undefined),
}
)
workerChoiceStrategiesContext.workerChoiceStrategies.set(
const workerChoiceStrategyNullStub = createStubInstance(
RoundRobinWorkerChoiceStrategy,
{
- choose: stub().returns(null)
+ choose: stub().returns(null),
}
)
workerChoiceStrategiesContext.workerChoiceStrategies.set(
.returns(undefined)
.onCall(4)
.returns(undefined)
- .returns(1)
+ .returns(1),
}
)
expect(workerChoiceStrategiesContext.defaultWorkerChoiceStrategy).toBe(
const workerChoiceStrategyStub = createStubInstance(
RoundRobinWorkerChoiceStrategy,
{
- choose: stub().returns(0)
+ choose: stub().returns(0),
}
)
expect(workerChoiceStrategiesContext.defaultWorkerChoiceStrategy).toBe(
const workerChoiceStrategyStub = createStubInstance(
RoundRobinWorkerChoiceStrategy,
{
- choose: stub().returns(0)
+ choose: stub().returns(0),
}
)
expect(workerChoiceStrategiesContext.defaultWorkerChoiceStrategy).toBe(
[wwrWorkerChoiceStrategy],
{
runTime: { median: true },
- waitTime: { median: true }
+ waitTime: { median: true },
}
)
expect(
[wwrWorkerChoiceStrategy],
{
runTime: { median: true },
- waitTime: { median: true }
+ waitTime: { median: true },
}
)
expect(
[fsWorkerChoiceStrategy],
{
runTime: { median: true },
- waitTime: { median: true }
+ waitTime: { median: true },
}
)
expect(
[fsWorkerChoiceStrategy],
{
runTime: { median: true },
- waitTime: { median: true }
+ waitTime: { median: true },
}
)
expect(
import {
DynamicThreadPool,
PoolEvents,
- WorkerChoiceStrategies
+ WorkerChoiceStrategies,
} from '../../../lib/index.cjs'
import { TaskFunctions } from '../../test-types.cjs'
import { sleep, waitPoolEvents, waitWorkerEvents } from '../../test-utils.cjs'
max,
'./tests/worker-files/thread/testWorker.mjs',
{
- errorHandler: e => console.error(e)
+ errorHandler: e => console.error(e),
}
)
it('Verify that the function is executed in a worker thread', async () => {
let result = await pool.execute({
- function: TaskFunctions.fibonacci
+ function: TaskFunctions.fibonacci,
})
expect(result).toBe(354224848179262000000)
result = await pool.execute({
- function: TaskFunctions.factorial
+ function: TaskFunctions.factorial,
})
expect(result).toBe(9.33262154439441e157)
})
pool.emitter.on(PoolEvents.destroy, () => ++poolDestroy)
expect(pool.emitter.eventNames()).toStrictEqual([
PoolEvents.busy,
- PoolEvents.destroy
+ PoolEvents.destroy,
])
await pool.destroy()
const numberOfExitEvents = await exitPromise
expect(pool.started).toBe(false)
expect(pool.emitter.eventNames()).toStrictEqual([
PoolEvents.busy,
- PoolEvents.destroy
+ PoolEvents.destroy,
])
expect(pool.readyEventEmitted).toBe(false)
expect(pool.workerNodes.length).toBe(0)
{
errorHandler: e => console.error(e),
onlineHandler: () => console.info('long executing worker is online'),
- exitHandler: () => console.info('long executing worker exited')
+ exitHandler: () => console.info('long executing worker exited'),
}
)
expect(longRunningPool.workerNodes.length).toBe(min)
{
errorHandler: e => console.error(e),
onlineHandler: () => console.info('long executing worker is online'),
- exitHandler: () => console.info('long executing worker exited')
+ exitHandler: () => console.info('long executing worker exited'),
}
)
expect(longRunningPool.workerNodes.length).toBe(min)
max,
'./tests/worker-files/thread/testWorker.mjs',
{
- workerChoiceStrategy
+ workerChoiceStrategy,
}
)
expect(pool.starting).toBe(false)
expect(pool.readyEventEmitted).toBe(false)
for (let run = 0; run < 2; run++) {
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
run % 2 !== 0 && pool.enableTasksQueue(true)
const maxMultiplier = 4
const promises = new Set()
numberOfThreads,
'./tests/worker-files/thread/testWorker.mjs',
{
- errorHandler: e => console.error(e)
+ errorHandler: e => console.error(e),
}
)
const queuePool = new FixedThreadPool(
{
enableTasksQueue: true,
tasksQueueOptions: {
- concurrency: tasksConcurrency
+ concurrency: tasksConcurrency,
},
- errorHandler: e => console.error(e)
+ errorHandler: e => console.error(e),
}
)
const emptyPool = new FixedThreadPool(
numberOfThreads,
'./tests/worker-files/thread/errorWorker.mjs',
{
- errorHandler: e => console.error(e)
+ errorHandler: e => console.error(e),
}
)
const asyncErrorPool = new FixedThreadPool(
numberOfThreads,
'./tests/worker-files/thread/asyncErrorWorker.mjs',
{
- errorHandler: e => console.error(e)
+ errorHandler: e => console.error(e),
}
)
const asyncPool = new FixedThreadPool(
it('Verify that the function is executed in a worker thread', async () => {
let result = await pool.execute({
- function: TaskFunctions.fibonacci
+ function: TaskFunctions.fibonacci,
})
expect(result).toBe(354224848179262000000)
result = await pool.execute({
- function: TaskFunctions.factorial
+ function: TaskFunctions.factorial,
})
expect(result).toBe(9.33262154439441e157)
})
numberOfThreads,
'./tests/worker-files/thread/testWorker.mjs',
{
- errorHandler: e => console.error(e)
+ errorHandler: e => console.error(e),
}
)
expect(pool.emitter.eventNames()).toStrictEqual([])
try {
result = await pool.execute(undefined, undefined, [
new ArrayBuffer(16),
- new MessageChannel().port1
+ new MessageChannel().port1,
])
} catch (e) {
error = e
expect(error).toBeUndefined()
try {
result = await pool.execute(undefined, undefined, [
- new SharedArrayBuffer(16)
+ new SharedArrayBuffer(16),
])
} catch (e) {
error = e
expect(taskError).toStrictEqual({
name: DEFAULT_TASK_NAME,
message: new Error('Error Message from ThreadWorker'),
- data
+ data,
})
expect(
errorPool.workerNodes.some(
taskError = e
})
expect(asyncErrorPool.emitter.eventNames()).toStrictEqual([
- PoolEvents.taskError
+ PoolEvents.taskError,
])
let inError
try {
expect(taskError).toStrictEqual({
name: DEFAULT_TASK_NAME,
message: new Error('Error Message from ThreadWorker:async'),
- data
+ data,
})
expect(
asyncErrorPool.workerNodes.some(
pool.emitter.on(PoolEvents.destroy, () => ++poolDestroy)
expect(pool.emitter.eventNames()).toStrictEqual([
PoolEvents.busy,
- PoolEvents.destroy
+ PoolEvents.destroy,
])
await pool.destroy()
const numberOfExitEvents = await exitPromise
expect(pool.started).toBe(false)
expect(pool.emitter.eventNames()).toStrictEqual([
PoolEvents.busy,
- PoolEvents.destroy
+ PoolEvents.destroy,
])
expect(pool.readyEventEmitted).toBe(false)
expect(pool.workerNodes.length).toBe(0)
pool = new FixedThreadPool(numberOfThreads, workerFilePath, {
workerOptions: {
env: { TEST: 'test' },
- name: 'test'
- }
+ name: 'test',
+ },
})
expect(pool.opts.workerOptions).toStrictEqual({
env: { TEST: 'test' },
- name: 'test'
+ name: 'test',
})
await pool.destroy()
})
getDefaultTasksQueueOptions,
getWorkerId,
getWorkerType,
- updateMeasurementStatistics
+ updateMeasurementStatistics,
} from '../../lib/pools/utils.cjs'
import { MeasurementHistorySize } from '../../lib/pools/worker.cjs'
expect(DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS).toStrictEqual({
aggregate: false,
average: false,
- median: false
+ median: false,
})
})
size: Math.pow(poolMaxSize, 2),
taskStealing: true,
tasksStealingOnBackPressure: false,
- tasksFinishedTimeout: 2000
+ tasksFinishedTimeout: 2000,
})
})
it('Verify updateMeasurementStatistics() behavior', () => {
const measurementStatistics = {
- history: new CircularBuffer(MeasurementHistorySize)
+ history: new CircularBuffer(MeasurementHistorySize),
}
updateMeasurementStatistics(
measurementStatistics,
expect(measurementStatistics).toMatchObject({
aggregate: 0.01,
maximum: 0.01,
- minimum: 0.01
+ minimum: 0.01,
})
updateMeasurementStatistics(
measurementStatistics,
expect(measurementStatistics).toMatchObject({
aggregate: 0.03,
maximum: 0.02,
- minimum: 0.01
+ minimum: 0.01,
})
updateMeasurementStatistics(
measurementStatistics,
aggregate: 0.031,
maximum: 0.02,
minimum: 0.001,
- average: 0.0010000000474974513
+ average: 0.0010000000474974513,
})
updateMeasurementStatistics(
measurementStatistics,
aggregate: 0.034,
maximum: 0.02,
minimum: 0.001,
- average: 0.0020000000367872417
+ average: 0.0020000000367872417,
})
updateMeasurementStatistics(
measurementStatistics,
aggregate: 0.04,
maximum: 0.02,
minimum: 0.001,
- median: 0.003000000026077032
+ median: 0.003000000026077032,
})
updateMeasurementStatistics(
measurementStatistics,
aggregate: 0.05,
maximum: 0.02,
minimum: 0.001,
- average: 0.004999999975552782
+ average: 0.004999999975552782,
})
})
{
tasksQueueBackPressureSize: 12,
tasksQueueBucketSize: 6,
- tasksQueuePriority: true
+ tasksQueuePriority: true,
}
)
const clusterWorkerNode = new WorkerNode(
{
tasksQueueBackPressureSize: 12,
tasksQueueBucketSize: 6,
- tasksQueuePriority: true
+ tasksQueuePriority: true,
}
)
WorkerTypes.thread,
'./tests/worker-files/thread/testWorker.mjs',
{
- tasksQueueBackPressureSize: 12
+ tasksQueueBackPressureSize: 12,
}
)
).toThrow(
'./tests/worker-files/thread/testWorker.mjs',
{
tasksQueueBackPressureSize: 12,
- tasksQueueBucketSize: 'invalidTasksQueueBucketSize'
+ tasksQueueBucketSize: 'invalidTasksQueueBucketSize',
}
)
).toThrow(
'./tests/worker-files/thread/testWorker.mjs',
{
tasksQueueBackPressureSize: 12,
- tasksQueueBucketSize: 6
+ tasksQueueBucketSize: 6,
}
)
).toThrow(
{
tasksQueueBackPressureSize: 12,
tasksQueueBucketSize: 6,
- tasksQueuePriority: 'invalidTasksQueuePriority'
+ tasksQueuePriority: 'invalidTasksQueuePriority',
}
)
).toThrow(
dynamic: false,
ready: false,
stealing: false,
- backPressure: false
+ backPressure: false,
})
expect(threadWorkerNode.usage).toStrictEqual({
tasks: {
maxQueued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
waitTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
elu: {
idle: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
active: {
- history: expect.any(CircularBuffer)
- }
- }
+ history: expect.any(CircularBuffer),
+ },
+ },
})
expect(threadWorkerNode.messageChannel).toBeInstanceOf(MessageChannel)
expect(threadWorkerNode.tasksQueueBackPressureSize).toBe(12)
dynamic: false,
ready: false,
stealing: false,
- backPressure: false
+ backPressure: false,
})
expect(clusterWorkerNode.usage).toStrictEqual({
tasks: {
maxQueued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
waitTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
elu: {
idle: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
active: {
- history: expect.any(CircularBuffer)
- }
- }
+ history: expect.any(CircularBuffer),
+ },
+ },
})
expect(clusterWorkerNode.messageChannel).toBeUndefined()
expect(clusterWorkerNode.tasksQueueBackPressureSize).toBe(12)
)
threadWorkerNode.info.taskFunctionsProperties = [
{ name: DEFAULT_TASK_NAME },
- { name: 'fn1' }
+ { name: 'fn1' },
]
expect(() =>
threadWorkerNode.getTaskFunctionWorkerUsage('invalidTaskFunction')
threadWorkerNode.info.taskFunctionsProperties = [
{ name: DEFAULT_TASK_NAME },
{ name: 'fn1' },
- { name: 'fn2' }
+ { name: 'fn2' },
]
expect(
threadWorkerNode.getTaskFunctionWorkerUsage(DEFAULT_TASK_NAME)
queued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
waitTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
elu: {
idle: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
active: {
- history: expect.any(CircularBuffer)
- }
- }
+ history: expect.any(CircularBuffer),
+ },
+ },
})
expect(threadWorkerNode.getTaskFunctionWorkerUsage('fn1')).toStrictEqual({
tasks: {
queued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
waitTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
elu: {
idle: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
active: {
- history: expect.any(CircularBuffer)
- }
- }
+ history: expect.any(CircularBuffer),
+ },
+ },
})
expect(threadWorkerNode.getTaskFunctionWorkerUsage('fn2')).toStrictEqual({
tasks: {
queued: 0,
sequentiallyStolen: 0,
stolen: 0,
- failed: 0
+ failed: 0,
},
runTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
waitTime: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
elu: {
idle: {
- history: expect.any(CircularBuffer)
+ history: expect.any(CircularBuffer),
},
active: {
- history: expect.any(CircularBuffer)
- }
- }
+ history: expect.any(CircularBuffer),
+ },
+ },
})
expect(threadWorkerNode.taskFunctionsUsage.size).toBe(2)
})
expect(threadWorkerNode.info.taskFunctionsProperties).toStrictEqual([
{ name: DEFAULT_TASK_NAME },
{ name: 'fn1' },
- { name: 'fn2' }
+ { name: 'fn2' },
])
expect(threadWorkerNode.taskFunctionsUsage.size).toBe(2)
expect(
expect(priorityQueue.maxSize).toBe(1)
expect(rtSize).toBe(priorityQueue.size)
expect(priorityQueue.head.nodeArray).toMatchObject([
- { data: 1, priority: 0 }
+ { data: 1, priority: 0 },
])
expect(priorityQueue.head.next).toBe(undefined)
expect(priorityQueue.tail).toStrictEqual(priorityQueue.head)
expect(rtSize).toBe(priorityQueue.size)
expect(priorityQueue.head.nodeArray).toMatchObject([
{ data: 1, priority: 0 },
- { data: 2, priority: 0 }
+ { data: 2, priority: 0 },
])
expect(priorityQueue.head.next).toBe(undefined)
expect(priorityQueue.tail).toStrictEqual(priorityQueue.head)
expect(priorityQueue.head.nodeArray).toMatchObject([
{ data: 1, priority: 0 },
{ data: 2, priority: 0 },
- { data: 3, priority: 0 }
+ { data: 3, priority: 0 },
])
expect(priorityQueue.head.next).toBe(undefined)
expect(priorityQueue.tail).toStrictEqual(priorityQueue.head)
{ data: 3, priority: -1 },
{ data: 1, priority: 0 },
{ data: 2, priority: 0 },
- { data: 3, priority: 0 }
+ { data: 3, priority: 0 },
])
expect(priorityQueue.head.next).toBe(undefined)
expect(priorityQueue.tail).toStrictEqual(priorityQueue.head)
{ data: 1, priority: 0 },
{ data: 2, priority: 0 },
{ data: 3, priority: 0 },
- { data: 1, priority: 1 }
+ { data: 1, priority: 1 },
])
expect(priorityQueue.head.next).toBe(undefined)
expect(priorityQueue.tail).toStrictEqual(priorityQueue.head)
expect(priorityQueue.maxSize).toBe(1)
expect(rtSize).toBe(priorityQueue.size)
expect(priorityQueue.head.nodeArray).toMatchObject([
- { data: 1, priority: 0 }
+ { data: 1, priority: 0 },
])
expect(priorityQueue.head.next).toBe(undefined)
expect(priorityQueue.tail).toStrictEqual(priorityQueue.head)
expect(rtSize).toBe(priorityQueue.size)
expect(priorityQueue.head.nodeArray).toMatchObject([
{ data: 1, priority: 0 },
- { data: 2, priority: 0 }
+ { data: 2, priority: 0 },
])
expect(priorityQueue.head.next).toBe(undefined)
expect(priorityQueue.tail).toStrictEqual(priorityQueue.head)
expect(priorityQueue.maxSize).toBe(3)
expect(rtSize).toBe(priorityQueue.size)
expect(priorityQueue.head.nodeArray).toMatchObject([
- { data: 3, priority: 0 }
+ { data: 3, priority: 0 },
])
expect(priorityQueue.head.next).toBe(undefined)
expect(priorityQueue.tail.nodeArray).toMatchObject([
{ data: 1, priority: 0 },
- { data: 2, priority: 0 }
+ { data: 2, priority: 0 },
])
expect(priorityQueue.tail.next).toStrictEqual(priorityQueue.head)
rtSize = priorityQueue.enqueue(3, -1)
expect(rtSize).toBe(priorityQueue.size)
expect(priorityQueue.head.nodeArray).toMatchObject([
{ data: 3, priority: -1 },
- { data: 3, priority: 0 }
+ { data: 3, priority: 0 },
])
expect(priorityQueue.head.next).toBe(undefined)
expect(priorityQueue.tail.nodeArray).toMatchObject([
{ data: 1, priority: 0 },
- { data: 2, priority: 0 }
+ { data: 2, priority: 0 },
])
expect(priorityQueue.tail.next).toStrictEqual(priorityQueue.head)
rtSize = priorityQueue.enqueue(1, 1)
expect(priorityQueue.maxSize).toBe(5)
expect(rtSize).toBe(priorityQueue.size)
expect(priorityQueue.head.nodeArray).toMatchObject([
- { data: 1, priority: 1 }
+ { data: 1, priority: 1 },
])
expect(priorityQueue.head.next).toBe(undefined)
expect(priorityQueue.tail.nodeArray).toMatchObject([
{ data: 1, priority: 0 },
- { data: 2, priority: 0 }
+ { data: 2, priority: 0 },
])
expect(priorityQueue.tail.next).not.toStrictEqual(priorityQueue.head)
expect(priorityQueue.tail.next.nodeArray).toMatchObject([
{ data: 3, priority: -1 },
- { data: 3, priority: 0 }
+ { data: 3, priority: 0 },
])
rtSize = priorityQueue.enqueue(3, -2)
expect(priorityQueue.buckets).toBe(3)
expect(rtSize).toBe(priorityQueue.size)
expect(priorityQueue.head.nodeArray).toMatchObject([
{ data: 3, priority: -2 },
- { data: 1, priority: 1 }
+ { data: 1, priority: 1 },
])
expect(priorityQueue.head.next).toBe(undefined)
expect(priorityQueue.tail.nodeArray).toMatchObject([
{ data: 1, priority: 0 },
- { data: 2, priority: 0 }
+ { data: 2, priority: 0 },
])
expect(priorityQueue.tail.next).not.toStrictEqual(priorityQueue.head)
expect(priorityQueue.tail.next.nodeArray).toMatchObject([
{ data: 3, priority: -1 },
- { data: 3, priority: 0 }
+ { data: 3, priority: 0 },
])
})
const TaskFunctions = {
jsonIntegerSerialization: 'jsonIntegerSerialization',
fibonacci: 'fibonacci',
- factorial: 'factorial'
+ factorial: 'factorial',
}
module.exports = { TaskFunctions }
const jsonIntegerSerialization = n => {
for (let i = 0; i < n; i++) {
const o = {
- a: i
+ a: i,
}
JSON.stringify(o)
}
}
/**
- * @param {number} n - The number of fibonacci numbers to generate.
- * @returns {number} - The nth fibonacci number.
+ * @param n - The number of fibonacci numbers to generate.
+ * @returns - The nth fibonacci number.
*/
const fibonacci = n => {
let current = 1
}
/**
- * @param {number} n - The number to calculate the factorial of.
- * @returns {number} - The factorial of n.
+ * @param n - The number to calculate the factorial of.
+ * @returns - The factorial of n.
*/
const factorial = n => {
if (n === 0 || n === 1) {
sleep,
sleepTaskFunction,
waitPoolEvents,
- waitWorkerEvents
+ waitWorkerEvents,
}
// once,
round,
secureRandom,
- sleep
+ sleep,
} from '../lib/utils.cjs'
describe('Utils test suite', () => {
expect(isAsyncFunction('')).toBe(false)
expect(isAsyncFunction([])).toBe(false)
expect(isAsyncFunction(new Date())).toBe(false)
- // eslint-disable-next-line prefer-regex-literals
+
expect(isAsyncFunction(/[a-z]/i)).toBe(false)
expect(isAsyncFunction(new Error())).toBe(false)
expect(isAsyncFunction(new Map())).toBe(false)
const { ClusterWorker, KillBehaviors } = require('../../../lib/index.cjs')
const { sleepTaskFunction } = require('../../test-utils.cjs')
+/**
+ *
+ * @param data
+ */
async function error (data) {
return sleepTaskFunction(
data,
module.exports = new ClusterWorker(error, {
killBehavior: KillBehaviors.HARD,
- maxInactiveTime: 500
+ maxInactiveTime: 500,
})
const { ClusterWorker, KillBehaviors } = require('../../../lib/index.cjs')
const { sleepTaskFunction } = require('../../test-utils.cjs')
+/**
+ *
+ * @param data
+ */
async function sleep (data) {
return sleepTaskFunction(data, 2000)
}
module.exports = new ClusterWorker(sleep, {
killBehavior: KillBehaviors.HARD,
- maxInactiveTime: 500
+ maxInactiveTime: 500,
})
'use strict'
const { ClusterWorker, KillBehaviors } = require('../../../lib/index.cjs')
+/**
+ *
+ * @param data
+ */
function echo (data) {
return data
}
module.exports = new ClusterWorker(echo, {
- killBehavior: KillBehaviors.HARD
+ killBehavior: KillBehaviors.HARD,
})
'use strict'
const { ClusterWorker, KillBehaviors } = require('../../../lib/index.cjs')
+/**
+ *
+ */
function test () {}
module.exports = new ClusterWorker(test, {
killBehavior: KillBehaviors.HARD,
- maxInactiveTime: 500
+ maxInactiveTime: 500,
})
'use strict'
const { ClusterWorker, KillBehaviors } = require('../../../lib/index.cjs')
+/**
+ *
+ */
function error () {
throw new Error('Error Message from ClusterWorker')
}
module.exports = new ClusterWorker(error, {
killBehavior: KillBehaviors.HARD,
- maxInactiveTime: 500
+ maxInactiveTime: 500,
})
const { ClusterWorker, KillBehaviors } = require('../../../lib/index.cjs')
const { sleepTaskFunction } = require('../../test-utils.cjs')
+/**
+ *
+ * @param data
+ */
async function sleep (data) {
return sleepTaskFunction(data, 50000)
}
module.exports = new ClusterWorker(sleep, {
killBehavior: KillBehaviors.HARD,
- maxInactiveTime: 500
+ maxInactiveTime: 500,
})
const { ClusterWorker } = require('../../../lib/index.cjs')
const { sleepTaskFunction } = require('../../test-utils.cjs')
+/**
+ *
+ * @param data
+ */
async function sleep (data) {
return sleepTaskFunction(data, 50000)
}
module.exports = new ClusterWorker(sleep, {
- maxInactiveTime: 500
+ maxInactiveTime: 500,
})
const {
jsonIntegerSerialization,
factorial,
- fibonacci
+ fibonacci,
} = require('../../test-utils.cjs')
module.exports = new ClusterWorker(
{
jsonIntegerSerialization: data => jsonIntegerSerialization(data.n),
factorial: data => factorial(data.n),
- fibonacci: data => fibonacci(data.n)
+ fibonacci: data => fibonacci(data.n),
},
{
killBehavior: KillBehaviors.HARD,
- maxInactiveTime: 500
+ maxInactiveTime: 500,
}
)
const {
factorial,
fibonacci,
- jsonIntegerSerialization
+ jsonIntegerSerialization,
} = require('../../test-utils.cjs')
module.exports = new ClusterWorker(
{
jsonIntegerSerialization: {
- taskFunction: data => jsonIntegerSerialization(data.n)
+ taskFunction: data => jsonIntegerSerialization(data.n),
},
factorial: { taskFunction: data => factorial(data.n) },
- fibonacci: { taskFunction: data => fibonacci(data.n), priority: -5 }
+ fibonacci: { taskFunction: data => fibonacci(data.n), priority: -5 },
},
{
killBehavior: KillBehaviors.HARD,
- maxInactiveTime: 500
+ maxInactiveTime: 500,
}
)
const { executeTaskFunction } = require('../../test-utils.cjs')
const { TaskFunctions } = require('../../test-types.cjs')
+/**
+ *
+ * @param data
+ */
function test (data) {
data = data || {}
data.function = data.function || TaskFunctions.jsonIntegerSerialization
module.exports = new ClusterWorker(test, {
killBehavior: KillBehaviors.HARD,
- maxInactiveTime: 500
+ maxInactiveTime: 500,
})
export default new ThreadWorker(error, {
killBehavior: KillBehaviors.HARD,
- maxInactiveTime: 500
+ maxInactiveTime: 500,
})
export default new ThreadWorker(sleep, {
killBehavior: KillBehaviors.HARD,
- maxInactiveTime: 500
+ maxInactiveTime: 500,
})
}
export default new ThreadWorker(echo, {
- killBehavior: KillBehaviors.HARD
+ killBehavior: KillBehaviors.HARD,
})
export default new ThreadWorker(test, {
killBehavior: KillBehaviors.HARD,
- maxInactiveTime: 500
+ maxInactiveTime: 500,
})
export default new ThreadWorker(error, {
killBehavior: KillBehaviors.HARD,
- maxInactiveTime: 500
+ maxInactiveTime: 500,
})
export default new ThreadWorker(sleep, {
killBehavior: KillBehaviors.HARD,
- maxInactiveTime: 500
+ maxInactiveTime: 500,
})
}
export default new ThreadWorker(sleep, {
- maxInactiveTime: 500
+ maxInactiveTime: 500,
})
import {
factorial,
fibonacci,
- jsonIntegerSerialization
+ jsonIntegerSerialization,
} from '../../test-utils.cjs'
export default new ThreadWorker(
{
jsonIntegerSerialization: data => jsonIntegerSerialization(data.n),
factorial: data => factorial(data.n),
- fibonacci: data => fibonacci(data.n)
+ fibonacci: data => fibonacci(data.n),
},
{
killBehavior: KillBehaviors.HARD,
- maxInactiveTime: 500
+ maxInactiveTime: 500,
}
)
import {
factorial,
fibonacci,
- jsonIntegerSerialization
+ jsonIntegerSerialization,
} from '../../test-utils.cjs'
export default new ThreadWorker(
{
jsonIntegerSerialization: {
- taskFunction: data => jsonIntegerSerialization(data.n)
+ taskFunction: data => jsonIntegerSerialization(data.n),
},
factorial: { taskFunction: data => factorial(data.n) },
- fibonacci: { taskFunction: data => fibonacci(data.n), priority: -5 }
+ fibonacci: { taskFunction: data => fibonacci(data.n), priority: -5 },
},
{
killBehavior: KillBehaviors.HARD,
- maxInactiveTime: 500
+ maxInactiveTime: 500,
}
)
export default new ThreadWorker(test, {
killBehavior: KillBehaviors.HARD,
- maxInactiveTime: 500
+ maxInactiveTime: 500,
})
ClusterWorker,
KillBehaviors,
ThreadWorker,
- WorkerChoiceStrategies
+ WorkerChoiceStrategies,
} from '../../lib/index.cjs'
import { DEFAULT_TASK_NAME, EMPTY_FUNCTION } from '../../lib/utils.cjs'
expect(worker.opts).toStrictEqual({
killBehavior: KillBehaviors.SOFT,
maxInactiveTime: 60000,
- killHandler: EMPTY_FUNCTION
+ killHandler: EMPTY_FUNCTION,
})
})
const worker = new ClusterWorker(() => {}, {
killBehavior: KillBehaviors.HARD,
maxInactiveTime: 6000,
- killHandler
+ killHandler,
})
expect(worker.opts).toStrictEqual({
killBehavior: KillBehaviors.HARD,
maxInactiveTime: 6000,
- killHandler
+ killHandler,
})
})
it('Verify that taskFunctions parameter with unique function is taken', () => {
const worker = new ThreadWorker(() => {})
expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.get('fn1')).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.size).toBe(2)
expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual(
expect(
() =>
new ThreadWorker({
- fn1: { taskFunction: fn1, strategy: 'invalidStrategy' }
+ fn1: { taskFunction: fn1, strategy: 'invalidStrategy' },
})
).toThrow(new Error("Invalid worker choice strategy 'invalidStrategy'"))
})
}
const worker = new ClusterWorker({ fn1, fn2 })
expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.get('fn1')).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.get('fn2')).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.size).toBe(3)
expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual(
taskFunction: () => {
return 1
},
- priority: 5
+ priority: 5,
}
const fn2Obj = {
taskFunction: () => {
return 2
},
priority: 6,
- strategy: WorkerChoiceStrategies.LESS_BUSY
+ strategy: WorkerChoiceStrategies.LESS_BUSY,
}
const worker = new ThreadWorker({
fn1: fn1Obj,
- fn2: fn2Obj
+ fn2: fn2Obj,
})
expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual(fn1Obj)
expect(worker.taskFunctions.get('fn1')).toStrictEqual(fn1Obj)
it('Verify that async kill handler is called when worker is killed', () => {
const killHandlerStub = stub().returns()
const worker = new ClusterWorker(() => {}, {
- killHandler: async () => await Promise.resolve(killHandlerStub())
+ killHandler: async () => await Promise.resolve(killHandlerStub()),
})
worker.isMain = false
worker.handleKillMessage()
const worker = new ClusterWorker({ fn1, fn2 })
expect(worker.hasTaskFunction(0)).toStrictEqual({
status: false,
- error: new TypeError('name parameter is not a string')
+ error: new TypeError('name parameter is not a string'),
})
expect(worker.hasTaskFunction('')).toStrictEqual({
status: false,
- error: new TypeError('name parameter is an empty string')
+ error: new TypeError('name parameter is an empty string'),
})
expect(worker.hasTaskFunction(DEFAULT_TASK_NAME)).toStrictEqual({
- status: true
+ status: true,
})
expect(worker.hasTaskFunction('fn1')).toStrictEqual({ status: true })
expect(worker.hasTaskFunction('fn2')).toStrictEqual({ status: true })
const worker = new ThreadWorker(fn1)
expect(worker.addTaskFunction(0, fn1)).toStrictEqual({
status: false,
- error: new TypeError('name parameter is not a string')
+ error: new TypeError('name parameter is not a string'),
})
expect(worker.addTaskFunction('', fn1)).toStrictEqual({
status: false,
- error: new TypeError('name parameter is an empty string')
+ error: new TypeError('name parameter is an empty string'),
})
expect(worker.addTaskFunction('fn2', 0)).toStrictEqual({
status: false,
error: new TypeError(
"taskFunction object 'taskFunction' property 'undefined' is not a function"
- )
+ ),
})
expect(worker.addTaskFunction('fn3', '')).toStrictEqual({
status: false,
error: new TypeError(
"taskFunction object 'taskFunction' property 'undefined' is not a function"
- )
+ ),
})
expect(worker.addTaskFunction('fn2', { taskFunction: 0 })).toStrictEqual({
status: false,
error: new TypeError(
"taskFunction object 'taskFunction' property '0' is not a function"
- )
+ ),
})
expect(worker.addTaskFunction('fn3', { taskFunction: '' })).toStrictEqual({
status: false,
error: new TypeError(
"taskFunction object 'taskFunction' property '' is not a function"
- )
+ ),
})
expect(
worker.addTaskFunction('fn2', { taskFunction: () => {}, priority: -21 })
).toStrictEqual({
status: false,
- error: new RangeError("Property 'priority' must be between -20 and 19")
+ error: new RangeError("Property 'priority' must be between -20 and 19"),
})
expect(
worker.addTaskFunction('fn3', { taskFunction: () => {}, priority: 20 })
).toStrictEqual({
status: false,
- error: new RangeError("Property 'priority' must be between -20 and 19")
+ error: new RangeError("Property 'priority' must be between -20 and 19"),
})
expect(
worker.addTaskFunction('fn2', {
taskFunction: () => {},
- strategy: 'invalidStrategy'
+ strategy: 'invalidStrategy',
})
).toStrictEqual({
status: false,
- error: new Error("Invalid worker choice strategy 'invalidStrategy'")
+ error: new Error("Invalid worker choice strategy 'invalidStrategy'"),
})
expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.get('fn1')).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.size).toBe(2)
expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual(
status: false,
error: new Error(
'Cannot add a task function with the default reserved name'
- )
+ ),
})
worker.addTaskFunction('fn2', fn2)
expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.get('fn1')).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.get('fn2')).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.size).toBe(3)
expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual(
)
worker.addTaskFunction('fn1', fn1Replacement)
expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.get('fn1')).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.get('fn2')).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.size).toBe(3)
expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual(
expect(worker.listTaskFunctionsProperties()).toStrictEqual([
{ name: DEFAULT_TASK_NAME },
{ name: 'fn1' },
- { name: 'fn2' }
+ { name: 'fn2' },
])
})
const worker = new ThreadWorker({ fn1, fn2 })
expect(worker.setDefaultTaskFunction(0, fn1)).toStrictEqual({
status: false,
- error: new TypeError('name parameter is not a string')
+ error: new TypeError('name parameter is not a string'),
})
expect(worker.setDefaultTaskFunction('', fn1)).toStrictEqual({
status: false,
- error: new TypeError('name parameter is an empty string')
+ error: new TypeError('name parameter is an empty string'),
})
expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.get('fn1')).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.get('fn2')).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.size).toBe(3)
expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual(
status: false,
error: new Error(
'Cannot set the default task function reserved name as the default task function'
- )
+ ),
})
expect(worker.setDefaultTaskFunction('fn3')).toStrictEqual({
status: false,
error: new Error(
'Cannot set the default task function to a non-existing task function'
- )
+ ),
})
worker.setDefaultTaskFunction('fn1')
expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual(
it('Verify that sync kill handler is called when worker is killed', () => {
const worker = new ClusterWorker(() => {}, {
- killHandler: stub().returns()
+ killHandler: stub().returns(),
})
worker.isMain = false
worker.getMainWorker = stub().returns({
id: 1,
- send: stub().returns()
+ send: stub().returns(),
})
worker.handleKillMessage()
expect(worker.getMainWorker.calledTwice).toBe(true)
const worker = new ClusterWorker({ fn1, fn2 })
worker.getMainWorker = stub().returns({
id: 1,
- send: stub().returns()
+ send: stub().returns(),
})
expect(worker.removeTaskFunction(0, fn1)).toStrictEqual({
status: false,
- error: new TypeError('name parameter is not a string')
+ error: new TypeError('name parameter is not a string'),
})
expect(worker.removeTaskFunction('', fn1)).toStrictEqual({
status: false,
- error: new TypeError('name parameter is an empty string')
+ error: new TypeError('name parameter is an empty string'),
})
expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.get('fn1')).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.get('fn2')).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.size).toBe(3)
expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual(
status: false,
error: new Error(
'Cannot remove the task function with the default reserved name'
- )
+ ),
})
expect(worker.removeTaskFunction('fn1')).toStrictEqual({
status: false,
error: new Error(
'Cannot remove the task function used as the default task function'
- )
+ ),
})
worker.removeTaskFunction('fn2')
expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.get('fn1')).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.get('fn2')).toBeUndefined()
expect(worker.taskFunctions.size).toBe(2)
it('Verify that sendToMainWorker() method invokes the getMainWorker() and send() methods', () => {
const worker = new ClusterWorker(() => {})
worker.getMainWorker = stub().returns({
- send: stub().returns()
+ send: stub().returns(),
})
worker.sendToMainWorker({ ok: 1 })
expect(worker.getMainWorker.calledTwice).toBe(true)
it('Verify that sync kill handler is called when worker is killed', () => {
const worker = new ThreadWorker(() => {}, {
- killHandler: stub().returns()
+ killHandler: stub().returns(),
})
worker.isMain = false
worker.port = {
postMessage: stub().returns(),
unref: stub().returns(),
- close: stub().returns()
+ close: stub().returns(),
}
worker.handleKillMessage()
expect(worker.port.postMessage.calledOnce).toBe(true)
}
const worker = new ThreadWorker({ fn1, fn2 })
worker.port = {
- postMessage: stub().returns()
+ postMessage: stub().returns(),
}
expect(worker.removeTaskFunction(0, fn1)).toStrictEqual({
status: false,
- error: new TypeError('name parameter is not a string')
+ error: new TypeError('name parameter is not a string'),
})
expect(worker.removeTaskFunction('', fn1)).toStrictEqual({
status: false,
- error: new TypeError('name parameter is an empty string')
+ error: new TypeError('name parameter is an empty string'),
})
expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.get('fn1')).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.get('fn2')).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.size).toBe(3)
expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual(
status: false,
error: new Error(
'Cannot remove the task function with the default reserved name'
- )
+ ),
})
expect(worker.removeTaskFunction('fn1')).toStrictEqual({
status: false,
error: new Error(
'Cannot remove the task function used as the default task function'
- )
+ ),
})
worker.removeTaskFunction('fn2')
expect(worker.taskFunctions.get(DEFAULT_TASK_NAME)).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.get('fn1')).toStrictEqual({
- taskFunction: expect.any(Function)
+ taskFunction: expect.any(Function),
})
expect(worker.taskFunctions.get('fn2')).toBeUndefined()
expect(worker.taskFunctions.size).toBe(2)
+++ /dev/null
-{
- "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json",
- "extends": ["typedoc/tsdoc.json"],
- "tagDefinitions": [
- {
- "tagName": "@author",
- "syntaxKind": "block"
- },
- {
- "tagName": "@since",
- "syntaxKind": "block"
- }
- ]
-}
try {
mkdirSync(join(dirname(fileURLToPath(import.meta.url)), 'tmp'), {
- recursive: true
+ recursive: true,
})
const markdownFiles = readdirSync(
join(dirname(fileURLToPath(import.meta.url)), 'docs')
}
rmSync(join(dirname(fileURLToPath(import.meta.url)), 'tmp'), {
recursive: true,
- force: true
+ force: true,
})
} catch (e) {
console.error(e)