langctl 0.1.1 ā 0.1.2
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/.gitattributes +2 -0
- package/NEXT_PHASE.md +618 -0
- package/README.md +971 -107
- package/WORKING_INSTRUCTIONS.md +1389 -0
- package/dist/auth.d.ts +4 -0
- package/dist/auth.js +6 -0
- package/dist/commands/export.d.ts +14 -0
- package/dist/commands/export.js +115 -0
- package/dist/commands/import.d.ts +11 -0
- package/dist/commands/import.js +171 -0
- package/dist/commands/keys.d.ts +25 -0
- package/dist/commands/keys.js +396 -0
- package/dist/commands/org.d.ts +13 -0
- package/dist/commands/org.js +147 -0
- package/dist/commands/projects.d.ts +28 -0
- package/dist/commands/projects.js +369 -21
- package/dist/commands/team.d.ts +29 -0
- package/dist/commands/team.js +285 -0
- package/dist/index.js +354 -3
- package/package.json +52 -5
- package/NPM_PUBLISH_GUIDE.md +0 -293
- package/QUICK_PUBLISH.md +0 -64
- package/SECURITY_FIX.md +0 -167
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import { isAuthenticated, getApiKey } from '../auth.js';
|
|
4
|
+
const EDGE_FUNCTION_URL = 'https://bcgnmvkgkbhbxzzflwdb.supabase.co/functions/v1/manage-translation-keys';
|
|
5
|
+
const LIST_PROJECTS_URL = 'https://bcgnmvkgkbhbxzzflwdb.supabase.co/functions/v1/list-projects';
|
|
6
|
+
/**
|
|
7
|
+
* Get project by slug
|
|
8
|
+
*/
|
|
9
|
+
async function getProjectBySlug(apiKey, slug) {
|
|
10
|
+
try {
|
|
11
|
+
const response = await fetch(LIST_PROJECTS_URL, {
|
|
12
|
+
method: 'POST',
|
|
13
|
+
headers: {
|
|
14
|
+
'Content-Type': 'application/json',
|
|
15
|
+
'X-API-Key': apiKey
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
if (!response.ok)
|
|
19
|
+
return null;
|
|
20
|
+
const data = await response.json();
|
|
21
|
+
if (!data.success || !data.projects)
|
|
22
|
+
return null;
|
|
23
|
+
return data.projects.find((p) => p.slug === slug) || null;
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* List translation keys
|
|
31
|
+
*/
|
|
32
|
+
export async function listKeysCommand(projectSlug, options) {
|
|
33
|
+
if (!isAuthenticated()) {
|
|
34
|
+
console.log(chalk.red('ā Not authenticated. Please run "langctl auth <api-key>" first.\n'));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const apiKey = getApiKey();
|
|
38
|
+
const spinner = ora('Fetching keys...').start();
|
|
39
|
+
try {
|
|
40
|
+
const project = await getProjectBySlug(apiKey, projectSlug);
|
|
41
|
+
if (!project) {
|
|
42
|
+
spinner.fail(chalk.red(`Project "${projectSlug}" not found`));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const response = await fetch(EDGE_FUNCTION_URL, {
|
|
46
|
+
method: 'POST',
|
|
47
|
+
headers: {
|
|
48
|
+
'Content-Type': 'application/json',
|
|
49
|
+
'X-API-Key': apiKey
|
|
50
|
+
},
|
|
51
|
+
body: JSON.stringify({
|
|
52
|
+
action: 'list',
|
|
53
|
+
projectId: project.id,
|
|
54
|
+
module: options.module,
|
|
55
|
+
published: options.published,
|
|
56
|
+
search: options.search,
|
|
57
|
+
limit: options.limit || 100,
|
|
58
|
+
offset: options.offset || 0
|
|
59
|
+
})
|
|
60
|
+
});
|
|
61
|
+
const data = await response.json();
|
|
62
|
+
if (!data.success) {
|
|
63
|
+
throw new Error(data.error);
|
|
64
|
+
}
|
|
65
|
+
spinner.stop();
|
|
66
|
+
if (!data.keys || data.keys.length === 0) {
|
|
67
|
+
console.log(chalk.yellow('\nNo keys found\n'));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
console.log(chalk.blue.bold(`\nš Translation Keys (${data.keys.length}${data.total ? ` of ${data.total}` : ''})\n`));
|
|
71
|
+
data.keys.forEach((key) => {
|
|
72
|
+
console.log(chalk.white.bold(key.key));
|
|
73
|
+
if (key.description) {
|
|
74
|
+
console.log(chalk.gray(` Description: ${key.description}`));
|
|
75
|
+
}
|
|
76
|
+
if (key.module) {
|
|
77
|
+
console.log(chalk.gray(` Module: ${key.module}`));
|
|
78
|
+
}
|
|
79
|
+
console.log(chalk.gray(` Published: ${key.published ? chalk.green('Yes') : chalk.yellow('No')}`));
|
|
80
|
+
const langs = Object.keys(key.translations);
|
|
81
|
+
if (langs.length > 0) {
|
|
82
|
+
console.log(chalk.gray(` Languages: ${langs.join(', ')}`));
|
|
83
|
+
}
|
|
84
|
+
console.log('');
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
spinner.fail(chalk.red('Failed to list keys'));
|
|
89
|
+
console.error(chalk.red(`Error: ${error.message}\n`));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Get single key
|
|
94
|
+
*/
|
|
95
|
+
export async function getKeyCommand(projectSlug, keyName) {
|
|
96
|
+
if (!isAuthenticated()) {
|
|
97
|
+
console.log(chalk.red('ā Not authenticated. Please run "langctl auth <api-key>" first.\n'));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const apiKey = getApiKey();
|
|
101
|
+
const spinner = ora('Fetching key...').start();
|
|
102
|
+
try {
|
|
103
|
+
const project = await getProjectBySlug(apiKey, projectSlug);
|
|
104
|
+
if (!project) {
|
|
105
|
+
spinner.fail(chalk.red(`Project "${projectSlug}" not found`));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
// First list to find the key ID
|
|
109
|
+
const listResponse = await fetch(EDGE_FUNCTION_URL, {
|
|
110
|
+
method: 'POST',
|
|
111
|
+
headers: {
|
|
112
|
+
'Content-Type': 'application/json',
|
|
113
|
+
'X-API-Key': apiKey
|
|
114
|
+
},
|
|
115
|
+
body: JSON.stringify({
|
|
116
|
+
action: 'list',
|
|
117
|
+
projectId: project.id,
|
|
118
|
+
search: keyName,
|
|
119
|
+
limit: 1
|
|
120
|
+
})
|
|
121
|
+
});
|
|
122
|
+
const listData = await listResponse.json();
|
|
123
|
+
if (!listData.success || !listData.keys || listData.keys.length === 0) {
|
|
124
|
+
spinner.fail(chalk.red(`Key "${keyName}" not found`));
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const key = listData.keys.find((k) => k.key === keyName);
|
|
128
|
+
if (!key) {
|
|
129
|
+
spinner.fail(chalk.red(`Key "${keyName}" not found`));
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
spinner.stop();
|
|
133
|
+
console.log(chalk.blue.bold('\nš Translation Key Details\n'));
|
|
134
|
+
console.log(chalk.white.bold(`Key: ${key.key}`));
|
|
135
|
+
console.log(chalk.gray(`ID: ${key.id}`));
|
|
136
|
+
if (key.description) {
|
|
137
|
+
console.log(chalk.gray(`Description: ${key.description}`));
|
|
138
|
+
}
|
|
139
|
+
if (key.module) {
|
|
140
|
+
console.log(chalk.gray(`Module: ${key.module}`));
|
|
141
|
+
}
|
|
142
|
+
console.log(chalk.gray(`Published: ${key.published ? chalk.green('Yes') : chalk.yellow('No')}`));
|
|
143
|
+
console.log(chalk.blue.bold('\nTranslations:'));
|
|
144
|
+
Object.entries(key.translations).forEach(([lang, value]) => {
|
|
145
|
+
console.log(chalk.white(` ${lang}: ${value}`));
|
|
146
|
+
});
|
|
147
|
+
console.log('');
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
spinner.fail(chalk.red('Failed to get key'));
|
|
151
|
+
console.error(chalk.red(`Error: ${error.message}\n`));
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Create translation key
|
|
156
|
+
*/
|
|
157
|
+
export async function createKeyCommand(projectSlug, keyName, options) {
|
|
158
|
+
if (!isAuthenticated()) {
|
|
159
|
+
console.log(chalk.red('ā Not authenticated. Please run "langctl auth <api-key>" first.\n'));
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const apiKey = getApiKey();
|
|
163
|
+
const spinner = ora('Creating key...').start();
|
|
164
|
+
try {
|
|
165
|
+
const project = await getProjectBySlug(apiKey, projectSlug);
|
|
166
|
+
if (!project) {
|
|
167
|
+
spinner.fail(chalk.red(`Project "${projectSlug}" not found`));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
// Build translations object from --value-* options
|
|
171
|
+
const translations = {};
|
|
172
|
+
Object.keys(options).forEach(opt => {
|
|
173
|
+
if (opt.startsWith('value')) {
|
|
174
|
+
const lang = opt.replace('value', '').toLowerCase();
|
|
175
|
+
if (lang) {
|
|
176
|
+
translations[lang] = options[opt];
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
const response = await fetch(EDGE_FUNCTION_URL, {
|
|
181
|
+
method: 'POST',
|
|
182
|
+
headers: {
|
|
183
|
+
'Content-Type': 'application/json',
|
|
184
|
+
'X-API-Key': apiKey
|
|
185
|
+
},
|
|
186
|
+
body: JSON.stringify({
|
|
187
|
+
action: 'create',
|
|
188
|
+
projectId: project.id,
|
|
189
|
+
key: keyName,
|
|
190
|
+
translations,
|
|
191
|
+
description: options.description,
|
|
192
|
+
module: options.module,
|
|
193
|
+
tags: options.tags ? options.tags.split(',') : []
|
|
194
|
+
})
|
|
195
|
+
});
|
|
196
|
+
const data = await response.json();
|
|
197
|
+
if (!data.success) {
|
|
198
|
+
throw new Error(data.error);
|
|
199
|
+
}
|
|
200
|
+
spinner.succeed(chalk.green(`Created key: ${keyName}`));
|
|
201
|
+
console.log('');
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
spinner.fail(chalk.red('Failed to create key'));
|
|
205
|
+
console.error(chalk.red(`Error: ${error.message}\n`));
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Delete translation key
|
|
210
|
+
*/
|
|
211
|
+
export async function deleteKeyCommand(projectSlug, keyName) {
|
|
212
|
+
if (!isAuthenticated()) {
|
|
213
|
+
console.log(chalk.red('ā Not authenticated. Please run "langctl auth <api-key>" first.\n'));
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const apiKey = getApiKey();
|
|
217
|
+
const spinner = ora('Deleting key...').start();
|
|
218
|
+
try {
|
|
219
|
+
const project = await getProjectBySlug(apiKey, projectSlug);
|
|
220
|
+
if (!project) {
|
|
221
|
+
spinner.fail(chalk.red(`Project "${projectSlug}" not found`));
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
// Find key ID
|
|
225
|
+
const listResponse = await fetch(EDGE_FUNCTION_URL, {
|
|
226
|
+
method: 'POST',
|
|
227
|
+
headers: {
|
|
228
|
+
'Content-Type': 'application/json',
|
|
229
|
+
'X-API-Key': apiKey
|
|
230
|
+
},
|
|
231
|
+
body: JSON.stringify({
|
|
232
|
+
action: 'list',
|
|
233
|
+
projectId: project.id,
|
|
234
|
+
search: keyName,
|
|
235
|
+
limit: 1
|
|
236
|
+
})
|
|
237
|
+
});
|
|
238
|
+
const listData = await listResponse.json();
|
|
239
|
+
const key = listData.keys?.find((k) => k.key === keyName);
|
|
240
|
+
if (!key) {
|
|
241
|
+
spinner.fail(chalk.red(`Key "${keyName}" not found`));
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
// Delete key
|
|
245
|
+
const response = await fetch(EDGE_FUNCTION_URL, {
|
|
246
|
+
method: 'POST',
|
|
247
|
+
headers: {
|
|
248
|
+
'Content-Type': 'application/json',
|
|
249
|
+
'X-API-Key': apiKey
|
|
250
|
+
},
|
|
251
|
+
body: JSON.stringify({
|
|
252
|
+
action: 'delete',
|
|
253
|
+
projectId: project.id,
|
|
254
|
+
keyId: key.id
|
|
255
|
+
})
|
|
256
|
+
});
|
|
257
|
+
const data = await response.json();
|
|
258
|
+
if (!data.success) {
|
|
259
|
+
throw new Error(data.error);
|
|
260
|
+
}
|
|
261
|
+
spinner.succeed(chalk.green(`Deleted key: ${keyName}`));
|
|
262
|
+
console.log('');
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
spinner.fail(chalk.red('Failed to delete key'));
|
|
266
|
+
console.error(chalk.red(`Error: ${error.message}\n`));
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Update single translation
|
|
271
|
+
*/
|
|
272
|
+
export async function translateKeyCommand(projectSlug, keyName, options) {
|
|
273
|
+
if (!isAuthenticated()) {
|
|
274
|
+
console.log(chalk.red('ā Not authenticated. Please run "langctl auth <api-key>" first.\n'));
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const apiKey = getApiKey();
|
|
278
|
+
const spinner = ora('Updating translation...').start();
|
|
279
|
+
try {
|
|
280
|
+
const project = await getProjectBySlug(apiKey, projectSlug);
|
|
281
|
+
if (!project) {
|
|
282
|
+
spinner.fail(chalk.red(`Project "${projectSlug}" not found`));
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
// Find key ID
|
|
286
|
+
const listResponse = await fetch(EDGE_FUNCTION_URL, {
|
|
287
|
+
method: 'POST',
|
|
288
|
+
headers: {
|
|
289
|
+
'Content-Type': 'application/json',
|
|
290
|
+
'X-API-Key': apiKey
|
|
291
|
+
},
|
|
292
|
+
body: JSON.stringify({
|
|
293
|
+
action: 'list',
|
|
294
|
+
projectId: project.id,
|
|
295
|
+
search: keyName,
|
|
296
|
+
limit: 1
|
|
297
|
+
})
|
|
298
|
+
});
|
|
299
|
+
const listData = await listResponse.json();
|
|
300
|
+
const key = listData.keys?.find((k) => k.key === keyName);
|
|
301
|
+
if (!key) {
|
|
302
|
+
spinner.fail(chalk.red(`Key "${keyName}" not found`));
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
// Update translation
|
|
306
|
+
const response = await fetch(EDGE_FUNCTION_URL, {
|
|
307
|
+
method: 'POST',
|
|
308
|
+
headers: {
|
|
309
|
+
'Content-Type': 'application/json',
|
|
310
|
+
'X-API-Key': apiKey
|
|
311
|
+
},
|
|
312
|
+
body: JSON.stringify({
|
|
313
|
+
action: 'translate',
|
|
314
|
+
projectId: project.id,
|
|
315
|
+
keyId: key.id,
|
|
316
|
+
language: options.language,
|
|
317
|
+
value: options.value
|
|
318
|
+
})
|
|
319
|
+
});
|
|
320
|
+
const data = await response.json();
|
|
321
|
+
if (!data.success) {
|
|
322
|
+
throw new Error(data.error);
|
|
323
|
+
}
|
|
324
|
+
spinner.succeed(chalk.green(`Updated ${options.language} translation for ${keyName}`));
|
|
325
|
+
console.log('');
|
|
326
|
+
}
|
|
327
|
+
catch (error) {
|
|
328
|
+
spinner.fail(chalk.red('Failed to update translation'));
|
|
329
|
+
console.error(chalk.red(`Error: ${error.message}\n`));
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Publish/unpublish keys
|
|
334
|
+
*/
|
|
335
|
+
export async function publishKeysCommand(projectSlug, keys, options) {
|
|
336
|
+
if (!isAuthenticated()) {
|
|
337
|
+
console.log(chalk.red('ā Not authenticated. Please run "langctl auth <api-key>" first.\n'));
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
const apiKey = getApiKey();
|
|
341
|
+
const action = options.unpublish ? 'unpublish' : 'publish';
|
|
342
|
+
const spinner = ora(`${action === 'publish' ? 'Publishing' : 'Unpublishing'} keys...`).start();
|
|
343
|
+
try {
|
|
344
|
+
const project = await getProjectBySlug(apiKey, projectSlug);
|
|
345
|
+
if (!project) {
|
|
346
|
+
spinner.fail(chalk.red(`Project "${projectSlug}" not found`));
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
// Get key IDs
|
|
350
|
+
const listResponse = await fetch(EDGE_FUNCTION_URL, {
|
|
351
|
+
method: 'POST',
|
|
352
|
+
headers: {
|
|
353
|
+
'Content-Type': 'application/json',
|
|
354
|
+
'X-API-Key': apiKey
|
|
355
|
+
},
|
|
356
|
+
body: JSON.stringify({
|
|
357
|
+
action: 'list',
|
|
358
|
+
projectId: project.id,
|
|
359
|
+
limit: 1000
|
|
360
|
+
})
|
|
361
|
+
});
|
|
362
|
+
const listData = await listResponse.json();
|
|
363
|
+
const keyIds = listData.keys
|
|
364
|
+
?.filter((k) => keys.includes(k.key))
|
|
365
|
+
.map((k) => k.id) || [];
|
|
366
|
+
if (keyIds.length === 0) {
|
|
367
|
+
spinner.fail(chalk.red('No matching keys found'));
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
// Publish/unpublish keys
|
|
371
|
+
const response = await fetch(EDGE_FUNCTION_URL, {
|
|
372
|
+
method: 'POST',
|
|
373
|
+
headers: {
|
|
374
|
+
'Content-Type': 'application/json',
|
|
375
|
+
'X-API-Key': apiKey
|
|
376
|
+
},
|
|
377
|
+
body: JSON.stringify({
|
|
378
|
+
action: 'publish',
|
|
379
|
+
projectId: project.id,
|
|
380
|
+
keyIds,
|
|
381
|
+
published: !options.unpublish
|
|
382
|
+
})
|
|
383
|
+
});
|
|
384
|
+
const data = await response.json();
|
|
385
|
+
if (!data.success) {
|
|
386
|
+
throw new Error(data.error);
|
|
387
|
+
}
|
|
388
|
+
spinner.succeed(chalk.green(data.message));
|
|
389
|
+
console.log('');
|
|
390
|
+
}
|
|
391
|
+
catch (error) {
|
|
392
|
+
spinner.fail(chalk.red(`Failed to ${action} keys`));
|
|
393
|
+
console.error(chalk.red(`Error: ${error.message}\n`));
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
//# sourceMappingURL=keys.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get organization information
|
|
3
|
+
*/
|
|
4
|
+
export declare function orgInfoCommand(): Promise<void>;
|
|
5
|
+
/**
|
|
6
|
+
* Get organization statistics
|
|
7
|
+
*/
|
|
8
|
+
export declare function orgStatsCommand(): Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* Get organization plan and limits
|
|
11
|
+
*/
|
|
12
|
+
export declare function orgPlanCommand(): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=org.d.ts.map
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import { isAuthenticated, getApiKey } from '../auth.js';
|
|
4
|
+
const ORG_INFO_URL = 'https://bcgnmvkgkbhbxzzflwdb.supabase.co/functions/v1/get-organization-info';
|
|
5
|
+
/**
|
|
6
|
+
* Get organization information
|
|
7
|
+
*/
|
|
8
|
+
export async function orgInfoCommand() {
|
|
9
|
+
if (!isAuthenticated()) {
|
|
10
|
+
console.log(chalk.red('ā Not authenticated. Please run "langctl auth <api-key>" first.\n'));
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const apiKey = getApiKey();
|
|
14
|
+
const spinner = ora('Fetching organization info...').start();
|
|
15
|
+
try {
|
|
16
|
+
const response = await fetch(ORG_INFO_URL, {
|
|
17
|
+
method: 'POST',
|
|
18
|
+
headers: {
|
|
19
|
+
'Content-Type': 'application/json',
|
|
20
|
+
'X-API-Key': apiKey
|
|
21
|
+
},
|
|
22
|
+
body: JSON.stringify({
|
|
23
|
+
action: 'info'
|
|
24
|
+
})
|
|
25
|
+
});
|
|
26
|
+
const data = await response.json();
|
|
27
|
+
if (!data.success) {
|
|
28
|
+
throw new Error(data.error);
|
|
29
|
+
}
|
|
30
|
+
spinner.stop();
|
|
31
|
+
const org = data.organization;
|
|
32
|
+
console.log(chalk.blue.bold('\nš¢ Organization Information\n'));
|
|
33
|
+
console.log(chalk.white.bold(org.name));
|
|
34
|
+
console.log(chalk.gray(`ID: ${org.id}`));
|
|
35
|
+
console.log(chalk.gray(`Slug: ${org.slug}`));
|
|
36
|
+
if (org.description) {
|
|
37
|
+
console.log(chalk.gray(`Description: ${org.description}`));
|
|
38
|
+
}
|
|
39
|
+
console.log(chalk.gray(`Plan: ${org.plan}`));
|
|
40
|
+
console.log(chalk.gray(`Created: ${new Date(org.created_at).toLocaleDateString()}`));
|
|
41
|
+
console.log('');
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
spinner.fail(chalk.red('Failed to fetch organization info'));
|
|
45
|
+
console.error(chalk.red(`Error: ${error.message}\n`));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get organization statistics
|
|
50
|
+
*/
|
|
51
|
+
export async function orgStatsCommand() {
|
|
52
|
+
if (!isAuthenticated()) {
|
|
53
|
+
console.log(chalk.red('ā Not authenticated. Please run "langctl auth <api-key>" first.\n'));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const apiKey = getApiKey();
|
|
57
|
+
const spinner = ora('Fetching organization statistics...').start();
|
|
58
|
+
try {
|
|
59
|
+
const response = await fetch(ORG_INFO_URL, {
|
|
60
|
+
method: 'POST',
|
|
61
|
+
headers: {
|
|
62
|
+
'Content-Type': 'application/json',
|
|
63
|
+
'X-API-Key': apiKey
|
|
64
|
+
},
|
|
65
|
+
body: JSON.stringify({
|
|
66
|
+
action: 'stats'
|
|
67
|
+
})
|
|
68
|
+
});
|
|
69
|
+
const data = await response.json();
|
|
70
|
+
if (!data.success) {
|
|
71
|
+
throw new Error(data.error);
|
|
72
|
+
}
|
|
73
|
+
spinner.stop();
|
|
74
|
+
const stats = data.stats;
|
|
75
|
+
console.log(chalk.blue.bold('\nš Organization Statistics\n'));
|
|
76
|
+
console.log(chalk.white.bold('Team'));
|
|
77
|
+
console.log(chalk.gray(` Members: ${stats.members}`));
|
|
78
|
+
console.log('');
|
|
79
|
+
console.log(chalk.white.bold('Projects'));
|
|
80
|
+
console.log(chalk.gray(` Total Projects: ${stats.projects}`));
|
|
81
|
+
console.log('');
|
|
82
|
+
console.log(chalk.white.bold('Translation Keys'));
|
|
83
|
+
console.log(chalk.gray(` Total Keys: ${stats.total_keys}`));
|
|
84
|
+
console.log(chalk.green(` Published: ${stats.published_keys}`));
|
|
85
|
+
console.log(chalk.yellow(` Unpublished: ${stats.unpublished_keys}`));
|
|
86
|
+
console.log('');
|
|
87
|
+
console.log(chalk.white.bold('Languages'));
|
|
88
|
+
console.log(chalk.gray(` Total Languages: ${stats.languages}`));
|
|
89
|
+
if (stats.language_codes && stats.language_codes.length > 0) {
|
|
90
|
+
console.log(chalk.gray(` Codes: ${stats.language_codes.join(', ')}`));
|
|
91
|
+
}
|
|
92
|
+
console.log('');
|
|
93
|
+
console.log(chalk.white.bold('Resources'));
|
|
94
|
+
console.log(chalk.gray(` API Keys: ${stats.api_keys}`));
|
|
95
|
+
console.log(chalk.gray(` Webhooks: ${stats.webhooks}`));
|
|
96
|
+
console.log('');
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
spinner.fail(chalk.red('Failed to fetch statistics'));
|
|
100
|
+
console.error(chalk.red(`Error: ${error.message}\n`));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Get organization plan and limits
|
|
105
|
+
*/
|
|
106
|
+
export async function orgPlanCommand() {
|
|
107
|
+
if (!isAuthenticated()) {
|
|
108
|
+
console.log(chalk.red('ā Not authenticated. Please run "langctl auth <api-key>" first.\n'));
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const apiKey = getApiKey();
|
|
112
|
+
const spinner = ora('Fetching plan information...').start();
|
|
113
|
+
try {
|
|
114
|
+
const response = await fetch(ORG_INFO_URL, {
|
|
115
|
+
method: 'POST',
|
|
116
|
+
headers: {
|
|
117
|
+
'Content-Type': 'application/json',
|
|
118
|
+
'X-API-Key': apiKey
|
|
119
|
+
},
|
|
120
|
+
body: JSON.stringify({
|
|
121
|
+
action: 'plan'
|
|
122
|
+
})
|
|
123
|
+
});
|
|
124
|
+
const data = await response.json();
|
|
125
|
+
if (!data.success) {
|
|
126
|
+
throw new Error(data.error);
|
|
127
|
+
}
|
|
128
|
+
spinner.stop();
|
|
129
|
+
const limits = data.limits;
|
|
130
|
+
console.log(chalk.blue.bold('\nš Subscription Plan\n'));
|
|
131
|
+
console.log(chalk.white.bold(`Current Plan: ${data.plan.toUpperCase()}`));
|
|
132
|
+
console.log('');
|
|
133
|
+
console.log(chalk.white.bold('Plan Limits'));
|
|
134
|
+
// Display limits with "Unlimited" for -1 or null values
|
|
135
|
+
const formatLimit = (value) => (value === -1 || value === null) ? chalk.green('Unlimited') : chalk.gray(value.toString());
|
|
136
|
+
console.log(chalk.gray(` Max Members: ${formatLimit(limits.max_members)}`));
|
|
137
|
+
console.log(chalk.gray(` Max Projects: ${formatLimit(limits.max_projects)}`));
|
|
138
|
+
console.log(chalk.gray(` Max Keys per Project: ${formatLimit(limits.max_keys_per_project)}`));
|
|
139
|
+
console.log(chalk.gray(` Max API Keys: ${formatLimit(limits.max_api_keys)}`));
|
|
140
|
+
console.log('');
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
spinner.fail(chalk.red('Failed to fetch plan information'));
|
|
144
|
+
console.error(chalk.red(`Error: ${error.message}\n`));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=org.js.map
|
|
@@ -1,2 +1,30 @@
|
|
|
1
1
|
export declare function projectsListCommand(): Promise<void>;
|
|
2
|
+
/**
|
|
3
|
+
* Create new project
|
|
4
|
+
*/
|
|
5
|
+
export declare function projectsCreateCommand(name: string, options: any): Promise<void>;
|
|
6
|
+
/**
|
|
7
|
+
* Get project details
|
|
8
|
+
*/
|
|
9
|
+
export declare function projectsGetCommand(slug: string): Promise<void>;
|
|
10
|
+
/**
|
|
11
|
+
* Update project
|
|
12
|
+
*/
|
|
13
|
+
export declare function projectsUpdateCommand(slug: string, options: any): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Delete project
|
|
16
|
+
*/
|
|
17
|
+
export declare function projectsDeleteCommand(slug: string): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Add language to project
|
|
20
|
+
*/
|
|
21
|
+
export declare function projectsAddLanguageCommand(slug: string, language: string): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Remove language from project
|
|
24
|
+
*/
|
|
25
|
+
export declare function projectsRemoveLanguageCommand(slug: string, language: string): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Get project statistics
|
|
28
|
+
*/
|
|
29
|
+
export declare function projectsStatsCommand(slug: string): Promise<void>;
|
|
2
30
|
//# sourceMappingURL=projects.d.ts.map
|