@mostajs/orm-cli 0.5.2 → 0.5.4
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 +140 -4
- package/package.json +1 -1
package/bin/mostajs.sh
CHANGED
|
@@ -1799,6 +1799,7 @@ menu_replicator() {
|
|
|
1799
1799
|
echo -e " ${CYAN}8${RESET}) Run a CDC sync + show stats"
|
|
1800
1800
|
echo -e " ${CYAN}9${RESET}) Remove a CDC rule"
|
|
1801
1801
|
echo -e " ${CYAN}m${RESET}) ${BOLD}Open monitor${RESET} (live dashboard — localhost:14499)"
|
|
1802
|
+
echo -e " ${CYAN}s${RESET}) ${BOLD}Scaffold services${RESET} — services/replicator.mjs + services/monitor.mjs + package.json scripts"
|
|
1802
1803
|
echo -e " ${CYAN}v${RESET}) View the raw tree file"
|
|
1803
1804
|
echo -e " ${CYAN}c${RESET}) Clear (delete the tree file — DESTRUCTIVE)"
|
|
1804
1805
|
echo
|
|
@@ -1817,6 +1818,7 @@ menu_replicator() {
|
|
|
1817
1818
|
8) action_rep_sync ;;
|
|
1818
1819
|
9) action_rep_remove_rule ;;
|
|
1819
1820
|
m|M) action_rep_open_monitor ;;
|
|
1821
|
+
s|S) action_rep_scaffold_services ;;
|
|
1820
1822
|
v|V) action_rep_view_tree ;;
|
|
1821
1823
|
c|C) action_rep_clear ;;
|
|
1822
1824
|
b|B) return ;;
|
|
@@ -1825,19 +1827,153 @@ menu_replicator() {
|
|
|
1825
1827
|
menu_replicator
|
|
1826
1828
|
}
|
|
1827
1829
|
|
|
1830
|
+
# ------------------------------------------------------------
|
|
1831
|
+
# Scaffold background services (replicator + monitor) + package.json patch
|
|
1832
|
+
# ------------------------------------------------------------
|
|
1833
|
+
action_rep_scaffold_services() {
|
|
1834
|
+
header
|
|
1835
|
+
echo -e "${BOLD}${MAGENTA}▶ Scaffold background services${RESET}"
|
|
1836
|
+
echo
|
|
1837
|
+
echo -e " This will :"
|
|
1838
|
+
echo -e " 1. ${CYAN}services/replicator.mjs${RESET} (from @mostajs/replicator)"
|
|
1839
|
+
echo -e " 2. ${CYAN}services/monitor.mjs${RESET} (from @mostajs/replica-monitor)"
|
|
1840
|
+
echo -e " 3. patch ${CYAN}package.json${RESET} : scripts.replicator / monitor / dev:all"
|
|
1841
|
+
echo -e " 4. install ${CYAN}concurrently${RESET} if missing"
|
|
1842
|
+
echo
|
|
1843
|
+
if ! confirm "Proceed?"; then return; fi
|
|
1844
|
+
|
|
1845
|
+
# Ensure the scaffolders' packages are installed locally
|
|
1846
|
+
ensure_pkg "@mostajs/replicator" "@mostajs/replica-monitor" || { pause; return; }
|
|
1847
|
+
|
|
1848
|
+
local force_arg=""
|
|
1849
|
+
if confirm "Overwrite existing services/*.mjs if present?"; then force_arg="--force"; fi
|
|
1850
|
+
|
|
1851
|
+
# Call each scaffolder (uses the lib's own emit logic — single source of truth)
|
|
1852
|
+
echo
|
|
1853
|
+
echo -e "${CYAN}▶ scaffoldReplicatorService${RESET}"
|
|
1854
|
+
node --input-type=module -e "
|
|
1855
|
+
const { scaffoldReplicatorService } = await import('${PROJECT_ROOT}/node_modules/@mostajs/replicator/dist/scaffold.js');
|
|
1856
|
+
const r = scaffoldReplicatorService({ projectDir: '${PROJECT_ROOT}', force: ${force_arg:+true}${force_arg:-false} });
|
|
1857
|
+
console.log(' ' + (r.wrote ? '✓' : '•') + ' ' + r.action + ' : ' + r.path);
|
|
1858
|
+
" 2>&1 | sed 's/^/ /'
|
|
1859
|
+
|
|
1860
|
+
echo
|
|
1861
|
+
echo -e "${CYAN}▶ scaffoldMonitorService${RESET}"
|
|
1862
|
+
node --input-type=module -e "
|
|
1863
|
+
const { scaffoldMonitorService } = await import('${PROJECT_ROOT}/node_modules/@mostajs/replica-monitor/dist/scaffold.js');
|
|
1864
|
+
const r = scaffoldMonitorService({ projectDir: '${PROJECT_ROOT}', force: ${force_arg:+true}${force_arg:-false} });
|
|
1865
|
+
console.log(' ' + (r.wrote ? '✓' : '•') + ' ' + r.action + ' : ' + r.path);
|
|
1866
|
+
" 2>&1 | sed 's/^/ /'
|
|
1867
|
+
|
|
1868
|
+
# Patch package.json scripts
|
|
1869
|
+
echo
|
|
1870
|
+
echo -e "${CYAN}▶ patching package.json scripts${RESET}"
|
|
1871
|
+
if [[ ! -f "$PROJECT_ROOT/package.json" ]]; then
|
|
1872
|
+
warn " no package.json found — skipping scripts patch"
|
|
1873
|
+
else
|
|
1874
|
+
PROJECT="$PROJECT_ROOT" node --input-type=module -e "
|
|
1875
|
+
const fs = await import('node:fs');
|
|
1876
|
+
const path = process.env.PROJECT + '/package.json';
|
|
1877
|
+
const pkg = JSON.parse(fs.readFileSync(path, 'utf8'));
|
|
1878
|
+
pkg.scripts = pkg.scripts || {};
|
|
1879
|
+
const add = (key, val) => {
|
|
1880
|
+
if (pkg.scripts[key]) {
|
|
1881
|
+
console.log(' • ' + key + ' already set (kept as-is)');
|
|
1882
|
+
} else {
|
|
1883
|
+
pkg.scripts[key] = val;
|
|
1884
|
+
console.log(' ✓ added ' + key);
|
|
1885
|
+
}
|
|
1886
|
+
};
|
|
1887
|
+
add('replicator', 'node services/replicator.mjs');
|
|
1888
|
+
add('monitor', 'node services/monitor.mjs');
|
|
1889
|
+
add('dev:all', 'concurrently --kill-others-on-fail --names next,rep,mon -c blue,magenta,cyan \"npm:dev\" \"npm:replicator\" \"npm:monitor\"');
|
|
1890
|
+
fs.writeFileSync(path, JSON.stringify(pkg, null, 2) + '\n');
|
|
1891
|
+
" 2>&1 | sed 's/^/ /'
|
|
1892
|
+
fi
|
|
1893
|
+
|
|
1894
|
+
# Ensure concurrently is installed (devDependency)
|
|
1895
|
+
echo
|
|
1896
|
+
echo -e "${CYAN}▶ checking concurrently${RESET}"
|
|
1897
|
+
if [[ -d "$PROJECT_ROOT/node_modules/concurrently" ]]; then
|
|
1898
|
+
ok " concurrently already installed"
|
|
1899
|
+
else
|
|
1900
|
+
if confirm "Install concurrently as a devDependency?"; then
|
|
1901
|
+
cd "$PROJECT_ROOT" || return 1
|
|
1902
|
+
local log_file="/tmp/mostajs-concurrently-$$.log"
|
|
1903
|
+
case "$PKG_MANAGER" in
|
|
1904
|
+
pnpm) pnpm add -D concurrently > "$log_file" 2>&1 & ;;
|
|
1905
|
+
yarn) yarn add -D concurrently > "$log_file" 2>&1 & ;;
|
|
1906
|
+
bun) bun add -d concurrently > "$log_file" 2>&1 & ;;
|
|
1907
|
+
*) npm install --save-dev concurrently --legacy-peer-deps > "$log_file" 2>&1 & ;;
|
|
1908
|
+
esac
|
|
1909
|
+
local pid=$! frames='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏' tick=0
|
|
1910
|
+
while kill -0 "$pid" 2>/dev/null; do
|
|
1911
|
+
local f="${frames:$((tick % 10)):1}"
|
|
1912
|
+
printf "\r ${YELLOW}%s${RESET} installing concurrently ${DIM}(%ds)${RESET} " "$f" "$((tick / 5))"
|
|
1913
|
+
tick=$((tick + 1)); sleep 0.2
|
|
1914
|
+
done
|
|
1915
|
+
wait "$pid"; local rc=$?
|
|
1916
|
+
printf "\r%60s\r" ""
|
|
1917
|
+
if [[ $rc -eq 0 ]]; then ok " concurrently installed"
|
|
1918
|
+
else err " install failed (see $log_file)"; tail -3 "$log_file"
|
|
1919
|
+
fi
|
|
1920
|
+
rm -f "$log_file"
|
|
1921
|
+
fi
|
|
1922
|
+
fi
|
|
1923
|
+
|
|
1924
|
+
echo
|
|
1925
|
+
echo -e "${BOLD}${GREEN}✓ Scaffold complete.${RESET}"
|
|
1926
|
+
echo
|
|
1927
|
+
echo -e " ${BOLD}Next steps :${RESET}"
|
|
1928
|
+
echo -e " 1. ${CYAN}mostajs${RESET} → menu r → add replicas + CDC rules (writes replicator-tree.json)"
|
|
1929
|
+
echo -e " 2. ${CYAN}npm run dev:all${RESET} — starts Next + replicator + monitor in parallel"
|
|
1930
|
+
echo -e " or individually : ${CYAN}npm run replicator${RESET} / ${CYAN}npm run monitor${RESET}"
|
|
1931
|
+
echo -e " 3. Open ${CYAN}http://localhost:14499${RESET} for the live dashboard"
|
|
1932
|
+
pause
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1828
1935
|
action_rep_add_replica() {
|
|
1936
|
+
echo
|
|
1937
|
+
dim " A project is a logical group of replicas (e.g. 'fitzone', 'secuaccess')."
|
|
1938
|
+
dim " Use a SHORT IDENTIFIER here (NOT a database URI — the URI comes later)."
|
|
1939
|
+
echo
|
|
1829
1940
|
local project name role dialect uri lag
|
|
1830
|
-
project=$(ask "Project name" "
|
|
1831
|
-
|
|
1941
|
+
project=$(ask "Project name (short id, e.g. 'fitzone')" "fitzone")
|
|
1942
|
+
# Basic validation : reject URIs or paths
|
|
1943
|
+
if [[ "$project" == *"://"* || "$project" == *"/"* ]]; then
|
|
1944
|
+
err " Project name looks like a URI or path. Use a short identifier (e.g. 'fitzone')."
|
|
1945
|
+
pause; return
|
|
1946
|
+
fi
|
|
1947
|
+
|
|
1948
|
+
echo
|
|
1949
|
+
dim " Replica name is a label inside the project (e.g. 'master-oracle', 'slave-pg')."
|
|
1950
|
+
name=$(ask "Replica name (label, e.g. 'master-oracle')" "master")
|
|
1951
|
+
if [[ "$name" == *"://"* ]]; then
|
|
1952
|
+
err " Replica name looks like a URI. Use a short label."
|
|
1953
|
+
pause; return
|
|
1954
|
+
fi
|
|
1955
|
+
|
|
1832
1956
|
role=$(ask "Role (master|slave)" "master")
|
|
1833
|
-
dialect=$(ask "Dialect" "${DB_DIALECT:-postgres}")
|
|
1834
|
-
uri=$(ask "URI" "${SGBD_URI:-postgres://user:pass@localhost:5432/db}")
|
|
1957
|
+
dialect=$(ask "Dialect (sqlite|postgres|mysql|mongodb|oracle|mssql|mariadb|cockroachdb|db2|hana|hsqldb|spanner|sybase)" "${DB_DIALECT:-postgres}")
|
|
1958
|
+
uri=$(ask "Connection URI" "${SGBD_URI:-postgres://user:pass@localhost:5432/db}")
|
|
1835
1959
|
if [[ "$role" == "slave" ]]; then
|
|
1836
1960
|
lag=$(ask "Lag tolerance (ms)" "5000")
|
|
1837
1961
|
else
|
|
1838
1962
|
lag="0"
|
|
1839
1963
|
fi
|
|
1840
1964
|
_replicator_run "
|
|
1965
|
+
// Auto-register the project in ProjectManager if it's not already there —
|
|
1966
|
+
// addReplica() requires the project to exist. We use the replica's own
|
|
1967
|
+
// dialect/uri as the project config (it's typically the master).
|
|
1968
|
+
const existing = typeof pm.listProjects === 'function' ? pm.listProjects() : [];
|
|
1969
|
+
const known = Array.isArray(existing) && existing.some(p => (p.name ?? p) === '$project');
|
|
1970
|
+
if (!known) {
|
|
1971
|
+
const method = ['addProject','createProject','registerProject'].find(m => typeof pm[m] === 'function');
|
|
1972
|
+
if (method) {
|
|
1973
|
+
await pm[method]({ name: '$project', dialect: '$dialect', uri: '$uri', schemas: [] });
|
|
1974
|
+
console.log(' ✓ project \\'$project\\' registered in ProjectManager');
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1841
1977
|
await rm.addReplica('$project', {
|
|
1842
1978
|
name: '$name', role: '$role', dialect: '$dialect', uri: '$uri',
|
|
1843
1979
|
lagTolerance: $lag,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mostajs/orm-cli",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
4
4
|
"description": "Universal CLI to integrate @mostajs/orm into any project — one-shot `mostajs bootstrap` migrates a Prisma project (codemod + deps + schema convert + DDL) to 13 databases with zero code change.",
|
|
5
5
|
"author": "Dr Hamid MADANI <drmdh@msn.com>",
|
|
6
6
|
"license": "AGPL-3.0-or-later",
|