* Acquire the cross-process lock around the refresh critical section. * Returns a `release` closure; when locking is disabled returns a no-op. * If locking is configured but cannot be acquired, fail closed rather than * refreshing with no lock and racing refresh_token rotation.
()
| 193 | * refreshing with no lock and racing refresh_token rotation. |
| 194 | */ |
| 195 | private async acquireRefreshLock(): Promise<() => Promise<void>> { |
| 196 | const target = this.resolveLockTarget(); |
| 197 | if (target === undefined) return async () => {}; |
| 198 | |
| 199 | // proper-lockfile requires the target path to exist. We create |
| 200 | // an empty sentinel file; the real lock indicator is the sibling |
| 201 | // `{target}.lock` directory proper-lockfile creates and cleans |
| 202 | // up on release (→ test oracle `{configDir}/oauth/{name}.lock` |
| 203 | // must be absent after a graceful exit). |
| 204 | try { |
| 205 | await mkdir(dirname(target), { recursive: true }); |
| 206 | await writeFile(target, '', { flag: 'a' }); |
| 207 | } catch (error) { |
| 208 | throw new OAuthError( |
| 209 | `Unable to prepare OAuth refresh lock for "${this.config.name}": ${ |
| 210 | error instanceof Error ? error.message : String(error) |
| 211 | }`, |
| 212 | ); |
| 213 | } |
| 214 | |
| 215 | try { |
| 216 | const release = await lockfile.lock(target, { |
| 217 | retries: { retries: 120, factor: 1, minTimeout: 500, maxTimeout: 1_000 }, |
| 218 | stale: 5_000, |
| 219 | realpath: false, |
| 220 | }); |
| 221 | return async () => { |
| 222 | try { |
| 223 | await release(); |
| 224 | } catch { |
| 225 | /* ignore release-after-stale */ |
| 226 | } |
| 227 | }; |
| 228 | } catch (error) { |
| 229 | throw new OAuthError( |
| 230 | `Unable to acquire OAuth refresh lock for "${this.config.name}": ${ |
| 231 | error instanceof Error ? error.message : String(error) |
| 232 | }`, |
| 233 | ); |
| 234 | } |
| 235 | } |
| 236 | |
| 237 | async hasToken(): Promise<boolean> { |
| 238 | return (await this.loadState()).kind === 'valid'; |
no test coverage detected