@habeetat/cli 0.1.0-dev.20260422103110.f3c4547 → 0.1.0-dev.20260423214949.af95b06
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/dist/{bin.js → bin.mjs} +139 -145
- package/dist/bin.mjs.map +1 -0
- package/dist/scripts/nhp-seed-dev.property.spec.ts +107 -0
- package/dist/scripts/nhp-seed-dev.ts +49 -36
- package/package.json +2 -2
- package/dist/bin.js.map +0 -1
package/dist/{bin.js → bin.mjs}
RENAMED
|
@@ -1,41 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import fs2, { readFileSync } from 'fs';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import ora from 'ora';
|
|
7
|
+
import chalk3 from 'chalk';
|
|
8
|
+
import { execa, execaCommand } from 'execa';
|
|
9
|
+
import { createInterface } from 'readline';
|
|
3
10
|
|
|
4
|
-
var
|
|
5
|
-
var fs2 = require('fs');
|
|
6
|
-
var path = require('path');
|
|
7
|
-
var ora = require('ora');
|
|
8
|
-
var chalk3 = require('chalk');
|
|
9
|
-
var execa = require('execa');
|
|
10
|
-
var readline = require('readline');
|
|
11
|
-
|
|
12
|
-
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
|
-
|
|
14
|
-
var fs2__default = /*#__PURE__*/_interopDefault(fs2);
|
|
15
|
-
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
16
|
-
var ora__default = /*#__PURE__*/_interopDefault(ora);
|
|
17
|
-
var chalk3__default = /*#__PURE__*/_interopDefault(chalk3);
|
|
18
|
-
|
|
19
|
-
var prefix = chalk3__default.default.cyan("[habeetat]");
|
|
11
|
+
var prefix = chalk3.cyan("[habeetat]");
|
|
20
12
|
var logger = {
|
|
21
13
|
info: (msg) => console.log(`${prefix} ${msg}`),
|
|
22
|
-
success: (msg) => console.log(`${prefix} ${
|
|
23
|
-
warn: (msg) => console.log(`${prefix} ${
|
|
24
|
-
error: (msg) => console.error(`${prefix} ${
|
|
14
|
+
success: (msg) => console.log(`${prefix} ${chalk3.green("\u2713")} ${msg}`),
|
|
15
|
+
warn: (msg) => console.log(`${prefix} ${chalk3.yellow("\u26A0")} ${msg}`),
|
|
16
|
+
error: (msg) => console.error(`${prefix} ${chalk3.red("\u2717")} ${msg}`),
|
|
25
17
|
phase: (msg) => {
|
|
26
18
|
console.log("");
|
|
27
|
-
console.log(
|
|
28
|
-
console.log(
|
|
29
|
-
console.log(
|
|
19
|
+
console.log(chalk3.cyan("\u2550".repeat(56)));
|
|
20
|
+
console.log(chalk3.cyan(` ${msg}`));
|
|
21
|
+
console.log(chalk3.cyan("\u2550".repeat(56)));
|
|
30
22
|
console.log("");
|
|
31
23
|
},
|
|
32
24
|
banner: () => {
|
|
33
25
|
console.log("");
|
|
34
|
-
console.log(
|
|
35
|
-
console.log(
|
|
36
|
-
console.log(
|
|
37
|
-
console.log(
|
|
38
|
-
console.log(
|
|
26
|
+
console.log(chalk3.cyan("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
|
|
27
|
+
console.log(chalk3.cyan("\u2551 \u2551"));
|
|
28
|
+
console.log(chalk3.cyan("\u2551 Habeetat Platform CLI \u2551"));
|
|
29
|
+
console.log(chalk3.cyan("\u2551 \u2551"));
|
|
30
|
+
console.log(chalk3.cyan("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
|
|
39
31
|
console.log("");
|
|
40
32
|
}
|
|
41
33
|
};
|
|
@@ -66,11 +58,11 @@ var SERVICES = [
|
|
|
66
58
|
// src/utils/config.ts
|
|
67
59
|
function findProjectRoot(startDir = process.cwd()) {
|
|
68
60
|
let dir = startDir;
|
|
69
|
-
while (dir !==
|
|
70
|
-
if (
|
|
61
|
+
while (dir !== path.dirname(dir)) {
|
|
62
|
+
if (fs2.existsSync(path.join(dir, CONFIG_FILE))) {
|
|
71
63
|
return dir;
|
|
72
64
|
}
|
|
73
|
-
dir =
|
|
65
|
+
dir = path.dirname(dir);
|
|
74
66
|
}
|
|
75
67
|
return null;
|
|
76
68
|
}
|
|
@@ -81,8 +73,8 @@ function loadConfig(projectDir) {
|
|
|
81
73
|
`Could not find ${CONFIG_FILE}. Are you inside a Habeetat project directory?`
|
|
82
74
|
);
|
|
83
75
|
}
|
|
84
|
-
const configPath =
|
|
85
|
-
const raw =
|
|
76
|
+
const configPath = path.join(dir, CONFIG_FILE);
|
|
77
|
+
const raw = fs2.readFileSync(configPath, "utf-8");
|
|
86
78
|
return JSON.parse(raw);
|
|
87
79
|
}
|
|
88
80
|
function getProjectDir() {
|
|
@@ -96,7 +88,7 @@ function getProjectDir() {
|
|
|
96
88
|
}
|
|
97
89
|
async function checkDocker() {
|
|
98
90
|
try {
|
|
99
|
-
const { stdout } = await
|
|
91
|
+
const { stdout } = await execaCommand("docker --version");
|
|
100
92
|
const match = stdout.match(/Docker version (\d+)/);
|
|
101
93
|
if (match && parseInt(match[1], 10) >= 20) {
|
|
102
94
|
return true;
|
|
@@ -111,7 +103,7 @@ async function checkDocker() {
|
|
|
111
103
|
}
|
|
112
104
|
async function checkDockerCompose() {
|
|
113
105
|
try {
|
|
114
|
-
await
|
|
106
|
+
await execaCommand("docker compose version");
|
|
115
107
|
return true;
|
|
116
108
|
} catch {
|
|
117
109
|
logger.error("Docker Compose V2 is not available");
|
|
@@ -126,28 +118,28 @@ async function checkPrerequisites() {
|
|
|
126
118
|
}
|
|
127
119
|
async function composeUp(opts) {
|
|
128
120
|
const file = opts.composeFile || "docker-compose.yml";
|
|
129
|
-
await
|
|
121
|
+
await execaCommand(`docker compose -f ${file} up -d`, {
|
|
130
122
|
cwd: opts.cwd,
|
|
131
123
|
stdio: opts.silent ? "pipe" : "inherit"
|
|
132
124
|
});
|
|
133
125
|
}
|
|
134
126
|
async function composeDown(opts) {
|
|
135
127
|
const file = opts.composeFile || "docker-compose.yml";
|
|
136
|
-
await
|
|
128
|
+
await execaCommand(`docker compose -f ${file} down`, {
|
|
137
129
|
cwd: opts.cwd,
|
|
138
130
|
stdio: opts.silent ? "pipe" : "inherit"
|
|
139
131
|
});
|
|
140
132
|
}
|
|
141
133
|
async function composeDestroy(opts) {
|
|
142
134
|
const file = opts.composeFile || "docker-compose.yml";
|
|
143
|
-
await
|
|
135
|
+
await execaCommand(`docker compose -f ${file} down -v --remove-orphans`, {
|
|
144
136
|
cwd: opts.cwd,
|
|
145
137
|
stdio: opts.silent ? "pipe" : "inherit"
|
|
146
138
|
});
|
|
147
139
|
}
|
|
148
140
|
async function composePs(opts) {
|
|
149
141
|
const file = opts.composeFile || "docker-compose.yml";
|
|
150
|
-
const { stdout } = await
|
|
142
|
+
const { stdout } = await execaCommand(`docker compose -f ${file} ps`, {
|
|
151
143
|
cwd: opts.cwd
|
|
152
144
|
});
|
|
153
145
|
return stdout;
|
|
@@ -158,7 +150,7 @@ async function composeLogs(opts) {
|
|
|
158
150
|
if (opts.follow) parts.push("-f");
|
|
159
151
|
if (opts.tail) parts.push("--tail", String(opts.tail));
|
|
160
152
|
if (opts.service) parts.push(opts.service);
|
|
161
|
-
await
|
|
153
|
+
await execaCommand(parts.join(" "), {
|
|
162
154
|
cwd: opts.cwd,
|
|
163
155
|
stdio: "inherit"
|
|
164
156
|
});
|
|
@@ -166,25 +158,25 @@ async function composeLogs(opts) {
|
|
|
166
158
|
async function composeRestart(opts) {
|
|
167
159
|
const file = opts.composeFile || "docker-compose.yml";
|
|
168
160
|
const cmd = opts.service ? `docker compose -f ${file} restart ${opts.service}` : `docker compose -f ${file} restart`;
|
|
169
|
-
await
|
|
161
|
+
await execaCommand(cmd, {
|
|
170
162
|
cwd: opts.cwd,
|
|
171
163
|
stdio: opts.silent ? "pipe" : "inherit"
|
|
172
164
|
});
|
|
173
165
|
}
|
|
174
166
|
var INITIALIZED_FILE = ".initialized";
|
|
175
167
|
function isInitialized(projectDir) {
|
|
176
|
-
return
|
|
168
|
+
return fs2.existsSync(path.join(projectDir, INITIALIZED_FILE));
|
|
177
169
|
}
|
|
178
170
|
function markInitialized(projectDir) {
|
|
179
|
-
|
|
180
|
-
|
|
171
|
+
fs2.writeFileSync(
|
|
172
|
+
path.join(projectDir, INITIALIZED_FILE),
|
|
181
173
|
JSON.stringify({ initializedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2) + "\n"
|
|
182
174
|
);
|
|
183
175
|
}
|
|
184
176
|
function loadEnv(projectDir) {
|
|
185
|
-
const envPath =
|
|
186
|
-
if (!
|
|
187
|
-
const lines =
|
|
177
|
+
const envPath = path.join(projectDir, ".env");
|
|
178
|
+
if (!fs2.existsSync(envPath)) return {};
|
|
179
|
+
const lines = fs2.readFileSync(envPath, "utf-8").split("\n");
|
|
188
180
|
const env = {};
|
|
189
181
|
for (const line of lines) {
|
|
190
182
|
const trimmed = line.trim();
|
|
@@ -196,7 +188,7 @@ function loadEnv(projectDir) {
|
|
|
196
188
|
return env;
|
|
197
189
|
}
|
|
198
190
|
async function execCompose(projectDir, args) {
|
|
199
|
-
const { stdout } = await
|
|
191
|
+
const { stdout } = await execaCommand(
|
|
200
192
|
`docker compose -f ${COMPOSE_FILE} ${args}`,
|
|
201
193
|
{ cwd: projectDir }
|
|
202
194
|
);
|
|
@@ -216,7 +208,7 @@ async function waitForService(projectDir, service, checkCmd, timeoutSec) {
|
|
|
216
208
|
}
|
|
217
209
|
async function getContainerState(projectDir, service) {
|
|
218
210
|
try {
|
|
219
|
-
const { stdout } = await
|
|
211
|
+
const { stdout } = await execaCommand(
|
|
220
212
|
`docker compose -f ${COMPOSE_FILE} ps ${service} --format json`,
|
|
221
213
|
{ cwd: projectDir }
|
|
222
214
|
);
|
|
@@ -599,7 +591,7 @@ async function initPlatform(projectDir) {
|
|
|
599
591
|
const config = loadConfig(projectDir);
|
|
600
592
|
const env = loadEnv(projectDir);
|
|
601
593
|
const domain = config.platform.domain;
|
|
602
|
-
const dbSpinner =
|
|
594
|
+
const dbSpinner = ora("Waiting for databases...").start();
|
|
603
595
|
const logtoDbReady = await waitForService(
|
|
604
596
|
projectDir,
|
|
605
597
|
"logto-db",
|
|
@@ -621,7 +613,7 @@ async function initPlatform(projectDir) {
|
|
|
621
613
|
throw new Error("platform-db timeout");
|
|
622
614
|
}
|
|
623
615
|
dbSpinner.succeed("Databases ready");
|
|
624
|
-
const clickhouseSpinner =
|
|
616
|
+
const clickhouseSpinner = ora("Initializing ClickHouse analytics schema...").start();
|
|
625
617
|
try {
|
|
626
618
|
const clickhouseSql = [
|
|
627
619
|
"CREATE DATABASE IF NOT EXISTS nhp_analytics",
|
|
@@ -630,7 +622,7 @@ async function initPlatform(projectDir) {
|
|
|
630
622
|
"ALTER TABLE nhp_analytics.events ADD INDEX IF NOT EXISTS idx_session_id session_id TYPE bloom_filter(0.01) GRANULARITY 4"
|
|
631
623
|
];
|
|
632
624
|
for (const sql of clickhouseSql) {
|
|
633
|
-
await execa
|
|
625
|
+
await execa("docker", [
|
|
634
626
|
"compose",
|
|
635
627
|
"-f",
|
|
636
628
|
COMPOSE_FILE,
|
|
@@ -648,7 +640,7 @@ async function initPlatform(projectDir) {
|
|
|
648
640
|
logger.error(String(err));
|
|
649
641
|
logger.info('Run manually: docker compose exec clickhouse clickhouse-client --query "CREATE DATABASE IF NOT EXISTS nhp_analytics"');
|
|
650
642
|
}
|
|
651
|
-
const logtoSpinner =
|
|
643
|
+
const logtoSpinner = ora("Waiting for Logto to be healthy (this may take up to 2 min)...").start();
|
|
652
644
|
const logtoReady = await waitForService(
|
|
653
645
|
projectDir,
|
|
654
646
|
"logto-core",
|
|
@@ -660,10 +652,10 @@ async function initPlatform(projectDir) {
|
|
|
660
652
|
throw new Error("logto-core timeout");
|
|
661
653
|
}
|
|
662
654
|
logtoSpinner.succeed("Logto is healthy");
|
|
663
|
-
const logtoSeedSpinner =
|
|
655
|
+
const logtoSeedSpinner = ora("Seeding Logto applications...").start();
|
|
664
656
|
try {
|
|
665
657
|
const sql = buildSeedLogtoAppsSql(env);
|
|
666
|
-
await
|
|
658
|
+
await execaCommand(
|
|
667
659
|
`docker compose -f ${COMPOSE_FILE} exec -T logto-db psql -U logto -d logto`,
|
|
668
660
|
{ cwd: projectDir, input: sql }
|
|
669
661
|
);
|
|
@@ -673,7 +665,7 @@ async function initPlatform(projectDir) {
|
|
|
673
665
|
logger.error(String(err));
|
|
674
666
|
throw err;
|
|
675
667
|
}
|
|
676
|
-
const bootstrapSpinner =
|
|
668
|
+
const bootstrapSpinner = ora("Bootstrapping Logto users and organizations...").start();
|
|
677
669
|
try {
|
|
678
670
|
const orgName = env.ORGANIZATION_NAME || config.platform.organization || "Default";
|
|
679
671
|
const orgSlug = orgName.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "");
|
|
@@ -681,10 +673,10 @@ async function initPlatform(projectDir) {
|
|
|
681
673
|
const adminPassword = env.PLATFORM_ADMIN_PASSWORD || "Habeetat_01";
|
|
682
674
|
const adminUsername = adminEmail.split("@")[0];
|
|
683
675
|
const logtoDbUrl = `postgres://${env.LOGTO_DB_USER || "logto"}:${env.LOGTO_DB_PASSWORD || "logto"}@logto-db:5432/${env.LOGTO_DB_NAME || "logto"}`;
|
|
684
|
-
const bootstrapScriptPath =
|
|
685
|
-
const hasLocalScript =
|
|
676
|
+
const bootstrapScriptPath = path.join(projectDir, "scripts", "nhp-seed-logto-bootstrap.mjs");
|
|
677
|
+
const hasLocalScript = fs2.existsSync(bootstrapScriptPath);
|
|
686
678
|
if (hasLocalScript) {
|
|
687
|
-
await execa
|
|
679
|
+
await execa(
|
|
688
680
|
"docker",
|
|
689
681
|
[
|
|
690
682
|
"run",
|
|
@@ -726,14 +718,14 @@ async function initPlatform(projectDir) {
|
|
|
726
718
|
logger.error(String(err));
|
|
727
719
|
logger.info("You may need to create the admin user manually via the Logto admin console");
|
|
728
720
|
}
|
|
729
|
-
const backendRunSpinner =
|
|
721
|
+
const backendRunSpinner = ora("Waiting for backend container to start...").start();
|
|
730
722
|
const backendRunning = await waitForDockerRunning(projectDir, "backend", 90);
|
|
731
723
|
if (!backendRunning) {
|
|
732
724
|
backendRunSpinner.fail("Backend container did not start");
|
|
733
725
|
throw new Error("backend container timeout");
|
|
734
726
|
}
|
|
735
727
|
backendRunSpinner.succeed("Backend container is running");
|
|
736
|
-
const migrateSpinner =
|
|
728
|
+
const migrateSpinner = ora("Running database migrations...").start();
|
|
737
729
|
try {
|
|
738
730
|
await execCompose(projectDir, "exec -T backend npx prisma migrate deploy");
|
|
739
731
|
migrateSpinner.succeed("Database migrations completed");
|
|
@@ -742,12 +734,12 @@ async function initPlatform(projectDir) {
|
|
|
742
734
|
logger.error(String(err));
|
|
743
735
|
logger.info("Run manually: docker compose exec backend npx prisma migrate deploy");
|
|
744
736
|
}
|
|
745
|
-
const seedSpinner =
|
|
737
|
+
const seedSpinner = ora("Seeding platform database...").start();
|
|
746
738
|
try {
|
|
747
739
|
const orgName = env.ORGANIZATION_NAME || config.platform.organization || "Default";
|
|
748
740
|
const orgSlug = orgName.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "");
|
|
749
741
|
const adminEmail = env.PLATFORM_ADMIN_EMAIL || config.platform.adminEmail;
|
|
750
|
-
await execa
|
|
742
|
+
await execa("docker", [
|
|
751
743
|
"compose",
|
|
752
744
|
"-f",
|
|
753
745
|
COMPOSE_FILE,
|
|
@@ -772,7 +764,7 @@ async function initPlatform(projectDir) {
|
|
|
772
764
|
} catch {
|
|
773
765
|
seedSpinner.warn("Prisma seed skipped (may not be available in Docker image)");
|
|
774
766
|
}
|
|
775
|
-
const backendSpinner =
|
|
767
|
+
const backendSpinner = ora("Waiting for backend to be healthy...").start();
|
|
776
768
|
const backendReady = await waitForDockerHealthy(
|
|
777
769
|
projectDir,
|
|
778
770
|
"backend",
|
|
@@ -784,10 +776,10 @@ async function initPlatform(projectDir) {
|
|
|
784
776
|
} else {
|
|
785
777
|
backendSpinner.succeed("Backend is healthy");
|
|
786
778
|
}
|
|
787
|
-
const platformSpinner =
|
|
779
|
+
const platformSpinner = ora("Initializing platform data...").start();
|
|
788
780
|
try {
|
|
789
781
|
const sql = buildInitPlatformSql(env);
|
|
790
|
-
await
|
|
782
|
+
await execaCommand(
|
|
791
783
|
`docker compose -f ${COMPOSE_FILE} exec -T platform-db psql -U ${env.PLATFORM_DB_USER || "habeetat"} -d ${env.PLATFORM_DB_NAME || "habeetat_platform"}`,
|
|
792
784
|
{ cwd: projectDir, input: sql }
|
|
793
785
|
);
|
|
@@ -797,13 +789,13 @@ async function initPlatform(projectDir) {
|
|
|
797
789
|
logger.error(String(err));
|
|
798
790
|
logger.info("You may need to initialize the platform manually after first login");
|
|
799
791
|
}
|
|
800
|
-
const analyticsSpinner =
|
|
792
|
+
const analyticsSpinner = ora("Seeding analytics demo data...").start();
|
|
801
793
|
try {
|
|
802
794
|
const orgName = env.ORGANIZATION_NAME || config.platform.organization || "Default";
|
|
803
795
|
const orgSlug = orgName.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "");
|
|
804
796
|
const adminUserId = "usr_plat_admin01";
|
|
805
797
|
const chSql = buildClickhouseAnalyticsSeedSql(orgSlug, adminUserId);
|
|
806
|
-
await execa
|
|
798
|
+
await execa("docker", [
|
|
807
799
|
"compose",
|
|
808
800
|
"-f",
|
|
809
801
|
COMPOSE_FILE,
|
|
@@ -813,7 +805,7 @@ async function initPlatform(projectDir) {
|
|
|
813
805
|
"clickhouse-client"
|
|
814
806
|
], { cwd: projectDir, input: chSql, stdio: ["pipe", "pipe", "pipe"] });
|
|
815
807
|
const pgSql = buildAnalyticsObjectsSql(orgSlug, adminUserId);
|
|
816
|
-
await
|
|
808
|
+
await execaCommand(
|
|
817
809
|
`docker compose -f ${COMPOSE_FILE} exec -T platform-db psql -U ${env.PLATFORM_DB_USER || "habeetat"} -d ${env.PLATFORM_DB_NAME || "habeetat_platform"}`,
|
|
818
810
|
{ cwd: projectDir, input: pgSql }
|
|
819
811
|
);
|
|
@@ -823,7 +815,7 @@ async function initPlatform(projectDir) {
|
|
|
823
815
|
logger.error(String(err));
|
|
824
816
|
}
|
|
825
817
|
if (config.services.signoz) {
|
|
826
|
-
const signozUserSpinner =
|
|
818
|
+
const signozUserSpinner = ora("Creating SigNoz admin user...").start();
|
|
827
819
|
try {
|
|
828
820
|
const signozReady = await waitForDockerHealthy(projectDir, "signoz-query-service", 120);
|
|
829
821
|
if (!signozReady) {
|
|
@@ -839,7 +831,7 @@ async function initPlatform(projectDir) {
|
|
|
839
831
|
organizationName: orgName
|
|
840
832
|
});
|
|
841
833
|
try {
|
|
842
|
-
await execa
|
|
834
|
+
await execa("docker", [
|
|
843
835
|
"compose",
|
|
844
836
|
"-f",
|
|
845
837
|
COMPOSE_FILE,
|
|
@@ -879,7 +871,7 @@ async function upCommand() {
|
|
|
879
871
|
process.exit(1);
|
|
880
872
|
}
|
|
881
873
|
const freshInstall = !isInitialized(projectDir);
|
|
882
|
-
const spinner =
|
|
874
|
+
const spinner = ora("Starting services...").start();
|
|
883
875
|
try {
|
|
884
876
|
await composeUp({ cwd: projectDir });
|
|
885
877
|
spinner.succeed("All services started");
|
|
@@ -922,7 +914,7 @@ async function upCommand() {
|
|
|
922
914
|
}
|
|
923
915
|
async function downCommand() {
|
|
924
916
|
const projectDir = getProjectDir();
|
|
925
|
-
const spinner =
|
|
917
|
+
const spinner = ora("Stopping services...").start();
|
|
926
918
|
try {
|
|
927
919
|
await composeDown({ cwd: projectDir });
|
|
928
920
|
spinner.succeed("All services stopped");
|
|
@@ -977,7 +969,7 @@ async function restartCommand(service) {
|
|
|
977
969
|
process.exit(1);
|
|
978
970
|
}
|
|
979
971
|
const label = service || "all services";
|
|
980
|
-
const spinner =
|
|
972
|
+
const spinner = ora(`Restarting ${label}...`).start();
|
|
981
973
|
try {
|
|
982
974
|
await composeRestart({ cwd: projectDir, service });
|
|
983
975
|
spinner.succeed(`Restarted ${label}`);
|
|
@@ -989,7 +981,7 @@ async function restartCommand(service) {
|
|
|
989
981
|
}
|
|
990
982
|
async function composePull(opts) {
|
|
991
983
|
const cmd = opts.service ? `docker compose -f ${COMPOSE_FILE} pull ${opts.service}` : `docker compose -f ${COMPOSE_FILE} pull`;
|
|
992
|
-
await
|
|
984
|
+
await execaCommand(cmd, {
|
|
993
985
|
cwd: opts.cwd,
|
|
994
986
|
stdio: "inherit"
|
|
995
987
|
});
|
|
@@ -1002,7 +994,7 @@ async function updateCommand(service) {
|
|
|
1002
994
|
process.exit(1);
|
|
1003
995
|
}
|
|
1004
996
|
const label = service ? `service '${service}'` : "all services";
|
|
1005
|
-
const pullSpinner =
|
|
997
|
+
const pullSpinner = ora(`Pulling latest images for ${label}...`).start();
|
|
1006
998
|
try {
|
|
1007
999
|
await composePull({ cwd: projectDir, service });
|
|
1008
1000
|
pullSpinner.succeed("Images pulled");
|
|
@@ -1011,7 +1003,7 @@ async function updateCommand(service) {
|
|
|
1011
1003
|
logger.error(String(err));
|
|
1012
1004
|
process.exit(1);
|
|
1013
1005
|
}
|
|
1014
|
-
const upSpinner =
|
|
1006
|
+
const upSpinner = ora("Restarting updated containers...").start();
|
|
1015
1007
|
try {
|
|
1016
1008
|
await composeUp({ cwd: projectDir });
|
|
1017
1009
|
upSpinner.succeed("Platform updated and running");
|
|
@@ -1027,39 +1019,39 @@ async function doctorCommand() {
|
|
|
1027
1019
|
logger.phase("Habeetat Doctor \u2014 Diagnostics");
|
|
1028
1020
|
let issues = 0;
|
|
1029
1021
|
const dockerOk = await checkDocker();
|
|
1030
|
-
console.log(` Docker: ${dockerOk ?
|
|
1022
|
+
console.log(` Docker: ${dockerOk ? chalk3.green("\u2713 Installed") : chalk3.red("\u2717 Not found")}`);
|
|
1031
1023
|
if (!dockerOk) issues++;
|
|
1032
1024
|
const composeOk = await checkDockerCompose();
|
|
1033
|
-
console.log(` Docker Compose: ${composeOk ?
|
|
1025
|
+
console.log(` Docker Compose: ${composeOk ? chalk3.green("\u2713 Available") : chalk3.red("\u2717 Not found")}`);
|
|
1034
1026
|
if (!composeOk) issues++;
|
|
1035
1027
|
const projectDir = findProjectRoot();
|
|
1036
|
-
console.log(` Project dir: ${projectDir ?
|
|
1028
|
+
console.log(` Project dir: ${projectDir ? chalk3.green(`\u2713 ${projectDir}`) : chalk3.yellow("\u26A0 Not in a Habeetat project")}`);
|
|
1037
1029
|
if (!projectDir) {
|
|
1038
1030
|
issues++;
|
|
1039
1031
|
console.log("");
|
|
1040
1032
|
logger.info(`Run \`npm create habeetat my-platform\` to create a new project`);
|
|
1041
1033
|
return;
|
|
1042
1034
|
}
|
|
1043
|
-
const configExists =
|
|
1044
|
-
console.log(` ${CONFIG_FILE}: ${configExists ?
|
|
1035
|
+
const configExists = fs2.existsSync(path.join(projectDir, CONFIG_FILE));
|
|
1036
|
+
console.log(` ${CONFIG_FILE}: ${configExists ? chalk3.green("\u2713 Found") : chalk3.red("\u2717 Missing")}`);
|
|
1045
1037
|
if (!configExists) issues++;
|
|
1046
|
-
const composeExists =
|
|
1047
|
-
console.log(` ${COMPOSE_FILE}: ${composeExists ?
|
|
1038
|
+
const composeExists = fs2.existsSync(path.join(projectDir, COMPOSE_FILE));
|
|
1039
|
+
console.log(` ${COMPOSE_FILE}: ${composeExists ? chalk3.green("\u2713 Found") : chalk3.red("\u2717 Missing")}`);
|
|
1048
1040
|
if (!composeExists) issues++;
|
|
1049
|
-
const envExists =
|
|
1050
|
-
console.log(` ${ENV_FILE}: ${envExists ?
|
|
1041
|
+
const envExists = fs2.existsSync(path.join(projectDir, ENV_FILE));
|
|
1042
|
+
console.log(` ${ENV_FILE}: ${envExists ? chalk3.green("\u2713 Found") : chalk3.red("\u2717 Missing")}`);
|
|
1051
1043
|
if (!envExists) issues++;
|
|
1052
|
-
const nginxExists =
|
|
1053
|
-
console.log(` nginx/platform.conf: ${nginxExists ?
|
|
1044
|
+
const nginxExists = fs2.existsSync(path.join(projectDir, "nginx", "platform.conf"));
|
|
1045
|
+
console.log(` nginx/platform.conf: ${nginxExists ? chalk3.green("\u2713 Found") : chalk3.red("\u2717 Missing")}`);
|
|
1054
1046
|
if (!nginxExists) issues++;
|
|
1055
1047
|
if (configExists) {
|
|
1056
1048
|
try {
|
|
1057
1049
|
const config = loadConfig(projectDir);
|
|
1058
|
-
console.log(` Version: ${
|
|
1059
|
-
console.log(` Domain: ${
|
|
1060
|
-
console.log(` Protocol: ${
|
|
1050
|
+
console.log(` Version: ${chalk3.cyan(config.version)}`);
|
|
1051
|
+
console.log(` Domain: ${chalk3.cyan(config.platform.domain)}`);
|
|
1052
|
+
console.log(` Protocol: ${chalk3.cyan(config.platform.protocol)}`);
|
|
1061
1053
|
} catch (err) {
|
|
1062
|
-
console.log(` Config: ${
|
|
1054
|
+
console.log(` Config: ${chalk3.red("\u2717 Invalid JSON")}`);
|
|
1063
1055
|
issues++;
|
|
1064
1056
|
}
|
|
1065
1057
|
}
|
|
@@ -1071,7 +1063,7 @@ async function doctorCommand() {
|
|
|
1071
1063
|
}
|
|
1072
1064
|
}
|
|
1073
1065
|
async function confirm(message) {
|
|
1074
|
-
const rl =
|
|
1066
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
1075
1067
|
return new Promise((resolve) => {
|
|
1076
1068
|
rl.question(`${message} (y/N) `, (answer) => {
|
|
1077
1069
|
rl.close();
|
|
@@ -1095,7 +1087,7 @@ async function destroyCommand(options) {
|
|
|
1095
1087
|
return;
|
|
1096
1088
|
}
|
|
1097
1089
|
}
|
|
1098
|
-
const spinner =
|
|
1090
|
+
const spinner = ora("Destroying platform...").start();
|
|
1099
1091
|
try {
|
|
1100
1092
|
await composeDestroy({ cwd: projectDir });
|
|
1101
1093
|
spinner.succeed("Platform destroyed \u2014 all containers and volumes removed");
|
|
@@ -1107,12 +1099,12 @@ async function destroyCommand(options) {
|
|
|
1107
1099
|
process.exit(1);
|
|
1108
1100
|
}
|
|
1109
1101
|
}
|
|
1110
|
-
var SEED_SCRIPT_PATH =
|
|
1102
|
+
var SEED_SCRIPT_PATH = path.resolve(__dirname, "scripts/nhp-seed-dev.ts");
|
|
1111
1103
|
var SEED_SCRIPT_REMOTE = "/app/apps/habeetat-backend/nhp-seed-dev-tmp.ts";
|
|
1112
1104
|
function loadEnv2(projectDir) {
|
|
1113
|
-
const envPath =
|
|
1114
|
-
if (!
|
|
1115
|
-
const lines =
|
|
1105
|
+
const envPath = path.join(projectDir, ".env");
|
|
1106
|
+
if (!fs2.existsSync(envPath)) return {};
|
|
1107
|
+
const lines = fs2.readFileSync(envPath, "utf-8").split("\n");
|
|
1116
1108
|
const env = {};
|
|
1117
1109
|
for (const line of lines) {
|
|
1118
1110
|
const trimmed = line.trim();
|
|
@@ -1124,13 +1116,13 @@ function loadEnv2(projectDir) {
|
|
|
1124
1116
|
return env;
|
|
1125
1117
|
}
|
|
1126
1118
|
async function runSeedScript(projectDir, command, args) {
|
|
1127
|
-
if (!
|
|
1119
|
+
if (!fs2.existsSync(SEED_SCRIPT_PATH)) {
|
|
1128
1120
|
throw new Error(
|
|
1129
1121
|
`Seed script not found at ${SEED_SCRIPT_PATH}. This is a bug \u2014 please reinstall @habeetat/cli.`
|
|
1130
1122
|
);
|
|
1131
1123
|
}
|
|
1132
|
-
const scriptContent =
|
|
1133
|
-
await execa
|
|
1124
|
+
const scriptContent = fs2.readFileSync(SEED_SCRIPT_PATH, "utf-8");
|
|
1125
|
+
await execa(
|
|
1134
1126
|
"docker",
|
|
1135
1127
|
[
|
|
1136
1128
|
"compose",
|
|
@@ -1149,7 +1141,7 @@ async function runSeedScript(projectDir, command, args) {
|
|
|
1149
1141
|
let stderr = "";
|
|
1150
1142
|
try {
|
|
1151
1143
|
const scriptFilename = SEED_SCRIPT_REMOTE.split("/").pop();
|
|
1152
|
-
({ stdout, stderr } = await execa
|
|
1144
|
+
({ stdout, stderr } = await execa(
|
|
1153
1145
|
"docker",
|
|
1154
1146
|
[
|
|
1155
1147
|
"compose",
|
|
@@ -1167,7 +1159,7 @@ async function runSeedScript(projectDir, command, args) {
|
|
|
1167
1159
|
{ cwd: projectDir, stdio: "pipe" }
|
|
1168
1160
|
));
|
|
1169
1161
|
} finally {
|
|
1170
|
-
await execa
|
|
1162
|
+
await execa(
|
|
1171
1163
|
"docker",
|
|
1172
1164
|
[
|
|
1173
1165
|
"compose",
|
|
@@ -1199,49 +1191,49 @@ function printSdkConfig(config, env, parts) {
|
|
|
1199
1191
|
const iamAudience = env.IAM_AUDIENCE || `${protocol}://api.${domain}/api`;
|
|
1200
1192
|
const apiUrl = iamAudience.replace(/\/api$/, "");
|
|
1201
1193
|
console.log("");
|
|
1202
|
-
console.log(
|
|
1203
|
-
console.log(
|
|
1204
|
-
console.log(
|
|
1194
|
+
console.log(chalk3.cyan("\u2550".repeat(60)));
|
|
1195
|
+
console.log(chalk3.cyan(" SDK Configuration"));
|
|
1196
|
+
console.log(chalk3.cyan("\u2550".repeat(60)));
|
|
1205
1197
|
console.log("");
|
|
1206
1198
|
if (parts.logtoAppId) {
|
|
1207
|
-
console.log(
|
|
1208
|
-
console.log(
|
|
1209
|
-
console.log(` VITE_LOGTO_ENDPOINT=${
|
|
1210
|
-
console.log(` VITE_LOGTO_APP_ID=${
|
|
1211
|
-
console.log(` VITE_LOGTO_API_RESOURCE=${
|
|
1199
|
+
console.log(chalk3.bold(" Frontend SDK (@habeetat/sdk-react)"));
|
|
1200
|
+
console.log(chalk3.dim(" " + "\u2500".repeat(54)));
|
|
1201
|
+
console.log(` VITE_LOGTO_ENDPOINT=${chalk3.green(iamUrl)}`);
|
|
1202
|
+
console.log(` VITE_LOGTO_APP_ID=${chalk3.green(parts.logtoAppId)}`);
|
|
1203
|
+
console.log(` VITE_LOGTO_API_RESOURCE=${chalk3.green(iamAudience)}`);
|
|
1212
1204
|
if (parts.tenant) {
|
|
1213
|
-
console.log(` VITE_APP_TENANT=${
|
|
1205
|
+
console.log(` VITE_APP_TENANT=${chalk3.green(parts.tenant)}`);
|
|
1214
1206
|
}
|
|
1215
1207
|
console.log("");
|
|
1216
1208
|
}
|
|
1217
1209
|
if (parts.m2mClientId) {
|
|
1218
|
-
console.log(
|
|
1219
|
-
console.log(
|
|
1220
|
-
console.log(` HABEETAT_ENDPOINT=${
|
|
1221
|
-
console.log(` HABEETAT_LOGTO_ENDPOINT=${
|
|
1222
|
-
console.log(` HABEETAT_IAM_AUDIENCE=${
|
|
1210
|
+
console.log(chalk3.bold(" Backend SDK (@habeetat/sdk-node)"));
|
|
1211
|
+
console.log(chalk3.dim(" " + "\u2500".repeat(54)));
|
|
1212
|
+
console.log(` HABEETAT_ENDPOINT=${chalk3.green(apiUrl)}`);
|
|
1213
|
+
console.log(` HABEETAT_LOGTO_ENDPOINT=${chalk3.green(iamUrl)}`);
|
|
1214
|
+
console.log(` HABEETAT_IAM_AUDIENCE=${chalk3.green(iamAudience)}`);
|
|
1223
1215
|
if (parts.tenant) {
|
|
1224
|
-
console.log(` HABEETAT_TENANT_SLUG=${
|
|
1216
|
+
console.log(` HABEETAT_TENANT_SLUG=${chalk3.green(parts.tenant)}`);
|
|
1225
1217
|
}
|
|
1226
|
-
console.log(` HABEETAT_M2M_CLIENT_ID=${
|
|
1227
|
-
console.log(` HABEETAT_M2M_CLIENT_SECRET=${
|
|
1218
|
+
console.log(` HABEETAT_M2M_CLIENT_ID=${chalk3.green(parts.m2mClientId)}`);
|
|
1219
|
+
console.log(` HABEETAT_M2M_CLIENT_SECRET=${chalk3.green(parts.m2mClientSecret ?? "")}`);
|
|
1228
1220
|
console.log("");
|
|
1229
1221
|
} else if (parts.tenant && !parts.logtoAppId) {
|
|
1230
|
-
console.log(
|
|
1231
|
-
console.log(
|
|
1232
|
-
console.log(` HABEETAT_ENDPOINT=${
|
|
1233
|
-
console.log(` HABEETAT_TENANT_SLUG=${
|
|
1222
|
+
console.log(chalk3.bold(" Backend SDK (@habeetat/sdk-node)"));
|
|
1223
|
+
console.log(chalk3.dim(" " + "\u2500".repeat(54)));
|
|
1224
|
+
console.log(` HABEETAT_ENDPOINT=${chalk3.green(apiUrl)}`);
|
|
1225
|
+
console.log(` HABEETAT_TENANT_SLUG=${chalk3.green(parts.tenant)}`);
|
|
1234
1226
|
console.log("");
|
|
1235
1227
|
}
|
|
1236
1228
|
if (parts.email && parts.password) {
|
|
1237
|
-
console.log(
|
|
1238
|
-
console.log(
|
|
1239
|
-
console.log(` Email: ${
|
|
1240
|
-
console.log(` Password: ${
|
|
1241
|
-
console.log(` IAM: ${
|
|
1229
|
+
console.log(chalk3.bold(" Test credentials"));
|
|
1230
|
+
console.log(chalk3.dim(" " + "\u2500".repeat(54)));
|
|
1231
|
+
console.log(` Email: ${chalk3.green(parts.email)}`);
|
|
1232
|
+
console.log(` Password: ${chalk3.green(parts.password)}`);
|
|
1233
|
+
console.log(` IAM: ${chalk3.green(iamUrl)}`);
|
|
1242
1234
|
console.log("");
|
|
1243
1235
|
}
|
|
1244
|
-
console.log(
|
|
1236
|
+
console.log(chalk3.cyan("\u2550".repeat(60)));
|
|
1245
1237
|
console.log("");
|
|
1246
1238
|
}
|
|
1247
1239
|
function validateSlug(slug, entity) {
|
|
@@ -1264,11 +1256,11 @@ async function seedTenantCommand(options) {
|
|
|
1264
1256
|
options.slug,
|
|
1265
1257
|
...options.description ? ["--description", options.description] : []
|
|
1266
1258
|
];
|
|
1267
|
-
const spinner =
|
|
1259
|
+
const spinner = ora(`Creating tenant "${options.slug}"...`).start();
|
|
1268
1260
|
let result;
|
|
1269
1261
|
try {
|
|
1270
1262
|
result = await runSeedScript(projectDir, "create-tenant", args);
|
|
1271
|
-
spinner.succeed(`Tenant created: ${
|
|
1263
|
+
spinner.succeed(`Tenant created: ${chalk3.bold(result.slug)} (${result.displayName})`);
|
|
1272
1264
|
} catch (err) {
|
|
1273
1265
|
spinner.fail("Failed to create tenant");
|
|
1274
1266
|
logger.error(String(err));
|
|
@@ -1293,13 +1285,14 @@ async function seedAppCommand(options) {
|
|
|
1293
1285
|
...options.redirectUri?.flatMap((u) => ["--redirect-uri", u]) ?? [],
|
|
1294
1286
|
...options.logoutUri?.flatMap((u) => ["--logout-uri", u]) ?? [],
|
|
1295
1287
|
...options.corsOrigin?.flatMap((o) => ["--cors-origin", o]) ?? [],
|
|
1296
|
-
...options.internal ? ["--internal"] : []
|
|
1288
|
+
...options.internal ? ["--internal"] : [],
|
|
1289
|
+
...options.noM2m ? ["--no-m2m"] : []
|
|
1297
1290
|
];
|
|
1298
|
-
const spinner =
|
|
1291
|
+
const spinner = ora(`Creating app "${options.slug}"...`).start();
|
|
1299
1292
|
let result;
|
|
1300
1293
|
try {
|
|
1301
1294
|
result = await runSeedScript(projectDir, "create-app", args);
|
|
1302
|
-
spinner.succeed(`App created: ${
|
|
1295
|
+
spinner.succeed(`App created: ${chalk3.bold(result.slug)} (Logto app: ${result.logtoAppId})`);
|
|
1303
1296
|
} catch (err) {
|
|
1304
1297
|
spinner.fail("Failed to create app");
|
|
1305
1298
|
logger.error(String(err));
|
|
@@ -1333,11 +1326,11 @@ async function seedUpdateAppCommand(options) {
|
|
|
1333
1326
|
...options.logoutUri?.flatMap((u) => ["--logout-uri", u]) ?? [],
|
|
1334
1327
|
...options.corsOrigin?.flatMap((o) => ["--cors-origin", o]) ?? []
|
|
1335
1328
|
];
|
|
1336
|
-
const spinner =
|
|
1329
|
+
const spinner = ora(`Updating app "${options.slug}"...`).start();
|
|
1337
1330
|
let result;
|
|
1338
1331
|
try {
|
|
1339
1332
|
result = await runSeedScript(projectDir, "update-app", args);
|
|
1340
|
-
spinner.succeed(`App updated: ${
|
|
1333
|
+
spinner.succeed(`App updated: ${chalk3.bold(result.slug)}`);
|
|
1341
1334
|
} catch (err) {
|
|
1342
1335
|
spinner.fail("Failed to update app");
|
|
1343
1336
|
logger.error(String(err));
|
|
@@ -1368,11 +1361,11 @@ async function seedUserCommand(options) {
|
|
|
1368
1361
|
...options.displayName ? ["--display-name", options.displayName] : [],
|
|
1369
1362
|
...options.role ? ["--role", options.role] : []
|
|
1370
1363
|
];
|
|
1371
|
-
const spinner =
|
|
1364
|
+
const spinner = ora(`Creating user "${options.email}" in tenant "${options.tenant}"...`).start();
|
|
1372
1365
|
let result;
|
|
1373
1366
|
try {
|
|
1374
1367
|
result = await runSeedScript(projectDir, "create-user", args);
|
|
1375
|
-
spinner.succeed(`User created: ${
|
|
1368
|
+
spinner.succeed(`User created: ${chalk3.bold(result.email)} (Logto ID: ${result.logtoUserId})`);
|
|
1376
1369
|
} catch (err) {
|
|
1377
1370
|
spinner.fail("Failed to create user");
|
|
1378
1371
|
logger.error(String(err));
|
|
@@ -1394,9 +1387,9 @@ function registerSeedCommand(program2) {
|
|
|
1394
1387
|
seed.command("tenant").description("Create a new tenant (Logto org + platform DB)").requiredOption("--name <name>", 'Display name (e.g. "Acme Corp")').requiredOption("--slug <slug>", "Unique slug, lowercase alphanumeric + hyphens (e.g. acme)").option("--description <desc>", "Optional description").action((opts) => {
|
|
1395
1388
|
return seedTenantCommand(opts);
|
|
1396
1389
|
});
|
|
1397
|
-
seed.command("app").description("Create a new OIDC application (Logto SPA app + platform DB)").requiredOption("--name <name>", 'App display name (e.g. "My CRM")').requiredOption("--slug <slug>", "Unique slug, lowercase alphanumeric + hyphens (e.g. my-crm)").option("--redirect-uri <uri...>", "OIDC redirect URI(s) (e.g. http://localhost:3000/callback)").option("--logout-uri <uri...>", "Post-logout redirect URI(s)").option("--cors-origin <origin...>", "CORS allowed origin(s)").option("--description <desc>", "Optional description").option("--tenant <slug>", "Install app on this tenant after creation").option("--internal", "Mark app as internal/system app (default: false)").action(
|
|
1390
|
+
seed.command("app").description("Create a new OIDC application (Logto SPA app + platform DB)").requiredOption("--name <name>", 'App display name (e.g. "My CRM")').requiredOption("--slug <slug>", "Unique slug, lowercase alphanumeric + hyphens (e.g. my-crm)").option("--redirect-uri <uri...>", "OIDC redirect URI(s) (e.g. http://localhost:3000/callback)").option("--logout-uri <uri...>", "Post-logout redirect URI(s)").option("--cors-origin <origin...>", "CORS allowed origin(s)").option("--description <desc>", "Optional description").option("--tenant <slug>", "Install app on this tenant after creation").option("--internal", "Mark app as internal/system app (default: false)").option("--no-m2m", "Skip M2M Logto application creation (frontend-only apps)").action(
|
|
1398
1391
|
(opts) => {
|
|
1399
|
-
return seedAppCommand(opts);
|
|
1392
|
+
return seedAppCommand({ ...opts, noM2m: opts.m2m === false });
|
|
1400
1393
|
}
|
|
1401
1394
|
);
|
|
1402
1395
|
seed.command("update-app").description("Update an existing app's OIDC URIs and CORS origins").requiredOption("--slug <slug>", "App slug to update").option("--redirect-uri <uri...>", "Replace OIDC redirect URI(s)").option("--logout-uri <uri...>", "Replace post-logout redirect URI(s)").option("--cors-origin <origin...>", "Replace CORS allowed origin(s)").action(
|
|
@@ -1412,10 +1405,11 @@ function registerSeedCommand(program2) {
|
|
|
1412
1405
|
}
|
|
1413
1406
|
|
|
1414
1407
|
// src/bin.ts
|
|
1408
|
+
var __dirname2 = path.dirname(fileURLToPath(import.meta.url));
|
|
1415
1409
|
var pkg = JSON.parse(
|
|
1416
|
-
|
|
1410
|
+
readFileSync(path.resolve(__dirname2, "..", "package.json"), "utf-8")
|
|
1417
1411
|
);
|
|
1418
|
-
var program = new
|
|
1412
|
+
var program = new Command();
|
|
1419
1413
|
program.name("habeetat").description("Habeetat Platform CLI \u2014 manage your platform instances").version(pkg.version);
|
|
1420
1414
|
program.command("up").description("Start the platform").action(upCommand);
|
|
1421
1415
|
program.command("down").description("Stop the platform").action(downCommand);
|
|
@@ -1434,5 +1428,5 @@ program.command("init").description("Initialize platform (seed Logto apps, creat
|
|
|
1434
1428
|
});
|
|
1435
1429
|
registerSeedCommand(program);
|
|
1436
1430
|
program.parse();
|
|
1437
|
-
//# sourceMappingURL=bin.
|
|
1438
|
-
//# sourceMappingURL=bin.
|
|
1431
|
+
//# sourceMappingURL=bin.mjs.map
|
|
1432
|
+
//# sourceMappingURL=bin.mjs.map
|