pgpm 0.0.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.
Files changed (121) hide show
  1. package/README.md +416 -0
  2. package/commands/add.d.ts +7 -0
  3. package/commands/add.js +86 -0
  4. package/commands/admin-users/add.d.ts +4 -0
  5. package/commands/admin-users/add.js +89 -0
  6. package/commands/admin-users/bootstrap.d.ts +4 -0
  7. package/commands/admin-users/bootstrap.js +50 -0
  8. package/commands/admin-users/remove.d.ts +4 -0
  9. package/commands/admin-users/remove.js +82 -0
  10. package/commands/admin-users.d.ts +4 -0
  11. package/commands/admin-users.js +68 -0
  12. package/commands/analyze.d.ts +4 -0
  13. package/commands/analyze.js +21 -0
  14. package/commands/clear.d.ts +3 -0
  15. package/commands/clear.js +59 -0
  16. package/commands/deploy.d.ts +4 -0
  17. package/commands/deploy.js +146 -0
  18. package/commands/explorer.d.ts +3 -0
  19. package/commands/explorer.js +94 -0
  20. package/commands/export.d.ts +3 -0
  21. package/commands/export.js +129 -0
  22. package/commands/extension.d.ts +4 -0
  23. package/commands/extension.js +48 -0
  24. package/commands/init/index.d.ts +7 -0
  25. package/commands/init/index.js +47 -0
  26. package/commands/init/module.d.ts +4 -0
  27. package/commands/init/module.js +71 -0
  28. package/commands/init/workspace.d.ts +4 -0
  29. package/commands/init/workspace.js +52 -0
  30. package/commands/install.d.ts +4 -0
  31. package/commands/install.js +37 -0
  32. package/commands/kill.d.ts +3 -0
  33. package/commands/kill.js +107 -0
  34. package/commands/migrate/deps.d.ts +4 -0
  35. package/commands/migrate/deps.js +186 -0
  36. package/commands/migrate/init.d.ts +4 -0
  37. package/commands/migrate/init.js +65 -0
  38. package/commands/migrate/list.d.ts +4 -0
  39. package/commands/migrate/list.js +85 -0
  40. package/commands/migrate/status.d.ts +4 -0
  41. package/commands/migrate/status.js +94 -0
  42. package/commands/migrate.d.ts +4 -0
  43. package/commands/migrate.js +69 -0
  44. package/commands/package.d.ts +3 -0
  45. package/commands/package.js +65 -0
  46. package/commands/plan.d.ts +3 -0
  47. package/commands/plan.js +62 -0
  48. package/commands/remove.d.ts +3 -0
  49. package/commands/remove.js +42 -0
  50. package/commands/rename.d.ts +4 -0
  51. package/commands/rename.js +35 -0
  52. package/commands/revert.d.ts +3 -0
  53. package/commands/revert.js +107 -0
  54. package/commands/server.d.ts +3 -0
  55. package/commands/server.js +187 -0
  56. package/commands/tag.d.ts +6 -0
  57. package/commands/tag.js +168 -0
  58. package/commands/verify.d.ts +3 -0
  59. package/commands/verify.js +85 -0
  60. package/commands.d.ts +5 -0
  61. package/commands.js +118 -0
  62. package/dist/README.md +416 -0
  63. package/dist/package.json +77 -0
  64. package/esm/commands/add.js +51 -0
  65. package/esm/commands/admin-users/add.js +87 -0
  66. package/esm/commands/admin-users/bootstrap.js +48 -0
  67. package/esm/commands/admin-users/remove.js +80 -0
  68. package/esm/commands/admin-users.js +63 -0
  69. package/esm/commands/analyze.js +16 -0
  70. package/esm/commands/clear.js +54 -0
  71. package/esm/commands/deploy.js +144 -0
  72. package/esm/commands/explorer.js +92 -0
  73. package/esm/commands/export.js +127 -0
  74. package/esm/commands/extension.js +46 -0
  75. package/esm/commands/init/index.js +42 -0
  76. package/esm/commands/init/module.js +68 -0
  77. package/esm/commands/init/workspace.js +46 -0
  78. package/esm/commands/install.js +35 -0
  79. package/esm/commands/kill.js +105 -0
  80. package/esm/commands/migrate/deps.js +184 -0
  81. package/esm/commands/migrate/init.js +63 -0
  82. package/esm/commands/migrate/list.js +83 -0
  83. package/esm/commands/migrate/status.js +92 -0
  84. package/esm/commands/migrate.js +64 -0
  85. package/esm/commands/package.js +63 -0
  86. package/esm/commands/plan.js +60 -0
  87. package/esm/commands/remove.js +40 -0
  88. package/esm/commands/rename.js +30 -0
  89. package/esm/commands/revert.js +105 -0
  90. package/esm/commands/server.js +185 -0
  91. package/esm/commands/tag.js +133 -0
  92. package/esm/commands/verify.js +83 -0
  93. package/esm/commands.js +111 -0
  94. package/esm/index.js +20 -0
  95. package/esm/package.js +26 -0
  96. package/esm/utils/argv.js +92 -0
  97. package/esm/utils/cli-error.js +48 -0
  98. package/esm/utils/database.js +78 -0
  99. package/esm/utils/deployed-changes.js +68 -0
  100. package/esm/utils/display.js +58 -0
  101. package/esm/utils/index.js +3 -0
  102. package/esm/utils/module-utils.js +51 -0
  103. package/index.d.ts +3 -0
  104. package/index.js +23 -0
  105. package/package.d.ts +1 -0
  106. package/package.js +29 -0
  107. package/package.json +77 -0
  108. package/utils/argv.d.ts +46 -0
  109. package/utils/argv.js +100 -0
  110. package/utils/cli-error.d.ts +8 -0
  111. package/utils/cli-error.js +52 -0
  112. package/utils/database.d.ts +21 -0
  113. package/utils/database.js +83 -0
  114. package/utils/deployed-changes.d.ts +4 -0
  115. package/utils/deployed-changes.js +72 -0
  116. package/utils/display.d.ts +3 -0
  117. package/utils/display.js +66 -0
  118. package/utils/index.d.ts +3 -0
  119. package/utils/index.js +19 -0
  120. package/utils/module-utils.d.ts +8 -0
  121. package/utils/module-utils.js +54 -0
