tthr 0.0.31 → 0.0.33
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/index.js +72 -213
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -188,7 +188,8 @@ async function deploySchemaToServer(projectId, token, schemaPath, dryRun) {
|
|
|
188
188
|
sql,
|
|
189
189
|
tables: tables.map((t) => ({
|
|
190
190
|
name: t.name,
|
|
191
|
-
source: t.source
|
|
191
|
+
source: t.source,
|
|
192
|
+
columns: t.columns
|
|
192
193
|
}))
|
|
193
194
|
})
|
|
194
195
|
});
|
|
@@ -1839,218 +1840,77 @@ export * from './api';
|
|
|
1839
1840
|
}
|
|
1840
1841
|
}
|
|
1841
1842
|
|
|
1842
|
-
// src/commands/
|
|
1843
|
+
// src/commands/login.ts
|
|
1843
1844
|
import chalk6 from "chalk";
|
|
1844
1845
|
import ora5 from "ora";
|
|
1845
|
-
import fs7 from "fs-extra";
|
|
1846
|
-
import path7 from "path";
|
|
1847
|
-
import prompts2 from "prompts";
|
|
1848
|
-
async function migrateCommand(action, options) {
|
|
1849
|
-
await requireAuth();
|
|
1850
|
-
const configPath = path7.resolve(process.cwd(), "tether.config.ts");
|
|
1851
|
-
if (!await fs7.pathExists(configPath)) {
|
|
1852
|
-
console.log(chalk6.red("\nError: Not a Tether project"));
|
|
1853
|
-
console.log(chalk6.dim("Run `tthr init` to create a new project\n"));
|
|
1854
|
-
process.exit(1);
|
|
1855
|
-
}
|
|
1856
|
-
const migrationsDir = path7.resolve(process.cwd(), "tether", "migrations");
|
|
1857
|
-
switch (action) {
|
|
1858
|
-
case "create":
|
|
1859
|
-
await createMigration(migrationsDir, options.name);
|
|
1860
|
-
break;
|
|
1861
|
-
case "up":
|
|
1862
|
-
await runMigrations(migrationsDir, "up");
|
|
1863
|
-
break;
|
|
1864
|
-
case "down":
|
|
1865
|
-
await runMigrations(migrationsDir, "down");
|
|
1866
|
-
break;
|
|
1867
|
-
case "status":
|
|
1868
|
-
default:
|
|
1869
|
-
await showStatus(migrationsDir);
|
|
1870
|
-
break;
|
|
1871
|
-
}
|
|
1872
|
-
}
|
|
1873
|
-
async function createMigration(migrationsDir, name) {
|
|
1874
|
-
console.log(chalk6.bold("\n\u26A1 Create migration\n"));
|
|
1875
|
-
let migrationName = name;
|
|
1876
|
-
if (!migrationName) {
|
|
1877
|
-
const response = await prompts2({
|
|
1878
|
-
type: "text",
|
|
1879
|
-
name: "name",
|
|
1880
|
-
message: "Migration name:",
|
|
1881
|
-
initial: "update_schema"
|
|
1882
|
-
});
|
|
1883
|
-
migrationName = response.name;
|
|
1884
|
-
if (!migrationName) {
|
|
1885
|
-
console.log(chalk6.red("Migration name is required"));
|
|
1886
|
-
process.exit(1);
|
|
1887
|
-
}
|
|
1888
|
-
}
|
|
1889
|
-
const spinner = ora5("Creating migration...").start();
|
|
1890
|
-
try {
|
|
1891
|
-
await fs7.ensureDir(migrationsDir);
|
|
1892
|
-
const timestamp = Date.now();
|
|
1893
|
-
const filename = `${timestamp}_${migrationName}.sql`;
|
|
1894
|
-
const filepath = path7.join(migrationsDir, filename);
|
|
1895
|
-
await fs7.writeFile(
|
|
1896
|
-
filepath,
|
|
1897
|
-
`-- Migration: ${migrationName}
|
|
1898
|
-
-- Created at: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
1899
|
-
|
|
1900
|
-
-- Up migration
|
|
1901
|
-
-- Add your schema changes here
|
|
1902
|
-
|
|
1903
|
-
-- Example:
|
|
1904
|
-
-- CREATE TABLE IF NOT EXISTS users (
|
|
1905
|
-
-- id TEXT PRIMARY KEY,
|
|
1906
|
-
-- email TEXT NOT NULL UNIQUE,
|
|
1907
|
-
-- name TEXT,
|
|
1908
|
-
-- created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
1909
|
-
-- );
|
|
1910
|
-
|
|
1911
|
-
-- Down migration (for rollback)
|
|
1912
|
-
-- DROP TABLE IF EXISTS users;
|
|
1913
|
-
`
|
|
1914
|
-
);
|
|
1915
|
-
spinner.succeed("Migration created");
|
|
1916
|
-
console.log(chalk6.dim(`
|
|
1917
|
-
${filepath}
|
|
1918
|
-
`));
|
|
1919
|
-
} catch (error) {
|
|
1920
|
-
spinner.fail("Failed to create migration");
|
|
1921
|
-
console.error(chalk6.red(error instanceof Error ? error.message : "Unknown error"));
|
|
1922
|
-
process.exit(1);
|
|
1923
|
-
}
|
|
1924
|
-
}
|
|
1925
|
-
async function runMigrations(migrationsDir, direction) {
|
|
1926
|
-
console.log(chalk6.bold(`
|
|
1927
|
-
\u26A1 Running migrations (${direction})
|
|
1928
|
-
`));
|
|
1929
|
-
const spinner = ora5("Checking migrations...").start();
|
|
1930
|
-
try {
|
|
1931
|
-
if (!await fs7.pathExists(migrationsDir)) {
|
|
1932
|
-
spinner.info("No migrations directory found");
|
|
1933
|
-
console.log(chalk6.dim("\nRun `tthr migrate create` to create your first migration\n"));
|
|
1934
|
-
return;
|
|
1935
|
-
}
|
|
1936
|
-
const files = await fs7.readdir(migrationsDir);
|
|
1937
|
-
const migrations = files.filter((f) => f.endsWith(".sql")).sort((a, b) => direction === "up" ? a.localeCompare(b) : b.localeCompare(a));
|
|
1938
|
-
if (migrations.length === 0) {
|
|
1939
|
-
spinner.info("No migrations found");
|
|
1940
|
-
console.log(chalk6.dim("\nRun `tthr migrate create` to create your first migration\n"));
|
|
1941
|
-
return;
|
|
1942
|
-
}
|
|
1943
|
-
spinner.text = `Found ${migrations.length} migration(s)`;
|
|
1944
|
-
spinner.succeed(`Would run ${migrations.length} migration(s)`);
|
|
1945
|
-
console.log("\nMigrations to run:");
|
|
1946
|
-
for (const migration of migrations) {
|
|
1947
|
-
console.log(chalk6.dim(` ${migration}`));
|
|
1948
|
-
}
|
|
1949
|
-
console.log(chalk6.yellow("\nNote: Migration execution not yet implemented\n"));
|
|
1950
|
-
} catch (error) {
|
|
1951
|
-
spinner.fail("Failed to run migrations");
|
|
1952
|
-
console.error(chalk6.red(error instanceof Error ? error.message : "Unknown error"));
|
|
1953
|
-
process.exit(1);
|
|
1954
|
-
}
|
|
1955
|
-
}
|
|
1956
|
-
async function showStatus(migrationsDir) {
|
|
1957
|
-
console.log(chalk6.bold("\n\u26A1 Migration status\n"));
|
|
1958
|
-
try {
|
|
1959
|
-
if (!await fs7.pathExists(migrationsDir)) {
|
|
1960
|
-
console.log(chalk6.dim("No migrations directory found"));
|
|
1961
|
-
console.log(chalk6.dim("\nRun `tthr migrate create` to create your first migration\n"));
|
|
1962
|
-
return;
|
|
1963
|
-
}
|
|
1964
|
-
const files = await fs7.readdir(migrationsDir);
|
|
1965
|
-
const migrations = files.filter((f) => f.endsWith(".sql")).sort();
|
|
1966
|
-
if (migrations.length === 0) {
|
|
1967
|
-
console.log(chalk6.dim("No migrations found"));
|
|
1968
|
-
console.log(chalk6.dim("\nRun `tthr migrate create` to create your first migration\n"));
|
|
1969
|
-
return;
|
|
1970
|
-
}
|
|
1971
|
-
console.log(`Found ${migrations.length} migration(s):
|
|
1972
|
-
`);
|
|
1973
|
-
for (const migration of migrations) {
|
|
1974
|
-
console.log(chalk6.yellow(" \u25CB") + ` ${migration} ${chalk6.dim("(pending)")}`);
|
|
1975
|
-
}
|
|
1976
|
-
console.log();
|
|
1977
|
-
} catch (error) {
|
|
1978
|
-
console.error(chalk6.red(error instanceof Error ? error.message : "Unknown error"));
|
|
1979
|
-
process.exit(1);
|
|
1980
|
-
}
|
|
1981
|
-
}
|
|
1982
|
-
|
|
1983
|
-
// src/commands/login.ts
|
|
1984
|
-
import chalk7 from "chalk";
|
|
1985
|
-
import ora6 from "ora";
|
|
1986
1846
|
import os from "os";
|
|
1987
1847
|
var isDev3 = process.env.NODE_ENV === "development" || process.env.TETHER_DEV === "true";
|
|
1988
1848
|
var API_URL3 = isDev3 ? "http://localhost:3001/api/v1" : "https://tether-api.strands.gg/api/v1";
|
|
1989
1849
|
var AUTH_URL = isDev3 ? "http://localhost:3000/cli" : "https://tthr.io/cli";
|
|
1990
1850
|
async function loginCommand() {
|
|
1991
|
-
console.log(
|
|
1851
|
+
console.log(chalk6.bold("\u26A1 Login to Tether\n"));
|
|
1992
1852
|
const existing = await getCredentials();
|
|
1993
1853
|
if (existing) {
|
|
1994
|
-
console.log(
|
|
1995
|
-
console.log(
|
|
1854
|
+
console.log(chalk6.green("\u2713") + ` Already logged in as ${chalk6.cyan(existing.email)}`);
|
|
1855
|
+
console.log(chalk6.dim("\nRun `tthr logout` to sign out\n"));
|
|
1996
1856
|
return;
|
|
1997
1857
|
}
|
|
1998
|
-
const spinner =
|
|
1858
|
+
const spinner = ora5("Generating authentication code...").start();
|
|
1999
1859
|
try {
|
|
2000
1860
|
const deviceCode = await requestDeviceCode();
|
|
2001
1861
|
spinner.stop();
|
|
2002
1862
|
const authUrl = `${AUTH_URL}/${deviceCode.userCode}`;
|
|
2003
|
-
console.log(
|
|
2004
|
-
console.log(
|
|
1863
|
+
console.log(chalk6.dim("Open this URL in your browser to authenticate:\n"));
|
|
1864
|
+
console.log(chalk6.cyan.bold(` ${authUrl}
|
|
2005
1865
|
`));
|
|
2006
|
-
console.log(
|
|
1866
|
+
console.log(chalk6.dim(`Your code: ${chalk6.white.bold(deviceCode.userCode)}
|
|
2007
1867
|
`));
|
|
2008
1868
|
const credentials = await pollForApproval(deviceCode.deviceCode, deviceCode.interval, deviceCode.expiresIn);
|
|
2009
1869
|
await saveCredentials(credentials);
|
|
2010
|
-
console.log(
|
|
1870
|
+
console.log(chalk6.green("\u2713") + ` Logged in as ${chalk6.cyan(credentials.email)}`);
|
|
2011
1871
|
console.log();
|
|
2012
1872
|
} catch (error) {
|
|
2013
1873
|
spinner.fail("Authentication failed");
|
|
2014
|
-
console.error(
|
|
2015
|
-
console.log(
|
|
1874
|
+
console.error(chalk6.red(error instanceof Error ? error.message : "Unknown error"));
|
|
1875
|
+
console.log(chalk6.dim("\nTry again or visit https://tthr.io/docs/cli for help\n"));
|
|
2016
1876
|
process.exit(1);
|
|
2017
1877
|
}
|
|
2018
1878
|
}
|
|
2019
1879
|
async function logoutCommand() {
|
|
2020
|
-
console.log(
|
|
1880
|
+
console.log(chalk6.bold("\n\u26A1 Logout from Tether\n"));
|
|
2021
1881
|
const credentials = await getCredentials();
|
|
2022
1882
|
if (!credentials) {
|
|
2023
|
-
console.log(
|
|
1883
|
+
console.log(chalk6.dim("Not logged in\n"));
|
|
2024
1884
|
return;
|
|
2025
1885
|
}
|
|
2026
|
-
const spinner =
|
|
1886
|
+
const spinner = ora5("Logging out...").start();
|
|
2027
1887
|
try {
|
|
2028
1888
|
await clearCredentials();
|
|
2029
|
-
spinner.succeed(`Logged out from ${
|
|
1889
|
+
spinner.succeed(`Logged out from ${chalk6.cyan(credentials.email)}`);
|
|
2030
1890
|
console.log();
|
|
2031
1891
|
} catch (error) {
|
|
2032
1892
|
spinner.fail("Logout failed");
|
|
2033
|
-
console.error(
|
|
1893
|
+
console.error(chalk6.red(error instanceof Error ? error.message : "Unknown error"));
|
|
2034
1894
|
process.exit(1);
|
|
2035
1895
|
}
|
|
2036
1896
|
}
|
|
2037
1897
|
async function whoamiCommand() {
|
|
2038
1898
|
const credentials = await getCredentials();
|
|
2039
1899
|
if (!credentials) {
|
|
2040
|
-
console.log(
|
|
2041
|
-
console.log(
|
|
1900
|
+
console.log(chalk6.dim("\nNot logged in"));
|
|
1901
|
+
console.log(chalk6.dim("Run `tthr login` to authenticate\n"));
|
|
2042
1902
|
return;
|
|
2043
1903
|
}
|
|
2044
|
-
console.log(
|
|
2045
|
-
console.log(` Email: ${
|
|
2046
|
-
console.log(` User ID: ${
|
|
1904
|
+
console.log(chalk6.bold("\n\u26A1 Current user\n"));
|
|
1905
|
+
console.log(` Email: ${chalk6.cyan(credentials.email)}`);
|
|
1906
|
+
console.log(` User ID: ${chalk6.dim(credentials.userId)}`);
|
|
2047
1907
|
if (credentials.expiresAt) {
|
|
2048
1908
|
const expiresAt = new Date(credentials.expiresAt);
|
|
2049
1909
|
const now = /* @__PURE__ */ new Date();
|
|
2050
1910
|
if (expiresAt > now) {
|
|
2051
|
-
console.log(` Session: ${
|
|
1911
|
+
console.log(` Session: ${chalk6.green("Active")}`);
|
|
2052
1912
|
} else {
|
|
2053
|
-
console.log(` Session: ${
|
|
1913
|
+
console.log(` Session: ${chalk6.yellow("Expired")}`);
|
|
2054
1914
|
}
|
|
2055
1915
|
}
|
|
2056
1916
|
console.log();
|
|
@@ -2092,20 +1952,20 @@ async function requestDeviceCode() {
|
|
|
2092
1952
|
async function pollForApproval(deviceCode, interval, expiresIn) {
|
|
2093
1953
|
const startTime = Date.now();
|
|
2094
1954
|
const expiresAt = startTime + expiresIn * 1e3;
|
|
2095
|
-
const spinner =
|
|
1955
|
+
const spinner = ora5("").start();
|
|
2096
1956
|
const updateCountdown = () => {
|
|
2097
1957
|
const remaining = Math.max(0, Math.ceil((expiresAt - Date.now()) / 1e3));
|
|
2098
1958
|
const mins = Math.floor(remaining / 60);
|
|
2099
1959
|
const secs = remaining % 60;
|
|
2100
1960
|
const timeStr = mins > 0 ? `${mins}:${secs.toString().padStart(2, "0")}` : `${secs}s`;
|
|
2101
|
-
spinner.text = `Waiting for approval... ${
|
|
1961
|
+
spinner.text = `Waiting for approval... ${chalk6.dim(`(${timeStr} remaining)`)}`;
|
|
2102
1962
|
};
|
|
2103
1963
|
updateCountdown();
|
|
2104
1964
|
const countdownInterval = setInterval(updateCountdown, 1e3);
|
|
2105
1965
|
try {
|
|
2106
1966
|
while (Date.now() < expiresAt) {
|
|
2107
1967
|
await sleep(interval * 1e3);
|
|
2108
|
-
spinner.text = `Checking... ${
|
|
1968
|
+
spinner.text = `Checking... ${chalk6.dim(`(${Math.ceil((expiresAt - Date.now()) / 1e3)}s remaining)`)}`;
|
|
2109
1969
|
const response = await fetch(`${API_URL3}/auth/device/${deviceCode}`, {
|
|
2110
1970
|
method: "GET"
|
|
2111
1971
|
}).catch(() => null);
|
|
@@ -2138,10 +1998,10 @@ function sleep(ms) {
|
|
|
2138
1998
|
}
|
|
2139
1999
|
|
|
2140
2000
|
// src/commands/update.ts
|
|
2141
|
-
import
|
|
2142
|
-
import
|
|
2143
|
-
import
|
|
2144
|
-
import
|
|
2001
|
+
import chalk7 from "chalk";
|
|
2002
|
+
import ora6 from "ora";
|
|
2003
|
+
import fs7 from "fs-extra";
|
|
2004
|
+
import path7 from "path";
|
|
2145
2005
|
import { execSync as execSync2 } from "child_process";
|
|
2146
2006
|
var TETHER_PACKAGES = [
|
|
2147
2007
|
"@tthr/client",
|
|
@@ -2153,13 +2013,13 @@ var TETHER_PACKAGES = [
|
|
|
2153
2013
|
];
|
|
2154
2014
|
function detectPackageManager() {
|
|
2155
2015
|
const cwd = process.cwd();
|
|
2156
|
-
if (
|
|
2016
|
+
if (fs7.existsSync(path7.join(cwd, "bun.lockb")) || fs7.existsSync(path7.join(cwd, "bun.lock"))) {
|
|
2157
2017
|
return "bun";
|
|
2158
2018
|
}
|
|
2159
|
-
if (
|
|
2019
|
+
if (fs7.existsSync(path7.join(cwd, "pnpm-lock.yaml"))) {
|
|
2160
2020
|
return "pnpm";
|
|
2161
2021
|
}
|
|
2162
|
-
if (
|
|
2022
|
+
if (fs7.existsSync(path7.join(cwd, "yarn.lock"))) {
|
|
2163
2023
|
return "yarn";
|
|
2164
2024
|
}
|
|
2165
2025
|
return "npm";
|
|
@@ -2189,14 +2049,14 @@ async function getLatestVersion2(packageName) {
|
|
|
2189
2049
|
}
|
|
2190
2050
|
}
|
|
2191
2051
|
async function updateCommand(options) {
|
|
2192
|
-
const packageJsonPath =
|
|
2193
|
-
if (!await
|
|
2194
|
-
console.log(
|
|
2195
|
-
console.log(
|
|
2052
|
+
const packageJsonPath = path7.resolve(process.cwd(), "package.json");
|
|
2053
|
+
if (!await fs7.pathExists(packageJsonPath)) {
|
|
2054
|
+
console.log(chalk7.red("\nError: No package.json found"));
|
|
2055
|
+
console.log(chalk7.dim("Make sure you're in the root of your project\n"));
|
|
2196
2056
|
process.exit(1);
|
|
2197
2057
|
}
|
|
2198
|
-
console.log(
|
|
2199
|
-
const packageJson = await
|
|
2058
|
+
console.log(chalk7.bold("\n\u26A1 Updating Tether packages\n"));
|
|
2059
|
+
const packageJson = await fs7.readJson(packageJsonPath);
|
|
2200
2060
|
const deps = packageJson.dependencies || {};
|
|
2201
2061
|
const devDeps = packageJson.devDependencies || {};
|
|
2202
2062
|
const installedDeps = [];
|
|
@@ -2209,13 +2069,13 @@ async function updateCommand(options) {
|
|
|
2209
2069
|
}
|
|
2210
2070
|
}
|
|
2211
2071
|
if (installedDeps.length === 0) {
|
|
2212
|
-
console.log(
|
|
2213
|
-
console.log(
|
|
2072
|
+
console.log(chalk7.yellow(" No updatable Tether packages found in package.json"));
|
|
2073
|
+
console.log(chalk7.dim(" Tether packages start with @tthr/ (workspace: dependencies are skipped)\n"));
|
|
2214
2074
|
return;
|
|
2215
2075
|
}
|
|
2216
|
-
console.log(
|
|
2076
|
+
console.log(chalk7.dim(` Found ${installedDeps.length} Tether package(s):
|
|
2217
2077
|
`));
|
|
2218
|
-
const spinner =
|
|
2078
|
+
const spinner = ora6("Checking for updates...").start();
|
|
2219
2079
|
const packagesToUpdate = [];
|
|
2220
2080
|
for (const pkg of installedDeps) {
|
|
2221
2081
|
const latestVersion = await getLatestVersion2(pkg.name);
|
|
@@ -2229,32 +2089,32 @@ async function updateCommand(options) {
|
|
|
2229
2089
|
isDev: pkg.isDev
|
|
2230
2090
|
});
|
|
2231
2091
|
} else {
|
|
2232
|
-
console.log(
|
|
2092
|
+
console.log(chalk7.dim(` ${pkg.name}@${currentClean} (up to date)`));
|
|
2233
2093
|
}
|
|
2234
2094
|
}
|
|
2235
2095
|
}
|
|
2236
2096
|
spinner.stop();
|
|
2237
2097
|
if (packagesToUpdate.length === 0) {
|
|
2238
|
-
console.log(
|
|
2098
|
+
console.log(chalk7.green("\n\u2713 All Tether packages are up to date\n"));
|
|
2239
2099
|
return;
|
|
2240
2100
|
}
|
|
2241
|
-
console.log(
|
|
2101
|
+
console.log(chalk7.cyan("\n Updates available:\n"));
|
|
2242
2102
|
for (const pkg of packagesToUpdate) {
|
|
2243
2103
|
console.log(
|
|
2244
|
-
|
|
2104
|
+
chalk7.white(` ${pkg.name}`) + chalk7.red(` ${pkg.current}`) + chalk7.dim(" \u2192 ") + chalk7.green(`${pkg.latest}`) + (pkg.isDev ? chalk7.dim(" (dev)") : "")
|
|
2245
2105
|
);
|
|
2246
2106
|
}
|
|
2247
2107
|
if (options.dryRun) {
|
|
2248
|
-
console.log(
|
|
2108
|
+
console.log(chalk7.yellow("\n Dry run - no packages were updated\n"));
|
|
2249
2109
|
return;
|
|
2250
2110
|
}
|
|
2251
2111
|
const pm = detectPackageManager();
|
|
2252
|
-
console.log(
|
|
2112
|
+
console.log(chalk7.dim(`
|
|
2253
2113
|
Using ${pm} to update packages...
|
|
2254
2114
|
`));
|
|
2255
2115
|
const depsToUpdate = packagesToUpdate.filter((p) => !p.isDev).map((p) => `${p.name}@latest`);
|
|
2256
2116
|
const devDepsToUpdate = packagesToUpdate.filter((p) => p.isDev).map((p) => `${p.name}@latest`);
|
|
2257
|
-
const updateSpinner =
|
|
2117
|
+
const updateSpinner = ora6("Installing updates...").start();
|
|
2258
2118
|
try {
|
|
2259
2119
|
if (depsToUpdate.length > 0) {
|
|
2260
2120
|
const cmd = getInstallCommand2(pm, depsToUpdate, false);
|
|
@@ -2265,43 +2125,43 @@ async function updateCommand(options) {
|
|
|
2265
2125
|
execSync2(cmd, { stdio: "pipe", cwd: process.cwd() });
|
|
2266
2126
|
}
|
|
2267
2127
|
updateSpinner.succeed("Packages updated successfully");
|
|
2268
|
-
console.log(
|
|
2128
|
+
console.log(chalk7.green(`
|
|
2269
2129
|
\u2713 Updated ${packagesToUpdate.length} package(s)
|
|
2270
2130
|
`));
|
|
2271
2131
|
} catch (error) {
|
|
2272
2132
|
updateSpinner.fail("Failed to update packages");
|
|
2273
|
-
console.error(
|
|
2133
|
+
console.error(chalk7.red(error instanceof Error ? error.message : "Unknown error"));
|
|
2274
2134
|
process.exit(1);
|
|
2275
2135
|
}
|
|
2276
2136
|
}
|
|
2277
2137
|
|
|
2278
2138
|
// src/commands/exec.ts
|
|
2279
|
-
import
|
|
2280
|
-
import
|
|
2281
|
-
import
|
|
2282
|
-
import
|
|
2139
|
+
import chalk8 from "chalk";
|
|
2140
|
+
import ora7 from "ora";
|
|
2141
|
+
import fs8 from "fs-extra";
|
|
2142
|
+
import path8 from "path";
|
|
2283
2143
|
var isDev4 = process.env.NODE_ENV === "development" || process.env.TETHER_DEV === "true";
|
|
2284
2144
|
var API_URL4 = isDev4 ? "http://localhost:3001/api/v1" : "https://tether-api.strands.gg/api/v1";
|
|
2285
2145
|
async function execCommand(sql) {
|
|
2286
2146
|
if (!sql || sql.trim() === "") {
|
|
2287
|
-
console.log(
|
|
2288
|
-
console.log(
|
|
2147
|
+
console.log(chalk8.red("\nError: SQL query required"));
|
|
2148
|
+
console.log(chalk8.dim('Usage: tthr exec "SELECT * FROM table_name"\n'));
|
|
2289
2149
|
process.exit(1);
|
|
2290
2150
|
}
|
|
2291
2151
|
const credentials = await requireAuth();
|
|
2292
|
-
const envPath =
|
|
2152
|
+
const envPath = path8.resolve(process.cwd(), ".env");
|
|
2293
2153
|
let projectId;
|
|
2294
|
-
if (await
|
|
2295
|
-
const envContent = await
|
|
2154
|
+
if (await fs8.pathExists(envPath)) {
|
|
2155
|
+
const envContent = await fs8.readFile(envPath, "utf-8");
|
|
2296
2156
|
const match = envContent.match(/TETHER_PROJECT_ID=(.+)/);
|
|
2297
2157
|
projectId = match?.[1]?.trim();
|
|
2298
2158
|
}
|
|
2299
2159
|
if (!projectId) {
|
|
2300
|
-
console.log(
|
|
2301
|
-
console.log(
|
|
2160
|
+
console.log(chalk8.red("\nError: Project ID not found"));
|
|
2161
|
+
console.log(chalk8.dim("Make sure TETHER_PROJECT_ID is set in your .env file\n"));
|
|
2302
2162
|
process.exit(1);
|
|
2303
2163
|
}
|
|
2304
|
-
const spinner =
|
|
2164
|
+
const spinner = ora7("Executing query...").start();
|
|
2305
2165
|
try {
|
|
2306
2166
|
const response = await fetch(`${API_URL4}/projects/${projectId}/exec`, {
|
|
2307
2167
|
method: "POST",
|
|
@@ -2321,24 +2181,24 @@ async function execCommand(sql) {
|
|
|
2321
2181
|
if (result.columns && result.rows) {
|
|
2322
2182
|
console.log();
|
|
2323
2183
|
if (result.rows.length === 0) {
|
|
2324
|
-
console.log(
|
|
2184
|
+
console.log(chalk8.dim(" No rows returned"));
|
|
2325
2185
|
} else {
|
|
2326
|
-
console.log(
|
|
2327
|
-
console.log(
|
|
2186
|
+
console.log(chalk8.bold(" " + result.columns.join(" ")));
|
|
2187
|
+
console.log(chalk8.dim(" " + result.columns.map(() => "--------").join(" ")));
|
|
2328
2188
|
for (const row of result.rows) {
|
|
2329
2189
|
const values = result.columns.map((col) => {
|
|
2330
2190
|
const val = row[col];
|
|
2331
|
-
if (val === null) return
|
|
2191
|
+
if (val === null) return chalk8.dim("NULL");
|
|
2332
2192
|
if (typeof val === "object") return JSON.stringify(val);
|
|
2333
2193
|
return String(val);
|
|
2334
2194
|
});
|
|
2335
2195
|
console.log(" " + values.join(" "));
|
|
2336
2196
|
}
|
|
2337
|
-
console.log(
|
|
2197
|
+
console.log(chalk8.dim(`
|
|
2338
2198
|
${result.rows.length} row(s)`));
|
|
2339
2199
|
}
|
|
2340
2200
|
} else if (result.rowsAffected !== void 0) {
|
|
2341
|
-
console.log(
|
|
2201
|
+
console.log(chalk8.dim(`
|
|
2342
2202
|
${result.rowsAffected} row(s) affected`));
|
|
2343
2203
|
}
|
|
2344
2204
|
console.log();
|
|
@@ -2354,7 +2214,6 @@ program.name("tthr").description("Tether CLI - Realtime SQLite for modern applic
|
|
|
2354
2214
|
program.command("init [name]").description("Create a new Tether project").option("-t, --template <template>", "Project template (vue, svelte, react, vanilla)", "vue").action(initCommand);
|
|
2355
2215
|
program.command("dev").description("Start local development server with hot reload").option("-p, --port <port>", "Port to run on", "3001").action(devCommand);
|
|
2356
2216
|
program.command("generate").alias("gen").description("Generate types from schema").action(generateCommand);
|
|
2357
|
-
program.command("migrate").description("Database migrations").argument("[action]", "Migration action: create, up, down, status", "status").option("-n, --name <name>", "Migration name (for create)").action(migrateCommand);
|
|
2358
2217
|
program.command("deploy").description("Deploy schema and functions to Tether").option("-s, --schema", "Deploy schema only").option("-f, --functions", "Deploy functions only").option("--dry-run", "Show what would be deployed without deploying").action(deployCommand);
|
|
2359
2218
|
program.command("login").description("Authenticate with Tether").action(loginCommand);
|
|
2360
2219
|
program.command("logout").description("Sign out of Tether").action(logoutCommand);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tthr",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Tether CLI - project scaffolding
|
|
3
|
+
"version": "0.0.33",
|
|
4
|
+
"description": "Tether CLI - project scaffolding and deployment",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"tthr": "./dist/index.js"
|