| 192 | // ── HuggingFace Hub Commit ─────────────────────────────────────────── |
| 193 | |
| 194 | async function commitToHF( |
| 195 | token: string, |
| 196 | repo: string, |
| 197 | branch: string, |
| 198 | filePath: string, |
| 199 | content: string, |
| 200 | ): Promise<boolean> { |
| 201 | const url = `${HF_API}/datasets/${repo}/commit/${branch}` |
| 202 | |
| 203 | // HF Hub commit API uses NDJSON (application/x-ndjson) |
| 204 | // Line 1: commit header with summary |
| 205 | // Line 2: file operation with base64-encoded content |
| 206 | const contentBase64 = btoa(content) |
| 207 | const ndjson = [ |
| 208 | JSON.stringify({ key: 'header', value: { summary: `[telemetry] ${filePath}` } }), |
| 209 | JSON.stringify({ key: 'file', value: { content: contentBase64, path: filePath, encoding: 'base64' } }), |
| 210 | ].join('\n') |
| 211 | |
| 212 | try { |
| 213 | const res = await fetch(url, { |
| 214 | method: 'POST', |
| 215 | headers: { |
| 216 | 'Authorization': `Bearer ${token}`, |
| 217 | 'Content-Type': 'application/x-ndjson', |
| 218 | }, |
| 219 | body: ndjson, |
| 220 | }) |
| 221 | |
| 222 | if (!res.ok) { |
| 223 | const err = await res.text().catch(() => '') |
| 224 | if (res.status === 401 || res.status === 403) { |
| 225 | console.error(`[Telemetry] HF AUTH FAILED (${res.status}) — HF_TOKEN is invalid or lacks write access to "${repo}"`) |
| 226 | } else if (res.status === 404) { |
| 227 | console.error(`[Telemetry] HF REPO NOT FOUND (404) — "${repo}" does not exist on HuggingFace`) |
| 228 | } else { |
| 229 | console.error(`[Telemetry] HF commit failed (${res.status}): ${err.slice(0, 300)}`) |
| 230 | } |
| 231 | } |
| 232 | |
| 233 | return res.ok |
| 234 | } catch (err) { |
| 235 | console.error(`[Telemetry] Network error:`, err) |
| 236 | return false |
| 237 | } |
| 238 | } |
| 239 | |
| 240 | // ── Helpers ────────────────────────────────────────────────────────── |
| 241 | |