@mostajs/orm-cli 0.5.1 → 0.5.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.
Files changed (2) hide show
  1. package/bin/mostajs.sh +168 -0
  2. package/package.json +1 -1
package/bin/mostajs.sh CHANGED
@@ -1798,6 +1798,8 @@ menu_replicator() {
1798
1798
  echo -e " ${CYAN}7${RESET}) List CDC rules"
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
+ 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"
1801
1803
  echo -e " ${CYAN}v${RESET}) View the raw tree file"
1802
1804
  echo -e " ${CYAN}c${RESET}) Clear (delete the tree file — DESTRUCTIVE)"
1803
1805
  echo
@@ -1815,6 +1817,8 @@ menu_replicator() {
1815
1817
  7) action_rep_list_rules ;;
1816
1818
  8) action_rep_sync ;;
1817
1819
  9) action_rep_remove_rule ;;
1820
+ m|M) action_rep_open_monitor ;;
1821
+ s|S) action_rep_scaffold_services ;;
1818
1822
  v|V) action_rep_view_tree ;;
1819
1823
  c|C) action_rep_clear ;;
1820
1824
  b|B) return ;;
@@ -1823,6 +1827,111 @@ menu_replicator() {
1823
1827
  menu_replicator
1824
1828
  }
1825
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
+
1826
1935
  action_rep_add_replica() {
1827
1936
  local project name role dialect uri lag
1828
1937
  project=$(ask "Project name" "default")
@@ -1963,6 +2072,65 @@ action_rep_remove_rule() {
1963
2072
  pause
1964
2073
  }
1965
2074
 
2075
+ action_rep_open_monitor() {
2076
+ header
2077
+ echo -e "${BOLD}${MAGENTA}▶ Open replica-monitor dashboard${RESET}"
2078
+ echo
2079
+ # Ensure the monitor package is installed
2080
+ if [[ ! -d "$PROJECT_ROOT/node_modules/@mostajs/replica-monitor" ]]; then
2081
+ warn "@mostajs/replica-monitor not installed in this project."
2082
+ if confirm "Install it now?"; then
2083
+ ensure_pkg "@mostajs/replica-monitor" || { pause; return; }
2084
+ else
2085
+ pause; return
2086
+ fi
2087
+ fi
2088
+ local tree_file
2089
+ tree_file=$(_replicator_tree_file)
2090
+ local port
2091
+ port=$(ask "Port" "14499")
2092
+ local token
2093
+ token=$(ask "Auth token (empty = no auth, local-only)" "")
2094
+ local url_suffix=""
2095
+ [[ -n "$token" ]] && url_suffix="?token=${token}"
2096
+
2097
+ local log_file="$PROJECT_ROOT/.mostajs/monitor.log"
2098
+ local pid_file="$PROJECT_ROOT/.mostajs/monitor.pid"
2099
+
2100
+ # If already running (pid file exists + process alive) : just open the URL.
2101
+ if [[ -f "$pid_file" ]] && kill -0 "$(cat "$pid_file" 2>/dev/null)" 2>/dev/null; then
2102
+ ok "Monitor already running at http://127.0.0.1:${port}"
2103
+ else
2104
+ # Spawn in background
2105
+ echo -e " ${DIM}spawning mostajs-monitor …${RESET}"
2106
+ MONITOR_TREE="$tree_file" MONITOR_PORT="$port" MONITOR_TOKEN="$token" \
2107
+ nohup node "$PROJECT_ROOT/node_modules/@mostajs/replica-monitor/dist/cli.js" \
2108
+ --tree "$tree_file" --port "$port" --runtime "$PROJECT_ROOT" \
2109
+ ${token:+--token "$token"} \
2110
+ > "$log_file" 2>&1 &
2111
+ local pid=$!
2112
+ echo "$pid" > "$pid_file"
2113
+ sleep 1
2114
+ if kill -0 "$pid" 2>/dev/null; then
2115
+ ok "Monitor started (pid=$pid) → http://127.0.0.1:${port}${url_suffix}"
2116
+ dim " logs : $log_file"
2117
+ dim " stop : kill \$(cat $pid_file) or menu r → m again then Ctrl+C"
2118
+ else
2119
+ err "Monitor failed to start — check $log_file"
2120
+ cat "$log_file" | tail -10
2121
+ pause; return
2122
+ fi
2123
+ fi
2124
+
2125
+ # Try to open in default browser
2126
+ if command -v xdg-open >/dev/null 2>&1; then
2127
+ xdg-open "http://127.0.0.1:${port}${url_suffix}" >/dev/null 2>&1 &
2128
+ elif command -v open >/dev/null 2>&1; then
2129
+ open "http://127.0.0.1:${port}${url_suffix}" >/dev/null 2>&1 &
2130
+ fi
2131
+ pause
2132
+ }
2133
+
1966
2134
  action_rep_view_tree() {
1967
2135
  local tree_file
1968
2136
  tree_file=$(_replicator_tree_file)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mostajs/orm-cli",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
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",