Skip to content

feat: Add optional parameter to unwire event when terminated (#12)#39

Open
remdalm wants to merge 1 commit intosilvermine:masterfrom
remdalm:feat/optional-param-to-unwire-event
Open

feat: Add optional parameter to unwire event when terminated (#12)#39
remdalm wants to merge 1 commit intosilvermine:masterfrom
remdalm:feat/optional-param-to-unwire-event

Conversation

@remdalm
Copy link
Copy Markdown

@remdalm remdalm commented Mar 30, 2026

No description provided.

@remdalm remdalm force-pushed the feat/optional-param-to-unwire-event branch 2 times, most recently from 481ad16 to bd731a4 Compare March 30, 2026 16:10
@velocitysystems velocitysystems self-requested a review March 30, 2026 16:32
const actions = {
listen(listener: (download: DownloadWithAnyStatus) => void): Promise<UnlistenFn> {
return DownloadEventManager.shared.addListener(this.path, listener);
listen(
Copy link
Copy Markdown
Collaborator

@velocitysystems velocitysystems Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than refactoring DownloadEventManager we can simplify this by relocating the wrapping logic from DownloadEventManager.addListener to the listen(..) method:

async listen(
   listener: (download: DownloadWithAnyStatus) => void,
   options?: ListenOptions,
): Promise<UnlistenFn> {
   if (!options?.autoUnlisten) {
      return DownloadEventManager.shared.addListener(this.path, listener);
   }

   let unlisten: UnlistenFn;

   const wrappedListener = (download: DownloadWithAnyStatus): void => {
      try {
         listener(download);
      } finally {
         const isTerminal = download.status === DownloadStatus.Completed
            || download.status === DownloadStatus.Canceled;

         if (isTerminal) {
            unlisten();
         }
      }
   };

   unlisten = await DownloadEventManager.shared.addListener(this.path, wrappedListener);
   return unlisten;
},

However this still leaves the issue of "how do we test?" without exposing public methods/utilities for resetting state. We can solve this by extracting into a small, pure, exported function:

// actions.ts
export function wrapListenerWithAutoUnlisten(
   listener: (download: DownloadWithAnyStatus) => void,
   unlisten: () => void,
): (download: DownloadWithAnyStatus) => void {
   return (download: DownloadWithAnyStatus): void => {
      try {
         listener(download);
      } finally {
         const isTerminal = download.status === DownloadStatus.Completed
            || download.status === DownloadStatus.Canceled;

         if (isTerminal) {
            unlisten();
         }
      }
   };
}

Then in actions.listen:

async listen(
   listener: (download: DownloadWithAnyStatus) => void,
   options?: ListenOptions,
): Promise<UnlistenFn> {
   if (!options?.autoUnlisten) {
      return DownloadEventManager.shared.addListener(this.path, listener);
   }

   let unlisten: UnlistenFn;
   const wrapped = wrapListenerWithAutoUnlisten(listener, () => unlisten());

   unlisten = await DownloadEventManager.shared.addListener(this.path, wrapped);
   return unlisten;
},

Tests then become trivial — just call the wrapper directly:

it('calls unlisten on Completed', () => {
   const listener = vi.fn();
   const unlisten = vi.fn();
   const wrapped = wrapListenerWithAutoUnlisten(listener, unlisten);

   wrapped(attachDownload({ ...IDLE_STATE, status: DownloadStatus.Completed }));

   expect(listener).toHaveBeenCalledTimes(1);
   expect(unlisten).toHaveBeenCalledTimes(1);
});

@remdalm remdalm force-pushed the feat/optional-param-to-unwire-event branch 2 times, most recently from a36a0b5 to 134954d Compare April 1, 2026 19:29
@remdalm remdalm force-pushed the feat/optional-param-to-unwire-event branch from 134954d to 24f6f7c Compare April 1, 2026 20:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants