@furystack/core 15.0.33 โ†’ 15.0.35

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 CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## [15.0.35] - 2026-02-09
4
+
5
+ ### ๐Ÿ› Bug Fixes
6
+
7
+ - 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
8
+
9
+ ### ๐Ÿงช Tests
10
+
11
+ - Refactored `globalDisposable` tests to use `usingAsync` for proper `Injector` disposal
12
+
13
+ ## [15.0.34] - 2026-01-26
14
+
15
+ ### ๐Ÿ”ง Chores
16
+
17
+ - Standardized author format, improved keywords, removed obsolete `gitHead`, added `engines` (Node 22+) and `sideEffects: false`
18
+
3
19
  ## [15.0.33] - 2026-01-26
4
20
 
5
21
  ### โฌ†๏ธ Dependencies
@@ -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
- const i = new Injector();
18
- disposeOnProcessExit(i);
19
- expect(globalDisposables).toContain(i);
20
- globalDisposables.delete(i);
21
- await i[Symbol.asyncDispose]();
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', async () => {
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,GAAG,IAAI,QAAQ,EAAE,CAAA;QACxB,oBAAoB,CAAC,CAAC,CAAC,CAAA;QACvB,MAAM,CAAC,iBAAiB,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAA;QACtC,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;QAC3B,MAAM,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAA;IAChC,CAAC,CAAC,CAAA;IACF,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,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"}
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"}
@@ -1,6 +1,8 @@
1
1
  /**
2
- * Generates a unique port number for testing purposes
3
- * @returns the next sequential port number starting from a random base between 14000 and 16000
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":"AAUA;;;GAGG;AACH,eAAO,MAAM,OAAO,QAAO,MAAgC,CAAA"}
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"}
@@ -1,14 +1,18 @@
1
+ const PORTS_PER_WORKER = 200;
2
+ const BASE_PORT = 14000;
1
3
  const portGenerator = function* () {
2
- const initialPort = 14000 + Math.floor(Math.random() * 2000);
3
- let port = initialPort;
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
- * @returns the next sequential port number starting from a random base between 14000 and 16000
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,WAAW,GAAG,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAA;IAC5D,IAAI,IAAI,GAAG,WAAW,CAAA;IACtB,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,IAAI,EAAE,CAAA;IACd,CAAC;AACH,CAAC,CAAA;AAED,MAAM,SAAS,GAAG,aAAa,EAAE,CAAA;AAEjC;;;GAGG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,GAAW,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,KAAK,CAAA"}
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,25 +1,27 @@
1
1
  {
2
2
  "name": "@furystack/core",
3
- "version": "15.0.33",
3
+ "version": "15.0.35",
4
4
  "description": "Core FuryStack package",
5
5
  "type": "module",
6
6
  "scripts": {
7
- "build:es6": "tsc --outDir ./esm"
7
+ "build": "tsc --outDir ./esm"
8
8
  },
9
9
  "exports": {
10
10
  ".": {
11
+ "types": "./esm/index.d.ts",
11
12
  "import": "./esm/index.js"
12
13
  },
13
14
  "./create-physical-store-tests": {
15
+ "types": "./esm/create-physical-store-tests.d.ts",
14
16
  "import": "./esm/create-physical-store-tests.js"
15
17
  },
16
18
  "./port-generator": {
19
+ "types": "./esm/port-generator.d.ts",
17
20
  "import": "./esm/port-generator.js"
18
21
  }
19
22
  },
20
23
  "files": [
21
24
  "esm",
22
- "types",
23
25
  "src"
24
26
  ],
25
27
  "repository": {
@@ -28,12 +30,16 @@
28
30
  },
29
31
  "keywords": [
30
32
  "FuryStack",
31
- "framework"
33
+ "framework",
34
+ "store",
35
+ "identity",
36
+ "data store",
37
+ "in-memory"
32
38
  ],
33
39
  "publishConfig": {
34
40
  "access": "public"
35
41
  },
36
- "author": "gallay.lajos@gmail.com",
42
+ "author": "Gallay Lajos <gallay.lajos@gmail.com>",
37
43
  "license": "GPL-2.0",
38
44
  "bugs": {
39
45
  "url": "https://github.com/furystack/furystack/issues"
@@ -45,8 +51,11 @@
45
51
  "vitest": "^4.0.17"
46
52
  },
47
53
  "dependencies": {
48
- "@furystack/inject": "^12.0.27",
49
- "@furystack/utils": "^8.1.8"
54
+ "@furystack/inject": "^12.0.29",
55
+ "@furystack/utils": "^8.1.9"
50
56
  },
51
- "gitHead": "1045d854bfd8c475b7035471d130d401417a2321"
57
+ "engines": {
58
+ "node": ">=22.0.0"
59
+ },
60
+ "sideEffects": false
52
61
  }
@@ -1,34 +1,36 @@
1
- import { Injector } from '@furystack/inject'
2
- import { describe, expect, it, vi } from 'vitest'
3
- import { exitHandler, globalDisposables } from './global-disposables.js'
4
- import { disposeOnProcessExit } from './helpers.js'
5
-
6
- describe('Global Disposables', () => {
7
- it('Should be empty by default', () => {
8
- expect(globalDisposables.size).toBe(0)
9
- })
10
-
11
- it('Should attach event listeners', () => {
12
- expect(process.listeners('exit')).toContain(exitHandler)
13
- expect(process.listeners('SIGINT')).toContain(exitHandler)
14
- expect(process.listeners('SIGUSR1')).toContain(exitHandler)
15
- expect(process.listeners('SIGUSR2')).toContain(exitHandler)
16
- expect(process.listeners('uncaughtException')).toContain(exitHandler)
17
- })
18
-
19
- it('Should be filled from an injector extension', async () => {
20
- const i = new Injector()
21
- disposeOnProcessExit(i)
22
- expect(globalDisposables).toContain(i)
23
- globalDisposables.delete(i)
24
- await i[Symbol.asyncDispose]()
25
- })
26
- it('Should dispose the injector on exit', async () => {
27
- const i = new Injector()
28
- i[Symbol.asyncDispose] = vi.fn(i[Symbol.asyncDispose])
29
- disposeOnProcessExit(i)
30
- exitHandler()
31
- expect(i[Symbol.asyncDispose]).toBeCalled()
32
- globalDisposables.delete(i)
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
+ })
@@ -1,6 +1,9 @@
1
+ const PORTS_PER_WORKER = 200
2
+ const BASE_PORT = 14000
3
+
1
4
  const portGenerator = function* () {
2
- const initialPort = 14000 + Math.floor(Math.random() * 2000)
3
- let port = initialPort
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
- * @returns the next sequential port number starting from a random base between 14000 and 16000
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