@hasna/cloud 0.1.24 → 0.1.25
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/cli/index.js +92 -6
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -12810,8 +12810,21 @@ function logSync(direction, service, rows, errors2) {
|
|
|
12810
12810
|
} catch {}
|
|
12811
12811
|
}
|
|
12812
12812
|
program2.name("cloud").description("Shared cloud infrastructure \u2014 database adapter, sync engine, feedback, dotfile migration").version("0.1.8");
|
|
12813
|
-
program2.command("setup").description("Configure cloud settings").option("--host <host>", "RDS hostname").option("--port <port>", "RDS port", "5432").option("--username <user>", "RDS username").option("--password-env <env>", "Env var for RDS password", "HASNA_RDS_PASSWORD").option("--ssl", "Enable SSL", true).option("--no-ssl", "Disable SSL").option("--mode <mode>", "Mode: local, cloud, or hybrid", "
|
|
12813
|
+
program2.command("setup").description("Configure cloud settings \u2014 interactive wizard or flags").option("--host <host>", "RDS hostname").option("--port <port>", "RDS port", "5432").option("--username <user>", "RDS username").option("--password-env <env>", "Env var for RDS password", "HASNA_RDS_PASSWORD").option("--ssl", "Enable SSL", true).option("--no-ssl", "Disable SSL").option("--mode <mode>", "Mode: local, cloud, or hybrid").option("--schedule <interval>", "Sync schedule (e.g. 30m, 1h)").option("--migrate", "Run PG migrations after setup").option("--pull", "Pull data from cloud after setup").action(async (opts) => {
|
|
12814
12814
|
const config = getCloudConfig();
|
|
12815
|
+
const isAutoDetect = !opts.host && !opts.username;
|
|
12816
|
+
if (isAutoDetect) {
|
|
12817
|
+
const envHost = process.env.HASNA_RDS_HOST;
|
|
12818
|
+
const envUser = process.env.HASNA_RDS_USERNAME;
|
|
12819
|
+
if (envHost && !config.rds.host) {
|
|
12820
|
+
config.rds.host = envHost;
|
|
12821
|
+
console.log(`Auto-detected RDS host: ${envHost}`);
|
|
12822
|
+
}
|
|
12823
|
+
if (envUser && !config.rds.username) {
|
|
12824
|
+
config.rds.username = envUser;
|
|
12825
|
+
console.log(`Auto-detected RDS username: ${envUser}`);
|
|
12826
|
+
}
|
|
12827
|
+
}
|
|
12815
12828
|
if (opts.host)
|
|
12816
12829
|
config.rds.host = opts.host;
|
|
12817
12830
|
if (opts.port)
|
|
@@ -12821,13 +12834,86 @@ program2.command("setup").description("Configure cloud settings").option("--host
|
|
|
12821
12834
|
if (opts.passwordEnv)
|
|
12822
12835
|
config.rds.password_env = opts.passwordEnv;
|
|
12823
12836
|
config.rds.ssl = opts.ssl;
|
|
12824
|
-
if (opts.mode)
|
|
12837
|
+
if (opts.mode) {
|
|
12825
12838
|
config.mode = opts.mode;
|
|
12826
|
-
if (
|
|
12827
|
-
config.
|
|
12839
|
+
} else if (config.mode === "local" && config.rds.host) {
|
|
12840
|
+
config.mode = "hybrid";
|
|
12841
|
+
console.log("Mode set to: hybrid (auto-upgraded from local)");
|
|
12842
|
+
}
|
|
12828
12843
|
saveCloudConfig(config);
|
|
12829
|
-
console.log(
|
|
12830
|
-
|
|
12844
|
+
console.log(`
|
|
12845
|
+
\u2713 Configuration saved
|
|
12846
|
+
`);
|
|
12847
|
+
const password = process.env[config.rds.password_env];
|
|
12848
|
+
if (!password) {
|
|
12849
|
+
console.error(`\u2717 ${config.rds.password_env} not set in environment`);
|
|
12850
|
+
console.error(` Add it to ~/.secrets/hasna/rds/live.env and source it`);
|
|
12851
|
+
return;
|
|
12852
|
+
}
|
|
12853
|
+
if (config.rds.host) {
|
|
12854
|
+
process.stdout.write("Testing PG connection... ");
|
|
12855
|
+
try {
|
|
12856
|
+
const connStr = getConnectionString("postgres");
|
|
12857
|
+
const pg2 = new PgAdapterAsync2(connStr);
|
|
12858
|
+
await pg2.all("SELECT 1");
|
|
12859
|
+
await pg2.close();
|
|
12860
|
+
console.log(`\u2713 Connected
|
|
12861
|
+
`);
|
|
12862
|
+
} catch (err) {
|
|
12863
|
+
console.log(`\u2717 Failed: ${err?.message ?? String(err)}`);
|
|
12864
|
+
return;
|
|
12865
|
+
}
|
|
12866
|
+
if (opts.migrate !== false) {
|
|
12867
|
+
console.log("Creating databases & running migrations...");
|
|
12868
|
+
const dbResults = await ensureAllPgDatabases();
|
|
12869
|
+
const created = dbResults.filter((r) => r.created);
|
|
12870
|
+
if (created.length > 0) {
|
|
12871
|
+
console.log(` Created ${created.length} database(s): ${created.map((r) => r.service).join(", ")}`);
|
|
12872
|
+
}
|
|
12873
|
+
const migResults = await migrateAllServices();
|
|
12874
|
+
const applied = migResults.filter((r) => r.applied.length > 0);
|
|
12875
|
+
const totalApplied = migResults.reduce((s, r) => s + r.applied.length, 0);
|
|
12876
|
+
if (totalApplied > 0) {
|
|
12877
|
+
console.log(` Applied ${totalApplied} migration(s) across ${applied.length} service(s)`);
|
|
12878
|
+
} else {
|
|
12879
|
+
console.log(" All migrations up to date");
|
|
12880
|
+
}
|
|
12881
|
+
console.log("");
|
|
12882
|
+
}
|
|
12883
|
+
if (opts.schedule) {
|
|
12884
|
+
try {
|
|
12885
|
+
const minutes = parseInterval(opts.schedule);
|
|
12886
|
+
await registerSyncSchedule(minutes);
|
|
12887
|
+
console.log(`\u2713 Sync scheduled every ${minutes}m
|
|
12888
|
+
`);
|
|
12889
|
+
} catch (err) {
|
|
12890
|
+
console.error(`\u2717 Schedule failed: ${err?.message}`);
|
|
12891
|
+
}
|
|
12892
|
+
}
|
|
12893
|
+
if (opts.pull) {
|
|
12894
|
+
console.log("Pulling data from cloud...");
|
|
12895
|
+
const services = discoverServices();
|
|
12896
|
+
for (const service of services) {
|
|
12897
|
+
try {
|
|
12898
|
+
const dbPath = getDbPath2(service);
|
|
12899
|
+
const local = new SqliteAdapter2(dbPath);
|
|
12900
|
+
const connStr = getConnectionString(service);
|
|
12901
|
+
const cloud = new PgAdapterAsync2(connStr);
|
|
12902
|
+
const tables = (await listPgTables(cloud)).filter((t) => !isSyncExcludedTable(t));
|
|
12903
|
+
if (tables.length > 0) {
|
|
12904
|
+
const results = await syncPull(cloud, local, { tables });
|
|
12905
|
+
const written = results.reduce((s, r) => s + r.rowsWritten, 0);
|
|
12906
|
+
if (written > 0)
|
|
12907
|
+
console.log(` ${service}: ${written} rows`);
|
|
12908
|
+
}
|
|
12909
|
+
local.close();
|
|
12910
|
+
await cloud.close();
|
|
12911
|
+
} catch {}
|
|
12912
|
+
}
|
|
12913
|
+
console.log("");
|
|
12914
|
+
}
|
|
12915
|
+
}
|
|
12916
|
+
console.log("Setup complete. Run `cloud doctor` to verify everything.");
|
|
12831
12917
|
});
|
|
12832
12918
|
program2.command("status").description("Show current cloud configuration and connection health").action(async () => {
|
|
12833
12919
|
const config = getCloudConfig();
|
package/package.json
CHANGED