From 422294cfc2df11faab26b7dbeef1e2f488f70b56 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 16 Aug 2024 17:32:34 +0000 Subject: [PATCH 01/14] chore(release): 1.7.0 [skip ci] ## [1.7.0](https://github.com/hirosystems/api-toolkit/compare/v1.6.2...v1.7.0) (2024-08-16) ### Features * add fastify cpu profiler server ([#28](https://github.com/hirosystems/api-toolkit/issues/28)) ([b224e06](https://github.com/hirosystems/api-toolkit/commit/b224e0673f09b71d52b8506f487c91aa60afdce5)) --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cb45b6..28acd91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.7.0](https://github.com/hirosystems/api-toolkit/compare/v1.6.2...v1.7.0) (2024-08-16) + + +### Features + +* add fastify cpu profiler server ([#28](https://github.com/hirosystems/api-toolkit/issues/28)) ([b224e06](https://github.com/hirosystems/api-toolkit/commit/b224e0673f09b71d52b8506f487c91aa60afdce5)) + ## [1.6.2](https://github.com/hirosystems/api-toolkit/compare/v1.6.1...v1.6.2) (2024-07-05) diff --git a/package-lock.json b/package-lock.json index 1be43da..19c35f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@hirosystems/api-toolkit", - "version": "1.6.2", + "version": "1.7.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@hirosystems/api-toolkit", - "version": "1.6.2", + "version": "1.7.0", "license": "Apache 2.0", "dependencies": { "@fastify/cors": "^8.0.0", diff --git a/package.json b/package.json index ae828f8..5318e94 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@hirosystems/api-toolkit", - "version": "1.6.2", + "version": "1.7.0", "description": "API development toolkit", "main": "./dist/index.js", "typings": "./dist/index.d.ts", From 800982b23393946af6c3017063506be1bb4e46df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20C=C3=A1rdenas?= Date: Mon, 19 Aug 2024 14:34:06 -0600 Subject: [PATCH 02/14] fix: heap snapshot file download (#30) * fix: heap snapshot file download * docs: readme --- README.md | 2 +- src/profiler/server.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ab7b867..804963b 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ Please see each tool's source directory for additional documentation * Node.js signal handlers that provide a way to shut down long-running application components gracefully on unhandled exceptions or interrupt signals. -### CPU Profiler +### Profiler server * Fastify server that controls a profiler capable of generating: * `.cpuprofile` files for CPU usage analysis diff --git a/src/profiler/server.ts b/src/profiler/server.ts index aea8d04..3d3d4c6 100644 --- a/src/profiler/server.ts +++ b/src/profiler/server.ts @@ -155,13 +155,13 @@ const CpuProfiler: FastifyPluginCallback, Server, TypeBoxTy logger.info( `[HeapProfiler] Completed, total snapshot byte size: ${result.totalSnapshotByteSize}` ); + await pipeline(fs.createReadStream(tmpFile), res.raw); await res.headers({ 'Cache-Control': 'no-store', 'Transfer-Encoding': 'chunked', 'Content-Disposition': `attachment; filename="${filename}"`, 'Content-Type': 'application/json; charset=utf-8', }); - await pipeline(fs.createReadStream(tmpFile), res.raw); } finally { const session = existingSession; existingSession = undefined; From 11b962271a0bb62ed063e917f03569541c309afa Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 19 Aug 2024 20:37:47 +0000 Subject: [PATCH 03/14] chore(release): 1.7.1 [skip ci] ## [1.7.1](https://github.com/hirosystems/api-toolkit/compare/v1.7.0...v1.7.1) (2024-08-19) ### Bug Fixes * heap snapshot file download ([#30](https://github.com/hirosystems/api-toolkit/issues/30)) ([800982b](https://github.com/hirosystems/api-toolkit/commit/800982b23393946af6c3017063506be1bb4e46df)) --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28acd91..a0a994b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.7.1](https://github.com/hirosystems/api-toolkit/compare/v1.7.0...v1.7.1) (2024-08-19) + + +### Bug Fixes + +* heap snapshot file download ([#30](https://github.com/hirosystems/api-toolkit/issues/30)) ([800982b](https://github.com/hirosystems/api-toolkit/commit/800982b23393946af6c3017063506be1bb4e46df)) + ## [1.7.0](https://github.com/hirosystems/api-toolkit/compare/v1.6.2...v1.7.0) (2024-08-16) diff --git a/package-lock.json b/package-lock.json index 19c35f3..fa6852f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@hirosystems/api-toolkit", - "version": "1.7.0", + "version": "1.7.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@hirosystems/api-toolkit", - "version": "1.7.0", + "version": "1.7.1", "license": "Apache 2.0", "dependencies": { "@fastify/cors": "^8.0.0", diff --git a/package.json b/package.json index 5318e94..7210a22 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@hirosystems/api-toolkit", - "version": "1.7.0", + "version": "1.7.1", "description": "API development toolkit", "main": "./dist/index.js", "typings": "./dist/index.d.ts", From d56a9ad24f9850be3c372769b9486b71a85f4ae3 Mon Sep 17 00:00:00 2001 From: Matthew Little Date: Thu, 31 Oct 2024 17:44:43 +0100 Subject: [PATCH 04/14] fix: memleak in timeout w/ abort signal (#32) --- src/helpers/__tests__/helpers.test.ts | 52 +++++++++++++++++++++++++++ src/helpers/time.ts | 22 ++++++------ 2 files changed, 64 insertions(+), 10 deletions(-) create mode 100644 src/helpers/__tests__/helpers.test.ts diff --git a/src/helpers/__tests__/helpers.test.ts b/src/helpers/__tests__/helpers.test.ts new file mode 100644 index 0000000..3ae3784 --- /dev/null +++ b/src/helpers/__tests__/helpers.test.ts @@ -0,0 +1,52 @@ +import * as events from 'node:events'; +import { timeout } from '../time'; + +describe('Helper tests', () => { + test('timeout function should not cause memory leak by accumulating abort listeners on abort', async () => { + const controller = new AbortController(); + const { signal } = controller; + + const countListeners = () => events.getEventListeners(signal, 'abort').length; + + // Ensure the initial listener count is zero + expect(countListeners()).toBe(0); + + // Run enough iterations to detect a pattern + for (let i = 0; i < 100; i++) { + try { + const sleepPromise = timeout(1000, signal); + controller.abort(); // Abort immediately + await sleepPromise; + } catch (err: any) { + expect(err.toString()).toMatch(/aborted/i); + } + + // Assert that listener count does not increase + expect(countListeners()).toBeLessThanOrEqual(1); // 1 listener may temporarily be added and removed + } + + // Final check to confirm listeners are cleaned up + expect(countListeners()).toBe(0); + }); + + test('timeout function should not cause memory leak by accumulating abort listeners on successful completion', async () => { + const controller = new AbortController(); + const { signal } = controller; + + const countListeners = () => events.getEventListeners(signal, 'abort').length; + + // Ensure the initial listener count is zero + expect(countListeners()).toBe(0); + + // Run enough iterations to detect a pattern + for (let i = 0; i < 100; i++) { + await timeout(2, signal); // Complete sleep without abort + + // Assert that listener count does not increase + expect(countListeners()).toBe(0); // No listeners should remain after successful sleep completion + } + + // Final check to confirm listeners are cleaned up + expect(countListeners()).toBe(0); + }); +}); diff --git a/src/helpers/time.ts b/src/helpers/time.ts index 3f4042d..37b7faa 100644 --- a/src/helpers/time.ts +++ b/src/helpers/time.ts @@ -1,22 +1,24 @@ +import { addAbortListener } from 'node:events'; + /** * Wait a set amount of milliseconds or until the timer is aborted. * @param ms - Number of milliseconds to wait - * @param abortController - Abort controller + * @param abort - Abort controller * @returns Promise */ -export function timeout(ms: number, abortController?: AbortController): Promise { +export function timeout(ms: number, abort?: AbortController | AbortSignal): Promise { return new Promise((resolve, reject) => { + const signal = abort && 'signal' in abort ? abort.signal : abort; + if (signal?.aborted) return reject(signal.reason); + const disposable = signal ? addAbortListener(signal, onAbort) : undefined; const timeout = setTimeout(() => { + disposable?.[Symbol.dispose ?? (Symbol.for('nodejs.dispose') as typeof Symbol.dispose)](); resolve(); }, ms); - abortController?.signal.addEventListener( - 'abort', - () => { - clearTimeout(timeout); - reject(new Error(`Timeout aborted`)); - }, - { once: true } - ); + function onAbort() { + clearTimeout(timeout); + reject(signal?.reason); + } }); } From cc7a19b6d3e6d5380927241d09ce5ed6ae82761d Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 31 Oct 2024 16:48:14 +0000 Subject: [PATCH 05/14] chore(release): 1.7.2 [skip ci] ## [1.7.2](https://github.com/hirosystems/api-toolkit/compare/v1.7.1...v1.7.2) (2024-10-31) ### Bug Fixes * memleak in timeout w/ abort signal ([#32](https://github.com/hirosystems/api-toolkit/issues/32)) ([d56a9ad](https://github.com/hirosystems/api-toolkit/commit/d56a9ad24f9850be3c372769b9486b71a85f4ae3)) --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0a994b..abe6feb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.7.2](https://github.com/hirosystems/api-toolkit/compare/v1.7.1...v1.7.2) (2024-10-31) + + +### Bug Fixes + +* memleak in timeout w/ abort signal ([#32](https://github.com/hirosystems/api-toolkit/issues/32)) ([d56a9ad](https://github.com/hirosystems/api-toolkit/commit/d56a9ad24f9850be3c372769b9486b71a85f4ae3)) + ## [1.7.1](https://github.com/hirosystems/api-toolkit/compare/v1.7.0...v1.7.1) (2024-08-19) diff --git a/package-lock.json b/package-lock.json index fa6852f..e044ebc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@hirosystems/api-toolkit", - "version": "1.7.1", + "version": "1.7.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@hirosystems/api-toolkit", - "version": "1.7.1", + "version": "1.7.2", "license": "Apache 2.0", "dependencies": { "@fastify/cors": "^8.0.0", diff --git a/package.json b/package.json index 7210a22..892286b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@hirosystems/api-toolkit", - "version": "1.7.1", + "version": "1.7.2", "description": "API development toolkit", "main": "./dist/index.js", "typings": "./dist/index.d.ts", From be9721bd6a86e3fe3135ffe3d3c72600d149f619 Mon Sep 17 00:00:00 2001 From: Matthew Little Date: Tue, 4 Mar 2025 10:09:09 -0700 Subject: [PATCH 06/14] ci: fix deprecated actions (#34) --- .github/workflows/ci.yml | 52 +++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7d6f77c..bb7843c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,26 +17,27 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Use Node.js - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: node-version-file: '.nvmrc' + # https://github.com/actions/cache/blob/main/examples.md#node---npm + - name: Get npm cache directory + id: npm-cache-dir + shell: bash + run: echo "dir=$(npm config get cache)" >> ${GITHUB_OUTPUT} + - name: Cache node modules - uses: actions/cache@v2 - env: - cache-name: cache-node-modules + uses: actions/cache@v4 + id: npm-cache # use this to check for `cache-hit` ==> if: steps.npm-cache.outputs.cache-hit != 'true' with: - path: | - ~/.npm - **/node_modules - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + path: ${{ steps.npm-cache-dir.outputs.dir }} + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- - ${{ runner.os }}-build- - ${{ runner.os }}- + ${{ runner.os }}-node- - name: Install deps run: npm ci --audit=false @@ -56,28 +57,29 @@ jobs: PGPASSWORD: postgres PGDATABASE: postgres steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Use Node.js - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: node-version-file: '.nvmrc' + # https://github.com/actions/cache/blob/main/examples.md#node---npm + - name: Get npm cache directory + id: npm-cache-dir + shell: bash + run: echo "dir=$(npm config get cache)" >> ${GITHUB_OUTPUT} + - name: Cache node modules - uses: actions/cache@v2 - env: - cache-name: cache-node-modules + uses: actions/cache@v4 + id: npm-cache # use this to check for `cache-hit` ==> if: steps.npm-cache.outputs.cache-hit != 'true' with: - path: | - ~/.npm - **/node_modules - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + path: ${{ steps.npm-cache-dir.outputs.dir }} + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- - ${{ runner.os }}-build- - ${{ runner.os }}- + ${{ runner.os }}-node- - name: Install deps run: npm ci --audit=false @@ -108,7 +110,7 @@ jobs: - lint - test steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: token: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }} fetch-depth: 0 From 954e7eaf47f747a6666e3d1884cf353ab0086f32 Mon Sep 17 00:00:00 2001 From: Matthew Little Date: Tue, 4 Mar 2025 10:11:41 -0700 Subject: [PATCH 07/14] fix: use the built-in abortable async setTimeout from `node:timers/promises` rather than implementing ourselves (#33) --- src/helpers/time.ts | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/helpers/time.ts b/src/helpers/time.ts index 37b7faa..e1c6e46 100644 --- a/src/helpers/time.ts +++ b/src/helpers/time.ts @@ -1,4 +1,4 @@ -import { addAbortListener } from 'node:events'; +import { setTimeout as setTimeoutAsync } from 'node:timers/promises'; /** * Wait a set amount of milliseconds or until the timer is aborted. @@ -7,19 +7,8 @@ import { addAbortListener } from 'node:events'; * @returns Promise */ export function timeout(ms: number, abort?: AbortController | AbortSignal): Promise { - return new Promise((resolve, reject) => { - const signal = abort && 'signal' in abort ? abort.signal : abort; - if (signal?.aborted) return reject(signal.reason); - const disposable = signal ? addAbortListener(signal, onAbort) : undefined; - const timeout = setTimeout(() => { - disposable?.[Symbol.dispose ?? (Symbol.for('nodejs.dispose') as typeof Symbol.dispose)](); - resolve(); - }, ms); - function onAbort() { - clearTimeout(timeout); - reject(signal?.reason); - } - }); + const signal = abort && (abort instanceof AbortSignal ? abort : abort.signal); + return setTimeoutAsync(ms, undefined, { signal }); } /** From 379dc9bc1e0465534366db6706acad8ae878e4fc Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 4 Mar 2025 17:13:24 +0000 Subject: [PATCH 08/14] chore(release): 1.7.3 [skip ci] ## [1.7.3](https://github.com/hirosystems/api-toolkit/compare/v1.7.2...v1.7.3) (2025-03-04) ### Bug Fixes * use the built-in abortable async setTimeout from `node:timers/promises` rather than implementing ourselves ([#33](https://github.com/hirosystems/api-toolkit/issues/33)) ([954e7ea](https://github.com/hirosystems/api-toolkit/commit/954e7eaf47f747a6666e3d1884cf353ab0086f32)) --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index abe6feb..e485abb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.7.3](https://github.com/hirosystems/api-toolkit/compare/v1.7.2...v1.7.3) (2025-03-04) + + +### Bug Fixes + +* use the built-in abortable async setTimeout from `node:timers/promises` rather than implementing ourselves ([#33](https://github.com/hirosystems/api-toolkit/issues/33)) ([954e7ea](https://github.com/hirosystems/api-toolkit/commit/954e7eaf47f747a6666e3d1884cf353ab0086f32)) + ## [1.7.2](https://github.com/hirosystems/api-toolkit/compare/v1.7.1...v1.7.2) (2024-10-31) diff --git a/package-lock.json b/package-lock.json index e044ebc..86400d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@hirosystems/api-toolkit", - "version": "1.7.2", + "version": "1.7.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@hirosystems/api-toolkit", - "version": "1.7.2", + "version": "1.7.3", "license": "Apache 2.0", "dependencies": { "@fastify/cors": "^8.0.0", diff --git a/package.json b/package.json index 892286b..39dc264 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@hirosystems/api-toolkit", - "version": "1.7.2", + "version": "1.7.3", "description": "API development toolkit", "main": "./dist/index.js", "typings": "./dist/index.d.ts", From 9c1d2b3dcd6519e46324a56df83da2ebb6cc53e5 Mon Sep 17 00:00:00 2001 From: Matthew Little Date: Wed, 5 Mar 2025 13:08:30 -0700 Subject: [PATCH 09/14] fix: isFinished never set on `waiter` (#35) --- src/helpers/__tests__/helpers.test.ts | 9 ++++++++- src/helpers/time.ts | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/helpers/__tests__/helpers.test.ts b/src/helpers/__tests__/helpers.test.ts index 3ae3784..c543308 100644 --- a/src/helpers/__tests__/helpers.test.ts +++ b/src/helpers/__tests__/helpers.test.ts @@ -1,5 +1,5 @@ import * as events from 'node:events'; -import { timeout } from '../time'; +import { timeout, waiter } from '../time'; describe('Helper tests', () => { test('timeout function should not cause memory leak by accumulating abort listeners on abort', async () => { @@ -49,4 +49,11 @@ describe('Helper tests', () => { // Final check to confirm listeners are cleaned up expect(countListeners()).toBe(0); }); + + test('waiter is finished', async () => { + const myWaiter = waiter(); + myWaiter.finish(); + await myWaiter; + expect(myWaiter.isFinished).toBe(true); + }); }); diff --git a/src/helpers/time.ts b/src/helpers/time.ts index e1c6e46..61f40a5 100644 --- a/src/helpers/time.ts +++ b/src/helpers/time.ts @@ -121,7 +121,7 @@ export function waiter(): Waiter { }); const completer = { finish: (result: T) => { - completer.isFinished = true; + void Object.assign(promise, { isFinished: true }); resolveFn(result); }, isFinished: false, From 60de7edcee98dd4f4caabd8131192d91c470d88d Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 5 Mar 2025 20:10:36 +0000 Subject: [PATCH 10/14] chore(release): 1.7.4 [skip ci] ## [1.7.4](https://github.com/hirosystems/api-toolkit/compare/v1.7.3...v1.7.4) (2025-03-05) ### Bug Fixes * isFinished never set on `waiter` ([#35](https://github.com/hirosystems/api-toolkit/issues/35)) ([9c1d2b3](https://github.com/hirosystems/api-toolkit/commit/9c1d2b3dcd6519e46324a56df83da2ebb6cc53e5)) --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e485abb..6e203c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.7.4](https://github.com/hirosystems/api-toolkit/compare/v1.7.3...v1.7.4) (2025-03-05) + + +### Bug Fixes + +* isFinished never set on `waiter` ([#35](https://github.com/hirosystems/api-toolkit/issues/35)) ([9c1d2b3](https://github.com/hirosystems/api-toolkit/commit/9c1d2b3dcd6519e46324a56df83da2ebb6cc53e5)) + ## [1.7.3](https://github.com/hirosystems/api-toolkit/compare/v1.7.2...v1.7.3) (2025-03-04) diff --git a/package-lock.json b/package-lock.json index 86400d1..3cea9bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@hirosystems/api-toolkit", - "version": "1.7.3", + "version": "1.7.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@hirosystems/api-toolkit", - "version": "1.7.3", + "version": "1.7.4", "license": "Apache 2.0", "dependencies": { "@fastify/cors": "^8.0.0", diff --git a/package.json b/package.json index 39dc264..c86284d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@hirosystems/api-toolkit", - "version": "1.7.3", + "version": "1.7.4", "description": "API development toolkit", "main": "./dist/index.js", "typings": "./dist/index.d.ts", From 6423000fe9d3cb9424179076ae50e487d7facf38 Mon Sep 17 00:00:00 2001 From: Matthew Little Date: Mon, 24 Mar 2025 16:52:51 +0700 Subject: [PATCH 11/14] fix: missing condition for `PostgresError: the database system is not yet accepting connections` (#36) --- src/postgres/errors.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/postgres/errors.ts b/src/postgres/errors.ts index b2ff28f..1d7cd43 100644 --- a/src/postgres/errors.ts +++ b/src/postgres/errors.ts @@ -41,6 +41,8 @@ export function isPgConnectionError(error: any): string | false { return 'Postgres connection closed due to administrator command'; } else if (msg.includes('password authentication failed')) { return 'Postgres authentication failed'; + } else if (msg.includes('database system is not yet accepting connections')) { + return 'Postgres not yet accepting connections'; } } return false; From ecb40b86effef79bd8ed29151260bffb27bbad46 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 24 Mar 2025 09:54:09 +0000 Subject: [PATCH 12/14] chore(release): 1.7.5 [skip ci] ## [1.7.5](https://github.com/hirosystems/api-toolkit/compare/v1.7.4...v1.7.5) (2025-03-24) ### Bug Fixes * missing condition for `PostgresError: the database system is not yet accepting connections` ([#36](https://github.com/hirosystems/api-toolkit/issues/36)) ([6423000](https://github.com/hirosystems/api-toolkit/commit/6423000fe9d3cb9424179076ae50e487d7facf38)) --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e203c3..144bca8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.7.5](https://github.com/hirosystems/api-toolkit/compare/v1.7.4...v1.7.5) (2025-03-24) + + +### Bug Fixes + +* missing condition for `PostgresError: the database system is not yet accepting connections` ([#36](https://github.com/hirosystems/api-toolkit/issues/36)) ([6423000](https://github.com/hirosystems/api-toolkit/commit/6423000fe9d3cb9424179076ae50e487d7facf38)) + ## [1.7.4](https://github.com/hirosystems/api-toolkit/compare/v1.7.3...v1.7.4) (2025-03-05) diff --git a/package-lock.json b/package-lock.json index 3cea9bc..9c36378 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@hirosystems/api-toolkit", - "version": "1.7.4", + "version": "1.7.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@hirosystems/api-toolkit", - "version": "1.7.4", + "version": "1.7.5", "license": "Apache 2.0", "dependencies": { "@fastify/cors": "^8.0.0", diff --git a/package.json b/package.json index c86284d..92fde3e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@hirosystems/api-toolkit", - "version": "1.7.4", + "version": "1.7.5", "description": "API development toolkit", "main": "./dist/index.js", "typings": "./dist/index.d.ts", From 8c56e1aabbac026ba18ca3f8792394bd654aa5e6 Mon Sep 17 00:00:00 2001 From: Matthew Little Date: Tue, 25 Mar 2025 10:41:20 +0700 Subject: [PATCH 13/14] feat: add `reject` function to `waiter` (#38) --- src/helpers/__tests__/helpers.test.ts | 55 ++++++++++++++++++++++++++- src/helpers/time.ts | 29 +++++++++++--- 2 files changed, 77 insertions(+), 7 deletions(-) diff --git a/src/helpers/__tests__/helpers.test.ts b/src/helpers/__tests__/helpers.test.ts index c543308..44e4100 100644 --- a/src/helpers/__tests__/helpers.test.ts +++ b/src/helpers/__tests__/helpers.test.ts @@ -50,10 +50,63 @@ describe('Helper tests', () => { expect(countListeners()).toBe(0); }); - test('waiter is finished', async () => { + test('waiter is resolved', async () => { + const myWaiter = waiter(); + myWaiter.resolve(); + await myWaiter; + expect(myWaiter.isFinished).toBe(true); + expect(myWaiter.isRejected).toBe(false); + expect(myWaiter.isResolved).toBe(true); + }); + + test('waiter is resolved with value', async () => { + const myWaiter = waiter(); + const value = 'my resolve result'; + myWaiter.resolve(value); + const result = await myWaiter; + expect(result).toBe(value); + expect(myWaiter.isFinished).toBe(true); + expect(myWaiter.isRejected).toBe(false); + expect(myWaiter.isResolved).toBe(true); + }); + + test('waiter is finished (ensure finish alias works)', async () => { const myWaiter = waiter(); myWaiter.finish(); await myWaiter; expect(myWaiter.isFinished).toBe(true); + expect(myWaiter.isRejected).toBe(false); + expect(myWaiter.isResolved).toBe(true); + }); + + test('waiter is rejected', async () => { + const myWaiter = waiter(); + const error = new Error('Waiter was rejected'); + myWaiter.reject(error); + await expect(myWaiter).rejects.toThrow(error); + expect(myWaiter.isFinished).toBe(true); + expect(myWaiter.isRejected).toBe(true); + expect(myWaiter.isResolved).toBe(false); + }); + + test('waiter is rejected with error type', async () => { + class MyError extends Error { + readonly name = 'MyError'; + } + const myWaiter = waiter(); + const error = new MyError('MyError test instance'); + myWaiter.reject(error); + await expect(myWaiter).rejects.toThrow(error); + expect(myWaiter.isFinished).toBe(true); + expect(myWaiter.isRejected).toBe(true); + expect(myWaiter.isResolved).toBe(false); + + // Expect other error types to cause a typescript error + class OtherError extends Error { + readonly name = 'OtherError'; + } + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + myWaiter.reject(new OtherError('OtherError test instance')); }); }); diff --git a/src/helpers/time.ts b/src/helpers/time.ts index 61f40a5..bfe6b4e 100644 --- a/src/helpers/time.ts +++ b/src/helpers/time.ts @@ -105,26 +105,43 @@ export function stopwatch(): Stopwatch { return result; } -export type Waiter = Promise & { +export type Waiter = Promise & { + /** Alias for `resolve` */ finish: (result: T) => void; + resolve: (result: T) => void; + reject: (error: E) => void; + /** True if the promise is resolved or rejected */ isFinished: boolean; + /** True only if the promise is resolved */ + isResolved: boolean; + /** True only if the promise is rejected */ + isRejected: boolean; }; /** - * Creates a `Waiter` promise that can be resolved at a later time with a return value. + * Creates a `Waiter` promise that can be resolved or rejected at a later time. * @returns Waiter */ -export function waiter(): Waiter { +export function waiter(): Waiter { let resolveFn: (result: T) => void; - const promise = new Promise(resolve => { + let rejectFn: (error: E) => void; + const promise = new Promise((resolve, reject) => { resolveFn = resolve; + rejectFn = reject; }); const completer = { - finish: (result: T) => { - void Object.assign(promise, { isFinished: true }); + finish: (result: T) => completer.resolve(result), + resolve: (result: T) => { + void Object.assign(promise, { isFinished: true, isResolved: true }); resolveFn(result); }, + reject: (error: E) => { + void Object.assign(promise, { isFinished: true, isRejected: true }); + rejectFn(error); + }, isFinished: false, + isResolved: false, + isRejected: false, }; return Object.assign(promise, completer); } From 4b0f152a57b497e3f12d0d5d75b0c06d5e4a52ce Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 25 Mar 2025 03:42:41 +0000 Subject: [PATCH 14/14] chore(release): 1.8.0 [skip ci] ## [1.8.0](https://github.com/hirosystems/api-toolkit/compare/v1.7.5...v1.8.0) (2025-03-25) ### Features * add `reject` function to `waiter` ([#38](https://github.com/hirosystems/api-toolkit/issues/38)) ([8c56e1a](https://github.com/hirosystems/api-toolkit/commit/8c56e1aabbac026ba18ca3f8792394bd654aa5e6)) --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 144bca8..8ae3f1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.8.0](https://github.com/hirosystems/api-toolkit/compare/v1.7.5...v1.8.0) (2025-03-25) + + +### Features + +* add `reject` function to `waiter` ([#38](https://github.com/hirosystems/api-toolkit/issues/38)) ([8c56e1a](https://github.com/hirosystems/api-toolkit/commit/8c56e1aabbac026ba18ca3f8792394bd654aa5e6)) + ## [1.7.5](https://github.com/hirosystems/api-toolkit/compare/v1.7.4...v1.7.5) (2025-03-24) diff --git a/package-lock.json b/package-lock.json index 9c36378..23c0e57 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@hirosystems/api-toolkit", - "version": "1.7.5", + "version": "1.8.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@hirosystems/api-toolkit", - "version": "1.7.5", + "version": "1.8.0", "license": "Apache 2.0", "dependencies": { "@fastify/cors": "^8.0.0", diff --git a/package.json b/package.json index 92fde3e..c3b8763 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@hirosystems/api-toolkit", - "version": "1.7.5", + "version": "1.8.0", "description": "API development toolkit", "main": "./dist/index.js", "typings": "./dist/index.d.ts",