-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
148 lines (120 loc) · 4.54 KB
/
index.js
File metadata and controls
148 lines (120 loc) · 4.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#!/usr/bin/env node
import fs from "fs";
import path from "path";
import axios from "axios";
import { Command } from "commander";
import { Parser } from "json2csv";
import { envConfig } from "./config.js";
function ensureDir(dirPath) {
if (!fs.existsSync(dirPath)) fs.mkdirSync(dirPath, { recursive: true });
}
function nowStamp() {
const d = new Date();
const pad = (n) => String(n).padStart(2, "0");
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}_${pad(d.getHours())}-${pad(d.getMinutes())}-${pad(d.getSeconds())}`;
}
function toArray(data) {
if (Array.isArray(data)) return data;
if (data && typeof data === "object") return [data];
return [{ value: data }];
}
function safeWrite(filePath, content) {
fs.writeFileSync(filePath, content);
}
async function fetchWithRetry({ url, headers, timeoutMs, retries, retryDelayMs }) {
let lastErr = null;
for (let attempt = 1; attempt <= retries + 1; attempt++) {
try {
const res = await axios.get(url, { headers, timeout: timeoutMs });
return res;
} catch (err) {
lastErr = err;
const status = err?.response?.status;
// On retry surtout sur erreurs réseau/timeout/5xx
const shouldRetry =
!status || (status >= 500 && status <= 599) || err.code === "ECONNABORTED";
if (!shouldRetry || attempt === retries + 1) break;
await new Promise((r) => setTimeout(r, retryDelayMs));
}
}
throw lastErr;
}
const program = new Command();
program
.name("gc-api")
.description("Fetch data from an API and export to JSON and/or CSV (GrowthCode).")
.option("-u, --url <string>", "API URL (overrides API_URL in .env)")
.option("-k, --key <string>", "API key/token (Bearer). Overrides API_KEY in .env")
.option(
"-f, --format <string>",
"Export format: json | csv | both",
"both"
)
.option("-o, --out <string>", "Output directory", "outputs")
.option("-n, --name <string>", "Base filename (without extension)", "export")
.option("-t, --timeout <number>", "Timeout in ms", String(envConfig.timeoutMs))
.option("-r, --retries <number>", "Retry count on network/5xx", "2")
.option("--retry-delay <number>", "Retry delay in ms", "600")
.option("--no-timestamp", "Disable timestamp suffix in filenames")
.parse(process.argv);
const opts = program.opts();
(async () => {
try {
const url = opts.url || envConfig.apiUrl;
if (!url) {
throw new Error(
"API URL manquante. Utilise --url <...> ou configure API_URL dans le fichier .env"
);
}
const token = opts.key ?? envConfig.apiKey;
const headers = {};
if (token) headers.Authorization = `Bearer ${token}`;
const timeoutMs = Number(opts.timeout);
const retries = Number(opts.retries);
const retryDelayMs = Number(opts.retryDelay);
const outDir = path.resolve(process.cwd(), opts.out);
ensureDir(outDir);
const suffix = opts.timestamp === false ? "" : `_${nowStamp()}`;
const baseName = `${opts.name}${suffix}`;
console.log("—");
console.log("🚀 GrowthCode API Automation");
console.log(`• URL: ${url}`);
console.log(`• Format: ${opts.format}`);
console.log(`• Output: ${outDir}`);
console.log(`• Retries: ${retries}`);
console.log("—");
const res = await fetchWithRetry({ url, headers, timeoutMs, retries, retryDelayMs });
const data = res.data;
const format = String(opts.format).toLowerCase();
const wantJson = format === "json" || format === "both";
const wantCsv = format === "csv" || format === "both";
if (!wantJson && !wantCsv) {
throw new Error("Format invalide. Utilise: json | csv | both");
}
if (wantJson) {
const jsonPath = path.join(outDir, `${baseName}.json`);
safeWrite(jsonPath, JSON.stringify(data, null, 2));
console.log(`✅ JSON export: ${jsonPath}`);
}
if (wantCsv) {
const rows = toArray(data);
const parser = new Parser();
const csv = parser.parse(rows);
const csvPath = path.join(outDir, `${baseName}.csv`);
safeWrite(csvPath, csv);
console.log(`✅ CSV export: ${csvPath}`);
}
console.log("🎉 Terminé.");
} catch (err) {
const status = err?.response?.status;
const details = err?.response?.data;
console.error("❌ Erreur :");
if (status) console.error(`• HTTP ${status}`);
console.error(`• ${err.message || String(err)}`);
if (details) {
const snippet = JSON.stringify(details).slice(0, 300);
console.error(`• Détails: ${snippet}${snippet.length >= 300 ? "…" : ""}`);
}
process.exit(1);
}
})();