langctl 0.1.0 → 0.1.1
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/README.md +78 -63
- package/SECURITY_FIX.md +167 -0
- package/dist/commands/auth.js +1 -9
- package/dist/commands/config.js +4 -7
- package/dist/commands/debug.js +8 -14
- package/dist/commands/init.js +2 -8
- package/dist/config.d.ts +1 -3
- package/dist/config.js +2 -4
- package/dist/supabase.d.ts +4 -4
- package/dist/supabase.js +8 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,20 +18,24 @@ npx langctl --help
|
|
|
18
18
|
|
|
19
19
|
## Quick Start
|
|
20
20
|
|
|
21
|
-
### 1.
|
|
21
|
+
### 1. Get Your API Key
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Generate an API key from your Langctl dashboard:
|
|
24
|
+
1. Go to **Settings → API Keys**
|
|
25
|
+
2. Click **"Generate New Key"**
|
|
26
|
+
3. Copy the key (shown only once)
|
|
27
|
+
|
|
28
|
+
### 2. Authenticate
|
|
24
29
|
|
|
25
30
|
```bash
|
|
26
31
|
langctl init
|
|
27
32
|
```
|
|
28
33
|
|
|
29
|
-
This will:
|
|
30
|
-
-
|
|
31
|
-
- Authenticate with your API key (get one from the dashboard)
|
|
34
|
+
This interactive wizard will:
|
|
35
|
+
- Authenticate with your API key
|
|
32
36
|
- Set your default language preference
|
|
33
37
|
|
|
34
|
-
###
|
|
38
|
+
### 3. List Your Projects
|
|
35
39
|
|
|
36
40
|
View all projects you have access to:
|
|
37
41
|
|
|
@@ -39,7 +43,7 @@ View all projects you have access to:
|
|
|
39
43
|
langctl projects list
|
|
40
44
|
```
|
|
41
45
|
|
|
42
|
-
###
|
|
46
|
+
### 4. Pull Translations
|
|
43
47
|
|
|
44
48
|
Download translations for a project:
|
|
45
49
|
|
|
@@ -47,6 +51,8 @@ Download translations for a project:
|
|
|
47
51
|
langctl pull <project-id> --language en --format json
|
|
48
52
|
```
|
|
49
53
|
|
|
54
|
+
---
|
|
55
|
+
|
|
50
56
|
## Commands
|
|
51
57
|
|
|
52
58
|
### `langctl init`
|
|
@@ -99,14 +105,14 @@ langctl pull <project-id> [options]
|
|
|
99
105
|
|
|
100
106
|
**Options:**
|
|
101
107
|
|
|
102
|
-
- `-l, --language <code>` - Language code to pull (default: en)
|
|
103
|
-
- `-f, --format <type>` - Export format (default: json)
|
|
108
|
+
- `-l, --language <code>` - Language code to pull (default: `en`)
|
|
109
|
+
- `-f, --format <type>` - Export format (default: `json`)
|
|
104
110
|
- `json` - Flat JSON (key-value pairs)
|
|
105
111
|
- `json-nested` - Nested JSON (organized by key structure)
|
|
106
112
|
- `ios` - iOS .strings format
|
|
107
113
|
- `android` - Android XML format
|
|
108
114
|
- `flutter` - Flutter ARB format
|
|
109
|
-
- `-o, --output <path>` - Output file path (default:
|
|
115
|
+
- `-o, --output <path>` - Output file path (default: `./translations/`)
|
|
110
116
|
- `--no-published-only` - Include unpublished translations
|
|
111
117
|
|
|
112
118
|
**Examples:**
|
|
@@ -125,6 +131,8 @@ langctl pull abc-123 --language en --no-published-only
|
|
|
125
131
|
langctl pull abc-123 --language en --output ./locales/en.json
|
|
126
132
|
```
|
|
127
133
|
|
|
134
|
+
---
|
|
135
|
+
|
|
128
136
|
## Export Formats
|
|
129
137
|
|
|
130
138
|
### JSON (Flat)
|
|
@@ -153,7 +161,7 @@ Organized by key structure.
|
|
|
153
161
|
|
|
154
162
|
### iOS Strings
|
|
155
163
|
|
|
156
|
-
Standard iOS
|
|
164
|
+
Standard iOS `.strings` format.
|
|
157
165
|
|
|
158
166
|
```
|
|
159
167
|
"home.welcome" = "Welcome!";
|
|
@@ -191,36 +199,13 @@ Application Resource Bundle format for Flutter.
|
|
|
191
199
|
}
|
|
192
200
|
```
|
|
193
201
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
Configuration is stored in `~/.langctl/config.json`:
|
|
197
|
-
|
|
198
|
-
```json
|
|
199
|
-
{
|
|
200
|
-
"supabaseUrl": "https://xxx.supabase.co",
|
|
201
|
-
"supabaseAnonKey": "eyJ...",
|
|
202
|
-
"apiKey": "lc_...",
|
|
203
|
-
"organizationId": "uuid",
|
|
204
|
-
"organizationName": "Company Name",
|
|
205
|
-
"defaultProject": "uuid",
|
|
206
|
-
"defaultLanguage": "en"
|
|
207
|
-
}
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
## API Keys
|
|
211
|
-
|
|
212
|
-
Generate API keys from the Langctl dashboard:
|
|
213
|
-
|
|
214
|
-
1. Go to Settings → API Keys
|
|
215
|
-
2. Click "Generate New Key"
|
|
216
|
-
3. Copy the key (shown only once)
|
|
217
|
-
4. Use it with `langctl auth <key>` or `langctl init`
|
|
218
|
-
|
|
219
|
-
API keys are organization-scoped and provide access to all projects within that organization.
|
|
202
|
+
---
|
|
220
203
|
|
|
221
204
|
## CI/CD Integration
|
|
222
205
|
|
|
223
|
-
|
|
206
|
+
### GitHub Actions
|
|
207
|
+
|
|
208
|
+
Example workflow for daily translation syncs:
|
|
224
209
|
|
|
225
210
|
```yaml
|
|
226
211
|
name: Sync Translations
|
|
@@ -244,7 +229,7 @@ jobs:
|
|
|
244
229
|
- name: Install Langctl
|
|
245
230
|
run: npm install -g langctl
|
|
246
231
|
|
|
247
|
-
- name:
|
|
232
|
+
- name: Authenticate
|
|
248
233
|
env:
|
|
249
234
|
LANGCTL_API_KEY: ${{ secrets.LANGCTL_API_KEY }}
|
|
250
235
|
run: langctl auth $LANGCTL_API_KEY
|
|
@@ -263,50 +248,80 @@ jobs:
|
|
|
263
248
|
git push
|
|
264
249
|
```
|
|
265
250
|
|
|
266
|
-
|
|
251
|
+
**Setup:**
|
|
252
|
+
1. Add `LANGCTL_API_KEY` to your repository secrets
|
|
253
|
+
2. Add `PROJECT_ID` to your repository secrets
|
|
254
|
+
3. Adjust languages and format as needed
|
|
267
255
|
|
|
268
|
-
|
|
256
|
+
---
|
|
269
257
|
|
|
270
|
-
|
|
258
|
+
## Troubleshooting
|
|
271
259
|
|
|
272
|
-
### "
|
|
260
|
+
### "Not authenticated" error
|
|
273
261
|
|
|
274
|
-
Run `langctl init`
|
|
262
|
+
**Solution:** Run `langctl init` or `langctl auth <api-key>` to authenticate.
|
|
275
263
|
|
|
276
264
|
### "Project not found" error
|
|
277
265
|
|
|
278
|
-
|
|
279
|
-
-
|
|
266
|
+
**Possible causes:**
|
|
267
|
+
- Invalid project ID - verify with `langctl projects list`
|
|
268
|
+
- API key doesn't have access to the project
|
|
269
|
+
- Project belongs to different organization
|
|
280
270
|
|
|
281
271
|
### Invalid API key format
|
|
282
272
|
|
|
283
|
-
API keys
|
|
273
|
+
API keys must:
|
|
284
274
|
- Start with `lc_`
|
|
285
|
-
- Be 67 characters long
|
|
286
|
-
- Be generated from the Langctl dashboard
|
|
275
|
+
- Be 67 characters long (including `lc_` prefix)
|
|
276
|
+
- Be generated from the Langctl dashboard at [langctl.com](https://langctl.com)
|
|
287
277
|
|
|
288
|
-
|
|
278
|
+
### Connection issues
|
|
289
279
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
280
|
+
If you experience connectivity problems:
|
|
281
|
+
- Check your internet connection
|
|
282
|
+
- Verify you're not behind a restrictive firewall
|
|
283
|
+
- Try again in a few moments
|
|
284
|
+
|
|
285
|
+
---
|
|
293
286
|
|
|
294
|
-
|
|
295
|
-
npm run build
|
|
287
|
+
## API Keys
|
|
296
288
|
|
|
297
|
-
|
|
298
|
-
npm run dev
|
|
289
|
+
API keys are **organization-scoped** and provide access to all projects within that organization.
|
|
299
290
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
291
|
+
**Security best practices:**
|
|
292
|
+
- ✅ Store API keys in environment variables or secrets managers
|
|
293
|
+
- ✅ Use different keys for development and production
|
|
294
|
+
- ✅ Rotate keys periodically
|
|
295
|
+
- ❌ Never commit API keys to version control
|
|
296
|
+
- ❌ Never share API keys publicly
|
|
303
297
|
|
|
304
|
-
|
|
298
|
+
**Revoke compromised keys immediately** from your dashboard.
|
|
305
299
|
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## Platform Support
|
|
303
|
+
|
|
304
|
+
- ✅ macOS (Apple Silicon & Intel)
|
|
305
|
+
- ✅ Linux (x64, ARM)
|
|
306
|
+
- ✅ Windows (x64)
|
|
307
|
+
- ✅ Node.js 16.0.0+
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## Links
|
|
312
|
+
|
|
313
|
+
- **Dashboard:** [app.langctl.com](https://app.langctl.com)
|
|
306
314
|
- **Documentation:** [langctl.com/docs](https://langctl.com/docs)
|
|
315
|
+
- **GitHub:** [github.com/siddharthsaxena0/langctl](https://github.com/siddharthsaxena0/langctl)
|
|
307
316
|
- **Issues:** [github.com/siddharthsaxena0/langctl/issues](https://github.com/siddharthsaxena0/langctl/issues)
|
|
308
|
-
- **Email:** hello@langctl.com
|
|
317
|
+
- **Email:** [hello@langctl.com](mailto:hello@langctl.com)
|
|
318
|
+
|
|
319
|
+
---
|
|
309
320
|
|
|
310
321
|
## License
|
|
311
322
|
|
|
312
|
-
MIT
|
|
323
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
**Made with ❤️ by the Langctl team**
|
package/SECURITY_FIX.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# 🔒 Security Fix - Supabase Credentials
|
|
2
|
+
|
|
3
|
+
**Date:** January 5, 2026
|
|
4
|
+
**Issue:** Supabase credentials were being stored in user config files
|
|
5
|
+
**Status:** ✅ FIXED
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 🚨 What Was Wrong
|
|
10
|
+
|
|
11
|
+
Previously, the CLI was:
|
|
12
|
+
- ❌ Storing Supabase URL in `~/.langctl/config.json`
|
|
13
|
+
- ❌ Storing Supabase anon key in `~/.langctl/config.json`
|
|
14
|
+
- ❌ Asking users about "Supabase configuration" during init
|
|
15
|
+
- ❌ Exposing backend implementation details to users
|
|
16
|
+
|
|
17
|
+
**Why this was bad:**
|
|
18
|
+
- Users could see our backend credentials
|
|
19
|
+
- Users could manipulate Supabase connection
|
|
20
|
+
- Exposed unnecessary implementation details
|
|
21
|
+
- Confused users with technical jargon
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## ✅ What's Fixed
|
|
26
|
+
|
|
27
|
+
Now the CLI:
|
|
28
|
+
- ✅ Hardcodes Supabase credentials in source code
|
|
29
|
+
- ✅ Only stores user credentials (API key, org ID, preferences)
|
|
30
|
+
- ✅ Users never see or interact with Supabase
|
|
31
|
+
- ✅ Clean, simple user experience
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 📄 Files Changed
|
|
36
|
+
|
|
37
|
+
### 1. `src/config.ts`
|
|
38
|
+
**Removed from interface:**
|
|
39
|
+
```typescript
|
|
40
|
+
// REMOVED - no longer stored
|
|
41
|
+
supabaseUrl?: string;
|
|
42
|
+
supabaseAnonKey?: string;
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Now only stores:**
|
|
46
|
+
```typescript
|
|
47
|
+
apiKey?: string; // User's API key
|
|
48
|
+
organizationId?: string; // User's org ID
|
|
49
|
+
organizationName?: string; // User's org name
|
|
50
|
+
defaultProject?: string; // User preference
|
|
51
|
+
defaultLanguage?: string; // User preference
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 2. `src/supabase.ts`
|
|
55
|
+
**Before:**
|
|
56
|
+
```typescript
|
|
57
|
+
// BAD - pulled from user config
|
|
58
|
+
const supabaseUrl = config.get('supabaseUrl');
|
|
59
|
+
const supabaseAnonKey = config.get('supabaseAnonKey');
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**After:**
|
|
63
|
+
```typescript
|
|
64
|
+
// GOOD - hardcoded in source
|
|
65
|
+
const SUPABASE_URL = 'https://bcgnmvkgkbhbxzzflwdb.supabase.co';
|
|
66
|
+
const SUPABASE_ANON_KEY = 'eyJhbGci...';
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 3. `src/commands/init.ts`
|
|
70
|
+
**Before:**
|
|
71
|
+
```typescript
|
|
72
|
+
// BAD - saved to user config
|
|
73
|
+
config.set('supabaseUrl', SUPABASE_URL);
|
|
74
|
+
config.set('supabaseAnonKey', SUPABASE_ANON_KEY);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**After:**
|
|
78
|
+
```typescript
|
|
79
|
+
// GOOD - just initializes, doesn't save
|
|
80
|
+
initializeSupabase();
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 4. `src/commands/config.ts`
|
|
84
|
+
**Before:**
|
|
85
|
+
```typescript
|
|
86
|
+
// BAD - displayed Supabase credentials
|
|
87
|
+
supabaseAnonKey: allConfig.supabaseAnonKey ? maskSensitive(...) : undefined
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**After:**
|
|
91
|
+
```typescript
|
|
92
|
+
// GOOD - only displays user data
|
|
93
|
+
apiKey: allConfig.apiKey ? maskApiKey(allConfig.apiKey) : undefined,
|
|
94
|
+
organizationId: allConfig.organizationId,
|
|
95
|
+
organizationName: allConfig.organizationName
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## 🔐 Security Notes
|
|
101
|
+
|
|
102
|
+
**Is it safe to hardcode Supabase credentials in the CLI?**
|
|
103
|
+
|
|
104
|
+
✅ **YES!** This is perfectly safe because:
|
|
105
|
+
|
|
106
|
+
1. **Anon key is designed for client-side use**
|
|
107
|
+
- It's meant to be public-facing
|
|
108
|
+
- Row Level Security (RLS) protects all data
|
|
109
|
+
- Users can only access what they're authorized for
|
|
110
|
+
|
|
111
|
+
2. **RLS policies enforce security**
|
|
112
|
+
- Users can only see their own organization data
|
|
113
|
+
- API key verification happens server-side (Edge Function)
|
|
114
|
+
- All operations are protected by RLS
|
|
115
|
+
|
|
116
|
+
3. **This is standard practice**
|
|
117
|
+
- Same as mobile apps that embed API credentials
|
|
118
|
+
- Same as web apps that expose client keys
|
|
119
|
+
- Backend security, not client security
|
|
120
|
+
|
|
121
|
+
**What if someone decompiles the CLI?**
|
|
122
|
+
- They'll see the Supabase URL and anon key
|
|
123
|
+
- But they CANNOT access data without a valid API key
|
|
124
|
+
- API keys are user-specific and verified server-side
|
|
125
|
+
- RLS prevents unauthorized access
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## 📊 What Users See Now
|
|
130
|
+
|
|
131
|
+
### Config File (`~/.langctl/config.json`)
|
|
132
|
+
```json
|
|
133
|
+
{
|
|
134
|
+
"apiKey": "lc_abc123...",
|
|
135
|
+
"organizationId": "uuid-here",
|
|
136
|
+
"organizationName": "My Company",
|
|
137
|
+
"defaultLanguage": "en"
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Clean and simple!** No backend implementation details.
|
|
142
|
+
|
|
143
|
+
### Running `langctl config`
|
|
144
|
+
```
|
|
145
|
+
📋 Langctl Configuration
|
|
146
|
+
|
|
147
|
+
apiKey: lc_abc123...wxyz
|
|
148
|
+
organizationId: 550e8400-e29b-41d4-a716-446655440000
|
|
149
|
+
organizationName: My Company
|
|
150
|
+
defaultLanguage: en
|
|
151
|
+
|
|
152
|
+
Config file: /Users/username/.langctl/config.json
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Only user-relevant information!**
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## ✅ Ready to Publish
|
|
160
|
+
|
|
161
|
+
This security fix is complete. The CLI now:
|
|
162
|
+
- ✅ Keeps backend credentials private
|
|
163
|
+
- ✅ Only exposes user data to users
|
|
164
|
+
- ✅ Maintains full security with RLS
|
|
165
|
+
- ✅ Provides clean user experience
|
|
166
|
+
|
|
167
|
+
**Safe to publish to npm!** 🚀
|
package/dist/commands/auth.js
CHANGED
|
@@ -3,16 +3,8 @@ import ora from 'ora';
|
|
|
3
3
|
import { authenticate, logout } from '../auth.js';
|
|
4
4
|
import { config } from '../config.js';
|
|
5
5
|
import { initializeSupabase } from '../supabase.js';
|
|
6
|
-
// Hardcoded Supabase credentials
|
|
7
|
-
const SUPABASE_URL = 'https://bcgnmvkgkbhbxzzflwdb.supabase.co';
|
|
8
|
-
const SUPABASE_ANON_KEY = 'sb_publishable_WCpKr-NwubrPtOj2E0cvAQ_TzvfXsNB';
|
|
9
6
|
export async function authCommand(apiKey) {
|
|
10
|
-
//
|
|
11
|
-
if (!config.get('supabaseUrl')) {
|
|
12
|
-
config.set('supabaseUrl', SUPABASE_URL);
|
|
13
|
-
config.set('supabaseAnonKey', SUPABASE_ANON_KEY);
|
|
14
|
-
}
|
|
15
|
-
// Initialize Supabase
|
|
7
|
+
// Initialize Supabase (with hardcoded credentials)
|
|
16
8
|
try {
|
|
17
9
|
initializeSupabase();
|
|
18
10
|
}
|
package/dist/commands/config.js
CHANGED
|
@@ -9,9 +9,11 @@ export function configCommand() {
|
|
|
9
9
|
}
|
|
10
10
|
// Display config with masked sensitive values
|
|
11
11
|
const displayConfig = {
|
|
12
|
-
...allConfig,
|
|
13
12
|
apiKey: allConfig.apiKey ? maskApiKey(allConfig.apiKey) : undefined,
|
|
14
|
-
|
|
13
|
+
organizationId: allConfig.organizationId,
|
|
14
|
+
organizationName: allConfig.organizationName,
|
|
15
|
+
defaultProject: allConfig.defaultProject,
|
|
16
|
+
defaultLanguage: allConfig.defaultLanguage
|
|
15
17
|
};
|
|
16
18
|
Object.entries(displayConfig).forEach(([key, value]) => {
|
|
17
19
|
if (value !== undefined) {
|
|
@@ -25,9 +27,4 @@ function maskApiKey(key) {
|
|
|
25
27
|
return '***';
|
|
26
28
|
return `${key.substring(0, 10)}...${key.substring(key.length - 4)}`;
|
|
27
29
|
}
|
|
28
|
-
function maskSensitive(value) {
|
|
29
|
-
if (value.length < 8)
|
|
30
|
-
return '***';
|
|
31
|
-
return `${value.substring(0, 8)}...`;
|
|
32
|
-
}
|
|
33
30
|
//# sourceMappingURL=config.js.map
|
package/dist/commands/debug.js
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import ora from 'ora';
|
|
3
3
|
import { getSupabase, initializeSupabase } from '../supabase.js';
|
|
4
|
-
import { config } from '../config.js';
|
|
5
4
|
export async function debugListApiKeys() {
|
|
6
|
-
//
|
|
7
|
-
const url = config.get('supabaseUrl');
|
|
8
|
-
const key = config.get('supabaseAnonKey');
|
|
5
|
+
// Initialize supabase (with hardcoded credentials)
|
|
9
6
|
try {
|
|
10
|
-
initializeSupabase(
|
|
7
|
+
initializeSupabase();
|
|
11
8
|
}
|
|
12
9
|
catch (e) {
|
|
13
|
-
console.error(chalk.red('✗
|
|
10
|
+
console.error(chalk.red('✗ Failed to connect to Langctl servers.'));
|
|
14
11
|
return;
|
|
15
12
|
}
|
|
16
13
|
const supabase = getSupabase();
|
|
@@ -21,14 +18,12 @@ export async function debugListApiKeys() {
|
|
|
21
18
|
.limit(100);
|
|
22
19
|
if (error) {
|
|
23
20
|
spinner.fail(chalk.red(`Error fetching API keys: ${error.message}`));
|
|
24
|
-
console.log(chalk.yellow('Hint:
|
|
21
|
+
console.log(chalk.yellow('Hint: This is a debug command and may require elevated permissions.'));
|
|
25
22
|
return;
|
|
26
23
|
}
|
|
27
24
|
spinner.succeed(chalk.green(`Found ${data?.length || 0} API keys`));
|
|
28
25
|
if (!data || data.length === 0) {
|
|
29
|
-
console.log(chalk.yellow('No API keys visible with current
|
|
30
|
-
console.log(chalk.white(`Supabase URL: ${url}`));
|
|
31
|
-
console.log(chalk.white(`Anon key prefix: ${(key || '').substring(0, 12)}...`));
|
|
26
|
+
console.log(chalk.yellow('No API keys visible with current permissions.'));
|
|
32
27
|
return;
|
|
33
28
|
}
|
|
34
29
|
for (const row of data) {
|
|
@@ -36,13 +31,12 @@ export async function debugListApiKeys() {
|
|
|
36
31
|
}
|
|
37
32
|
}
|
|
38
33
|
export async function debugListOrganizations() {
|
|
39
|
-
|
|
40
|
-
const key = config.get('supabaseAnonKey');
|
|
34
|
+
// Initialize supabase (with hardcoded credentials)
|
|
41
35
|
try {
|
|
42
|
-
initializeSupabase(
|
|
36
|
+
initializeSupabase();
|
|
43
37
|
}
|
|
44
38
|
catch (e) {
|
|
45
|
-
console.error(chalk.red('✗
|
|
39
|
+
console.error(chalk.red('✗ Failed to connect to Langctl servers.'));
|
|
46
40
|
return;
|
|
47
41
|
}
|
|
48
42
|
const supabase = getSupabase();
|
package/dist/commands/init.js
CHANGED
|
@@ -5,9 +5,6 @@ import { config } from '../config.js';
|
|
|
5
5
|
import { authenticate } from '../auth.js';
|
|
6
6
|
import { initializeSupabase } from '../supabase.js';
|
|
7
7
|
import { showLogo } from '../utils/banner.js';
|
|
8
|
-
// Hardcoded Supabase credentials - users don't need to know about our backend
|
|
9
|
-
const SUPABASE_URL = 'https://bcgnmvkgkbhbxzzflwdb.supabase.co';
|
|
10
|
-
const SUPABASE_ANON_KEY = 'sb_publishable_WCpKr-NwubrPtOj2E0cvAQ_TzvfXsNB';
|
|
11
8
|
export async function initCommand() {
|
|
12
9
|
// Show logo
|
|
13
10
|
showLogo();
|
|
@@ -28,12 +25,9 @@ export async function initCommand() {
|
|
|
28
25
|
return;
|
|
29
26
|
}
|
|
30
27
|
}
|
|
31
|
-
//
|
|
32
|
-
config.set('supabaseUrl', SUPABASE_URL);
|
|
33
|
-
config.set('supabaseAnonKey', SUPABASE_ANON_KEY);
|
|
34
|
-
// Initialize Supabase client
|
|
28
|
+
// Initialize Supabase client (with hardcoded credentials - user doesn't need to know)
|
|
35
29
|
try {
|
|
36
|
-
initializeSupabase(
|
|
30
|
+
initializeSupabase();
|
|
37
31
|
}
|
|
38
32
|
catch (error) {
|
|
39
33
|
console.error(chalk.red('✗ Failed to connect to Langctl servers'));
|
package/dist/config.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
export interface LangctlConfig {
|
|
2
|
-
supabaseUrl?: string;
|
|
3
|
-
supabaseAnonKey?: string;
|
|
4
2
|
apiKey?: string;
|
|
5
3
|
organizationId?: string;
|
|
6
4
|
organizationName?: string;
|
|
@@ -36,7 +34,7 @@ declare class ConfigManager {
|
|
|
36
34
|
*/
|
|
37
35
|
clear(): void;
|
|
38
36
|
/**
|
|
39
|
-
* Check if
|
|
37
|
+
* Check if user is authenticated
|
|
40
38
|
*/
|
|
41
39
|
isConfigured(): boolean;
|
|
42
40
|
/**
|
package/dist/config.js
CHANGED
|
@@ -51,12 +51,10 @@ class ConfigManager {
|
|
|
51
51
|
this.config.clear();
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
54
|
-
* Check if
|
|
54
|
+
* Check if user is authenticated
|
|
55
55
|
*/
|
|
56
56
|
isConfigured() {
|
|
57
|
-
return !!(this.config.get('
|
|
58
|
-
this.config.get('supabaseAnonKey') &&
|
|
59
|
-
this.config.get('apiKey') &&
|
|
57
|
+
return !!(this.config.get('apiKey') &&
|
|
60
58
|
this.config.get('organizationId'));
|
|
61
59
|
}
|
|
62
60
|
/**
|
package/dist/supabase.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { SupabaseClient } from '@supabase/supabase-js';
|
|
2
2
|
/**
|
|
3
|
-
* Initialize Supabase client
|
|
3
|
+
* Initialize Supabase client with hardcoded credentials
|
|
4
4
|
*/
|
|
5
|
-
export declare function initializeSupabase(
|
|
5
|
+
export declare function initializeSupabase(): SupabaseClient;
|
|
6
6
|
/**
|
|
7
|
-
* Get existing Supabase client or
|
|
7
|
+
* Get existing Supabase client or initialize it
|
|
8
8
|
*/
|
|
9
9
|
export declare function getSupabase(): SupabaseClient;
|
|
10
10
|
/**
|
|
11
|
-
* Reset Supabase client (useful for tests
|
|
11
|
+
* Reset Supabase client (useful for tests)
|
|
12
12
|
*/
|
|
13
13
|
export declare function resetSupabase(): void;
|
|
14
14
|
//# sourceMappingURL=supabase.d.ts.map
|
package/dist/supabase.js
CHANGED
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
import { createClient } from '@supabase/supabase-js';
|
|
2
|
-
|
|
2
|
+
// Hardcoded Supabase credentials (safe for client-side use with RLS)
|
|
3
|
+
const SUPABASE_URL = 'https://bcgnmvkgkbhbxzzflwdb.supabase.co';
|
|
4
|
+
const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImJjZ25tdmtna2JoYnh6emZsd2RiIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzQ3OTE4ODEsImV4cCI6MjA1MDM2Nzg4MX0.LqZYO8GGQfI-C9WCF_a2NTKqIrO1TDsPXU9LHRE8b0E';
|
|
3
5
|
let supabaseClient = null;
|
|
4
6
|
/**
|
|
5
|
-
* Initialize Supabase client
|
|
7
|
+
* Initialize Supabase client with hardcoded credentials
|
|
6
8
|
*/
|
|
7
|
-
export function initializeSupabase(
|
|
8
|
-
const supabaseUrl = url || config.get('supabaseUrl');
|
|
9
|
-
const supabaseAnonKey = anonKey || config.get('supabaseAnonKey');
|
|
10
|
-
if (!supabaseUrl || !supabaseAnonKey) {
|
|
11
|
-
throw new Error('Supabase credentials not found. Please run "langctl init" first.');
|
|
12
|
-
}
|
|
9
|
+
export function initializeSupabase() {
|
|
13
10
|
if (!supabaseClient) {
|
|
14
|
-
supabaseClient = createClient(
|
|
11
|
+
supabaseClient = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
|
|
15
12
|
}
|
|
16
13
|
return supabaseClient;
|
|
17
14
|
}
|
|
18
15
|
/**
|
|
19
|
-
* Get existing Supabase client or
|
|
16
|
+
* Get existing Supabase client or initialize it
|
|
20
17
|
*/
|
|
21
18
|
export function getSupabase() {
|
|
22
19
|
if (!supabaseClient) {
|
|
@@ -25,7 +22,7 @@ export function getSupabase() {
|
|
|
25
22
|
return supabaseClient;
|
|
26
23
|
}
|
|
27
24
|
/**
|
|
28
|
-
* Reset Supabase client (useful for tests
|
|
25
|
+
* Reset Supabase client (useful for tests)
|
|
29
26
|
*/
|
|
30
27
|
export function resetSupabase() {
|
|
31
28
|
supabaseClient = null;
|