@erdoai/cli 0.151.1 → 0.154.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 +140 -14
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -331,6 +331,9 @@ var ErdoClient = class {
|
|
|
331
331
|
listTokens() {
|
|
332
332
|
return this.request("GET", "/v1/tokens");
|
|
333
333
|
}
|
|
334
|
+
rotateToken(id) {
|
|
335
|
+
return this.request("POST", `/v1/tokens/${encodeURIComponent(id)}/rotate`, void 0, false);
|
|
336
|
+
}
|
|
334
337
|
revokeToken(id) {
|
|
335
338
|
return this.request("DELETE", `/v1/tokens/${encodeURIComponent(id)}`);
|
|
336
339
|
}
|
|
@@ -1261,6 +1264,33 @@ var ErdoClient = class {
|
|
|
1261
1264
|
setDatasetRowAction(input) {
|
|
1262
1265
|
return this.request("PUT", "/v1/dataset-row-actions", input, false);
|
|
1263
1266
|
}
|
|
1267
|
+
listProviderLeadSources(opts) {
|
|
1268
|
+
const q = new URLSearchParams();
|
|
1269
|
+
if (opts?.provider) q.set("provider", opts.provider);
|
|
1270
|
+
if (opts?.account_id) q.set("account_id", opts.account_id);
|
|
1271
|
+
const qs = q.toString();
|
|
1272
|
+
return this.request(
|
|
1273
|
+
"GET",
|
|
1274
|
+
`/v1/provider-lead-sources${qs ? `?${qs}` : ""}`
|
|
1275
|
+
);
|
|
1276
|
+
}
|
|
1277
|
+
listProviderLeadSourceForms(connectionId, accountId) {
|
|
1278
|
+
const q = new URLSearchParams({ connection_id: connectionId, account_id: accountId });
|
|
1279
|
+
return this.request(
|
|
1280
|
+
"GET",
|
|
1281
|
+
`/v1/provider-lead-sources/forms?${q.toString()}`
|
|
1282
|
+
);
|
|
1283
|
+
}
|
|
1284
|
+
setProviderLeadSource(input) {
|
|
1285
|
+
return this.request("PUT", "/v1/provider-lead-sources", input, false);
|
|
1286
|
+
}
|
|
1287
|
+
deleteProviderLeadSource(provider, accountId) {
|
|
1288
|
+
const q = new URLSearchParams({ provider, account_id: accountId });
|
|
1289
|
+
return this.request(
|
|
1290
|
+
"DELETE",
|
|
1291
|
+
`/v1/provider-lead-sources?${q.toString()}`
|
|
1292
|
+
);
|
|
1293
|
+
}
|
|
1264
1294
|
listDatasetUserPermissions(slug) {
|
|
1265
1295
|
return this.request("GET", `/v1/datasets/${encodeURIComponent(slug)}/permissions/users`);
|
|
1266
1296
|
}
|
|
@@ -3321,6 +3351,25 @@ ${res.from} to ${res.to} (${res.timezone} days)
|
|
|
3321
3351
|
}
|
|
3322
3352
|
);
|
|
3323
3353
|
var tokenCmd = program.command("token").description("Manage your API tokens (account-level credentials)");
|
|
3354
|
+
function printNewToken(res, replacedTokenID) {
|
|
3355
|
+
process.stderr.write("Store this token now \u2014 it is shown only once and cannot be retrieved again.\n");
|
|
3356
|
+
console.log(res.token);
|
|
3357
|
+
const scoped = res.is_scoped === true || res.capabilities !== void 0;
|
|
3358
|
+
const scopeDetails = scoped ? `capabilities: ${res.capabilities?.join(", ") || "(none)"}
|
|
3359
|
+
resource slugs: ${res.resource_slugs?.join(", ") || "(none)"}
|
|
3360
|
+
` : "";
|
|
3361
|
+
const scopeDescription = scoped ? "This token is pinned to the default org above and can use only its listed capabilities; resource restrictions apply when slugs are listed.\n" : res.access === "read" ? "This token can read as you in any org you belong to and cannot change anything; pass --org on a command to target another.\n" : "This token acts as you in any org you belong to; pass --org on a command to target another.\n";
|
|
3362
|
+
process.stderr.write(
|
|
3363
|
+
`
|
|
3364
|
+
id: ${res.id}
|
|
3365
|
+
hint: ${res.hint}
|
|
3366
|
+
expires: ${res.expires_at}
|
|
3367
|
+
default org: ${res.default_org ? `${res.default_org.name} (${res.default_org.id})` : "(none)"}
|
|
3368
|
+
access: ${res.access ?? "full"}
|
|
3369
|
+
` + scopeDetails + (replacedTokenID ? `replaced token id: ${replacedTokenID}
|
|
3370
|
+
` : "") + scopeDescription
|
|
3371
|
+
);
|
|
3372
|
+
}
|
|
3324
3373
|
tokenCmd.command("create").description("Mint a new API token; the secret is printed ONCE").requiredOption("--name <name>", "a label for the token").option("--expires-days <n>", "days until expiry (default: 30)", (v) => parseInt(v, 10)).option("--read-only", "mint a read-only token: it can read through the API in any org you belong to, and never write").addOption(
|
|
3325
3374
|
orgOption("the token's default org (defaults to your active org; must be one you belong to)")
|
|
3326
3375
|
).action(async (opts) => {
|
|
@@ -3331,19 +3380,37 @@ tokenCmd.command("create").description("Mint a new API token; the secret is prin
|
|
|
3331
3380
|
organization_id: opts.org,
|
|
3332
3381
|
...opts.readOnly ? { access: "read" } : {}
|
|
3333
3382
|
});
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
);
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3383
|
+
printNewToken(res);
|
|
3384
|
+
} catch (e) {
|
|
3385
|
+
fail(e);
|
|
3386
|
+
}
|
|
3387
|
+
});
|
|
3388
|
+
tokenCmd.command("rotate <id>").description("Replace an API token; the replacement secret is printed ONCE").option("--update-login", "save the new secret when the rotated token is the active account's credential").action(async (id, opts) => {
|
|
3389
|
+
try {
|
|
3390
|
+
let accountKey;
|
|
3391
|
+
let savedToken;
|
|
3392
|
+
if (opts.updateLogin) {
|
|
3393
|
+
const file = loadConfigFile();
|
|
3394
|
+
accountKey = file ? activeAccountKey(file) : void 0;
|
|
3395
|
+
const saved = accountKey ? file?.accounts[accountKey] : void 0;
|
|
3396
|
+
if (!saved?.token) throw new Error("No active saved login to update. Run: erdo auth login");
|
|
3397
|
+
savedToken = saved.token;
|
|
3398
|
+
const me = await fetchMe(saved.token);
|
|
3399
|
+
if (!me.credential_id || me.credential_id !== id) {
|
|
3400
|
+
throw new Error("--update-login requires the rotated token id to match the active saved login's credential id");
|
|
3401
|
+
}
|
|
3402
|
+
}
|
|
3403
|
+
const res = await new ErdoClient().rotateToken(id);
|
|
3404
|
+
printNewToken(res, res.replaced_token_id);
|
|
3405
|
+
if (accountKey) {
|
|
3406
|
+
const current = loadConfigFile();
|
|
3407
|
+
if (!current || activeAccountKey(current) !== accountKey || current.accounts[accountKey]?.token !== savedToken) {
|
|
3408
|
+
throw new Error("Rotation succeeded and the replacement secret was printed above, but the active saved login changed during the request and was not overwritten. Save the new key with erdo login --key if needed");
|
|
3409
|
+
}
|
|
3410
|
+
saveAccount(accountKey, { token: res.token }, false);
|
|
3411
|
+
process.stderr.write(`Updated saved login for ${accountKey}.
|
|
3412
|
+
`);
|
|
3413
|
+
}
|
|
3347
3414
|
} catch (e) {
|
|
3348
3415
|
fail(e);
|
|
3349
3416
|
}
|
|
@@ -3358,7 +3425,7 @@ tokenCmd.command("list").description("List your API tokens (never shows the secr
|
|
|
3358
3425
|
for (const t of tokens) {
|
|
3359
3426
|
const org2 = t.default_org ? t.default_org.name || t.default_org.id : "-";
|
|
3360
3427
|
const used = t.last_used_at ?? "never";
|
|
3361
|
-
console.log(`${t.id} ${t.name || "-"} ${t.hint} access:${t.access ?? "full"} default-org:${org2} expires:${t.expires_at} used:${used}`);
|
|
3428
|
+
console.log(`${t.id} ${t.name || "-"} ${t.hint} access:${t.access ?? "full"} default-org:${org2} expires:${t.expires_at} last-used:${used}`);
|
|
3362
3429
|
}
|
|
3363
3430
|
} catch (e) {
|
|
3364
3431
|
fail(e);
|
|
@@ -7276,6 +7343,65 @@ voiceAgentsCmd.command("whatsapp-replies <slug>").description("Turn a voice agen
|
|
|
7276
7343
|
}
|
|
7277
7344
|
});
|
|
7278
7345
|
var datasetsCmd = program.command("datasets").description("Datasets");
|
|
7346
|
+
var providerLeadSourcesCmd = program.command("provider-lead-sources").description("Ingest ad-platform lead form responses into a lead dataset");
|
|
7347
|
+
providerLeadSourcesCmd.command("list").description("List LinkedIn lead form source declarations").option("--provider <provider>", "filter by ad platform provider").option("--account-id <id>", "filter by provider ad account id").action(async (opts) => {
|
|
7348
|
+
try {
|
|
7349
|
+
print(await new ErdoClient().listProviderLeadSources({ provider: opts.provider, account_id: opts.accountId }));
|
|
7350
|
+
} catch (e) {
|
|
7351
|
+
fail(e);
|
|
7352
|
+
}
|
|
7353
|
+
});
|
|
7354
|
+
providerLeadSourcesCmd.command("forms").description("List LinkedIn lead forms available on a connected ad account").requiredOption("--connection-id <id>", "LinkedIn Ads connector account id from /connectors/my-connections").requiredOption("--account-id <id>", "numeric LinkedIn ad account id").action(async (opts) => {
|
|
7355
|
+
try {
|
|
7356
|
+
print(await new ErdoClient().listProviderLeadSourceForms(opts.connectionId, opts.accountId));
|
|
7357
|
+
} catch (e) {
|
|
7358
|
+
fail(e);
|
|
7359
|
+
}
|
|
7360
|
+
});
|
|
7361
|
+
providerLeadSourcesCmd.command("set").description("Replace a provider lead form source declaration from JSON or flags").option("-f, --file <path>", "one JSON declaration object; use - to read from stdin").option("--dataset <slug>", "lead dataset slug").option("--provider <provider>", "ad platform provider", "linkedin_ads").option("--connection-id <id>", "LinkedIn Ads connector account id from /connectors/my-connections").option("--account-id <id>", "numeric LinkedIn ad account id").option("--form <id>", "LinkedIn lead gen form id (repeatable)", collect, []).option("--disabled", "save the declaration disabled").action(async (opts) => {
|
|
7362
|
+
try {
|
|
7363
|
+
let input;
|
|
7364
|
+
if (opts.file) {
|
|
7365
|
+
input = await readJSONInput(opts.file, "--file");
|
|
7366
|
+
} else {
|
|
7367
|
+
input = {
|
|
7368
|
+
dataset: opts.dataset,
|
|
7369
|
+
provider: opts.provider,
|
|
7370
|
+
connection_id: opts.connectionId,
|
|
7371
|
+
account_id: opts.accountId,
|
|
7372
|
+
forms: opts.form,
|
|
7373
|
+
...opts.disabled ? { enabled: false } : {}
|
|
7374
|
+
};
|
|
7375
|
+
}
|
|
7376
|
+
const dataset = typeof input.dataset === "string" ? input.dataset.trim() : "";
|
|
7377
|
+
const provider = typeof input.provider === "string" ? input.provider.trim() : "";
|
|
7378
|
+
const connectionID = typeof input.connection_id === "string" ? input.connection_id.trim() : "";
|
|
7379
|
+
const accountID = typeof input.account_id === "string" ? input.account_id.trim() : "";
|
|
7380
|
+
const forms = Array.isArray(input.forms) ? input.forms.filter((form) => typeof form === "string" && form.trim().length > 0) : [];
|
|
7381
|
+
if (!dataset) throw new Error("dataset must be a non-empty string");
|
|
7382
|
+
if (!provider) throw new Error("provider must be a non-empty string");
|
|
7383
|
+
if (!connectionID) throw new Error("connection_id must be a non-empty string");
|
|
7384
|
+
if (!accountID) throw new Error("account_id must be a non-empty string");
|
|
7385
|
+
if (forms.length === 0) throw new Error("forms must contain at least one form");
|
|
7386
|
+
print(await new ErdoClient().setProviderLeadSource({
|
|
7387
|
+
...input,
|
|
7388
|
+
dataset,
|
|
7389
|
+
provider,
|
|
7390
|
+
connection_id: connectionID,
|
|
7391
|
+
account_id: accountID,
|
|
7392
|
+
forms
|
|
7393
|
+
}));
|
|
7394
|
+
} catch (e) {
|
|
7395
|
+
fail(e);
|
|
7396
|
+
}
|
|
7397
|
+
});
|
|
7398
|
+
providerLeadSourcesCmd.command("delete").description("Delete a provider lead form source declaration").option("--provider <provider>", "ad platform provider", "linkedin_ads").requiredOption("--account-id <id>", "numeric provider ad account id").action(async (opts) => {
|
|
7399
|
+
try {
|
|
7400
|
+
print(await new ErdoClient().deleteProviderLeadSource(opts.provider, opts.accountId));
|
|
7401
|
+
} catch (e) {
|
|
7402
|
+
fail(e);
|
|
7403
|
+
}
|
|
7404
|
+
});
|
|
7279
7405
|
var datasetRowActionsCmd = datasetsCmd.command("row-actions").description("Read and replace actions for arriving or excluded dataset rows");
|
|
7280
7406
|
datasetRowActionsCmd.command("get <slug>").description("Read the row-action declarations and optional bounded diagnostics for a dataset").option("--include-receipts", "include bounded provider receipt diagnostics").option("--include-unresolved", "include bounded unresolved lookup diagnostics").action(async (slug, opts) => {
|
|
7281
7407
|
try {
|