@occam-scaly/scaly-cli 0.2.11 → 0.2.12

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/scaly.js +82 -33
  2. package/package.json +1 -1
package/bin/scaly.js CHANGED
@@ -83,10 +83,10 @@ Usage:
83
83
  scaly secrets sync --app <appId> [--config-app <name>] [--env dev|prod] [--dry-run] [--apply] [--json]
84
84
 
85
85
  scaly login --token <api-bearer> [--endpoint https://api.<stage>.scalyapps.io/graphql] | --clear
86
- scaly db connect --addon <addOnId> [--ttl-minutes 60] [--local-port 5432] [--host 127.0.0.1] [--copy] [--show] [--json]
87
- scaly db shell --addon <addOnId> [--ttl-minutes 60] [--local-port 5432] [--host 127.0.0.1]
88
- scaly db schema dump --addon <addOnId> [--out .scaly/schema.sql] [--ttl-minutes 60]
89
- scaly db migrate <sql-file> --addon <addOnId> [--ttl-minutes 60] [--yes]
86
+ scaly db connect --addon <addOnId> [--ttl-minutes 60] [--local-port 55432] [--host 127.0.0.1] [--copy] [--show] [--json]
87
+ scaly db shell --addon <addOnId> [--ttl-minutes 60] [--local-port 55432] [--host 127.0.0.1]
88
+ scaly db schema dump --addon <addOnId> [--out .scaly/schema.sql] [--ttl-minutes 60] [--local-port 55432] [--host 127.0.0.1]
89
+ scaly db migrate <sql-file> --addon <addOnId> [--ttl-minutes 60] [--local-port 55432] [--host 127.0.0.1] [--yes]
90
90
  scaly deploy --app <appId> [--watch] [--strategy auto|git|restart|upload] [--json]
91
91
  - upload flags: [--path <dir>] [--preview] [--yes] [--allow-unsafe] [--max-bytes N] [--max-files N]
92
92
  scaly logs --follow --app <appId> [--since 10m] [--level error|warn|info|debug|all] [--q <str>] [--duration-seconds N] [--max-lines N] [--json]
@@ -104,6 +104,7 @@ Notes:
104
104
  - Wraps existing npm QA helpers and auto-loads .env.dev.scaly-deployer.local
105
105
  - If no AWS creds in env, runs under 'aws-vault exec scaly-dev'
106
106
  - DB tunnel requires a short-lived Scaly session token. Run: scaly auth login
107
+ - Default local port is 55432 to avoid conflicts with local Postgres (often 5432).
107
108
  `);
108
109
  }
109
110
 
@@ -2892,6 +2893,19 @@ async function startDbTunnelServer({ bearer, tunnelUrl, host, localPort }) {
2892
2893
  const { WebSocket, createWebSocketStream } = require('ws');
2893
2894
  const { pipeline } = require('stream');
2894
2895
 
2896
+ const listenErrorHint = (err) => {
2897
+ const code = err && err.code ? String(err.code) : '';
2898
+ if (code !== 'EADDRINUSE') return null;
2899
+ const port = localPort;
2900
+ const alt = port === 5432 ? 55432 : port + 1;
2901
+ return [
2902
+ `[db connect] Port ${host}:${port} is already in use.`,
2903
+ ` Try a different local port: scaly db connect --addon <id> --local-port ${alt}`,
2904
+ ` Or find the process using the port: lsof -nP -iTCP:${port} -sTCP:LISTEN`,
2905
+ ` Note: If your app runs in Docker, use DB_HOST=host.docker.internal (macOS/Windows).`
2906
+ ].join('\n');
2907
+ };
2908
+
2895
2909
  const server = net.createServer((socket) => {
2896
2910
  socket.setNoDelay(true);
2897
2911
 
@@ -2925,7 +2939,15 @@ async function startDbTunnelServer({ bearer, tunnelUrl, host, localPort }) {
2925
2939
  });
2926
2940
 
2927
2941
  await new Promise((resolve, reject) => {
2928
- server.once('error', reject);
2942
+ server.once('error', (err) => {
2943
+ const hint = listenErrorHint(err);
2944
+ if (hint) {
2945
+ const e = new Error(hint);
2946
+ e.code = 'SCALY_DB_LOCAL_PORT_IN_USE';
2947
+ return reject(e);
2948
+ }
2949
+ return reject(err);
2950
+ });
2929
2951
  server.listen(localPort, host, resolve);
2930
2952
  });
2931
2953
 
@@ -2951,14 +2973,23 @@ async function runDbConnect(rest) {
2951
2973
  const { addOnId, bearer, info, tunnelUrl } = minted;
2952
2974
 
2953
2975
  const host = f.host || '127.0.0.1';
2954
- const localPort = Number(f['local-port'] || info.port || 5432);
2976
+ const localPort = Number(f['local-port'] || 55432);
2955
2977
 
2956
- const server = await startDbTunnelServer({
2957
- bearer,
2958
- tunnelUrl,
2959
- host,
2960
- localPort
2961
- });
2978
+ let server;
2979
+ try {
2980
+ server = await startDbTunnelServer({
2981
+ bearer,
2982
+ tunnelUrl,
2983
+ host,
2984
+ localPort
2985
+ });
2986
+ } catch (e) {
2987
+ const msg = String(e && e.message ? e.message : e);
2988
+ if (json)
2989
+ console.log(JSON.stringify({ ok: false, error: { message: msg } }));
2990
+ else console.error(msg);
2991
+ return 2;
2992
+ }
2962
2993
 
2963
2994
  const psqlCmd = `PGSSLMODE=require PGPASSWORD='${info.token}' psql -h ${host} -p ${localPort} -U ${info.username} -d ${info.database}`;
2964
2995
  let copied = false;
@@ -3030,13 +3061,19 @@ async function runDbShell(rest) {
3030
3061
  }
3031
3062
  const { addOnId, bearer, info, tunnelUrl } = minted;
3032
3063
  const host = f.host || '127.0.0.1';
3033
- const localPort = Number(f['local-port'] || info.port || 5432);
3034
- const server = await startDbTunnelServer({
3035
- bearer,
3036
- tunnelUrl,
3037
- host,
3038
- localPort
3039
- });
3064
+ const localPort = Number(f['local-port'] || 55432);
3065
+ let server;
3066
+ try {
3067
+ server = await startDbTunnelServer({
3068
+ bearer,
3069
+ tunnelUrl,
3070
+ host,
3071
+ localPort
3072
+ });
3073
+ } catch (e) {
3074
+ console.error(String(e && e.message ? e.message : e));
3075
+ return 2;
3076
+ }
3040
3077
 
3041
3078
  const env = {
3042
3079
  ...process.env,
@@ -3086,13 +3123,19 @@ async function runDbSchemaDump(rest) {
3086
3123
  }
3087
3124
  const { addOnId, bearer, info, tunnelUrl } = minted;
3088
3125
  const host = f.host || '127.0.0.1';
3089
- const localPort = Number(f['local-port'] || info.port || 5432);
3090
- const server = await startDbTunnelServer({
3091
- bearer,
3092
- tunnelUrl,
3093
- host,
3094
- localPort
3095
- });
3126
+ const localPort = Number(f['local-port'] || 55432);
3127
+ let server;
3128
+ try {
3129
+ server = await startDbTunnelServer({
3130
+ bearer,
3131
+ tunnelUrl,
3132
+ host,
3133
+ localPort
3134
+ });
3135
+ } catch (e) {
3136
+ console.error(String(e && e.message ? e.message : e));
3137
+ return 2;
3138
+ }
3096
3139
 
3097
3140
  const env = {
3098
3141
  ...process.env,
@@ -3171,13 +3214,19 @@ async function runDbMigrate(rest) {
3171
3214
  }
3172
3215
  const { addOnId, bearer, info, tunnelUrl } = minted;
3173
3216
  const host = f.host || '127.0.0.1';
3174
- const localPort = Number(f['local-port'] || info.port || 5432);
3175
- const server = await startDbTunnelServer({
3176
- bearer,
3177
- tunnelUrl,
3178
- host,
3179
- localPort
3180
- });
3217
+ const localPort = Number(f['local-port'] || 55432);
3218
+ let server;
3219
+ try {
3220
+ server = await startDbTunnelServer({
3221
+ bearer,
3222
+ tunnelUrl,
3223
+ host,
3224
+ localPort
3225
+ });
3226
+ } catch (e) {
3227
+ console.error(String(e && e.message ? e.message : e));
3228
+ return 2;
3229
+ }
3181
3230
 
3182
3231
  const env = {
3183
3232
  ...process.env,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@occam-scaly/scaly-cli",
3
- "version": "0.2.11",
3
+ "version": "0.2.12",
4
4
  "description": "Scaly CLI (auth + project config helpers)",
5
5
  "bin": {
6
6
  "scaly": "./bin/scaly.js"