@intlpullhq/cli 0.1.0
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/LICENSE +21 -0
- package/README.md +765 -0
- package/dist/api-D35M5BOX.js +29 -0
- package/dist/chunk-2T7ERBDS.js +394 -0
- package/dist/chunk-S3EWA4QD.js +995 -0
- package/dist/config-HHJ7OBGT.js +46 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +10737 -0
- package/package.json +86 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ApiClient,
|
|
3
|
+
ApiKeysApi,
|
|
4
|
+
BaseApiClient,
|
|
5
|
+
BillingApi,
|
|
6
|
+
DocumentsApi,
|
|
7
|
+
EmailsApi,
|
|
8
|
+
ImportExportApi,
|
|
9
|
+
PLAN_LIMITS,
|
|
10
|
+
ProjectsApi,
|
|
11
|
+
TranslationsApi,
|
|
12
|
+
WorkflowsApi,
|
|
13
|
+
createApiClient
|
|
14
|
+
} from "./chunk-S3EWA4QD.js";
|
|
15
|
+
import "./chunk-2T7ERBDS.js";
|
|
16
|
+
export {
|
|
17
|
+
ApiClient,
|
|
18
|
+
ApiKeysApi,
|
|
19
|
+
BaseApiClient,
|
|
20
|
+
BillingApi,
|
|
21
|
+
DocumentsApi,
|
|
22
|
+
EmailsApi,
|
|
23
|
+
ImportExportApi,
|
|
24
|
+
PLAN_LIMITS,
|
|
25
|
+
ProjectsApi,
|
|
26
|
+
TranslationsApi,
|
|
27
|
+
WorkflowsApi,
|
|
28
|
+
createApiClient
|
|
29
|
+
};
|
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
// src/lib/config.ts
|
|
9
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync, chmodSync, renameSync } from "fs";
|
|
10
|
+
import { homedir } from "os";
|
|
11
|
+
import { join, dirname } from "path";
|
|
12
|
+
function writeFileAtomic(filePath, content, options) {
|
|
13
|
+
const dir = dirname(filePath);
|
|
14
|
+
if (options?.createDir && !existsSync(dir)) {
|
|
15
|
+
mkdirSync(dir, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
const tempPath = `${filePath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2, 8)}`;
|
|
18
|
+
try {
|
|
19
|
+
writeFileSync(tempPath, content, { mode: options?.mode });
|
|
20
|
+
renameSync(tempPath, filePath);
|
|
21
|
+
if (options?.mode) {
|
|
22
|
+
try {
|
|
23
|
+
chmodSync(filePath, options.mode);
|
|
24
|
+
} catch {
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
} catch (error) {
|
|
28
|
+
try {
|
|
29
|
+
if (existsSync(tempPath)) {
|
|
30
|
+
unlinkSync(tempPath);
|
|
31
|
+
}
|
|
32
|
+
} catch {
|
|
33
|
+
}
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
var CONFIG_DIR = join(homedir(), ".intlpull");
|
|
38
|
+
var CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
39
|
+
var AUTH_FILE = join(CONFIG_DIR, "auth.json");
|
|
40
|
+
var ENV_API_KEY = "INTLPULL_API_KEY";
|
|
41
|
+
var ENV_PROJECT_ID = "INTLPULL_PROJECT_ID";
|
|
42
|
+
var customEnvFile = null;
|
|
43
|
+
function setCustomEnvFile(filePath) {
|
|
44
|
+
customEnvFile = filePath;
|
|
45
|
+
}
|
|
46
|
+
function getCustomEnvFile() {
|
|
47
|
+
return customEnvFile;
|
|
48
|
+
}
|
|
49
|
+
function parseEnvFile(content) {
|
|
50
|
+
const env = {};
|
|
51
|
+
const lines = content.split("\n");
|
|
52
|
+
for (const line of lines) {
|
|
53
|
+
const trimmed = line.trim();
|
|
54
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
55
|
+
const match = trimmed.match(/^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/);
|
|
56
|
+
if (match) {
|
|
57
|
+
const key = match[1];
|
|
58
|
+
let value = match[2].trim();
|
|
59
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
60
|
+
value = value.slice(1, -1);
|
|
61
|
+
}
|
|
62
|
+
if (match[2].trim().startsWith('"')) {
|
|
63
|
+
value = value.replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ").replace(/\\"/g, '"');
|
|
64
|
+
}
|
|
65
|
+
env[key] = value;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return env;
|
|
69
|
+
}
|
|
70
|
+
function loadEnvFiles(projectDir = process.cwd()) {
|
|
71
|
+
const loaded = [];
|
|
72
|
+
const vars = {};
|
|
73
|
+
const envFiles = [
|
|
74
|
+
".env",
|
|
75
|
+
".env.development",
|
|
76
|
+
".env.local"
|
|
77
|
+
];
|
|
78
|
+
if (customEnvFile) {
|
|
79
|
+
envFiles.push(customEnvFile);
|
|
80
|
+
}
|
|
81
|
+
let currentDir = projectDir;
|
|
82
|
+
const root = process.platform === "win32" ? currentDir.split(":")[0] + ":\\" : "/";
|
|
83
|
+
const checkedDirs = [];
|
|
84
|
+
while (currentDir !== root && checkedDirs.length < 10) {
|
|
85
|
+
checkedDirs.push(currentDir);
|
|
86
|
+
const parentDir = dirname(currentDir);
|
|
87
|
+
if (parentDir === currentDir) break;
|
|
88
|
+
currentDir = parentDir;
|
|
89
|
+
}
|
|
90
|
+
for (const dir of checkedDirs.reverse()) {
|
|
91
|
+
for (const envFile of envFiles) {
|
|
92
|
+
const filePath = envFile.startsWith("/") || envFile.match(/^[A-Z]:\\/i) ? envFile : join(dir, envFile);
|
|
93
|
+
if (existsSync(filePath)) {
|
|
94
|
+
try {
|
|
95
|
+
const content = readFileSync(filePath, "utf-8");
|
|
96
|
+
const parsed = parseEnvFile(content);
|
|
97
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
98
|
+
if (process.env[key] === void 0) {
|
|
99
|
+
process.env[key] = value;
|
|
100
|
+
vars[key] = value;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (Object.keys(parsed).length > 0 && !loaded.includes(filePath)) {
|
|
104
|
+
loaded.push(filePath);
|
|
105
|
+
}
|
|
106
|
+
} catch {
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return { loaded, vars };
|
|
112
|
+
}
|
|
113
|
+
function getEnvProjectId() {
|
|
114
|
+
return process.env[ENV_PROJECT_ID] || null;
|
|
115
|
+
}
|
|
116
|
+
function detectFramework(projectDir = process.cwd()) {
|
|
117
|
+
const indicators = [];
|
|
118
|
+
let framework = "unknown";
|
|
119
|
+
let library = "react-i18next";
|
|
120
|
+
let confidence = "low";
|
|
121
|
+
const nextConfigPaths = [
|
|
122
|
+
join(projectDir, "next.config.js"),
|
|
123
|
+
join(projectDir, "next.config.mjs"),
|
|
124
|
+
join(projectDir, "next.config.ts")
|
|
125
|
+
];
|
|
126
|
+
const hasNextConfig = nextConfigPaths.some((p) => existsSync(p));
|
|
127
|
+
const packageJsonPath = join(projectDir, "package.json");
|
|
128
|
+
let packageJson = {};
|
|
129
|
+
if (existsSync(packageJsonPath)) {
|
|
130
|
+
try {
|
|
131
|
+
packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
132
|
+
} catch {
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
136
|
+
if (hasNextConfig || deps["next"]) {
|
|
137
|
+
framework = "next";
|
|
138
|
+
indicators.push(hasNextConfig ? "next.config.* found" : "next in dependencies");
|
|
139
|
+
confidence = "high";
|
|
140
|
+
if (deps["next-intl"]) {
|
|
141
|
+
library = "next-intl";
|
|
142
|
+
indicators.push("next-intl detected");
|
|
143
|
+
} else if (deps["next-i18next"]) {
|
|
144
|
+
library = "next-i18next";
|
|
145
|
+
indicators.push("next-i18next detected");
|
|
146
|
+
} else if (deps["react-i18next"]) {
|
|
147
|
+
library = "react-i18next";
|
|
148
|
+
indicators.push("react-i18next detected");
|
|
149
|
+
}
|
|
150
|
+
} else if (deps["vue"] || existsSync(join(projectDir, "vue.config.js"))) {
|
|
151
|
+
framework = "vue";
|
|
152
|
+
library = deps["vue-i18n"] ? "vue-i18n" : "vue-i18n";
|
|
153
|
+
indicators.push("Vue.js detected");
|
|
154
|
+
confidence = "high";
|
|
155
|
+
} else if (deps["svelte"] || existsSync(join(projectDir, "svelte.config.js"))) {
|
|
156
|
+
framework = "svelte";
|
|
157
|
+
library = "svelte-i18n";
|
|
158
|
+
indicators.push("Svelte detected");
|
|
159
|
+
confidence = "high";
|
|
160
|
+
} else if (deps["astro"] || existsSync(join(projectDir, "astro.config.mjs"))) {
|
|
161
|
+
framework = "astro";
|
|
162
|
+
library = "astro-i18n";
|
|
163
|
+
indicators.push("Astro detected");
|
|
164
|
+
confidence = "high";
|
|
165
|
+
} else if (deps["react"]) {
|
|
166
|
+
framework = "react";
|
|
167
|
+
indicators.push("React detected");
|
|
168
|
+
confidence = "medium";
|
|
169
|
+
if (deps["react-i18next"]) {
|
|
170
|
+
library = "react-i18next";
|
|
171
|
+
indicators.push("react-i18next detected");
|
|
172
|
+
} else if (deps["react-intl"]) {
|
|
173
|
+
library = "react-intl";
|
|
174
|
+
indicators.push("react-intl detected");
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const i18nConfigFiles = [
|
|
178
|
+
"next-i18next.config.js",
|
|
179
|
+
"i18n.config.js",
|
|
180
|
+
"i18n.config.ts",
|
|
181
|
+
"i18n.js",
|
|
182
|
+
"i18n.ts"
|
|
183
|
+
];
|
|
184
|
+
for (const configFile of i18nConfigFiles) {
|
|
185
|
+
if (existsSync(join(projectDir, configFile))) {
|
|
186
|
+
indicators.push(`${configFile} found`);
|
|
187
|
+
if (confidence === "low") confidence = "medium";
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return { framework, library, confidence, indicators };
|
|
191
|
+
}
|
|
192
|
+
function getProjectConfig() {
|
|
193
|
+
const configPath = join(process.cwd(), ".intlpull.json");
|
|
194
|
+
if (!existsSync(configPath)) {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
try {
|
|
198
|
+
const content = readFileSync(configPath, "utf-8");
|
|
199
|
+
return JSON.parse(content);
|
|
200
|
+
} catch {
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
function saveProjectConfig(config) {
|
|
205
|
+
const configPath = join(process.cwd(), ".intlpull.json");
|
|
206
|
+
writeFileAtomic(configPath, JSON.stringify(config, null, 2));
|
|
207
|
+
}
|
|
208
|
+
function getAuthConfig() {
|
|
209
|
+
if (!existsSync(AUTH_FILE)) {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
const content = readFileSync(AUTH_FILE, "utf-8");
|
|
214
|
+
return JSON.parse(content);
|
|
215
|
+
} catch {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
function saveAuthConfig(config) {
|
|
220
|
+
try {
|
|
221
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
222
|
+
mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
|
|
223
|
+
}
|
|
224
|
+
writeFileAtomic(AUTH_FILE, JSON.stringify(config, null, 2), { mode: 384 });
|
|
225
|
+
} catch (err) {
|
|
226
|
+
throw new Error(`Failed to save auth config: ${err instanceof Error ? err.message : "Permission denied or disk full"}`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
function clearAuthConfig() {
|
|
230
|
+
try {
|
|
231
|
+
if (existsSync(AUTH_FILE)) {
|
|
232
|
+
unlinkSync(AUTH_FILE);
|
|
233
|
+
}
|
|
234
|
+
} catch (err) {
|
|
235
|
+
throw new Error(`Failed to clear auth config: ${err instanceof Error ? err.message : "Permission denied"}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
var DEFAULT_API_URL = "https://api.intlpull.com";
|
|
239
|
+
function getGlobalConfig() {
|
|
240
|
+
const defaults = {
|
|
241
|
+
apiUrl: DEFAULT_API_URL,
|
|
242
|
+
defaultFramework: "next"
|
|
243
|
+
};
|
|
244
|
+
if (!existsSync(CONFIG_FILE)) {
|
|
245
|
+
return defaults;
|
|
246
|
+
}
|
|
247
|
+
try {
|
|
248
|
+
const content = readFileSync(CONFIG_FILE, "utf-8");
|
|
249
|
+
const config = JSON.parse(content);
|
|
250
|
+
if (config.apiUrl && config.apiUrl.includes("localhost")) {
|
|
251
|
+
config.apiUrl = DEFAULT_API_URL;
|
|
252
|
+
}
|
|
253
|
+
return { ...defaults, ...config };
|
|
254
|
+
} catch {
|
|
255
|
+
return defaults;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
function getEnvApiKey() {
|
|
259
|
+
return process.env[ENV_API_KEY] || null;
|
|
260
|
+
}
|
|
261
|
+
function getResolvedApiKey() {
|
|
262
|
+
const envKey = getEnvApiKey();
|
|
263
|
+
if (envKey) {
|
|
264
|
+
return { key: envKey, source: "env" };
|
|
265
|
+
}
|
|
266
|
+
const auth = getAuthConfig();
|
|
267
|
+
if (auth?.apiKey) {
|
|
268
|
+
return { key: auth.apiKey, source: "config" };
|
|
269
|
+
}
|
|
270
|
+
if (auth?.token && auth?.expiresAt) {
|
|
271
|
+
const expiryDate = new Date(auth.expiresAt);
|
|
272
|
+
if (!isNaN(expiryDate.getTime()) && expiryDate > /* @__PURE__ */ new Date()) {
|
|
273
|
+
return { key: auth.token, source: "config" };
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
function isAuthenticated() {
|
|
279
|
+
return getResolvedApiKey() !== null;
|
|
280
|
+
}
|
|
281
|
+
function getAuthErrorMessage() {
|
|
282
|
+
return `Not authenticated. To authenticate, you can:
|
|
283
|
+
|
|
284
|
+
1. Add to your .env file:
|
|
285
|
+
${ENV_API_KEY}="your-api-key"
|
|
286
|
+
(Reads from .env, .env.local, or .env.development)
|
|
287
|
+
|
|
288
|
+
2. Set environment variable:
|
|
289
|
+
export ${ENV_API_KEY}="your-api-key"
|
|
290
|
+
(Useful for CI/CD pipelines)
|
|
291
|
+
|
|
292
|
+
3. Run: npx @intlpullhq/cli login
|
|
293
|
+
(Interactive login - saves token to ~/.intlpull/auth.json)
|
|
294
|
+
|
|
295
|
+
4. Use a custom env file:
|
|
296
|
+
npx @intlpullhq/cli --env-file .env.production <command>
|
|
297
|
+
|
|
298
|
+
Get your API key from: Settings \u2192 API Keys in the IntlPull dashboard.`;
|
|
299
|
+
}
|
|
300
|
+
function findProjectRoot(startDir = process.cwd()) {
|
|
301
|
+
let currentDir = startDir;
|
|
302
|
+
const root = process.platform === "win32" ? currentDir.split(":")[0] + ":\\" : "/";
|
|
303
|
+
while (currentDir !== root) {
|
|
304
|
+
const configPath = join(currentDir, ".intlpull.json");
|
|
305
|
+
if (existsSync(configPath)) {
|
|
306
|
+
return currentDir;
|
|
307
|
+
}
|
|
308
|
+
const parentDir = join(currentDir, "..");
|
|
309
|
+
if (parentDir === currentDir) break;
|
|
310
|
+
currentDir = parentDir;
|
|
311
|
+
}
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
function getProjectConfigFromDir(dir) {
|
|
315
|
+
if (dir) {
|
|
316
|
+
const configPath2 = join(dir, ".intlpull.json");
|
|
317
|
+
if (existsSync(configPath2)) {
|
|
318
|
+
try {
|
|
319
|
+
const content = readFileSync(configPath2, "utf-8");
|
|
320
|
+
return { config: JSON.parse(content), projectRoot: dir };
|
|
321
|
+
} catch {
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
const projectRoot = findProjectRoot();
|
|
328
|
+
if (!projectRoot) return null;
|
|
329
|
+
const configPath = join(projectRoot, ".intlpull.json");
|
|
330
|
+
try {
|
|
331
|
+
const content = readFileSync(configPath, "utf-8");
|
|
332
|
+
return { config: JSON.parse(content), projectRoot };
|
|
333
|
+
} catch {
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
function resolveOutputDir(outputDir, projectRoot) {
|
|
338
|
+
if (outputDir.startsWith("/") || outputDir.match(/^[A-Z]:\\/i)) {
|
|
339
|
+
return outputDir;
|
|
340
|
+
}
|
|
341
|
+
return join(projectRoot, outputDir);
|
|
342
|
+
}
|
|
343
|
+
function detectGitBranch(dir = process.cwd()) {
|
|
344
|
+
try {
|
|
345
|
+
let currentDir = dir;
|
|
346
|
+
const root = process.platform === "win32" ? currentDir.split(":")[0] + ":\\" : "/";
|
|
347
|
+
while (currentDir !== root) {
|
|
348
|
+
const gitHead = join(currentDir, ".git", "HEAD");
|
|
349
|
+
if (existsSync(gitHead)) {
|
|
350
|
+
const content = readFileSync(gitHead, "utf-8").trim();
|
|
351
|
+
if (content.startsWith("ref: refs/heads/")) {
|
|
352
|
+
return content.replace("ref: refs/heads/", "");
|
|
353
|
+
}
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
const parentDir = dirname(currentDir);
|
|
357
|
+
if (parentDir === currentDir) break;
|
|
358
|
+
currentDir = parentDir;
|
|
359
|
+
}
|
|
360
|
+
return null;
|
|
361
|
+
} catch {
|
|
362
|
+
return null;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
function getEffectiveBranch(cliBranch, dir) {
|
|
366
|
+
if (cliBranch) return cliBranch;
|
|
367
|
+
const gitBranch = detectGitBranch(dir);
|
|
368
|
+
return gitBranch || "main";
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
export {
|
|
372
|
+
__require,
|
|
373
|
+
writeFileAtomic,
|
|
374
|
+
setCustomEnvFile,
|
|
375
|
+
getCustomEnvFile,
|
|
376
|
+
loadEnvFiles,
|
|
377
|
+
getEnvProjectId,
|
|
378
|
+
detectFramework,
|
|
379
|
+
getProjectConfig,
|
|
380
|
+
saveProjectConfig,
|
|
381
|
+
getAuthConfig,
|
|
382
|
+
saveAuthConfig,
|
|
383
|
+
clearAuthConfig,
|
|
384
|
+
getGlobalConfig,
|
|
385
|
+
getEnvApiKey,
|
|
386
|
+
getResolvedApiKey,
|
|
387
|
+
isAuthenticated,
|
|
388
|
+
getAuthErrorMessage,
|
|
389
|
+
findProjectRoot,
|
|
390
|
+
getProjectConfigFromDir,
|
|
391
|
+
resolveOutputDir,
|
|
392
|
+
detectGitBranch,
|
|
393
|
+
getEffectiveBranch
|
|
394
|
+
};
|