@veloxts/cli 0.6.26 → 0.6.29

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.
@@ -0,0 +1,635 @@
1
+ /**
2
+ * Tenant command - Multi-tenancy management commands
3
+ *
4
+ * Provides subcommands for managing tenant schemas:
5
+ * - tenant:create - Create a new tenant with PostgreSQL schema
6
+ * - tenant:list - List all tenants
7
+ * - tenant:migrate - Run migrations on tenant schemas
8
+ * - tenant:status - Show tenant status
9
+ * - tenant:suspend - Suspend a tenant
10
+ * - tenant:activate - Activate a suspended tenant
11
+ *
12
+ * SECURITY: All SQL queries use parameterized queries to prevent SQL injection
13
+ */
14
+ import * as p from '@clack/prompts';
15
+ import { createTenantSchemaManager, InvalidSlugError, slugToSchemaName, TenantError, } from '@veloxts/orm/tenant';
16
+ import { Command } from 'commander';
17
+ import pg from 'pg';
18
+ import pc from 'picocolors';
19
+ import { error, info, step, success, warning } from '../utils/output.js';
20
+ const { Client } = pg;
21
+ // ============================================================================
22
+ // Security: Input Validation
23
+ // ============================================================================
24
+ /**
25
+ * Valid tenant statuses
26
+ */
27
+ const VALID_STATUSES = new Set(['active', 'suspended', 'pending', 'migrating']);
28
+ /**
29
+ * Validate tenant name to prevent SQL injection
30
+ * Names must be alphanumeric with spaces, hyphens, and underscores
31
+ */
32
+ function validateName(name) {
33
+ if (!name || name.trim().length === 0) {
34
+ throw new Error('Name cannot be empty');
35
+ }
36
+ if (name.length > 100) {
37
+ throw new Error('Name cannot exceed 100 characters');
38
+ }
39
+ // Strict whitelist: only allow safe characters
40
+ const SAFE_NAME_REGEX = /^[a-zA-Z0-9\s\-_.']+$/;
41
+ if (!SAFE_NAME_REGEX.test(name)) {
42
+ throw new Error('Name contains invalid characters. Only letters, numbers, spaces, hyphens, underscores, periods, and apostrophes are allowed.');
43
+ }
44
+ }
45
+ /**
46
+ * Validate status filter option
47
+ */
48
+ function validateStatus(status) {
49
+ if (!VALID_STATUSES.has(status)) {
50
+ throw new Error(`Invalid status: ${status}. Must be one of: ${[...VALID_STATUSES].join(', ')}`);
51
+ }
52
+ }
53
+ /**
54
+ * Validate slug format (additional security check)
55
+ */
56
+ function validateSlugInput(slug) {
57
+ if (!slug || slug.trim().length === 0) {
58
+ throw new Error('Slug cannot be empty');
59
+ }
60
+ if (slug.length > 50) {
61
+ throw new Error('Slug cannot exceed 50 characters');
62
+ }
63
+ // Strict whitelist: only lowercase letters, numbers, and hyphens
64
+ const SAFE_SLUG_REGEX = /^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/;
65
+ if (!SAFE_SLUG_REGEX.test(slug)) {
66
+ throw new Error('Slug must contain only lowercase letters, numbers, and hyphens, and must start and end with alphanumeric characters.');
67
+ }
68
+ }
69
+ // ============================================================================
70
+ // Security: Database URL Validation
71
+ // ============================================================================
72
+ /**
73
+ * Validate and sanitize DATABASE_URL
74
+ */
75
+ function validateDatabaseUrl(url) {
76
+ try {
77
+ const parsed = new URL(url);
78
+ // Only allow postgresql:// protocol
79
+ if (parsed.protocol !== 'postgresql:' && parsed.protocol !== 'postgres:') {
80
+ throw new Error('Invalid database protocol. Only postgresql:// is allowed.');
81
+ }
82
+ // Check for shell metacharacters that could indicate injection
83
+ const DANGEROUS_CHARS = /[;|&$`<>(){}[\]!]/;
84
+ if (DANGEROUS_CHARS.test(url)) {
85
+ throw new Error('Database URL contains potentially dangerous characters.');
86
+ }
87
+ }
88
+ catch (err) {
89
+ if (err instanceof Error && err.message.includes('Invalid database')) {
90
+ throw err;
91
+ }
92
+ throw new Error('Invalid DATABASE_URL format');
93
+ }
94
+ }
95
+ /**
96
+ * Get database URL from environment with validation
97
+ */
98
+ function getDatabaseUrl() {
99
+ const url = process.env.DATABASE_URL;
100
+ if (!url) {
101
+ throw new Error('DATABASE_URL environment variable is not set.\n' +
102
+ 'Please set it in your .env file or export it in your shell.');
103
+ }
104
+ validateDatabaseUrl(url);
105
+ return url;
106
+ }
107
+ // ============================================================================
108
+ // Secure Database Operations
109
+ // ============================================================================
110
+ /**
111
+ * Create a PostgreSQL client connection
112
+ * Ensures proper cleanup even if connect() fails
113
+ */
114
+ async function createDbClient(databaseUrl) {
115
+ const client = new Client({ connectionString: databaseUrl });
116
+ try {
117
+ await client.connect();
118
+ return client;
119
+ }
120
+ catch (err) {
121
+ // Ensure client is cleaned up even if connect fails
122
+ try {
123
+ await client.end();
124
+ }
125
+ catch {
126
+ // Ignore cleanup errors
127
+ }
128
+ throw err;
129
+ }
130
+ }
131
+ /**
132
+ * Execute a parameterized SQL query safely
133
+ * Uses pg library with parameterized queries to prevent SQL injection
134
+ */
135
+ async function executeQuery(databaseUrl, sql, params = []) {
136
+ const client = await createDbClient(databaseUrl);
137
+ try {
138
+ const result = await client.query(sql, params);
139
+ return result.rows;
140
+ }
141
+ finally {
142
+ await client.end();
143
+ }
144
+ }
145
+ /**
146
+ * Execute a single-row query
147
+ */
148
+ async function executeQuerySingle(databaseUrl, sql, params = []) {
149
+ const rows = await executeQuery(databaseUrl, sql, params);
150
+ return rows[0] ?? null;
151
+ }
152
+ /**
153
+ * Validate that the tenants table exists in the database
154
+ * Provides a helpful error message if not found
155
+ */
156
+ async function validateTenantsTableExists(databaseUrl) {
157
+ const result = await executeQuerySingle(databaseUrl, `SELECT EXISTS (
158
+ SELECT 1 FROM information_schema.tables
159
+ WHERE table_schema = 'public'
160
+ AND table_name = 'tenants'
161
+ ) as exists`, []);
162
+ if (!result?.exists) {
163
+ throw new Error('Tenants table not found in the database.\n' +
164
+ 'Please ensure your Prisma schema includes a Tenant model and run migrations:\n' +
165
+ ' npx prisma migrate dev\n' +
166
+ '\nOr create the table manually with the required columns:\n' +
167
+ ' id, slug, name, schema_name, status, created_at, updated_at');
168
+ }
169
+ }
170
+ // ============================================================================
171
+ // Utility Functions
172
+ // ============================================================================
173
+ /**
174
+ * Format date for display
175
+ */
176
+ function formatDate(date) {
177
+ const d = typeof date === 'string' ? new Date(date) : date;
178
+ return d.toISOString().replace('T', ' ').slice(0, 19);
179
+ }
180
+ /**
181
+ * Format status with color
182
+ */
183
+ function formatStatus(status) {
184
+ switch (status) {
185
+ case 'active':
186
+ return pc.green(status);
187
+ case 'suspended':
188
+ return pc.red(status);
189
+ case 'pending':
190
+ return pc.yellow(status);
191
+ case 'migrating':
192
+ return pc.cyan(status);
193
+ default:
194
+ return pc.gray(status);
195
+ }
196
+ }
197
+ /**
198
+ * Sanitize error messages to prevent credential leakage
199
+ */
200
+ function sanitizeErrorMessage(message) {
201
+ // Remove connection strings
202
+ let sanitized = message.replace(/postgresql:\/\/[^@]+@[^\s"']+/gi, 'postgresql://***:***@***/***');
203
+ // Remove passwords
204
+ sanitized = sanitized.replace(/password[=:]\s*['"]?[^'"\s]+/gi, 'password=***');
205
+ return sanitized;
206
+ }
207
+ // ============================================================================
208
+ // tenant:create
209
+ // ============================================================================
210
+ function createTenantCreateCommand() {
211
+ return new Command('create')
212
+ .description('Create a new tenant with PostgreSQL schema')
213
+ .argument('<slug>', 'URL-safe tenant slug (e.g., acme-corp)')
214
+ .option('-n, --name <name>', 'Human-readable tenant name')
215
+ .option('--dry-run', 'Preview without creating', false)
216
+ .option('--json', 'Output as JSON', false)
217
+ .action(async (slug, options) => {
218
+ try {
219
+ // Validate inputs
220
+ validateSlugInput(slug);
221
+ const name = options.name ?? slug;
222
+ validateName(name);
223
+ const databaseUrl = getDatabaseUrl();
224
+ const schemaManager = createTenantSchemaManager({ databaseUrl });
225
+ const schemaName = slugToSchemaName(slug);
226
+ if (options.dryRun) {
227
+ info(`Would create tenant: ${pc.cyan(slug)}`);
228
+ step(`Schema name: ${pc.cyan(schemaName)}`);
229
+ step(`Display name: ${name}`);
230
+ return;
231
+ }
232
+ // Validate tenants table exists before proceeding
233
+ await validateTenantsTableExists(databaseUrl);
234
+ if (!options.json) {
235
+ info(`Creating tenant: ${pc.cyan(slug)}`);
236
+ }
237
+ const s = p.spinner();
238
+ s.start('Creating PostgreSQL schema...');
239
+ // Create schema
240
+ const schemaResult = await schemaManager.createSchema(slug);
241
+ if (!schemaResult.created) {
242
+ s.stop('Schema already exists');
243
+ warning(`Schema ${schemaName} already exists`);
244
+ if (options.json) {
245
+ console.log(JSON.stringify({ success: false, error: 'Schema already exists', schemaName }, null, 2));
246
+ }
247
+ return; // Explicit early return
248
+ }
249
+ // Schema was created, continue with migration
250
+ s.message('Running migrations...');
251
+ // Run migrations
252
+ const migrateResult = await schemaManager.migrateSchema(schemaName);
253
+ s.message('Creating tenant record...');
254
+ // Insert tenant record using parameterized query
255
+ await executeQuery(databaseUrl, `INSERT INTO tenants (id, slug, name, schema_name, status, created_at, updated_at)
256
+ VALUES (gen_random_uuid(), $1, $2, $3, 'active', NOW(), NOW())`, [slug, name, schemaName]);
257
+ s.stop('Tenant created successfully');
258
+ if (options.json) {
259
+ console.log(JSON.stringify({
260
+ success: true,
261
+ tenant: {
262
+ slug,
263
+ name,
264
+ schemaName,
265
+ status: 'active',
266
+ migrationsApplied: migrateResult.migrationsApplied,
267
+ },
268
+ }, null, 2));
269
+ }
270
+ else {
271
+ success(`Created tenant ${pc.cyan(slug)}`);
272
+ step(`Schema: ${pc.cyan(schemaName)}`);
273
+ step(`Migrations applied: ${migrateResult.migrationsApplied}`);
274
+ }
275
+ }
276
+ catch (err) {
277
+ if (err instanceof InvalidSlugError) {
278
+ error(err.message);
279
+ }
280
+ else if (err instanceof TenantError) {
281
+ error(`Tenant error: ${err.message}`);
282
+ }
283
+ else {
284
+ error(sanitizeErrorMessage(err instanceof Error ? err.message : String(err)));
285
+ }
286
+ process.exit(1);
287
+ }
288
+ });
289
+ }
290
+ // ============================================================================
291
+ // tenant:list
292
+ // ============================================================================
293
+ function createTenantListCommand() {
294
+ return new Command('list')
295
+ .description('List all tenants')
296
+ .option('--status <status>', 'Filter by status (active/suspended/pending)')
297
+ .option('--json', 'Output as JSON', false)
298
+ .action(async (options) => {
299
+ try {
300
+ const databaseUrl = getDatabaseUrl();
301
+ // Validate tenants table exists
302
+ await validateTenantsTableExists(databaseUrl);
303
+ // Build query with optional parameterized status filter
304
+ let sql;
305
+ let params;
306
+ if (options.status) {
307
+ validateStatus(options.status);
308
+ sql =
309
+ 'SELECT slug, name, schema_name, status, created_at FROM tenants WHERE status = $1 ORDER BY created_at DESC';
310
+ params = [options.status];
311
+ }
312
+ else {
313
+ sql =
314
+ 'SELECT slug, name, schema_name, status, created_at FROM tenants ORDER BY created_at DESC';
315
+ params = [];
316
+ }
317
+ const tenants = await executeQuery(databaseUrl, sql, params);
318
+ if (tenants.length === 0) {
319
+ if (options.json) {
320
+ console.log(JSON.stringify({ tenants: [] }, null, 2));
321
+ }
322
+ else {
323
+ info('No tenants found');
324
+ }
325
+ return;
326
+ }
327
+ if (options.json) {
328
+ console.log(JSON.stringify({
329
+ tenants: tenants.map((t) => ({
330
+ slug: t.slug,
331
+ name: t.name,
332
+ schemaName: t.schema_name,
333
+ status: t.status,
334
+ createdAt: t.created_at,
335
+ })),
336
+ }, null, 2));
337
+ }
338
+ else {
339
+ console.log('');
340
+ console.log(pc.dim('┌─────────────────────┬────────────────────┬────────────┬─────────────────────┐'));
341
+ console.log(`│ ${pc.bold('Slug')} │ ${pc.bold('Schema')} │ ${pc.bold('Status')} │ ${pc.bold('Created')} │`);
342
+ console.log(pc.dim('├─────────────────────┼────────────────────┼────────────┼─────────────────────┤'));
343
+ for (const t of tenants) {
344
+ const slug = t.slug.padEnd(19);
345
+ const schema = t.schema_name.padEnd(18);
346
+ const status = formatStatus(t.status).padEnd(20); // Extra padding for color codes
347
+ const created = formatDate(t.created_at);
348
+ console.log(`│ ${slug} │ ${schema} │ ${status} │ ${created} │`);
349
+ }
350
+ console.log(pc.dim('└─────────────────────┴────────────────────┴────────────┴─────────────────────┘'));
351
+ console.log('');
352
+ info(`Total: ${tenants.length} tenant(s)`);
353
+ }
354
+ }
355
+ catch (err) {
356
+ error(sanitizeErrorMessage(err instanceof Error ? err.message : String(err)));
357
+ process.exit(1);
358
+ }
359
+ });
360
+ }
361
+ // ============================================================================
362
+ // tenant:migrate
363
+ // ============================================================================
364
+ function createTenantMigrateCommand() {
365
+ return new Command('migrate')
366
+ .description('Run migrations on tenant schemas')
367
+ .argument('[slug]', 'Specific tenant to migrate')
368
+ .option('--all', 'Migrate all active tenants', false)
369
+ .option('--dry-run', 'Preview without running migrations', false)
370
+ .option('--json', 'Output as JSON', false)
371
+ .action(async (slug, options) => {
372
+ try {
373
+ const databaseUrl = getDatabaseUrl();
374
+ const schemaManager = createTenantSchemaManager({ databaseUrl });
375
+ // Validate tenants table exists
376
+ await validateTenantsTableExists(databaseUrl);
377
+ // Get tenants to migrate using parameterized queries
378
+ let sql;
379
+ let params;
380
+ if (slug) {
381
+ validateSlugInput(slug);
382
+ sql = 'SELECT slug, schema_name FROM tenants WHERE slug = $1';
383
+ params = [slug];
384
+ }
385
+ else {
386
+ sql = "SELECT slug, schema_name FROM tenants WHERE status = 'active'";
387
+ params = [];
388
+ }
389
+ const tenants = await executeQuery(databaseUrl, sql, params);
390
+ if (tenants.length === 0) {
391
+ if (slug) {
392
+ error(`Tenant not found: ${slug}`);
393
+ process.exit(1);
394
+ }
395
+ else {
396
+ info('No active tenants to migrate');
397
+ return;
398
+ }
399
+ }
400
+ if (options.dryRun) {
401
+ info('Would migrate the following tenants:');
402
+ for (const t of tenants) {
403
+ step(`${t.slug} (${t.schema_name})`);
404
+ }
405
+ return;
406
+ }
407
+ const results = [];
408
+ const s = p.spinner();
409
+ for (const t of tenants) {
410
+ s.start(`Migrating ${t.slug}...`);
411
+ try {
412
+ // Check current status before updating (prevents concurrent migrations)
413
+ const currentTenant = await executeQuerySingle(databaseUrl, 'SELECT status FROM tenants WHERE slug = $1', [t.slug]);
414
+ if (!currentTenant) {
415
+ s.stop(`Tenant ${t.slug} no longer exists`);
416
+ warning(`Skipping ${t.slug}: tenant not found`);
417
+ continue;
418
+ }
419
+ if (currentTenant.status === 'migrating') {
420
+ s.stop(`Tenant ${t.slug} already migrating`);
421
+ warning(`Skipping ${t.slug}: migration already in progress`);
422
+ continue;
423
+ }
424
+ if (currentTenant.status === 'suspended') {
425
+ s.stop(`Tenant ${t.slug} is suspended`);
426
+ warning(`Skipping ${t.slug}: tenant is suspended`);
427
+ continue;
428
+ }
429
+ // Update status to migrating using parameterized query
430
+ await executeQuery(databaseUrl, 'UPDATE tenants SET status = $1 WHERE slug = $2', [
431
+ 'migrating',
432
+ t.slug,
433
+ ]);
434
+ const migrateResult = await schemaManager.migrateSchema(t.schema_name);
435
+ // Update status back to active
436
+ await executeQuery(databaseUrl, 'UPDATE tenants SET status = $1 WHERE slug = $2', [
437
+ 'active',
438
+ t.slug,
439
+ ]);
440
+ results.push({
441
+ slug: t.slug,
442
+ schemaName: t.schema_name,
443
+ migrationsApplied: migrateResult.migrationsApplied,
444
+ });
445
+ s.stop(`Migrated ${t.slug}: ${migrateResult.migrationsApplied} migration(s) applied`);
446
+ }
447
+ catch (err) {
448
+ s.stop(`Failed to migrate ${t.slug}`);
449
+ error(sanitizeErrorMessage(err instanceof Error ? err.message : String(err)));
450
+ // Restore status (try to set back to active, ignore if it fails)
451
+ try {
452
+ await executeQuery(databaseUrl, 'UPDATE tenants SET status = $1 WHERE slug = $2', [
453
+ 'active',
454
+ t.slug,
455
+ ]);
456
+ }
457
+ catch {
458
+ warning(`Could not restore status for ${t.slug} - may need manual intervention`);
459
+ }
460
+ }
461
+ }
462
+ if (options.json) {
463
+ console.log(JSON.stringify({ results }, null, 2));
464
+ }
465
+ else {
466
+ console.log('');
467
+ success(`Migrated ${results.length} tenant(s)`);
468
+ }
469
+ }
470
+ catch (err) {
471
+ error(sanitizeErrorMessage(err instanceof Error ? err.message : String(err)));
472
+ process.exit(1);
473
+ }
474
+ });
475
+ }
476
+ // ============================================================================
477
+ // tenant:status
478
+ // ============================================================================
479
+ function createTenantStatusCommand() {
480
+ return new Command('status')
481
+ .description('Show tenant status and schema info')
482
+ .argument('<slug>', 'Tenant slug')
483
+ .option('--json', 'Output as JSON', false)
484
+ .action(async (slug, options) => {
485
+ try {
486
+ validateSlugInput(slug);
487
+ const databaseUrl = getDatabaseUrl();
488
+ // Validate tenants table exists
489
+ await validateTenantsTableExists(databaseUrl);
490
+ // Use parameterized query
491
+ const tenant = await executeQuerySingle(databaseUrl, `SELECT id, slug, name, schema_name, status, created_at, updated_at
492
+ FROM tenants WHERE slug = $1`, [slug]);
493
+ if (!tenant) {
494
+ error(`Tenant not found: ${slug}`);
495
+ process.exit(1);
496
+ }
497
+ // Check if schema exists using parameterized query
498
+ const schemaCheck = await executeQuerySingle(databaseUrl, 'SELECT EXISTS(SELECT 1 FROM information_schema.schemata WHERE schema_name = $1) as exists', [tenant.schema_name]);
499
+ const tenantInfo = {
500
+ id: tenant.id,
501
+ slug: tenant.slug,
502
+ name: tenant.name,
503
+ schemaName: tenant.schema_name,
504
+ status: tenant.status,
505
+ schemaExists: schemaCheck?.exists ?? false,
506
+ createdAt: tenant.created_at,
507
+ updatedAt: tenant.updated_at,
508
+ };
509
+ if (options.json) {
510
+ console.log(JSON.stringify(tenantInfo, null, 2));
511
+ }
512
+ else {
513
+ console.log('');
514
+ console.log(`${pc.bold('Tenant:')} ${tenant.name} (${tenant.slug})`);
515
+ console.log(`${pc.bold('Status:')} ${formatStatus(tenant.status)}`);
516
+ console.log(`${pc.bold('Schema:')} ${tenant.schema_name}`);
517
+ console.log(`${pc.bold('Schema exists:')} ${tenantInfo.schemaExists ? pc.green('yes') : pc.red('no')}`);
518
+ console.log(`${pc.bold('Created:')} ${formatDate(tenant.created_at)}`);
519
+ console.log(`${pc.bold('Updated:')} ${formatDate(tenant.updated_at)}`);
520
+ console.log('');
521
+ }
522
+ }
523
+ catch (err) {
524
+ error(sanitizeErrorMessage(err instanceof Error ? err.message : String(err)));
525
+ process.exit(1);
526
+ }
527
+ });
528
+ }
529
+ // ============================================================================
530
+ // tenant:suspend
531
+ // ============================================================================
532
+ function createTenantSuspendCommand() {
533
+ return new Command('suspend')
534
+ .description('Suspend a tenant (block access)')
535
+ .argument('<slug>', 'Tenant slug to suspend')
536
+ .option('-f, --force', 'Skip confirmation', false)
537
+ .option('--json', 'Output as JSON', false)
538
+ .action(async (slug, options) => {
539
+ try {
540
+ validateSlugInput(slug);
541
+ const databaseUrl = getDatabaseUrl();
542
+ // Validate tenants table exists
543
+ await validateTenantsTableExists(databaseUrl);
544
+ // Check tenant exists using parameterized query
545
+ const existing = await executeQuerySingle(databaseUrl, 'SELECT status FROM tenants WHERE slug = $1', [slug]);
546
+ if (!existing) {
547
+ error(`Tenant not found: ${slug}`);
548
+ process.exit(1);
549
+ }
550
+ if (existing.status === 'suspended') {
551
+ warning(`Tenant ${slug} is already suspended`);
552
+ return;
553
+ }
554
+ // Confirm if not forced
555
+ if (!options.force && !options.json) {
556
+ const confirmed = await p.confirm({
557
+ message: `Are you sure you want to suspend tenant ${pc.cyan(slug)}?`,
558
+ });
559
+ if (p.isCancel(confirmed) || !confirmed) {
560
+ info('Cancelled');
561
+ return;
562
+ }
563
+ }
564
+ // Suspend using parameterized query
565
+ await executeQuery(databaseUrl, 'UPDATE tenants SET status = $1, updated_at = NOW() WHERE slug = $2', ['suspended', slug]);
566
+ if (options.json) {
567
+ console.log(JSON.stringify({ success: true, slug, status: 'suspended' }, null, 2));
568
+ }
569
+ else {
570
+ success(`Suspended tenant ${pc.cyan(slug)}`);
571
+ }
572
+ }
573
+ catch (err) {
574
+ error(sanitizeErrorMessage(err instanceof Error ? err.message : String(err)));
575
+ process.exit(1);
576
+ }
577
+ });
578
+ }
579
+ // ============================================================================
580
+ // tenant:activate
581
+ // ============================================================================
582
+ function createTenantActivateCommand() {
583
+ return new Command('activate')
584
+ .description('Activate a suspended tenant')
585
+ .argument('<slug>', 'Tenant slug to activate')
586
+ .option('--json', 'Output as JSON', false)
587
+ .action(async (slug, options) => {
588
+ try {
589
+ validateSlugInput(slug);
590
+ const databaseUrl = getDatabaseUrl();
591
+ // Validate tenants table exists
592
+ await validateTenantsTableExists(databaseUrl);
593
+ // Check tenant exists using parameterized query
594
+ const existing = await executeQuerySingle(databaseUrl, 'SELECT status FROM tenants WHERE slug = $1', [slug]);
595
+ if (!existing) {
596
+ error(`Tenant not found: ${slug}`);
597
+ process.exit(1);
598
+ }
599
+ if (existing.status === 'active') {
600
+ warning(`Tenant ${slug} is already active`);
601
+ return;
602
+ }
603
+ // Activate using parameterized query
604
+ await executeQuery(databaseUrl, 'UPDATE tenants SET status = $1, updated_at = NOW() WHERE slug = $2', ['active', slug]);
605
+ if (options.json) {
606
+ console.log(JSON.stringify({ success: true, slug, status: 'active' }, null, 2));
607
+ }
608
+ else {
609
+ success(`Activated tenant ${pc.cyan(slug)}`);
610
+ }
611
+ }
612
+ catch (err) {
613
+ error(sanitizeErrorMessage(err instanceof Error ? err.message : String(err)));
614
+ process.exit(1);
615
+ }
616
+ });
617
+ }
618
+ // ============================================================================
619
+ // Main Command
620
+ // ============================================================================
621
+ /**
622
+ * Create the tenant command with subcommands
623
+ */
624
+ export function createTenantCommand() {
625
+ const tenant = new Command('tenant')
626
+ .description('Multi-tenancy management commands')
627
+ .addCommand(createTenantCreateCommand())
628
+ .addCommand(createTenantListCommand())
629
+ .addCommand(createTenantMigrateCommand())
630
+ .addCommand(createTenantStatusCommand())
631
+ .addCommand(createTenantSuspendCommand())
632
+ .addCommand(createTenantActivateCommand());
633
+ return tenant;
634
+ }
635
+ //# sourceMappingURL=tenant.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant.js","sourceRoot":"","sources":["../../src/commands/tenant.ts"],"names":[],"mappings":"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"}