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

cameri / nostream / 24597013493

18 Apr 2026 04:35AM UTC coverage: 47.213% (-1.6%) from 48.812%
24597013493

push

github

web-flow
feat: add opt-in event retention purge (#359) (#412)

Co-authored-by: Ricardo Cabral <me@ricardocabral.io>

461 of 1107 branches covered (41.64%)

Branch coverage included in aggregate %.

55 of 83 new or added lines in 5 files covered. (66.27%)

71 existing lines in 8 files now uncovered.

1343 of 2714 relevant lines covered (49.48%)

3.0 hits per line

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

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

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

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

10
const debug = createLogger('settings')
1✔
11

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

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

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

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

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

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

43
  public static settingsFileType(path: string): SettingsFileTypes | undefined {
UNCOV
44
    const files: string[] = fs.readdirSync(path)
×
UNCOV
45
    const filteredFile = files.find(fn => fn.startsWith('settings'))
×
UNCOV
46
    if (filteredFile) {
×
47
      const extension = extname(filteredFile).substring(1)
×
48
      if (SettingsFileTypes[extension]) {
×
49
        return SettingsFileTypes[extension]
×
50
      }
51
    }
52

UNCOV
53
    return SettingsFileTypes.yaml
×
54
  }
55

56
  public static loadSettings(path: string, fileType: SettingsFileTypes) {
57
    debug('loading settings from %s', path)
1✔
58

59
    switch (fileType) {
1!
60
      case SettingsFileTypes.json: {
61
        console.warn('settings.json is deprecated, please use a yaml file based on resources/default-settings.yaml')
×
62
        return SettingsStatic.loadAndParseJsonFile(path)
×
63
      }
64
      case SettingsFileTypes.yaml: {
65
        return SettingsStatic.loadAndParseYamlFile(path)
1✔
66
      }
67
      default: {
68
        throw new Error('settings file was missing or did not contain .yaml or .json extensions.')
×
69
      }
70
    }
71
  }
72

73
  public static createSettings(): Settings {
74
    if (SettingsStatic._settings) {
4✔
75
      return SettingsStatic._settings
1✔
76
    }
77
    debug('creating settings')
3✔
78

79
    const basePath = SettingsStatic.getSettingsFileBasePath()
3✔
80
    if (!fs.existsSync(basePath)) {
3✔
81
      fs.mkdirSync(basePath)
2✔
82
    }
83
    const defaultsFilePath = SettingsStatic.getDefaultSettingsFilePath()
3✔
84
    const fileType = SettingsStatic.settingsFileType(basePath)
3✔
85
    const settingsFilePath = join(basePath, `settings.${fileType}`)
3✔
86

87
    const defaults = SettingsStatic.loadSettings(defaultsFilePath, SettingsFileTypes.yaml)
3✔
88

89
    try {
3✔
90
      if (fileType) {
3✔
91
        SettingsStatic._settings = mergeDeepRight(
1✔
92
          defaults,
93
          SettingsStatic.loadSettings(settingsFilePath, fileType)
94
        )
95
      } else {
96
        SettingsStatic.saveSettings(basePath, defaults)
2✔
97
        SettingsStatic._settings = mergeDeepRight({}, defaults)
1✔
98
      }
99

100
      if (typeof SettingsStatic._settings === 'undefined') {
2!
101
        throw new Error('Unable to set settings')
×
102
      }
103

104
      return SettingsStatic._settings
2✔
105
    } catch (error) {
106
      debug('error reading config file at %s: %o', settingsFilePath, error)
1✔
107

108
      return defaults
1✔
109
    }
110
  }
111

112
  public static saveSettings(path: string, settings: Settings) {
113
    debug('saving settings to %s: %o', path, settings)
1✔
114
    return fs.writeFileSync(
1✔
115
      join(path, 'settings.yaml'),
116
      yaml.dump(settings),
117
      { encoding: 'utf-8' },
118
    )
119
  }
120

121
  public static watchSettings() {
122
    const basePath = SettingsStatic.getSettingsFileBasePath()
×
123
    const defaultsFilePath = SettingsStatic.getDefaultSettingsFilePath()
×
124
    const fileType = SettingsStatic.settingsFileType(basePath)
×
125
    const settingsFilePath = join(basePath, `settings.${fileType}`)
×
126

127
    const reload = () => {
×
128
      debug('reloading settings')
×
129
      SettingsStatic._settings = undefined
×
130
      SettingsStatic.createSettings()
×
131
    }
132

133
    return [
×
134
      fs.watch(defaultsFilePath, 'utf8', reload),
135
      fs.watch(settingsFilePath, 'utf8', reload),
136
    ]
137
  }
138
}
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