@mostajs/orm-cli 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/mostajs.sh +194 -4
- package/package.json +1 -1
package/bin/mostajs.sh
CHANGED
|
@@ -594,7 +594,8 @@ prompt_dialect() {
|
|
|
594
594
|
sqlite) suggest="./data.sqlite" ;;
|
|
595
595
|
postgres) suggest="postgres://user:pw@localhost:5432/app" ;;
|
|
596
596
|
mysql|mariadb) suggest="mysql://user:pw@localhost:3306/app" ;;
|
|
597
|
-
|
|
597
|
+
# MongoDB : include ?authSource=admin (common pitfall without it)
|
|
598
|
+
mongodb) suggest="mongodb://devuser:devpass26@localhost:27017/app?authSource=admin" ;;
|
|
598
599
|
mssql) suggest="mssql://user:pw@localhost:1433/app" ;;
|
|
599
600
|
oracle) suggest="oracle://user:pw@localhost:1521/ORCLPDB" ;;
|
|
600
601
|
db2) suggest="db2://user:pw@localhost:50000/app" ;;
|
|
@@ -772,6 +773,46 @@ function stripScheme(uri) {
|
|
|
772
773
|
return uri;
|
|
773
774
|
}
|
|
774
775
|
|
|
776
|
+
// Provide dialect-specific hints for common auth / connection errors.
|
|
777
|
+
function hintFor(dialect, rawUri, err) {
|
|
778
|
+
const msg = (err && err.message) ? err.message : '';
|
|
779
|
+
const code = err && (err.code ?? err.codeName);
|
|
780
|
+
|
|
781
|
+
// MongoDB code 18 : Authentication failed → missing ?authSource=admin
|
|
782
|
+
if (dialect === 'mongodb' && (code === 18 || /AuthenticationFailed|18/.test(msg))) {
|
|
783
|
+
if (!/authSource=/.test(rawUri)) {
|
|
784
|
+
return 'MongoDB users are usually declared in the admin DB. Add ?authSource=admin to the URI :\n'
|
|
785
|
+
+ ' ' + (rawUri.includes('?') ? rawUri + '&authSource=admin' : rawUri + '?authSource=admin');
|
|
786
|
+
}
|
|
787
|
+
return 'Verify credentials (username / password) in the URI.';
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
// PostgreSQL common errors
|
|
791
|
+
if (dialect === 'postgres' || dialect === 'cockroachdb') {
|
|
792
|
+
if (/password authentication failed/i.test(msg)) return 'Wrong PG password. Check the URI or run: psql "' + rawUri + '" -c "SELECT 1"';
|
|
793
|
+
if (/ECONNREFUSED|connect ECONNREFUSED/i.test(msg)) return 'PG server not running on that host/port. Try: pg_isready -h HOST -p PORT';
|
|
794
|
+
if (/no pg_hba.conf entry/i.test(msg)) return 'Server rejects the connection (pg_hba.conf). Add your IP or use SSL.';
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
// MySQL common errors
|
|
798
|
+
if (dialect === 'mysql' || dialect === 'mariadb') {
|
|
799
|
+
if (/Access denied for user/i.test(msg)) return 'Wrong MySQL password. Try: mysql -u USER -p -h HOST';
|
|
800
|
+
if (/ECONNREFUSED/i.test(msg)) return 'MySQL not running. Try: systemctl status mysql';
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// SQLite common errors
|
|
804
|
+
if (dialect === 'sqlite') {
|
|
805
|
+
if (/SQLITE_CANTOPEN/i.test(msg)) return 'Cannot open SQLite file. Check the path exists and is writable.';
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
// Generic network errors
|
|
809
|
+
if (/ECONNREFUSED/i.test(msg)) return 'Service is not reachable at that host/port.';
|
|
810
|
+
if (/ENOTFOUND|getaddrinfo/i.test(msg)) return 'DNS resolution failed. Check the hostname.';
|
|
811
|
+
if (/ETIMEDOUT/i.test(msg)) return 'Connection timed out. Check firewall / VPN / host.';
|
|
812
|
+
|
|
813
|
+
return null;
|
|
814
|
+
}
|
|
815
|
+
|
|
775
816
|
let ok = 0, fail = 0;
|
|
776
817
|
for (const [dialect, rawUri] of pairs) {
|
|
777
818
|
const uri = dialect === 'sqlite' ? stripScheme(rawUri) : rawUri;
|
|
@@ -790,6 +831,9 @@ for (const [dialect, rawUri] of pairs) {
|
|
|
790
831
|
} catch (e) {
|
|
791
832
|
console.error(' \u2717 ' + (e.message ?? e));
|
|
792
833
|
if (e.code) console.error(' code : ' + e.code);
|
|
834
|
+
if (e.codeName) console.error(' codeName : ' + e.codeName);
|
|
835
|
+
const hint = hintFor(dialect, rawUri, e);
|
|
836
|
+
if (hint) console.error(' \u2192 ' + hint);
|
|
793
837
|
fail++;
|
|
794
838
|
}
|
|
795
839
|
}
|
|
@@ -800,7 +844,66 @@ EOF
|
|
|
800
844
|
|
|
801
845
|
cd "$PROJECT_ROOT"
|
|
802
846
|
node "$CONFIG_DIR/test-connections.mjs" "${args[@]}" 2>&1 | tee "$LOG_DIR/test-connections.log"
|
|
847
|
+
local test_rc=${PIPESTATUS[0]}
|
|
803
848
|
echo
|
|
849
|
+
|
|
850
|
+
# Offer to auto-fix common MongoDB auth issue (missing ?authSource=admin)
|
|
851
|
+
if [[ $test_rc -ne 0 ]] && grep -qE "authSource=admin|AuthenticationFailed|code : 18" "$LOG_DIR/test-connections.log"; then
|
|
852
|
+
echo
|
|
853
|
+
warn "Detected MongoDB authentication failure that is usually fixed by adding"
|
|
854
|
+
warn " ?authSource=admin to the URI."
|
|
855
|
+
if confirm "Append '?authSource=admin' to your MongoDB URI now?"; then
|
|
856
|
+
# Fix the primary SGBD_URI if it's mongodb
|
|
857
|
+
if [[ "${DB_DIALECT:-}" == "mongodb" ]] && [[ -n "${SGBD_URI:-}" ]] && [[ ! "$SGBD_URI" =~ authSource= ]]; then
|
|
858
|
+
local new_uri
|
|
859
|
+
if [[ "$SGBD_URI" =~ \? ]]; then
|
|
860
|
+
new_uri="${SGBD_URI}&authSource=admin"
|
|
861
|
+
else
|
|
862
|
+
new_uri="${SGBD_URI}?authSource=admin"
|
|
863
|
+
fi
|
|
864
|
+
save_var SGBD_URI "$new_uri"
|
|
865
|
+
ok "Updated SGBD_URI : $new_uri"
|
|
866
|
+
fi
|
|
867
|
+
# Fix any MongoDB extra binding missing authSource
|
|
868
|
+
if [[ -n "${EXTRA_BINDINGS:-}" ]]; then
|
|
869
|
+
local new_bindings=""
|
|
870
|
+
local IFS=';'
|
|
871
|
+
for b in $EXTRA_BINDINGS; do
|
|
872
|
+
local name="${b%%:*}"
|
|
873
|
+
local rest="${b#*:}"
|
|
874
|
+
local dialect="${rest%%:*}"
|
|
875
|
+
local uri="${rest#*:}"
|
|
876
|
+
if [[ "$dialect" == "mongodb" ]] && [[ ! "$uri" =~ authSource= ]]; then
|
|
877
|
+
if [[ "$uri" =~ \? ]]; then
|
|
878
|
+
uri="${uri}&authSource=admin"
|
|
879
|
+
else
|
|
880
|
+
uri="${uri}?authSource=admin"
|
|
881
|
+
fi
|
|
882
|
+
fi
|
|
883
|
+
new_bindings+="${new_bindings:+;}${name}:${dialect}:${uri}"
|
|
884
|
+
done
|
|
885
|
+
IFS=$' \t\n'
|
|
886
|
+
save_var EXTRA_BINDINGS "$new_bindings"
|
|
887
|
+
ok "Updated EXTRA_BINDINGS"
|
|
888
|
+
fi
|
|
889
|
+
echo
|
|
890
|
+
info "Re-running the test with the fixed URI..."
|
|
891
|
+
# Rebuild args with fresh env
|
|
892
|
+
load_env
|
|
893
|
+
args=()
|
|
894
|
+
[[ -n "${DB_DIALECT:-}" && -n "${SGBD_URI:-}" ]] && args+=("${DB_DIALECT}|${SGBD_URI}")
|
|
895
|
+
if [[ -n "${EXTRA_BINDINGS:-}" ]]; then
|
|
896
|
+
local IFS=';'
|
|
897
|
+
for b in $EXTRA_BINDINGS; do
|
|
898
|
+
local rest="${b#*:}"
|
|
899
|
+
args+=("${rest%%:*}|${rest#*:}")
|
|
900
|
+
done
|
|
901
|
+
IFS=$' \t\n'
|
|
902
|
+
fi
|
|
903
|
+
node "$CONFIG_DIR/test-connections.mjs" "${args[@]}" 2>&1 | tee "$LOG_DIR/test-connections.log"
|
|
904
|
+
fi
|
|
905
|
+
fi
|
|
906
|
+
|
|
804
907
|
pause
|
|
805
908
|
}
|
|
806
909
|
|
|
@@ -908,6 +1011,21 @@ const schemaStrategy = process.env.DB_SCHEMA_STRATEGY ?? 'update';
|
|
|
908
1011
|
const poolSize = parseInt(process.env.DB_POOL_SIZE ?? '20', 10);
|
|
909
1012
|
const showSql = process.env.DB_SHOW_SQL === 'true';
|
|
910
1013
|
|
|
1014
|
+
function hintFor(dialect, rawUri, err) {
|
|
1015
|
+
const msg = (err && err.message) ? err.message : '';
|
|
1016
|
+
const code = err && (err.code ?? err.codeName);
|
|
1017
|
+
if (dialect === 'mongodb' && (code === 18 || /AuthenticationFailed|18/.test(msg))) {
|
|
1018
|
+
if (!/authSource=/.test(rawUri)) {
|
|
1019
|
+
return 'Missing ?authSource=admin on MongoDB URI. Try :\n '
|
|
1020
|
+
+ (rawUri.includes('?') ? rawUri + '&authSource=admin' : rawUri + '?authSource=admin');
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
if (/ECONNREFUSED/i.test(msg)) return 'Service not running at that host/port';
|
|
1024
|
+
if (/ENOTFOUND/i.test(msg)) return 'DNS resolution failed';
|
|
1025
|
+
if (/ETIMEDOUT/i.test(msg)) return 'Connection timed out';
|
|
1026
|
+
return null;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
911
1029
|
for (const [dialect, rawUri] of pairs) {
|
|
912
1030
|
const uri = dialect === 'sqlite' ? stripScheme(rawUri) : rawUri;
|
|
913
1031
|
process.stdout.write('→ ' + dialect.padEnd(12) + ' : ' + rawUri + '\n');
|
|
@@ -920,6 +1038,8 @@ for (const [dialect, rawUri] of pairs) {
|
|
|
920
1038
|
} catch (e) {
|
|
921
1039
|
console.error(' ✗ ' + dialect + ' failed : ' + (e.message ?? e));
|
|
922
1040
|
if (e.code) console.error(' code : ' + e.code);
|
|
1041
|
+
const hint = hintFor(dialect, rawUri, e);
|
|
1042
|
+
if (hint) console.error(' → ' + hint);
|
|
923
1043
|
fail++;
|
|
924
1044
|
}
|
|
925
1045
|
}
|
|
@@ -1144,9 +1264,79 @@ svc_start_dev() {
|
|
|
1144
1264
|
}
|
|
1145
1265
|
|
|
1146
1266
|
svc_start_mostanet() {
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1267
|
+
load_env
|
|
1268
|
+
cd "$PROJECT_ROOT" || return
|
|
1269
|
+
|
|
1270
|
+
if [[ ! -f "$GENERATED_DIR/entities.json" ]]; then
|
|
1271
|
+
err "No entities.json — run menu 1 (Convert) first"
|
|
1272
|
+
return
|
|
1273
|
+
fi
|
|
1274
|
+
|
|
1275
|
+
# Ensure @mostajs/net AND its peer deps are installed
|
|
1276
|
+
info "Checking @mostajs/net + peer dependencies..."
|
|
1277
|
+
if ! ensure_pkg "@mostajs/net" "@mostajs/orm" "@mostajs/mproject" "@mostajs/replicator"; then
|
|
1278
|
+
err "Cannot start mosta-net server without these packages."
|
|
1279
|
+
return
|
|
1280
|
+
fi
|
|
1281
|
+
|
|
1282
|
+
# Make our entities available to mostajs-net via schemas.json
|
|
1283
|
+
# (mostajs-net's server.js looks for ./schemas.json in CWD)
|
|
1284
|
+
if [[ ! -L schemas.json && ! -f schemas.json ]]; then
|
|
1285
|
+
ln -sf "$GENERATED_DIR/entities.json" "$PROJECT_ROOT/schemas.json" 2>/dev/null \
|
|
1286
|
+
|| cp "$GENERATED_DIR/entities.json" "$PROJECT_ROOT/schemas.json"
|
|
1287
|
+
ok "Linked schemas.json → $GENERATED_DIR/entities.json"
|
|
1288
|
+
fi
|
|
1289
|
+
|
|
1290
|
+
# Derive port from MOSTA_NET_URL
|
|
1291
|
+
local mosta_port=14488
|
|
1292
|
+
if [[ "${MOSTA_NET_URL:-}" =~ :([0-9]+) ]]; then
|
|
1293
|
+
mosta_port="${BASH_REMATCH[1]}"
|
|
1294
|
+
fi
|
|
1295
|
+
|
|
1296
|
+
# Prepare env for the child process
|
|
1297
|
+
# - DB vars : DB_DIALECT, SGBD_URI, DB_SCHEMA_STRATEGY, ...
|
|
1298
|
+
# - MOSTA_NET_PORT : derived from MOSTA_NET_URL
|
|
1299
|
+
# - MOSTA_NET_<transport>_ENABLED=true
|
|
1300
|
+
local transport="${MOSTA_NET_TRANSPORT:-rest}"
|
|
1301
|
+
local tr_upper="$(echo "$transport" | tr '[:lower:]' '[:upper:]')"
|
|
1302
|
+
|
|
1303
|
+
info "Launching mostajs-net serve (port $mosta_port, transport $transport)"
|
|
1304
|
+
info "Logs → $LOG_DIR/mostanet.log"
|
|
1305
|
+
|
|
1306
|
+
local launcher
|
|
1307
|
+
if [[ -x "$PROJECT_ROOT/node_modules/.bin/mostajs-net" ]]; then
|
|
1308
|
+
launcher="$PROJECT_ROOT/node_modules/.bin/mostajs-net"
|
|
1309
|
+
else
|
|
1310
|
+
launcher="npx mostajs-net"
|
|
1311
|
+
fi
|
|
1312
|
+
|
|
1313
|
+
# Launch detached with all env vars
|
|
1314
|
+
(
|
|
1315
|
+
export DB_DIALECT="${DB_DIALECT:-sqlite}"
|
|
1316
|
+
export SGBD_URI="${SGBD_URI:-./data.sqlite}"
|
|
1317
|
+
export DB_SCHEMA_STRATEGY="${DB_SCHEMA_STRATEGY:-update}"
|
|
1318
|
+
export DB_POOL_SIZE="${DB_POOL_SIZE:-20}"
|
|
1319
|
+
export DB_SHOW_SQL="${DB_SHOW_SQL:-false}"
|
|
1320
|
+
export MOSTA_NET_PORT="$mosta_port"
|
|
1321
|
+
export "MOSTA_NET_${tr_upper}_ENABLED"="true"
|
|
1322
|
+
# Also enable MCP alongside — commonly wanted for AI integrations
|
|
1323
|
+
[[ "$tr_upper" != "MCP" && "${MOSTA_NET_ALSO_MCP:-true}" == "true" ]] && export MOSTA_NET_MCP_ENABLED=true
|
|
1324
|
+
nohup $launcher serve >> "$LOG_DIR/mostanet.log" 2>&1 &
|
|
1325
|
+
echo "$!" > "$LOG_DIR/mostanet.pid"
|
|
1326
|
+
)
|
|
1327
|
+
local pid
|
|
1328
|
+
pid=$(cat "$LOG_DIR/mostanet.pid" 2>/dev/null || echo "?")
|
|
1329
|
+
ok "Started (PID $pid)"
|
|
1330
|
+
echo
|
|
1331
|
+
info "Endpoints (wait 2-3 seconds then hit them) :"
|
|
1332
|
+
dim " REST CRUD : http://localhost:${mosta_port}/api/v1/<collection>"
|
|
1333
|
+
dim " (collection = snake_case plural, e.g. /api/v1/users)"
|
|
1334
|
+
dim " MCP (AI) : http://localhost:${mosta_port}/mcp"
|
|
1335
|
+
dim " Tail log : tail -f $LOG_DIR/mostanet.log"
|
|
1336
|
+
echo
|
|
1337
|
+
info "Try it :"
|
|
1338
|
+
dim " curl http://localhost:${mosta_port}/api/v1/users"
|
|
1339
|
+
dim " curl http://localhost:${mosta_port}/api/v1/members"
|
|
1150
1340
|
}
|
|
1151
1341
|
|
|
1152
1342
|
svc_stop_all() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mostajs/orm-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Universal CLI to integrate @mostajs/orm into any project — auto-detects Prisma, OpenAPI, JSON Schema. Interactive menu + subcommands. 13 databases.",
|
|
5
5
|
"author": "Dr Hamid MADANI <drmdh@msn.com>",
|
|
6
6
|
"license": "AGPL-3.0-or-later",
|