langctl 0.1.2 → 0.3.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.
Files changed (63) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/LICENSE +1 -1
  3. package/README.md +159 -1151
  4. package/dist/commands/auth.js +82 -24
  5. package/dist/commands/config.js +36 -25
  6. package/dist/commands/export.js +11 -112
  7. package/dist/commands/import.js +32 -164
  8. package/dist/commands/init.js +59 -80
  9. package/dist/commands/keys.js +145 -381
  10. package/dist/commands/org.js +45 -140
  11. package/dist/commands/projects.js +125 -390
  12. package/dist/commands/pull.js +78 -183
  13. package/dist/commands/push.js +125 -0
  14. package/dist/commands/team.js +68 -272
  15. package/dist/core/config.js +130 -0
  16. package/dist/core/errors.js +67 -0
  17. package/dist/core/files.js +38 -0
  18. package/dist/core/http.js +121 -0
  19. package/dist/core/output.js +96 -0
  20. package/dist/core/project.js +58 -0
  21. package/dist/core/prompts.js +56 -0
  22. package/dist/formats/index.js +285 -0
  23. package/dist/index.js +261 -508
  24. package/dist/version.js +4 -0
  25. package/package.json +22 -16
  26. package/.gitattributes +0 -2
  27. package/NEXT_PHASE.md +0 -618
  28. package/WORKING_INSTRUCTIONS.md +0 -1389
  29. package/dist/auth.d.ts +0 -37
  30. package/dist/auth.js +0 -112
  31. package/dist/commands/auth.d.ts +0 -3
  32. package/dist/commands/config.d.ts +0 -2
  33. package/dist/commands/debug.d.ts +0 -3
  34. package/dist/commands/debug.js +0 -57
  35. package/dist/commands/export.d.ts +0 -14
  36. package/dist/commands/import.d.ts +0 -11
  37. package/dist/commands/init.d.ts +0 -2
  38. package/dist/commands/keys.d.ts +0 -25
  39. package/dist/commands/org.d.ts +0 -13
  40. package/dist/commands/projects.d.ts +0 -30
  41. package/dist/commands/pull.d.ts +0 -9
  42. package/dist/commands/team.d.ts +0 -29
  43. package/dist/config.d.ts +0 -47
  44. package/dist/config.js +0 -69
  45. package/dist/exporters/index.d.ts +0 -36
  46. package/dist/exporters/index.js +0 -214
  47. package/dist/index.d.ts +0 -3
  48. package/dist/supabase.d.ts +0 -14
  49. package/dist/supabase.js +0 -30
  50. package/dist/utils/banner.d.ts +0 -9
  51. package/dist/utils/banner.js +0 -24
  52. package/translations/en.json +0 -5
  53. package/translations/en.xml +0 -9
  54. package/translations/fr.json +0 -4
  55. package/translations/fr.xml +0 -7
  56. package/translations/hi.json +0 -4
  57. package/translations/hi.xml +0 -7
  58. package/translations/ios/en.strings +0 -9
  59. package/translations/ios/fr.strings +0 -6
  60. package/translations/ios/hi.strings +0 -6
  61. package/translations/ios/ja.strings +0 -6
  62. package/translations/ja.json +0 -4
  63. package/translations/ja.xml +0 -7