@@ -0,0 +1,64 @@
1
+ import { extractFirst } from '../utils';
2
+ import deps from './migrate/deps';
3
+ // Migrate subcommands
4
+ import init from './migrate/init';
5
+ import list from './migrate/list';
6
+ import status from './migrate/status';
7
+ const subcommandMap = {
8
+ init,
9
+ status,
10
+ list,
11
+ deps
12
+ };
13
+ const migrateUsageText = `
14
+ LaunchQL Migrate Commands:
15
+
16
+ launchql migrate init Initialize migration tracking in database
17
+ launchql migrate status Show current migration status
18
+ launchql migrate list List all changes (deployed and pending)
19
+ launchql migrate deps Show change dependencies
20
+
21
+ Options:
22
+ --help, -h Show this help message
23
+ --cwd Working directory (default: current directory)
24
+ `;
25
+ export default async (argv, prompter, options) => {
26
+ let { first: subcommand, newArgv } = extractFirst(argv);
27
+ // Show usage if explicitly requested
28
+ if (argv.help || argv.h || subcommand === 'help') {
29
+ console.log(migrateUsageText);
30
+ process.exit(0);
31
+ }
32
+ // Prompt if no subcommand provided
33
+ if (!subcommand) {
34
+ const answer = await prompter.prompt(argv, [
35
+ {
36
+ type: 'autocomplete',
37
+ name: 'subcommand',
38
+ message: 'What migrate operation do you want to perform?',
39
+ options: Object.keys(subcommandMap).map(cmd => ({
40
+ name: cmd,
41
+ value: cmd,
42
+ description: getSubcommandDescription(cmd)
43
+ }))
44
+ }
45
+ ]);
46
+ subcommand = answer.subcommand;
47
+ }
48
+ const subcommandFn = subcommandMap[subcommand];
49
+ if (!subcommandFn) {
50
+ console.error(`Unknown migrate subcommand: ${subcommand}`);
51
+ console.log(migrateUsageText);
52
+ process.exit(1);
53
+ }
54
+ await subcommandFn(newArgv, prompter, options);
55
+ };
56
+ function getSubcommandDescription(cmd) {
57
+ const descriptions = {
58
+ init: 'Initialize migration tracking in database',
59
+ status: 'Show current migration status',
60
+ list: 'List all changes (deployed and pending)',
61
+ deps: 'Show change dependencies'
62
+ };
63
+ return descriptions[cmd] || '';
64
+ }
@@ -0,0 +1,63 @@
1
+ import { LaunchQLPackage, writePackage } from '@launchql/core';
2
+ const packageUsageText = `
3
+ LaunchQL Package Command:
4
+
5
+ lql package [OPTIONS]
6
+
7
+ Package module for distribution.
8
+
9
+ Options:
10
+ --help, -h Show this help message
11
+ --plan Include deployment plan (default: true)
12
+ --pretty Pretty-print output (default: true)
13
+ --functionDelimiter <delimiter> Function delimiter (default: $EOFCODE$)
14
+ --cwd <directory> Working directory (default: current directory)
15
+
16
+ Examples:
17
+ lql package Package with defaults
18
+ lql package --no-plan Package without plan
19
+ `;
20
+ export default async (argv, prompter, _options) => {
21
+ // Show usage if explicitly requested
22
+ if (argv.help || argv.h) {
23
+ console.log(packageUsageText);
24
+ process.exit(0);
25
+ }
26
+ const questions = [
27
+ {
28
+ type: 'confirm',
29
+ name: 'plan',
30
+ default: true,
31
+ useDefault: true,
32
+ required: true
33
+ },
34
+ {
35
+ type: 'confirm',
36
+ name: 'pretty',
37
+ default: true,
38
+ useDefault: true,
39
+ required: true
40
+ },
41
+ {
42
+ type: 'text',
43
+ name: 'functionDelimiter',
44
+ default: '$EOFCODE$',
45
+ useDefault: true,
46
+ required: false
47
+ }
48
+ ];
49
+ let { cwd, plan, pretty, functionDelimiter } = await prompter.prompt(argv, questions);
50
+ const project = new LaunchQLPackage(cwd);
51
+ project.ensureModule();
52
+ const info = project.getModuleInfo();
53
+ info.version;
54
+ await writePackage({
55
+ version: info.version,
56
+ extension: true,
57
+ usePlan: plan,
58
+ packageDir: project.modulePath,
59
+ pretty,
60
+ functionDelimiter
61
+ });
62
+ return argv;
63
+ };
@@ -0,0 +1,60 @@
1
+ import { LaunchQLPackage } from '@launchql/core';
2
+ import { Logger } from '@launchql/logger';
3
+ const log = new Logger('plan');
4
+ const planUsageText = `
5
+ LaunchQL Plan Command:
6
+
7
+ lql plan [OPTIONS]
8
+
9
+ Generate module deployment plans.
10
+
11
+ Options:
12
+ --help, -h Show this help message
13
+ --includePackages Include packages in plan (default: true)
14
+ --includeTags Prefer @tag references for external packages when available (default: true)
15
+ --cwd <directory> Working directory (default: current directory)
16
+
17
+ Examples:
18
+ lql plan Generate deployment plan for current module with defaults
19
+ lql plan --includePackages false Disable including external packages
20
+ lql plan --includeTags false Do not prefer tags for external packages
21
+ `;
22
+ export default async (argv, prompter, _options) => {
23
+ // Show usage if explicitly requested
24
+ if (argv.help || argv.h) {
25
+ console.log(planUsageText);
26
+ process.exit(0);
27
+ }
28
+ const questions = [
29
+ {
30
+ type: 'confirm',
31
+ name: 'includePackages',
32
+ message: 'Include packages in plan?',
33
+ useDefault: true,
34
+ default: true
35
+ },
36
+ {
37
+ type: 'confirm',
38
+ name: 'includeTags',
39
+ message: 'Prefer @tag references for external packages when available?',
40
+ useDefault: true,
41
+ default: true
42
+ }
43
+ ];
44
+ let { cwd, includePackages, includeTags } = await prompter.prompt(argv, questions);
45
+ if (!cwd) {
46
+ cwd = process.cwd();
47
+ log.info(`Using current directory: ${cwd}`);
48
+ }
49
+ const pkg = new LaunchQLPackage(cwd);
50
+ if (!pkg.isInModule()) {
51
+ throw new Error('This command must be run inside a LaunchQL module.');
52
+ }
53
+ const includePackagesFlag = typeof includePackages === 'boolean' ? includePackages : true;
54
+ const includeTagsFlag = typeof includeTags === 'boolean' ? includeTags : true;
55
+ pkg.writeModulePlan({
56
+ includePackages: includePackagesFlag,
57
+ includeTags: includeTagsFlag
58
+ });
59
+ return argv;
60
+ };
@@ -0,0 +1,40 @@
1
+ import { LaunchQLPackage } from '@launchql/core';
2
+ import { Logger } from '@launchql/logger';
3
+ import { getEnvOptions } from '@launchql/env';
4
+ import { getPgEnvOptions } from 'pg-env';
5
+ import { getTargetDatabase } from '../utils';
6
+ import { cliExitWithError } from '../utils/cli-error';
7
+ const log = new Logger('remove');
8
+ export default async (argv, prompter, _options) => {
9
+ if (!argv.to) {
10
+ await cliExitWithError('No change specified. Usage: lql remove --to <change>');
11
+ }
12
+ const database = await getTargetDatabase(argv, prompter, {
13
+ message: 'Select database'
14
+ });
15
+ const questions = [
16
+ {
17
+ name: 'yes',
18
+ type: 'confirm',
19
+ message: 'Are you sure you want to proceed with removing changes?',
20
+ required: true
21
+ }
22
+ ];
23
+ let { yes, cwd } = await prompter.prompt(argv, questions);
24
+ if (!yes) {
25
+ log.info('Operation cancelled.');
26
+ return;
27
+ }
28
+ log.debug(`Using current directory: ${cwd}`);
29
+ const pkg = new LaunchQLPackage(cwd);
30
+ if (!pkg.isInModule()) {
31
+ throw new Error('Not in a LaunchQL module directory. Please run this command from within a module.');
32
+ }
33
+ const opts = getEnvOptions({
34
+ pg: getPgEnvOptions({ database })
35
+ });
36
+ const toChange = argv.to;
37
+ await pkg.removeFromPlan(toChange);
38
+ log.success(`✅ Successfully removed changes from '${toChange}' to end of plan.`);
39
+ return argv;
40
+ };
@@ -0,0 +1,30 @@
1
+ import path from 'path';
2
+ import { LaunchQLPackage } from '@launchql/core';
3
+ import { cliExitWithError } from '../utils/cli-error';
4
+ export default async (argv, _prompter) => {
5
+ const cwd = argv.cwd || process.cwd();
6
+ const to = argv.to || (argv._ && argv._[0]);
7
+ if (!to) {
8
+ await cliExitWithError('Missing new name. Use --to <name> or provide as positional argument.');
9
+ }
10
+ const dryRun = !!argv['dry-run'] || !!argv.dryRun;
11
+ const syncPkg = !!argv['sync-pkg-name'] || !!argv.syncPkgName;
12
+ const proj = new LaunchQLPackage(path.resolve(cwd));
13
+ const res = proj.renameModule(to, { dryRun, syncPackageJsonName: syncPkg });
14
+ if (dryRun) {
15
+ console.log('Dry run');
16
+ }
17
+ if (res.changed.length > 0) {
18
+ console.log('Changed:');
19
+ for (const f of res.changed)
20
+ console.log(`- ${f}`);
21
+ }
22
+ else {
23
+ console.log('No changes');
24
+ }
25
+ if (res.warnings.length > 0) {
26
+ console.log('Warnings:');
27
+ for (const w of res.warnings)
28
+ console.log(`- ${w}`);
29
+ }
30
+ };
@@ -0,0 +1,105 @@
1
+ import { LaunchQLPackage } from '@launchql/core';
2
+ import { Logger } from '@launchql/logger';
3
+ import { getEnvOptions } from '@launchql/env';
4
+ import { getPgEnvOptions } from 'pg-env';
5
+ import { getTargetDatabase } from '../utils';
6
+ import { selectDeployedChange, selectDeployedPackage } from '../utils/deployed-changes';
7
+ import { cliExitWithError } from '../utils/cli-error';
8
+ const log = new Logger('revert');
9
+ const revertUsageText = `
10
+ LaunchQL Revert Command:
11
+
12
+ lql revert [OPTIONS]
13
+
14
+ Revert database changes and migrations.
15
+
16
+ Options:
17
+ --help, -h Show this help message
18
+ --recursive Revert recursively through dependencies
19
+ --package <name> Revert specific package
20
+ --to <target> Revert to specific change or tag
21
+ --to Interactive selection of deployed changes
22
+ --tx Use transactions (default: true)
23
+ --cwd <directory> Working directory (default: current directory)
24
+
25
+ Examples:
26
+ lql revert Revert latest changes
27
+ lql revert --to @v1.0.0 Revert to specific tag
28
+ lql revert --to Interactive selection from deployed changes
29
+ `;
30
+ export default async (argv, prompter, _options) => {
31
+ // Show usage if explicitly requested
32
+ if (argv.help || argv.h) {
33
+ console.log(revertUsageText);
34
+ process.exit(0);
35
+ }
36
+ const database = await getTargetDatabase(argv, prompter, {
37
+ message: 'Select database'
38
+ });
39
+ const questions = [
40
+ {
41
+ name: 'yes',
42
+ type: 'confirm',
43
+ message: 'Are you sure you want to proceed?',
44
+ required: true
45
+ },
46
+ {
47
+ name: 'recursive',
48
+ type: 'confirm',
49
+ message: 'Deploy recursively through dependencies?',
50
+ useDefault: true,
51
+ default: true,
52
+ required: false
53
+ },
54
+ {
55
+ name: 'tx',
56
+ type: 'confirm',
57
+ message: 'Use Transaction?',
58
+ useDefault: true,
59
+ default: true,
60
+ required: false
61
+ }
62
+ ];
63
+ let { yes, recursive, cwd, tx } = await prompter.prompt(argv, questions);
64
+ if (!yes) {
65
+ log.info('Operation cancelled.');
66
+ return;
67
+ }
68
+ log.debug(`Using current directory: ${cwd}`);
69
+ let packageName;
70
+ if (recursive && argv.to !== true) {
71
+ packageName = await selectDeployedPackage(database, argv, prompter, log, 'revert');
72
+ if (!packageName) {
73
+ await cliExitWithError('No package found to revert');
74
+ }
75
+ }
76
+ const pkg = new LaunchQLPackage(cwd);
77
+ const opts = getEnvOptions({
78
+ pg: getPgEnvOptions({ database }),
79
+ deployment: {
80
+ useTx: tx
81
+ }
82
+ });
83
+ let target;
84
+ if (argv.to === true) {
85
+ target = await selectDeployedChange(database, argv, prompter, log, 'revert');
86
+ if (!target) {
87
+ await cliExitWithError('No target selected, operation cancelled');
88
+ }
89
+ }
90
+ else if (packageName && argv.to) {
91
+ target = `${packageName}:${argv.to}`;
92
+ }
93
+ else if (packageName) {
94
+ target = packageName;
95
+ }
96
+ else if (argv.package && argv.to) {
97
+ target = `${argv.package}:${argv.to}`;
98
+ }
99
+ else if (argv.package) {
100
+ target = argv.package;
101
+ }
102
+ await pkg.revert(opts, target, recursive);
103
+ log.success('Revert complete.');
104
+ return argv;
105
+ };
@@ -0,0 +1,185 @@
1
+ import { Logger } from '@launchql/logger';
2
+ import { LaunchQLServer as server } from '@launchql/server';
3
+ import { getEnvOptions } from '@launchql/env';
4
+ import { getPgPool } from 'pg-cache';
5
+ const log = new Logger('server');
6
+ const serverUsageText = `
7
+ LaunchQL Server Command:
8
+
9
+ lql server [OPTIONS]
10
+
11
+ Start LaunchQL GraphQL development server.
12
+
13
+ Options:
14
+ --help, -h Show this help message
15
+ --port <number> Server port (default: 5555)
16
+ --simpleInflection Use simple inflection (default: true)
17
+ --oppositeBaseNames Use opposite base names (default: false)
18
+ --postgis Enable PostGIS extension (default: true)
19
+ --metaApi Enable Meta API (default: true)
20
+ --cwd <directory> Working directory (default: current directory)
21
+
22
+ Examples:
23
+ lql server Start server with defaults
24
+ lql server --port 8080 Start server on custom port
25
+ lql server --no-postgis Start server without PostGIS
26
+ `;
27
+ const questions = [
28
+ {
29
+ name: 'simpleInflection',
30
+ message: 'Use simple inflection?',
31
+ type: 'confirm',
32
+ required: false,
33
+ default: true,
34
+ useDefault: true
35
+ },
36
+ {
37
+ name: 'oppositeBaseNames',
38
+ message: 'Use opposite base names?',
39
+ type: 'confirm',
40
+ required: false,
41
+ default: false,
42
+ useDefault: true
43
+ },
44
+ {
45
+ name: 'postgis',
46
+ message: 'Enable PostGIS extension?',
47
+ type: 'confirm',
48
+ required: false,
49
+ default: true,
50
+ useDefault: true
51
+ },
52
+ {
53
+ name: 'metaApi',
54
+ message: 'Enable Meta API?',
55
+ type: 'confirm',
56
+ required: false,
57
+ default: true,
58
+ useDefault: true
59
+ },
60
+ {
61
+ name: 'origin',
62
+ message: 'CORS origin (exact URL or *)',
63
+ type: 'text',
64
+ required: false,
65
+ // no default to avoid accidentally opening up CORS; pass explicitly or via env
66
+ },
67
+ {
68
+ name: 'port',
69
+ message: 'Development server port',
70
+ type: 'number',
71
+ required: false,
72
+ default: 5555,
73
+ useDefault: true
74
+ }
75
+ ];
76
+ export default async (argv, prompter, _options) => {
77
+ // Show usage if explicitly requested
78
+ if (argv.help || argv.h) {
79
+ console.log(serverUsageText);
80
+ process.exit(0);
81
+ }
82
+ log.info('🔧 LaunchQL Server Configuration:\n');
83
+ let selectedDb = process.env.PGDATABASE;
84
+ if (!selectedDb) {
85
+ const db = await getPgPool({ database: 'postgres' });
86
+ const result = await db.query(`
87
+ SELECT datname FROM pg_database
88
+ WHERE datistemplate = false AND datname NOT IN ('postgres')
89
+ AND datname !~ '^pg_'
90
+ ORDER BY datname;
91
+ `);
92
+ const dbChoices = result.rows.map(row => row.datname);
93
+ const { database } = await prompter.prompt(argv, [
94
+ {
95
+ type: 'autocomplete',
96
+ name: 'database',
97
+ message: 'Select the database to use',
98
+ options: dbChoices,
99
+ required: true
100
+ }
101
+ ]);
102
+ selectedDb = database;
103
+ log.info(`📌 Using database: "${selectedDb}"`);
104
+ }
105
+ const { oppositeBaseNames, port, postgis, simpleInflection, metaApi, origin } = await prompter.prompt(argv, questions);
106
+ // Warn when passing CORS override via CLI, especially in production
107
+ if (origin && origin.trim().length) {
108
+ const env = (process.env.NODE_ENV || 'development').toLowerCase();
109
+ if (env === 'production') {
110
+ if (origin.trim() === '*') {
111
+ log.warn('CORS wildcard ("*") provided via --origin in production: this effectively disables CORS and is not recommended. Prefer per-API CORS via meta schema.');
112
+ }
113
+ else {
114
+ log.warn(`CORS override (origin=${origin.trim()}) provided via --origin in production. Prefer per-API CORS via meta schema.`);
115
+ }
116
+ }
117
+ }
118
+ let selectedSchemas = [];
119
+ let authRole;
120
+ let roleName;
121
+ if (!metaApi) {
122
+ const db = await getPgPool({ database: selectedDb });
123
+ const result = await db.query(`
124
+ SELECT nspname
125
+ FROM pg_namespace
126
+ WHERE nspname NOT IN ('pg_catalog', 'information_schema')
127
+ ORDER BY nspname;
128
+ `);
129
+ const schemaChoices = result.rows.map(row => ({
130
+ name: row.nspname,
131
+ value: row.nspname,
132
+ selected: true
133
+ }));
134
+ const { schemas } = await prompter.prompt(argv, [
135
+ {
136
+ type: 'checkbox',
137
+ name: 'schemas',
138
+ message: 'Select schemas to expose',
139
+ options: schemaChoices,
140
+ required: true
141
+ }
142
+ ]);
143
+ selectedSchemas = schemas.filter(s => s.selected).map(s => s.value);
144
+ const { authRole: selectedAuthRole, roleName: selectedRoleName } = await prompter.prompt(argv, [
145
+ {
146
+ type: 'autocomplete',
147
+ name: 'authRole',
148
+ message: 'Select the authentication role',
149
+ options: ['postgres', 'authenticated', 'anonymous'],
150
+ required: true
151
+ },
152
+ {
153
+ type: 'autocomplete',
154
+ name: 'roleName',
155
+ message: 'Enter the default role name:',
156
+ options: ['postgres', 'authenticated', 'anonymous'],
157
+ required: true
158
+ }
159
+ ]);
160
+ authRole = selectedAuthRole;
161
+ roleName = selectedRoleName;
162
+ }
163
+ const options = getEnvOptions({
164
+ pg: { database: selectedDb },
165
+ features: {
166
+ oppositeBaseNames,
167
+ simpleInflection,
168
+ postgis
169
+ },
170
+ api: {
171
+ enableMetaApi: metaApi,
172
+ ...(metaApi === false && { exposedSchemas: selectedSchemas, authRole, roleName })
173
+ },
174
+ server: {
175
+ port,
176
+ ...(origin ? { origin } : {})
177
+ }
178
+ });
179
+ log.success('✅ Selected Configuration:');
180
+ for (const [key, value] of Object.entries(options)) {
181
+ log.debug(`${key}: ${JSON.stringify(value)}`);
182
+ }
183
+ log.success('🚀 Launching Server...\n');
184
+ server(options);
185
+ };
@@ -0,0 +1,133 @@
1
+ import { LaunchQLPackage } from '@launchql/core';
2
+ import { Logger } from '@launchql/logger';
3
+ import { errors } from '@launchql/types';
4
+ import { extractFirst } from '../utils/argv';
5
+ import { selectPackage } from '../utils/module-utils';
6
+ import * as path from 'path';
7
+ const log = new Logger('tag');
8
+ const tagUsageText = `
9
+ LaunchQL Tag Command:
10
+
11
+ lql tag [tag_name] [OPTIONS]
12
+
13
+ Add tags to changes for versioning.
14
+
15
+ Arguments:
16
+ tag_name Name of the tag to create
17
+
18
+ Options:
19
+ --help, -h Show this help message
20
+ --package <name> Target specific package
21
+ --changeName <name> Target specific change (default: latest)
22
+ --comment <text> Optional tag comment
23
+ --cwd <directory> Working directory (default: current directory)
24
+
25
+ Examples:
26
+ lql tag v1.0.0 Add tag to latest change
27
+ lql tag v1.0.0 --comment "Initial release" Add tag with comment
28
+ lql tag v1.1.0 --package mypackage --changeName my-change Tag specific change in package
29
+ `;
30
+ export default async (argv, prompter, _options) => {
31
+ // Show usage if explicitly requested
32
+ if (argv.help || argv.h) {
33
+ console.log(tagUsageText);
34
+ process.exit(0);
35
+ }
36
+ const { first: tagName, newArgv } = extractFirst(argv);
37
+ const cwdResult = await prompter.prompt(newArgv, [
38
+ {
39
+ type: 'text',
40
+ name: 'cwd',
41
+ message: 'Working directory',
42
+ required: false,
43
+ default: process.cwd(),
44
+ useDefault: true
45
+ }
46
+ ]);
47
+ const cwd = cwdResult.cwd || process.cwd();
48
+ const pkg = new LaunchQLPackage(cwd);
49
+ let packageName;
50
+ if (argv.package) {
51
+ packageName = argv.package;
52
+ log.info(`Using specified package: ${packageName}`);
53
+ }
54
+ else if (pkg.isInModule()) {
55
+ packageName = pkg.getModuleName();
56
+ log.info(`Using current module: ${packageName}`);
57
+ }
58
+ else if (pkg.isInWorkspace()) {
59
+ packageName = await selectPackage(newArgv, prompter, cwd, 'add tag to', log);
60
+ if (!packageName) {
61
+ throw new Error('No package selected. Cannot add tag without specifying a target package.');
62
+ }
63
+ }
64
+ else {
65
+ throw new Error('This command must be run inside a LaunchQL workspace or module.');
66
+ }
67
+ const questions = [];
68
+ if (!tagName) {
69
+ questions.push({
70
+ type: 'text',
71
+ name: 'tagName',
72
+ message: 'Tag name',
73
+ required: true,
74
+ validate: (value) => {
75
+ if (!value || value.trim().length === 0) {
76
+ return false;
77
+ }
78
+ if (value.includes('/')) {
79
+ return false;
80
+ }
81
+ if (value.includes('@')) {
82
+ return false;
83
+ }
84
+ return true;
85
+ }
86
+ });
87
+ }
88
+ questions.push({
89
+ type: 'text',
90
+ name: 'changeName',
91
+ message: 'Target change name (leave empty for latest change)',
92
+ required: false
93
+ }, {
94
+ type: 'text',
95
+ name: 'comment',
96
+ message: 'Tag comment (optional)',
97
+ required: false
98
+ });
99
+ const answers = await prompter.prompt(newArgv, questions);
100
+ const finalTagName = tagName || answers.tagName;
101
+ const changeName = answers.changeName;
102
+ const comment = answers.comment;
103
+ try {
104
+ if (argv.package || !pkg.isInModule()) {
105
+ const moduleMap = pkg.getModuleMap();
106
+ const module = moduleMap[packageName];
107
+ if (!module) {
108
+ throw errors.MODULE_NOT_FOUND({ name: packageName });
109
+ }
110
+ const workspacePath = pkg.getWorkspacePath();
111
+ const absoluteModulePath = path.resolve(workspacePath, module.path);
112
+ const originalCwd = process.cwd();
113
+ process.chdir(absoluteModulePath);
114
+ try {
115
+ const modulePkg = new LaunchQLPackage(absoluteModulePath);
116
+ modulePkg.addTag(finalTagName.trim(), changeName?.trim() || undefined, comment?.trim() || undefined);
117
+ log.info(`Successfully added tag '${finalTagName}' to ${changeName || 'latest change'} in package '${packageName}'`);
118
+ }
119
+ finally {
120
+ process.chdir(originalCwd);
121
+ }
122
+ }
123
+ else {
124
+ pkg.addTag(finalTagName.trim(), changeName?.trim() || undefined, comment?.trim() || undefined);
125
+ log.info(`Successfully added tag '${finalTagName}' to ${changeName || 'latest change'}`);
126
+ }
127
+ }
128
+ catch (error) {
129
+ log.error(`Failed to add tag: ${error instanceof Error ? error.message : String(error)}`);
130
+ throw error;
131
+ }
132
+ return newArgv;
133
+ };