clivly 0.4.0 → 0.4.1
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/README.md +4 -3
- package/index.cjs +55 -8
- package/index.d.cts +3 -1
- package/index.d.mts +3 -1
- package/index.mjs +55 -10
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -40,9 +40,10 @@ import { createWorkOSAuthAdapter } from "clivly/auth/workos";
|
|
|
40
40
|
import { createBetterAuthAdapter } from "clivly/auth/better-auth";
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
Provider and framework integrations use optional peer dependencies.
|
|
44
|
-
|
|
45
|
-
`@
|
|
43
|
+
Provider and framework integrations use optional peer dependencies.
|
|
44
|
+
**Supported auth providers: Clerk, WorkOS, and BetterAuth.** Install only
|
|
45
|
+
what your app actually uses, such as `drizzle-orm`, `vite`, `@clerk/backend`,
|
|
46
|
+
`@workos-inc/node`, or `better-auth`.
|
|
46
47
|
|
|
47
48
|
`clivly init` detects your framework from `package.json`, locates your Drizzle
|
|
48
49
|
schema, and generates a `clivly.config.ts` that maps likely contact and company
|
package/index.cjs
CHANGED
|
@@ -1389,9 +1389,10 @@ function parentDir(dir) {
|
|
|
1389
1389
|
const parent = (0, node_path.dirname)(dir);
|
|
1390
1390
|
return parent === dir ? null : parent;
|
|
1391
1391
|
}
|
|
1392
|
-
function findNearestPackageDir(start) {
|
|
1392
|
+
function findNearestPackageDir(start, boundary) {
|
|
1393
1393
|
let current = (0, node_path.resolve)(start);
|
|
1394
1394
|
while (true) {
|
|
1395
|
+
if (current === boundary) return null;
|
|
1395
1396
|
if ((0, node_fs.existsSync)((0, node_path.join)(current, "package.json"))) return current;
|
|
1396
1397
|
const parent = parentDir(current);
|
|
1397
1398
|
if (!parent) return null;
|
|
@@ -1423,9 +1424,10 @@ function expandWorkspaceGlob(root, pattern) {
|
|
|
1423
1424
|
const exact = (0, node_path.join)(root, pattern);
|
|
1424
1425
|
return (0, node_fs.existsSync)((0, node_path.join)(exact, "package.json")) ? [exact] : [];
|
|
1425
1426
|
}
|
|
1426
|
-
function findWorkspaceRoot(start) {
|
|
1427
|
+
function findWorkspaceRoot(start, boundary) {
|
|
1427
1428
|
let current = (0, node_path.resolve)(start);
|
|
1428
1429
|
while (true) {
|
|
1430
|
+
if (current === boundary) return null;
|
|
1429
1431
|
if (readWorkspaceGlobs(current).length > 0) return current;
|
|
1430
1432
|
const parent = parentDir(current);
|
|
1431
1433
|
if (!parent) return null;
|
|
@@ -1444,13 +1446,14 @@ function rankCandidates(paths, start) {
|
|
|
1444
1446
|
return distance(a) - distance(b) || a.localeCompare(b);
|
|
1445
1447
|
});
|
|
1446
1448
|
}
|
|
1447
|
-
function resolveTargetApp(start) {
|
|
1448
|
-
const
|
|
1449
|
+
function resolveTargetApp(start, boundary = (0, node_os.homedir)()) {
|
|
1450
|
+
const stop = (0, node_path.resolve)(boundary);
|
|
1451
|
+
const nearestPackageDir = findNearestPackageDir(start, stop);
|
|
1449
1452
|
if (nearestPackageDir && isDrizzleApp(nearestPackageDir)) return {
|
|
1450
1453
|
cwd: nearestPackageDir,
|
|
1451
1454
|
reason: "direct"
|
|
1452
1455
|
};
|
|
1453
|
-
const workspaceRoot = findWorkspaceRoot(start);
|
|
1456
|
+
const workspaceRoot = findWorkspaceRoot(start, stop);
|
|
1454
1457
|
if (!workspaceRoot) return {
|
|
1455
1458
|
cwd: nearestPackageDir ?? (0, node_path.resolve)(start),
|
|
1456
1459
|
reason: "direct"
|
|
@@ -1710,6 +1713,40 @@ function flagValue(argv, flag) {
|
|
|
1710
1713
|
const index = argv.indexOf(flag);
|
|
1711
1714
|
return index >= 0 ? argv[index + 1] : void 0;
|
|
1712
1715
|
}
|
|
1716
|
+
const KNOWN_COMMANDS = [
|
|
1717
|
+
"init",
|
|
1718
|
+
"status",
|
|
1719
|
+
"push-schema",
|
|
1720
|
+
"dev",
|
|
1721
|
+
"login",
|
|
1722
|
+
"help"
|
|
1723
|
+
];
|
|
1724
|
+
function editDistance(a, b) {
|
|
1725
|
+
const m = a.length;
|
|
1726
|
+
const n = b.length;
|
|
1727
|
+
const prev = Array.from({ length: n + 1 }, (_, i) => i);
|
|
1728
|
+
const curr = Array.from({ length: n + 1 }, () => 0);
|
|
1729
|
+
for (let i = 1; i <= m; i++) {
|
|
1730
|
+
curr[0] = i;
|
|
1731
|
+
for (let j = 1; j <= n; j++) {
|
|
1732
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
1733
|
+
curr[j] = Math.min(prev[j] + 1, curr[j - 1] + 1, prev[j - 1] + cost);
|
|
1734
|
+
}
|
|
1735
|
+
for (let j = 0; j <= n; j++) prev[j] = curr[j];
|
|
1736
|
+
}
|
|
1737
|
+
return curr[n];
|
|
1738
|
+
}
|
|
1739
|
+
function nearestCommand(input) {
|
|
1740
|
+
let best;
|
|
1741
|
+
for (const command of KNOWN_COMMANDS) {
|
|
1742
|
+
const distance = editDistance(input, command);
|
|
1743
|
+
if (distance <= 2 && (!best || distance < best.distance)) best = {
|
|
1744
|
+
command,
|
|
1745
|
+
distance
|
|
1746
|
+
};
|
|
1747
|
+
}
|
|
1748
|
+
return best?.command;
|
|
1749
|
+
}
|
|
1713
1750
|
function readDeps(cwd) {
|
|
1714
1751
|
const pkgPath = (0, node_path.join)(cwd, "package.json");
|
|
1715
1752
|
if (!(0, node_fs.existsSync)(pkgPath)) return {};
|
|
@@ -1780,7 +1817,7 @@ async function acquireSchema(options, deps) {
|
|
|
1780
1817
|
const { out } = deps;
|
|
1781
1818
|
const appDeps = deps.readDepsFn(options.cwd);
|
|
1782
1819
|
if (Object.keys(appDeps).length === 0) {
|
|
1783
|
-
out(
|
|
1820
|
+
out(`No package.json found in ${options.cwd}. Run \`clivly init\` from inside an existing app — cd into your project first.\n`);
|
|
1784
1821
|
return { code: 1 };
|
|
1785
1822
|
}
|
|
1786
1823
|
const framework = detectFramework(appDeps);
|
|
@@ -2166,19 +2203,29 @@ async function main(argv) {
|
|
|
2166
2203
|
openBrowser: !rest.includes("--no-browser"),
|
|
2167
2204
|
deps: defaultLoginDeps()
|
|
2168
2205
|
});
|
|
2206
|
+
case "--version":
|
|
2207
|
+
case "-v":
|
|
2208
|
+
process.stdout.write(`${readOwnVersion() ?? "unknown"}\n`);
|
|
2209
|
+
return 0;
|
|
2169
2210
|
case void 0:
|
|
2170
2211
|
case "help":
|
|
2171
2212
|
case "--help":
|
|
2172
|
-
process.stdout.write("clivly — embed a CRM in your app\n\nUsage:\n clivly init [--force] [--dry-run] [--schema <path>] [--no-login] [--no-browser] Scaffold Clivly (config, routes, .env) for your app\n clivly status [--verbose] [--config <path>] Check your setup, step by step\n clivly push-schema [--config <path>] Report your schema to Clivly without deploying\n clivly dev [--port <n>] [--api-url <url>] [--route-path <path>] [-- <cmd>] Tunnel localhost for remote sync\n clivly login [--force] [--rotate] [--api-url <url>] [--no-browser] Pair this machine and write CLIVLY_API_KEY / CLIVLY_SYNC_TRIGGER_SECRET to .env\n");
|
|
2213
|
+
process.stdout.write("clivly — embed a CRM in your app\n\nUsage:\n clivly init [--force] [--dry-run] [--schema <path>] [--no-login] [--no-browser] Scaffold Clivly (config, routes, .env) for your app\n clivly status [--verbose] [--config <path>] Check your setup, step by step\n clivly push-schema [--config <path>] Report your schema to Clivly without deploying\n clivly dev [--port <n>] [--api-url <url>] [--route-path <path>] [-- <cmd>] Tunnel localhost for remote sync\n clivly login [--force] [--rotate] [--api-url <url>] [--no-browser] Pair this machine and write CLIVLY_API_KEY / CLIVLY_SYNC_TRIGGER_SECRET to .env\n clivly --version Print the installed clivly version\n");
|
|
2173
2214
|
return 0;
|
|
2174
|
-
default:
|
|
2215
|
+
default: {
|
|
2175
2216
|
process.stdout.write(`Unknown command: ${command}\n`);
|
|
2217
|
+
const suggestion = nearestCommand(command);
|
|
2218
|
+
if (suggestion) process.stdout.write(`Did you mean \`clivly ${suggestion}\`?\n`);
|
|
2219
|
+
process.stdout.write("Run `clivly --help` to see available commands.\n");
|
|
2176
2220
|
return 1;
|
|
2221
|
+
}
|
|
2177
2222
|
}
|
|
2178
2223
|
}
|
|
2179
2224
|
if (isEntrypoint(process.argv[1], require("url").pathToFileURL(__filename).href)) main(process.argv.slice(2)).then((code) => {
|
|
2180
2225
|
process.exitCode = code;
|
|
2181
2226
|
});
|
|
2182
2227
|
//#endregion
|
|
2228
|
+
exports.main = main;
|
|
2229
|
+
exports.nearestCommand = nearestCommand;
|
|
2183
2230
|
exports.runInit = runInit;
|
|
2184
2231
|
exports.runInitFromArgv = runInitFromArgv;
|
package/index.d.cts
CHANGED
|
@@ -36,6 +36,7 @@ interface ProbeHit {
|
|
|
36
36
|
}
|
|
37
37
|
//#endregion
|
|
38
38
|
//#region src/index.d.ts
|
|
39
|
+
declare function nearestCommand(input: string): string | undefined;
|
|
39
40
|
interface InstallResult {
|
|
40
41
|
command: string;
|
|
41
42
|
ok: boolean;
|
|
@@ -73,5 +74,6 @@ interface RunInitOptions {
|
|
|
73
74
|
}
|
|
74
75
|
declare function runInit(options: RunInitOptions): Promise<number>;
|
|
75
76
|
declare function runInitFromArgv(argv: string[], cwd: string): Promise<number>;
|
|
77
|
+
declare function main(argv: string[]): Promise<number>;
|
|
76
78
|
//#endregion
|
|
77
|
-
export { RunInitOptions, runInit, runInitFromArgv };
|
|
79
|
+
export { RunInitOptions, main, nearestCommand, runInit, runInitFromArgv };
|
package/index.d.mts
CHANGED
|
@@ -36,6 +36,7 @@ interface ProbeHit {
|
|
|
36
36
|
}
|
|
37
37
|
//#endregion
|
|
38
38
|
//#region src/index.d.ts
|
|
39
|
+
declare function nearestCommand(input: string): string | undefined;
|
|
39
40
|
interface InstallResult {
|
|
40
41
|
command: string;
|
|
41
42
|
ok: boolean;
|
|
@@ -73,5 +74,6 @@ interface RunInitOptions {
|
|
|
73
74
|
}
|
|
74
75
|
declare function runInit(options: RunInitOptions): Promise<number>;
|
|
75
76
|
declare function runInitFromArgv(argv: string[], cwd: string): Promise<number>;
|
|
77
|
+
declare function main(argv: string[]): Promise<number>;
|
|
76
78
|
//#endregion
|
|
77
|
-
export { RunInitOptions, runInit, runInitFromArgv };
|
|
79
|
+
export { RunInitOptions, main, nearestCommand, runInit, runInitFromArgv };
|
package/index.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import { t as createClivlySDK } from "./sdk-DdzBxgMx.mjs";
|
|
|
6
6
|
import { createRequire } from "node:module";
|
|
7
7
|
import { spawn } from "node:child_process";
|
|
8
8
|
import { accessSync, constants, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, statSync, writeFileSync } from "node:fs";
|
|
9
|
-
import { hostname } from "node:os";
|
|
9
|
+
import { homedir, hostname } from "node:os";
|
|
10
10
|
import { delimiter, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
11
11
|
import { createInterface } from "node:readline/promises";
|
|
12
12
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
@@ -1388,9 +1388,10 @@ function parentDir(dir) {
|
|
|
1388
1388
|
const parent = dirname(dir);
|
|
1389
1389
|
return parent === dir ? null : parent;
|
|
1390
1390
|
}
|
|
1391
|
-
function findNearestPackageDir(start) {
|
|
1391
|
+
function findNearestPackageDir(start, boundary) {
|
|
1392
1392
|
let current = resolve(start);
|
|
1393
1393
|
while (true) {
|
|
1394
|
+
if (current === boundary) return null;
|
|
1394
1395
|
if (existsSync(join(current, "package.json"))) return current;
|
|
1395
1396
|
const parent = parentDir(current);
|
|
1396
1397
|
if (!parent) return null;
|
|
@@ -1422,9 +1423,10 @@ function expandWorkspaceGlob(root, pattern) {
|
|
|
1422
1423
|
const exact = join(root, pattern);
|
|
1423
1424
|
return existsSync(join(exact, "package.json")) ? [exact] : [];
|
|
1424
1425
|
}
|
|
1425
|
-
function findWorkspaceRoot(start) {
|
|
1426
|
+
function findWorkspaceRoot(start, boundary) {
|
|
1426
1427
|
let current = resolve(start);
|
|
1427
1428
|
while (true) {
|
|
1429
|
+
if (current === boundary) return null;
|
|
1428
1430
|
if (readWorkspaceGlobs(current).length > 0) return current;
|
|
1429
1431
|
const parent = parentDir(current);
|
|
1430
1432
|
if (!parent) return null;
|
|
@@ -1443,13 +1445,14 @@ function rankCandidates(paths, start) {
|
|
|
1443
1445
|
return distance(a) - distance(b) || a.localeCompare(b);
|
|
1444
1446
|
});
|
|
1445
1447
|
}
|
|
1446
|
-
function resolveTargetApp(start) {
|
|
1447
|
-
const
|
|
1448
|
+
function resolveTargetApp(start, boundary = homedir()) {
|
|
1449
|
+
const stop = resolve(boundary);
|
|
1450
|
+
const nearestPackageDir = findNearestPackageDir(start, stop);
|
|
1448
1451
|
if (nearestPackageDir && isDrizzleApp(nearestPackageDir)) return {
|
|
1449
1452
|
cwd: nearestPackageDir,
|
|
1450
1453
|
reason: "direct"
|
|
1451
1454
|
};
|
|
1452
|
-
const workspaceRoot = findWorkspaceRoot(start);
|
|
1455
|
+
const workspaceRoot = findWorkspaceRoot(start, stop);
|
|
1453
1456
|
if (!workspaceRoot) return {
|
|
1454
1457
|
cwd: nearestPackageDir ?? resolve(start),
|
|
1455
1458
|
reason: "direct"
|
|
@@ -1709,6 +1712,40 @@ function flagValue(argv, flag) {
|
|
|
1709
1712
|
const index = argv.indexOf(flag);
|
|
1710
1713
|
return index >= 0 ? argv[index + 1] : void 0;
|
|
1711
1714
|
}
|
|
1715
|
+
const KNOWN_COMMANDS = [
|
|
1716
|
+
"init",
|
|
1717
|
+
"status",
|
|
1718
|
+
"push-schema",
|
|
1719
|
+
"dev",
|
|
1720
|
+
"login",
|
|
1721
|
+
"help"
|
|
1722
|
+
];
|
|
1723
|
+
function editDistance(a, b) {
|
|
1724
|
+
const m = a.length;
|
|
1725
|
+
const n = b.length;
|
|
1726
|
+
const prev = Array.from({ length: n + 1 }, (_, i) => i);
|
|
1727
|
+
const curr = Array.from({ length: n + 1 }, () => 0);
|
|
1728
|
+
for (let i = 1; i <= m; i++) {
|
|
1729
|
+
curr[0] = i;
|
|
1730
|
+
for (let j = 1; j <= n; j++) {
|
|
1731
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
1732
|
+
curr[j] = Math.min(prev[j] + 1, curr[j - 1] + 1, prev[j - 1] + cost);
|
|
1733
|
+
}
|
|
1734
|
+
for (let j = 0; j <= n; j++) prev[j] = curr[j];
|
|
1735
|
+
}
|
|
1736
|
+
return curr[n];
|
|
1737
|
+
}
|
|
1738
|
+
function nearestCommand(input) {
|
|
1739
|
+
let best;
|
|
1740
|
+
for (const command of KNOWN_COMMANDS) {
|
|
1741
|
+
const distance = editDistance(input, command);
|
|
1742
|
+
if (distance <= 2 && (!best || distance < best.distance)) best = {
|
|
1743
|
+
command,
|
|
1744
|
+
distance
|
|
1745
|
+
};
|
|
1746
|
+
}
|
|
1747
|
+
return best?.command;
|
|
1748
|
+
}
|
|
1712
1749
|
function readDeps(cwd) {
|
|
1713
1750
|
const pkgPath = join(cwd, "package.json");
|
|
1714
1751
|
if (!existsSync(pkgPath)) return {};
|
|
@@ -1779,7 +1816,7 @@ async function acquireSchema(options, deps) {
|
|
|
1779
1816
|
const { out } = deps;
|
|
1780
1817
|
const appDeps = deps.readDepsFn(options.cwd);
|
|
1781
1818
|
if (Object.keys(appDeps).length === 0) {
|
|
1782
|
-
out(
|
|
1819
|
+
out(`No package.json found in ${options.cwd}. Run \`clivly init\` from inside an existing app — cd into your project first.\n`);
|
|
1783
1820
|
return { code: 1 };
|
|
1784
1821
|
}
|
|
1785
1822
|
const framework = detectFramework(appDeps);
|
|
@@ -2165,18 +2202,26 @@ async function main(argv) {
|
|
|
2165
2202
|
openBrowser: !rest.includes("--no-browser"),
|
|
2166
2203
|
deps: defaultLoginDeps()
|
|
2167
2204
|
});
|
|
2205
|
+
case "--version":
|
|
2206
|
+
case "-v":
|
|
2207
|
+
process.stdout.write(`${readOwnVersion() ?? "unknown"}\n`);
|
|
2208
|
+
return 0;
|
|
2168
2209
|
case void 0:
|
|
2169
2210
|
case "help":
|
|
2170
2211
|
case "--help":
|
|
2171
|
-
process.stdout.write("clivly — embed a CRM in your app\n\nUsage:\n clivly init [--force] [--dry-run] [--schema <path>] [--no-login] [--no-browser] Scaffold Clivly (config, routes, .env) for your app\n clivly status [--verbose] [--config <path>] Check your setup, step by step\n clivly push-schema [--config <path>] Report your schema to Clivly without deploying\n clivly dev [--port <n>] [--api-url <url>] [--route-path <path>] [-- <cmd>] Tunnel localhost for remote sync\n clivly login [--force] [--rotate] [--api-url <url>] [--no-browser] Pair this machine and write CLIVLY_API_KEY / CLIVLY_SYNC_TRIGGER_SECRET to .env\n");
|
|
2212
|
+
process.stdout.write("clivly — embed a CRM in your app\n\nUsage:\n clivly init [--force] [--dry-run] [--schema <path>] [--no-login] [--no-browser] Scaffold Clivly (config, routes, .env) for your app\n clivly status [--verbose] [--config <path>] Check your setup, step by step\n clivly push-schema [--config <path>] Report your schema to Clivly without deploying\n clivly dev [--port <n>] [--api-url <url>] [--route-path <path>] [-- <cmd>] Tunnel localhost for remote sync\n clivly login [--force] [--rotate] [--api-url <url>] [--no-browser] Pair this machine and write CLIVLY_API_KEY / CLIVLY_SYNC_TRIGGER_SECRET to .env\n clivly --version Print the installed clivly version\n");
|
|
2172
2213
|
return 0;
|
|
2173
|
-
default:
|
|
2214
|
+
default: {
|
|
2174
2215
|
process.stdout.write(`Unknown command: ${command}\n`);
|
|
2216
|
+
const suggestion = nearestCommand(command);
|
|
2217
|
+
if (suggestion) process.stdout.write(`Did you mean \`clivly ${suggestion}\`?\n`);
|
|
2218
|
+
process.stdout.write("Run `clivly --help` to see available commands.\n");
|
|
2175
2219
|
return 1;
|
|
2220
|
+
}
|
|
2176
2221
|
}
|
|
2177
2222
|
}
|
|
2178
2223
|
if (isEntrypoint(process.argv[1], import.meta.url)) main(process.argv.slice(2)).then((code) => {
|
|
2179
2224
|
process.exitCode = code;
|
|
2180
2225
|
});
|
|
2181
2226
|
//#endregion
|
|
2182
|
-
export { runInit, runInitFromArgv };
|
|
2227
|
+
export { main, nearestCommand, runInit, runInitFromArgv };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clivly",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Clivly CLI — scaffold a CRM into your app (clivly init).",
|
|
@@ -210,7 +210,8 @@
|
|
|
210
210
|
"types": "./auth-better-auth.d.cts",
|
|
211
211
|
"default": "./auth-better-auth.cjs"
|
|
212
212
|
}
|
|
213
|
-
}
|
|
213
|
+
},
|
|
214
|
+
"./package.json": "./package.json"
|
|
214
215
|
},
|
|
215
216
|
"dependencies": {
|
|
216
217
|
"jiti": "^2.7.0"
|
|
@@ -218,6 +219,7 @@
|
|
|
218
219
|
"peerDependencies": {
|
|
219
220
|
"@clerk/backend": ">=1",
|
|
220
221
|
"@workos-inc/node": ">=7",
|
|
222
|
+
"better-auth": ">=1",
|
|
221
223
|
"drizzle-orm": ">=0.30",
|
|
222
224
|
"vite": ">=5"
|
|
223
225
|
},
|
|
@@ -228,6 +230,9 @@
|
|
|
228
230
|
"@workos-inc/node": {
|
|
229
231
|
"optional": true
|
|
230
232
|
},
|
|
233
|
+
"better-auth": {
|
|
234
|
+
"optional": true
|
|
235
|
+
},
|
|
231
236
|
"drizzle-orm": {
|
|
232
237
|
"optional": true
|
|
233
238
|
},
|