fix(picker): pointer-width vtable offsets, COM apartment pairing, unconditional abort budget, and the full failure chain
Review round two on the in-process dialog:
- Vtable slots and out-pointers use koffi.sizeof('void *') instead of a
hardcoded 8 - win32-ia32 (which Node and koffi both ship) would have read
method pointers from the wrong address and crashed in-process before any
fallback could run.
- runFolderDialog pairs every successful (incl. S_FALSE) CoInitializeEx
with CoUninitialize in the outermost finally, releasing the dialog first;
a failed init is deliberately unpaired. Pinned across fake-bindings and
mocked-koffi suites.
- The abort close budget starts unconditionally: a worker hung before the
showing notice (koffi import or COM init) now ends in terminate instead
of a dangling promise; WM_CLOSE posting still waits for the thread id.
- A triple miss (dialog + pwsh + 5.1) surfaces an AggregateError carrying
all three causes - the in-process tier's reason was previously
unrecoverable from the final PowerShell error.
- The stray '=>{ ' formatter artifacts are normalized to real blocks.
Both stale note claims from the review are fixed: the DPI note's
Consequences no longer claims an ENOENT classification or zero new
dependencies, and the 2026-07-27 picker note's Windows bullet now names
the in-process primary and keeps the PowerShell chain as fallback (both
languages, pairings re-recorded).
This commit is contained in:
@@ -97,10 +97,16 @@ describe('native directory picker', () => {
|
||||
.mockResolvedValueOnce({ stdout: '', stderr: '' })
|
||||
await expect(pickNativeDirectory(signal(), { platform: 'win32', run: cancelled, pickWin32Dialog: noDialog })).resolves.toBeNull()
|
||||
|
||||
// Triple miss: the surfaced AggregateError carries all three causes,
|
||||
// including the otherwise-lost in-process dialog failure.
|
||||
const failed = vi.fn<DirectoryPickerRunner>()
|
||||
.mockRejectedValueOnce(failure('ENOENT'))
|
||||
.mockRejectedValueOnce(failure(2))
|
||||
await expect(pickNativeDirectory(signal(), { platform: 'win32', run: failed, pickWin32Dialog: noDialog })).rejects.toThrow('command failed')
|
||||
const tripleMiss = await pickNativeDirectory(signal(), { platform: 'win32', run: failed, pickWin32Dialog: noDialog })
|
||||
.then(() => { throw new Error('expected rejection') }, (error: unknown) => error as AggregateError)
|
||||
expect(tripleMiss.message).toContain('the in-process dialog and both PowerShell hosts failed')
|
||||
expect((tripleMiss.errors[0] as Error).message).toBe('dialog unavailable')
|
||||
expect((tripleMiss.errors[2] as Error).message).toContain('command failed')
|
||||
})
|
||||
|
||||
it('wires the real Win32 dialog as the default tier', async () => {
|
||||
@@ -153,7 +159,9 @@ describe('native directory picker', () => {
|
||||
execFileMock.mockImplementationOnce((_command, _args, _options, callback) => {
|
||||
callback(commandError, 'partial output', 'failure details')
|
||||
})
|
||||
await expect(pickNativeDirectory(signal(), { platform: 'win32', pickWin32Dialog: noDialog })).rejects.toMatchObject({
|
||||
const surfaced = await pickNativeDirectory(signal(), { platform: 'win32', pickWin32Dialog: noDialog })
|
||||
.then(() => { throw new Error('expected rejection') }, (error: unknown) => error as AggregateError)
|
||||
expect(surfaced.errors[2]).toMatchObject({
|
||||
message: 'powershell failed', cause: commandError, code: 7,
|
||||
stdout: 'partial output', stderr: 'failure details',
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user