Align root Node types with the supported Node 24 runtime (#30617)

* Align root Node types with the supported Node 24 runtime

* Preserve mobile rejection listeners with Node 24 types
This commit is contained in:
Neil
2026-10-19 00:46:25 -07:00
committed by GitHub
parent 5be871e537
commit f184c13bd7
13 changed files with 269 additions and 200 deletions
-3
View File
@@ -27,8 +27,6 @@
1 tests/e2e/cross-version-wire/structured-agent-session-host-fixture.ts
1 tests/e2e/cross-version-wire/submission-positions-downgrade.unit.test.ts
1 tests/e2e/cross-version-wire/versioned-agent-session-wire.ts
1 tests/e2e/daemon-generation-legacy-close-safety.spec.ts
1 tests/e2e/daemon-generation-reconnect-safety.spec.ts
1 tests/e2e/editable-context-paste-ownership.spec.ts
1 tests/e2e/file-explorer-linked-watch-refresh.spec.ts
5 tests/e2e/fixtures/daemon-generation-legacy-close-client.ts
@@ -38,7 +36,6 @@
1 tests/e2e/github-created-issue-start-prefill.spec.ts
1 tests/e2e/headless-paired-remote-terminal-reveal-grid.spec.ts
1 tests/e2e/headless-serve-desktop-activation.spec.ts
1 tests/e2e/helpers/daemon-generation-safety-fixtures.ts
5 tests/e2e/helpers/headless-paired-runtime-host.ts
1 tests/e2e/helpers/native-chat-view.ts
2 tests/e2e/helpers/nested-runtime-ssh-client-route.ts
+16
View File
@@ -109,6 +109,22 @@ export function findNodeRuntimePinProblems({
`NODE_RUNTIME_PIN.version ${pin.version} is not package.json engines.node major ${engineMajor}`
)
}
const runtimeMajor = majorOf(pin.version)
const declaredNodeTypes =
packageJson.devDependencies?.['@types/node'] ?? packageJson.dependencies?.['@types/node']
if (majorOf(declaredNodeTypes) !== runtimeMajor) {
problems.push(
`package.json @types/node is ${declaredNodeTypes}, but NODE_RUNTIME_PIN.version major is ${runtimeMajor}`
)
}
const lockedNodeTypes = lockedVersion(
rootImporter.devDependencies?.['@types/node'] ?? rootImporter.dependencies?.['@types/node']
)
if (majorOf(lockedNodeTypes) !== runtimeMajor) {
problems.push(
`pnpm-lock.yaml resolves @types/node ${lockedNodeTypes}, but NODE_RUNTIME_PIN.version major is ${runtimeMajor}`
)
}
if (!Number.isInteger(pin.napi) || pin.napi < 1) {
problems.push(`NODE_RUNTIME_PIN.napi must be a positive integer, got ${pin.napi}`)
}
+35 -2
View File
@@ -45,10 +45,14 @@ function validInput() {
pin,
assets,
targets,
packageJson: { devDependencies: { electron: '43.7.5' }, engines: { node: '24' } },
packageJson: {
devDependencies: { electron: '43.7.5', '@types/node': '^24.19.2' },
engines: { node: '24' }
},
rootImporter: {
devDependencies: {
electron: { specifier: '43.7.5', version: '43.7.5(supports-color@7.2.0)' }
electron: { specifier: '43.7.5', version: '43.7.5(supports-color@7.2.0)' },
'@types/node': { specifier: '^24.19.2', version: '24.19.2' }
}
}
}
@@ -85,6 +89,35 @@ describe('findNodeRuntimePinProblems', () => {
])
})
it.each(['^25.6.0', '^22.20.0', undefined])(
'rejects declared Node types %s outside the runtime major',
(nodeTypes) => {
const input = validInput()
input.packageJson.devDependencies['@types/node'] = nodeTypes
expect(findNodeRuntimePinProblems(input)).toEqual([
`package.json @types/node is ${nodeTypes}, but NODE_RUNTIME_PIN.version major is 24`
])
}
)
it.each(['25.6.0', '22.20.0', undefined])(
'rejects locked Node types %s outside the runtime major',
(nodeTypes) => {
const input = validInput()
input.rootImporter.devDependencies['@types/node'].version = nodeTypes
expect(findNodeRuntimePinProblems(input)).toEqual([
`pnpm-lock.yaml resolves @types/node ${nodeTypes ?? null}, but NODE_RUNTIME_PIN.version major is 24`
])
}
)
it('accepts Node type versions within the runtime major', () => {
const input = validInput()
input.packageJson.devDependencies['@types/node'] = '^24.18.0'
input.rootImporter.devDependencies['@types/node'].version = '24.19.0'
expect(findNodeRuntimePinProblems(input)).toEqual([])
})
it('requires exactly one asset per server target', () => {
const input = validInput()
delete input.assets['win32-x64']
@@ -45,7 +45,8 @@ async function unhandledRejectionsWhile(run: () => Promise<void>): Promise<unkno
} finally {
process.removeAllListeners('unhandledRejection')
for (const listener of previous) {
process.on('unhandledRejection', listener)
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: raw listeners handle this event; preserve their wrappers so once listeners still fire once.
process.on('unhandledRejection', listener as NodeJS.UnhandledRejectionListener)
}
}
return captured
@@ -17,7 +17,8 @@ export function recordUnhandledRejections(
active = false
process.removeAllListeners('unhandledRejection')
for (const listener of previous) {
process.on('unhandledRejection', listener)
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: raw listeners handle this event; preserve their wrappers so once listeners still fire once.
process.on('unhandledRejection', listener as NodeJS.UnhandledRejectionListener)
}
}
}
+1 -1
View File
@@ -255,7 +255,7 @@
"@tiptap/starter-kit": "3.31.3",
"@types/hast": "^3.0.4",
"@types/mdast": "^4.0.4",
"@types/node": "^25.6.0",
"@types/node": "^24.19.2",
"@types/proper-lockfile": "^4.1.4",
"@types/qrcode": "^1.5.6",
"@types/react": "~19.2.18",
+104 -109
View File
@@ -286,7 +286,7 @@ importers:
version: 10.0.0(@dnd-kit/core@6.3.1(@types/react-dom@19.2.7(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(@types/react@19.2.18)(react@19.2.8))(react@19.2.8))(@types/react@19.2.18)(react@19.2.8)
'@electron-toolkit/tsconfig':
specifier: ^2.0.0
version: 2.0.0(@types/node@25.9.5)
version: 2.0.0(@types/node@24.19.2)
'@electron/rebuild':
specifier: ^4.2.1
version: 4.2.1(supports-color@7.2.0)
@@ -316,13 +316,13 @@ importers:
version: 0.0.26
'@tailwindcss/vite':
specifier: ^4.3.3
version: 4.3.3(vite@8.3.4(@types/node@25.9.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))
version: 4.3.3(vite@8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))
'@tanstack/react-virtual':
specifier: ^3.14.13
version: 3.14.13(@types/react-dom@19.2.7(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(@types/react@19.2.18)(react@19.2.8))(react@19.2.8)
'@testing-library/jest-dom':
specifier: ^6.9.1
version: 6.9.1(vitest@5.0.5(@opentelemetry/api@1.9.1)(@types/node@25.9.5)(happy-dom@20.14.5)(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(vite@8.3.4(@types/node@25.9.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)))
version: 6.9.1(vitest@5.0.5(@opentelemetry/api@1.9.1)(@types/node@24.19.2)(happy-dom@20.14.5)(msw@2.14.3(@types/node@24.19.2)(typescript@7.0.2))(vite@8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)))
'@testing-library/react':
specifier: ^16.3.3
version: 16.3.3(@testing-library/dom@10.4.1)(@types/react-dom@19.2.7(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(@types/react@19.2.18)(react@19.2.8))(react@19.2.8)
@@ -390,8 +390,8 @@ importers:
specifier: ^4.0.4
version: 4.0.4
'@types/node':
specifier: ^25.6.0
version: 25.9.5
specifier: ^24.19.2
version: 24.19.2
'@types/proper-lockfile':
specifier: ^4.1.4
version: 4.1.4
@@ -412,7 +412,7 @@ importers:
version: 8.18.1
'@vitejs/plugin-react':
specifier: ^6.1.2
version: 6.1.2(vite@8.3.4(@types/node@25.9.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))
version: 6.1.2(vite@8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))
'@vscode/ripgrep-universal':
specifier: 1.18.0
version: 1.18.0
@@ -469,7 +469,7 @@ importers:
version: 26.15.3(electron-builder-squirrel-windows@26.15.3)(supports-color@7.2.0)
electron-vite:
specifier: ^6.0.0
version: 6.0.0(@swc/core@1.16.2)(electron@43.7.8(supports-color@7.2.0))(supports-color@7.2.0)(vite@8.3.4(@types/node@25.9.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))
version: 6.0.0(@swc/core@1.16.2)(electron@43.7.8(supports-color@7.2.0))(supports-color@7.2.0)(vite@8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))
emoji-picker-react:
specifier: ^4.22.3
version: 4.22.3(@types/react@19.2.18)(react@19.2.8)
@@ -493,7 +493,7 @@ importers:
version: 9.1.7
i18next-cli:
specifier: 1.74.2
version: 1.74.2(patch_hash=2ee32eef742615cd133e1a6940f027deb3723a8430bb7953bba3a6769b0aac47)(@types/node@25.9.5)(@types/react@19.2.18)(react-dom@19.2.8(@types/react@19.2.18)(react@19.2.8))(react@19.2.8)(typescript@7.0.2)
version: 1.74.2(patch_hash=2ee32eef742615cd133e1a6940f027deb3723a8430bb7953bba3a6769b0aac47)(@types/node@24.19.2)(@types/react@19.2.18)(react-dom@19.2.8(@types/react@19.2.18)(react@19.2.8))(react@19.2.8)(typescript@7.0.2)
katex:
specifier: 0.18.10
version: 0.18.10
@@ -628,10 +628,10 @@ importers:
version: 11.0.5
vite:
specifier: ^8.3.4
version: 8.3.4(@types/node@25.9.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)
version: 8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)
vitest:
specifier: 5.0.5
version: 5.0.5(@opentelemetry/api@1.9.1)(@types/node@25.9.5)(happy-dom@20.14.5)(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(vite@8.3.4(@types/node@25.9.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))
version: 5.0.5(@opentelemetry/api@1.9.1)(@types/node@24.19.2)(happy-dom@20.14.5)(msw@2.14.3(@types/node@24.19.2)(typescript@7.0.2))(vite@8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))
vscode-oniguruma:
specifier: ^2.0.1
version: 2.0.1
@@ -4154,8 +4154,8 @@ packages:
'@types/node@18.19.130':
resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==}
'@types/node@24.12.4':
resolution: {integrity: sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==}
'@types/node@24.19.2':
resolution: {integrity: sha512-93d49wCWJkCyN87MxLpNN6KXPCwFw7bVUg79mGUV1OS40JGWwVCr8n61DXCSqz7CV6/VfPkb7xec7uP2M+QHWQ==}
'@types/node@25.9.5':
resolution: {integrity: sha512-OScDchr2fwuUmWdf4kZ9h7PcJiYDVInhJizG/biAq3cAvqwYktuy/TYGGdZNMtNTFUP7rnb0NU4TUdm82kt4Rg==}
@@ -8056,9 +8056,6 @@ packages:
undici-types@5.26.5:
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
undici-types@7.16.0:
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
undici-types@7.24.6:
resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==}
@@ -8836,9 +8833,9 @@ snapshots:
'@electron-internal/extract-zip@1.0.4': {}
'@electron-toolkit/tsconfig@2.0.0(@types/node@25.9.5)':
'@electron-toolkit/tsconfig@2.0.0(@types/node@24.19.2)':
dependencies:
'@types/node': 25.9.5
'@types/node': 24.19.2
'@electron-toolkit/utils@4.0.0(electron@43.7.8(supports-color@7.2.0))':
dependencies:
@@ -9115,14 +9112,14 @@ snapshots:
'@inquirer/ansi@2.0.8': {}
'@inquirer/checkbox@5.2.5(@types/node@25.9.5)':
'@inquirer/checkbox@5.2.5(@types/node@24.19.2)':
dependencies:
'@inquirer/ansi': 2.0.8
'@inquirer/core': 12.0.3(@types/node@25.9.5)
'@inquirer/core': 12.0.3(@types/node@24.19.2)
'@inquirer/figures': 2.0.9
'@inquirer/type': 4.1.1(@types/node@25.9.5)
'@inquirer/type': 4.1.1(@types/node@24.19.2)
optionalDependencies:
'@types/node': 25.9.5
'@types/node': 24.19.2
'@inquirer/confirm@6.3.2(@types/node@18.19.130)':
dependencies:
@@ -9132,12 +9129,12 @@ snapshots:
'@types/node': 18.19.130
optional: true
'@inquirer/confirm@6.3.2(@types/node@25.9.5)':
'@inquirer/confirm@6.3.2(@types/node@24.19.2)':
dependencies:
'@inquirer/core': 12.0.3(@types/node@25.9.5)
'@inquirer/type': 4.1.1(@types/node@25.9.5)
'@inquirer/core': 12.0.3(@types/node@24.19.2)
'@inquirer/type': 4.1.1(@types/node@24.19.2)
optionalDependencies:
'@types/node': 25.9.5
'@types/node': 24.19.2
'@inquirer/core@12.0.3(@types/node@18.19.130)':
dependencies:
@@ -9152,111 +9149,111 @@ snapshots:
'@types/node': 18.19.130
optional: true
'@inquirer/core@12.0.3(@types/node@25.9.5)':
'@inquirer/core@12.0.3(@types/node@24.19.2)':
dependencies:
'@inquirer/ansi': 2.0.8
'@inquirer/figures': 2.0.9
'@inquirer/type': 4.1.1(@types/node@25.9.5)
'@inquirer/type': 4.1.1(@types/node@24.19.2)
cli-width: 4.1.0
fast-wrap-ansi: 0.2.2
mute-stream: 3.0.0
signal-exit: 4.1.0
optionalDependencies:
'@types/node': 25.9.5
'@types/node': 24.19.2
'@inquirer/editor@5.3.3(@types/node@25.9.5)':
'@inquirer/editor@5.3.3(@types/node@24.19.2)':
dependencies:
'@inquirer/core': 12.0.3(@types/node@25.9.5)
'@inquirer/external-editor': 3.0.5(@types/node@25.9.5)
'@inquirer/type': 4.1.1(@types/node@25.9.5)
'@inquirer/core': 12.0.3(@types/node@24.19.2)
'@inquirer/external-editor': 3.0.5(@types/node@24.19.2)
'@inquirer/type': 4.1.1(@types/node@24.19.2)
optionalDependencies:
'@types/node': 25.9.5
'@types/node': 24.19.2
'@inquirer/expand@5.1.5(@types/node@25.9.5)':
'@inquirer/expand@5.1.5(@types/node@24.19.2)':
dependencies:
'@inquirer/core': 12.0.3(@types/node@25.9.5)
'@inquirer/type': 4.1.1(@types/node@25.9.5)
'@inquirer/core': 12.0.3(@types/node@24.19.2)
'@inquirer/type': 4.1.1(@types/node@24.19.2)
optionalDependencies:
'@types/node': 25.9.5
'@types/node': 24.19.2
'@inquirer/external-editor@3.0.5(@types/node@25.9.5)':
'@inquirer/external-editor@3.0.5(@types/node@24.19.2)':
dependencies:
chardet: 2.2.0
iconv-lite: 0.7.2
optionalDependencies:
'@types/node': 25.9.5
'@types/node': 24.19.2
'@inquirer/figures@2.0.9': {}
'@inquirer/input@5.1.6(@types/node@25.9.5)':
'@inquirer/input@5.1.6(@types/node@24.19.2)':
dependencies:
'@inquirer/core': 12.0.3(@types/node@25.9.5)
'@inquirer/type': 4.1.1(@types/node@25.9.5)
'@inquirer/core': 12.0.3(@types/node@24.19.2)
'@inquirer/type': 4.1.1(@types/node@24.19.2)
optionalDependencies:
'@types/node': 25.9.5
'@types/node': 24.19.2
'@inquirer/number@4.2.3(@types/node@25.9.5)':
'@inquirer/number@4.2.3(@types/node@24.19.2)':
dependencies:
'@inquirer/core': 12.0.3(@types/node@25.9.5)
'@inquirer/type': 4.1.1(@types/node@25.9.5)
'@inquirer/core': 12.0.3(@types/node@24.19.2)
'@inquirer/type': 4.1.1(@types/node@24.19.2)
optionalDependencies:
'@types/node': 25.9.5
'@types/node': 24.19.2
'@inquirer/password@5.2.2(@types/node@25.9.5)':
'@inquirer/password@5.2.2(@types/node@24.19.2)':
dependencies:
'@inquirer/ansi': 2.0.8
'@inquirer/core': 12.0.3(@types/node@25.9.5)
'@inquirer/type': 4.1.1(@types/node@25.9.5)
'@inquirer/core': 12.0.3(@types/node@24.19.2)
'@inquirer/type': 4.1.1(@types/node@24.19.2)
optionalDependencies:
'@types/node': 25.9.5
'@types/node': 24.19.2
'@inquirer/prompts@8.7.2(@types/node@25.9.5)':
'@inquirer/prompts@8.7.2(@types/node@24.19.2)':
dependencies:
'@inquirer/checkbox': 5.2.5(@types/node@25.9.5)
'@inquirer/confirm': 6.3.2(@types/node@25.9.5)
'@inquirer/editor': 5.3.3(@types/node@25.9.5)
'@inquirer/expand': 5.1.5(@types/node@25.9.5)
'@inquirer/input': 5.1.6(@types/node@25.9.5)
'@inquirer/number': 4.2.3(@types/node@25.9.5)
'@inquirer/password': 5.2.2(@types/node@25.9.5)
'@inquirer/rawlist': 5.3.5(@types/node@25.9.5)
'@inquirer/search': 4.3.3(@types/node@25.9.5)
'@inquirer/select': 5.2.5(@types/node@25.9.5)
'@inquirer/checkbox': 5.2.5(@types/node@24.19.2)
'@inquirer/confirm': 6.3.2(@types/node@24.19.2)
'@inquirer/editor': 5.3.3(@types/node@24.19.2)
'@inquirer/expand': 5.1.5(@types/node@24.19.2)
'@inquirer/input': 5.1.6(@types/node@24.19.2)
'@inquirer/number': 4.2.3(@types/node@24.19.2)
'@inquirer/password': 5.2.2(@types/node@24.19.2)
'@inquirer/rawlist': 5.3.5(@types/node@24.19.2)
'@inquirer/search': 4.3.3(@types/node@24.19.2)
'@inquirer/select': 5.2.5(@types/node@24.19.2)
optionalDependencies:
'@types/node': 25.9.5
'@types/node': 24.19.2
'@inquirer/rawlist@5.3.5(@types/node@25.9.5)':
'@inquirer/rawlist@5.3.5(@types/node@24.19.2)':
dependencies:
'@inquirer/core': 12.0.3(@types/node@25.9.5)
'@inquirer/type': 4.1.1(@types/node@25.9.5)
'@inquirer/core': 12.0.3(@types/node@24.19.2)
'@inquirer/type': 4.1.1(@types/node@24.19.2)
optionalDependencies:
'@types/node': 25.9.5
'@types/node': 24.19.2
'@inquirer/search@4.3.3(@types/node@25.9.5)':
'@inquirer/search@4.3.3(@types/node@24.19.2)':
dependencies:
'@inquirer/core': 12.0.3(@types/node@25.9.5)
'@inquirer/core': 12.0.3(@types/node@24.19.2)
'@inquirer/figures': 2.0.9
'@inquirer/type': 4.1.1(@types/node@25.9.5)
'@inquirer/type': 4.1.1(@types/node@24.19.2)
optionalDependencies:
'@types/node': 25.9.5
'@types/node': 24.19.2
'@inquirer/select@5.2.5(@types/node@25.9.5)':
'@inquirer/select@5.2.5(@types/node@24.19.2)':
dependencies:
'@inquirer/ansi': 2.0.8
'@inquirer/core': 12.0.3(@types/node@25.9.5)
'@inquirer/core': 12.0.3(@types/node@24.19.2)
'@inquirer/figures': 2.0.9
'@inquirer/type': 4.1.1(@types/node@25.9.5)
'@inquirer/type': 4.1.1(@types/node@24.19.2)
optionalDependencies:
'@types/node': 25.9.5
'@types/node': 24.19.2
'@inquirer/type@4.1.1(@types/node@18.19.130)':
optionalDependencies:
'@types/node': 18.19.130
optional: true
'@inquirer/type@4.1.1(@types/node@25.9.5)':
'@inquirer/type@4.1.1(@types/node@24.19.2)':
optionalDependencies:
'@types/node': 25.9.5
'@types/node': 24.19.2
'@isaacs/fs-minipass@4.0.1':
dependencies:
@@ -10963,12 +10960,12 @@ snapshots:
'@tailwindcss/oxide-win32-arm64-msvc': 4.3.3
'@tailwindcss/oxide-win32-x64-msvc': 4.3.3
'@tailwindcss/vite@4.3.3(vite@8.3.4(@types/node@25.9.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))':
'@tailwindcss/vite@4.3.3(vite@8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))':
dependencies:
'@tailwindcss/node': 4.3.3
'@tailwindcss/oxide': 4.3.3
tailwindcss: 4.3.3
vite: 8.3.4(@types/node@25.9.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)
vite: 8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)
'@tanstack/react-virtual@3.14.13(@types/react-dom@19.2.7(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(@types/react@19.2.18)(react@19.2.8))(react@19.2.8)':
dependencies:
@@ -10992,7 +10989,7 @@ snapshots:
picocolors: 1.1.1
pretty-format: 27.5.1
'@testing-library/jest-dom@6.9.1(vitest@5.0.5(@opentelemetry/api@1.9.1)(@types/node@25.9.5)(happy-dom@20.14.5)(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(vite@8.3.4(@types/node@25.9.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)))':
'@testing-library/jest-dom@6.9.1(vitest@5.0.5(@opentelemetry/api@1.9.1)(@types/node@24.19.2)(happy-dom@20.14.5)(msw@2.14.3(@types/node@24.19.2)(typescript@7.0.2))(vite@8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)))':
dependencies:
'@adobe/css-tools': 4.5.0
'@types/aria-query': 5.0.4
@@ -11002,7 +10999,7 @@ snapshots:
picocolors: 1.1.1
redent: 3.0.0
optionalDependencies:
vitest: 5.0.5(@opentelemetry/api@1.9.1)(@types/node@25.9.5)(happy-dom@20.14.5)(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(vite@8.3.4(@types/node@25.9.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))
vitest: 5.0.5(@opentelemetry/api@1.9.1)(@types/node@24.19.2)(happy-dom@20.14.5)(msw@2.14.3(@types/node@24.19.2)(typescript@7.0.2))(vite@8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))
'@testing-library/react@16.3.3(@testing-library/dom@10.4.1)(@types/react-dom@19.2.7(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(@types/react@19.2.18)(react@19.2.8))(react@19.2.8)':
dependencies:
@@ -11444,9 +11441,9 @@ snapshots:
dependencies:
undici-types: 5.26.5
'@types/node@24.12.4':
'@types/node@24.19.2':
dependencies:
undici-types: 7.16.0
undici-types: 7.24.6
'@types/node@25.9.5':
dependencies:
@@ -11476,7 +11473,7 @@ snapshots:
'@types/set-cookie-parser@2.4.10':
dependencies:
'@types/node': 25.9.5
'@types/node': 18.19.130
optional: true
'@types/ssh2@1.15.6':
@@ -11574,10 +11571,10 @@ snapshots:
transitivePeerDependencies:
- '@types/d3-selection'
'@vitejs/plugin-react@6.1.2(vite@8.3.4(@types/node@25.9.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))':
'@vitejs/plugin-react@6.1.2(vite@8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))':
dependencies:
'@rolldown/pluginutils': 1.0.1
vite: 8.3.4(@types/node@25.9.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)
vite: 8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)
'@vitest/mocker@5.0.5(msw@2.14.3(@types/node@18.19.130)(typescript@7.0.2))(vite@8.3.4(@types/node@18.19.130)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))':
dependencies:
@@ -11589,15 +11586,15 @@ snapshots:
msw: 2.14.3(@types/node@18.19.130)(typescript@7.0.2)
vite: 8.3.4(@types/node@18.19.130)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)
'@vitest/mocker@5.0.5(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(vite@8.3.4(@types/node@25.9.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))':
'@vitest/mocker@5.0.5(msw@2.14.3(@types/node@24.19.2)(typescript@7.0.2))(vite@8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))':
dependencies:
'@jridgewell/trace-mapping': 0.3.31
'@vitest/spy': 5.0.5
estree-walker: 3.0.3
magic-string: 1.4.3
optionalDependencies:
msw: 2.14.3(@types/node@25.9.5)(typescript@7.0.2)
vite: 8.3.4(@types/node@25.9.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)
msw: 2.14.3(@types/node@24.19.2)(typescript@7.0.2)
vite: 8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)
'@vitest/spy@5.0.5': {}
@@ -12522,7 +12519,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
electron-vite@6.0.0(@swc/core@1.16.2)(electron@43.7.8(supports-color@7.2.0))(supports-color@7.2.0)(vite@8.3.4(@types/node@25.9.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)):
electron-vite@6.0.0(@swc/core@1.16.2)(electron@43.7.8(supports-color@7.2.0))(supports-color@7.2.0)(vite@8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)):
dependencies:
'@babel/core': 7.29.7(supports-color@7.2.0)
'@babel/plugin-transform-arrow-functions': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))
@@ -12531,7 +12528,7 @@ snapshots:
magic-string: 1.4.2
picocolors: 1.1.1
rolldown: 1.2.14
vite: 8.3.4(@types/node@25.9.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)
vite: 8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)
optionalDependencies:
'@swc/core': 1.16.2
transitivePeerDependencies:
@@ -12555,7 +12552,7 @@ snapshots:
dependencies:
'@electron-internal/extract-zip': 1.0.4
'@electron/get': 5.0.0(supports-color@7.2.0)
'@types/node': 24.12.4
'@types/node': 24.19.2
transitivePeerDependencies:
- supports-color
@@ -13347,7 +13344,7 @@ snapshots:
husky@9.1.7: {}
i18next-cli@1.74.2(patch_hash=2ee32eef742615cd133e1a6940f027deb3723a8430bb7953bba3a6769b0aac47)(@types/node@25.9.5)(@types/react@19.2.18)(react-dom@19.2.8(@types/react@19.2.18)(react@19.2.8))(react@19.2.8)(typescript@7.0.2):
i18next-cli@1.74.2(patch_hash=2ee32eef742615cd133e1a6940f027deb3723a8430bb7953bba3a6769b0aac47)(@types/node@24.19.2)(@types/react@19.2.18)(react-dom@19.2.8(@types/react@19.2.18)(react@19.2.8))(react@19.2.8)(typescript@7.0.2):
dependencies:
'@croct/json5-parser': 0.2.2
'@swc/core': 1.16.2
@@ -13357,7 +13354,7 @@ snapshots:
glob: 13.0.6
i18next: 26.4.2(typescript@7.0.2)
i18next-resources-for-ts: 2.1.1
inquirer: 14.2.2(@types/node@25.9.5)
inquirer: 14.2.2(@types/node@24.19.2)
jiti: 2.7.0
jsonc-parser: 3.3.1
magic-string: 1.4.2
@@ -13422,16 +13419,16 @@ snapshots:
inline-style-parser@0.2.7: {}
inquirer@14.2.2(@types/node@25.9.5):
inquirer@14.2.2(@types/node@24.19.2):
dependencies:
'@inquirer/ansi': 2.0.8
'@inquirer/core': 12.0.3(@types/node@25.9.5)
'@inquirer/prompts': 8.7.2(@types/node@25.9.5)
'@inquirer/type': 4.1.1(@types/node@25.9.5)
'@inquirer/core': 12.0.3(@types/node@24.19.2)
'@inquirer/prompts': 8.7.2(@types/node@24.19.2)
'@inquirer/type': 4.1.1(@types/node@24.19.2)
mute-stream: 3.0.0
run-async: 4.0.6
optionalDependencies:
'@types/node': 25.9.5
'@types/node': 24.19.2
inspect-webkit@0.0.5(typescript@7.0.2):
dependencies:
@@ -14371,9 +14368,9 @@ snapshots:
- '@types/node'
optional: true
msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2):
msw@2.14.3(@types/node@24.19.2)(typescript@7.0.2):
dependencies:
'@inquirer/confirm': 6.3.2(@types/node@25.9.5)
'@inquirer/confirm': 6.3.2(@types/node@24.19.2)
'@mswjs/interceptors': 0.41.9
'@open-draft/deferred-promise': 3.0.0
'@types/statuses': 2.0.6
@@ -15888,8 +15885,6 @@ snapshots:
undici-types@5.26.5: {}
undici-types@7.16.0: {}
undici-types@7.24.6: {}
undici@6.29.0: {}
@@ -16032,7 +16027,7 @@ snapshots:
transitivePeerDependencies:
- '@types/picomatch'
vite@8.3.4(@types/node@25.9.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1):
vite@8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1):
dependencies:
lightningcss: 1.33.0
picomatch: 4.0.7
@@ -16040,7 +16035,7 @@ snapshots:
rolldown: 1.2.14
tinyglobby: 0.2.17
optionalDependencies:
'@types/node': 25.9.5
'@types/node': 24.19.2
esbuild: 0.28.2
fsevents: 2.3.3
jiti: 2.7.0
@@ -16074,10 +16069,10 @@ snapshots:
- '@types/picomatch'
- msw
vitest@5.0.5(@opentelemetry/api@1.9.1)(@types/node@25.9.5)(happy-dom@20.14.5)(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(vite@8.3.4(@types/node@25.9.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)):
vitest@5.0.5(@opentelemetry/api@1.9.1)(@types/node@24.19.2)(happy-dom@20.14.5)(msw@2.14.3(@types/node@24.19.2)(typescript@7.0.2))(vite@8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)):
dependencies:
'@types/chai': 5.2.3
'@vitest/mocker': 5.0.5(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(vite@8.3.4(@types/node@25.9.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))
'@vitest/mocker': 5.0.5(msw@2.14.3(@types/node@24.19.2)(typescript@7.0.2))(vite@8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))
chai: 6.3.0
es-module-lexer: 2.3.2
expect-type: 1.4.0
@@ -16088,11 +16083,11 @@ snapshots:
tinybench: 6.2.2
tinyexec: 1.3.1
tinyglobby: 0.2.17
vite: 8.3.4(@types/node@25.9.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)
vite: 8.3.4(@types/node@24.19.2)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)
why-is-node-running: 3.2.1
optionalDependencies:
'@opentelemetry/api': 1.9.1
'@types/node': 25.9.5
'@types/node': 24.19.2
happy-dom: 20.14.5
transitivePeerDependencies:
- '@types/msw'
@@ -32,7 +32,7 @@ const disconnect = vi.fn()
let restoreProcess = (): void => undefined
function emit(message: AiVaultServiceParentMessage): void {
process.emit('message', message)
process.emit('message', message, undefined)
}
function scan(id: number): void {
@@ -82,7 +82,7 @@ vi.mock('node:fs/promises', async () => {
streaming = true
stream.once('end', () => (streaming = false))
stream.once('close', () => (streaming = false))
stream.on('data', (chunk: Buffer) => {
stream.on('data', (chunk) => {
read.bytes += chunk.length
})
return stream
@@ -23,9 +23,9 @@ vi.mock('./shallow-watch-delivery-probe', () => ({
vi.mock('@parcel/watcher', () => ({ subscribe: subscribeMock }))
describe('parcel watcher process canary', () => {
let originalMessageListeners: ReturnType<typeof process.listeners>
let originalExitListeners: ReturnType<typeof process.listeners>
let originalDisconnectListeners: ReturnType<typeof process.listeners>
let originalMessageListeners: NodeJS.MessageListener[]
let originalExitListeners: NodeJS.ExitListener[]
let originalDisconnectListeners: NodeJS.DisconnectListener[]
let originalSend: typeof process.send
beforeEach(() => {
@@ -77,12 +77,16 @@ describe('parcel watcher process canary', () => {
await import('./parcel-watcher-process-entry')
await vi.advanceTimersByTimeAsync(0)
process.emit('message', {
op: 'subscribe',
id: 7,
dir: '/repo/.git',
opts: { mode: 'shallow', include: ['HEAD'] }
})
process.emit(
'message',
{
op: 'subscribe',
id: 7,
dir: '/repo/.git',
opts: { mode: 'shallow', include: ['HEAD'] }
},
undefined
)
await vi.advanceTimersByTimeAsync(0)
expect(sendMock).toHaveBeenCalledWith(
@@ -119,12 +123,16 @@ describe('parcel watcher process canary', () => {
await import('./parcel-watcher-process-entry')
await vi.advanceTimersByTimeAsync(0)
process.emit('message', {
op: 'subscribe',
id: 1,
dir: '/repo/.git',
opts: { mode: 'shallow', include: ['HEAD'] }
})
process.emit(
'message',
{
op: 'subscribe',
id: 1,
dir: '/repo/.git',
opts: { mode: 'shallow', include: ['HEAD'] }
},
undefined
)
await vi.advanceTimersByTimeAsync(0)
expect(subscribeMock).toHaveBeenCalledTimes(1)
@@ -148,7 +156,7 @@ describe('parcel watcher process canary', () => {
await import('./parcel-watcher-process-entry')
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'subscribe', id: 1, dir: '/large-repo', opts: {} })
process.emit('message', { op: 'subscribe', id: 1, dir: '/large-repo', opts: {} }, undefined)
await vi.advanceTimersByTimeAsync(30_000)
@@ -165,12 +173,12 @@ describe('parcel watcher process canary', () => {
await import('./parcel-watcher-process-entry')
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'subscribe', id: 1, dir: '/repo', opts: {} })
process.emit('message', { op: 'subscribe', id: 1, dir: '/repo', opts: {} }, undefined)
await vi.advanceTimersByTimeAsync(0)
await vi.advanceTimersByTimeAsync(10_000)
expect(writeFileSyncMock).toHaveBeenCalledTimes(1)
process.emit('message', { op: 'subscribe', id: 2, dir: '/large-repo', opts: {} })
process.emit('message', { op: 'subscribe', id: 2, dir: '/large-repo', opts: {} }, undefined)
await vi.advanceTimersByTimeAsync(20_000)
expect(writeFileSyncMock).toHaveBeenCalledTimes(1)
@@ -186,12 +194,12 @@ describe('parcel watcher process canary', () => {
await import('./parcel-watcher-process-entry')
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'subscribe', id: 1, dir: '/repo-a', opts: {} })
process.emit('message', { op: 'subscribe', id: 1, dir: '/repo-a', opts: {} }, undefined)
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'subscribe', id: 2, dir: '/repo-b', opts: {} })
process.emit('message', { op: 'subscribe', id: 2, dir: '/repo-b', opts: {} }, undefined)
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'unsubscribe', id: 1 })
process.emit('message', { op: 'unsubscribe', id: 1 }, undefined)
await vi.advanceTimersByTimeAsync(30_000)
expect(writeFileSyncMock).toHaveBeenCalledTimes(3)
@@ -215,11 +223,11 @@ describe('parcel watcher process canary', () => {
await import('./parcel-watcher-process-entry')
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'subscribe', id: 1, dir: '/repo-a', opts: {} })
process.emit('message', { op: 'subscribe', id: 1, dir: '/repo-a', opts: {} }, undefined)
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'subscribe', id: 2, dir: '/repo-b', opts: {} })
process.emit('message', { op: 'subscribe', id: 2, dir: '/repo-b', opts: {} }, undefined)
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'unsubscribe', id: 1 })
process.emit('message', { op: 'unsubscribe', id: 1 }, undefined)
await vi.advanceTimersByTimeAsync(30_000)
expect(deadlockedUnsubscribe).not.toHaveBeenCalled()
@@ -244,15 +252,15 @@ describe('parcel watcher process canary', () => {
await import('./parcel-watcher-process-entry')
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'subscribe', id: 1, dir: '/repo-a', opts: {} })
process.emit('message', { op: 'subscribe', id: 1, dir: '/repo-a', opts: {} }, undefined)
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'subscribe', id: 2, dir: '/repo-b', opts: {} })
process.emit('message', { op: 'subscribe', id: 2, dir: '/repo-b', opts: {} }, undefined)
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'unsubscribe', id: 1 })
process.emit('message', { op: 'unsubscribe', id: 1 }, undefined)
await vi.advanceTimersByTimeAsync(0)
expect(deadlockedUnsubscribe).toHaveBeenCalledTimes(1)
process.emit('message', { op: 'subscribe', id: 3, dir: '/repo-c', opts: {} })
process.emit('message', { op: 'subscribe', id: 3, dir: '/repo-c', opts: {} }, undefined)
await vi.advanceTimersByTimeAsync(30_000)
expect(subscribeMock).toHaveBeenCalledTimes(3)
@@ -275,12 +283,12 @@ describe('parcel watcher process canary', () => {
await import('./parcel-watcher-process-entry')
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'subscribe', id: 1, dir: '/live-repo', opts: {} })
process.emit('message', { op: 'subscribe', id: 1, dir: '/live-repo', opts: {} }, undefined)
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'subscribe', id: 2, dir: '/crawling-repo', opts: {} })
process.emit('message', { op: 'subscribe', id: 2, dir: '/crawling-repo', opts: {} }, undefined)
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'unsubscribe', id: 2 })
process.emit('message', { op: 'subscribe', id: 3, dir: '/later-repo', opts: {} })
process.emit('message', { op: 'unsubscribe', id: 2 }, undefined)
process.emit('message', { op: 'subscribe', id: 3, dir: '/later-repo', opts: {} }, undefined)
await vi.advanceTimersByTimeAsync(30_000)
expect(writeFileSyncMock).not.toHaveBeenCalled()
@@ -308,10 +316,10 @@ describe('parcel watcher process canary', () => {
await import('./parcel-watcher-process-entry')
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'subscribe', id: 1, dir: '/active', opts: {} })
process.emit('message', { op: 'subscribe', id: 1, dir: '/active', opts: {} }, undefined)
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'subscribe', id: 2, dir: '/queued', opts: {} })
process.emit('message', { op: 'cancel-subscribe', id: 2 })
process.emit('message', { op: 'subscribe', id: 2, dir: '/queued', opts: {} }, undefined)
process.emit('message', { op: 'cancel-subscribe', id: 2 }, undefined)
// Why: non-restart cancel reuses async unsubscribe teardown; drain the
// exclusive lifecycle queue after the active crawl finishes.
@@ -337,11 +345,11 @@ describe('parcel watcher process canary', () => {
await import('./parcel-watcher-process-entry')
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'subscribe', id: 1, dir: '/finished', opts: {} })
process.emit('message', { op: 'subscribe', id: 1, dir: '/finished', opts: {} }, undefined)
await vi.advanceTimersByTimeAsync(0)
expect(sendMock).toHaveBeenCalledWith({ op: 'subscribed', id: 1 }, expect.any(Function))
process.emit('message', { op: 'cancel-subscribe', id: 1 })
process.emit('message', { op: 'cancel-subscribe', id: 1 }, undefined)
await vi.advanceTimersByTimeAsync(0)
expect(unsubscribe).toHaveBeenCalledTimes(1)
@@ -362,9 +370,9 @@ describe('parcel watcher process canary', () => {
await import('./parcel-watcher-process-entry')
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'subscribe', id: 1, dir: '/repo', opts: {} })
process.emit('message', { op: 'subscribe', id: 1, dir: '/repo', opts: {} }, undefined)
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'unsubscribe', id: 1 })
process.emit('message', { op: 'unsubscribe', id: 1 }, undefined)
await vi.advanceTimersByTimeAsync(0)
expect(sendMock).toHaveBeenCalledWith(
@@ -390,9 +398,9 @@ describe('parcel watcher process canary', () => {
await import('./parcel-watcher-process-entry')
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'subscribe', id: 1, dir: '/active', opts: {} })
process.emit('message', { op: 'subscribe', id: 1, dir: '/active', opts: {} }, undefined)
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'cancel-subscribe', id: 1 })
process.emit('message', { op: 'cancel-subscribe', id: 1 }, undefined)
expect(sendMock).toHaveBeenCalledWith(
{ op: 'cancel-requires-restart', id: 1 },
@@ -409,7 +417,7 @@ describe('parcel watcher process canary', () => {
await import('./parcel-watcher-process-entry')
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'subscribe', id: 1, dir: '/repo', opts: {} })
process.emit('message', { op: 'subscribe', id: 1, dir: '/repo', opts: {} }, undefined)
await vi.advanceTimersByTimeAsync(0)
await vi.advanceTimersByTimeAsync(30_000)
@@ -436,13 +444,17 @@ describe('parcel watcher process canary', () => {
await import('./parcel-watcher-process-entry')
await vi.advanceTimersByTimeAsync(0)
process.emit('message', {
op: 'subscribe',
id: 1,
dir: '/repo',
opts: {},
delivery: { includeDirectoryMetadata: true, maxEventsPerBatch: 2 }
})
process.emit(
'message',
{
op: 'subscribe',
id: 1,
dir: '/repo',
opts: {},
delivery: { includeDirectoryMetadata: true, maxEventsPerBatch: 2 }
},
undefined
)
await vi.advanceTimersByTimeAsync(0)
callback?.(null, [
@@ -488,7 +500,7 @@ describe('parcel watcher process canary', () => {
await import('./parcel-watcher-process-entry')
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'subscribe', id: 1, dir: '/repo', opts: {} })
process.emit('message', { op: 'subscribe', id: 1, dir: '/repo', opts: {} }, undefined)
await vi.advanceTimersByTimeAsync(0)
callback?.(
@@ -532,7 +544,7 @@ describe('parcel watcher process canary', () => {
process.send = sendMock
await import('./parcel-watcher-process-entry')
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'subscribe', id: 1, dir, opts: {} })
process.emit('message', { op: 'subscribe', id: 1, dir, opts: {} }, undefined)
await vi.advanceTimersByTimeAsync(0)
sendMock.mockClear()
@@ -575,13 +587,17 @@ describe('parcel watcher process canary', () => {
process.send = sendMock
await import('./parcel-watcher-process-entry')
await vi.advanceTimersByTimeAsync(0)
process.emit('message', {
op: 'subscribe',
id: 1,
dir: '/repo',
opts: {},
delivery: { maxEventsPerBatch: 1 }
})
process.emit(
'message',
{
op: 'subscribe',
id: 1,
dir: '/repo',
opts: {},
delivery: { maxEventsPerBatch: 1 }
},
undefined
)
await vi.advanceTimersByTimeAsync(0)
sendMock.mockClear()
@@ -628,13 +644,17 @@ describe('parcel watcher process canary', () => {
await import('./parcel-watcher-process-entry')
await vi.advanceTimersByTimeAsync(0)
process.emit('message', {
op: 'subscribe',
id: 1,
dir: '/repo',
opts: {},
delivery: { includeDirectoryMetadata: true, maxEventsPerBatch: 2 }
})
process.emit(
'message',
{
op: 'subscribe',
id: 1,
dir: '/repo',
opts: {},
delivery: { includeDirectoryMetadata: true, maxEventsPerBatch: 2 }
},
undefined
)
await vi.advanceTimersByTimeAsync(0)
callback?.(null, [{ type: 'update', path: '/repo/first.txt' }])
@@ -673,19 +693,23 @@ describe('parcel watcher process canary', () => {
await import('./parcel-watcher-process-entry')
await vi.advanceTimersByTimeAsync(0)
process.emit('message', {
op: 'subscribe',
id: 1,
dir: '/repo',
opts: {},
delivery: { includeDirectoryMetadata: true, maxEventsPerBatch: 2 }
})
process.emit(
'message',
{
op: 'subscribe',
id: 1,
dir: '/repo',
opts: {},
delivery: { includeDirectoryMetadata: true, maxEventsPerBatch: 2 }
},
undefined
)
await vi.advanceTimersByTimeAsync(0)
callback?.(null, [{ type: 'update', path: '/repo/first.txt' }])
callback?.(null, [{ type: 'update', path: '/repo/queued.txt' }])
await vi.advanceTimersByTimeAsync(0)
process.emit('message', { op: 'unsubscribe', id: 1 })
process.emit('message', { op: 'unsubscribe', id: 1 }, undefined)
await vi.advanceTimersByTimeAsync(0)
releaseFirstEvent?.()
await vi.advanceTimersByTimeAsync(0)
+6 -6
View File
@@ -40,10 +40,10 @@ class RuntimeChild extends EventEmitter {
let child: RuntimeChild
const signalNames = ['SIGINT', 'SIGTERM', 'SIGHUP'] as const
let oldListeners: Map<NodeJS.Signals, ReturnType<typeof process.rawListeners>>
let oldListeners: Map<NodeJS.Signals, NodeJS.SignalsListener[]>
beforeEach(() => {
oldListeners = new Map(signalNames.map((signal) => [signal, process.rawListeners(signal)]))
oldListeners = new Map(signalNames.map((signal) => [signal, process.listeners(signal)]))
child = new RuntimeChild()
fixture.exists.mockReturnValue(true)
fixture.read.mockImplementation((path) =>
@@ -61,7 +61,7 @@ beforeEach(() => {
afterEach(() => {
for (const signal of signalNames) {
for (const listener of process.rawListeners(signal)) {
for (const listener of process.listeners(signal)) {
if (!oldListeners.get(signal)?.includes(listener)) {
process.off(signal, listener)
}
@@ -165,7 +165,7 @@ describe('bundled Orca runtime handoff', () => {
})
for (const signal of signalNames) {
const listener = process
.rawListeners(signal)
.listeners(signal)
.find((candidate) => !oldListeners.get(signal)?.includes(candidate))
if (signal === 'SIGHUP' && platform === 'win32') {
expect(listener).toBeUndefined()
@@ -193,7 +193,7 @@ describe('bundled Orca runtime handoff', () => {
expect(process.exit).toHaveBeenCalledWith(23)
expect(process.kill).not.toHaveBeenCalled()
for (const signal of signalNames) {
expect(process.rawListeners(signal)).toEqual(oldListeners.get(signal))
expect(process.listeners(signal)).toEqual(oldListeners.get(signal))
}
})
@@ -222,7 +222,7 @@ describe('bundled Orca runtime handoff', () => {
expect(() => child.emit('error', new Error('ENOENT'))).toThrow('test process exit')
expect(process.exit).toHaveBeenCalledWith(78)
for (const signal of signalNames) {
expect(process.rawListeners(signal)).toEqual(oldListeners.get(signal))
expect(process.listeners(signal)).toEqual(oldListeners.get(signal))
}
})
@@ -46,7 +46,9 @@ export function enoent(): Error {
return Object.assign(new Error('ENOENT'), { code: 'ENOENT' })
}
export async function fsModuleMock() {
export async function fsModuleMock(): Promise<
Omit<typeof Fs, 'watch'> & { watch: typeof watchMock }
> {
const actual = await vi.importActual<typeof Fs>('fs')
return {
...actual,
@@ -148,7 +148,7 @@ export abstract class SpeechModelDownloadTransport extends SpeechModelHttpDownlo
cleanup()
reject(error)
}
const onData = (chunk: Buffer): void => {
const onData = (chunk: string | Buffer): void => {
hash.update(chunk)
}
const onError = (error: Error): void => {