package/dist/auth.d.ts DELETED
@@ -1,37 +0,0 @@
1
- export interface ApiKeyData {
2
- organization_id: string;
3
- organization: {
4
- id: string;
5
- name: string;
6
- plan: string;
7
- };
8
- }
9
- /**
10
- * Verify API key via Edge Function
11
- */
12
- export declare function verifyApiKey(plainTextKey: string): Promise<ApiKeyData | null>;
13
- /**
14
- * Authenticate and save credentials to config
15
- */
16
- export declare function authenticate(apiKey: string): Promise<{
17
- success: boolean;
18
- message: string;
19
- data?: ApiKeyData;
20
- }>;
21
- /**
22
- * Check if user is authenticated
23
- */
24
- export declare function isAuthenticated(): boolean;
25
- /**
26
- * Get current organization ID
27
- */
28
- export declare function getOrganizationId(): string | undefined;
29
- /**
30
- * Get current API key
31
- */
32
- export declare function getApiKey(): string | undefined;
33
- /**
34
- * Logout (clear authentication)
35
- */
36
- export declare function logout(): void;
37
- //# sourceMappingURL=auth.d.ts.map
package/dist/auth.js DELETED
@@ -1,112 +0,0 @@
1
- import { config } from './config.js';
2
- // Edge Function URL
3
- const EDGE_FUNCTION_URL = 'https://bcgnmvkgkbhbxzzflwdb.supabase.co/functions/v1/verify-api-key';
4
- // Normalize and validate API key input
5
- function sanitizeApiKey(input) {
6
- const raw = (input || '').trim().toLowerCase();
7
- if (!raw.startsWith('lc_')) {
8
- return { ok: false, message: 'API key must start with lc_' };
9
- }
10
- const hex = raw.slice(3); // after lc_
11
- const hexOnly = hex.replace(/[^a-f0-9]/g, '');
12
- if (hexOnly.length !== 64) {
13
- return { ok: false, message: 'Invalid API key format. Expected lc_ followed by 64 hex characters' };
14
- }
15
- return { ok: true, key: `lc_${hexOnly}` };
16
- }
17
- /**
18
- * Verify API key via Edge Function
19
- */
20
- export async function verifyApiKey(plainTextKey) {
21
- try {
22
- const sanitized = sanitizeApiKey(plainTextKey);
23
- if (!sanitized.ok || !sanitized.key) {
24
- return null;
25
- }
26
- // Call Edge Function
27
- const response = await fetch(EDGE_FUNCTION_URL, {
28
- method: 'POST',
29
- headers: {
30
- 'Content-Type': 'application/json',
31
- },
32
- body: JSON.stringify({ apiKey: sanitized.key })
33
- });
34
- if (!response.ok) {
35
- return null;
36
- }
37
- const data = await response.json();
38
- if (!data.success) {
39
- return null;
40
- }
41
- // Map Edge Function response to ApiKeyData format
42
- return {
43
- organization_id: data.organizationId,
44
- organization: {
45
- id: data.organizationId,
46
- name: data.organizationName,
47
- plan: data.plan
48
- }
49
- };
50
- }
51
- catch (error) {
52
- console.error('Error verifying API key:', error);
53
- return null;
54
- }
55
- }
56
- /**
57
- * Authenticate and save credentials to config
58
- */
59
- export async function authenticate(apiKey) {
60
- const sanitized = sanitizeApiKey(apiKey);
61
- if (!sanitized.ok || !sanitized.key) {
62
- return {
63
- success: false,
64
- message: sanitized.message || 'Invalid API key format. Expected format: lc_[64 hex characters]'
65
- };
66
- }
67
- // Verify via Edge Function
68
- const keyData = await verifyApiKey(sanitized.key);
69
- if (!keyData) {
70
- return {
71
- success: false,
72
- message: 'Invalid or revoked API key. Please check your key and try again.'
73
- };
74
- }
75
- // Save to config
76
- config.set('apiKey', sanitized.key);
77
- config.set('organizationId', keyData.organization_id);
78
- config.set('organizationName', keyData.organization.name);
79
- return {
80
- success: true,
81
- message: `Successfully authenticated as ${keyData.organization.name}`,
82
- data: keyData
83
- };
84
- }
85
- /**
86
- * Check if user is authenticated
87
- */
88
- export function isAuthenticated() {
89
- return !!(config.get('apiKey') && config.get('organizationId'));
90
- }
91
- /**
92
- * Get current organization ID
93
- */
94
- export function getOrganizationId() {
95
- return config.get('organizationId');
96
- }
97
- /**
98
- * Get current API key
99
- */
100
- export function getApiKey() {
101
- return config.get('apiKey');
102
- }
103
- /**
104
- * Logout (clear authentication)
105
- */
106
- export function logout() {
107
- config.delete('apiKey');
108
- config.delete('organizationId');
109
- config.delete('organizationName');
110
- config.delete('defaultProject');
111
- }
112
- //# sourceMappingURL=auth.js.map
@@ -1,3 +0,0 @@
1
- export declare function authCommand(apiKey: string): Promise<void>;
2
- export declare function logoutCommand(): Promise<void>;
3
- //# sourceMappingURL=auth.d.ts.map
@@ -1,2 +0,0 @@
1
- export declare function configCommand(): void;
2
- //# sourceMappingURL=config.d.ts.map
@@ -1,3 +0,0 @@
1
- export declare function debugListApiKeys(): Promise<void>;
2
- export declare function debugListOrganizations(): Promise<void>;
3
- //# sourceMappingURL=debug.d.ts.map
@@ -1,57 +0,0 @@
1
- import chalk from 'chalk';
2
- import ora from 'ora';
3
- import { getSupabase, initializeSupabase } from '../supabase.js';
4
- export async function debugListApiKeys() {
5
- // Initialize supabase (with hardcoded credentials)
6
- try {
7
- initializeSupabase();
8
- }
9
- catch (e) {
10
- console.error(chalk.red('✗ Failed to connect to Langctl servers.'));
11
- return;
12
- }
13
- const supabase = getSupabase();
14
- const spinner = ora('Fetching API keys (debug)...').start();
15
- const { data, error } = await supabase
16
- .from('api_keys')
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.'));
22
- return;
23
- }
24
- spinner.succeed(chalk.green(`Found ${data?.length || 0} API keys`));
25
- if (!data || data.length === 0) {
26
- console.log(chalk.yellow('No API keys visible with current permissions.'));
27
- return;
28
- }
29
- for (const row of data) {
30
- console.log(`${chalk.cyan(row.id)} ${chalk.white(row.name)} prefix=${chalk.magenta(row.key_prefix)} org=${chalk.yellow(row.organization_id)} revoked=${row.revoked ? chalk.red('true') : chalk.green('false')} last_used=${chalk.gray(row.last_used_at || 'never')}`);
31
- }
32
- }
33
- export async function debugListOrganizations() {
34
- // Initialize supabase (with hardcoded credentials)
35
- try {
36
- initializeSupabase();
37
- }
38
- catch (e) {
39
- console.error(chalk.red('✗ Failed to connect to Langctl servers.'));
40
- return;
41
- }
42
- const supabase = getSupabase();
43
- const spinner = ora('Fetching organizations (debug)...').start();
44
- const { data, error } = await supabase
45
- .from('organizations')
46
- .select('id, name, plan, created_at')
47
- .limit(100);
48
- if (error) {
49
- spinner.fail(chalk.red(`Error fetching organizations: ${error.message}`));
50
- return;
51
- }
52
- spinner.succeed(chalk.green(`Found ${data?.length || 0} organizations`));
53
- (data || []).forEach(o => {
54
- console.log(`${chalk.cyan(o.id)} ${chalk.white(o.name)} plan=${chalk.magenta(o.plan)} created=${chalk.gray(o.created_at)}`);
55
- });
56
- }
57
- //# sourceMappingURL=debug.js.map
@@ -1,14 +0,0 @@
1
- type ExportFormat = 'i18n-json' | 'android-xml' | 'ios-strings' | 'flutter-arb' | 'flat-json' | 'nested-json';
2
- interface ExportOptions {
3
- language?: string;
4
- format?: ExportFormat;
5
- output?: string;
6
- module?: string;
7
- includeUnpublished?: boolean;
8
- }
9
- /**
10
- * Export translations command
11
- */
12
- export declare function exportCommand(projectSlug: string, options: ExportOptions): Promise<void>;
13
- export {};
14
- //# sourceMappingURL=export.d.ts.map
@@ -1,11 +0,0 @@
1
- interface ImportOptions {
2
- language: string;
3
- overwrite?: boolean;
4
- publish?: boolean;
5
- }
6
- /**
7
- * Import translations command
8
- */
9
- export declare function importCommand(projectSlug: string, filePath: string, options: ImportOptions): Promise<void>;
10
- export {};
11
- //# sourceMappingURL=import.d.ts.map
@@ -1,2 +0,0 @@
1
- export declare function initCommand(): Promise<void>;
2
- //# sourceMappingURL=init.d.ts.map
@@ -1,25 +0,0 @@
1
- /**
2
- * List translation keys
3
- */
4
- export declare function listKeysCommand(projectSlug: string, options: any): Promise<void>;
5
- /**
6
- * Get single key
7
- */
8
- export declare function getKeyCommand(projectSlug: string, keyName: string): Promise<void>;
9
- /**
10
- * Create translation key
11
- */
12
- export declare function createKeyCommand(projectSlug: string, keyName: string, options: any): Promise<void>;
13
- /**
14
- * Delete translation key
15
- */
16
- export declare function deleteKeyCommand(projectSlug: string, keyName: string): Promise<void>;
17
- /**
18
- * Update single translation
19
- */
20
- export declare function translateKeyCommand(projectSlug: string, keyName: string, options: any): Promise<void>;
21
- /**
22
- * Publish/unpublish keys
23
- */
24
- export declare function publishKeysCommand(projectSlug: string, keys: string[], options: any): Promise<void>;
25
- //# sourceMappingURL=keys.d.ts.map
@@ -1,13 +0,0 @@
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
@@ -1,30 +0,0 @@
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>;
30
- //# sourceMappingURL=projects.d.ts.map
@@ -1,9 +0,0 @@
1
- export interface PullOptions {
2
- language?: string;
3
- format?: string;
4
- output?: string;
5
- dir?: string;
6
- publishedOnly?: boolean;
7
- }
8
- export declare function pullCommand(projectIdentifier: string, options: PullOptions): Promise<void>;
9
- //# sourceMappingURL=pull.d.ts.map
@@ -1,29 +0,0 @@
1
- /**
2
- * List all team members
3
- */
4
- export declare function listTeamCommand(): Promise<void>;
5
- /**
6
- * Get team member details
7
- */
8
- export declare function getTeamMemberCommand(email: string): Promise<void>;
9
- /**
10
- * Invite team member
11
- */
12
- export declare function inviteTeamMemberCommand(email: string, options: any): Promise<void>;
13
- /**
14
- * Remove team member
15
- */
16
- export declare function removeTeamMemberCommand(email: string): Promise<void>;
17
- /**
18
- * Update team member role
19
- */
20
- export declare function updateTeamRoleCommand(email: string, role: string): Promise<void>;
21
- /**
22
- * List invitations
23
- */
24
- export declare function listInvitationsCommand(options: any): Promise<void>;
25
- /**
26
- * Revoke invitation
27
- */
28
- export declare function revokeInvitationCommand(email: string): Promise<void>;
29
- //# sourceMappingURL=team.d.ts.map
package/dist/config.d.ts DELETED
@@ -1,47 +0,0 @@
1
- export interface LangctlConfig {
2
- apiKey?: string;
3
- organizationId?: string;
4
- organizationName?: string;
5
- defaultProject?: string;
6
- defaultLanguage?: string;
7
- }
8
- declare class ConfigManager {
9
- private config;
10
- private configDir;
11
- constructor();
12
- /**
13
- * Get a configuration value
14
- */
15
- get<K extends keyof LangctlConfig>(key: K): LangctlConfig[K] | undefined;
16
- /**
17
- * Set a configuration value
18
- */
19
- set<K extends keyof LangctlConfig>(key: K, value: LangctlConfig[K]): void;
20
- /**
21
- * Get all configuration
22
- */
23
- getAll(): LangctlConfig;
24
- /**
25
- * Set multiple configuration values
26
- */
27
- setAll(config: Partial<LangctlConfig>): void;
28
- /**
29
- * Delete a configuration value
30
- */
31
- delete(key: keyof LangctlConfig): void;
32
- /**
33
- * Clear all configuration
34
- */
35
- clear(): void;
36
- /**
37
- * Check if user is authenticated
38
- */
39
- isConfigured(): boolean;
40
- /**
41
- * Get the configuration file path
42
- */
43
- getConfigPath(): string;
44
- }
45
- export declare const config: ConfigManager;
46
- export {};
47
- //# sourceMappingURL=config.d.ts.map
package/dist/config.js DELETED
@@ -1,69 +0,0 @@
1
- import Conf from 'conf';
2
- import { join } from 'path';
3
- import { homedir } from 'os';
4
- class ConfigManager {
5
- constructor() {
6
- this.configDir = join(homedir(), '.langctl');
7
- this.config = new Conf({
8
- projectName: 'langctl',
9
- cwd: this.configDir,
10
- configName: 'config'
11
- });
12
- }
13
- /**
14
- * Get a configuration value
15
- */
16
- get(key) {
17
- return this.config.get(key);
18
- }
19
- /**
20
- * Set a configuration value
21
- */
22
- set(key, value) {
23
- this.config.set(key, value);
24
- }
25
- /**
26
- * Get all configuration
27
- */
28
- getAll() {
29
- return this.config.store;
30
- }
31
- /**
32
- * Set multiple configuration values
33
- */
34
- setAll(config) {
35
- Object.entries(config).forEach(([key, value]) => {
36
- if (value !== undefined) {
37
- this.config.set(key, value);
38
- }
39
- });
40
- }
41
- /**
42
- * Delete a configuration value
43
- */
44
- delete(key) {
45
- this.config.delete(key);
46
- }
47
- /**
48
- * Clear all configuration
49
- */
50
- clear() {
51
- this.config.clear();
52
- }
53
- /**
54
- * Check if user is authenticated
55
- */
56
- isConfigured() {
57
- return !!(this.config.get('apiKey') &&
58
- this.config.get('organizationId'));
59
- }
60
- /**
61
- * Get the configuration file path
62
- */
63
- getConfigPath() {
64
- return this.config.path;
65
- }
66
- }
67
- // Singleton instance
68
- export const config = new ConfigManager();
69
- //# sourceMappingURL=config.js.map
@@ -1,36 +0,0 @@
1
- export interface TranslationKey {
2
- key: string;
3
- translations: Record<string, string>;
4
- description?: string;
5
- module?: string;
6
- }
7
- export type ExportFormat = 'json' | 'json-nested' | 'ios' | 'android' | 'flutter';
8
- export interface ExportResult {
9
- content: string;
10
- filename: string;
11
- }
12
- /**
13
- * Export as flat JSON (simple key-value pairs)
14
- */
15
- export declare function exportFlatJson(keys: TranslationKey[], languageCode: string): ExportResult;
16
- /**
17
- * Export as nested JSON (organized by key structure)
18
- */
19
- export declare function exportNestedJson(keys: TranslationKey[], languageCode: string): ExportResult;
20
- /**
21
- * Export as iOS .strings format
22
- */
23
- export declare function exportIosStrings(keys: TranslationKey[], languageCode: string): ExportResult;
24
- /**
25
- * Export as Android XML format
26
- */
27
- export declare function exportAndroidXml(keys: TranslationKey[], languageCode: string): ExportResult;
28
- /**
29
- * Export as Flutter ARB format
30
- */
31
- export declare function exportFlutterArb(keys: TranslationKey[], languageCode: string): ExportResult;
32
- /**
33
- * Export translations in the specified format
34
- */
35
- export declare function exportTranslations(keys: TranslationKey[], languageCode: string, format: ExportFormat): ExportResult;
36
- //# sourceMappingURL=index.d.ts.map