@webmate-studio/cli 0.3.44 → 0.3.46

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/bin/wm.js CHANGED
@@ -1,15 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { Command } from 'commander';
4
- import { buildCommand } from '../src/commands/build.js';
5
- import { pushCommand } from '../src/commands/push.js';
6
4
  import { devCommand } from '../src/commands/dev.js';
7
5
  import { initCommand } from '../src/commands/init.js';
8
- import { loginCommand } from '../src/commands/login.js';
9
6
  import { generate } from '../src/commands/generate.js';
10
- import { logout } from '../src/commands/logout.js';
11
- import { info } from '../src/commands/info.js';
12
- import { switchCommand } from '../src/commands/switch.js';
13
7
  import { readFileSync } from 'fs';
14
8
  import { fileURLToPath } from 'url';
15
9
  import { dirname, join } from 'path';
@@ -24,13 +18,6 @@ program
24
18
  .description('Webmate Component CLI - Build and manage HTML-first components')
25
19
  .version(packageJson.version);
26
20
 
27
- // wm login - Login to CMS
28
- program
29
- .command('login')
30
- .description('Login to Webmate CMS')
31
- .option('-u, --url <url>', 'CMS base URL')
32
- .action(loginCommand);
33
-
34
21
  // wm init - Create new component project
35
22
  program
36
23
  .command('init')
@@ -58,44 +45,4 @@ program
58
45
  .option('-o, --open', 'Open browser automatically')
59
46
  .action(devCommand);
60
47
 
61
- // wm build - Build components
62
- program
63
- .command('build')
64
- .description('Build components for production')
65
- .option('-o, --output <dir>', 'Output directory', './dist')
66
- .option('-m, --minify', 'Minify output')
67
- .option('--watch', 'Watch for changes')
68
- .action(buildCommand);
69
-
70
- // wm push - Upload to CMS
71
- program
72
- .command('push')
73
- .description('Upload components to CMS (auto-builds by default)')
74
- .option('-t, --target <url>', 'CMS target URL')
75
- .option('--token <token>', 'Authentication token')
76
- .option('-f, --force', 'Overwrite existing version (development only)')
77
- .option('--patch', 'Increment patch version (x.y.Z)')
78
- .option('--minor', 'Increment minor version (x.Y.0)')
79
- .option('--major', 'Increment major version (X.0.0)')
80
- .option('--no-build', 'Skip auto-build, use existing dist/ (for CI/CD)')
81
- .action(pushCommand);
82
-
83
- // wm logout - Logout from CMS
84
- program
85
- .command('logout')
86
- .description('Logout from Webmate CMS')
87
- .action(logout);
88
-
89
- // wm info - Show current project information
90
- program
91
- .command('info')
92
- .description('Show current project information')
93
- .action(info);
94
-
95
- // wm switch - Switch to a different project
96
- program
97
- .command('switch')
98
- .description('Switch to a different project')
99
- .action(switchCommand);
100
-
101
48
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webmate-studio/cli",
3
- "version": "0.3.44",
3
+ "version": "0.3.46",
4
4
  "type": "module",
5
5
  "description": "Webmate Studio CLI - Build and manage your Webmate components",
