@intlpullhq/cli 0.1.13 → 0.1.15

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.
Files changed (2) hide show
  1. package/dist/index.js +111 -36
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -74,8 +74,19 @@ var icons = {
74
74
  arrow: "\u2192",
75
75
  bullet: "\u2022",
76
76
  check: "\u2714",
77
- cross: "\u2716"
77
+ cross: "\u2716",
78
+ // Brand icon - globe represents internationalization
79
+ brand: "\u{1F310}"
78
80
  };
81
+ var brand = {
82
+ name: "IntlPull",
83
+ icon: "\u{1F310}",
84
+ url: "https://intlpull.com",
85
+ appUrl: "https://app.intlpull.com"
86
+ };
87
+ function terminalLink(text, url) {
88
+ return `\x1B]8;;${url}\x07${text}\x1B]8;;\x07`;
89
+ }
79
90
  var spinners = {
80
91
  dots: {
81
92
  interval: 80,
@@ -1086,6 +1097,10 @@ import { join as join5, dirname as dirname3 } from "path";
1086
1097
  var DEFAULT_TIMEOUT = 3e4;
1087
1098
  var MAX_RETRIES = 3;
1088
1099
  var RETRY_DELAYS = [1e3, 2e3, 4e3];
1100
+ var CONNECTION_HEADERS = {
1101
+ Connection: "keep-alive",
1102
+ "Accept-Encoding": "gzip, deflate, br"
1103
+ };
1089
1104
  function sleep(ms) {
1090
1105
  return new Promise((resolve2) => setTimeout(resolve2, ms));
1091
1106
  }
@@ -1097,6 +1112,10 @@ async function fetchWithRetry(url, options = {}, retries = MAX_RETRIES) {
1097
1112
  try {
1098
1113
  const response = await fetch(url, {
1099
1114
  ...fetchOptions,
1115
+ headers: {
1116
+ ...CONNECTION_HEADERS,
1117
+ ...fetchOptions.headers
1118
+ },
1100
1119
  signal: controller.signal
1101
1120
  });
1102
1121
  clearTimeout(timeoutId);
@@ -1280,12 +1299,43 @@ async function fetchTranslationsByNamespace(projectId, apiUrl, apiKey, language,
1280
1299
  return { language, namespace, translations: {} };
1281
1300
  }
1282
1301
  }
1302
+ var Semaphore = class {
1303
+ constructor(concurrency) {
1304
+ this.concurrency = concurrency;
1305
+ }
1306
+ queue = [];
1307
+ running = 0;
1308
+ async acquire() {
1309
+ if (this.running < this.concurrency) {
1310
+ this.running++;
1311
+ return;
1312
+ }
1313
+ return new Promise((resolve2) => this.queue.push(resolve2));
1314
+ }
1315
+ release() {
1316
+ this.running--;
1317
+ const next = this.queue.shift();
1318
+ if (next) {
1319
+ this.running++;
1320
+ next();
1321
+ }
1322
+ }
1323
+ async run(fn) {
1324
+ await this.acquire();
1325
+ try {
1326
+ return await fn();
1327
+ } finally {
1328
+ this.release();
1329
+ }
1330
+ }
1331
+ };
1283
1332
  async function fetchTranslationsParallel(projectId, apiUrl, apiKey, options) {
1284
1333
  const headers = { Accept: "application/json" };
1285
1334
  if (apiKey) headers["X-API-Key"] = apiKey;
1286
- const projectResponse = await fetchWithRetry(`${apiUrl}/api/v1/projects/${projectId}`, {
1287
- headers
1288
- });
1335
+ const [projectResponse, namespacesResult] = await Promise.all([
1336
+ fetchWithRetry(`${apiUrl}/api/v1/projects/${projectId}`, { headers }),
1337
+ fetchNamespaces(projectId, apiUrl, apiKey)
1338
+ ]);
1289
1339
  if (!projectResponse.ok) {
1290
1340
  if (projectResponse.status === 401) {
1291
1341
  throw new Error("Authentication required. Run `npx @intlpullhq/cli login` first.");
@@ -1298,7 +1348,6 @@ async function fetchTranslationsParallel(projectId, apiUrl, apiKey, options) {
1298
1348
  const projectData = await projectResponse.json();
1299
1349
  const availableLanguages = projectData.languages?.map((l) => l.code) || ["en"];
1300
1350
  const targetLanguages = options?.languages?.length ? options.languages : availableLanguages;
1301
- const namespacesResult = await fetchNamespaces(projectId, apiUrl, apiKey);
1302
1351
  let namespaces = namespacesResult.namespaces;
1303
1352
  if (options?.namespaces?.length) {
1304
1353
  const requestedNamespaces = new Set(options.namespaces);
@@ -1314,7 +1363,7 @@ async function fetchTranslationsParallel(projectId, apiUrl, apiKey, options) {
1314
1363
  }
1315
1364
  }
1316
1365
  const totalTasks = taskParams.length;
1317
- const concurrency = options?.concurrency || 5;
1366
+ const concurrency = options?.concurrency || 10;
1318
1367
  let completed = 0;
1319
1368
  const languageProgress = /* @__PURE__ */ new Map();
1320
1369
  for (const lang of targetLanguages) {
@@ -1347,28 +1396,33 @@ async function fetchTranslationsParallel(projectId, apiUrl, apiKey, options) {
1347
1396
  };
1348
1397
  };
1349
1398
  const results = [];
1350
- for (let i = 0; i < taskParams.length; i += concurrency) {
1351
- const batch = taskParams.slice(i, i + concurrency);
1352
- const batchResults = await Promise.all(
1353
- batch.map(
1354
- ({ language, namespace }) => fetchTranslationsByNamespace(projectId, apiUrl, apiKey, language, namespace, {
1399
+ const semaphore = new Semaphore(concurrency);
1400
+ const fetchPromises = taskParams.map(
1401
+ ({ language, namespace }) => semaphore.run(async () => {
1402
+ const result = await fetchTranslationsByNamespace(
1403
+ projectId,
1404
+ apiUrl,
1405
+ apiKey,
1406
+ language,
1407
+ namespace,
1408
+ {
1355
1409
  branch: options?.branch,
1356
1410
  platform: options?.platform
1357
- })
1358
- )
1359
- );
1360
- for (const result of batchResults) {
1411
+ }
1412
+ );
1361
1413
  const langProg = languageProgress.get(result.language);
1362
1414
  if (langProg) {
1363
1415
  langProg.completed++;
1364
1416
  langProg.keys += Object.keys(result.translations).length;
1365
1417
  }
1366
- }
1367
- results.push(...batchResults);
1368
- completed += batchResults.length;
1369
- options?.onProgress?.(completed, totalTasks);
1370
- options?.onEnhancedProgress?.(buildEnhancedProgress());
1371
- }
1418
+ completed++;
1419
+ options?.onProgress?.(completed, totalTasks);
1420
+ options?.onEnhancedProgress?.(buildEnhancedProgress());
1421
+ return result;
1422
+ })
1423
+ );
1424
+ const allResults = await Promise.all(fetchPromises);
1425
+ results.push(...allResults);
1372
1426
  const bundle = {};
1373
1427
  const namespacedBundle = {};
1374
1428
  for (const result of results) {
@@ -2813,7 +2867,11 @@ function DownloadProgress({
2813
2867
  const hiddenCount = languages.length - visibleLanguages.length;
2814
2868
  return /* @__PURE__ */ jsxs11(Box10, { flexDirection: "column", paddingX: 1, children: [
2815
2869
  /* @__PURE__ */ jsxs11(Box10, { marginBottom: 1, children: [
2816
- /* @__PURE__ */ jsx11(Text11, { bold: true, color: colors.primary, children: "IntlPull" }),
2870
+ /* @__PURE__ */ jsxs11(Text11, { children: [
2871
+ brand.icon,
2872
+ " "
2873
+ ] }),
2874
+ /* @__PURE__ */ jsx11(Text11, { bold: true, color: colors.primary, children: brand.name }),
2817
2875
  /* @__PURE__ */ jsx11(Text11, { color: colors.text, children: " Download" }),
2818
2876
  projectName && /* @__PURE__ */ jsxs11(Fragment2, { children: [
2819
2877
  /* @__PURE__ */ jsx11(Text11, { color: colors.textDim, children: " \u2022 " }),
@@ -2867,7 +2925,11 @@ function DownloadComplete({
2867
2925
  }) {
2868
2926
  return /* @__PURE__ */ jsxs11(Box10, { flexDirection: "column", paddingX: 1, children: [
2869
2927
  /* @__PURE__ */ jsxs11(Box10, { marginBottom: 1, children: [
2870
- /* @__PURE__ */ jsx11(Text11, { bold: true, color: colors.primary, children: "IntlPull" }),
2928
+ /* @__PURE__ */ jsxs11(Text11, { children: [
2929
+ brand.icon,
2930
+ " "
2931
+ ] }),
2932
+ /* @__PURE__ */ jsx11(Text11, { bold: true, color: colors.primary, children: brand.name }),
2871
2933
  /* @__PURE__ */ jsx11(Text11, { color: colors.text, children: " Download" })
2872
2934
  ] }),
2873
2935
  /* @__PURE__ */ jsxs11(Box10, { children: [
@@ -2909,7 +2971,8 @@ function DownloadComplete({
2909
2971
  files.length > 10 && /* @__PURE__ */ jsx11(Box10, { marginTop: 1, children: /* @__PURE__ */ jsxs11(Text11, { color: colors.textDim, children: [
2910
2972
  files.length,
2911
2973
  " files written"
2912
- ] }) })
2974
+ ] }) }),
2975
+ /* @__PURE__ */ jsx11(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text11, { color: colors.textDim, children: terminalLink(`${icons.arrow} Open dashboard`, brand.appUrl) }) })
2913
2976
  ] });
2914
2977
  }
2915
2978
 
@@ -3247,11 +3310,15 @@ ${writeErrors.join("\n")}`);
3247
3310
  return /* @__PURE__ */ jsxs12(Box11, { flexDirection: "column", paddingX: 1, children: [
3248
3311
  (state.status === "loading" || state.status === "detecting") && /* @__PURE__ */ jsxs12(Fragment3, { children: [
3249
3312
  /* @__PURE__ */ jsxs12(Box11, { marginBottom: 1, children: [
3250
- /* @__PURE__ */ jsx12(Text12, { bold: true, color: "cyan", children: "IntlPull" }),
3251
- /* @__PURE__ */ jsx12(Text12, { children: " Download" })
3313
+ /* @__PURE__ */ jsxs12(Text12, { children: [
3314
+ brand.icon,
3315
+ " "
3316
+ ] }),
3317
+ /* @__PURE__ */ jsx12(Text12, { bold: true, color: colors.primary, children: brand.name }),
3318
+ /* @__PURE__ */ jsx12(Text12, { color: colors.text, children: " Download" })
3252
3319
  ] }),
3253
3320
  /* @__PURE__ */ jsxs12(Box11, { children: [
3254
- /* @__PURE__ */ jsx12(Text12, { color: "cyan", children: /* @__PURE__ */ jsx12(Spinner4, { type: "dots" }) }),
3321
+ /* @__PURE__ */ jsx12(Text12, { color: colors.primary, children: /* @__PURE__ */ jsx12(Spinner4, { type: "dots" }) }),
3255
3322
  /* @__PURE__ */ jsxs12(Text12, { children: [
3256
3323
  " ",
3257
3324
  state.message
@@ -3273,11 +3340,15 @@ ${writeErrors.join("\n")}`);
3273
3340
  ),
3274
3341
  state.status === "downloading" && !showEnhancedProgress && /* @__PURE__ */ jsxs12(Fragment3, { children: [
3275
3342
  /* @__PURE__ */ jsxs12(Box11, { marginBottom: 1, children: [
3276
- /* @__PURE__ */ jsx12(Text12, { bold: true, color: "cyan", children: "IntlPull" }),
3277
- /* @__PURE__ */ jsx12(Text12, { children: " Download" })
3343
+ /* @__PURE__ */ jsxs12(Text12, { children: [
3344
+ brand.icon,
3345
+ " "
3346
+ ] }),
3347
+ /* @__PURE__ */ jsx12(Text12, { bold: true, color: colors.primary, children: brand.name }),
3348
+ /* @__PURE__ */ jsx12(Text12, { color: colors.text, children: " Download" })
3278
3349
  ] }),
3279
3350
  /* @__PURE__ */ jsxs12(Box11, { children: [
3280
- /* @__PURE__ */ jsx12(Text12, { color: "cyan", children: /* @__PURE__ */ jsx12(Spinner4, { type: "dots" }) }),
3351
+ /* @__PURE__ */ jsx12(Text12, { color: colors.primary, children: /* @__PURE__ */ jsx12(Spinner4, { type: "dots" }) }),
3281
3352
  /* @__PURE__ */ jsxs12(Text12, { children: [
3282
3353
  " ",
3283
3354
  state.message
@@ -3297,18 +3368,22 @@ ${writeErrors.join("\n")}`);
3297
3368
  ),
3298
3369
  state.status === "error" && /* @__PURE__ */ jsxs12(Box11, { flexDirection: "column", children: [
3299
3370
  /* @__PURE__ */ jsxs12(Box11, { marginBottom: 1, children: [
3300
- /* @__PURE__ */ jsx12(Text12, { bold: true, color: "cyan", children: "IntlPull" }),
3301
- /* @__PURE__ */ jsx12(Text12, { children: " Download" })
3371
+ /* @__PURE__ */ jsxs12(Text12, { children: [
3372
+ brand.icon,
3373
+ " "
3374
+ ] }),
3375
+ /* @__PURE__ */ jsx12(Text12, { bold: true, color: colors.primary, children: brand.name }),
3376
+ /* @__PURE__ */ jsx12(Text12, { color: colors.text, children: " Download" })
3302
3377
  ] }),
3303
- /* @__PURE__ */ jsxs12(Text12, { color: "red", children: [
3378
+ /* @__PURE__ */ jsxs12(Text12, { color: colors.error, children: [
3304
3379
  "\u2715 ",
3305
3380
  state.message
3306
3381
  ] }),
3307
3382
  /* @__PURE__ */ jsxs12(Box11, { flexDirection: "column", marginTop: 1, children: [
3308
3383
  /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "Tips:" }),
3309
- /* @__PURE__ */ jsx12(Text12, { color: "gray", children: " - Run `npx @intlpullhq/cli login` to authenticate" }),
3310
- /* @__PURE__ */ jsx12(Text12, { color: "gray", children: " - Use `npx @intlpullhq/cli download --project <id>` to specify project" }),
3311
- /* @__PURE__ */ jsx12(Text12, { color: "gray", children: " - Use a project-scoped API key for automatic project selection" })
3384
+ /* @__PURE__ */ jsx12(Text12, { color: colors.textDim, children: " - Run `npx @intlpullhq/cli login` to authenticate" }),
3385
+ /* @__PURE__ */ jsx12(Text12, { color: colors.textDim, children: " - Use `npx @intlpullhq/cli download --project <id>` to specify project" }),
3386
+ /* @__PURE__ */ jsx12(Text12, { color: colors.textDim, children: " - Use a project-scoped API key for automatic project selection" })
3312
3387
  ] })
3313
3388
  ] })
3314
3389
  ] });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intlpullhq/cli",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "The official CLI for IntlPull - intelligent i18n for modern apps. Manage translations, sync with cloud, and automate localization workflows.",
5
5
  "type": "module",
6
6
  "bin": {