@launchframe/cli 1.0.0-beta.25 → 1.0.0-beta.26
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/LICENSE +21 -0
- package/package.json +1 -1
- package/src/commands/help.js +5 -6
- package/src/commands/migration-create.js +40 -0
- package/src/commands/migration-revert.js +32 -0
- package/src/commands/migration-run.js +32 -0
- package/src/index.js +15 -2
- package/src/utils/telemetry.js +10 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 LaunchFrame
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/package.json
CHANGED
package/src/commands/help.js
CHANGED
|
@@ -37,6 +37,11 @@ function help() {
|
|
|
37
37
|
console.log(chalk.gray(' docker:logs [service] View logs from all services or specific service'));
|
|
38
38
|
console.log(chalk.gray(' docker:destroy Remove all resources (containers, volumes, images)'));
|
|
39
39
|
console.log(chalk.gray(' --force, -f Skip confirmation prompt\n'));
|
|
40
|
+
console.log(chalk.white('Database Migrations:'));
|
|
41
|
+
console.log(chalk.gray(' migration:run Run pending database migrations'));
|
|
42
|
+
console.log(chalk.gray(' migration:create Create new database migration'));
|
|
43
|
+
console.log(chalk.gray(' migration:revert Revert last database migration\n'));
|
|
44
|
+
|
|
40
45
|
console.log(chalk.white('Service Management:'));
|
|
41
46
|
console.log(chalk.gray(' service:add <name> Add an optional service to your project'));
|
|
42
47
|
console.log(chalk.gray(' service:list List available services'));
|
|
@@ -77,9 +82,6 @@ function help() {
|
|
|
77
82
|
} else {
|
|
78
83
|
console.log(chalk.white('Available commands:'));
|
|
79
84
|
console.log(chalk.gray(' init Initialize a new LaunchFrame project'));
|
|
80
|
-
console.log(chalk.gray(' --project-name <name> Project name (skips prompt)'));
|
|
81
|
-
console.log(chalk.gray(' --tenancy <single|multi> Tenancy model (skips prompt)'));
|
|
82
|
-
console.log(chalk.gray(' --user-model <b2b|b2b2c> User model (skips prompt)'));
|
|
83
85
|
console.log(chalk.gray(' help Show this help message\n'));
|
|
84
86
|
console.log(chalk.white('Telemetry:'));
|
|
85
87
|
console.log(chalk.gray(' telemetry Show telemetry status'));
|
|
@@ -90,10 +92,7 @@ function help() {
|
|
|
90
92
|
console.log(chalk.gray(' cache:update Force update cache to latest version'));
|
|
91
93
|
console.log(chalk.gray(' cache:clear Delete cache (re-download on next use)\n'));
|
|
92
94
|
console.log(chalk.white('Examples:'));
|
|
93
|
-
console.log(chalk.gray(' # Interactive mode'));
|
|
94
95
|
console.log(chalk.gray(' launchframe init\n'));
|
|
95
|
-
console.log(chalk.gray(' # Non-interactive mode'));
|
|
96
|
-
console.log(chalk.gray(' launchframe init --project-name my-saas --tenancy single --user-model b2b\n'));
|
|
97
96
|
console.log(chalk.gray(' # With verbose output'));
|
|
98
97
|
console.log(chalk.gray(' launchframe init --verbose\n'));
|
|
99
98
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const { execSync } = require('child_process');
|
|
5
|
+
const { requireProject } = require('../utils/project-helpers');
|
|
6
|
+
|
|
7
|
+
async function migrateCreate() {
|
|
8
|
+
requireProject();
|
|
9
|
+
|
|
10
|
+
const infrastructurePath = path.join(process.cwd(), 'infrastructure');
|
|
11
|
+
|
|
12
|
+
if (!fs.existsSync(infrastructurePath)) {
|
|
13
|
+
console.error(chalk.red('\n❌ Error: infrastructure/ directory not found'));
|
|
14
|
+
console.log(chalk.gray('Make sure you are in the root of your LaunchFrame project.\n'));
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const migrationName = process.argv[3];
|
|
19
|
+
|
|
20
|
+
if (!migrationName) {
|
|
21
|
+
console.error(chalk.red('\n❌ Error: migration name is required'));
|
|
22
|
+
console.log(chalk.gray('Usage: launchframe migrate:create <name>\n'));
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
console.log(chalk.blue.bold(`\n🗄️ Creating migration: ${migrationName}\n`));
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
execSync(`docker compose -f docker-compose.yml -f docker-compose.dev.yml exec backend npm run migration:create -- ${migrationName}`, {
|
|
30
|
+
cwd: infrastructurePath,
|
|
31
|
+
stdio: 'inherit'
|
|
32
|
+
});
|
|
33
|
+
console.log(chalk.green.bold('\n✅ Migration created successfully.\n'));
|
|
34
|
+
} catch (error) {
|
|
35
|
+
console.error(chalk.red('\n❌ Error creating migration:'), error.message);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = { migrateCreate };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const { execSync } = require('child_process');
|
|
5
|
+
const { requireProject } = require('../utils/project-helpers');
|
|
6
|
+
|
|
7
|
+
async function migrateRevert() {
|
|
8
|
+
requireProject();
|
|
9
|
+
|
|
10
|
+
const infrastructurePath = path.join(process.cwd(), 'infrastructure');
|
|
11
|
+
|
|
12
|
+
if (!fs.existsSync(infrastructurePath)) {
|
|
13
|
+
console.error(chalk.red('\n❌ Error: infrastructure/ directory not found'));
|
|
14
|
+
console.log(chalk.gray('Make sure you are in the root of your LaunchFrame project.\n'));
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
console.log(chalk.blue.bold('\n🗄️ Reverting last database migration\n'));
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
execSync('docker compose -f docker-compose.yml -f docker-compose.dev.yml exec backend npm run migration:revert', {
|
|
22
|
+
cwd: infrastructurePath,
|
|
23
|
+
stdio: 'inherit'
|
|
24
|
+
});
|
|
25
|
+
console.log(chalk.green.bold('\n✅ Migration reverted successfully.\n'));
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.error(chalk.red('\n❌ Error reverting migration:'), error.message);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module.exports = { migrateRevert };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const { execSync } = require('child_process');
|
|
5
|
+
const { requireProject } = require('../utils/project-helpers');
|
|
6
|
+
|
|
7
|
+
async function migrateRun() {
|
|
8
|
+
requireProject();
|
|
9
|
+
|
|
10
|
+
const infrastructurePath = path.join(process.cwd(), 'infrastructure');
|
|
11
|
+
|
|
12
|
+
if (!fs.existsSync(infrastructurePath)) {
|
|
13
|
+
console.error(chalk.red('\n❌ Error: infrastructure/ directory not found'));
|
|
14
|
+
console.log(chalk.gray('Make sure you are in the root of your LaunchFrame project.\n'));
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
console.log(chalk.blue.bold('\n🗄️ Running database migrations\n'));
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
execSync('docker compose -f docker-compose.yml -f docker-compose.dev.yml exec backend npm run migration:run', {
|
|
22
|
+
cwd: infrastructurePath,
|
|
23
|
+
stdio: 'inherit'
|
|
24
|
+
});
|
|
25
|
+
console.log(chalk.green.bold('\n✅ Migrations completed successfully.\n'));
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.error(chalk.red('\n❌ Error running migrations:'), error.message);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module.exports = { migrateRun };
|
package/src/index.js
CHANGED
|
@@ -8,7 +8,8 @@ const { initTelemetry, trackEvent, sanitize, setTelemetryEnabled, showTelemetryS
|
|
|
8
8
|
// Detect locally linked version: npm link installs to global node_modules
|
|
9
9
|
// as a symlink. When running from a real install, __dirname is inside the
|
|
10
10
|
// global node_modules folder. When linked, it resolves to the source directory.
|
|
11
|
-
|
|
11
|
+
const isDevMode = !__dirname.includes('node_modules');
|
|
12
|
+
if (isDevMode) {
|
|
12
13
|
const packageJson = require('../package.json');
|
|
13
14
|
console.log(chalk.yellow(`⚠ Running locally linked CLI v${packageJson.version} (${__dirname})`));
|
|
14
15
|
}
|
|
@@ -28,6 +29,9 @@ const { dockerBuild } = require('./commands/docker-build');
|
|
|
28
29
|
const { dockerUp } = require('./commands/docker-up');
|
|
29
30
|
const { dockerDown } = require('./commands/docker-down');
|
|
30
31
|
const { dockerLogs } = require('./commands/docker-logs');
|
|
32
|
+
const { migrateRun } = require('./commands/migration-run');
|
|
33
|
+
const { migrateCreate } = require('./commands/migration-create');
|
|
34
|
+
const { migrateRevert } = require('./commands/migration-revert');
|
|
31
35
|
const { dockerDestroy } = require('./commands/docker-destroy');
|
|
32
36
|
const { doctor } = require('./commands/doctor');
|
|
33
37
|
const { help } = require('./commands/help');
|
|
@@ -99,7 +103,7 @@ async function main() {
|
|
|
99
103
|
// Route commands
|
|
100
104
|
switch (command) {
|
|
101
105
|
case 'init':
|
|
102
|
-
await init({
|
|
106
|
+
await init({
|
|
103
107
|
projectName: flags['project-name'],
|
|
104
108
|
tenancy: flags['tenancy'],
|
|
105
109
|
userModel: flags['user-model']
|
|
@@ -147,6 +151,15 @@ async function main() {
|
|
|
147
151
|
case 'docker:destroy':
|
|
148
152
|
await dockerDestroy({ force: flags.force || flags.f });
|
|
149
153
|
break;
|
|
154
|
+
case 'migration:run':
|
|
155
|
+
await migrateRun();
|
|
156
|
+
break;
|
|
157
|
+
case 'migration:create':
|
|
158
|
+
await migrateCreate();
|
|
159
|
+
break;
|
|
160
|
+
case 'migration:revert':
|
|
161
|
+
await migrateRevert();
|
|
162
|
+
break;
|
|
150
163
|
case 'doctor':
|
|
151
164
|
await doctor();
|
|
152
165
|
break;
|
package/src/utils/telemetry.js
CHANGED
|
@@ -63,11 +63,20 @@ function isDisabledByEnv() {
|
|
|
63
63
|
return process.env.DO_NOT_TRACK === '1' || process.env.LAUNCHFRAME_TELEMETRY_DISABLED === '1';
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
/**
|
|
67
|
+
* Check if running from a locally linked (dev) version
|
|
68
|
+
* @returns {boolean} True if running via npm link
|
|
69
|
+
*/
|
|
70
|
+
function isDevMode() {
|
|
71
|
+
return !__dirname.includes('node_modules');
|
|
72
|
+
}
|
|
73
|
+
|
|
66
74
|
/**
|
|
67
75
|
* Check if telemetry is enabled
|
|
68
76
|
* @returns {boolean} True if telemetry is enabled
|
|
69
77
|
*/
|
|
70
78
|
function isEnabled() {
|
|
79
|
+
if (isDevMode()) return false;
|
|
71
80
|
if (isDisabledByEnv()) return false;
|
|
72
81
|
if (!config || !config.telemetry) return false;
|
|
73
82
|
return config.telemetry.enabled !== false;
|
|
@@ -96,7 +105,7 @@ function initTelemetry() {
|
|
|
96
105
|
writeConfig(config);
|
|
97
106
|
}
|
|
98
107
|
|
|
99
|
-
if (!config.telemetry.noticeShown && !isDisabledByEnv()) {
|
|
108
|
+
if (!config.telemetry.noticeShown && !isDisabledByEnv() && !isDevMode()) {
|
|
100
109
|
console.log(
|
|
101
110
|
chalk.gray(
|
|
102
111
|
'\nLaunchFrame collects anonymous usage data to improve the CLI.\n' +
|