@furystack/core 15.0.34 → 15.0.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/esm/global-disposable.spec.js +8 -6
- package/esm/global-disposable.spec.js.map +1 -1
- package/esm/port-generator.d.ts +4 -2
- package/esm/port-generator.d.ts.map +1 -1
- package/esm/port-generator.js +8 -4
- package/esm/port-generator.js.map +1 -1
- package/package.json +5 -5
- package/src/global-disposable.spec.ts +36 -34
- package/src/port-generator.ts +9 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [15.0.36] - 2026-02-11
|
|
4
|
+
|
|
5
|
+
### ⬆️ Dependencies
|
|
6
|
+
|
|
7
|
+
- Bump `vitest` from `^4.0.17` to `^4.0.18`
|
|
8
|
+
- Bump `@types/node` from `^25.0.10` to `^25.2.3`
|
|
9
|
+
- Updated internal dependencies
|
|
10
|
+
|
|
11
|
+
## [15.0.35] - 2026-02-09
|
|
12
|
+
|
|
13
|
+
### 🐛 Bug Fixes
|
|
14
|
+
|
|
15
|
+
- Fixed `getPort()` to assign deterministic port ranges per Vitest worker using `VITEST_POOL_ID` instead of a random base port, preventing port collisions in parallel test runs
|
|
16
|
+
|
|
17
|
+
### 🧪 Tests
|
|
18
|
+
|
|
19
|
+
- Refactored `globalDisposable` tests to use `usingAsync` for proper `Injector` disposal
|
|
20
|
+
|
|
3
21
|
## [15.0.34] - 2026-01-26
|
|
4
22
|
|
|
5
23
|
### 🔧 Chores
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Injector } from '@furystack/inject';
|
|
2
|
+
import { usingAsync } from '@furystack/utils';
|
|
2
3
|
import { describe, expect, it, vi } from 'vitest';
|
|
3
4
|
import { exitHandler, globalDisposables } from './global-disposables.js';
|
|
4
5
|
import { disposeOnProcessExit } from './helpers.js';
|
|
@@ -14,13 +15,14 @@ describe('Global Disposables', () => {
|
|
|
14
15
|
expect(process.listeners('uncaughtException')).toContain(exitHandler);
|
|
15
16
|
});
|
|
16
17
|
it('Should be filled from an injector extension', async () => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
await usingAsync(new Injector(), async (i) => {
|
|
19
|
+
disposeOnProcessExit(i);
|
|
20
|
+
expect(globalDisposables).toContain(i);
|
|
21
|
+
globalDisposables.delete(i);
|
|
22
|
+
});
|
|
22
23
|
});
|
|
23
|
-
it('Should dispose the injector on exit',
|
|
24
|
+
it('Should dispose the injector on exit', () => {
|
|
25
|
+
// Not using usingAsync here because exitHandler() itself disposes the injector
|
|
24
26
|
const i = new Injector();
|
|
25
27
|
i[Symbol.asyncDispose] = vi.fn(i[Symbol.asyncDispose]);
|
|
26
28
|
disposeOnProcessExit(i);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"global-disposable.spec.js","sourceRoot":"","sources":["../src/global-disposable.spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AACxE,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AAEnD,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACxC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;QACxD,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;QAC1D,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;QAC3D,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;QAC3D,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;IACvE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"global-disposable.spec.js","sourceRoot":"","sources":["../src/global-disposable.spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AACxE,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AAEnD,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACxC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;QACxD,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;QAC1D,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;QAC3D,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;QAC3D,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;IACvE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,UAAU,CAAC,IAAI,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;YAC3C,oBAAoB,CAAC,CAAC,CAAC,CAAA;YACvB,MAAM,CAAC,iBAAiB,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAA;YACtC,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;QAC7B,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IACF,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,+EAA+E;QAC/E,MAAM,CAAC,GAAG,IAAI,QAAQ,EAAE,CAAA;QACxB,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAA;QACtD,oBAAoB,CAAC,CAAC,CAAC,CAAA;QACvB,WAAW,EAAE,CAAA;QACb,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,EAAE,CAAA;QAC3C,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IAC7B,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
package/esm/port-generator.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Generates a unique port number for testing purposes
|
|
3
|
-
*
|
|
2
|
+
* Generates a unique port number for testing purposes.
|
|
3
|
+
* Each Vitest worker gets a dedicated range of {@link PORTS_PER_WORKER} ports
|
|
4
|
+
* based on its VITEST_POOL_ID to avoid collisions between parallel workers.
|
|
5
|
+
* @returns the next sequential port number
|
|
4
6
|
*/
|
|
5
7
|
export declare const getPort: () => number;
|
|
6
8
|
//# sourceMappingURL=port-generator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"port-generator.d.ts","sourceRoot":"","sources":["../src/port-generator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"port-generator.d.ts","sourceRoot":"","sources":["../src/port-generator.ts"],"names":[],"mappings":"AAaA;;;;;GAKG;AACH,eAAO,MAAM,OAAO,QAAO,MAAgC,CAAA"}
|
package/esm/port-generator.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
|
+
const PORTS_PER_WORKER = 200;
|
|
2
|
+
const BASE_PORT = 14000;
|
|
1
3
|
const portGenerator = function* () {
|
|
2
|
-
const
|
|
3
|
-
let port =
|
|
4
|
+
const workerId = parseInt(process.env.VITEST_POOL_ID ?? '0', 10);
|
|
5
|
+
let port = BASE_PORT + workerId * PORTS_PER_WORKER;
|
|
4
6
|
while (true) {
|
|
5
7
|
yield port++;
|
|
6
8
|
}
|
|
7
9
|
};
|
|
8
10
|
const generator = portGenerator();
|
|
9
11
|
/**
|
|
10
|
-
* Generates a unique port number for testing purposes
|
|
11
|
-
*
|
|
12
|
+
* Generates a unique port number for testing purposes.
|
|
13
|
+
* Each Vitest worker gets a dedicated range of {@link PORTS_PER_WORKER} ports
|
|
14
|
+
* based on its VITEST_POOL_ID to avoid collisions between parallel workers.
|
|
15
|
+
* @returns the next sequential port number
|
|
12
16
|
*/
|
|
13
17
|
export const getPort = () => generator.next().value;
|
|
14
18
|
//# sourceMappingURL=port-generator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"port-generator.js","sourceRoot":"","sources":["../src/port-generator.ts"],"names":[],"mappings":"AAAA,MAAM,aAAa,GAAG,QAAQ,CAAC;IAC7B,MAAM,
|
|
1
|
+
{"version":3,"file":"port-generator.js","sourceRoot":"","sources":["../src/port-generator.ts"],"names":[],"mappings":"AAAA,MAAM,gBAAgB,GAAG,GAAG,CAAA;AAC5B,MAAM,SAAS,GAAG,KAAK,CAAA;AAEvB,MAAM,aAAa,GAAG,QAAQ,CAAC;IAC7B,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,GAAG,EAAE,EAAE,CAAC,CAAA;IAChE,IAAI,IAAI,GAAG,SAAS,GAAG,QAAQ,GAAG,gBAAgB,CAAA;IAClD,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,IAAI,EAAE,CAAA;IACd,CAAC;AACH,CAAC,CAAA;AAED,MAAM,SAAS,GAAG,aAAa,EAAE,CAAA;AAEjC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,GAAW,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,KAAK,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@furystack/core",
|
|
3
|
-
"version": "15.0.
|
|
3
|
+
"version": "15.0.36",
|
|
4
4
|
"description": "Core FuryStack package",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -46,13 +46,13 @@
|
|
|
46
46
|
},
|
|
47
47
|
"homepage": "https://github.com/furystack/furystack",
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@types/node": "^25.
|
|
49
|
+
"@types/node": "^25.2.3",
|
|
50
50
|
"typescript": "^5.9.3",
|
|
51
|
-
"vitest": "^4.0.
|
|
51
|
+
"vitest": "^4.0.18"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@furystack/inject": "^12.0.
|
|
55
|
-
"@furystack/utils": "^8.1.
|
|
54
|
+
"@furystack/inject": "^12.0.30",
|
|
55
|
+
"@furystack/utils": "^8.1.10"
|
|
56
56
|
},
|
|
57
57
|
"engines": {
|
|
58
58
|
"node": ">=22.0.0"
|
|
@@ -1,34 +1,36 @@
|
|
|
1
|
-
import { Injector } from '@furystack/inject'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
expect(process.listeners('
|
|
14
|
-
expect(process.listeners('
|
|
15
|
-
expect(process.listeners('
|
|
16
|
-
expect(process.listeners('
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
1
|
+
import { Injector } from '@furystack/inject'
|
|
2
|
+
import { usingAsync } from '@furystack/utils'
|
|
3
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
4
|
+
import { exitHandler, globalDisposables } from './global-disposables.js'
|
|
5
|
+
import { disposeOnProcessExit } from './helpers.js'
|
|
6
|
+
|
|
7
|
+
describe('Global Disposables', () => {
|
|
8
|
+
it('Should be empty by default', () => {
|
|
9
|
+
expect(globalDisposables.size).toBe(0)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
it('Should attach event listeners', () => {
|
|
13
|
+
expect(process.listeners('exit')).toContain(exitHandler)
|
|
14
|
+
expect(process.listeners('SIGINT')).toContain(exitHandler)
|
|
15
|
+
expect(process.listeners('SIGUSR1')).toContain(exitHandler)
|
|
16
|
+
expect(process.listeners('SIGUSR2')).toContain(exitHandler)
|
|
17
|
+
expect(process.listeners('uncaughtException')).toContain(exitHandler)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('Should be filled from an injector extension', async () => {
|
|
21
|
+
await usingAsync(new Injector(), async (i) => {
|
|
22
|
+
disposeOnProcessExit(i)
|
|
23
|
+
expect(globalDisposables).toContain(i)
|
|
24
|
+
globalDisposables.delete(i)
|
|
25
|
+
})
|
|
26
|
+
})
|
|
27
|
+
it('Should dispose the injector on exit', () => {
|
|
28
|
+
// Not using usingAsync here because exitHandler() itself disposes the injector
|
|
29
|
+
const i = new Injector()
|
|
30
|
+
i[Symbol.asyncDispose] = vi.fn(i[Symbol.asyncDispose])
|
|
31
|
+
disposeOnProcessExit(i)
|
|
32
|
+
exitHandler()
|
|
33
|
+
expect(i[Symbol.asyncDispose]).toBeCalled()
|
|
34
|
+
globalDisposables.delete(i)
|
|
35
|
+
})
|
|
36
|
+
})
|
package/src/port-generator.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
const PORTS_PER_WORKER = 200
|
|
2
|
+
const BASE_PORT = 14000
|
|
3
|
+
|
|
1
4
|
const portGenerator = function* () {
|
|
2
|
-
const
|
|
3
|
-
let port =
|
|
5
|
+
const workerId = parseInt(process.env.VITEST_POOL_ID ?? '0', 10)
|
|
6
|
+
let port = BASE_PORT + workerId * PORTS_PER_WORKER
|
|
4
7
|
while (true) {
|
|
5
8
|
yield port++
|
|
6
9
|
}
|
|
@@ -9,7 +12,9 @@ const portGenerator = function* () {
|
|
|
9
12
|
const generator = portGenerator()
|
|
10
13
|
|
|
11
14
|
/**
|
|
12
|
-
* Generates a unique port number for testing purposes
|
|
13
|
-
*
|
|
15
|
+
* Generates a unique port number for testing purposes.
|
|
16
|
+
* Each Vitest worker gets a dedicated range of {@link PORTS_PER_WORKER} ports
|
|
17
|
+
* based on its VITEST_POOL_ID to avoid collisions between parallel workers.
|
|
18
|
+
* @returns the next sequential port number
|
|
14
19
|
*/
|
|
15
20
|
export const getPort = (): number => generator.next().value
|