From 17e4aacf426787143b8cd16d8f15b9a0fcd36b0b Mon Sep 17 00:00:00 2001 From: Theo Gravity Date: Sat, 6 Apr 2024 19:16:51 -0700 Subject: [PATCH] fix(datadog-transport-common): update p-retry to 6.2.0, exit-hook to 4.0.0 --- .husky/commit-msg | 4 + .husky/post-merge | 4 + .husky/pre-commit | 7 + biome.json | 2 + commitlint.config.js | 28 ++ package.json | 26 +- .../datadog-transport-common/package.json | 5 +- .../src/DataDogTransport.ts | 4 +- .../src/vendor/README.md | 7 + .../src/vendor/exit-hook/.editorconfig | 12 + .../src/vendor/exit-hook/.gitattributes | 1 + .../src/vendor/exit-hook/.github/funding.yml | 4 + .../src/vendor/exit-hook/.github/security.md | 3 + .../exit-hook/.github/workflows/main.yml | 21 ++ .../src/vendor/exit-hook/.gitignore | 2 + .../src/vendor/exit-hook/.npmrc | 1 + .../src/vendor/exit-hook/fixtures/async.js | 37 +++ .../src/vendor/exit-hook/fixtures/empty.js | 5 + .../src/vendor/exit-hook/fixtures/signal.js | 13 + .../src/vendor/exit-hook/fixtures/sync.js | 18 ++ .../src/vendor/exit-hook/index.d.ts | 100 ++++++ .../src/vendor/exit-hook/index.js | 132 ++++++++ .../src/vendor/exit-hook/index.test-d.ts | 14 + .../src/vendor/exit-hook/license | 9 + .../src/vendor/exit-hook/package.json | 53 +++ .../src/vendor/exit-hook/readme.md | 138 ++++++++ .../src/vendor/exit-hook/test.js | 118 +++++++ .../src/vendor/p-retry/.editorconfig | 12 + .../src/vendor/p-retry/.gitattributes | 1 + .../src/vendor/p-retry/.github/security.md | 3 + .../vendor/p-retry/.github/workflows/main.yml | 22 ++ .../src/vendor/p-retry/.gitignore | 2 + .../src/vendor/p-retry/.npmrc | 1 + .../src/vendor/p-retry/index.d.ts | 134 ++++++++ .../src/vendor/p-retry/index.js | 94 ++++++ .../src/vendor/p-retry/index.test-d.ts | 28 ++ .../src/vendor/p-retry/license | 9 + .../src/vendor/p-retry/package.json | 58 ++++ .../src/vendor/p-retry/readme.md | 184 +++++++++++ .../src/vendor/p-retry/test.js | 304 ++++++++++++++++++ .../test/DataDogTransport.test.ts | 8 +- .../datadog-transport-common/tsconfig.json | 3 +- pnpm-lock.yaml | 210 ++++++++++-- turbo.json | 4 +- 44 files changed, 1793 insertions(+), 52 deletions(-) create mode 100755 .husky/commit-msg create mode 100755 .husky/post-merge create mode 100755 .husky/pre-commit create mode 100644 commitlint.config.js create mode 100644 packages/datadog-transport-common/src/vendor/README.md create mode 100644 packages/datadog-transport-common/src/vendor/exit-hook/.editorconfig create mode 100644 packages/datadog-transport-common/src/vendor/exit-hook/.gitattributes create mode 100644 packages/datadog-transport-common/src/vendor/exit-hook/.github/funding.yml create mode 100644 packages/datadog-transport-common/src/vendor/exit-hook/.github/security.md create mode 100644 packages/datadog-transport-common/src/vendor/exit-hook/.github/workflows/main.yml create mode 100644 packages/datadog-transport-common/src/vendor/exit-hook/.gitignore create mode 100644 packages/datadog-transport-common/src/vendor/exit-hook/.npmrc create mode 100644 packages/datadog-transport-common/src/vendor/exit-hook/fixtures/async.js create mode 100644 packages/datadog-transport-common/src/vendor/exit-hook/fixtures/empty.js create mode 100644 packages/datadog-transport-common/src/vendor/exit-hook/fixtures/signal.js create mode 100644 packages/datadog-transport-common/src/vendor/exit-hook/fixtures/sync.js create mode 100644 packages/datadog-transport-common/src/vendor/exit-hook/index.d.ts create mode 100644 packages/datadog-transport-common/src/vendor/exit-hook/index.js create mode 100644 packages/datadog-transport-common/src/vendor/exit-hook/index.test-d.ts create mode 100644 packages/datadog-transport-common/src/vendor/exit-hook/license create mode 100644 packages/datadog-transport-common/src/vendor/exit-hook/package.json create mode 100644 packages/datadog-transport-common/src/vendor/exit-hook/readme.md create mode 100644 packages/datadog-transport-common/src/vendor/exit-hook/test.js create mode 100644 packages/datadog-transport-common/src/vendor/p-retry/.editorconfig create mode 100644 packages/datadog-transport-common/src/vendor/p-retry/.gitattributes create mode 100644 packages/datadog-transport-common/src/vendor/p-retry/.github/security.md create mode 100644 packages/datadog-transport-common/src/vendor/p-retry/.github/workflows/main.yml create mode 100644 packages/datadog-transport-common/src/vendor/p-retry/.gitignore create mode 100644 packages/datadog-transport-common/src/vendor/p-retry/.npmrc create mode 100644 packages/datadog-transport-common/src/vendor/p-retry/index.d.ts create mode 100644 packages/datadog-transport-common/src/vendor/p-retry/index.js create mode 100644 packages/datadog-transport-common/src/vendor/p-retry/index.test-d.ts create mode 100644 packages/datadog-transport-common/src/vendor/p-retry/license create mode 100644 packages/datadog-transport-common/src/vendor/p-retry/package.json create mode 100644 packages/datadog-transport-common/src/vendor/p-retry/readme.md create mode 100644 packages/datadog-transport-common/src/vendor/p-retry/test.js diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100755 index 0000000..80416c7 --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npx --no-install commitlint --edit "$1" diff --git a/.husky/post-merge b/.husky/post-merge new file mode 100755 index 0000000..c752065 --- /dev/null +++ b/.husky/post-merge @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +pnpm diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..b3d3451 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,7 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +pnpm typecheck +pnpm lint:packages +pnpm test +pnpm lint-staged diff --git a/biome.json b/biome.json index aac4912..9b9440b 100644 --- a/biome.json +++ b/biome.json @@ -8,6 +8,7 @@ "indentStyle": "space", "lineWidth": 120, "ignore": [ + "vendor/*", "node_modules/*", "*.config.*", "*.json", @@ -17,6 +18,7 @@ }, "linter": { "enabled": true, + "ignore": ["vendor/*"], "rules": { "performance": { "noDelete": "off" diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 0000000..dea8988 --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1,28 @@ +module.exports = { + extends: ['@commitlint/config-conventional'], + rules: { + 'scope-enum': [2, 'always', + [ + 'all', + 'datadog-transport-common', + 'electron-log-transport-datadog', + 'pino-datadog-transport' + ]], + 'type-enum': [ + 2, + 'always', + [ + 'feat', + 'fix', + 'docs', + 'chore', + 'style', + 'refactor', + 'ci', + 'test', + 'revert', + 'perf' + ], + ], + }, +}; diff --git a/package.json b/package.json index 592f267..5911399 100644 --- a/package.json +++ b/package.json @@ -3,14 +3,14 @@ "private": true, "scripts": { "add-changeset": "changeset add", - "build": "turbo build", + "build": "turbo run build", "changeset": "changeset", "clean": "git clean -xdf node_modules", "clean:workspaces": "turbo clean", - "format": "turbo format --continue --", - "format:fix": "turbo format --continue -- --write", - "lint": "turbo lint --continue --", - "lint:fix": "turbo lint --continue -- --apply", + "format": "turbo run format --continue --", + "format:fix": "turbo run format --continue -- --write", + "lint": "turbo run lint --continue --", + "lint:fix": "turbo run lint --continue -- --apply", "lint:packages": "pnpm run lint:packages:semver && pnpm run lint:packages:mismatches", "lint:packages:semver": "syncpack lint-semver-ranges", "lint:packages:mismatches": "syncpack list-mismatches", @@ -18,9 +18,10 @@ "publish-packages": "turbo run build && changeset version && changeset publish", "release": "changeset publish", "syncpack": "syncpack", - "test": "turbo test", - "typecheck": "turbo typecheck", - "version-packages": "changeset version" + "test": "turbo run test --", + "typecheck": "turbo run typecheck", + "version-packages": "changeset version", + "prepare": "husky install" }, "devDependencies": { "@biomejs/biome": "^1.6.4", @@ -29,7 +30,8 @@ "@commitlint/cli": "^19.2.1", "@commitlint/config-conventional": "^19.1.0", "@types/node": "^20.12.5", - "husky": "^9.0.11", + "husky": "^8.0.0", + "lint-staged": "^15.2.2", "syncpack": "^12.3.0", "tsconfig": "workspace:*", "turbo": "^1.13.2", @@ -39,9 +41,7 @@ "engines": { "node": ">=18" }, - "husky": { - "hooks": { - "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" - } + "lint-staged": { + "**/*.{js,jsx,ts,tsx,html,css,json}": ["pnpm lint:fix"] } } diff --git a/packages/datadog-transport-common/package.json b/packages/datadog-transport-common/package.json index 4ceee17..1311407 100644 --- a/packages/datadog-transport-common/package.json +++ b/packages/datadog-transport-common/package.json @@ -43,10 +43,11 @@ }, "dependencies": { "@datadog/datadog-api-client": "^1.23.0", - "exit-hook": "^2.2.1", - "p-retry": "^4.6.2" + "is-network-error": "^1.1.0", + "retry": "^0.13.1" }, "devDependencies": { + "@types/retry": "^0.12.5", "tsconfig": "workspace:*", "tsup": "^8.0.2", "vitest": "^1.4.0" diff --git a/packages/datadog-transport-common/src/DataDogTransport.ts b/packages/datadog-transport-common/src/DataDogTransport.ts index 676ca54..cc453ca 100644 --- a/packages/datadog-transport-common/src/DataDogTransport.ts +++ b/packages/datadog-transport-common/src/DataDogTransport.ts @@ -1,8 +1,8 @@ import type { HTTPLogItem } from "@datadog/datadog-api-client/dist/packages/datadog-api-client-v2/models/HTTPLogItem"; import type { LogsApiSubmitLogRequest } from "@datadog/datadog-api-client/dist/packages/datadog-api-client-v2/apis/LogsApi"; import { client, v2 } from "@datadog/datadog-api-client"; -import pRetry from "p-retry"; -import exitHook from "exit-hook"; +import pRetry from "./vendor/p-retry"; +import exitHook from "./vendor/exit-hook"; import { LogStorage } from "./LogStorage"; import type { DDTransportOptions, SendLogOpts } from "./types"; diff --git a/packages/datadog-transport-common/src/vendor/README.md b/packages/datadog-transport-common/src/vendor/README.md new file mode 100644 index 0000000..156d812 --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/README.md @@ -0,0 +1,7 @@ +We're using a copy of + +- [`exit-hook`](https://github.com/sindresorhus/exit-hook) +- [`p-retry'](https://github.com/sindresorhus/p-retry) + +instead of using the package directly because newer versions are ESM-only +and this project supports both ESM and CJS. diff --git a/packages/datadog-transport-common/src/vendor/exit-hook/.editorconfig b/packages/datadog-transport-common/src/vendor/exit-hook/.editorconfig new file mode 100644 index 0000000..1c6314a --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/exit-hook/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = tab +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.yml] +indent_style = space +indent_size = 2 diff --git a/packages/datadog-transport-common/src/vendor/exit-hook/.gitattributes b/packages/datadog-transport-common/src/vendor/exit-hook/.gitattributes new file mode 100644 index 0000000..6313b56 --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/exit-hook/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/packages/datadog-transport-common/src/vendor/exit-hook/.github/funding.yml b/packages/datadog-transport-common/src/vendor/exit-hook/.github/funding.yml new file mode 100644 index 0000000..797757b --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/exit-hook/.github/funding.yml @@ -0,0 +1,4 @@ +github: sindresorhus +open_collective: sindresorhus +tidelift: npm/exit-hook +custom: https://sindresorhus.com/donate diff --git a/packages/datadog-transport-common/src/vendor/exit-hook/.github/security.md b/packages/datadog-transport-common/src/vendor/exit-hook/.github/security.md new file mode 100644 index 0000000..5358dc5 --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/exit-hook/.github/security.md @@ -0,0 +1,3 @@ +# Security Policy + +To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. diff --git a/packages/datadog-transport-common/src/vendor/exit-hook/.github/workflows/main.yml b/packages/datadog-transport-common/src/vendor/exit-hook/.github/workflows/main.yml new file mode 100644 index 0000000..c4cdca2 --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/exit-hook/.github/workflows/main.yml @@ -0,0 +1,21 @@ +name: CI +on: + - push + - pull_request +jobs: + test: + name: Node.js ${{ matrix.node-version }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node-version: + - 20 + - 18 + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + - run: npm install + - run: npm test diff --git a/packages/datadog-transport-common/src/vendor/exit-hook/.gitignore b/packages/datadog-transport-common/src/vendor/exit-hook/.gitignore new file mode 100644 index 0000000..239ecff --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/exit-hook/.gitignore @@ -0,0 +1,2 @@ +node_modules +yarn.lock diff --git a/packages/datadog-transport-common/src/vendor/exit-hook/.npmrc b/packages/datadog-transport-common/src/vendor/exit-hook/.npmrc new file mode 100644 index 0000000..43c97e7 --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/exit-hook/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/packages/datadog-transport-common/src/vendor/exit-hook/fixtures/async.js b/packages/datadog-transport-common/src/vendor/exit-hook/fixtures/async.js new file mode 100644 index 0000000..b564732 --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/exit-hook/fixtures/async.js @@ -0,0 +1,37 @@ +import process from 'node:process'; +import exitHook, {asyncExitHook, gracefulExit} from '../index.js'; + +exitHook(() => { + console.log('foo'); +}); + +exitHook(() => { + console.log('bar'); +}); + +const unsubscribe = exitHook(() => { + console.log('baz'); +}); + +unsubscribe(); + +asyncExitHook( + async () => { + await new Promise(resolve => { + setTimeout(() => { + resolve(); + }, 100); + }); + + console.log('quux'); + }, + { + wait: 200, + }, +); + +if (process.env.EXIT_HOOK_SYNC === '1') { + process.exit(0); // eslint-disable-line unicorn/no-process-exit +} + +gracefulExit(); diff --git a/packages/datadog-transport-common/src/vendor/exit-hook/fixtures/empty.js b/packages/datadog-transport-common/src/vendor/exit-hook/fixtures/empty.js new file mode 100644 index 0000000..4cee342 --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/exit-hook/fixtures/empty.js @@ -0,0 +1,5 @@ +import exitHook from '../index.js'; + +exitHook(() => { + // https://github.com/sindresorhus/exit-hook/issues/23 +}); diff --git a/packages/datadog-transport-common/src/vendor/exit-hook/fixtures/signal.js b/packages/datadog-transport-common/src/vendor/exit-hook/fixtures/signal.js new file mode 100644 index 0000000..a2d9bdb --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/exit-hook/fixtures/signal.js @@ -0,0 +1,13 @@ +import exitHook, {asyncExitHook} from '../index.js'; + +exitHook(signal => { + console.log(signal); +}); + +asyncExitHook(async signal => { + console.log(signal); +}, { + wait: 200, +}); + +setInterval(() => {}, 1e9); diff --git a/packages/datadog-transport-common/src/vendor/exit-hook/fixtures/sync.js b/packages/datadog-transport-common/src/vendor/exit-hook/fixtures/sync.js new file mode 100644 index 0000000..9a7872d --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/exit-hook/fixtures/sync.js @@ -0,0 +1,18 @@ +import process from 'node:process'; +import exitHook from '../index.js'; + +exitHook(() => { + console.log('foo'); +}); + +exitHook(() => { + console.log('bar'); +}); + +const unsubscribe = exitHook(() => { + console.log('baz'); +}); + +unsubscribe(); + +process.exit(0); // eslint-disable-line unicorn/no-process-exit diff --git a/packages/datadog-transport-common/src/vendor/exit-hook/index.d.ts b/packages/datadog-transport-common/src/vendor/exit-hook/index.d.ts new file mode 100644 index 0000000..d5371ae --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/exit-hook/index.d.ts @@ -0,0 +1,100 @@ +/** +@callback onExit +@param {number} signal - The exit code. +*/ + +/** +Run some code when the process exits. + +The `process.on('exit')` event doesn't catch all the ways a process can exit. + +This is useful for cleaning synchronously before exiting. + +@param {onExit} onExit - The callback function to execute when the process exits. +@returns A function that removes the hook when called. + +@example +``` +import exitHook from 'exit-hook'; + +exitHook(signal => { + console.log(`Exiting with signal: ${signal}`); +}); + +// You can add multiple hooks, even across files +exitHook(() => { + console.log('Exiting 2'); +}); + +throw new Error('πŸ¦„'); + +//=> 'Exiting' +//=> 'Exiting 2' + +// Removing an exit hook: +const unsubscribe = exitHook(() => {}); + +unsubscribe(); +``` +*/ +export default function exitHook(onExit: (signal: number) => void): () => void; + +/** +Run code asynchronously when the process exits. + +@see https://github.com/sindresorhus/exit-hook/blob/main/readme.md#asynchronous-exit-notes +@param {onExit} onExit - The callback function to execute when the process exits via `gracefulExit`, and will be wrapped in `Promise.resolve`. +@returns A function that removes the hook when called. + +@example +``` +import {asyncExitHook} from 'exit-hook'; + +asyncExitHook(() => { + console.log('Exiting'); +}, { + wait: 500 +}); + +throw new Error('πŸ¦„'); + +//=> 'Exiting' + +// Removing an exit hook: +const unsubscribe = asyncExitHook(() => {}, {wait: 500}); + +unsubscribe(); +``` +*/ +export function asyncExitHook(onExit: (signal: number) => (void | Promise), options: Options): () => void; + +/** +Exit the process and make a best-effort to complete all asynchronous hooks. + +If you are using `asyncExitHook`, consider using `gracefulExit()` instead of `process.exit()` to ensure all asynchronous tasks are given an opportunity to run. + +@param signal - The exit code to use. Same as the argument to `process.exit()`. +@see https://github.com/sindresorhus/exit-hook/blob/main/readme.md#asynchronous-exit-notes + +@example +``` +import {asyncExitHook, gracefulExit} from 'exit-hook'; + +asyncExitHook(() => { + console.log('Exiting'); +}, { + wait: 500 +}); + +// Instead of `process.exit()` +gracefulExit(); +``` +*/ +export function gracefulExit(signal?: number): void; + +export type Options = { + /** + The amount of time in milliseconds that the `onExit` function is expected to take. When multiple async handlers are registered, the longest `wait` time will be used. + */ + readonly wait: number; +}; diff --git a/packages/datadog-transport-common/src/vendor/exit-hook/index.js b/packages/datadog-transport-common/src/vendor/exit-hook/index.js new file mode 100644 index 0000000..9d24483 --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/exit-hook/index.js @@ -0,0 +1,132 @@ +import process from 'node:process'; + +const asyncCallbacks = new Set(); +const callbacks = new Set(); + +let isCalled = false; +let isRegistered = false; + +async function exit(shouldManuallyExit, isSynchronous, signal) { + if (isCalled) { + return; + } + + isCalled = true; + + if (asyncCallbacks.size > 0 && isSynchronous) { + console.error([ + 'SYNCHRONOUS TERMINATION NOTICE:', + 'When explicitly exiting the process via process.exit or via a parent process,', + 'asynchronous tasks in your exitHooks will not run. Either remove these tasks,', + 'use gracefulExit() instead of process.exit(), or ensure your parent process', + 'sends a SIGINT to the process running this code.', + ].join(' ')); + } + + const exitCode = 128 + signal; + + const done = (force = false) => { + if (force === true || shouldManuallyExit === true) { + process.exit(exitCode); // eslint-disable-line unicorn/no-process-exit + } + }; + + for (const callback of callbacks) { + callback(exitCode); + } + + if (isSynchronous) { + done(); + return; + } + + const promises = []; + let forceAfter = 0; + for (const [callback, wait] of asyncCallbacks) { + forceAfter = Math.max(forceAfter, wait); + promises.push(Promise.resolve(callback(exitCode))); + } + + // Force exit if we exceeded our wait value + const asyncTimer = setTimeout(() => { + done(true); + }, forceAfter); + + await Promise.all(promises); + clearTimeout(asyncTimer); + done(); +} + +function addHook(options) { + const {onExit, wait, isSynchronous} = options; + const asyncCallbackConfig = [onExit, wait]; + + if (isSynchronous) { + callbacks.add(onExit); + } else { + asyncCallbacks.add(asyncCallbackConfig); + } + + if (!isRegistered) { + isRegistered = true; + + // Exit cases that support asynchronous handling + process.once('beforeExit', exit.bind(undefined, true, false, -128)); + process.once('SIGINT', exit.bind(undefined, true, false, 2)); + process.once('SIGTERM', exit.bind(undefined, true, false, 15)); + + // Explicit exit events. Calling will force an immediate exit and run all + // synchronous hooks. Explicit exits must not extend the node process + // artificially. Will log errors if asynchronous calls exist. + process.once('exit', exit.bind(undefined, false, true, 0)); + + // PM2 Cluster shutdown message. Caught to support async handlers with pm2, + // needed because explicitly calling process.exit() doesn't trigger the + // beforeExit event, and the exit event cannot support async handlers, + // since the event loop is never called after it. + process.on('message', message => { + if (message === 'shutdown') { + exit(true, true, -128); + } + }); + } + + return () => { + if (isSynchronous) { + callbacks.delete(onExit); + } else { + asyncCallbacks.delete(asyncCallbackConfig); + } + }; +} + +export default function exitHook(onExit) { + if (typeof onExit !== 'function') { + throw new TypeError('onExit must be a function'); + } + + return addHook({ + onExit, + isSynchronous: true, + }); +} + +export function asyncExitHook(onExit, options = {}) { + if (typeof onExit !== 'function') { + throw new TypeError('onExit must be a function'); + } + + if (!(typeof options.wait === 'number' && options.wait > 0)) { + throw new TypeError('wait must be set to a positive numeric value'); + } + + return addHook({ + onExit, + wait: options.wait, + isSynchronous: false, + }); +} + +export function gracefulExit(signal = 0) { + exit(true, false, -128 + signal); +} diff --git a/packages/datadog-transport-common/src/vendor/exit-hook/index.test-d.ts b/packages/datadog-transport-common/src/vendor/exit-hook/index.test-d.ts new file mode 100644 index 0000000..d237e66 --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/exit-hook/index.test-d.ts @@ -0,0 +1,14 @@ +import {expectType} from 'tsd'; +import exitHook, {asyncExitHook} from './index.js'; + +const unsubscribe = exitHook(() => {}); // eslint-disable-line @typescript-eslint/no-empty-function + +const asyncUnsubscribe = asyncExitHook(async () => {}, // eslint-disable-line @typescript-eslint/no-empty-function + {wait: 300}, +); + +expectType<() => void>(unsubscribe); +unsubscribe(); + +expectType<() => void>(asyncUnsubscribe); +asyncUnsubscribe(); diff --git a/packages/datadog-transport-common/src/vendor/exit-hook/license b/packages/datadog-transport-common/src/vendor/exit-hook/license new file mode 100644 index 0000000..fa7ceba --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/exit-hook/license @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/datadog-transport-common/src/vendor/exit-hook/package.json b/packages/datadog-transport-common/src/vendor/exit-hook/package.json new file mode 100644 index 0000000..5ce9abe --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/exit-hook/package.json @@ -0,0 +1,53 @@ +{ + "name": "exit-hook", + "version": "4.0.0", + "private": true, + "description": "Run some code when the process exits", + "license": "MIT", + "repository": "sindresorhus/exit-hook", + "funding": "https://github.com/sponsors/sindresorhus", + "author": { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "https://sindresorhus.com" + }, + "type": "module", + "exports": { + "types": "./index.d.ts", + "default": "./index.js" + }, + "engines": { + "node": ">=18" + }, + "scripts": { + "test": "xo && ava && tsd" + }, + "files": [ + "index.js", + "index.d.ts" + ], + "keywords": [ + "exit", + "quit", + "process", + "hook", + "graceful", + "handler", + "shutdown", + "sigterm", + "sigint", + "terminate", + "kill", + "stop", + "event", + "signal", + "async", + "asynchronous" + ], + "devDependencies": { + "ava": "^5.3.1", + "execa": "^8.0.1", + "tsd": "^0.28.1", + "xo": "^0.56.0" + } +} diff --git a/packages/datadog-transport-common/src/vendor/exit-hook/readme.md b/packages/datadog-transport-common/src/vendor/exit-hook/readme.md new file mode 100644 index 0000000..9e1293d --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/exit-hook/readme.md @@ -0,0 +1,138 @@ +# exit-hook + +> Run some code when the process exits + +The `process.on('exit')` event doesn't catch all the ways a process can exit. + +This package is useful for cleaning up before exiting. + +## Install + +```sh +npm install exit-hook +``` + +## Usage + +```js +import exitHook from 'exit-hook'; + +exitHook(signal => { + console.log(`Exiting with signal: ${signal}`); +}); + +// You can add multiple hooks, even across files +exitHook(() => { + console.log('Exiting 2'); +}); + +throw new Error('πŸ¦„'); + +//=> 'Exiting' +//=> 'Exiting 2' +``` + +Removing an exit hook: + +```js +import exitHook from 'exit-hook'; + +const unsubscribe = exitHook(() => {}); + +unsubscribe(); +``` + +## API + +### exitHook(onExit) + +Register a function to run during `process.exit`. + +Returns a function that removes the hook when called. + +#### onExit + +Type: `(signal: number) => void` + +The callback function to execute when the process exits. + +### asyncExitHook(onExit, options) + +Register a function to run during `gracefulExit`. + +Returns a function that removes the hook when called. + +Please see [Async Notes](#asynchronous-exit-notes) for considerations when using the asynchronous API. + +#### onExit + +Type: `(signal: number) => (void | Promise)` + +The callback function to execute when the process exits via `gracefulExit`, and will be wrapped in `Promise.resolve`. + +#### options + +Type: `object` + +##### wait + +Type: `number` + +The amount of time in milliseconds that the `onExit` function is expected to take. When multiple async handlers are registered, the longest `wait` time will be used. + +```js +import {asyncExitHook} from 'exit-hook'; + +asyncExitHook(async () => { + console.log('Exiting'); +}, { + wait: 300 +}); + +throw new Error('πŸ¦„'); + +//=> 'Exiting' +``` + +Removing an asynchronous exit hook: + +```js +import {asyncExitHook} from 'exit-hook'; + +const unsubscribe = asyncExitHook(async () => { + console.log('Exiting'); +}, { + wait: 300 +}); + +unsubscribe(); +``` + +### gracefulExit(signal?: number): void + +Exit the process and make a best-effort to complete all asynchronous hooks. + +If you are using `asyncExitHook`, consider using `gracefulExit()` instead of `process.exit()` to ensure all asynchronous tasks are given an opportunity to run. + +```js +import {gracefulExit} from 'exit-hook'; + +gracefulExit(); +``` + +#### signal + +Type: `number`\ +Default: `0` + +The exit code to use. Same as the argument to `process.exit()`. + +## Asynchronous Exit Notes + +**tl;dr** If you have 100% control over how your process terminates, then you can swap `exitHook` and `process.exit` for `asyncExitHook` and `gracefulExit` respectively. Otherwise, keep reading to understand important tradeoffs if you're using `asyncExitHook`. + +Node.js does not offer an asynchronous shutdown API by default [#1](https://github.com/nodejs/node/discussions/29480#discussioncomment-99213) [#2](https://github.com/nodejs/node/discussions/29480#discussioncomment-99217), so `asyncExitHook` and `gracefulExit` will make a "best effort" attempt to shut down the process and run your asynchronous tasks. + +If you have asynchronous hooks registered and your Node.js process is terminated in a synchronous manner, a `SYNCHRONOUS TERMINATION NOTICE` error will be logged to the console. To avoid this, ensure you're only exiting via `gracefulExit` or that an upstream process manager is sending a `SIGINT` or `SIGTERM` signal to Node.js. + +Asynchronous hooks should make a "best effort" to perform their tasks within the `wait` time, but also be written to assume they may not complete their tasks before termination. diff --git a/packages/datadog-transport-common/src/vendor/exit-hook/test.js b/packages/datadog-transport-common/src/vendor/exit-hook/test.js new file mode 100644 index 0000000..037030b --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/exit-hook/test.js @@ -0,0 +1,118 @@ +import process from 'node:process'; +import test from 'ava'; +import {execa} from 'execa'; +import exitHook, {asyncExitHook} from './index.js'; + +test('main', async t => { + const {stdout, stderr, exitCode} = await execa(process.execPath, ['./fixtures/sync.js']); + t.is(stdout, 'foo\nbar'); + t.is(stderr, ''); + t.is(exitCode, 0); +}); + +test('main-empty', async t => { + const {stderr, exitCode} = await execa(process.execPath, ['./fixtures/empty.js']); + t.is(stderr, ''); + t.is(exitCode, 0); +}); + +test('main-async', async t => { + const {stdout, stderr, exitCode} = await execa(process.execPath, ['./fixtures/async.js']); + t.is(stdout, 'foo\nbar\nquux'); + t.is(stderr, ''); + t.is(exitCode, 0); +}); + +test('main-async-notice', async t => { + const {stdout, stderr, exitCode} = await execa(process.execPath, ['./fixtures/async.js'], { + env: { + EXIT_HOOK_SYNC: '1', + }, + }); + t.is(stdout, 'foo\nbar'); + t.regex(stderr, /SYNCHRONOUS TERMINATION NOTICE/); + t.is(exitCode, 0); +}); + +test('listener count', t => { + t.is(process.listenerCount('exit'), 0); + + const unsubscribe1 = exitHook(() => {}); + const unsubscribe2 = exitHook(() => {}); + t.is(process.listenerCount('exit'), 1); + + // Remove all listeners + unsubscribe1(); + unsubscribe2(); + t.is(process.listenerCount('exit'), 1); + + // Re-add listener + const unsubscribe3 = exitHook(() => {}); + t.is(process.listenerCount('exit'), 1); + + // Remove again + unsubscribe3(); + t.is(process.listenerCount('exit'), 1); + + // Add async style listener + const unsubscribe4 = asyncExitHook( + async () => {}, + { + wait: 100, + }, + ); + t.is(process.listenerCount('exit'), 1); + + // Remove again + unsubscribe4(); + t.is(process.listenerCount('exit'), 1); +}); + +test('type enforcing', t => { + // Non-function passed to `exitHook`. + t.throws(() => { + exitHook(null); + }, {instanceOf: TypeError}); + + // Non-function passed to `asyncExitHook`. + t.throws(() => { + asyncExitHook(null, { + wait: 100, + }); + }, { + instanceOf: TypeError, + }); + + // Non-numeric passed to `wait` option. + t.throws(() => { + asyncExitHook(async () => true, {wait: 'abc'}); + }); + + // Empty value passed to `wait` option. + t.throws(() => { + asyncExitHook(async () => true, {}); + }); +}); + +const signalTests = [ + ['SIGINT', 130], + ['SIGTERM', 143], +]; + +for (const [signal, exitCode] of signalTests) { + test(signal, async t => { + const subprocess = execa(process.execPath, ['./fixtures/signal.js']); + + setTimeout(() => { + subprocess.kill(signal); + }, 1000); + + try { + await subprocess; + } catch (error) { + t.is(error.exitCode, exitCode); + t.is(error.stderr, ''); + t.is(error.stdout, `${exitCode}\n${exitCode}`); + } + }); +} diff --git a/packages/datadog-transport-common/src/vendor/p-retry/.editorconfig b/packages/datadog-transport-common/src/vendor/p-retry/.editorconfig new file mode 100644 index 0000000..1c6314a --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/p-retry/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = tab +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.yml] +indent_style = space +indent_size = 2 diff --git a/packages/datadog-transport-common/src/vendor/p-retry/.gitattributes b/packages/datadog-transport-common/src/vendor/p-retry/.gitattributes new file mode 100644 index 0000000..6313b56 --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/p-retry/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/packages/datadog-transport-common/src/vendor/p-retry/.github/security.md b/packages/datadog-transport-common/src/vendor/p-retry/.github/security.md new file mode 100644 index 0000000..5358dc5 --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/p-retry/.github/security.md @@ -0,0 +1,3 @@ +# Security Policy + +To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. diff --git a/packages/datadog-transport-common/src/vendor/p-retry/.github/workflows/main.yml b/packages/datadog-transport-common/src/vendor/p-retry/.github/workflows/main.yml new file mode 100644 index 0000000..a023591 --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/p-retry/.github/workflows/main.yml @@ -0,0 +1,22 @@ +name: CI +on: + - push + - pull_request +jobs: + test: + name: Node.js ${{ matrix.node-version }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node-version: + - 20 + - 18 + - 16 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + - run: npm install + - run: npm test diff --git a/packages/datadog-transport-common/src/vendor/p-retry/.gitignore b/packages/datadog-transport-common/src/vendor/p-retry/.gitignore new file mode 100644 index 0000000..239ecff --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/p-retry/.gitignore @@ -0,0 +1,2 @@ +node_modules +yarn.lock diff --git a/packages/datadog-transport-common/src/vendor/p-retry/.npmrc b/packages/datadog-transport-common/src/vendor/p-retry/.npmrc new file mode 100644 index 0000000..43c97e7 --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/p-retry/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/packages/datadog-transport-common/src/vendor/p-retry/index.d.ts b/packages/datadog-transport-common/src/vendor/p-retry/index.d.ts new file mode 100644 index 0000000..95ebb17 --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/p-retry/index.d.ts @@ -0,0 +1,134 @@ +import {type OperationOptions} from 'retry'; + +export class AbortError extends Error { + readonly name: 'AbortError'; + readonly originalError: Error; + + /** + Abort retrying and reject the promise. + + @param message - An error message or a custom error. + */ + constructor(message: string | Error); +} + +export type FailedAttemptError = { + readonly attemptNumber: number; + readonly retriesLeft: number; +} & Error; + +export type Options = { + /** + Callback invoked on each retry. Receives the error thrown by `input` as the first argument with properties `attemptNumber` and `retriesLeft` which indicate the current attempt number and the number of attempts left, respectively. + + The `onFailedAttempt` function can return a promise. For example, to add a [delay](https://github.com/sindresorhus/delay): + + ``` + import pRetry from 'p-retry'; + import delay from 'delay'; + + const run = async () => { ... }; + + const result = await pRetry(run, { + onFailedAttempt: async error => { + console.log('Waiting for 1 second before retrying'); + await delay(1000); + } + }); + ``` + + If the `onFailedAttempt` function throws, all retries will be aborted and the original promise will reject with the thrown error. + */ + readonly onFailedAttempt?: (error: FailedAttemptError) => void | Promise; + + /** + Decide if a retry should occur based on the error. Returning true triggers a retry, false aborts with the error. + + It is not called for `TypeError` (except network errors) and `AbortError`. + + @param error - The error thrown by the input function. + + @example + ``` + import pRetry from 'p-retry'; + + const run = async () => { … }; + + const result = await pRetry(run, { + shouldRetry: error => !(error instanceof CustomError); + }); + ``` + + In the example above, the operation will be retried unless the error is an instance of `CustomError`. + */ + readonly shouldRetry?: (error: FailedAttemptError) => boolean | Promise; + + /** + You can abort retrying using [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController). + + ``` + import pRetry from 'p-retry'; + + const run = async () => { … }; + const controller = new AbortController(); + + cancelButton.addEventListener('click', () => { + controller.abort(new Error('User clicked cancel button')); + }); + + try { + await pRetry(run, {signal: controller.signal}); + } catch (error) { + console.log(error.message); + //=> 'User clicked cancel button' + } + ``` + */ + readonly signal?: AbortSignal; +} & OperationOptions; + +/** +Returns a `Promise` that is fulfilled when calling `input` returns a fulfilled promise. If calling `input` returns a rejected promise, `input` is called again until the max retries are reached, it then rejects with the last rejection reason. + +Does not retry on most `TypeErrors`, with the exception of network errors. This is done on a best case basis as different browsers have different [messages](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Checking_that_the_fetch_was_successful) to indicate this. +See [whatwg/fetch#526 (comment)](https://github.com/whatwg/fetch/issues/526#issuecomment-554604080) + +@param input - Receives the number of attempts as the first argument and is expected to return a `Promise` or any value. +@param options - Options are passed to the [`retry`](https://github.com/tim-kos/node-retry#retryoperationoptions) module. + +@example +``` +import pRetry, {AbortError} from 'p-retry'; +import fetch from 'node-fetch'; + +const run = async () => { + const response = await fetch('https://sindresorhus.com/unicorn'); + + // Abort retrying if the resource doesn't exist + if (response.status === 404) { + throw new AbortError(response.statusText); + } + + return response.blob(); +}; + +console.log(await pRetry(run, {retries: 5})); + +// With the `onFailedAttempt` option: +const result = await pRetry(run, { + onFailedAttempt: error => { + console.log(`Attempt ${error.attemptNumber} failed. There are ${error.retriesLeft} retries left.`); + // 1st request => Attempt 1 failed. There are 4 retries left. + // 2nd request => Attempt 2 failed. There are 3 retries left. + // … + }, + retries: 5 +}); + +console.log(result); +``` +*/ +export default function pRetry( + input: (attemptCount: number) => PromiseLike | T, + options?: Options +): Promise; diff --git a/packages/datadog-transport-common/src/vendor/p-retry/index.js b/packages/datadog-transport-common/src/vendor/p-retry/index.js new file mode 100644 index 0000000..3a2f2c6 --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/p-retry/index.js @@ -0,0 +1,94 @@ +import retry from 'retry'; +import isNetworkError from 'is-network-error'; + +export class AbortError extends Error { + constructor(message) { + super(); + + if (message instanceof Error) { + this.originalError = message; + ({message} = message); + } else { + this.originalError = new Error(message); + this.originalError.stack = this.stack; + } + + this.name = 'AbortError'; + this.message = message; + } +} + +const decorateErrorWithCounts = (error, attemptNumber, options) => { + // Minus 1 from attemptNumber because the first attempt does not count as a retry + const retriesLeft = options.retries - (attemptNumber - 1); + + error.attemptNumber = attemptNumber; + error.retriesLeft = retriesLeft; + return error; +}; + +export default async function pRetry(input, options) { + return new Promise((resolve, reject) => { + options = { + onFailedAttempt() {}, + retries: 10, + shouldRetry: () => true, + ...options, + }; + + const operation = retry.operation(options); + + const abortHandler = () => { + operation.stop(); + reject(options.signal?.reason); + }; + + if (options.signal && !options.signal.aborted) { + options.signal.addEventListener('abort', abortHandler, {once: true}); + } + + const cleanUp = () => { + options.signal?.removeEventListener('abort', abortHandler); + operation.stop(); + }; + + operation.attempt(async attemptNumber => { + try { + const result = await input(attemptNumber); + cleanUp(); + resolve(result); + } catch (error) { + try { + if (!(error instanceof Error)) { + throw new TypeError(`Non-error was thrown: "${error}". You should only throw errors.`); + } + + if (error instanceof AbortError) { + throw error.originalError; + } + + if (error instanceof TypeError && !isNetworkError(error)) { + throw error; + } + + decorateErrorWithCounts(error, attemptNumber, options); + + if (!(await options.shouldRetry(error))) { + operation.stop(); + reject(error); + } + + await options.onFailedAttempt(error); + + if (!operation.retry(error)) { + throw operation.mainError(); + } + } catch (finalError) { + decorateErrorWithCounts(finalError, attemptNumber, options); + cleanUp(); + reject(finalError); + } + } + }); + }); +} diff --git a/packages/datadog-transport-common/src/vendor/p-retry/index.test-d.ts b/packages/datadog-transport-common/src/vendor/p-retry/index.test-d.ts new file mode 100644 index 0000000..1599c22 --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/p-retry/index.test-d.ts @@ -0,0 +1,28 @@ +import {expectType} from 'tsd'; +import pRetry, {AbortError, type FailedAttemptError} from './index.js'; + +expectType>( + pRetry(async count => { + expectType(count); + return 1; + }), +); +expectType>( + pRetry(() => {}, { // eslint-disable-line @typescript-eslint/no-empty-function + onFailedAttempt(error) { + expectType(error); + expectType(error.attemptNumber); + expectType(error.retriesLeft); + }, + }), +); +expectType>( + pRetry(() => 'foo', { + retries: 5, + }), +); + +const abortError = new AbortError('foo'); +new AbortError(new Error('foo')); // eslint-disable-line no-new + +expectType(abortError); diff --git a/packages/datadog-transport-common/src/vendor/p-retry/license b/packages/datadog-transport-common/src/vendor/p-retry/license new file mode 100644 index 0000000..fa7ceba --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/p-retry/license @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) Sindre Sorhus (https://sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/datadog-transport-common/src/vendor/p-retry/package.json b/packages/datadog-transport-common/src/vendor/p-retry/package.json new file mode 100644 index 0000000..5fc5e2b --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/p-retry/package.json @@ -0,0 +1,58 @@ +{ + "name": "p-retry", + "private": true, + "version": "6.2.0", + "description": "Retry a promise-returning or async function", + "license": "MIT", + "repository": "sindresorhus/p-retry", + "funding": "https://github.com/sponsors/sindresorhus", + "author": { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "https://sindresorhus.com" + }, + "type": "module", + "exports": "./index.js", + "types": "./index.d.ts", + "sideEffects": false, + "engines": { + "node": ">=16.17" + }, + "scripts": { + "test": "xo && ava && tsd" + }, + "files": [ + "index.js", + "index.d.ts" + ], + "keywords": [ + "promise", + "retry", + "retries", + "operation", + "failed", + "rejected", + "try", + "exponential", + "backoff", + "attempt", + "async", + "await", + "promises", + "concurrently", + "concurrency", + "parallel", + "bluebird" + ], + "dependencies": { + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", + "retry": "^0.13.1" + }, + "devDependencies": { + "ava": "^5.3.1", + "delay": "^6.0.0", + "tsd": "^0.28.1", + "xo": "^0.56.0" + } +} diff --git a/packages/datadog-transport-common/src/vendor/p-retry/readme.md b/packages/datadog-transport-common/src/vendor/p-retry/readme.md new file mode 100644 index 0000000..a12566d --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/p-retry/readme.md @@ -0,0 +1,184 @@ +# p-retry + +> Retry a promise-returning or async function + +It does exponential backoff and supports custom retry strategies for failed operations. + +## Install + +```sh +npm install p-retry +``` + +## Usage + +```js +import pRetry, {AbortError} from 'p-retry'; +import fetch from 'node-fetch'; + +const run = async () => { + const response = await fetch('https://sindresorhus.com/unicorn'); + + // Abort retrying if the resource doesn't exist + if (response.status === 404) { + throw new AbortError(response.statusText); + } + + return response.blob(); +}; + +console.log(await pRetry(run, {retries: 5})); +``` + +## API + +### pRetry(input, options?) + +Returns a `Promise` that is fulfilled when calling `input` returns a fulfilled promise. If calling `input` returns a rejected promise, `input` is called again until the maximum number of retries is reached. It then rejects with the last rejection reason. + +It does not retry on most `TypeError`'s, with the exception of network errors. This is done on a best case basis as different browsers have different [messages](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Checking_that_the_fetch_was_successful) to indicate this. See [whatwg/fetch#526 (comment)](https://github.com/whatwg/fetch/issues/526#issuecomment-554604080) + +#### input + +Type: `Function` + +Receives the current attempt number as the first argument and is expected to return a `Promise` or any value. + +#### options + +Type: `object` + +Options are passed to the [`retry`](https://github.com/tim-kos/node-retry#retryoperationoptions) module. + +##### onFailedAttempt(error) + +Type: `Function` + +Callback invoked on each retry. Receives the error thrown by `input` as the first argument with properties `attemptNumber` and `retriesLeft` which indicate the current attempt number and the number of attempts left, respectively. + +```js +import pRetry from 'p-retry'; + +const run = async () => { + const response = await fetch('https://sindresorhus.com/unicorn'); + + if (!response.ok) { + throw new Error(response.statusText); + } + + return response.json(); +}; + +const result = await pRetry(run, { + onFailedAttempt: error => { + console.log(`Attempt ${error.attemptNumber} failed. There are ${error.retriesLeft} retries left.`); + // 1st request => Attempt 1 failed. There are 4 retries left. + // 2nd request => Attempt 2 failed. There are 3 retries left. + // … + }, + retries: 5 +}); + +console.log(result); +``` + +The `onFailedAttempt` function can return a promise. For example, you can do some async logging: + +```js +import pRetry from 'p-retry'; +import logger from './some-logger'; + +const run = async () => { … }; + +const result = await pRetry(run, { + onFailedAttempt: async error => { + await logger.log(error); + } +}); +``` + +If the `onFailedAttempt` function throws, all retries will be aborted and the original promise will reject with the thrown error. + +##### shouldRetry(error) + +Type: `Function` + +Decide if a retry should occur based on the error. Returning true triggers a retry, false aborts with the error. + +It is not called for `TypeError` (except network errors) and `AbortError`. + +```js +import pRetry from 'p-retry'; + +const run = async () => { … }; + +const result = await pRetry(run, { + shouldRetry: error => !(error instanceof CustomError); +}); +``` + +In the example above, the operation will be retried unless the error is an instance of `CustomError`. + +##### signal + +Type: [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) + +You can abort retrying using [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController). + +```js +import pRetry from 'p-retry'; + +const run = async () => { … }; +const controller = new AbortController(); + +cancelButton.addEventListener('click', () => { + controller.abort(new Error('User clicked cancel button')); +}); + +try { + await pRetry(run, {signal: controller.signal}); +} catch (error) { + console.log(error.message); + //=> 'User clicked cancel button' +} +``` + +### AbortError(message) +### AbortError(error) + +Abort retrying and reject the promise. + +### message + +Type: `string` + +An error message. + +### error + +Type: `Error` + +A custom error. + +## Tip + +You can pass arguments to the function being retried by wrapping it in an inline arrow function: + +```js +import pRetry from 'p-retry'; + +const run = async emoji => { + // … +}; + +// Without arguments +await pRetry(run, {retries: 5}); + +// With arguments +await pRetry(() => run('πŸ¦„'), {retries: 5}); +``` + +## Related + +- [p-timeout](https://github.com/sindresorhus/p-timeout) - Timeout a promise after a specified amount of time +- [More…](https://github.com/sindresorhus/promise-fun) diff --git a/packages/datadog-transport-common/src/vendor/p-retry/test.js b/packages/datadog-transport-common/src/vendor/p-retry/test.js new file mode 100644 index 0000000..ac3d461 --- /dev/null +++ b/packages/datadog-transport-common/src/vendor/p-retry/test.js @@ -0,0 +1,304 @@ +import test from 'ava'; +import delay from 'delay'; +import pRetry, {AbortError} from './index.js'; + +const fixture = Symbol('fixture'); +const fixtureError = new Error('fixture'); + +test('retries', async t => { + let index = 0; + + const returnValue = await pRetry(async attemptNumber => { + await delay(40); + index++; + return attemptNumber === 3 ? fixture : Promise.reject(fixtureError); + }); + + t.is(returnValue, fixture); + t.is(index, 3); +}); + +test('aborts', async t => { + t.plan(2); + + let index = 0; + + await t.throwsAsync(pRetry(async attemptNumber => { + await delay(40); + index++; + return attemptNumber === 3 ? Promise.reject(new AbortError(fixtureError)) : Promise.reject(fixtureError); + }), {is: fixtureError}); + + t.is(index, 3); +}); + +test('no retry on TypeError', async t => { + t.plan(2); + + const typeErrorFixture = new TypeError('type-error-fixture'); + + let index = 0; + + await t.throwsAsync(pRetry(async attemptNumber => { + await delay(40); + index++; + return attemptNumber === 3 ? fixture : Promise.reject(typeErrorFixture); + }), {is: typeErrorFixture}); + + t.is(index, 1); +}); + +test('retry on TypeError - failed to fetch', async t => { + const typeErrorFixture = new TypeError('Failed to fetch'); + let index = 0; + + const returnValue = await pRetry(async attemptNumber => { + await delay(40); + index++; + return attemptNumber === 3 ? fixture : Promise.reject(typeErrorFixture); + }); + + t.is(returnValue, fixture); + t.is(index, 3); +}); + +test('AbortError - string', t => { + const error = new AbortError('fixture').originalError; + t.is(error.constructor.name, 'Error'); + t.is(error.message, 'fixture'); +}); + +test('AbortError - error', t => { + const error = new AbortError(new Error('fixture')).originalError; + t.is(error.constructor.name, 'Error'); + t.is(error.message, 'fixture'); +}); + +test('onFailedAttempt is called expected number of times', async t => { + t.plan(8); + + const retries = 5; + let index = 0; + let attemptNumber = 0; + + await pRetry( + async attemptNumber => { + await delay(40); + index++; + return attemptNumber === 3 ? fixture : Promise.reject(fixtureError); + }, + { + onFailedAttempt(error) { + t.is(error, fixtureError); + t.is(error.attemptNumber, ++attemptNumber); + + switch (index) { + case 1: { + t.is(error.retriesLeft, retries); + break; + } + + case 2: { + t.is(error.retriesLeft, 4); + break; + } + + case 3: { + t.is(error.retriesLeft, 3); + break; + } + + case 4: { + t.is(error.retriesLeft, 2); + break; + } + + default: { + t.fail('onFailedAttempt was called more than 4 times'); + break; + } + } + }, + retries, + }, + ); + + t.is(index, 3); + t.is(attemptNumber, 2); +}); + +test('onFailedAttempt is called before last rejection', async t => { + t.plan(15); + + const r = 3; + let i = 0; + let j = 0; + + await t.throwsAsync(pRetry( + async () => { + await delay(40); + i++; + throw fixtureError; + }, + { + onFailedAttempt(error) { + t.is(error, fixtureError); + t.is(error.attemptNumber, ++j); + + switch (i) { + case 1: { + t.is(error.retriesLeft, r); + break; + } + + case 2: { + t.is(error.retriesLeft, 2); + break; + } + + case 3: { + t.is(error.retriesLeft, 1); + break; + } + + case 4: { + t.is(error.retriesLeft, 0); + break; + } + + default: { + t.fail('onFailedAttempt was called more than 4 times'); + break; + } + } + }, + retries: r, + }, + ), {is: fixtureError}); + + t.is(i, 4); + t.is(j, 4); +}); + +test('onFailedAttempt can return a promise to add a delay', async t => { + const waitFor = 1000; + const start = Date.now(); + let isCalled; + + await pRetry( + async () => { + if (isCalled) { + return fixture; + } + + isCalled = true; + + throw fixtureError; + }, + { + async onFailedAttempt() { + await delay(waitFor); + }, + }, + ); + + t.true(Date.now() > start + waitFor); +}); + +test('onFailedAttempt can throw, causing all retries to be aborted', async t => { + t.plan(1); + const error = new Error('thrown from onFailedAttempt'); + + try { + await pRetry(async () => { + throw fixtureError; + }, { + onFailedAttempt() { + throw error; + }, + }); + } catch (error_) { + t.is(error_, error); + } +}); + +test('throws useful error message when non-error is thrown', async t => { + await t.throwsAsync(pRetry(() => { + throw 'foo'; // eslint-disable-line no-throw-literal + }), { + message: /Non-error/, + }); +}); + +test('aborts with an AbortSignal', async t => { + t.plan(2); + + let index = 0; + const controller = new AbortController(); + + await t.throwsAsync(pRetry(async attemptNumber => { + await delay(40); + index++; + if (attemptNumber === 3) { + controller.abort(); + } + + throw fixtureError; + }, { + signal: controller.signal, + }), { + // TODO: Make this only `instanceOf: DOMException` when targeting Node.js 18. + instanceOf: globalThis.DOMException === undefined ? Error : DOMException, + }); + + t.is(index, 3); +}); + +test('preserves the abort reason', async t => { + t.plan(2); + + let index = 0; + const controller = new AbortController(); + + await t.throwsAsync(pRetry(async attemptNumber => { + await delay(40); + index++; + if (attemptNumber === 3) { + controller.abort(fixtureError); + return; + } + + throw fixtureError; + }, { + signal: controller.signal, + }), { + is: fixtureError, + }); + + t.is(index, 3); +}); + +test('should retry only when shouldRetry returns true', async t => { + t.plan(2); + + const shouldRetryError = new Error('should-retry'); + const customError = new Error('custom-error'); + + let index = 0; + + await t.throwsAsync(pRetry(async () => { + await delay(40); + index++; + const error = index < 3 ? shouldRetryError : customError; + throw error; + }, { + async shouldRetry(error) { + return error.message === shouldRetryError.message; + }, + retries: 10, + }), { + is: customError, + }); + + t.is(index, 3); +}); diff --git a/packages/datadog-transport-common/test/DataDogTransport.test.ts b/packages/datadog-transport-common/test/DataDogTransport.test.ts index 45985bc..d9f394d 100644 --- a/packages/datadog-transport-common/test/DataDogTransport.test.ts +++ b/packages/datadog-transport-common/test/DataDogTransport.test.ts @@ -1,7 +1,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import * as datadogApiClient from "@datadog/datadog-api-client"; -import pRetry from "p-retry"; -import * as exitHook from "exit-hook"; +import pRetry from "../src/vendor/p-retry"; +import * as exitHook from "../src/vendor/exit-hook"; import { type LogStorage, DataDogTransport } from "../src"; vi.mock("@datadog/datadog-api-client", () => ({ @@ -18,11 +18,11 @@ vi.mock("@datadog/datadog-api-client", () => ({ }, })); -vi.mock("p-retry", () => ({ +vi.mock("../src/vendor/p-retry", () => ({ default: vi.fn((fn) => fn()), })); -vi.mock("exit-hook", () => ({ +vi.mock("../src/vendor/exit-hook", () => ({ default: vi.fn((callback) => callback()), })); diff --git a/packages/datadog-transport-common/tsconfig.json b/packages/datadog-transport-common/tsconfig.json index f1b331b..2f59240 100644 --- a/packages/datadog-transport-common/tsconfig.json +++ b/packages/datadog-transport-common/tsconfig.json @@ -1,4 +1,5 @@ { "extends": "tsconfig/tsconfig.json", - "include": ["./src/**/*"] + "include": ["./src/**/*"], + "exclude": ["./src/vendor/**/*"] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c8159e5..edd4a7a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -27,8 +27,11 @@ importers: specifier: ^20.12.5 version: 20.12.5 husky: - specifier: ^9.0.11 - version: 9.0.11 + specifier: ^8.0.0 + version: 8.0.3 + lint-staged: + specifier: ^15.2.2 + version: 15.2.2 syncpack: specifier: ^12.3.0 version: 12.3.0(typescript@5.4.4) @@ -47,13 +50,16 @@ importers: '@datadog/datadog-api-client': specifier: ^1.23.0 version: 1.23.0 - exit-hook: - specifier: ^2.2.1 - version: 2.2.1 - p-retry: - specifier: ^4.6.2 - version: 4.6.2 + is-network-error: + specifier: ^1.1.0 + version: 1.1.0 + retry: + specifier: ^0.13.1 + version: 0.13.1 devDependencies: + '@types/retry': + specifier: ^0.12.5 + version: 0.12.5 tsconfig: specifier: workspace:* version: link:../tsconfig @@ -1289,9 +1295,9 @@ packages: resolution: {integrity: sha512-YBtzT2ztNF6R/9+UXj2wTGFnC9NklAnASt3sC0h2m1bbH7G6FyBIkt4AN8ThZpNfxUo1b2iMVO0UawiJymEt8A==} dev: false - /@types/retry@0.12.0: - resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} - dev: false + /@types/retry@0.12.5: + resolution: {integrity: sha512-3xSjTp3v03X/lSQLkczaN9UIEwJMoMCA1+Nb5HfbJEQWogdeQIyVtTvxPXDQjZ5zws8rFQfVfRdz03ARihPJgw==} + dev: true /@types/semver@7.5.8: resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} @@ -1376,6 +1382,11 @@ packages: engines: {node: '>=6'} dev: true + /ansi-escapes@6.2.1: + resolution: {integrity: sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==} + engines: {node: '>=14.16'} + dev: true + /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -1680,11 +1691,26 @@ packages: restore-cursor: 3.1.0 dev: true + /cli-cursor@4.0.0: + resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + restore-cursor: 4.0.0 + dev: true + /cli-spinners@2.9.2: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} dev: true + /cli-truncate@4.0.0: + resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==} + engines: {node: '>=18'} + dependencies: + slice-ansi: 5.0.0 + string-width: 7.1.0 + dev: true + /cliui@6.0.0: resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} dependencies: @@ -1728,6 +1754,10 @@ packages: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: true + /colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + dev: true + /combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -1993,6 +2023,10 @@ packages: engines: {node: '>= 14'} dev: false + /emoji-regex@10.3.0: + resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==} + dev: true + /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: true @@ -2208,6 +2242,10 @@ packages: engines: {node: '>=6'} dev: false + /eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + dev: true + /events@3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} @@ -2243,11 +2281,6 @@ packages: strip-final-newline: 3.0.0 dev: true - /exit-hook@2.2.1: - resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} - engines: {node: '>=6'} - dev: false - /extendable-error@0.1.7: resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} dev: true @@ -2400,6 +2433,11 @@ packages: engines: {node: 6.* || 8.* || >= 10.*} dev: true + /get-east-asian-width@1.2.0: + resolution: {integrity: sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==} + engines: {node: '>=18'} + dev: true + /get-func-name@2.0.2: resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} dev: true @@ -2577,9 +2615,9 @@ packages: engines: {node: '>=16.17.0'} dev: true - /husky@9.0.11: - resolution: {integrity: sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw==} - engines: {node: '>=18'} + /husky@8.0.3: + resolution: {integrity: sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==} + engines: {node: '>=14'} hasBin: true dev: true @@ -2701,6 +2739,18 @@ packages: engines: {node: '>=8'} dev: true + /is-fullwidth-code-point@4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + dev: true + + /is-fullwidth-code-point@5.0.0: + resolution: {integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==} + engines: {node: '>=18'} + dependencies: + get-east-asian-width: 1.2.0 + dev: true + /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -2718,6 +2768,11 @@ packages: engines: {node: '>= 0.4'} dev: true + /is-network-error@1.1.0: + resolution: {integrity: sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==} + engines: {node: '>=16'} + dev: false + /is-number-object@1.0.7: resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} engines: {node: '>= 0.4'} @@ -2904,6 +2959,11 @@ packages: engines: {node: '>=6'} dev: true + /lilconfig@3.0.0: + resolution: {integrity: sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==} + engines: {node: '>=14'} + dev: true + /lilconfig@3.1.1: resolution: {integrity: sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==} engines: {node: '>=14'} @@ -2913,6 +2973,37 @@ packages: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} dev: true + /lint-staged@15.2.2: + resolution: {integrity: sha512-TiTt93OPh1OZOsb5B7k96A/ATl2AjIZo+vnzFZ6oHK5FuTk63ByDtxGQpHm+kFETjEWqgkF95M8FRXKR/LEBcw==} + engines: {node: '>=18.12.0'} + hasBin: true + dependencies: + chalk: 5.3.0 + commander: 11.1.0 + debug: 4.3.4 + execa: 8.0.1 + lilconfig: 3.0.0 + listr2: 8.0.1 + micromatch: 4.0.5 + pidtree: 0.6.0 + string-argv: 0.3.2 + yaml: 2.3.4 + transitivePeerDependencies: + - supports-color + dev: true + + /listr2@8.0.1: + resolution: {integrity: sha512-ovJXBXkKGfq+CwmKTjluEqFi3p4h8xvkxGQQAQan22YCgef4KZ1mKGjzfGh6PL6AW5Csw0QiQPNuQyH+6Xk3hA==} + engines: {node: '>=18.0.0'} + dependencies: + cli-truncate: 4.0.0 + colorette: 2.0.20 + eventemitter3: 5.0.1 + log-update: 6.0.0 + rfdc: 1.3.1 + wrap-ansi: 9.0.0 + dev: true + /load-tsconfig@0.2.5: resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -3005,6 +3096,17 @@ packages: is-unicode-supported: 0.1.0 dev: true + /log-update@6.0.0: + resolution: {integrity: sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==} + engines: {node: '>=18'} + dependencies: + ansi-escapes: 6.2.1 + cli-cursor: 4.0.0 + slice-ansi: 7.1.0 + strip-ansi: 7.1.0 + wrap-ansi: 9.0.0 + dev: true + /loglevel@1.9.1: resolution: {integrity: sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg==} engines: {node: '>= 0.6.0'} @@ -3354,14 +3456,6 @@ packages: engines: {node: '>=6'} dev: true - /p-retry@4.6.2: - resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} - engines: {node: '>=8'} - dependencies: - '@types/retry': 0.12.0 - retry: 0.13.1 - dev: false - /p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} @@ -3442,6 +3536,12 @@ packages: engines: {node: '>=8.6'} dev: true + /pidtree@0.6.0: + resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} + engines: {node: '>=0.10'} + hasBin: true + dev: true + /pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} @@ -3708,6 +3808,14 @@ packages: signal-exit: 3.0.7 dev: true + /restore-cursor@4.0.0: + resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + dev: true + /retry@0.13.1: resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} engines: {node: '>= 4'} @@ -3718,6 +3826,10 @@ packages: engines: {iojs: '>=1.0.0', node: '>=0.10.0'} dev: true + /rfdc@1.3.1: + resolution: {integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==} + dev: true + /rollup@4.14.0: resolution: {integrity: sha512-Qe7w62TyawbDzB4yt32R0+AbIo6m1/sqO7UPzFS8Z/ksL5mrfhA0v4CavfdmFav3D+ub4QeAgsGEe84DoWe/nQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -3878,6 +3990,22 @@ packages: engines: {node: '>=8'} dev: true + /slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + dev: true + + /slice-ansi@7.1.0: + resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==} + engines: {node: '>=18'} + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 5.0.0 + dev: true + /smartwrap@2.0.2: resolution: {integrity: sha512-vCsKNQxb7PnCNd2wY1WClWifAc2lwqsG8OaswpJkVJsvMGcnEntdTCDajZCkk93Ay1U3t/9puJmb525Rg5MZBA==} engines: {node: '>=6'} @@ -3954,6 +4082,11 @@ packages: mixme: 0.5.10 dev: true + /string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + dev: true + /string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -3972,6 +4105,15 @@ packages: strip-ansi: 7.1.0 dev: true + /string-width@7.1.0: + resolution: {integrity: sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==} + engines: {node: '>=18'} + dependencies: + emoji-regex: 10.3.0 + get-east-asian-width: 1.2.0 + strip-ansi: 7.1.0 + dev: true + /string.prototype.trim@1.2.9: resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} engines: {node: '>= 0.4'} @@ -4660,6 +4802,15 @@ packages: strip-ansi: 7.1.0 dev: true + /wrap-ansi@9.0.0: + resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} + engines: {node: '>=18'} + dependencies: + ansi-styles: 6.2.1 + string-width: 7.1.0 + strip-ansi: 7.1.0 + dev: true + /y18n@4.0.3: resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} dev: true @@ -4677,6 +4828,11 @@ packages: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} dev: true + /yaml@2.3.4: + resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==} + engines: {node: '>= 14'} + dev: true + /yaml@2.4.1: resolution: {integrity: sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==} engines: {node: '>= 14'} diff --git a/turbo.json b/turbo.json index ce2e0e4..81c8b4b 100644 --- a/turbo.json +++ b/turbo.json @@ -10,9 +10,7 @@ "dependsOn": ["^build"], "outputs": ["dist/**"] }, - "test": { - "inputs": ["test/**/*.ts"] - }, + "test": {}, "lint": {}, "format": {}, "typecheck": {