MCPcopy Create free account
hub / github.com/tiann/hapi / updateSettings

Function updateSettings

cli/src/persistence.ts:90–153  ·  view source on GitHub ↗
(
  updater: (current: Settings) => Settings | Promise<Settings>
)

Source from the content-addressed store, hash-verified

88 * @returns The updated settings
89 */
90export async function updateSettings(
91 updater: (current: Settings) => Settings | Promise<Settings>
92): Promise<Settings> {
93 // Timing constants
94 const LOCK_RETRY_INTERVAL_MS = 100; // How long to wait between lock attempts
95 const MAX_LOCK_ATTEMPTS = 50; // Maximum number of attempts (5 seconds total)
96 const STALE_LOCK_TIMEOUT_MS = 10000; // Consider lock stale after 10 seconds
97
98 if (!existsSync(configuration.happyHomeDir)) {
99 await mkdir(configuration.happyHomeDir, { recursive: true });
100 }
101
102 const lockFile = configuration.settingsFile + '.lock';
103 const tmpFile = configuration.settingsFile + '.tmp';
104 let fileHandle;
105 let attempts = 0;
106
107 // Acquire exclusive lock with retries
108 while (attempts < MAX_LOCK_ATTEMPTS) {
109 try {
110 // 'wx' = create exclusively, fail if exists (cross-platform compatible)
111 fileHandle = await open(lockFile, 'wx');
112 break;
113 } catch (err: any) {
114 if (err.code === 'EEXIST') {
115 // Lock file exists, wait and retry
116 attempts++;
117 await new Promise(resolve => setTimeout(resolve, LOCK_RETRY_INTERVAL_MS));
118
119 // Check for stale lock
120 try {
121 const stats = await stat(lockFile);
122 if (Date.now() - stats.mtimeMs > STALE_LOCK_TIMEOUT_MS) {
123 await unlink(lockFile).catch(() => { });
124 }
125 } catch { }
126 } else {
127 throw err;
128 }
129 }
130 }
131
132 if (!fileHandle) {
133 throw new Error(`Failed to acquire settings lock after ${MAX_LOCK_ATTEMPTS * LOCK_RETRY_INTERVAL_MS / 1000} seconds`);
134 }
135
136 try {
137 // Read current settings with defaults
138 const current = await readSettings() || { ...defaultSettings };
139
140 // Apply update
141 const updated = await updater(current);
142
143 // Write atomically using rename
144 await writeFile(tmpFile, JSON.stringify(updated, null, 2));
145 await rename(tmpFile, configuration.settingsFile); // Atomic on POSIX
146
147 return updated;

Callers 4

handleAuthCommandFunction · 0.90
initializeTokenFunction · 0.90
clearMachineIdFunction · 0.85

Calls 3

readSettingsFunction · 0.70
closeMethod · 0.65
openFunction · 0.50

Tested by

no test coverage detected