(
originalName: string,
nameExists: (name: string) => Promise<boolean>,
options?: { hasExtension?: boolean }
)
| 9 | * 3. `name_restored_{6-char hex}` — retries random suffixes until one is free |
| 10 | */ |
| 11 | export async function generateRestoreName( |
| 12 | originalName: string, |
| 13 | nameExists: (name: string) => Promise<boolean>, |
| 14 | options?: { hasExtension?: boolean } |
| 15 | ): Promise<string> { |
| 16 | if (!(await nameExists(originalName))) { |
| 17 | return originalName |
| 18 | } |
| 19 | |
| 20 | const restoredName = addSuffix(originalName, '_restored', options?.hasExtension) |
| 21 | if (!(await nameExists(restoredName))) { |
| 22 | return restoredName |
| 23 | } |
| 24 | |
| 25 | for (let i = 0; i < HASH_ATTEMPTS; i++) { |
| 26 | const hash = randomBytes(3).toString('hex') |
| 27 | const candidate = addSuffix(originalName, `_restored_${hash}`, options?.hasExtension) |
| 28 | if (!(await nameExists(candidate))) { |
| 29 | return candidate |
| 30 | } |
| 31 | } |
| 32 | |
| 33 | throw new Error(`Could not generate a unique restore name for "${originalName}"`) |
| 34 | } |
| 35 | |
| 36 | function addSuffix(name: string, suffix: string, hasExtension?: boolean): string { |
| 37 | if (hasExtension) { |
no test coverage detected