Select the types of activity you want to include in your feed.
refactor: Reduce usage of ErrorWithCause
Error Cause (https://github.com/tc39/proposal-error-cause) was finalized and introduced in ES2022 so we don't need to ponyfill this anymore. Still using the helpful helper functions thought.
···1717import {SimpleIntervalJob, ToadScheduler} from "toad-scheduler";
1818import { createHeartbeatSourcesTask } from "./tasks/heartbeatSources.js";
1919import { createHeartbeatClientsTask } from "./tasks/heartbeatClients.js";
2020-import {ErrorWithCause} from "pony-cause";
2120import {loggerDebug, childLogger, LogData, Logger as FoxLogger} from '@foxxmd/logging';
22212322dayjs.extend(utc)
···4241let logger: FoxLogger;
43424443process.on('uncaughtExceptionMonitor', (err, origin) => {
4545- const appError = new ErrorWithCause(`Uncaught exception is crashing the app! :( Type: ${origin}`, {cause: err});
4444+ const appError = new Error(`Uncaught exception is crashing the app! :( Type: ${origin}`, {cause: err});
4645 if(logger !== undefined) {
4746 logger.error(appError)
4847 } else {
···149148 logger.info('Scheduler started.');
150149151150 } catch (e) {
152152- const appError = new ErrorWithCause('Exited with uncaught error', {cause: e});
151151+ const appError = new Error('Exited with uncaught error', {cause: e});
153152 if(logger !== undefined) {
154153 logger.error(appError);
155154 } else {
+7-7
src/backend/utils.ts
···2121} from "./common/infrastructure/Atomic.js";
2222import {Request} from "express";
2323import pathUtil from "path";
2424-import {ErrorWithCause, getErrorCause} from "pony-cause";
2424+import {getErrorCause} from "pony-cause";
2525import backoffStrategies from '@kenyip/backoff-strategies';
2626import {replaceResultTransformer, stripIndentTransformer, TemplateTag, trimResultTransformer} from 'common-tags';
2727import {Duration} from "dayjs/plugin/duration.js";
···4040 const {code} = e;
4141 if (code === 'ENOENT') {
4242 if (throwOnNotFound) {
4343- throw new ErrorWithCause(`No file found at given path: ${path}`, {cause: e});
4343+ throw new Error(`No file found at given path: ${path}`, {cause: e});
4444 } else {
4545 return;
4646 }
4747 }
4848- throw new ErrorWithCause(`Encountered error while parsing file: ${path}`, {cause: e})
4848+ throw new Error(`Encountered error while parsing file: ${path}`, {cause: e})
4949 }
5050}
5151···536536 // also can't access directory :(
537537 throw new Error(`No ${isDir ? 'directory' : 'file'} exists at ${location} and application does not have permission to write to the parent directory`);
538538 } else {
539539- throw new ErrorWithCause(`No ${isDir ? 'directory' : 'file'} exists at ${location} and application is unable to access the parent directory due to a system error`, {cause: accessError});
539539+ throw new Error(`No ${isDir ? 'directory' : 'file'} exists at ${location} and application is unable to access the parent directory due to a system error`, {cause: accessError});
540540 }
541541 }
542542 } else if(code === 'EACCES') {
543543 throw new Error(`${isDir ? 'Directory' : 'File'} exists at ${location} but application does not have permission to write to it.`);
544544 } else {
545545- throw new ErrorWithCause(`${isDir ? 'Directory' : 'File'} exists at ${location} but application is unable to access it due to a system error`, {cause: err});
545545+ throw new Error(`${isDir ? 'Directory' : 'File'} exists at ${location} but application is unable to access it due to a system error`, {cause: err});
546546 }
547547 }
548548}
···600600 const results = parseRegex(reg, val);
601601 if (results !== undefined) {
602602 if (results.length > 1) {
603603- throw new ErrorWithCause(`Expected Regex to match once but got ${results.length} results. Either Regex must NOT be global (using 'g' flag) or parsed value must only match regex once. Given: ${val} || Regex: ${reg.toString()}`);
603603+ throw new Error(`Expected Regex to match once but got ${results.length} results. Either Regex must NOT be global (using 'g' flag) or parsed value must only match regex once. Given: ${val} || Regex: ${reg.toString()}`);
604604 }
605605 return results[0];
606606 }
···733733 } catch (e) {
734734 if (process.env.DEBUG_MODE === 'true') {
735735 if (logger !== undefined) {
736736- logger.warn(new ErrorWithCause('Could not get machine IP address', {cause: e}));
736736+ logger.warn(new Error('Could not get machine IP address', {cause: e}));
737737 } else {
738738 console.warn('Could not get machine IP address');
739739 console.warn(e);
+5-5
src/backend/scrobblers/AbstractScrobbleClient.ts
···4141import { compareScrobbleArtists, compareScrobbleTracks, normalizeStr } from "../utils/StringUtils.js";
4242import { hasUpstreamError, UpstreamError } from "../common/errors/UpstreamError.js";
4343import {nanoid} from "nanoid";
4444-import {ErrorWithCause, messageWithCauses} from "pony-cause";
4444+import {messageWithCauses} from "pony-cause";
4545import { hasNodeNetworkException } from "../common/errors/NodeErrors.js";
4646import {
4747 comparePlayTemporally,
···187187 // only signal as auth failure if error was NOT either a node network error or a non-showstopping upstream error
188188 this.authFailure = !(hasNodeNetworkException(e) || hasUpstreamError(e, false));
189189 this.authed = false;
190190- this.logger.error(new ErrorWithCause(`Authentication test failed!${this.authFailure === false ? ' Due to a network issue. Will retry authentication on next heartbeat.' : ''}`, {cause: e}));
190190+ this.logger.error(new Error(`Authentication test failed!${this.authFailure === false ? ' Due to a network issue. Will retry authentication on next heartbeat.' : ''}`, {cause: e}));
191191 }
192192 }
193193···583583 } catch (e) {
584584 if (e instanceof UpstreamError && e.showStopper === false) {
585585 this.addDeadLetterScrobble(currQueuedPlay, e);
586586- this.logger.warn(new ErrorWithCause(`Could not scrobble ${buildTrackString(currQueuedPlay.play)} from Source '${currQueuedPlay.source}' but error was not show stopping. Adding scrobble to Dead Letter Queue and will retry on next heartbeat.`, {cause: e}));
586586+ this.logger.warn(new Error(`Could not scrobble ${buildTrackString(currQueuedPlay.play)} from Source '${currQueuedPlay.source}' but error was not show stopping. Adding scrobble to Dead Letter Queue and will retry on next heartbeat.`, {cause: e}));
587587 } else {
588588 this.queuedScrobbles.unshift(currQueuedPlay);
589589- throw new ErrorWithCause('Error occurred while trying to scrobble', {cause: e});
589589+ throw new Error('Error occurred while trying to scrobble', {cause: e});
590590 }
591591 }
592592 } else if (!timeFrameValid) {
···666666 deadScrobble.retries++;
667667 deadScrobble.error = messageWithCauses(e);
668668 deadScrobble.lastRetry = dayjs();
669669- this.logger.error(new ErrorWithCause(`Could not scrobble ${buildTrackString(deadScrobble.play)} from Source '${deadScrobble.source}' due to error`, {cause: e}));
669669+ this.logger.error(new Error(`Could not scrobble ${buildTrackString(deadScrobble.play)} from Source '${deadScrobble.source}' due to error`, {cause: e}));
670670 this.deadLetterScrobbles[deadScrobbleIndex] = deadScrobble;
671671 return [false, deadScrobble];
672672 } finally {
···1111import EventEmitter from "events";
1212import { UpstreamError } from "../common/errors/UpstreamError.js";
1313import { isNodeNetworkException } from "../common/errors/NodeErrors.js";
1414-import {ErrorWithCause} from "pony-cause";
15141615export default class ListenbrainzScrobbler extends AbstractScrobbleClient {
1716···4039 this.initialized = true;
4140 this.logger.info('Initialized');
4241 } catch (e) {
4343- this.logger.warn(new ErrorWithCause('Could not initialize', {cause: e}));
4242+ this.logger.warn(new Error('Could not initialize', {cause: e}));
4443 this.initialized = false;
4544 }
4645 }
+5-7
src/backend/scrobblers/MalojaScrobbler.ts
···2424import EventEmitter from "events";
2525import normalizeUrl from "normalize-url";
2626import { UpstreamError } from "../common/errors/UpstreamError.js";
2727-import {ErrorWithCause} from "pony-cause";
2827import { getScrobbleTsSOCDate, getScrobbleTsSOCDateWithContext } from "../utils/TimeUtils.js";
2929-import e from "express";
3028import { isNodeNetworkException } from "../common/errors/NodeErrors.js";
3129import { isSuperAgentResponseError } from "../common/errors/ErrorUtils.js";
3230···170168 throw new UpstreamError(`API Call failed (HTTP ${status}) => ${message}`, {cause: e})
171169 }
172170 } else {
173173- throw new ErrorWithCause('Unexpected error occurred during API call', {cause : e});
171171+ throw new Error('Unexpected error occurred during API call', {cause : e});
174172 }
175173 }
176174 }
···208206 }
209207 return true;
210208 } catch (e) {
211211- this.logger.error(new ErrorWithCause('Communication test failed', {cause: e}));
209209+ this.logger.error(new Error('Communication test failed', {cause: e}));
212210 return false;
213211 }
214212 }
···244242245243 return [true];
246244 } catch (e) {
247247- this.logger.error(new ErrorWithCause('Unexpected error encountered while testing server health', {cause: e}));
245245+ this.logger.error(new Error('Unexpected error encountered while testing server health', {cause: e}));
248246 throw e;
249247 }
250248 }
···293291 }
294292 } catch (e) {
295293 if(e instanceof UpstreamError) {
296296- if(e.cause.status === 403) {
294294+ if((e?.cause as any)?.status === 403) {
297295 // may be an older version that doesn't support auth readiness before db upgrade
298296 // and if it was before api was accessible during db build then test would fail during testConnection()
299297 if(compareVersions(this.serverVersion, '2.12.19') < 0) {
···322320 this.serverIsHealthy = true;
323321 }
324322 } catch (e) {
325325- this.logger.error(new ErrorWithCause(`Testing server health failed due to an unexpected error`, {cause: e}));
323323+ this.logger.error(new Error(`Testing server health failed due to an unexpected error`, {cause: e}));
326324 this.serverIsHealthy = false;
327325 }
328326 return this.serverIsHealthy
+3-4
src/backend/server/index.ts
···88import { setupApi } from "./api.js";
99import { getAddress, mergeArr, parseBool } from "../utils.js";
1010import {stripIndents} from "common-tags";
1111-import {ErrorWithCause} from "pony-cause";
1211import {childLogger, LogData, LogDataPretty} from "@foxxmd/logging";
1312import {PassThrough} from "node:stream";
1413import {Logger} from '@foxxmd/logging';
···8584 logger.info(`User-defined base URL for UI and redirect URLs (spotify, deezer, lastfm): ${local}`)
8685 }
8786 }).on('error', (err) => {
8888- throw new ErrorWithCause('Server encountered unrecoverable error', {cause: err});
8787+ throw new Error('Server encountered unrecoverable error', {cause: err});
8988 });
9089 } catch (e) {
9191- throw new ErrorWithCause('Server encountered unrecoverable error', {cause: e});
9090+ throw new Error('Server encountered unrecoverable error', {cause: e});
9291 }
93929493 } catch (e) {
9595- throw new ErrorWithCause('Server crashed with uncaught exception', {cause: e});
9494+ throw new Error('Server crashed with uncaught exception', {cause: e});
9695 }
9796}
+6-7
src/backend/sources/AbstractSource.ts
···3636import { PlayObject, TA_CLOSE } from "../../core/Atomic.js";
3737import { buildTrackString, capitalize } from "../../core/StringUtils.js";
3838import { isNodeNetworkException } from "../common/errors/NodeErrors.js";
3939-import {ErrorWithCause} from "pony-cause";
4039import { comparePlayTemporally, temporalAccuracyIsAtLeast } from "../utils/TimeUtils.js";
41404241export interface RecentlyPlayedOptions {
···111110 this.logger.info('Fully Initialized!');
112111 return true;
113112 } catch(e) {
114114- this.logger.error(new ErrorWithCause('Initialization failed', {cause: e}));
113113+ this.logger.error(new Error('Initialization failed', {cause: e}));
115114 return false;
116115 }
117116 }
···135134 this.buildOK = true;
136135 } catch (e) {
137136 this.buildOK = false;
138138- throw new ErrorWithCause('Building required data for initialization failed', {cause: e});
137137+ throw new Error('Building required data for initialization failed', {cause: e});
139138 }
140139 }
141140···166165 this.connectionOK = true;
167166 } catch (e) {
168167 this.connectionOK = false;
169169- throw new ErrorWithCause('Communicating with upstream service failed', {cause: e});
168168+ throw new Error('Communicating with upstream service failed', {cause: e});
170169 }
171170 }
172171···202201 // only signal as auth failure if error was NOT a node network error
203202 this.authFailure = findCauseByFunc(e, isNodeNetworkException) === undefined;
204203 this.authed = false;
205205- throw new ErrorWithCause(`Authentication test failed!${this.authFailure === false ? ' Due to a network issue. Will retry authentication on next heartbeat.' : ''}`, {cause: e})
204204+ throw new Error(`Authentication test failed!${this.authFailure === false ? ' Due to a network issue. Will retry authentication on next heartbeat.' : ''}`, {cause: e})
206205 }
207206 }
208207···322321 try {
323322 backlogPlays = await this.getBackloggedPlays();
324323 } catch (e) {
325325- throw new ErrorWithCause('Error occurred while fetching backlogged plays', {cause: e});
324324+ throw new Error('Error occurred while fetching backlogged plays', {cause: e});
326325 }
327326 const discovered = this.discover(backlogPlays);
328327···385384 try {
386385 await this.processBacklog();
387386 } catch (e) {
388388- this.logger.error(new ErrorWithCause('Cannot start polling because error occurred while processing backlog', {cause: e}));
387387+ this.logger.error(new Error('Cannot start polling because error occurred while processing backlog', {cause: e}));
389388 this.notify({
390389 title: `${this.identifier} - Polling Error`,
391390 message: 'Cannot start polling because error occurred while processing backlog.',
+15-15
src/backend/sources/ChromecastSource.ts
···1111import {EventEmitter} from "events";
1212import {MediaController, PersistentClient, Media, createPlatform} from "@foxxmd/chromecast-client";
1313import {Client as CastClient} from 'castv2';
1414-import {ErrorWithCause, findCauseByReference} from "pony-cause";
1414+import {findCauseByReference} from "pony-cause";
1515import { PlayObject } from "../../core/Atomic.js";
1616import dayjs from "dayjs";
1717import { RecentlyPlayedOptions } from "./AbstractSource.js";
···140140141141 for (const device of devices) {
142142 this.initializeDevice({name: device.name, addresses: [device.address], type: 'googlecast'}).catch((err) => {
143143- this.logger.error(new ErrorWithCause('Uncaught error occurred while connecting to manually configured device', {cause: err}));
143143+ this.logger.error(new Error('Uncaught error occurred while connecting to manually configured device', {cause: err}));
144144 });
145145 }
146146147147 if (useAutoDiscovery) {
148148 if (useAvahi) {
149149 this.discoverAvahi(initial).catch((err) => {
150150- this.logger.error(new ErrorWithCause('Uncaught error occurred during mDNS discovery via Avahi', {cause: err}));
150150+ this.logger.error(new Error('Uncaught error occurred during mDNS discovery via Avahi', {cause: err}));
151151 });
152152 } else {
153153 this.discoverNative(initial).catch((err) => {
154154- this.logger.error(new ErrorWithCause('Uncaught error occurred during mDNS discovery', {cause: err}));
154154+ this.logger.error(new Error('Uncaught error occurred during mDNS discovery', {cause: err}));
155155 });
156156 }
157157 }
···167167 },
168168 });
169169 } catch (e) {
170170- this.logger.error(new ErrorWithCause('Uncaught error occurred during mDNS discovery via Avahi', {cause: e}));
170170+ this.logger.error(new Error('Uncaught error occurred during mDNS discovery via Avahi', {cause: e}));
171171 }
172172 }
173173···181181 },
182182 });
183183 } catch (e) {
184184- this.logger.error(new ErrorWithCause('Uncaught error occurred during mDNS discovery', {cause: e}));
184184+ this.logger.error(new Error('Uncaught error occurred during mDNS discovery', {cause: e}));
185185 }
186186 }
187187···261261 await client.connect();
262262 } catch (e) {
263263 if(index < device.addresses.length - 1) {
264264- this.logger.warn(new ErrorWithCause(`Could not connect to ${device.name} but more interfaces exist, will attempt next host.`, {cause: e}));
264264+ this.logger.warn(new Error(`Could not connect to ${device.name} but more interfaces exist, will attempt next host.`, {cause: e}));
265265 continue;
266266 } else {
267267- throw new ErrorWithCause(`Could not connect to ${device.name} and no additional interfaces exist`, {cause: e});
267267+ throw new Error(`Could not connect to ${device.name} and no additional interfaces exist`, {cause: e});
268268 }
269269 }
270270···284284 }
285285 if(event === "reconnect") {
286286 if(payload instanceof Error) {
287287- info.logger.warn(new ErrorWithCause(`Failed to reconnect, will retry ${5 - info.retries} more times`, {cause: e}))
287287+ info.logger.warn(new Error(`Failed to reconnect, will retry ${5 - info.retries} more times`, {cause: e}))
288288 } else {
289289 info.logger.verbose(`Reconnected`);
290290 info.retries = 0;
···312312 break;
313313 case 'error':
314314 if(info === undefined) {
315315- this.logger.error(new ErrorWithCause(`(${clientName}) Encountered error in castv2 lib`, {cause: payload as Error}));
315315+ this.logger.error(new Error(`(${clientName}) Encountered error in castv2 lib`, {cause: payload as Error}));
316316 } else {
317317 if(NETWORK_ERROR_FAILURE_CODES.some(x => (payload as Error).message.includes(x))) {
318318- info.logger.warn(new ErrorWithCause(`Encountered network error. Will try to reconnect to device`, {cause: payload as Error}));
318318+ info.logger.warn(new Error(`Encountered network error. Will try to reconnect to device`, {cause: payload as Error}));
319319 info.client.client.close();
320320 } else {
321321- info.logger.error(new ErrorWithCause(`Encountered error in castv2 lib`, {cause: payload as Error}));
321321+ info.logger.error(new Error(`Encountered error in castv2 lib`, {cause: payload as Error}));
322322 }
323323 }
324324 break;
···336336 apps = await getCurrentPlatformApplications(v.platform);
337337 v.retries = 0;
338338 } catch (e) {
339339- v.logger.warn(new ErrorWithCause(`Could not refresh applications. Will remove after ${5 - v.retries} retries if error does not resolve itself.`, {cause: e}));
339339+ v.logger.warn(new Error(`Could not refresh applications. Will remove after ${5 - v.retries} retries if error does not resolve itself.`, {cause: e}));
340340 const validationError = findCauseByReference(e, ContextualValidationError);
341341 if(validationError && validationError.data !== undefined) {
342342 v.logger.warn(JSON.stringify(validationError.data));
···495495 try {
496496 await this.refreshApplications();
497497 } catch (e) {
498498- this.logger.warn(new ErrorWithCause('Could not refresh all applications', {cause: e}));
498498+ this.logger.warn(new Error('Could not refresh all applications', {cause: e}));
499499 }
500500501501 for (const [k, v] of this.devices.entries()) {
···629629 plays.push(playerState);
630630631631 } catch (e) {
632632- application.logger.warn(new ErrorWithCause(`Could not get Player State`, {cause: e}))
632632+ application.logger.warn(new Error(`Could not get Player State`, {cause: e}))
633633 const validationError = findCauseByReference(e, ContextualValidationError);
634634 if (validationError && validationError.data !== undefined) {
635635 application.logger.warn(JSON.stringify(validationError.data));
+1-2
src/backend/sources/DeezerSource.ts
···1414import { DEFAULT_RETRY_MULTIPLIER, FormatPlayObjectOptions, InternalConfig } from "../common/infrastructure/Atomic.js";
1515import EventEmitter from "events";
1616import { PlayObject } from "../../core/Atomic.js";
1717-import {ErrorWithCause} from "pony-cause";
18171918export default class DeezerSource extends AbstractSource {
2019 workingCredsPath;
···102101 this.logger.warn(`No Deezer credentials file found at ${this.workingCredsPath}`);
103102 }
104103 } catch (e) {
105105- throw new ErrorWithCause('Current deezer credentials file exists but could not be parsed', {cause: e});
104104+ throw new Error('Current deezer credentials file exists but could not be parsed', {cause: e});
106105 }
107106 if (this.config.data.accessToken === undefined) {
108107 if (this.config.data.clientId === undefined) {
+3-4
src/backend/sources/LastfmSource.ts
···99import { LastfmSourceConfig } from "../common/infrastructure/config/source/lastfm.js";
1010import dayjs from "dayjs";
1111import { isNodeNetworkException } from "../common/errors/NodeErrors.js";
1212-import {ErrorWithCause} from "pony-cause";
1313-import request, {options} from "superagent";
1212+import request from "superagent";
14131514export default class LastfmSource extends MemorySource {
1615···5756 return true;
5857 } catch (e) {
5958 if(isNodeNetworkException(e)) {
6060- throw new ErrorWithCause('Could not communicate with Last.fm API server', {cause: e});
5959+ throw new Error('Could not communicate with Last.fm API server', {cause: e});
6160 } else if(e.status >= 500) {
6262- throw new ErrorWithCause('Last.fm API server returning an unexpected response', {cause: e})
6161+ throw new Error('Last.fm API server returning an unexpected response', {cause: e})
6362 }
6463 return true;
6564 }
+3-4
src/backend/sources/ListenbrainzSource.ts
···44import { ListenBrainzSourceConfig } from "../common/infrastructure/config/source/listenbrainz.js";
55import { ListenbrainzApiClient } from "../common/vendor/ListenbrainzApiClient.js";
66import MemorySource from "./MemorySource.js";
77-import {ErrorWithCause} from "pony-cause";
87import request from "superagent";
98import {isNodeNetworkException} from "../common/errors/NodeErrors.js";
109import {PlayObject, SOURCE_SOT} from "../../core/Atomic.js";
···4241 return true;
4342 } catch (e) {
4443 if(isNodeNetworkException(e)) {
4545- throw new ErrorWithCause('Could not communicate with Listenbrainz API server', {cause: e});
4444+ throw new Error('Could not communicate with Listenbrainz API server', {cause: e});
4645 } else if(e.status !== 410) {
4747- throw new ErrorWithCause('Listenbrainz API server returning an unexpected response', {cause: e})
4646+ throw new Error('Listenbrainz API server returning an unexpected response', {cause: e})
4847 }
4948 return true;
5049 }
···5857 return await this.api.testAuth();
5958 } catch (e) {
6059 throw e;
6161- //throw new ErrorWithCause('Could not communicate with Listenbrainz API', {cause: e});
6060+ //throw new Error('Could not communicate with Listenbrainz API', {cause: e});
6261 }
6362 }
6463
+5-6
src/backend/sources/MPRISSource.ts
···1313import { RecentlyPlayedOptions } from "./AbstractSource.js";
1414import { removeDuplicates } from "../utils.js";
1515import EventEmitter from "events";
1616-import {ErrorWithCause} from "pony-cause";
1716import { PlayObject } from "../../core/Atomic.js";
1817import {DBusInterface, sessionBus} from 'dbus-ts';
1918import { Interfaces as Notifications } from '@dbus-types/notifications'
···9695 await this.getDBus();
9796 return true;
9897 } catch (e) {
9999- throw new ErrorWithCause('Could not get DBus interface from operating system', {cause: e});
9898+ throw new Error('Could not get DBus interface from operating system', {cause: e});
10099 }
101100 }
102101···144143 });
145144 }
146145 catch (e) {
147147- this.logger.warn(new ErrorWithCause(`Could not parse D-bus info for player ${plainPlayerName}`, {cause: e}));
146146+ this.logger.warn(new Error(`Could not parse D-bus info for player ${plainPlayerName}`, {cause: e}));
148147 }
149148150149 }
···158157 // microseconds
159158 return dayjs.duration({milliseconds: Number(pos / 1000)}).asSeconds();
160159 } catch(e) {
161161- throw new ErrorWithCause('Could not get player Position', {cause: e});
160160+ throw new Error('Could not get player Position', {cause: e});
162161 }
163162 }
164163···167166 const status = await props['PlaybackStatus'];
168167 return status as PlaybackStatus;
169168 } catch (e) {
170170- throw new ErrorWithCause('Could not get player PlaybackStatus', {cause: e})
169169+ throw new Error('Could not get player PlaybackStatus', {cause: e})
171170 }
172171 }
173172···176175 const metadata = await props['Metadata'];
177176 return this.metadataToPlain(metadata);
178177 } catch(e) {
179179- throw new ErrorWithCause('Could not get player Metadata', {cause: e});
178178+ throw new Error('Could not get player Metadata', {cause: e});
180179 }
181180 }
182181
+1-2
src/backend/sources/MopidySource.ts
···1515import { RecentlyPlayedOptions } from "./AbstractSource.js";
1616import { PlayObject } from "../../core/Atomic.js";
1717import { buildTrackString } from "../../core/StringUtils.js";
1818-import {ErrorWithCause} from "pony-cause";
1918import {loggerTest} from "@foxxmd/logging";
20192120export class MopidySource extends MemorySource {
···118117 return true;
119118 } else {
120119 this.client.close();
121121- throw new ErrorWithCause(`Could not connect to Mopidy server`, {cause: (res as Error)});
120120+ throw new Error(`Could not connect to Mopidy server`, {cause: (res as Error)});
122121 }
123122 }
124123
+3-7
src/backend/sources/SpotifySource.ts
···3030import AlbumObjectSimplified = SpotifyApi.AlbumObjectSimplified;
3131import UserDevice = SpotifyApi.UserDevice;
3232import MemorySource from "./MemorySource.js";
3333-import {ErrorWithCause} from "pony-cause";
3433import { PlayObject, SCROBBLE_TS_SOC_END, SCROBBLE_TS_SOC_START, ScrobbleTsSOC } from "../../core/Atomic.js";
3534import { buildTrackString, truncateStringToLength } from "../../core/StringUtils.js";
3635import { isNodeNetworkException } from "../common/errors/NodeErrors.js";
···256255 return true;
257256 } catch (e) {
258257 if(isNodeNetworkException(e)) {
259259- throw new ErrorWithCause('Could not communicate with Spotify API server', {cause: e});
258258+ throw new Error('Could not communicate with Spotify API server', {cause: e});
260259 }
261260 if(e.status >= 500) {
262262- throw new ErrorWithCause('Spotify API server returned an unexpected response', { cause: e});
261261+ throw new Error('Spotify API server returned an unexpected response', { cause: e});
263262 }
264263 return true;
265264 }
···277276 if(isNodeNetworkException(e)) {
278277 this.logger.error('Could not communicate with Spotify API');
279278 }
280280- // this.authFailure = !(e instanceof ErrorWithCause && e.cause !== undefined && isNodeNetworkException(e.cause));
281281- // this.logger.error(new ErrorWithCause('Could not successfully communicate with Spotify API', {cause: e}));
282282- // this.authed = false;
283279 throw e;
284280 }
285281 }
···405401 if(hasApiError(e)) {
406402 throw new UpstreamError('Error occurred while trying to retrieve current playback state', {cause: e});
407403 }
408408- throw new ErrorWithCause('Error occurred while trying to retrieve current playback state', {cause: e});
404404+ throw new Error('Error occurred while trying to retrieve current playback state', {cause: e});
409405 }
410406 }
411407
+1-4
src/backend/sources/SubsonicSource.ts
···1010import EventEmitter from "events";
1111import { PlayObject } from "../../core/Atomic.js";
1212import {isNodeNetworkException} from "../common/errors/NodeErrors.js";
1313-import {ErrorWithCause} from "pony-cause";
1413import {UpstreamError} from "../common/errors/UpstreamError.js";
1514import {getSubsonicResponse, SubsonicResponse, SubsonicResponseCommon} from "../common/vendor/subsonic/interfaces.js";
1616-import {hash} from "@astronautlabs/mdns/dist/hash.js";
1717-import e from "express";
18151916dayjs.extend(isSameOrAfter);
2017···216213 } else if(e.status >= 500) {
217214 throw new UpstreamError('Subsonic server returning an unexpected response', {cause: e})
218215 } else {
219219- throw new ErrorWithCause('Unexpected error occurred', {cause: e})
216216+ throw new Error('Unexpected error occurred', {cause: e})
220217 }
221218 }
222219 }
+4-5
src/backend/utils/MDNSUtils.ts
···22import AvahiBrowser from 'avahi-browse';
33import { MaybeLogger } from "../common/logging.js";
44import { sleep } from "../utils.js";
55-import {ErrorWithCause} from "pony-cause";
65import { MdnsDeviceInfo } from "../common/infrastructure/Atomic.js";
76import {Browser, Service, ServiceType} from "@astronautlabs/mdns";
87import {debounce, DebouncedFunction} from "./debounce.js";
···7877 }
7978 });
8079 browser.on(AvahiBrowser.EVENT_DNSSD_ERROR, (err) => {
8181- const e = new ErrorWithCause('Error occurred while using avahi-browse', {cause: err});
8080+ const e = new Error('Error occurred while using avahi-browse', {cause: err});
8281 if (onDnsError) {
8382 onDnsError(e)
8483 } else {
···9796 }
9897 maybeLogger.debug('Stopped discovery');
9998 } catch (e) {
100100- maybeLogger.warn(new ErrorWithCause('mDNS device discovery with avahi-browse failed', {cause: e}));
9999+ maybeLogger.warn(new Error('mDNS device discovery with avahi-browse failed', {cause: e}));
101100 }
102101}
103102···121120 })
122121 .start();
123122 testBrowser.on('error', (err) => {
124124- maybeLogger.error(new ErrorWithCause('Error occurred during mDNS service discovery', {cause: err}));
123123+ maybeLogger.error(new Error('Error occurred during mDNS service discovery', {cause: err}));
125124 });
126125 maybeLogger.debug('Waiting 1s to gather advertised mdns services...');
127126 await sleep(1000);
···141140 }
142141 })
143142 browser.on('error', (err) => {
144144- const e = new ErrorWithCause('Error occurred during mDNS discovery', {cause: err});
143143+ const e = new Error('Error occurred during mDNS discovery', {cause: err});
145144 if (onDnsError) {
146145 onDnsError(e)
147146 } else {
+1-2
src/backend/common/errors/UpstreamError.ts
···11-import {ErrorWithCause} from "pony-cause";
21import { findCauseByFunc } from "../../utils.js";
32import {Response} from 'superagent';
4355-export class UpstreamError<T = undefined> extends ErrorWithCause<T> {
44+export class UpstreamError<T = undefined> extends Error {
6576 showStopper: boolean = false;
87 response?: Response
+2-3
src/backend/common/vendor/JRiverApiClient.ts
···22import {JRiverData} from "../infrastructure/config/source/jriver.js";
33import request, {Request, Response} from 'superagent';
44import xml2js from 'xml2js';
55-import {ErrorWithCause} from "pony-cause";
65import {AbstractApiOptions, DEFAULT_RETRY_MULTIPLIER} from "../infrastructure/Atomic.js";
7687const parser = new xml2js.Parser({'async': true});
···134133 this.logger.verbose(`Found ${data.ProgramName} ${data.ProgramVersion} (${data.FriendlyName})`);
135134 return true;
136135 } catch (e) {
137137- throw new ErrorWithCause('Could not communicate with JRiver server. Verify your server URL is correct.', {cause: e});
136136+ throw new Error('Could not communicate with JRiver server. Verify your server URL is correct.', {cause: e});
138137 }
139138 }
140139···152151 if(this.config.username === undefined || this.config.password === undefined) {
153152 msg = 'Authentication failed. No username/password was provided in config! Did you mean to do this?';
154153 }
155155- this.logger.error(new ErrorWithCause(msg, {cause: e}));
154154+ this.logger.error(new Error(msg, {cause: e}));
156155 return false;
157156 }
158157 }
+1-2
src/backend/common/vendor/KodiApiClient.ts
···11import AbstractApiClient from "./AbstractApiClient.js";
22-import {ErrorWithCause} from "pony-cause";
32import { KodiData } from "../infrastructure/config/source/kodi.js";
43import { KodiClient } from 'kodi-api'
54import normalizeUrl from "normalize-url";
···143142 if(this.config.username === undefined || this.config.password === undefined) {
144143 msg = 'Authentication failed. No username/password was provided in config! Did you mean to do this?';
145144 }
146146- this.logger.error(new ErrorWithCause(msg, {cause: e}));
145145+ this.logger.error(new Error(msg, {cause: e}));
147146 return false;
148147 }
149148 }
+1-2
src/backend/common/vendor/LastfmApiClient.ts
···1313import { PlayObject } from "../../../core/Atomic.js";
1414import {getNodeNetworkException, isNodeNetworkException} from "../errors/NodeErrors.js";
1515import {nonEmptyStringOrDefault, splitByFirstFound} from "../../../core/StringUtils.js";
1616-import {ErrorWithCause} from "pony-cause";
1716import {getScrobbleTsSOCDate} from "../../utils/TimeUtils.js";
1817import {UpstreamError} from "../errors/UpstreamError.js";
1918···168167 }
169168 return true;
170169 } catch (e) {
171171- throw new ErrorWithCause('Current lastfm credentials file exists but could not be parsed', {cause: e});
170170+ throw new Error('Current lastfm credentials file exists but could not be parsed', {cause: e});
172171 }
173172 }
174173