@erdoai/cli 0.140.2 → 0.141.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 +42 -13
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2193,6 +2193,40 @@ async function promptLine(question) {
|
|
|
2193
2193
|
}
|
|
2194
2194
|
}
|
|
2195
2195
|
|
|
2196
|
+
// src/integration-credential-input.ts
|
|
2197
|
+
var PROMPT_FIELD = /^[A-Za-z0-9_.-]+$/;
|
|
2198
|
+
async function resolveIntegrationCredentials(options) {
|
|
2199
|
+
if (options.fromConnection && (options.credentialArgs.length || options.promptFields.length)) {
|
|
2200
|
+
throw new Error("pass either credentials or --from-connection, not both \u2014 otherwise the connection would hold a credential you did not choose");
|
|
2201
|
+
}
|
|
2202
|
+
if (options.promptFields.length && !options.interactive) {
|
|
2203
|
+
throw new Error("--prompt-credential requires both standard input and standard output to be terminals");
|
|
2204
|
+
}
|
|
2205
|
+
const credentials = /* @__PURE__ */ new Map();
|
|
2206
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2207
|
+
const claim = (field) => {
|
|
2208
|
+
if (seen.has(field)) throw new Error("duplicate credential field");
|
|
2209
|
+
seen.add(field);
|
|
2210
|
+
};
|
|
2211
|
+
for (const value of options.credentialArgs) {
|
|
2212
|
+
const separator = value.indexOf("=");
|
|
2213
|
+
if (separator < 1) throw new Error("invalid --credential; expected key=value");
|
|
2214
|
+
const field = value.slice(0, separator);
|
|
2215
|
+
claim(field);
|
|
2216
|
+
credentials.set(field, value.slice(separator + 1));
|
|
2217
|
+
}
|
|
2218
|
+
for (const field of options.promptFields) {
|
|
2219
|
+
if (!PROMPT_FIELD.test(field)) throw new Error("prompt credential field must contain only letters, digits, dots, hyphens and underscores");
|
|
2220
|
+
claim(field);
|
|
2221
|
+
}
|
|
2222
|
+
for (const field of options.promptFields) {
|
|
2223
|
+
const value = await options.prompt(field);
|
|
2224
|
+
if (!value.trim()) throw new Error("prompted credential cannot be empty");
|
|
2225
|
+
credentials.set(field, value);
|
|
2226
|
+
}
|
|
2227
|
+
return seen.size ? Object.fromEntries(credentials) : void 0;
|
|
2228
|
+
}
|
|
2229
|
+
|
|
2196
2230
|
// src/integrations.ts
|
|
2197
2231
|
function formatIntegrationListRow(i) {
|
|
2198
2232
|
const provided = i.provided_by_organization_slug ? ` provided by ${i.provided_by_organization_slug}` : "";
|
|
@@ -8590,7 +8624,7 @@ integrationsCmd.command("apps [query]").description("Search connectable apps (na
|
|
|
8590
8624
|
fail(e);
|
|
8591
8625
|
}
|
|
8592
8626
|
});
|
|
8593
|
-
integrationsCmd.command("connect <app>").description("Connect an app \u2014 pass
|
|
8627
|
+
integrationsCmd.command("connect <app>").description("Connect an app \u2014 pass credentials with -c or --prompt-credential, or omit them to get a browser connect URL for OAuth apps").option("-c, --credential <key=value...>", "credential field, e.g. -c api_key=\u2026 (repeatable); rejected by OAuth apps, which have no credential to pass", (v, acc) => acc.concat(v), []).option("--prompt-credential <field>", "prompt securely for a credential field (repeatable; interactive terminals only)", (v, acc) => acc.concat(v), []).option("-n, --name <name>", "display name for the connection").option("--rotate", "replace the credentials of the app's existing connection instead of adding a second one \u2014 for a key that was rotated at the provider; requires -c or --prompt-credential").option("--share", "share the connection with the whole organization instead of keeping it private to you \u2014 for org-level credentials teammates and agents should see").option(
|
|
8594
8628
|
"--provide-to-managed",
|
|
8595
8629
|
"let the organizations you manage use this connection as if it were their own \u2014 for a vendor key your agency pays for. Key-authenticated native integrations only, connected in a manager organization"
|
|
8596
8630
|
).option(
|
|
@@ -8598,9 +8632,6 @@ integrationsCmd.command("connect <app>").description("Connect an app \u2014 pass
|
|
|
8598
8632
|
"reuse a credential you verifiably supplied \u2014 find its connection id in column 5 of `erdo integrations list --org <that-org>`. The credential is copied inside Erdo and never shown. Legacy keys without supplier records require an authenticated credential update"
|
|
8599
8633
|
).action(async (app, opts) => {
|
|
8600
8634
|
try {
|
|
8601
|
-
if (opts.fromConnection && opts.credential.length) {
|
|
8602
|
-
fail(new Error("pass either -c or --from-connection, not both \u2014 otherwise the connection would hold a credential you did not choose"));
|
|
8603
|
-
}
|
|
8604
8635
|
if (opts.fromConnection && opts.rotate) {
|
|
8605
8636
|
fail(
|
|
8606
8637
|
new Error(
|
|
@@ -8608,15 +8639,13 @@ integrationsCmd.command("connect <app>").description("Connect an app \u2014 pass
|
|
|
8608
8639
|
)
|
|
8609
8640
|
);
|
|
8610
8641
|
}
|
|
8611
|
-
|
|
8612
|
-
|
|
8613
|
-
|
|
8614
|
-
|
|
8615
|
-
|
|
8616
|
-
|
|
8617
|
-
|
|
8618
|
-
}
|
|
8619
|
-
}
|
|
8642
|
+
const credentials = await resolveIntegrationCredentials({
|
|
8643
|
+
credentialArgs: opts.credential,
|
|
8644
|
+
fromConnection: opts.fromConnection,
|
|
8645
|
+
promptFields: opts.promptCredential,
|
|
8646
|
+
interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY),
|
|
8647
|
+
prompt: (field) => password({ message: `Credential ${field}:`, mask: "*" })
|
|
8648
|
+
});
|
|
8620
8649
|
const res = await new ErdoClient().connectIntegration({
|
|
8621
8650
|
app,
|
|
8622
8651
|
name: opts.name,
|