6
6
  "keywords": [
@@ -32,10 +32,10 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@inquirer/prompts": "^5.0.0",
35
- "@webmate-studio/builder": "^0.2.64",
35
+ "@webmate-studio/builder": "^0.2.66",
36
36
  "@webmate-studio/core": "^0.2.7",
37
37
  "@webmate-studio/parser": "^0.2.8",
38
- "@webmate-studio/preview": "^0.2.38",
38
+ "@webmate-studio/preview": "^0.2.39",
39
39
  "alpinejs": "^3.15.0",
40
40
  "commander": "^11.0.0",
41
41
  "esbuild": "^0.19.0",
@@ -1,113 +0,0 @@
1
- import { build as buildComponents } from '@webmate-studio/builder';
2
- import { logger } from '@webmate-studio/core';
3
- import { isLoggedIn, loadAuth, getTenantCmsUrl } from '../utils/auth.js';
4
- import ora from 'ora';
5
- import pc from 'picocolors';
6
-
7
- /**
8
- * Load design tokens from CMS
9
- */
10
- async function loadDesignTokens() {
11
- try {
12
- const auth = loadAuth();
13
- if (!auth || !auth.apiToken) {
14
- return null;
15
- }
16
-
17
- const cmsUrl = getTenantCmsUrl();
18
- if (!cmsUrl) {
19
- return null;
20
- }
21
-
22
- // Disable SSL verification for localhost
23
- const isLocalhost = cmsUrl.includes('localhost') || cmsUrl.includes('127.0.0.1');
24
- if (isLocalhost) {
25
- process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
26
- }
27
-
28
- const response = await fetch(`${cmsUrl}/api/design-tokens`, {
29
- headers: {
30
- 'x-api-token': auth.apiToken
31
- }
32
- });
33
-
34
- if (!response.ok) {
35
- logger.warn('Could not load design tokens from CMS');
36
- return null;
37
- }
38
-
39
- const data = await response.json();
40
-
41
- // Restore SSL verification
42
- if (isLocalhost) {
43
- delete process.env.NODE_TLS_REJECT_UNAUTHORIZED;
44
- }
45
-
46
- return data.tokens || null;
47
- } catch (error) {
48
- logger.warn(`Error loading design tokens: ${error.message}`);
49
- return null;
50
- }
51
- }
52
-
53
- /**
54
- * Build command - compile components to distribution
55
- * Requires login for project context
56
- */
57
- export async function buildCommand(options) {
58
- // Check if logged in
59
- if (!isLoggedIn()) {
60
- console.log('');
61
- logger.error('Nicht eingeloggt.');
62
- logger.info(`Bitte zuerst einloggen: ${pc.cyan('wm login')}`);
63
- console.log('');
64
- process.exit(1);
65
- }
66
-
67
- const auth = loadAuth();
68
- logger.info(`Projekt: ${pc.cyan(auth.tenant.name)}`);
69
-
70
- // Load design tokens from CMS
71
- const designTokens = await loadDesignTokens();
72
- if (designTokens) {
73
- logger.success('Loaded design tokens from CMS');
74
- } else {
75
- logger.info('Using default design tokens');
76
- }
77
-
78
- const spinner = ora('Building components...').start();
79
-
80
- try {
81
- const manifest = await buildComponents({
82
- outputDir: options.output,
83
- minify: options.minify || false,
84
- designTokens: designTokens // Pass design tokens to builder
85
- });
86
-
87
- spinner.succeed('Build complete!');
88
-
89
- logger.info(`\n📦 Built ${manifest.components.length} components`);
90
- logger.info(`📁 Output: ${options.output}`);
91
-
92
- if (manifest.styles.length > 0) {
93
- logger.info(`🎨 Styles: ${manifest.styles.length} files`);
94
- }
95
-
96
- if (manifest.islands) {
97
- logger.info(`🏝️ Islands: ${manifest.islands.files.length} files`);
98
- }
99
-
100
- // Show component list
101
- console.log('\n📋 Components:');
102
- for (const comp of manifest.components) {
103
- const propsCount = comp.props ? Object.keys(comp.props).length : 0;
104
- logger.info(` • ${comp.name} (${propsCount} props)`);
105
- }
106
-
107
- return manifest;
108
- } catch (error) {
109
- spinner.fail('Build failed');
110
- logger.error(error.message);
111
- process.exit(1);
112
- }
113
- }
@@ -1,49 +0,0 @@
1
- import { loadAuth } from '../utils/auth.js';
2
- import { logger } from '@webmate-studio/core';
3
- import pc from 'picocolors';
4
-
5
- /**
6
- * Info command - Show current project information
7
- */
8
- export async function info(options = {}) {
9
- try {
10
- const auth = loadAuth();
11
-
12
- if (!auth) {
13
- logger.error('Not logged in. Run ' + pc.cyan('wm login') + ' first');
14
- process.exit(1);
15
- }
16
-
17
- showProjectInfo(auth);
18
- } catch (error) {
19
- logger.error(`Info command failed: ${error.message}`);
20
- process.exit(1);
21
- }
22
- }
23
-
24
- /**
25
- * Show current project information
26
- */
27
- function showProjectInfo(auth) {
28
- console.log();
29
- logger.info(pc.bold('Current Project'));
30
- console.log();
31
-
32
- // Build CMS URL from base URL and tenant subdomain
33
- let cmsUrl = 'Not set';
34
- if (auth.baseUrl && auth.tenant?.subdomain) {
35
- try {
36
- const baseUrl = new URL(auth.baseUrl);
37
- const subdomain = auth.tenant.subdomain;
38
- cmsUrl = `${baseUrl.protocol}//${subdomain}.cms.${baseUrl.host}`;
39
- } catch (error) {
40
- cmsUrl = auth.baseUrl;
41
- }
42
- }
43
-
44
- console.log(pc.gray(' CMS URL: ') + pc.cyan(cmsUrl));
45
- console.log(pc.gray(' User: ') + pc.cyan(auth.user?.email || 'Not set'));
46
- console.log();
47
- console.log(pc.gray(' To switch project, run: ') + pc.cyan('wm switch'));
48
- console.log();
49
- }
@@ -1,233 +0,0 @@
1
- import { input, password, select } from '@inquirer/prompts';
2
- import { logger } from '@webmate-studio/core';
3
- import { saveAuth, loadAuth, getCmsBaseUrl } from '../utils/auth.js';
4
- import pc from 'picocolors';
5
-
6
- /**
7
- * Custom fetch wrapper that accepts self-signed certificates for localhost
8
- */
9
- async function secureFetch(url, options = {}) {
10
- const isLocalhost = url.includes('localhost') || url.includes('127.0.0.1');
11
-
12
- if (isLocalhost) {
13
- // Temporarily disable TLS verification for localhost
14
- const originalValue = process.env.NODE_TLS_REJECT_UNAUTHORIZED;
15
- process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
16
-
17
- try {
18
- return await fetch(url, options);
19
- } finally {
20
- // Restore original value
21
- if (originalValue !== undefined) {
22
- process.env.NODE_TLS_REJECT_UNAUTHORIZED = originalValue;
23
- } else {
24
- delete process.env.NODE_TLS_REJECT_UNAUTHORIZED;
25
- }
26
- }
27
- }
28
-
29
- // For non-localhost, use regular fetch
30
- return fetch(url, options);
31
- }
32
-
33
- /**
34
- * Login command - Interactive login flow
35
- */
36
- export async function loginCommand(options = {}) {
37
- console.log('');
38
- logger.info(pc.bold('Webmate CLI Login'));
39
- console.log('');
40
-
41
- try {
42
- // Check if already logged in
43
- const existingAuth = loadAuth();
44
- if (existingAuth?.user) {
45
- const shouldLogout = await select({
46
- message: `Bereits eingeloggt als ${pc.cyan(existingAuth.user.email)}. Neu anmelden?`,
47
- choices: [
48
- { name: 'Nein, weiter mit aktuellem Login', value: false },
49
- { name: 'Ja, neu anmelden', value: true }
50
- ]
51
- });
52
-
53
- if (!shouldLogout) {
54
- logger.info('Login abgebrochen');
55
- return;
56
- }
57
- }
58
-
59
- // Get base URL (optional, default to production)
60
- // Note: CLI API routes are under app subdomain
61
- const baseUrl = options.url || await input({
62
- message: 'Webmate Base URL:',
63
- default: 'https://app.webmate-studio.com',
64
- validate: (value) => {
65
- try {
66
- new URL(value);
67
- return true;
68
- } catch {
69
- return 'Bitte gültige URL eingeben';
70
- }
71
- }
72
- });
73
-
74
- // Get credentials
75
- const email = await input({
76
- message: 'E-Mail:',
77
- validate: (value) => {
78
- if (!value || !value.includes('@')) {
79
- return 'Bitte gültige E-Mail-Adresse eingeben';
80
- }
81
- return true;
82
- }
83
- });
84
-
85
- const pwd = await password({
86
- message: 'Passwort:',
87
- mask: '*'
88
- });
89
-
90
- console.log('');
91
- logger.info('Authentifiziere...');
92
-
93
- // Login API call
94
- const loginUrl = `${baseUrl}/api/cli/auth/login`;
95
- const loginResponse = await secureFetch(loginUrl, {
96
- method: 'POST',
97
- headers: { 'Content-Type': 'application/json' },
98
- body: JSON.stringify({ email, password: pwd })
99
- });
100
-
101
- if (!loginResponse.ok) {
102
- const error = await loginResponse.json();
103
- throw new Error(error.error || 'Login fehlgeschlagen');
104
- }
105
-
106
- const loginData = await loginResponse.json();
107
- logger.success(`Eingeloggt als ${pc.cyan(loginData.user.email)}`);
108
-
109
- // Get list of organizations
110
- console.log('');
111
- logger.info('Lade Organizations...');
112
-
113
- const organizationsUrl = `${baseUrl}/api/cli/organizations?userId=${loginData.user.id}`;
114
- const organizationsResponse = await secureFetch(organizationsUrl);
115
-
116
- if (!organizationsResponse.ok) {
117
- throw new Error('Fehler beim Laden der Organizations');
118
- }
119
-
120
- const organizationsData = await organizationsResponse.json();
121
-
122
- if (!organizationsData.organizations || organizationsData.organizations.length === 0) {
123
- logger.warning('Keine Organizations gefunden. Bitte erstelle zuerst eine Organization im CMS.');
124
- return;
125
- }
126
-
127
- // Let user select organization
128
- let selectedOrganizationId;
129
- if (organizationsData.organizations.length === 1) {
130
- // Auto-select if only one organization
131
- selectedOrganizationId = organizationsData.organizations[0].id;
132
- logger.info(`Organization: ${pc.cyan(organizationsData.organizations[0].name)}`);
133
- } else {
134
- console.log('');
135
- selectedOrganizationId = await select({
136
- message: 'Wähle eine Organization:',
137
- choices: organizationsData.organizations.map(org => ({
138
- name: `${org.name} (${org.role})`,
139
- value: org.id,
140
- description: `Erstellt am ${new Date(org.createdAt).toLocaleDateString('de-DE')}`
141
- }))
142
- });
143
- }
144
-
145
- const selectedOrganization = organizationsData.organizations.find(o => o.id === selectedOrganizationId);
146
-
147
- // Get list of tenants for selected organization
148
- console.log('');
149
- logger.info('Lade Projekte...');
150
-
151
- const tenantsUrl = `${baseUrl}/api/cli/organizations/${selectedOrganizationId}/tenants?userId=${loginData.user.id}`;
152
- const tenantsResponse = await secureFetch(tenantsUrl);
153
-
154
- if (!tenantsResponse.ok) {
155
- throw new Error('Fehler beim Laden der Projekte');
156
- }
157
-
158
- const tenantsData = await tenantsResponse.json();
159
-
160
- if (!tenantsData.tenants || tenantsData.tenants.length === 0) {
161
- logger.warning('Keine Projekte in dieser Organization gefunden. Bitte erstelle zuerst ein Projekt im CMS.');
162
- return;
163
- }
164
-
165
- // Let user select tenant
166
- console.log('');
167
- const selectedTenantId = await select({
168
- message: 'Wähle ein Projekt:',
169
- choices: tenantsData.tenants.map(t => ({
170
- name: `${t.name} (${t.subdomain})`,
171
- value: t.id,
172
- description: `Erstellt am ${new Date(t.createdAt).toLocaleDateString('de-DE')}`
173
- }))
174
- });
175
-
176
- const selectedTenant = tenantsData.tenants.find(t => t.id === selectedTenantId);
177
-
178
- // Generate API token for selected tenant
179
- console.log('');
180
- logger.info('Generiere API-Token...');
181
-
182
- const tokenUrl = `${baseUrl}/api/cli/tenants`;
183
- const tokenResponse = await secureFetch(tokenUrl, {
184
- method: 'POST',
185
- headers: { 'Content-Type': 'application/json' },
186
- body: JSON.stringify({
187
- userId: loginData.user.id,
188
- tenantId: selectedTenantId
189
- })
190
- });
191
-
192
- if (!tokenResponse.ok) {
193
- throw new Error('Fehler beim Generieren des API-Tokens');
194
- }
195
-
196
- const tokenData = await tokenResponse.json();
197
-
198
- // Save auth data
199
- saveAuth({
200
- user: loginData.user,
201
- organization: selectedOrganization,
202
- tenant: selectedTenant,
203
- apiToken: tokenData.apiToken,
204
- baseUrl,
205
- loginAt: new Date().toISOString()
206
- });
207
-
208
- console.log('');
209
- logger.success(pc.green('✨ Login erfolgreich!'));
210
- console.log('');
211
- console.log(` ${pc.bold('Organization:')} ${pc.cyan(selectedOrganization.name)}`);
212
- console.log(` ${pc.bold('Projekt:')} ${pc.cyan(selectedTenant.name)}`);
213
- console.log(` ${pc.bold('Subdomain:')} ${pc.cyan(selectedTenant.subdomain)}`);
214
- console.log('');
215
- console.log(`${pc.gray('Du kannst jetzt')} ${pc.cyan('wm dev')} ${pc.gray('und')} ${pc.cyan('wm push')} ${pc.gray('verwenden.')}`);
216
- console.log('');
217
-
218
- } catch (error) {
219
- console.log('');
220
- logger.error(`Login fehlgeschlagen: ${error.message}`);
221
-
222
- // Detaillierte Fehlerausgabe für Debugging
223
- if (error.cause) {
224
- logger.error(`Ursache: ${error.cause.message || error.cause}`);
225
- }
226
- if (error.stack) {
227
- console.error('\nStack trace:');
228
- console.error(error.stack);
229
- }
230
-
231
- process.exit(1);
232
- }
233
- }
@@ -1,20 +0,0 @@
1
- import { clearAuth } from '../utils/auth.js';
2
- import { logger } from '@webmate-studio/core';
3
- import pc from 'picocolors';
4
-
5
- /**
6
- * Logout command - removes stored authentication
7
- */
8
- export async function logout(options = {}) {
9
- try {
10
- // Clear authentication
11
- clearAuth();
12
-
13
- logger.success('Successfully logged out');
14
- logger.info('Run ' + pc.cyan('wm login') + ' to log in again');
15
-
16
- } catch (error) {
17
- logger.error(`Logout failed: ${error.message}`);
18
- process.exit(1);
19
- }
20
- }
@@ -1,177 +0,0 @@
1
- import { loadAuth, saveAuth } from '../utils/auth.js';
2
- import { logger } from '@webmate-studio/core';
3
- import pc from 'picocolors';
4
- import { select } from '@inquirer/prompts';
5
-
6
- /**
7
- * Custom fetch wrapper that accepts self-signed certificates for localhost
8
- */
9
- async function secureFetch(url, options = {}) {
10
- const isLocalhost = url.includes('localhost') || url.includes('127.0.0.1');
11
-
12
- if (isLocalhost) {
13
- const originalValue = process.env.NODE_TLS_REJECT_UNAUTHORIZED;
14
- process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
15
-
16
- try {
17
- return await fetch(url, options);
18
- } finally {
19
- if (originalValue !== undefined) {
20
- process.env.NODE_TLS_REJECT_UNAUTHORIZED = originalValue;
21
- } else {
22
- delete process.env.NODE_TLS_REJECT_UNAUTHORIZED;
23
- }
24
- }
25
- }
26
-
27
- return fetch(url, options);
28
- }
29
-
30
- /**
31
- * Switch Organization command - Switch to a different organization
32
- */
33
- export async function switchOrgCommand(options = {}) {
34
- try {
35
- const auth = loadAuth();
36
-
37
- if (!auth) {
38
- logger.error('Not logged in. Run ' + pc.cyan('wm login') + ' first');
39
- process.exit(1);
40
- }
41
-
42
- console.log();
43
- logger.info(pc.bold('Switch Organization'));
44
- console.log();
45
-
46
- // Load available organizations for this user
47
- logger.info('Loading available organizations...');
48
-
49
- const organizationsUrl = `${auth.baseUrl}/api/cli/organizations?userId=${auth.user.id}`;
50
- const organizationsResponse = await secureFetch(organizationsUrl);
51
-
52
- if (!organizationsResponse.ok) {
53
- throw new Error('Failed to load organizations from CMS');
54
- }
55
-
56
- const organizationsData = await organizationsResponse.json();
57
-
58
- if (!organizationsData.organizations || organizationsData.organizations.length === 0) {
59
- logger.error('No organizations found');
60
- process.exit(1);
61
- }
62
-
63
- // Show current organization
64
- const currentOrganization = auth.organization;
65
- console.log();
66
- if (currentOrganization) {
67
- console.log(pc.gray(' Current: ') + pc.cyan(currentOrganization.name));
68
- }
69
- console.log();
70
-
71
- // Let user select a different organization
72
- const selectedOrganizationId = await select({
73
- message: 'Switch to:',
74
- choices: organizationsData.organizations.map(org => ({
75
- name: `${org.name} (${org.role})`,
76
- value: org.id,
77
- description: org.id === currentOrganization?.id ? 'Current organization' : `Created ${new Date(org.createdAt).toLocaleDateString('de-DE')}`
78
- }))
79
- });
80
-
81
- const selectedOrganization = organizationsData.organizations.find(o => o.id === selectedOrganizationId);
82
-
83
- // If same organization, no need to switch
84
- if (currentOrganization && selectedOrganization.id === currentOrganization.id) {
85
- console.log();
86
- logger.info('Already using this organization');
87
- return;
88
- }
89
-
90
- // Load tenants for new organization
91
- console.log();
92
- logger.info('Loading projects...');
93
-
94
- const tenantsUrl = `${auth.baseUrl}/api/cli/organizations/${selectedOrganizationId}/tenants?userId=${auth.user.id}`;
95
- const tenantsResponse = await secureFetch(tenantsUrl);
96
-
97
- if (!tenantsResponse.ok) {
98
- throw new Error('Failed to load projects');
99
- }
100
-
101
- const tenantsData = await tenantsResponse.json();
102
-
103
- if (!tenantsData.tenants || tenantsData.tenants.length === 0) {
104
- logger.warning('No projects found in this organization. Please create a project first.');
105
-
106
- // Update auth with new organization but no tenant
107
- const newAuth = {
108
- ...auth,
109
- organization: selectedOrganization,
110
- tenant: null,
111
- apiToken: null
112
- };
113
- saveAuth(newAuth);
114
-
115
- console.log();
116
- logger.success(pc.green('✨ Switched to organization: ') + pc.cyan(selectedOrganization.name));
117
- console.log();
118
- return;
119
- }
120
-
121
- // Let user select a tenant
122
- const selectedTenantId = await select({
123
- message: 'Select a project:',
124
- choices: tenantsData.tenants.map(t => ({
125
- name: `${t.name} (${t.subdomain})`,
126
- value: t.id,
127
- description: `Created ${new Date(t.createdAt).toLocaleDateString('de-DE')}`
128
- }))
129
- });
130
-
131
- const selectedTenant = tenantsData.tenants.find(t => t.id === selectedTenantId);
132
-
133
- // Generate API token for selected tenant
134
- console.log();
135
- logger.info('Generating API token...');
136
-
137
- const tokenUrl = `${auth.baseUrl}/api/cli/tenants`;
138
- const tokenResponse = await secureFetch(tokenUrl, {
139
- method: 'POST',
140
- headers: { 'Content-Type': 'application/json' },
141
- body: JSON.stringify({
142
- userId: auth.user.id,
143
- tenantId: selectedTenantId
144
- })
145
- });
146
-
147
- if (!tokenResponse.ok) {
148
- throw new Error('Failed to generate API token');
149
- }
150
-
151
- const tokenData = await tokenResponse.json();
152
-
153
- // Update auth with new organization, tenant and token
154
- const newAuth = {
155
- ...auth,
156
- organization: selectedOrganization,
157
- tenant: selectedTenant,
158
- apiToken: tokenData.apiToken
159
- };
160
-
161
- saveAuth(newAuth);
162
-
163
- console.log();
164
- logger.success(pc.green('✨ Switched to organization: ') + pc.cyan(selectedOrganization.name));
165
- console.log();
166
- console.log(` ${pc.bold('Project:')} ${pc.cyan(selectedTenant.name)}`);
167
- console.log(` ${pc.bold('Subdomain:')} ${pc.cyan(selectedTenant.subdomain)}`);
168
- console.log();
169
- console.log(pc.yellow('⚠ ') + pc.gray('If you have ') + pc.cyan('wm dev') + pc.gray(' running, please restart it to load the new project.'));
170
- console.log();
171
-
172
- } catch (error) {
173
- console.log();
174
- logger.error(`Switch organization failed: ${error.message}`);
175
- process.exit(1);
176
- }
177
- }
@@ -1,143 +0,0 @@
1
- import { loadAuth, saveAuth } from '../utils/auth.js';
2
- import { logger } from '@webmate-studio/core';
3
- import pc from 'picocolors';
4
- import { select } from '@inquirer/prompts';
5
-
6
- /**
7
- * Custom fetch wrapper that accepts self-signed certificates for localhost
8
- */
9
- async function secureFetch(url, options = {}) {
10
- const isLocalhost = url.includes('localhost') || url.includes('127.0.0.1');
11
-
12
- if (isLocalhost) {
13
- const originalValue = process.env.NODE_TLS_REJECT_UNAUTHORIZED;
14
- process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
15
-
16
- try {
17
- return await fetch(url, options);
18
- } finally {
19
- if (originalValue !== undefined) {
20
- process.env.NODE_TLS_REJECT_UNAUTHORIZED = originalValue;
21
- } else {
22
- delete process.env.NODE_TLS_REJECT_UNAUTHORIZED;
23
- }
24
- }
25
- }
26
-
27
- return fetch(url, options);
28
- }
29
-
30
- /**
31
- * Switch command - Switch to a different tenant/project
32
- */
33
- export async function switchCommand(options = {}) {
34
- try {
35
- const auth = loadAuth();
36
-
37
- if (!auth) {
38
- logger.error('Not logged in. Run ' + pc.cyan('wm login') + ' first');
39
- process.exit(1);
40
- }
41
-
42
- if (!auth.organization) {
43
- logger.error('No organization selected. Run ' + pc.cyan('wm switch-org') + ' first');
44
- process.exit(1);
45
- }
46
-
47
- console.log();
48
- logger.info(pc.bold('Switch Project'));
49
- console.log();
50
-
51
- // Show current organization
52
- console.log(pc.gray(' Organization: ') + pc.cyan(auth.organization.name));
53
- console.log();
54
-
55
- // Load available tenants for current organization
56
- logger.info('Loading available projects...');
57
-
58
- const tenantsUrl = `${auth.baseUrl}/api/cli/organizations/${auth.organization.id}/tenants?userId=${auth.user.id}`;
59
- const tenantsResponse = await secureFetch(tenantsUrl);
60
-
61
- if (!tenantsResponse.ok) {
62
- throw new Error('Failed to load projects from CMS');
63
- }
64
-
65
- const tenantsData = await tenantsResponse.json();
66
-
67
- if (!tenantsData.tenants || tenantsData.tenants.length === 0) {
68
- logger.error('No projects found in this organization');
69
- console.log();
70
- console.log(pc.gray(' Tip: Use ') + pc.cyan('wm switch-org') + pc.gray(' to switch to a different organization'));
71
- console.log();
72
- process.exit(1);
73
- }
74
-
75
- // Show current project
76
- const currentTenant = auth.tenant;
77
- console.log();
78
- console.log(pc.gray(' Current: ') + pc.cyan(`${currentTenant.name} (${currentTenant.subdomain})`));
79
- console.log();
80
-
81
- // Let user select a different tenant
82
- const selectedTenantId = await select({
83
- message: 'Switch to:',
84
- choices: tenantsData.tenants.map(t => ({
85
- name: `${t.name} (${t.subdomain})`,
86
- value: t.id,
87
- description: t.id === currentTenant.id ? 'Current project' : `Created ${new Date(t.createdAt).toLocaleDateString('de-DE')}`
88
- }))
89
- });
90
-
91
- const selectedTenant = tenantsData.tenants.find(t => t.id === selectedTenantId);
92
-
93
- // If same tenant, no need to switch
94
- if (selectedTenant.id === currentTenant.id) {
95
- console.log();
96
- logger.info('Already using this project');
97
- return;
98
- }
99
-
100
- // Generate new API token for selected tenant
101
- console.log();
102
- logger.info('Generating API token...');
103
-
104
- const tokenUrl = `${auth.baseUrl}/api/cli/tenants`;
105
- const tokenResponse = await secureFetch(tokenUrl, {
106
- method: 'POST',
107
- headers: { 'Content-Type': 'application/json' },
108
- body: JSON.stringify({
109
- userId: auth.user.id,
110
- tenantId: selectedTenantId
111
- })
112
- });
113
-
114
- if (!tokenResponse.ok) {
115
- throw new Error('Failed to generate API token');
116
- }
117
-
118
- const tokenData = await tokenResponse.json();
119
-
120
- // Update auth with new tenant and token
121
- const newAuth = {
122
- ...auth,
123
- tenant: selectedTenant,
124
- apiToken: tokenData.apiToken
125
- };
126
-
127
- saveAuth(newAuth);
128
-
129
- console.log();
130
- logger.success(pc.green('✨ Switched to project: ') + pc.cyan(selectedTenant.name));
131
- console.log();
132
- console.log(` ${pc.bold('Subdomain:')} ${pc.cyan(selectedTenant.subdomain)}`);
133
- console.log(` ${pc.bold('CMS URL:')} ${pc.cyan(`${new URL(auth.baseUrl).protocol}//${selectedTenant.subdomain}.cms.${new URL(auth.baseUrl).host}`)}`);
134
- console.log();
135
- console.log(pc.yellow('⚠ ') + pc.gray('If you have ') + pc.cyan('wm dev') + pc.gray(' running, please restart it to load the new project.'));
136
- console.log();
137
-
138
- } catch (error) {
139
- console.log();
140
- logger.error(`Switch failed: ${error.message}`);
141
- process.exit(1);
142
- }
143
- }