@iksdev/shard-cli 0.1.46 → 0.1.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/shard.js +199 -176
- package/package.json +1 -1
package/bin/shard.js
CHANGED
|
@@ -106,7 +106,7 @@ Options avancees:
|
|
|
106
106
|
whoami [--server <url>]
|
|
107
107
|
account [--server <url>]
|
|
108
108
|
sync <dossier> [--server <url>] [--dry-run] [--force] [--once] [--interval-ms <n>]
|
|
109
|
-
share <fichier> [--server <url>] [--limits <n>] [--temps <jours>]
|
|
109
|
+
share <fichier> [--server <url>] [--limits <n>] [--temps <jours>]
|
|
110
110
|
|
|
111
111
|
Exemples:
|
|
112
112
|
shard login
|
|
@@ -114,7 +114,6 @@ Exemples:
|
|
|
114
114
|
shard sync ./MonDossier
|
|
115
115
|
shard sync ./MonDossier --once
|
|
116
116
|
shard share ./MonFichier.mp4
|
|
117
|
-
shard share ./MonFichier.mp4 --upload
|
|
118
117
|
|
|
119
118
|
Serveur par defaut: https://shard-0ow4.onrender.com
|
|
120
119
|
`);
|
|
@@ -473,14 +472,6 @@ async function uploadOneFile(server, token, file) {
|
|
|
473
472
|
});
|
|
474
473
|
}
|
|
475
474
|
|
|
476
|
-
async function findRemoteFileByNameAndSize(server, token, fileName, fileSize) {
|
|
477
|
-
const data = await httpJson(`${server}/api/files?limit=100&offset=0&sort=created_at&order=desc&search=${encodeURIComponent(fileName)}`, {
|
|
478
|
-
method: 'GET',
|
|
479
|
-
headers: { Authorization: `Bearer ${token}` }
|
|
480
|
-
});
|
|
481
|
-
const rows = Array.isArray(data.files) ? data.files : [];
|
|
482
|
-
return rows.find((row) => row.original_name === fileName && Number(row.file_size || 0) === Number(fileSize || 0)) || null;
|
|
483
|
-
}
|
|
484
475
|
|
|
485
476
|
function parseOptionalPositiveInt(raw, flagName) {
|
|
486
477
|
if (raw === undefined || raw === null) return undefined;
|
|
@@ -520,7 +511,7 @@ async function shareFile(positionals, flags) {
|
|
|
520
511
|
target = await askText('Fichier a partager');
|
|
521
512
|
}
|
|
522
513
|
if (!target) {
|
|
523
|
-
throw new Error('Usage: shard share <file> [--server <url>] [--limits <n>] [--temps <jours>]
|
|
514
|
+
throw new Error('Usage: shard share <file> [--server <url>] [--limits <n>] [--temps <jours>]');
|
|
524
515
|
}
|
|
525
516
|
|
|
526
517
|
const absPath = path.resolve(process.cwd(), target);
|
|
@@ -534,7 +525,7 @@ async function shareFile(positionals, flags) {
|
|
|
534
525
|
|
|
535
526
|
const limits = parseOptionalPositiveInt(flags.limits, '--limits');
|
|
536
527
|
const temps = parseOptionalPositiveInt(flags.temps, '--temps');
|
|
537
|
-
const localMode =
|
|
528
|
+
const localMode = true; // transfert direct uniquement — upload serveur désactivé
|
|
538
529
|
|
|
539
530
|
const config = await readConfig();
|
|
540
531
|
const server = getServer(flags, config);
|
|
@@ -743,43 +734,6 @@ async function shareFile(positionals, flags) {
|
|
|
743
734
|
throw error;
|
|
744
735
|
}
|
|
745
736
|
}
|
|
746
|
-
|
|
747
|
-
let remote = await findRemoteFileByNameAndSize(server, token, fileName, st.size);
|
|
748
|
-
let fileId = remote?.id || null;
|
|
749
|
-
|
|
750
|
-
if (!fileId) {
|
|
751
|
-
console.log(`Upload necessaire: ${fileName} (${formatBytes(st.size)})`);
|
|
752
|
-
const uploaded = await uploadOneFile(server, token, {
|
|
753
|
-
absPath,
|
|
754
|
-
relPath: fileName,
|
|
755
|
-
size: st.size,
|
|
756
|
-
mtimeMs: Math.round(st.mtimeMs)
|
|
757
|
-
});
|
|
758
|
-
fileId = uploaded?.file?.id;
|
|
759
|
-
if (!fileId) {
|
|
760
|
-
throw new Error('Upload reussi mais ID fichier manquant');
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
const payload = { fileId };
|
|
765
|
-
if (limits !== undefined && limits > 0) payload.maxDownloads = limits;
|
|
766
|
-
if (temps !== undefined && temps > 0) payload.expiresInDays = temps;
|
|
767
|
-
|
|
768
|
-
const created = await httpJson(`${server}/api/share/create`, {
|
|
769
|
-
method: 'POST',
|
|
770
|
-
headers: {
|
|
771
|
-
Authorization: `Bearer ${token}`,
|
|
772
|
-
'Content-Type': 'application/json'
|
|
773
|
-
},
|
|
774
|
-
body: JSON.stringify(payload)
|
|
775
|
-
});
|
|
776
|
-
|
|
777
|
-
const share = created?.share || {};
|
|
778
|
-
console.log(`Partage cree pour: ${fileName}`);
|
|
779
|
-
if (share.url) console.log(`URL: ${share.url}`);
|
|
780
|
-
if (share.token) console.log(`Token: ${share.token}`);
|
|
781
|
-
console.log(`Limite downloads: ${limits && limits > 0 ? limits : 'illimitee'}`);
|
|
782
|
-
console.log(`Expiration: ${temps && temps > 0 ? `${temps} jour(s)` : 'aucune'}`);
|
|
783
737
|
}
|
|
784
738
|
|
|
785
739
|
function fileListToMap(files) {
|
|
@@ -1144,114 +1098,164 @@ async function syncFolder(positionals, flags) {
|
|
|
1144
1098
|
}
|
|
1145
1099
|
}
|
|
1146
1100
|
|
|
1101
|
+
function printPlanLimitBox(error) {
|
|
1102
|
+
const data = error?.data || {};
|
|
1103
|
+
const plan = String(data.plan || '').toUpperCase() || 'FREE';
|
|
1104
|
+
const maxFileSize = Number(data.maxFileSize || 0);
|
|
1105
|
+
const fileSize = Number(data.fileSize || 0);
|
|
1106
|
+
const maxLabel = maxFileSize > 0 ? formatBytes(maxFileSize) : '?';
|
|
1107
|
+
const fileLabel = fileSize > 0 ? formatBytes(fileSize) : '?';
|
|
1108
|
+
const lines = [
|
|
1109
|
+
'',
|
|
1110
|
+
`${c(C.bYellow, '╔════════════════════════════════════════════════════╗')}`,
|
|
1111
|
+
`${c(C.bYellow, '║')} ${c(C.bRed, '⚠')} ${c(C.bWhite, `Limite du plan ${plan}`)}`.padEnd(52 + 20) + ` ${c(C.bYellow, '║')}`,
|
|
1112
|
+
`${c(C.bYellow, '╠════════════════════════════════════════════════════╣')}`,
|
|
1113
|
+
`${c(C.bYellow, '║')} ${c(C.gray, 'Taille fichier')} : ${c(C.white, fileLabel)}`.padEnd(52 + 20) + ` ${c(C.bYellow, '║')}`,
|
|
1114
|
+
`${c(C.bYellow, '║')} ${c(C.gray, 'Limite max')} : ${c(C.white, maxLabel + ' / fichier')}`.padEnd(52 + 20) + ` ${c(C.bYellow, '║')}`,
|
|
1115
|
+
`${c(C.bYellow, '║')} ${c(C.bYellow, '║')}`,
|
|
1116
|
+
`${c(C.bYellow, '║')} ${c(C.gray, 'Passe à une offre supérieure pour continuer.')} ${c(C.bYellow, '║')}`,
|
|
1117
|
+
`${c(C.bYellow, '╚════════════════════════════════════════════════════╝')}`,
|
|
1118
|
+
''
|
|
1119
|
+
];
|
|
1120
|
+
console.error(lines.join('\n'));
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1147
1123
|
// ─── Couleurs ANSI ───────────────────────────────────────────────────────────
|
|
1148
1124
|
|
|
1149
1125
|
const C = {
|
|
1150
|
-
reset:
|
|
1151
|
-
bold:
|
|
1152
|
-
dim:
|
|
1153
|
-
cyan:
|
|
1154
|
-
blue:
|
|
1155
|
-
green:
|
|
1156
|
-
yellow:
|
|
1157
|
-
red:
|
|
1158
|
-
white:
|
|
1159
|
-
gray:
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1126
|
+
reset: '\x1b[0m',
|
|
1127
|
+
bold: '\x1b[1m',
|
|
1128
|
+
dim: '\x1b[2m',
|
|
1129
|
+
cyan: '\x1b[36m',
|
|
1130
|
+
blue: '\x1b[34m',
|
|
1131
|
+
green: '\x1b[32m',
|
|
1132
|
+
yellow: '\x1b[33m',
|
|
1133
|
+
red: '\x1b[31m',
|
|
1134
|
+
white: '\x1b[97m',
|
|
1135
|
+
gray: '\x1b[90m',
|
|
1136
|
+
bgCyan: '\x1b[46m',
|
|
1137
|
+
bgGray: '\x1b[100m',
|
|
1138
|
+
black: '\x1b[30m',
|
|
1139
|
+
bCyan: '\x1b[1m\x1b[36m',
|
|
1140
|
+
bWhite: '\x1b[1m\x1b[97m',
|
|
1141
|
+
bGreen: '\x1b[1m\x1b[32m',
|
|
1142
|
+
bRed: '\x1b[1m\x1b[31m',
|
|
1143
|
+
bYellow: '\x1b[1m\x1b[33m',
|
|
1144
|
+
bBlue: '\x1b[1m\x1b[34m',
|
|
1166
1145
|
};
|
|
1167
1146
|
|
|
1168
1147
|
function c(color, text) { return `${color}${text}${C.reset}`; }
|
|
1148
|
+
function strip(s) { return s.replace(/\x1b\[[0-9;]*m/g, ''); }
|
|
1169
1149
|
|
|
1170
1150
|
// ─── Panel interactif ────────────────────────────────────────────────────────
|
|
1171
1151
|
|
|
1172
|
-
const W =
|
|
1152
|
+
const W = 58; // largeur intérieure (sans les bordures)
|
|
1173
1153
|
|
|
1174
1154
|
function clearScreen() {
|
|
1175
1155
|
process.stdout.write('\x1Bc');
|
|
1176
1156
|
}
|
|
1177
1157
|
|
|
1178
|
-
|
|
1179
|
-
|
|
1158
|
+
// Ligne de bordure
|
|
1159
|
+
function hr(left = '├', mid = '─', right = '┤', color = C.gray) {
|
|
1160
|
+
return c(color, `${left}${mid.repeat(W)}${right}`);
|
|
1180
1161
|
}
|
|
1181
1162
|
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
const
|
|
1185
|
-
|
|
1163
|
+
// Ligne avec bordures latérales, contenu centré ou libre
|
|
1164
|
+
function row(content = '', color = C.gray) {
|
|
1165
|
+
const vis = strip(content);
|
|
1166
|
+
const pad = W - vis.length;
|
|
1167
|
+
return `${c(color, '│')}${content}${' '.repeat(Math.max(0, pad))}${c(color, '│')}`;
|
|
1186
1168
|
}
|
|
1187
1169
|
|
|
1188
|
-
function
|
|
1189
|
-
const
|
|
1190
|
-
const
|
|
1191
|
-
const
|
|
1192
|
-
return ' '.repeat(
|
|
1170
|
+
function rowCentered(content, color = C.gray) {
|
|
1171
|
+
const vis = strip(content);
|
|
1172
|
+
const l = Math.floor((W - vis.length) / 2);
|
|
1173
|
+
const r = W - vis.length - l;
|
|
1174
|
+
return row(' '.repeat(l) + content + ' '.repeat(r), color);
|
|
1193
1175
|
}
|
|
1194
1176
|
|
|
1195
1177
|
function printPanel(username, plan, statusMsg) {
|
|
1196
1178
|
const now = new Date();
|
|
1197
1179
|
const timeStr = now.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' });
|
|
1180
|
+
const planLabel = plan ? plan.toUpperCase() : 'FREE';
|
|
1181
|
+
const planColor = planLabel === 'FREE' ? C.gray : C.bYellow;
|
|
1198
1182
|
|
|
1183
|
+
// ── Titre ──────────────────────────────────────────────────────────────────
|
|
1199
1184
|
console.log('');
|
|
1200
|
-
console.log(
|
|
1201
|
-
|
|
1202
|
-
|
|
1185
|
+
console.log(hr('┌', '─', '┐', C.cyan));
|
|
1186
|
+
|
|
1187
|
+
const title = c(C.bCyan, 'S H A R D');
|
|
1188
|
+
console.log(rowCentered(title, C.cyan));
|
|
1203
1189
|
|
|
1204
|
-
|
|
1190
|
+
console.log(hr('├', '─', '┤', C.cyan));
|
|
1191
|
+
|
|
1192
|
+
// ── Infos session ──────────────────────────────────────────────────────────
|
|
1205
1193
|
if (username) {
|
|
1206
|
-
const
|
|
1207
|
-
|
|
1194
|
+
const userPart = ` ${c(C.gray, 'Utilisateur')} ${c(C.bWhite, username)}`;
|
|
1195
|
+
const planPart = ` ${c(C.gray, 'Plan')} ${c(planColor, planLabel)} `;
|
|
1196
|
+
const userVis = strip(userPart);
|
|
1197
|
+
const planVis = strip(planPart);
|
|
1198
|
+
const spacer = W - userVis.length - planVis.length;
|
|
1199
|
+
const infoLine = userPart + ' '.repeat(Math.max(1, spacer)) + planPart;
|
|
1200
|
+
console.log(row(infoLine, C.cyan));
|
|
1201
|
+
console.log(hr('├', '─', '┤', C.cyan));
|
|
1208
1202
|
}
|
|
1209
|
-
console.log(`${c(C.cyan, '╠' + '═'.repeat(W - 2) + '╣')}`);
|
|
1210
1203
|
|
|
1211
|
-
// Menu
|
|
1204
|
+
// ── Menu ───────────────────────────────────────────────────────────────────
|
|
1212
1205
|
const entries = [
|
|
1213
|
-
{ key: '1',
|
|
1214
|
-
{ key: '2',
|
|
1215
|
-
{ key: '3',
|
|
1216
|
-
{ key: '4',
|
|
1217
|
-
{ key: '5',
|
|
1218
|
-
{ key: '6',
|
|
1206
|
+
{ key: '1', tag: 'SHARE', label: 'share', desc: 'Partager un fichier via relay' },
|
|
1207
|
+
{ key: '2', tag: 'SYNC', label: 'sync', desc: 'Synchroniser un dossier local' },
|
|
1208
|
+
{ key: '3', tag: 'ACCOUNT', label: 'account', desc: 'Informations du compte' },
|
|
1209
|
+
{ key: '4', tag: 'WHOAMI', label: 'whoami', desc: 'Utilisateur connecté' },
|
|
1210
|
+
{ key: '5', tag: 'CONFIG', label: 'config', desc: 'Configuration serveur' },
|
|
1211
|
+
{ key: '6', tag: 'LOGOUT', label: 'logout', desc: 'Se déconnecter et quitter' },
|
|
1219
1212
|
];
|
|
1220
1213
|
|
|
1221
|
-
console.log(
|
|
1214
|
+
console.log(row('', C.cyan));
|
|
1222
1215
|
for (const e of entries) {
|
|
1223
|
-
const
|
|
1224
|
-
const
|
|
1225
|
-
const
|
|
1226
|
-
const
|
|
1227
|
-
|
|
1216
|
+
const num = ` ${c(C.bgGray + C.bWhite, ` ${e.key} `)}`;
|
|
1217
|
+
const lbl = ` ${c(C.bWhite, e.label.padEnd(9))}`;
|
|
1218
|
+
const sep = `${c(C.gray, '│')}`;
|
|
1219
|
+
const desc = ` ${c(C.gray, e.desc)}`;
|
|
1220
|
+
const numVis = strip(num);
|
|
1221
|
+
const lblVis = strip(lbl);
|
|
1222
|
+
const descVis = strip(desc);
|
|
1223
|
+
const padRight = W - numVis.length - lblVis.length - 1 - descVis.length;
|
|
1224
|
+
const line = `${num}${lbl}${sep}${desc}${' '.repeat(Math.max(0, padRight - 2))}`;
|
|
1225
|
+
console.log(row(line, C.cyan));
|
|
1228
1226
|
}
|
|
1229
|
-
console.log(
|
|
1227
|
+
console.log(row('', C.cyan));
|
|
1230
1228
|
|
|
1231
|
-
|
|
1229
|
+
// ── Footer ─────────────────────────────────────────────────────────────────
|
|
1230
|
+
console.log(hr('├', '─', '┤', C.gray));
|
|
1232
1231
|
|
|
1233
|
-
// Status / message
|
|
1234
1232
|
if (statusMsg) {
|
|
1235
|
-
console.log(
|
|
1233
|
+
console.log(rowCentered(statusMsg, C.gray));
|
|
1236
1234
|
} else {
|
|
1237
|
-
|
|
1235
|
+
const hint = `${c(C.gray, timeStr + ' ── Entre un numéro ou un nom de commande')}`;
|
|
1236
|
+
console.log(rowCentered(hint, C.gray));
|
|
1238
1237
|
}
|
|
1239
1238
|
|
|
1240
|
-
console.log(
|
|
1239
|
+
console.log(hr('└', '─', '┘', C.gray));
|
|
1241
1240
|
console.log('');
|
|
1242
1241
|
}
|
|
1243
1242
|
|
|
1244
|
-
|
|
1243
|
+
// ── Sous-écrans ───────────────────────────────────────────────────────────────
|
|
1244
|
+
|
|
1245
|
+
function printSubHeader(title) {
|
|
1245
1246
|
console.log('');
|
|
1246
|
-
console.log(
|
|
1247
|
-
|
|
1248
|
-
|
|
1247
|
+
console.log(c(C.cyan, `┌${'─'.repeat(W)}┐`));
|
|
1248
|
+
const vis = strip(title);
|
|
1249
|
+
const l = Math.floor((W - vis.length) / 2);
|
|
1250
|
+
const r = W - vis.length - l;
|
|
1251
|
+
console.log(`${c(C.cyan, '│')}${' '.repeat(l)}${c(C.bWhite, title)}${' '.repeat(r)}${c(C.cyan, '│')}`);
|
|
1252
|
+
console.log(c(C.gray, `└${'─'.repeat(W)}┘`));
|
|
1249
1253
|
console.log('');
|
|
1250
1254
|
}
|
|
1251
1255
|
|
|
1252
|
-
function printSuccess(msg) { console.log(`\n ${c(C.bGreen, '
|
|
1253
|
-
function printError(msg) { console.log(`\n ${c(C.bRed,
|
|
1254
|
-
function printInfo(msg) { console.log(` ${c(C.
|
|
1256
|
+
function printSuccess(msg) { console.log(`\n ${c(C.bGreen, '+ ')} ${c(C.green, msg)}`); }
|
|
1257
|
+
function printError(msg) { console.log(`\n ${c(C.bRed, 'x ')} ${c(C.red, msg)}`); }
|
|
1258
|
+
function printInfo(msg) { console.log(` ${c(C.bCyan, '> ')} ${c(C.white, msg)}`); }
|
|
1255
1259
|
|
|
1256
1260
|
async function askPanelInput(prompt) {
|
|
1257
1261
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -1261,30 +1265,29 @@ async function askPanelInput(prompt) {
|
|
|
1261
1265
|
}
|
|
1262
1266
|
|
|
1263
1267
|
async function pressEnter() {
|
|
1264
|
-
await askPanelInput(`\n ${c(C.gray, 'Appuie sur
|
|
1268
|
+
await askPanelInput(`\n ${c(C.gray, 'Appuie sur Entree pour revenir au menu…')}`);
|
|
1265
1269
|
}
|
|
1266
1270
|
|
|
1271
|
+
// ── Actions ───────────────────────────────────────────────────────────────────
|
|
1272
|
+
|
|
1267
1273
|
async function panelShare() {
|
|
1268
1274
|
clearScreen();
|
|
1269
|
-
printSubHeader('Partager un fichier'
|
|
1275
|
+
printSubHeader('Partager un fichier');
|
|
1270
1276
|
|
|
1271
|
-
const target = await askText(` ${c(C.cyan, '
|
|
1277
|
+
const target = await askText(` ${c(C.cyan, '>')} Chemin du fichier`);
|
|
1272
1278
|
if (!target) return;
|
|
1273
|
-
|
|
1274
|
-
const
|
|
1275
|
-
const temps = await askText(` ${c(C.cyan, '›')} Expiration en jours ${c(C.gray, '(0 = aucune)')}`, '0');
|
|
1276
|
-
const modeRaw = await askText(` ${c(C.cyan, '›')} Mode upload serveur ? ${c(C.gray, '[o/n]')}`, 'n');
|
|
1279
|
+
const limits = await askText(` ${c(C.cyan, '>')} Limite de telechargements ${c(C.gray, '(0 = illimite)')}`, '0');
|
|
1280
|
+
const temps = await askText(` ${c(C.cyan, '>')} Expiration en jours ${c(C.gray, '(0 = aucune)')}`, '0');
|
|
1277
1281
|
|
|
1278
1282
|
const flags = {};
|
|
1279
1283
|
if (parseInt(limits, 10) > 0) flags.limits = limits;
|
|
1280
1284
|
if (parseInt(temps, 10) > 0) flags.temps = temps;
|
|
1281
|
-
if (modeRaw.toLowerCase() === 'o') flags.upload = true;
|
|
1282
1285
|
|
|
1283
1286
|
console.log('');
|
|
1284
|
-
console.log(
|
|
1287
|
+
console.log(c(C.gray, '─'.repeat(W + 2)));
|
|
1285
1288
|
try {
|
|
1286
1289
|
await shareFile([target], flags);
|
|
1287
|
-
printSuccess('Partage
|
|
1290
|
+
printSuccess('Partage cree avec succes.');
|
|
1288
1291
|
} catch (err) {
|
|
1289
1292
|
if (err?.data?.code === 'PLAN_FILE_LIMIT_EXCEEDED') {
|
|
1290
1293
|
printPlanLimitBox(err);
|
|
@@ -1297,14 +1300,13 @@ async function panelShare() {
|
|
|
1297
1300
|
|
|
1298
1301
|
async function panelSync() {
|
|
1299
1302
|
clearScreen();
|
|
1300
|
-
printSubHeader('Synchroniser un dossier'
|
|
1303
|
+
printSubHeader('Synchroniser un dossier');
|
|
1301
1304
|
|
|
1302
|
-
const target
|
|
1305
|
+
const target = await askText(` ${c(C.cyan, '>')} Chemin du dossier`);
|
|
1303
1306
|
if (!target) return;
|
|
1304
|
-
|
|
1305
|
-
const
|
|
1306
|
-
const
|
|
1307
|
-
const forceRaw = await askText(` ${c(C.cyan, '›')} Forcer le re-upload de tout ? ${c(C.gray, '[o/n]')}`, 'n');
|
|
1307
|
+
const onceRaw = await askText(` ${c(C.cyan, '>')} Sync unique (sans surveillance) ? ${c(C.gray, '[o/n]')}`, 'n');
|
|
1308
|
+
const dryRaw = await askText(` ${c(C.cyan, '>')} Simulation dry-run ? ${c(C.gray, '[o/n]')}`, 'n');
|
|
1309
|
+
const forceRaw = await askText(` ${c(C.cyan, '>')} Forcer le re-upload ? ${c(C.gray, '[o/n]')}`, 'n');
|
|
1308
1310
|
|
|
1309
1311
|
const flags = {};
|
|
1310
1312
|
if (onceRaw.toLowerCase() === 'o') flags.once = true;
|
|
@@ -1312,14 +1314,13 @@ async function panelSync() {
|
|
|
1312
1314
|
if (forceRaw.toLowerCase() === 'o') flags.force = true;
|
|
1313
1315
|
|
|
1314
1316
|
console.log('');
|
|
1315
|
-
console.log(
|
|
1317
|
+
console.log(c(C.gray, '─'.repeat(W + 2)));
|
|
1316
1318
|
try {
|
|
1317
1319
|
await syncFolder([target], flags);
|
|
1318
1320
|
if (flags.once || flags['dry-run']) {
|
|
1319
|
-
printSuccess('Synchronisation
|
|
1321
|
+
printSuccess('Synchronisation terminee.');
|
|
1320
1322
|
await pressEnter();
|
|
1321
1323
|
}
|
|
1322
|
-
// mode watch : syncFolder bloque, on revient au menu quand il se termine
|
|
1323
1324
|
} catch (err) {
|
|
1324
1325
|
printError(err.message);
|
|
1325
1326
|
await pressEnter();
|
|
@@ -1328,9 +1329,24 @@ async function panelSync() {
|
|
|
1328
1329
|
|
|
1329
1330
|
async function panelAccount() {
|
|
1330
1331
|
clearScreen();
|
|
1331
|
-
printSubHeader('Informations du compte'
|
|
1332
|
+
printSubHeader('Informations du compte');
|
|
1332
1333
|
try {
|
|
1333
|
-
await
|
|
1334
|
+
const config = await readConfig();
|
|
1335
|
+
const server = getServer({}, config);
|
|
1336
|
+
const token = getToken(config);
|
|
1337
|
+
if (!token) throw new Error('Non connecte.');
|
|
1338
|
+
const data = await httpJson(`${server}/api/auth/profile`, {
|
|
1339
|
+
method: 'GET',
|
|
1340
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
1341
|
+
});
|
|
1342
|
+
const u = data.user || {};
|
|
1343
|
+
const planRaw = String(u.billing_plan || 'free').toUpperCase();
|
|
1344
|
+
const planCol = planRaw === 'FREE' ? C.gray : C.bYellow;
|
|
1345
|
+
console.log('');
|
|
1346
|
+
printInfo(`Utilisateur ${c(C.bWhite, u.username || '—')}`);
|
|
1347
|
+
printInfo(`Email ${c(C.white, u.email || '—')}`);
|
|
1348
|
+
printInfo(`Plan ${c(planCol, planRaw)}`);
|
|
1349
|
+
printInfo(`Serveur ${c(C.gray, server)}`);
|
|
1334
1350
|
} catch (err) {
|
|
1335
1351
|
printError(err.message);
|
|
1336
1352
|
}
|
|
@@ -1339,9 +1355,21 @@ async function panelAccount() {
|
|
|
1339
1355
|
|
|
1340
1356
|
async function panelWhoami() {
|
|
1341
1357
|
clearScreen();
|
|
1342
|
-
printSubHeader('Utilisateur
|
|
1358
|
+
printSubHeader('Utilisateur connecte');
|
|
1343
1359
|
try {
|
|
1344
|
-
await
|
|
1360
|
+
const config = await readConfig();
|
|
1361
|
+
const server = getServer({}, config);
|
|
1362
|
+
const token = getToken(config);
|
|
1363
|
+
if (!token) throw new Error('Non connecte.');
|
|
1364
|
+
const data = await httpJson(`${server}/api/auth/verify`, {
|
|
1365
|
+
method: 'POST',
|
|
1366
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
1367
|
+
});
|
|
1368
|
+
const u = data.user || {};
|
|
1369
|
+
console.log('');
|
|
1370
|
+
printInfo(`Utilisateur ${c(C.bWhite, u.username || u.userId || '—')}`);
|
|
1371
|
+
if (u.email) printInfo(`Email ${c(C.white, u.email)}`);
|
|
1372
|
+
printInfo(`Serveur ${c(C.gray, server)}`);
|
|
1345
1373
|
} catch (err) {
|
|
1346
1374
|
printError(err.message);
|
|
1347
1375
|
}
|
|
@@ -1350,38 +1378,42 @@ async function panelWhoami() {
|
|
|
1350
1378
|
|
|
1351
1379
|
async function panelConfig() {
|
|
1352
1380
|
clearScreen();
|
|
1353
|
-
printSubHeader('Configuration'
|
|
1381
|
+
printSubHeader('Configuration');
|
|
1354
1382
|
|
|
1355
|
-
printInfo(`${c(C.
|
|
1356
|
-
printInfo(`${c(C.
|
|
1383
|
+
printInfo(`${c(C.bgGray + C.bWhite, ' a ')} Afficher la configuration actuelle`);
|
|
1384
|
+
printInfo(`${c(C.bgGray + C.bWhite, ' b ')} Changer de serveur`);
|
|
1357
1385
|
console.log('');
|
|
1358
1386
|
|
|
1359
|
-
const choice = await askPanelInput(` ${c(C.cyan, '
|
|
1387
|
+
const choice = await askPanelInput(` ${c(C.cyan, '>')} Choix ${c(C.gray, '[a / b]')} : `);
|
|
1360
1388
|
|
|
1361
1389
|
if (choice.toLowerCase() === 'a') {
|
|
1362
1390
|
console.log('');
|
|
1363
|
-
console.log(
|
|
1391
|
+
console.log(c(C.gray, '─'.repeat(W + 2)));
|
|
1364
1392
|
try {
|
|
1365
|
-
await
|
|
1393
|
+
const config = await readConfig();
|
|
1394
|
+
printInfo(`Serveur ${c(C.white, config.server)}`);
|
|
1395
|
+
printInfo(`Token ${config.token ? c(C.green, 'present') : c(C.red, 'absent')}`);
|
|
1366
1396
|
} catch (err) {
|
|
1367
1397
|
printError(err.message);
|
|
1368
1398
|
}
|
|
1369
1399
|
} else if (choice.toLowerCase() === 'b') {
|
|
1370
|
-
const url = await askText(` ${c(C.cyan, '
|
|
1400
|
+
const url = await askText(` ${c(C.cyan, '>')} Nouvelle URL du serveur`);
|
|
1371
1401
|
if (url) {
|
|
1372
1402
|
try {
|
|
1373
1403
|
await setServer([url]);
|
|
1374
|
-
printSuccess(`Serveur mis
|
|
1404
|
+
printSuccess(`Serveur mis a jour : ${url}`);
|
|
1375
1405
|
} catch (err) {
|
|
1376
1406
|
printError(err.message);
|
|
1377
1407
|
}
|
|
1378
1408
|
}
|
|
1379
1409
|
} else {
|
|
1380
|
-
printError('Choix invalide.');
|
|
1410
|
+
printError('Choix invalide. Entre a ou b.');
|
|
1381
1411
|
}
|
|
1382
1412
|
await pressEnter();
|
|
1383
1413
|
}
|
|
1384
1414
|
|
|
1415
|
+
// ── Boucle principale ─────────────────────────────────────────────────────────
|
|
1416
|
+
|
|
1385
1417
|
async function runPanel(username, plan) {
|
|
1386
1418
|
// Logout automatique à la fermeture du process
|
|
1387
1419
|
process.on('exit', () => {
|
|
@@ -1394,11 +1426,11 @@ async function runPanel(username, plan) {
|
|
|
1394
1426
|
});
|
|
1395
1427
|
|
|
1396
1428
|
const handleStop = async (sig) => {
|
|
1397
|
-
process.stdout.write(`\n\n ${c(C.gray, `Fermeture (${sig})
|
|
1429
|
+
process.stdout.write(`\n\n ${c(C.gray, `Fermeture (${sig})...`)}\n`);
|
|
1398
1430
|
try {
|
|
1399
1431
|
const cfg = await readConfig();
|
|
1400
1432
|
await writeConfig({ ...cfg, token: '' });
|
|
1401
|
-
process.stdout.write(` ${c(C.green, '
|
|
1433
|
+
process.stdout.write(` ${c(C.green, '+')} Session fermee. A bientot !\n\n`);
|
|
1402
1434
|
} catch (_) {}
|
|
1403
1435
|
process.exit(0);
|
|
1404
1436
|
};
|
|
@@ -1412,7 +1444,7 @@ async function runPanel(username, plan) {
|
|
|
1412
1444
|
printPanel(username, plan, statusMsg);
|
|
1413
1445
|
statusMsg = null;
|
|
1414
1446
|
|
|
1415
|
-
const answer = (await askPanelInput(` ${c(C.bCyan, '
|
|
1447
|
+
const answer = (await askPanelInput(` ${c(C.bCyan, '>')} `)).toLowerCase();
|
|
1416
1448
|
|
|
1417
1449
|
if (answer === '1' || answer === 'share') { await panelShare(); }
|
|
1418
1450
|
else if (answer === '2' || answer === 'sync') { await panelSync(); }
|
|
@@ -1424,12 +1456,12 @@ async function runPanel(username, plan) {
|
|
|
1424
1456
|
process.removeListener('SIGINT', handleStop);
|
|
1425
1457
|
process.removeListener('SIGTERM', handleStop);
|
|
1426
1458
|
await logout();
|
|
1427
|
-
console.log(`\n ${c(C.bGreen, '
|
|
1459
|
+
console.log(`\n ${c(C.bGreen, '+')} Deconnecte avec succes. A bientot !\n`);
|
|
1428
1460
|
process.exit(0);
|
|
1429
1461
|
} else if (answer === '') {
|
|
1430
|
-
// reboucle
|
|
1462
|
+
// reboucle
|
|
1431
1463
|
} else {
|
|
1432
|
-
statusMsg = c(C.bRed,
|
|
1464
|
+
statusMsg = c(C.bRed, `x Inconnu : "${answer}" ── choisis 1 a 6`);
|
|
1433
1465
|
}
|
|
1434
1466
|
}
|
|
1435
1467
|
}
|
|
@@ -1469,17 +1501,28 @@ async function main() {
|
|
|
1469
1501
|
const server = getServer(flags, config);
|
|
1470
1502
|
const token = getToken(config);
|
|
1471
1503
|
let username = String(flags.username || '').trim();
|
|
1472
|
-
|
|
1473
|
-
|
|
1504
|
+
let plan = '';
|
|
1505
|
+
// Récupère le username et le plan depuis le serveur si possible
|
|
1506
|
+
if (token) {
|
|
1474
1507
|
try {
|
|
1475
|
-
const data = await httpJson(`${server}/api/auth/
|
|
1476
|
-
method: '
|
|
1508
|
+
const data = await httpJson(`${server}/api/auth/profile`, {
|
|
1509
|
+
method: 'GET',
|
|
1477
1510
|
headers: { Authorization: `Bearer ${token}` }
|
|
1478
1511
|
});
|
|
1479
|
-
|
|
1480
|
-
|
|
1512
|
+
const user = data.user || {};
|
|
1513
|
+
if (!username) username = user.username || user.userId || '';
|
|
1514
|
+
plan = String(user.billing_plan || 'free').toLowerCase();
|
|
1515
|
+
} catch (_) {
|
|
1516
|
+
try {
|
|
1517
|
+
const data = await httpJson(`${server}/api/auth/verify`, {
|
|
1518
|
+
method: 'POST',
|
|
1519
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
1520
|
+
});
|
|
1521
|
+
if (!username) username = data.user?.username || data.user?.userId || '';
|
|
1522
|
+
} catch (_2) {}
|
|
1523
|
+
}
|
|
1481
1524
|
}
|
|
1482
|
-
await runPanel(username);
|
|
1525
|
+
await runPanel(username, plan);
|
|
1483
1526
|
}
|
|
1484
1527
|
return;
|
|
1485
1528
|
}
|
|
@@ -1525,27 +1568,7 @@ async function main() {
|
|
|
1525
1568
|
throw new Error(`Commande inconnue: ${command}`);
|
|
1526
1569
|
}
|
|
1527
1570
|
|
|
1528
|
-
|
|
1529
|
-
const data = error?.data || {};
|
|
1530
|
-
const plan = String(data.plan || '').toUpperCase() || 'FREE';
|
|
1531
|
-
const maxFileSize = Number(data.maxFileSize || 0);
|
|
1532
|
-
const fileSize = Number(data.fileSize || 0);
|
|
1533
|
-
const maxLabel = maxFileSize > 0 ? formatBytes(maxFileSize) : '?';
|
|
1534
|
-
const fileLabel = fileSize > 0 ? formatBytes(fileSize) : '?';
|
|
1535
|
-
const lines = [
|
|
1536
|
-
'',
|
|
1537
|
-
'╔════════════════════════════════════════════════════╗',
|
|
1538
|
-
`║ ⚠ Limite du plan ${plan}`.padEnd(52) + ' ║',
|
|
1539
|
-
'╠════════════════════════════════════════════════════╣',
|
|
1540
|
-
`║ Taille fichier : ${fileLabel}`.padEnd(52) + ' ║',
|
|
1541
|
-
`║ Limite max : ${maxLabel} / fichier`.padEnd(52) + ' ║',
|
|
1542
|
-
'║ ║',
|
|
1543
|
-
'║ Passe a une offre superieure pour continuer. ║',
|
|
1544
|
-
'╚════════════════════════════════════════════════════╝',
|
|
1545
|
-
''
|
|
1546
|
-
];
|
|
1547
|
-
console.error(lines.join('\n'));
|
|
1548
|
-
}
|
|
1571
|
+
|
|
1549
1572
|
|
|
1550
1573
|
main().catch((error) => {
|
|
1551
1574
|
if (error?.data?.code === 'PLAN_FILE_LIMIT_EXCEEDED') {
|