@overaihq/cli 0.6.0 → 0.7.0
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 +136 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -34775,11 +34775,34 @@ var workflow = `# CLI editing workflow
|
|
|
34775
34775
|
|
|
34776
34776
|
Never edit .overai/ by hand \u2014 it holds the manifest and pristine base copies
|
|
34777
34777
|
that make status/diff/fast-forward work.`;
|
|
34778
|
+
var tablespaces = `# TableSpace best practices
|
|
34779
|
+
|
|
34780
|
+
TableSpaces are isolated PostgreSQL databases. Use PostgreSQL syntax and the
|
|
34781
|
+
generated env.TBSxxx client from pages, functions, and automation code.
|
|
34782
|
+
|
|
34783
|
+
- \`overai sql <tableSpaceId>\` runs SQL through OverAI's authenticated,
|
|
34784
|
+
audited HTTP surface. This is the normal interactive CLI path.
|
|
34785
|
+
- \`overai sql credential create <tableSpaceId> --name <name>\` creates a
|
|
34786
|
+
durable \`postgresql://\` connection string for standard database clients.
|
|
34787
|
+
The CLI prints a PostgreSQL 16+ libpq URL with
|
|
34788
|
+
\`sslmode=verify-full&sslrootcert=system\`. Older libpq clients must point
|
|
34789
|
+
\`sslrootcert\` at a trusted CA file. Other drivers should use the host,
|
|
34790
|
+
port, database, username, and secret with hostname and certificate
|
|
34791
|
+
verification enabled through that driver's TLS settings.
|
|
34792
|
+
It expires after one year unless \`--expires-in <days>\` or \`--never\` is
|
|
34793
|
+
supplied and permitted by organization policy.
|
|
34794
|
+
- Give each service its own credential. List, rotate, or revoke it with
|
|
34795
|
+
\`overai sql credential list|rotate|revoke\`.
|
|
34796
|
+
- The generated secret is the PostgreSQL password. Account passwords, PATs,
|
|
34797
|
+
and JWTs are not accepted. Create and rotate show the secret once.
|
|
34798
|
+
- Rotation, expiration, and revocation reject new connections. Existing
|
|
34799
|
+
sessions continue until disconnect.`;
|
|
34778
34800
|
var BEST_PRACTICES = {
|
|
34779
34801
|
platform: platform2,
|
|
34780
34802
|
automations,
|
|
34781
34803
|
pages,
|
|
34782
34804
|
functions,
|
|
34805
|
+
tablespaces,
|
|
34783
34806
|
workflow
|
|
34784
34807
|
};
|
|
34785
34808
|
|
|
@@ -34986,6 +35009,112 @@ var runReview = async () => {
|
|
|
34986
35009
|
|
|
34987
35010
|
// src/commands/sql.ts
|
|
34988
35011
|
import { createInterface } from "readline";
|
|
35012
|
+
|
|
35013
|
+
// src/commands/sqlCredential.ts
|
|
35014
|
+
var connectionString = async (tableSpaceId, secret) => {
|
|
35015
|
+
const response = await v2Fetch("/v2/cluster-info");
|
|
35016
|
+
const body = await response.json();
|
|
35017
|
+
return `postgresql://overai:${encodeURIComponent(secret)}@${body.postgres.host}:${String(body.postgres.port)}/${tableSpaceId}?sslmode=${body.postgres.sslMode}${body.postgres.sslMode === "verify-full" ? "&sslrootcert=system" : ""}`;
|
|
35018
|
+
};
|
|
35019
|
+
var credentialTableSpaceId = async (credentialId) => {
|
|
35020
|
+
const data = await gqlRequest(
|
|
35021
|
+
`query TableSpaceCredential($id: String!) {
|
|
35022
|
+
tableSpaceCredential(id: $id) { tableSpaceId }
|
|
35023
|
+
}`,
|
|
35024
|
+
{ id: credentialId }
|
|
35025
|
+
);
|
|
35026
|
+
if (!data.tableSpaceCredential) {
|
|
35027
|
+
throw new Error("Credential not found or you lack access to it");
|
|
35028
|
+
}
|
|
35029
|
+
return data.tableSpaceCredential.tableSpaceId;
|
|
35030
|
+
};
|
|
35031
|
+
var runSqlCredential = async (args) => {
|
|
35032
|
+
const [action, id] = args;
|
|
35033
|
+
if (!action || !id) {
|
|
35034
|
+
throw new Error(
|
|
35035
|
+
"Usage: overai sql credential create|list <tableSpaceId> | rotate|revoke <credentialId>"
|
|
35036
|
+
);
|
|
35037
|
+
}
|
|
35038
|
+
if (action === "create") {
|
|
35039
|
+
const tableSpaceId = id;
|
|
35040
|
+
const name2 = flagValue(args, "--name");
|
|
35041
|
+
if (!name2) throw new Error("create requires --name <name>");
|
|
35042
|
+
const expiresIn = flagValue(args, "--expires-in");
|
|
35043
|
+
if (expiresIn && args.includes("--never")) {
|
|
35044
|
+
throw new Error("Use either --expires-in <days> or --never, not both");
|
|
35045
|
+
}
|
|
35046
|
+
const days = expiresIn ? Number(expiresIn) : 365;
|
|
35047
|
+
if (!args.includes("--never") && (!Number.isInteger(days) || days < 1)) {
|
|
35048
|
+
throw new Error("--expires-in must be a positive whole number of days");
|
|
35049
|
+
}
|
|
35050
|
+
const data = await gqlRequest(
|
|
35051
|
+
`mutation CreateTableSpaceCredential($tableSpaceId: String!, $name: String!, $validUntil: Datetime) {
|
|
35052
|
+
createTableSpaceCredential(input: { tableSpaceId: $tableSpaceId, name: $name, validUntil: $validUntil }) { result }
|
|
35053
|
+
}`,
|
|
35054
|
+
{
|
|
35055
|
+
tableSpaceId,
|
|
35056
|
+
name: name2,
|
|
35057
|
+
validUntil: args.includes("--never") ? null : new Date(Date.now() + days * 864e5).toISOString()
|
|
35058
|
+
}
|
|
35059
|
+
);
|
|
35060
|
+
const result = data.createTableSpaceCredential?.result;
|
|
35061
|
+
if (!result) throw new Error("The server did not return a credential");
|
|
35062
|
+
process.stdout.write(
|
|
35063
|
+
`${await connectionString(tableSpaceId, result.secret)}
|
|
35064
|
+
`
|
|
35065
|
+
);
|
|
35066
|
+
return;
|
|
35067
|
+
}
|
|
35068
|
+
if (action === "list") {
|
|
35069
|
+
const tableSpaceId = id;
|
|
35070
|
+
const data = await gqlRequest(
|
|
35071
|
+
`query TableSpaceCredentials($tableSpaceId: String!) {
|
|
35072
|
+
tableSpaceCredentials(condition: { tableSpaceId: $tableSpaceId }) {
|
|
35073
|
+
nodes { id name validUntil lastUsedAt createdAt }
|
|
35074
|
+
}
|
|
35075
|
+
}`,
|
|
35076
|
+
{ tableSpaceId }
|
|
35077
|
+
);
|
|
35078
|
+
printResult(
|
|
35079
|
+
data.tableSpaceCredentials?.nodes ?? [],
|
|
35080
|
+
resolveFormat(flagValue(args, "-o", "--output"))
|
|
35081
|
+
);
|
|
35082
|
+
return;
|
|
35083
|
+
}
|
|
35084
|
+
if (action === "rotate") {
|
|
35085
|
+
const credentialId = id;
|
|
35086
|
+
const tableSpaceId = await credentialTableSpaceId(credentialId);
|
|
35087
|
+
const data = await gqlRequest(
|
|
35088
|
+
`mutation RotateTableSpaceCredential($credentialId: String!) {
|
|
35089
|
+
rotateTableSpaceCredential(input: { credentialId: $credentialId }) { result }
|
|
35090
|
+
}`,
|
|
35091
|
+
{ credentialId }
|
|
35092
|
+
);
|
|
35093
|
+
const secret = data.rotateTableSpaceCredential?.result;
|
|
35094
|
+
if (!secret) throw new Error("The server did not return a credential");
|
|
35095
|
+
process.stdout.write(`${await connectionString(tableSpaceId, secret)}
|
|
35096
|
+
`);
|
|
35097
|
+
return;
|
|
35098
|
+
}
|
|
35099
|
+
if (action === "revoke") {
|
|
35100
|
+
const credentialId = id;
|
|
35101
|
+
await credentialTableSpaceId(credentialId);
|
|
35102
|
+
await gqlRequest(
|
|
35103
|
+
`mutation RevokeTableSpaceCredential($id: String!, $validUntil: Datetime!) {
|
|
35104
|
+
updateTableSpaceCredential(input: { id: $id, patch: { validUntil: $validUntil } }) {
|
|
35105
|
+
tableSpaceCredential { id }
|
|
35106
|
+
}
|
|
35107
|
+
}`,
|
|
35108
|
+
{ id: credentialId, validUntil: (/* @__PURE__ */ new Date()).toISOString() }
|
|
35109
|
+
);
|
|
35110
|
+
process.stdout.write(`${credentialId} revoked
|
|
35111
|
+
`);
|
|
35112
|
+
return;
|
|
35113
|
+
}
|
|
35114
|
+
throw new Error(`Unknown credential action: ${action}`);
|
|
35115
|
+
};
|
|
35116
|
+
|
|
35117
|
+
// src/commands/sql.ts
|
|
34989
35118
|
var runQuery = async (organizationId, tableSpaceId, query, params) => {
|
|
34990
35119
|
const res = await v2Fetch(
|
|
34991
35120
|
`/v2/table-spaces/${organizationId}/${tableSpaceId}/run`,
|
|
@@ -35135,6 +35264,9 @@ var runRepl = async (organizationId, tableSpaceId, format2) => {
|
|
|
35135
35264
|
});
|
|
35136
35265
|
};
|
|
35137
35266
|
var runSql = async (args) => {
|
|
35267
|
+
if (args[0] === "credential") {
|
|
35268
|
+
return runSqlCredential(args.slice(1));
|
|
35269
|
+
}
|
|
35138
35270
|
const tableSpaceId = args[0];
|
|
35139
35271
|
if (tableSpaceId == null || tableSpaceId.startsWith("-")) {
|
|
35140
35272
|
throw new Error(
|
|
@@ -35608,6 +35740,10 @@ Usage:
|
|
|
35608
35740
|
Execution history / logs
|
|
35609
35741
|
overai sql <tableSpaceId> ["<SQL>"] Run SQL against a tablespace; no query
|
|
35610
35742
|
opens a psql-style session (stdin scripts work)
|
|
35743
|
+
overai sql credential create <tableSpaceId> --name <name> [--expires-in <days>|--never]
|
|
35744
|
+
Create a durable PostgreSQL connection string
|
|
35745
|
+
overai sql credential list <tableSpaceId>
|
|
35746
|
+
overai sql credential rotate|revoke <credentialId>
|
|
35611
35747
|
|
|
35612
35748
|
Workspace sync (edit resources as local files):
|
|
35613
35749
|
overai clone <workspaceId> [dir] Materialize resources and WORKSPACE.md
|