ardent-cli 0.0.16 → 0.0.18
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 +240 -14
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { readFileSync as
|
|
5
|
-
import { Command as
|
|
4
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
5
|
+
import { Command as Command8 } from "commander";
|
|
6
6
|
|
|
7
7
|
// src/commands/branch/index.ts
|
|
8
8
|
import { Command } from "commander";
|
|
@@ -700,6 +700,33 @@ async function createAction2(type, url, options) {
|
|
|
700
700
|
console.error(` Supported: ${supportedTypes.join(", ")}`);
|
|
701
701
|
process.exit(1);
|
|
702
702
|
}
|
|
703
|
+
const deploymentModel = options.deploymentModel ?? "ardent-cloud";
|
|
704
|
+
if (deploymentModel !== "ardent-cloud" && deploymentModel !== "customer-cloud") {
|
|
705
|
+
console.error(`\u2717 Invalid --deployment-model: ${deploymentModel}`);
|
|
706
|
+
console.error(" Supported: ardent-cloud, customer-cloud");
|
|
707
|
+
process.exit(1);
|
|
708
|
+
}
|
|
709
|
+
const isCustomerCloud = deploymentModel === "customer-cloud";
|
|
710
|
+
if (isCustomerCloud) {
|
|
711
|
+
const missing = [];
|
|
712
|
+
if (!options.awsRoleArn) missing.push("--aws-role-arn");
|
|
713
|
+
if (!options.awsExternalId) missing.push("--aws-external-id");
|
|
714
|
+
if (!options.awsRegion) missing.push("--aws-region");
|
|
715
|
+
if (missing.length > 0) {
|
|
716
|
+
console.error(
|
|
717
|
+
`\u2717 ${missing.join(", ")} required when --deployment-model=customer-cloud`
|
|
718
|
+
);
|
|
719
|
+
process.exit(1);
|
|
720
|
+
}
|
|
721
|
+
} else {
|
|
722
|
+
const stray = options.awsRoleArn || options.awsExternalId || options.awsRegion;
|
|
723
|
+
if (stray) {
|
|
724
|
+
console.error(
|
|
725
|
+
"\u2717 --aws-role-arn / --aws-external-id / --aws-region require --deployment-model=customer-cloud"
|
|
726
|
+
);
|
|
727
|
+
process.exit(1);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
703
730
|
const isByoc = Boolean(options.byoc);
|
|
704
731
|
if (isByoc) {
|
|
705
732
|
if (!options.apiKey || !options.projectId) {
|
|
@@ -727,7 +754,9 @@ async function createAction2(type, url, options) {
|
|
|
727
754
|
}
|
|
728
755
|
let createPayload;
|
|
729
756
|
if (isByoc) {
|
|
730
|
-
console.log(
|
|
757
|
+
console.log(
|
|
758
|
+
`Creating connector (BYOC Neon${isCustomerCloud ? ", customer-cloud data plane" : ""})...`
|
|
759
|
+
);
|
|
731
760
|
createPayload = {
|
|
732
761
|
name: connectorName,
|
|
733
762
|
service_name: "postgresql",
|
|
@@ -744,7 +773,9 @@ async function createAction2(type, url, options) {
|
|
|
744
773
|
console.error(" Example: postgresql://user:password@host:5432/db");
|
|
745
774
|
process.exit(1);
|
|
746
775
|
}
|
|
747
|
-
console.log(
|
|
776
|
+
console.log(
|
|
777
|
+
`Creating connector${isCustomerCloud ? " (customer-cloud data plane)" : ""}...`
|
|
778
|
+
);
|
|
748
779
|
createPayload = {
|
|
749
780
|
name: connectorName,
|
|
750
781
|
service_name: "postgresql",
|
|
@@ -757,6 +788,14 @@ async function createAction2(type, url, options) {
|
|
|
757
788
|
}
|
|
758
789
|
};
|
|
759
790
|
}
|
|
791
|
+
if (isCustomerCloud) {
|
|
792
|
+
createPayload.deployment_model = "customer-cloud";
|
|
793
|
+
createPayload.byoc_access_credentials = {
|
|
794
|
+
role_arn: options.awsRoleArn,
|
|
795
|
+
external_id: options.awsExternalId,
|
|
796
|
+
region: options.awsRegion
|
|
797
|
+
};
|
|
798
|
+
}
|
|
760
799
|
const created = await api.post("/v1/connectors", createPayload);
|
|
761
800
|
const connectorId = created.id;
|
|
762
801
|
if (isByoc) {
|
|
@@ -807,7 +846,11 @@ async function createAction2(type, url, options) {
|
|
|
807
846
|
setCacheEntry("connectors", cachedConnectors);
|
|
808
847
|
setConfig("currentConnectorId", connectorId);
|
|
809
848
|
setConfig("currentConnectorName", connectorName);
|
|
810
|
-
trackEvent("CLI: connector create succeeded", {
|
|
849
|
+
trackEvent("CLI: connector create succeeded", {
|
|
850
|
+
db_type: type,
|
|
851
|
+
byoc: isByoc,
|
|
852
|
+
deployment_model: deploymentModel
|
|
853
|
+
});
|
|
811
854
|
console.log("\u2713 Connector created and ready");
|
|
812
855
|
console.log(` ID: ${connectorId}`);
|
|
813
856
|
showNextStep();
|
|
@@ -1009,7 +1052,19 @@ async function switchAction2(name) {
|
|
|
1009
1052
|
|
|
1010
1053
|
// src/commands/connector/index.ts
|
|
1011
1054
|
var connectorCommand = new Command2("connector").description("Manage database connectors");
|
|
1012
|
-
connectorCommand.command("create <type> [url]").description("Create a new connector").option("-n, --name <name>", "Connector name").option("--byoc <provider>", "Bring your own Neon project (e.g. neon)").option("--api-key <key>", "Neon API key (required with --byoc)").option("--project-id <id>", "Neon project ID (required with --byoc)").
|
|
1055
|
+
connectorCommand.command("create <type> [url]").description("Create a new connector").option("-n, --name <name>", "Connector name").option("--byoc <provider>", "Bring your own Neon project (e.g. neon)").option("--api-key <key>", "Neon API key (required with --byoc)").option("--project-id <id>", "Neon project ID (required with --byoc)").option(
|
|
1056
|
+
"--deployment-model <model>",
|
|
1057
|
+
"'ardent-cloud' (default) or 'customer-cloud' to route CDC through the customer's AWS account"
|
|
1058
|
+
).option(
|
|
1059
|
+
"--aws-role-arn <arn>",
|
|
1060
|
+
"ArdentDeployer role ARN in the customer account (required with --deployment-model=customer-cloud)"
|
|
1061
|
+
).option(
|
|
1062
|
+
"--aws-external-id <id>",
|
|
1063
|
+
"External ID for sts:AssumeRole (required with --deployment-model=customer-cloud)"
|
|
1064
|
+
).option(
|
|
1065
|
+
"--aws-region <region>",
|
|
1066
|
+
"AWS region of the customer data plane (required with --deployment-model=customer-cloud)"
|
|
1067
|
+
).action(createAction2);
|
|
1013
1068
|
connectorCommand.command("list").description("List your connectors").action(listAction2);
|
|
1014
1069
|
connectorCommand.command("switch <name>").description("Switch to a different connector").action(switchAction2);
|
|
1015
1070
|
connectorCommand.command("delete <name>").description("Delete a connector by name").action(deleteAction2);
|
|
@@ -1385,9 +1440,174 @@ projectCommand.command("create <name>").description("Create a new project").acti
|
|
|
1385
1440
|
projectCommand.command("list").description("List your projects").action(listAction4);
|
|
1386
1441
|
projectCommand.command("switch <name>").description("Switch to a different project").action(switchAction3);
|
|
1387
1442
|
|
|
1388
|
-
// src/commands/
|
|
1443
|
+
// src/commands/settings/index.ts
|
|
1389
1444
|
import { Command as Command6 } from "commander";
|
|
1390
1445
|
|
|
1446
|
+
// src/lib/settings.ts
|
|
1447
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
1448
|
+
var SETTING_KEYS = ["default_db", "branch_sql"];
|
|
1449
|
+
function requireConnectorAndOrg() {
|
|
1450
|
+
const connectorId = getConfig("currentConnectorId");
|
|
1451
|
+
const user = getConfig("user");
|
|
1452
|
+
const orgId = user?.org_id;
|
|
1453
|
+
if (!connectorId) {
|
|
1454
|
+
console.error("\u2717 No connector selected. Run 'ardent connector switch' first.");
|
|
1455
|
+
process.exit(1);
|
|
1456
|
+
}
|
|
1457
|
+
if (!orgId) {
|
|
1458
|
+
console.error("\u2717 Not logged in. Run 'ardent login' first.");
|
|
1459
|
+
process.exit(1);
|
|
1460
|
+
}
|
|
1461
|
+
return {
|
|
1462
|
+
connectorId,
|
|
1463
|
+
connectorName: getConfig("currentConnectorName") ?? connectorId,
|
|
1464
|
+
orgId
|
|
1465
|
+
};
|
|
1466
|
+
}
|
|
1467
|
+
function parseSettingKey(key) {
|
|
1468
|
+
if (!SETTING_KEYS.includes(key)) {
|
|
1469
|
+
console.error(`\u2717 Unknown setting '${key}'. Valid: ${SETTING_KEYS.join(", ")}`);
|
|
1470
|
+
process.exit(1);
|
|
1471
|
+
}
|
|
1472
|
+
return key;
|
|
1473
|
+
}
|
|
1474
|
+
var SETTING_DESCRIPTIONS = {
|
|
1475
|
+
default_db: "Default database in branch URLs",
|
|
1476
|
+
branch_sql: "SQL to run on every new branch after creation"
|
|
1477
|
+
};
|
|
1478
|
+
function settingKeyToPolicyType(key) {
|
|
1479
|
+
if (key === "default_db") return "connection_default_db";
|
|
1480
|
+
if (key === "branch_sql") return "branch_create_hook";
|
|
1481
|
+
throw new Error(`Unknown setting key: ${key}`);
|
|
1482
|
+
}
|
|
1483
|
+
function buildPolicyConfig(key, value) {
|
|
1484
|
+
if (key === "default_db") return { database: value };
|
|
1485
|
+
if (key === "branch_sql") return { sql: value };
|
|
1486
|
+
throw new Error(`Unknown setting key: ${key}`);
|
|
1487
|
+
}
|
|
1488
|
+
function readSettingValue(key, config) {
|
|
1489
|
+
if (key === "default_db") return String(config.database ?? "");
|
|
1490
|
+
if (key === "branch_sql") return String(config.sql ?? "");
|
|
1491
|
+
throw new Error(`Unknown setting key: ${key}`);
|
|
1492
|
+
}
|
|
1493
|
+
function resolveValueFromArg(value) {
|
|
1494
|
+
if (value.startsWith("@")) {
|
|
1495
|
+
const path = value.slice(1);
|
|
1496
|
+
try {
|
|
1497
|
+
return readFileSync3(path, "utf-8");
|
|
1498
|
+
} catch (err) {
|
|
1499
|
+
throw new Error(
|
|
1500
|
+
`Failed to read ${path}: ${err instanceof Error ? err.message : String(err)}`
|
|
1501
|
+
);
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
return value;
|
|
1505
|
+
}
|
|
1506
|
+
async function findPolicyForConnector(orgId, connectorId, policyType) {
|
|
1507
|
+
const policies = await api.get(
|
|
1508
|
+
`/v1/policies?org_id=${orgId}&connector_id=${connectorId}`
|
|
1509
|
+
);
|
|
1510
|
+
return policies.find((policy) => policy.type === policyType) ?? null;
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
// src/commands/settings/list.ts
|
|
1514
|
+
async function listAction5() {
|
|
1515
|
+
const { connectorId, connectorName, orgId } = requireConnectorAndOrg();
|
|
1516
|
+
try {
|
|
1517
|
+
console.log(`Connector: ${connectorName}
|
|
1518
|
+
`);
|
|
1519
|
+
for (const key of SETTING_KEYS) {
|
|
1520
|
+
const policy = await findPolicyForConnector(
|
|
1521
|
+
orgId,
|
|
1522
|
+
connectorId,
|
|
1523
|
+
settingKeyToPolicyType(key)
|
|
1524
|
+
);
|
|
1525
|
+
if (policy) {
|
|
1526
|
+
const value = readSettingValue(key, policy.config);
|
|
1527
|
+
const display = value.length > 80 ? value.slice(0, 77) + "..." : value;
|
|
1528
|
+
console.log(` ${key.padEnd(12)} ${display}`);
|
|
1529
|
+
} else {
|
|
1530
|
+
console.log(` ${key.padEnd(12)} (not set) \u2014 ${SETTING_DESCRIPTIONS[key]}`);
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
trackEvent("CLI: settings list succeeded");
|
|
1534
|
+
} catch (err) {
|
|
1535
|
+
trackEvent("CLI: settings list failed", { reason: "api_error" });
|
|
1536
|
+
console.error("\u2717 Failed:", err instanceof Error ? err.message : err);
|
|
1537
|
+
process.exit(1);
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
// src/commands/settings/set.ts
|
|
1542
|
+
async function setAction(key, value) {
|
|
1543
|
+
const settingKey = parseSettingKey(key);
|
|
1544
|
+
const { connectorId, orgId } = requireConnectorAndOrg();
|
|
1545
|
+
let resolvedValue;
|
|
1546
|
+
try {
|
|
1547
|
+
resolvedValue = resolveValueFromArg(value);
|
|
1548
|
+
} catch (err) {
|
|
1549
|
+
console.error("\u2717", err instanceof Error ? err.message : err);
|
|
1550
|
+
process.exit(1);
|
|
1551
|
+
}
|
|
1552
|
+
const policyType = settingKeyToPolicyType(settingKey);
|
|
1553
|
+
const config = buildPolicyConfig(settingKey, resolvedValue);
|
|
1554
|
+
try {
|
|
1555
|
+
const existing = await findPolicyForConnector(orgId, connectorId, policyType);
|
|
1556
|
+
if (existing) {
|
|
1557
|
+
await api.patch(`/v1/policies/${existing.id}`, { config });
|
|
1558
|
+
console.log(`\u2713 Updated ${settingKey}`);
|
|
1559
|
+
trackEvent("CLI: settings set succeeded", { key: settingKey, op: "update" });
|
|
1560
|
+
return;
|
|
1561
|
+
}
|
|
1562
|
+
await api.post("/v1/policies", {
|
|
1563
|
+
org_id: orgId,
|
|
1564
|
+
name: settingKey,
|
|
1565
|
+
type: policyType,
|
|
1566
|
+
config,
|
|
1567
|
+
assign_to_scope: { scope_type: "connectors", scope_id: connectorId }
|
|
1568
|
+
});
|
|
1569
|
+
console.log(`\u2713 Set ${settingKey}`);
|
|
1570
|
+
trackEvent("CLI: settings set succeeded", { key: settingKey, op: "create" });
|
|
1571
|
+
} catch (err) {
|
|
1572
|
+
trackEvent("CLI: settings set failed", { key: settingKey });
|
|
1573
|
+
console.error("\u2717 Failed:", err instanceof Error ? err.message : err);
|
|
1574
|
+
process.exit(1);
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
// src/commands/settings/remove.ts
|
|
1579
|
+
async function removeAction2(key) {
|
|
1580
|
+
const settingKey = parseSettingKey(key);
|
|
1581
|
+
const { connectorId, orgId } = requireConnectorAndOrg();
|
|
1582
|
+
const policyType = settingKeyToPolicyType(settingKey);
|
|
1583
|
+
try {
|
|
1584
|
+
const existing = await findPolicyForConnector(orgId, connectorId, policyType);
|
|
1585
|
+
if (!existing) {
|
|
1586
|
+
console.log(`${settingKey} is not set`);
|
|
1587
|
+
trackEvent("CLI: settings remove noop", { key: settingKey });
|
|
1588
|
+
return;
|
|
1589
|
+
}
|
|
1590
|
+
await api.delete(`/v1/policies/${existing.id}`);
|
|
1591
|
+
console.log(`\u2713 Removed ${settingKey}`);
|
|
1592
|
+
trackEvent("CLI: settings remove succeeded", { key: settingKey });
|
|
1593
|
+
} catch (err) {
|
|
1594
|
+
trackEvent("CLI: settings remove failed", { key: settingKey });
|
|
1595
|
+
console.error("\u2717 Failed:", err instanceof Error ? err.message : err);
|
|
1596
|
+
process.exit(1);
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
// src/commands/settings/index.ts
|
|
1601
|
+
var settingsCommand = new Command6("settings").description("Manage settings for the current connector").showHelpAfterError("(run 'ardent settings --help' for valid keys)");
|
|
1602
|
+
settingsCommand.command("list").description("List current settings for the connector").action(listAction5);
|
|
1603
|
+
settingsCommand.command("set <key> <value>").description(
|
|
1604
|
+
"Set a setting. Keys: default_db, branch_sql. For branch_sql, prefix value with @ to read from file."
|
|
1605
|
+
).action(setAction);
|
|
1606
|
+
settingsCommand.command("remove <key>").description("Remove a setting. Keys: default_db, branch_sql.").action(removeAction2);
|
|
1607
|
+
|
|
1608
|
+
// src/commands/auth/index.ts
|
|
1609
|
+
import { Command as Command7 } from "commander";
|
|
1610
|
+
|
|
1391
1611
|
// src/commands/auth/login.ts
|
|
1392
1612
|
async function loginAction(options) {
|
|
1393
1613
|
if (options.token) {
|
|
@@ -1517,12 +1737,12 @@ function statusAction() {
|
|
|
1517
1737
|
}
|
|
1518
1738
|
|
|
1519
1739
|
// src/commands/auth/index.ts
|
|
1520
|
-
var loginCommand = new
|
|
1521
|
-
var logoutCommand = new
|
|
1522
|
-
var statusCommand = new
|
|
1740
|
+
var loginCommand = new Command7("login").description("Login to Ardent").option("-t, --token <token>", "API token (skip browser login)").action(loginAction);
|
|
1741
|
+
var logoutCommand = new Command7("logout").description("Logout from Ardent").action(logoutAction);
|
|
1742
|
+
var statusCommand = new Command7("status").description("Show status").action(statusAction);
|
|
1523
1743
|
|
|
1524
1744
|
// src/lib/update-check.ts
|
|
1525
|
-
import { existsSync as existsSync2, readFileSync as
|
|
1745
|
+
import { existsSync as existsSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
1526
1746
|
import { join as join2 } from "path";
|
|
1527
1747
|
import { homedir as homedir2 } from "os";
|
|
1528
1748
|
var UPDATE_CHECK_FILE = join2(homedir2(), ".ardent", "update-check.json");
|
|
@@ -1531,7 +1751,7 @@ var PACKAGE_NAME = "ardent-cli";
|
|
|
1531
1751
|
function loadCache() {
|
|
1532
1752
|
try {
|
|
1533
1753
|
if (existsSync2(UPDATE_CHECK_FILE)) {
|
|
1534
|
-
return JSON.parse(
|
|
1754
|
+
return JSON.parse(readFileSync4(UPDATE_CHECK_FILE, "utf-8"));
|
|
1535
1755
|
}
|
|
1536
1756
|
} catch {
|
|
1537
1757
|
}
|
|
@@ -1624,6 +1844,11 @@ BRANCHES
|
|
|
1624
1844
|
branch delete Delete a branch
|
|
1625
1845
|
branch switch Switch to a different branch
|
|
1626
1846
|
|
|
1847
|
+
SETTINGS
|
|
1848
|
+
settings list List current settings for the connector
|
|
1849
|
+
settings set Set a setting (e.g. default_db testdb)
|
|
1850
|
+
settings remove Remove a setting
|
|
1851
|
+
|
|
1627
1852
|
TEAM
|
|
1628
1853
|
invite <email> Invite a user to your organization
|
|
1629
1854
|
invite list List pending invites
|
|
@@ -1644,11 +1869,11 @@ EXAMPLES
|
|
|
1644
1869
|
ardent org members
|
|
1645
1870
|
`;
|
|
1646
1871
|
var CLI_VERSION2 = getCliVersion2();
|
|
1647
|
-
var program = new
|
|
1872
|
+
var program = new Command8();
|
|
1648
1873
|
function getCliVersion2() {
|
|
1649
1874
|
try {
|
|
1650
1875
|
const packageUrl = new URL("../package.json", import.meta.url);
|
|
1651
|
-
const raw =
|
|
1876
|
+
const raw = readFileSync5(packageUrl, "utf-8");
|
|
1652
1877
|
const parsed = JSON.parse(raw);
|
|
1653
1878
|
return parsed.version ?? "unknown";
|
|
1654
1879
|
} catch {
|
|
@@ -1664,6 +1889,7 @@ program.addCommand(statusCommand);
|
|
|
1664
1889
|
program.addCommand(projectCommand);
|
|
1665
1890
|
program.addCommand(connectorCommand);
|
|
1666
1891
|
program.addCommand(branchCommand);
|
|
1892
|
+
program.addCommand(settingsCommand);
|
|
1667
1893
|
program.addCommand(inviteCommand);
|
|
1668
1894
|
program.addCommand(orgCommand);
|
|
1669
1895
|
program.on("command:*", (operands) => {
|