langctl 0.1.2 → 0.2.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/.github/ISSUE_TEMPLATE/bug_report.md +26 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
- package/CONTRIBUTING.md +33 -0
- package/LICENSE +1 -1
- package/README.md +52 -11
- package/dist/api.d.ts +20 -0
- package/dist/api.js +75 -0
- package/dist/auth.d.ts +3 -2
- package/dist/auth.js +21 -27
- package/dist/commands/auth.js +2 -10
- package/dist/commands/config.js +1 -0
- package/dist/commands/debug.js +45 -41
- package/dist/commands/export.d.ts +1 -2
- package/dist/commands/export.js +70 -60
- package/dist/commands/import.d.ts +1 -0
- package/dist/commands/import.js +51 -72
- package/dist/commands/init.js +0 -10
- package/dist/commands/keys.js +122 -224
- package/dist/commands/org.js +43 -72
- package/dist/commands/projects.d.ts +3 -0
- package/dist/commands/projects.js +146 -223
- package/dist/commands/pull.js +40 -95
- package/dist/commands/team.js +115 -130
- package/dist/config.d.ts +1 -0
- package/dist/index.js +3 -3
- package/package.json +2 -3
- package/NEXT_PHASE.md +0 -618
- package/WORKING_INSTRUCTIONS.md +0 -1389
- package/dist/supabase.d.ts +0 -14
- package/dist/supabase.js +0 -30
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug Report
|
|
3
|
+
about: Report a bug or unexpected behavior
|
|
4
|
+
title: ''
|
|
5
|
+
labels: bug
|
|
6
|
+
assignees: ''
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
**Describe the bug**
|
|
10
|
+
A clear description of what the bug is.
|
|
11
|
+
|
|
12
|
+
**To reproduce**
|
|
13
|
+
Steps to reproduce:
|
|
14
|
+
1. Run `langctl ...`
|
|
15
|
+
2. ...
|
|
16
|
+
|
|
17
|
+
**Expected behavior**
|
|
18
|
+
What you expected to happen.
|
|
19
|
+
|
|
20
|
+
**Environment**
|
|
21
|
+
- OS: [e.g. macOS 14, Ubuntu 22.04]
|
|
22
|
+
- Node.js version: [e.g. 18.17.0]
|
|
23
|
+
- langctl version: [output of `langctl --version`]
|
|
24
|
+
|
|
25
|
+
**Additional context**
|
|
26
|
+
Add any other context, logs, or screenshots.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature Request
|
|
3
|
+
about: Suggest a new feature or improvement
|
|
4
|
+
title: ''
|
|
5
|
+
labels: enhancement
|
|
6
|
+
assignees: ''
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
**Problem**
|
|
10
|
+
What problem does this feature solve?
|
|
11
|
+
|
|
12
|
+
**Proposed solution**
|
|
13
|
+
Describe how you'd like this to work.
|
|
14
|
+
|
|
15
|
+
**Alternatives considered**
|
|
16
|
+
Any alternative solutions or workarounds you've tried.
|
|
17
|
+
|
|
18
|
+
**Additional context**
|
|
19
|
+
Any other context, examples, or references.
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Contributing to langctl
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in contributing! Here's how to get started.
|
|
4
|
+
|
|
5
|
+
## Development Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/siddharthsaxena0/langctl.git
|
|
9
|
+
cd langctl
|
|
10
|
+
npm install
|
|
11
|
+
npm run dev # runs tsx watch
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Making Changes
|
|
15
|
+
|
|
16
|
+
1. Fork the repo and create a feature branch from `main`
|
|
17
|
+
2. Make your changes
|
|
18
|
+
3. Test locally with `npm run dev`
|
|
19
|
+
4. Submit a pull request
|
|
20
|
+
|
|
21
|
+
## Reporting Bugs
|
|
22
|
+
|
|
23
|
+
Use the [bug report template](https://github.com/siddharthsaxena0/langctl/issues/new?template=bug_report.md) and include your `langctl --version`, Node.js version, and OS.
|
|
24
|
+
|
|
25
|
+
## Code Style
|
|
26
|
+
|
|
27
|
+
- TypeScript with strict mode
|
|
28
|
+
- Use `commander` for CLI commands
|
|
29
|
+
- Keep commands in `src/commands/`
|
|
30
|
+
|
|
31
|
+
## License
|
|
32
|
+
|
|
33
|
+
By contributing, you agree that your contributions will be licensed under the MIT License.
|
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# Langctl
|
|
4
|
+
|
|
5
|
+
**CLI-first translation management for developers**
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/langctl)
|
|
8
|
+
[](https://github.com/siddharthsaxena0/langctl/blob/main/LICENSE)
|
|
9
|
+
[](https://www.npmjs.com/package/langctl)
|
|
10
|
+
|
|
11
|
+
**[Website](https://langctl.com)** · **[Documentation](https://langctl.com/docs)** · **[Get Started](https://app.langctl.com/signup)**
|
|
12
|
+
|
|
13
|
+
<!-- Add a demo GIF here: -->
|
|
14
|
+
<!--  -->
|
|
15
|
+
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
---
|
|
4
19
|
|
|
5
20
|
Langctl is a powerful command-line tool that lets you manage translations directly from your terminal. Create projects, manage translation keys, invite team members, export in multiple formats, and integrate seamlessly into your CI/CD pipeline.
|
|
6
21
|
|
|
@@ -29,13 +44,17 @@ npx langctl --help
|
|
|
29
44
|
|
|
30
45
|
## Quick Start
|
|
31
46
|
|
|
47
|
+
> **📌 First time here?** Check out our [Getting Started Guide](https://langctl.com/docs/getting-started/introduction) on the website for a complete walkthrough!
|
|
48
|
+
|
|
32
49
|
### 1. Get Your API Key
|
|
33
50
|
|
|
34
|
-
1. Visit [app.langctl.com](https://app.langctl.com) and
|
|
51
|
+
1. Visit **[app.langctl.com](https://app.langctl.com/signup)** and create a free account
|
|
35
52
|
2. Go to **Settings → API Keys**
|
|
36
53
|
3. Click **"Generate New Key"**
|
|
37
54
|
4. Copy the key (it's only shown once!)
|
|
38
55
|
|
|
56
|
+
> **💡 Tip:** Learn more about API keys and authentication at [langctl.com/docs/cli/authentication](https://langctl.com/docs/cli/authentication)
|
|
57
|
+
|
|
39
58
|
### 2. Authenticate
|
|
40
59
|
|
|
41
60
|
```bash
|
|
@@ -1163,20 +1182,34 @@ A: Yes! Store your API key as a secret and use it in your workflow. See [CI/CD I
|
|
|
1163
1182
|
|
|
1164
1183
|
---
|
|
1165
1184
|
|
|
1166
|
-
##
|
|
1185
|
+
## 🌟 Why Langctl?
|
|
1167
1186
|
|
|
1168
|
-
|
|
1169
|
-
- **
|
|
1170
|
-
- **
|
|
1171
|
-
- **
|
|
1172
|
-
- **
|
|
1173
|
-
- **
|
|
1187
|
+
Tired of expensive translation management tools? Langctl offers:
|
|
1188
|
+
- ✅ **Free to start** - No credit card required
|
|
1189
|
+
- ✅ **90% cheaper** than enterprise alternatives
|
|
1190
|
+
- ✅ **Developer-first** - Built for your workflow
|
|
1191
|
+
- ✅ **AI-powered** - Context-aware translations
|
|
1192
|
+
- ✅ **Open source CLI** - Inspect, fork, contribute
|
|
1193
|
+
|
|
1194
|
+
**[See pricing and compare features →](https://langctl.com/pricing)**
|
|
1195
|
+
|
|
1196
|
+
---
|
|
1197
|
+
|
|
1198
|
+
## 📚 Resources & Support
|
|
1199
|
+
|
|
1200
|
+
- 🌐 **[Website](https://langctl.com)** - Features, pricing, and comparisons
|
|
1201
|
+
- 📖 **[Full Documentation](https://langctl.com/docs)** - Guides, tutorials, and best practices
|
|
1202
|
+
- 🎯 **[Quick Start Tutorial](https://langctl.com/docs/getting-started/quickstart)** - Step-by-step walkthrough
|
|
1203
|
+
- 💡 **[Integration Guides](https://langctl.com/docs/integrations/overview)** - React, Angular, Vue, iOS, Android, Flutter
|
|
1204
|
+
- 📊 **[Dashboard](https://app.langctl.com)** - Manage translations visually
|
|
1205
|
+
- 💬 **[Get Support](https://langctl.com/contact)** - Email us at [hello@langctl.com](mailto:hello@langctl.com)
|
|
1206
|
+
- 🐛 **[Report Issues](https://github.com/siddharthsaxena0/langctl/issues)** - Bug reports and feature requests
|
|
1174
1207
|
|
|
1175
1208
|
---
|
|
1176
1209
|
|
|
1177
1210
|
## Contributing
|
|
1178
1211
|
|
|
1179
|
-
We welcome contributions!
|
|
1212
|
+
We welcome contributions! This is an open-source project and we'd love your help making it better.
|
|
1180
1213
|
|
|
1181
1214
|
---
|
|
1182
1215
|
|
|
@@ -1184,8 +1217,16 @@ We welcome contributions! Please see our [contributing guidelines](CONTRIBUTING.
|
|
|
1184
1217
|
|
|
1185
1218
|
MIT License - see [LICENSE](LICENSE) file for details.
|
|
1186
1219
|
|
|
1220
|
+
Copyright © 2026 Litcode Private Limited. All rights reserved.
|
|
1221
|
+
|
|
1187
1222
|
---
|
|
1188
1223
|
|
|
1224
|
+
<div align="center">
|
|
1225
|
+
|
|
1189
1226
|
**Built with ❤️ by the Langctl team**
|
|
1190
1227
|
|
|
1191
1228
|
*Making translation management simple, fast, and developer-friendly.*
|
|
1229
|
+
|
|
1230
|
+
**[Get Started Free →](https://app.langctl.com/signup)**
|
|
1231
|
+
|
|
1232
|
+
</div>
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare class ApiClient {
|
|
2
|
+
private baseUrl;
|
|
3
|
+
private apiKey;
|
|
4
|
+
constructor(baseUrl: string, apiKey: string);
|
|
5
|
+
private request;
|
|
6
|
+
get<T>(path: string, params?: Record<string, string>): Promise<T>;
|
|
7
|
+
post<T>(path: string, body?: unknown): Promise<T>;
|
|
8
|
+
patch<T>(path: string, body: unknown): Promise<T>;
|
|
9
|
+
delete<T>(path: string): Promise<T>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Create an API client from the current config.
|
|
13
|
+
* Throws if not authenticated.
|
|
14
|
+
*/
|
|
15
|
+
export declare function getApiClient(): ApiClient;
|
|
16
|
+
/**
|
|
17
|
+
* Create an API client with a specific API key (for auth flow before key is saved).
|
|
18
|
+
*/
|
|
19
|
+
export declare function createApiClient(apiKey: string): ApiClient;
|
|
20
|
+
//# sourceMappingURL=api.d.ts.map
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { config } from './config.js';
|
|
2
|
+
const DEFAULT_API_URL = 'https://api.langctl.com/api/v1';
|
|
3
|
+
export class ApiClient {
|
|
4
|
+
constructor(baseUrl, apiKey) {
|
|
5
|
+
this.baseUrl = baseUrl.replace(/\/$/, '');
|
|
6
|
+
this.apiKey = apiKey;
|
|
7
|
+
}
|
|
8
|
+
async request(method, path, body, params) {
|
|
9
|
+
let url = `${this.baseUrl}${path}`;
|
|
10
|
+
if (params && Object.keys(params).length > 0) {
|
|
11
|
+
const searchParams = new URLSearchParams();
|
|
12
|
+
for (const [key, value] of Object.entries(params)) {
|
|
13
|
+
if (value !== undefined && value !== null && value !== '') {
|
|
14
|
+
searchParams.append(key, value);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const qs = searchParams.toString();
|
|
18
|
+
if (qs)
|
|
19
|
+
url += `?${qs}`;
|
|
20
|
+
}
|
|
21
|
+
const headers = {
|
|
22
|
+
'X-API-Key': this.apiKey,
|
|
23
|
+
};
|
|
24
|
+
if (body !== undefined) {
|
|
25
|
+
headers['Content-Type'] = 'application/json';
|
|
26
|
+
}
|
|
27
|
+
const response = await fetch(url, {
|
|
28
|
+
method,
|
|
29
|
+
headers,
|
|
30
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
31
|
+
signal: AbortSignal.timeout(30000),
|
|
32
|
+
});
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
const errorData = await response.json().catch(() => ({}));
|
|
35
|
+
throw new Error(errorData.error || errorData.message || `HTTP ${response.status}: ${response.statusText}`);
|
|
36
|
+
}
|
|
37
|
+
// Handle 204 No Content
|
|
38
|
+
if (response.status === 204) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
return response.json();
|
|
42
|
+
}
|
|
43
|
+
async get(path, params) {
|
|
44
|
+
return this.request('GET', path, undefined, params);
|
|
45
|
+
}
|
|
46
|
+
async post(path, body) {
|
|
47
|
+
return this.request('POST', path, body);
|
|
48
|
+
}
|
|
49
|
+
async patch(path, body) {
|
|
50
|
+
return this.request('PATCH', path, body);
|
|
51
|
+
}
|
|
52
|
+
async delete(path) {
|
|
53
|
+
return this.request('DELETE', path);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Create an API client from the current config.
|
|
58
|
+
* Throws if not authenticated.
|
|
59
|
+
*/
|
|
60
|
+
export function getApiClient() {
|
|
61
|
+
const apiKey = config.get('apiKey');
|
|
62
|
+
const baseUrl = config.get('apiBaseUrl') || DEFAULT_API_URL;
|
|
63
|
+
if (!apiKey) {
|
|
64
|
+
throw new Error('Not authenticated. Please run "langctl auth <api-key>" first.');
|
|
65
|
+
}
|
|
66
|
+
return new ApiClient(baseUrl, apiKey);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Create an API client with a specific API key (for auth flow before key is saved).
|
|
70
|
+
*/
|
|
71
|
+
export function createApiClient(apiKey) {
|
|
72
|
+
const baseUrl = config.get('apiBaseUrl') || DEFAULT_API_URL;
|
|
73
|
+
return new ApiClient(baseUrl, apiKey);
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=api.js.map
|
package/dist/auth.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
export interface ApiKeyData {
|
|
2
|
-
|
|
2
|
+
organizationId: string;
|
|
3
3
|
organization: {
|
|
4
4
|
id: string;
|
|
5
5
|
name: string;
|
|
6
|
+
slug: string;
|
|
6
7
|
plan: string;
|
|
7
8
|
};
|
|
8
9
|
}
|
|
9
10
|
/**
|
|
10
|
-
* Verify API key via
|
|
11
|
+
* Verify API key via Fastify API
|
|
11
12
|
*/
|
|
12
13
|
export declare function verifyApiKey(plainTextKey: string): Promise<ApiKeyData | null>;
|
|
13
14
|
/**
|
package/dist/auth.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { config } from './config.js';
|
|
2
|
-
|
|
3
|
-
const EDGE_FUNCTION_URL = 'https://bcgnmvkgkbhbxzzflwdb.supabase.co/functions/v1/verify-api-key';
|
|
2
|
+
import { createApiClient } from './api.js';
|
|
4
3
|
// Normalize and validate API key input
|
|
5
4
|
function sanitizeApiKey(input) {
|
|
6
5
|
const raw = (input || '').trim().toLowerCase();
|
|
@@ -15,7 +14,7 @@ function sanitizeApiKey(input) {
|
|
|
15
14
|
return { ok: true, key: `lc_${hexOnly}` };
|
|
16
15
|
}
|
|
17
16
|
/**
|
|
18
|
-
* Verify API key via
|
|
17
|
+
* Verify API key via Fastify API
|
|
19
18
|
*/
|
|
20
19
|
export async function verifyApiKey(plainTextKey) {
|
|
21
20
|
try {
|
|
@@ -23,33 +22,28 @@ export async function verifyApiKey(plainTextKey) {
|
|
|
23
22
|
if (!sanitized.ok || !sanitized.key) {
|
|
24
23
|
return null;
|
|
25
24
|
}
|
|
26
|
-
//
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
},
|
|
32
|
-
body: JSON.stringify({ apiKey: sanitized.key })
|
|
25
|
+
// Create a temporary API client with the key to validate
|
|
26
|
+
const client = createApiClient(sanitized.key);
|
|
27
|
+
// Validate the API key
|
|
28
|
+
const validateResult = await client.post('/api-keys/validate', {
|
|
29
|
+
apiKey: sanitized.key,
|
|
33
30
|
});
|
|
34
|
-
if (!
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
const data = await response.json();
|
|
38
|
-
if (!data.success) {
|
|
31
|
+
if (!validateResult.valid) {
|
|
39
32
|
return null;
|
|
40
33
|
}
|
|
41
|
-
//
|
|
34
|
+
// Fetch organization details
|
|
35
|
+
const org = await client.get(`/orgs/${validateResult.organizationId}`);
|
|
42
36
|
return {
|
|
43
|
-
|
|
37
|
+
organizationId: validateResult.organizationId,
|
|
44
38
|
organization: {
|
|
45
|
-
id:
|
|
46
|
-
name:
|
|
47
|
-
|
|
48
|
-
|
|
39
|
+
id: org.id,
|
|
40
|
+
name: org.name,
|
|
41
|
+
slug: org.slug,
|
|
42
|
+
plan: org.plan,
|
|
43
|
+
},
|
|
49
44
|
};
|
|
50
45
|
}
|
|
51
46
|
catch (error) {
|
|
52
|
-
console.error('Error verifying API key:', error);
|
|
53
47
|
return null;
|
|
54
48
|
}
|
|
55
49
|
}
|
|
@@ -61,25 +55,25 @@ export async function authenticate(apiKey) {
|
|
|
61
55
|
if (!sanitized.ok || !sanitized.key) {
|
|
62
56
|
return {
|
|
63
57
|
success: false,
|
|
64
|
-
message: sanitized.message || 'Invalid API key format. Expected format: lc_[64 hex characters]'
|
|
58
|
+
message: sanitized.message || 'Invalid API key format. Expected format: lc_[64 hex characters]',
|
|
65
59
|
};
|
|
66
60
|
}
|
|
67
|
-
// Verify via
|
|
61
|
+
// Verify via Fastify API
|
|
68
62
|
const keyData = await verifyApiKey(sanitized.key);
|
|
69
63
|
if (!keyData) {
|
|
70
64
|
return {
|
|
71
65
|
success: false,
|
|
72
|
-
message: 'Invalid or revoked API key. Please check your key and try again.'
|
|
66
|
+
message: 'Invalid or revoked API key. Please check your key and try again.',
|
|
73
67
|
};
|
|
74
68
|
}
|
|
75
69
|
// Save to config
|
|
76
70
|
config.set('apiKey', sanitized.key);
|
|
77
|
-
config.set('organizationId', keyData.
|
|
71
|
+
config.set('organizationId', keyData.organizationId);
|
|
78
72
|
config.set('organizationName', keyData.organization.name);
|
|
79
73
|
return {
|
|
80
74
|
success: true,
|
|
81
75
|
message: `Successfully authenticated as ${keyData.organization.name}`,
|
|
82
|
-
data: keyData
|
|
76
|
+
data: keyData,
|
|
83
77
|
};
|
|
84
78
|
}
|
|
85
79
|
/**
|
package/dist/commands/auth.js
CHANGED
|
@@ -2,16 +2,7 @@ import chalk from 'chalk';
|
|
|
2
2
|
import ora from 'ora';
|
|
3
3
|
import { authenticate, logout } from '../auth.js';
|
|
4
4
|
import { config } from '../config.js';
|
|
5
|
-
import { initializeSupabase } from '../supabase.js';
|
|
6
5
|
export async function authCommand(apiKey) {
|
|
7
|
-
// Initialize Supabase (with hardcoded credentials)
|
|
8
|
-
try {
|
|
9
|
-
initializeSupabase();
|
|
10
|
-
}
|
|
11
|
-
catch (error) {
|
|
12
|
-
console.log(chalk.red('✗ Failed to connect to Langctl servers.\n'));
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
6
|
const spinner = ora('Authenticating...').start();
|
|
16
7
|
const result = await authenticate(apiKey);
|
|
17
8
|
if (result.success) {
|
|
@@ -20,10 +11,11 @@ export async function authCommand(apiKey) {
|
|
|
20
11
|
}
|
|
21
12
|
else {
|
|
22
13
|
spinner.fail(chalk.red(result.message));
|
|
14
|
+
process.exitCode = 1;
|
|
23
15
|
console.log(chalk.yellow('\nTroubleshooting:'));
|
|
24
16
|
console.log(chalk.white(' - Check that your API key is correct'));
|
|
25
17
|
console.log(chalk.white(' - Verify the key is not revoked in the dashboard'));
|
|
26
|
-
console.log(chalk.white(' - Generate a new key: https://langctl.com/dashboard/settings/api-keys\n'));
|
|
18
|
+
console.log(chalk.white(' - Generate a new key: https://app.langctl.com/dashboard/settings/api-keys\n'));
|
|
27
19
|
}
|
|
28
20
|
}
|
|
29
21
|
export async function logoutCommand() {
|
package/dist/commands/config.js
CHANGED
|
@@ -9,6 +9,7 @@ export function configCommand() {
|
|
|
9
9
|
}
|
|
10
10
|
// Display config with masked sensitive values
|
|
11
11
|
const displayConfig = {
|
|
12
|
+
apiBaseUrl: allConfig.apiBaseUrl || 'https://api.langctl.com/api/v1 (default)',
|
|
12
13
|
apiKey: allConfig.apiKey ? maskApiKey(allConfig.apiKey) : undefined,
|
|
13
14
|
organizationId: allConfig.organizationId,
|
|
14
15
|
organizationName: allConfig.organizationName,
|
package/dist/commands/debug.js
CHANGED
|
@@ -1,57 +1,61 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import ora from 'ora';
|
|
3
|
-
import {
|
|
3
|
+
import { isAuthenticated } from '../auth.js';
|
|
4
|
+
import { getApiClient } from '../api.js';
|
|
5
|
+
import { config } from '../config.js';
|
|
4
6
|
export async function debugListApiKeys() {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
catch (e) {
|
|
10
|
-
console.error(chalk.red('✗ Failed to connect to Langctl servers.'));
|
|
7
|
+
if (!isAuthenticated()) {
|
|
8
|
+
console.log(chalk.red('✗ Not authenticated.\n'));
|
|
9
|
+
process.exitCode = 1;
|
|
11
10
|
return;
|
|
12
11
|
}
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
.
|
|
17
|
-
.select('id, name, key_prefix, organization_id, revoked, created_at, last_used_at')
|
|
18
|
-
.limit(100);
|
|
19
|
-
if (error) {
|
|
20
|
-
spinner.fail(chalk.red(`Error fetching API keys: ${error.message}`));
|
|
21
|
-
console.log(chalk.yellow('Hint: This is a debug command and may require elevated permissions.'));
|
|
12
|
+
const orgId = config.get('organizationId');
|
|
13
|
+
if (!orgId) {
|
|
14
|
+
console.log(chalk.red('✗ No organization configured.\n'));
|
|
15
|
+
process.exitCode = 1;
|
|
22
16
|
return;
|
|
23
17
|
}
|
|
24
|
-
spinner
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
console.log(
|
|
18
|
+
const spinner = ora('Testing API connection...').start();
|
|
19
|
+
try {
|
|
20
|
+
const api = getApiClient();
|
|
21
|
+
const org = await api.get(`/orgs/${orgId}`);
|
|
22
|
+
spinner.succeed(chalk.green(`API connection successful`));
|
|
23
|
+
console.log(chalk.blue.bold('\n🔧 Debug Info\n'));
|
|
24
|
+
console.log(chalk.white(`Organization: ${org.name}`));
|
|
25
|
+
console.log(chalk.white(`Plan: ${org.plan}`));
|
|
26
|
+
console.log(chalk.gray(`API URL: ${config.get('apiBaseUrl') || 'https://api.langctl.com/api/v1'}`));
|
|
27
|
+
console.log(chalk.gray(`Config: ${config.getConfigPath()}`));
|
|
28
|
+
console.log('');
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
spinner.fail(chalk.red('API connection failed'));
|
|
32
|
+
console.error(chalk.red(`Error: ${error.message}\n`));
|
|
33
|
+
process.exitCode = 1;
|
|
31
34
|
}
|
|
32
35
|
}
|
|
33
36
|
export async function debugListOrganizations() {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
catch (e) {
|
|
39
|
-
console.error(chalk.red('✗ Failed to connect to Langctl servers.'));
|
|
37
|
+
if (!isAuthenticated()) {
|
|
38
|
+
console.log(chalk.red('✗ Not authenticated.\n'));
|
|
39
|
+
process.exitCode = 1;
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
.
|
|
46
|
-
.select('id, name, plan, created_at')
|
|
47
|
-
.limit(100);
|
|
48
|
-
if (error) {
|
|
49
|
-
spinner.fail(chalk.red(`Error fetching organizations: ${error.message}`));
|
|
42
|
+
const orgId = config.get('organizationId');
|
|
43
|
+
if (!orgId) {
|
|
44
|
+
console.log(chalk.red('✗ No organization configured.\n'));
|
|
45
|
+
process.exitCode = 1;
|
|
50
46
|
return;
|
|
51
47
|
}
|
|
52
|
-
spinner
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
48
|
+
const spinner = ora('Fetching organization...').start();
|
|
49
|
+
try {
|
|
50
|
+
const api = getApiClient();
|
|
51
|
+
const org = await api.get(`/orgs/${orgId}`);
|
|
52
|
+
spinner.succeed(chalk.green('Found organization'));
|
|
53
|
+
console.log(`${chalk.cyan(org.id)} ${chalk.white(org.name)} plan=${chalk.magenta(org.plan)} created=${chalk.gray(org.createdAt)}`);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
spinner.fail(chalk.red('Failed to fetch organization'));
|
|
57
|
+
console.error(chalk.red(`Error: ${error.message}\n`));
|
|
58
|
+
process.exitCode = 1;
|
|
59
|
+
}
|
|
56
60
|
}
|
|
57
61
|
//# sourceMappingURL=debug.js.map
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
type ExportFormat = 'i18n-json' | 'android-xml' | 'ios-strings' | 'flutter-arb' | 'flat-json' | 'nested-json';
|
|
2
1
|
interface ExportOptions {
|
|
3
2
|
language?: string;
|
|
4
|
-
format?:
|
|
3
|
+
format?: string;
|
|
5
4
|
output?: string;
|
|
6
5
|
module?: string;
|
|
7
6
|
includeUnpublished?: boolean;
|