@erdoai/cli 0.40.2 → 0.42.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 +85 -5
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -127,9 +127,10 @@ function networkErrorFor(method, path, err) {
127
127
  return new ErdoNetworkError(`${method} ${path} failed: ${detail}`, cause);
128
128
  }
129
129
  var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
130
- async function rawRequest(baseURL, token, orgId, method, path, body) {
130
+ async function rawRequest(baseURL, token, orgId, projectId, method, path, body) {
131
131
  const headers = { Authorization: `Bearer ${token}` };
132
132
  if (orgId) headers["X-Organization-ID"] = orgId;
133
+ if (projectId) headers["X-Project-ID"] = projectId;
133
134
  if (body !== void 0) headers["Content-Type"] = "application/json";
134
135
  const upper = method.toUpperCase();
135
136
  const maxRetries = upper === "GET" || upper === "HEAD" ? 2 : 1;
@@ -178,13 +179,21 @@ function looksLikeHTML(text) {
178
179
  return head.startsWith("<!doctype html") || head.startsWith("<html") || head.includes("<head>");
179
180
  }
180
181
  function fetchMe(token, orgId) {
181
- return rawRequest(resolveApiUrl(), token, orgId, "GET", "/v1/me");
182
+ return rawRequest(
183
+ resolveApiUrl(),
184
+ token,
185
+ orgId,
186
+ void 0,
187
+ "GET",
188
+ "/v1/me"
189
+ );
182
190
  }
183
191
  var announcedOrg = false;
184
192
  var ErdoClient = class {
185
193
  baseURL;
186
194
  token;
187
195
  orgId;
196
+ projectId;
188
197
  orgPinned;
189
198
  orgName;
190
199
  constructor(orgOverride) {
@@ -196,6 +205,7 @@ var ErdoClient = class {
196
205
  }
197
206
  this.token = token;
198
207
  this.orgId = resolveOrgId(acct, orgOverride);
208
+ this.projectId = process.env.ERDO_PROJECT?.trim() || void 0;
199
209
  this.orgPinned = Boolean(orgOverride || process.env.ERDO_ORG);
200
210
  this.orgName = acct?.organizationName;
201
211
  }
@@ -217,7 +227,15 @@ var ErdoClient = class {
217
227
  }
218
228
  request(method, path, body) {
219
229
  this.announceOrgOnce(method);
220
- return rawRequest(this.baseURL, this.token, this.orgId, method, path, body);
230
+ return rawRequest(
231
+ this.baseURL,
232
+ this.token,
233
+ this.orgId,
234
+ this.projectId,
235
+ method,
236
+ path,
237
+ body
238
+ );
221
239
  }
222
240
  me() {
223
241
  return this.request("GET", "/v1/me");
@@ -694,6 +712,24 @@ var ErdoClient = class {
694
712
  checkIntegrationConnection(app) {
695
713
  return this.request("GET", `/v1/integrations-connect/${encodeURIComponent(app)}`);
696
714
  }
715
+ // --- integration connect links ---
716
+ // A connect link is an unauthenticated, shareable URL that lets a third party
717
+ // (e.g. a client's IT admin) complete a native integration's OAuth / API-key
718
+ // setup without an Erdo account. It expires in 14 days and completes once — the
719
+ // returned link_url is a secret.
720
+ createConnectLink(body) {
721
+ return this.request("POST", "/v1/integration-connect-links", body);
722
+ }
723
+ listConnectLinks(app) {
724
+ const qs = app ? `?app=${encodeURIComponent(app)}` : "";
725
+ return this.request("GET", `/v1/integration-connect-links${qs}`);
726
+ }
727
+ revokeConnectLink(id) {
728
+ return this.request(
729
+ "POST",
730
+ `/v1/integration-connect-links/${encodeURIComponent(id)}/revoke`
731
+ );
732
+ }
697
733
  // --- dataset filters ---
698
734
  listDatasetFilters(datasetSlug) {
699
735
  return this.request(
@@ -1150,10 +1186,12 @@ function summariseResults(results, cases = []) {
1150
1186
  }
1151
1187
  }
1152
1188
  var program = new Command();
1153
- program.name("erdo").description("Erdo CLI").version(pkg.version).option("--org <idOrSlug>", "org to target for this command (overrides the active org)");
1189
+ program.name("erdo").description("Erdo CLI").version(pkg.version).option("--org <idOrSlug>", "org to target for this command (overrides the active org)").option("--project <uuid>", "project context for this command (must belong to the active org)");
1154
1190
  program.hook("preAction", (thisCommand) => {
1155
- const org2 = thisCommand.opts().org;
1191
+ const opts = thisCommand.opts();
1192
+ const org2 = opts.org;
1156
1193
  if (org2) process.env.ERDO_ORG = org2;
1194
+ if (opts.project) process.env.ERDO_PROJECT = opts.project;
1157
1195
  });
1158
1196
  async function doLogin(opts) {
1159
1197
  let token;
@@ -3000,6 +3038,48 @@ List tables with: erdo integrations tables ${app} <schema>`);
3000
3038
  fail(e);
3001
3039
  }
3002
3040
  });
3041
+ var connectLinksCmd = integrationsCmd.command("connect-links").description("Generate shareable links so a third party can connect an app for you");
3042
+ connectLinksCmd.command("create <app>").description("Mint a shareable connect link for an app by slug \u2014 native (e.g. github, hubspot) or Pipedream (e.g. slack, notion); link_url is a secret").option("-n, --name <name>", "display name for the connection the recipient creates").option("--integration-id <id>", "re-authorize an existing, non-active native integration instead of creating a new one (native only)").action(async (app, opts) => {
3043
+ try {
3044
+ const res = await new ErdoClient().createConnectLink({
3045
+ app,
3046
+ name: opts.name,
3047
+ integration_id: opts.integrationId
3048
+ });
3049
+ print(res);
3050
+ process.stderr.write(
3051
+ `
3052
+ Share link_url with the person who holds the credentials. It expires ${res.expires_at} and completes once. Treat it as a secret \u2014 anyone with it can finish the connection.
3053
+ `
3054
+ );
3055
+ } catch (e) {
3056
+ fail(e);
3057
+ }
3058
+ });
3059
+ connectLinksCmd.command("list").description("List your connect links (id app status for_reauth expires_at link_url)").option("--app <app>", "filter by app slug \u2014 native (e.g. github) or Pipedream (e.g. slack)").action(async (opts) => {
3060
+ try {
3061
+ const { links } = await new ErdoClient().listConnectLinks(opts.app);
3062
+ if (links.length === 0) {
3063
+ console.log("No connect links. Create one with: erdo integrations connect-links create <app>");
3064
+ return;
3065
+ }
3066
+ for (const l of links) {
3067
+ console.log(
3068
+ `${l.id} ${l.app || "-"} ${l.status} ${l.for_reauth ? "reauth" : "new"} ${l.expires_at} ${l.link_url}`
3069
+ );
3070
+ }
3071
+ } catch (e) {
3072
+ fail(e);
3073
+ }
3074
+ });
3075
+ connectLinksCmd.command("revoke <id>").description("Revoke a pending connect link so its URL stops working").action(async (id) => {
3076
+ try {
3077
+ await new ErdoClient().revokeConnectLink(id);
3078
+ console.log(`revoked: ${id}`);
3079
+ } catch (e) {
3080
+ fail(e);
3081
+ }
3082
+ });
3003
3083
  var pipelinesCmd = program.command("event-pipelines").description("Inspect event pipelines (lead-capture / webhook flows)");
3004
3084
  pipelinesCmd.command("list").description("List event pipelines in the active org").option("-n, --limit <n>", "max rows", (v) => parseInt(v, 10)).action(async (opts) => {
3005
3085
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@erdoai/cli",
3
- "version": "0.40.2",
3
+ "version": "0.42.0",
4
4
  "description": "Erdo CLI \u2014 drive datasets, pages, and evals from the terminal or CI",
5
5
  "type": "module",
6
6
  "bin": {