• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

cameri / nostream / 24630512047

19 Apr 2026 01:43PM UTC coverage: 68.518% (+0.2%) from 68.308%
24630512047

Pull #511

github

web-flow
Merge 4a7e41095 into f5093cb11
Pull Request #511: chore: migrate to pino 456

945 of 1497 branches covered (63.13%)

Branch coverage included in aggregate %.

269 of 396 new or added lines in 50 files covered. (67.93%)

1 existing line in 1 file now uncovered.

2472 of 3490 relevant lines covered (70.83%)

18.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

72.15
/src/utils/settings.ts
1
import fs from 'fs'
2✔
2
import yaml from 'js-yaml'
2✔
3

4
import { extname, join } from 'path'
2✔
5
import { mergeDeepRight } from 'ramda'
2✔
6

7
import { createLogger } from '../factories/logger-factory'
2✔
8
import { Settings } from '../@types/settings'
9

10
const logger = createLogger('settings')
2✔
11

12
export enum SettingsFileTypes {
2✔
13
  yaml = 'yaml',
2✔
14
  json = 'json',
2✔
15
}
16

17
export class SettingsStatic {
2✔
18
  static _settings: Settings | undefined
19

20
  public static getSettingsFileBasePath(): string {
21
    return process.env.NOSTR_CONFIG_DIR ?? join(process.cwd(), '.nostr')
4✔
22
  }
23

24
  public static getDefaultSettingsFilePath(): string {
25
    return join(process.cwd(), 'resources', 'default-settings.yaml')
3✔
26
  }
27

28
  public static loadAndParseYamlFile(path: string): Settings {
29
    const defaultSettingsFileContent = fs.readFileSync(path, { encoding: 'utf-8' })
4✔
30
    const defaults = yaml.load(defaultSettingsFileContent) as Settings
3✔
31
    return defaults
3✔
32
  }
33

34
  public static loadAndParseJsonFile(path: string) {
35
    return JSON.parse(fs.readFileSync(path, { encoding: 'utf-8' }))
2✔
36
  }
37

38
  public static settingsFileType(path: string): SettingsFileTypes | undefined {
39
    const files: string[] = fs.readdirSync(path)
1✔
40
    const filteredFile = files.find((fn) => fn.startsWith('settings'))
12✔
41
    if (filteredFile) {
1!
42
      const extension = extname(filteredFile).substring(1)
×
43
      if (SettingsFileTypes[extension]) {
×
44
        return SettingsFileTypes[extension]
×
45
      }
46
    }
47

48
    return SettingsFileTypes.yaml
1✔
49
  }
50

51
  public static loadSettings(path: string, fileType: SettingsFileTypes) {
52
    logger('loading settings from %s', path)
3✔
53

54
    switch (fileType) {
3!
55
      case SettingsFileTypes.json: {
NEW
56
        logger.warn('settings.json is deprecated, please use a yaml file based on resources/default-settings.yaml')
×
57
        return SettingsStatic.loadAndParseJsonFile(path)
×
58
      }
59
      case SettingsFileTypes.yaml: {
60
        return SettingsStatic.loadAndParseYamlFile(path)
3✔
61
      }
62
      default: {
63
        throw new Error('settings file was missing or did not contain .yaml or .json extensions.')
×
64
      }
65
    }
66
  }
67

68
  public static createSettings(): Settings {
69
    if (SettingsStatic._settings) {
704✔
70
      return SettingsStatic._settings
700✔
71
    }
72
    logger('creating settings')
4✔
73

74
    const basePath = SettingsStatic.getSettingsFileBasePath()
4✔
75
    if (!fs.existsSync(basePath)) {
4✔
76
      fs.mkdirSync(basePath)
2✔
77
    }
78
    const defaultsFilePath = SettingsStatic.getDefaultSettingsFilePath()
4✔
79
    const fileType = SettingsStatic.settingsFileType(basePath)
4✔
80
    const settingsFilePath = join(basePath, `settings.${fileType}`)
4✔
81

82
    const defaults = SettingsStatic.loadSettings(defaultsFilePath, SettingsFileTypes.yaml)
4✔
83

84
    try {
4✔
85
      if (fileType) {
4✔
86
        SettingsStatic._settings = mergeDeepRight(defaults, SettingsStatic.loadSettings(settingsFilePath, fileType))
2✔
87
      } else {
88
        SettingsStatic.saveSettings(basePath, defaults)
2✔
89
        SettingsStatic._settings = mergeDeepRight({}, defaults)
1✔
90
      }
91

92
      if (typeof SettingsStatic._settings === 'undefined') {
2!
93
        throw new Error('Unable to set settings')
×
94
      }
95

96
      return SettingsStatic._settings
2✔
97
    } catch (error) {
98
      logger('error reading config file at %s: %o', settingsFilePath, error)
2✔
99

100
      return defaults
2✔
101
    }
102
  }
103

104
  public static saveSettings(path: string, settings: Settings) {
105
    logger('saving settings to %s: %o', path, settings)
1✔
106
    return fs.writeFileSync(join(path, 'settings.yaml'), yaml.dump(settings), { encoding: 'utf-8' })
1✔
107
  }
108

109
  public static watchSettings() {
110
    const basePath = SettingsStatic.getSettingsFileBasePath()
×
111
    const defaultsFilePath = SettingsStatic.getDefaultSettingsFilePath()
×
112
    const fileType = SettingsStatic.settingsFileType(basePath)
×
113
    const settingsFilePath = join(basePath, `settings.${fileType}`)
×
114

115
    const reload = () => {
×
NEW
116
      logger('reloading settings')
×
117
      SettingsStatic._settings = undefined
×
118
      SettingsStatic.createSettings()
×
119
    }
120

121
    return [fs.watch(defaultsFilePath, 'utf8', reload), fs.watch(settingsFilePath, 'utf8', reload)]
×
122
  }
123
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc