@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.
Files changed (2) hide show
  1. package/dist/index.js +136 -0
  2. 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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@overaihq/cli",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Create, edit, deploy, and run OverAI workspace resources from the command line",
5
5
  "type": "module",
6
6
  "homepage": "https://overai.com",