Skip to content

Commit 98a499c

Browse files
committed
fix unhandled promises
1 parent ebacb40 commit 98a499c

9 files changed

Lines changed: 54 additions & 17 deletions

File tree

.eslintrc.js

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
module.exports = {
2+
root: true,
23
env: {
34
browser: true,
45
commonjs: true,
@@ -27,5 +28,29 @@ module.exports = {
2728
'build/',
2829
'coverage/',
2930
'*.min.js'
31+
],
32+
// Type-aware rules to catch a forgotten `await`. They need TypeScript type info, so
33+
// they run via @typescript-eslint with parserOptions.project, scoped to the source
34+
// files in tsconfig.eslint.json. Test files and other excluded paths keep the plain
35+
// parser so linting never errors on a file outside the TS program.
36+
overrides: [
37+
{
38+
files: ['**/*.js'],
39+
excludedFiles: ['**/*.test.js', 'tests/**', 'static/**', 'coverage/**'],
40+
parser: '@typescript-eslint/parser',
41+
parserOptions: {
42+
ecmaVersion: 2022,
43+
sourceType: 'module',
44+
project: './tsconfig.eslint.json'
45+
},
46+
plugins: ['@typescript-eslint'],
47+
rules: {
48+
// A promise-returning call left unhandled is almost always a forgotten await.
49+
'@typescript-eslint/no-floating-promises': 'error',
50+
// A promise used where a sync value is expected (e.g. `if (asyncThing())`).
51+
// Warn, not error: there are intentional fire-and-forget callbacks.
52+
'@typescript-eslint/no-misused-promises': 'warn'
53+
}
54+
}
3055
]
31-
};
56+
};

npmprojector/watcher.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ class PackageWatcher {
313313
*/
314314
stop() {
315315
if (this.watcher) {
316-
this.watcher.close();
316+
this.watcher.close().catch((err) => this.log.error('Error closing watcher: ' + err.message));
317317
this.watcher = null;
318318
}
319319
if (this.debounceTimer) {

packages/packages.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1712,7 +1712,7 @@ class PackagesModule {
17121712
// Update download counts after successful response
17131713
// Do this asynchronously to not delay the response
17141714
setImmediate(() => {
1715-
this.incrementDownloadCounts(packageData.PackageVersionKey, id);
1715+
void this.incrementDownloadCounts(packageData.PackageVersionKey, id); // fire-and-forget; errors handled internally
17161716
});
17171717

17181718
} catch (error) {

publisher/publisher.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2665,14 +2665,14 @@ class PublisherModule {
26652665
return colors[status] || 'secondary';
26662666
}
26672667

2668-
async logUserAction(userId, action, targetId, ipAddress) {
2669-
return new Promise((resolve) => {
2670-
this.db.run(
2671-
'INSERT INTO user_actions (user_id, action, target_id, ip_address) VALUES (?, ?, ?, ?)',
2672-
[userId, action, targetId, ipAddress],
2673-
() => resolve() // Don't fail if logging fails
2674-
);
2675-
});
2668+
// Fire-and-forget audit logging: callers don't await this, and it must never fail a
2669+
// request, so it returns void and swallows any DB error in the callback.
2670+
logUserAction(userId, action, targetId, ipAddress) {
2671+
this.db.run(
2672+
'INSERT INTO user_actions (user_id, action, target_id, ip_address) VALUES (?, ?, ?, ?)',
2673+
[userId, action, targetId, ipAddress],
2674+
() => {} // don't fail (or block) the request if audit logging fails
2675+
);
26762676
}
26772677

26782678
getStatus() {

registry/registry.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,13 @@ class RegistryModule {
116116

117117
// Run initial crawl after a short delay
118118
setTimeout(() => {
119-
this.performCrawl();
119+
this.performCrawl().catch((err) => this.logger.error('Registry crawl failed: ' + err.message));
120120
}, 5000);
121121

122122
// Set up periodic crawling
123123
this.stats.addTask("TxRegistry", `${intervalMinutes} min`);
124124
this.crawlInterval = setInterval(() => {
125-
this.performCrawl();
125+
this.performCrawl().catch((err) => this.logger.error('Registry crawl failed: ' + err.message));
126126
}, intervalMs);
127127

128128
this.logger.info(`Started periodic crawl every ${intervalMinutes} minutes`);

server.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -860,4 +860,7 @@ async function serveFhirsmithHome(req, res) {
860860
}
861861

862862
// Start the server
863-
startServer();
863+
startServer().catch((err) => {
864+
serverLog.error('Fatal error during startup:', err);
865+
process.exit(1);
866+
});

token/token.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ class TokenModule {
528528
}
529529

530530
if (userId) {
531-
this.logSecurityEvent(userId, 'logout', req.ip, req.get('User-Agent'), {});
531+
void this.logSecurityEvent(userId, 'logout', req.ip, req.get('User-Agent'), {}); // fire-and-forget audit; errors handled internally
532532
}
533533

534534
res.redirect('/token/login');

tsconfig.eslint.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"compilerOptions": {
3+
"allowJs": true, "checkJs": false, "noEmit": true,
4+
"moduleResolution": "node", "target": "es2022", "module": "commonjs",
5+
"strict": false, "skipLibCheck": true
6+
},
7+
"include": ["**/*.js"],
8+
"exclude": ["node_modules", "static", "**/*.test.js", "tests", "coverage"]
9+
}

xig/xig.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3156,7 +3156,7 @@ async function initializeXigModule(stats, xigConfig) {
31563156
if (!fs.existsSync(XIG_DB_PATH)) {
31573157
xigLog.info('No existing XIG database found, triggering initial download');
31583158
setTimeout(() => {
3159-
updateXigDatabase();
3159+
updateXigDatabase().catch((err) => xigLog.error('XIG database update failed: ' + err.message));
31603160
}, 5000);
31613161
}
31623162

@@ -3167,7 +3167,7 @@ async function initializeXigModule(stats, xigConfig) {
31673167
// Note: This assumes we're called only when XIG is enabled
31683168
if (xigConfig?.autoUpdate !== false) {
31693169
cron.schedule('0 2 * * *', () => {
3170-
updateXigDatabase();
3170+
updateXigDatabase().catch((err) => xigLog.error('XIG database update failed: ' + err.message));
31713171
});
31723172
}
31733173

0 commit comments

Comments
 (0)