@audienti/cli 0.1.51 → 0.1.53
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/CHANGELOG.md +12 -0
- package/README.md +5 -3
- package/package.json +1 -1
- package/src/api-client.js +15 -1
- package/src/cli.js +63 -7
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@ All notable changes to the Audienti CLI are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.1.53] - 2026-09-04
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Reject cross-account or conflicting Operator principal parameters through the account API, and preserve true-user privacy semantics for projected Operator reads.
|
|
12
|
+
|
|
13
|
+
## [0.1.52] - 2026-09-03
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- Add direct, server-normalized `inbox-ops rule set` and `inbox-ops rule remove` commands for sender and domain rules while retaining authorized row-derived updates.
|
|
18
|
+
|
|
7
19
|
## [0.1.51] - 2026-09-03
|
|
8
20
|
|
|
9
21
|
### Added
|
package/README.md
CHANGED
|
@@ -215,17 +215,19 @@ audienti operator next --done --note "Connection request sent."
|
|
|
215
215
|
```
|
|
216
216
|
|
|
217
217
|
Inbox Ops has its own owner-scoped CLI surface. Queue rows expose the stable row
|
|
218
|
-
id used by the rule command
|
|
219
|
-
server
|
|
218
|
+
id used by the row-based rule command. Rules can also be set or removed directly
|
|
219
|
+
by sender or domain; the server normalizes and validates every supplied key:
|
|
220
220
|
|
|
221
221
|
```bash
|
|
222
222
|
audienti inbox-ops queue [--page <n>]
|
|
223
223
|
audienti inbox-ops filters
|
|
224
224
|
audienti inbox-ops rule <row_id> --scope sender --disposition filter
|
|
225
225
|
audienti inbox-ops rule <row_id> --scope domain --disposition allow
|
|
226
|
+
audienti inbox-ops rule set --scope sender --key news@example.com --disposition filter
|
|
227
|
+
audienti inbox-ops rule remove --scope domain --key example.com
|
|
226
228
|
```
|
|
227
229
|
|
|
228
|
-
The
|
|
230
|
+
The rule commands mirror the Operator card actions. They update only
|
|
229
231
|
the authenticated owner's personal/global Inbox Ops preferences and do not
|
|
230
232
|
archive mail, call the provider, or add a DNC entry.
|
|
231
233
|
|
package/package.json
CHANGED
package/src/api-client.js
CHANGED
|
@@ -668,6 +668,20 @@ export class AudientiClient {
|
|
|
668
668
|
});
|
|
669
669
|
}
|
|
670
670
|
|
|
671
|
+
setInboxOpsRule(accountId, body) {
|
|
672
|
+
return this.requestJson(accountPath(accountId, ["inbox_ops", "rules"]), {
|
|
673
|
+
method: "PATCH",
|
|
674
|
+
body
|
|
675
|
+
});
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
removeInboxOpsRule(accountId, body) {
|
|
679
|
+
return this.requestJson(accountPath(accountId, ["inbox_ops", "rules"]), {
|
|
680
|
+
method: "DELETE",
|
|
681
|
+
body
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
|
|
671
685
|
operatorNext(accountId, query = {}) {
|
|
672
686
|
return this.requestJson(accountPath(accountId, ["operator", "next"], query));
|
|
673
687
|
}
|
|
@@ -823,7 +837,7 @@ function errorMessage(status, body) {
|
|
|
823
837
|
|
|
824
838
|
if (status === 422) {
|
|
825
839
|
const reasons = [body?.errors, body?.details].find(Array.isArray);
|
|
826
|
-
const details = reasons?.length > 0 ? reasons.join(", ") : body?.error;
|
|
840
|
+
const details = reasons?.length > 0 ? reasons.join(", ") : body?.message || body?.error;
|
|
827
841
|
return details ? `Audienti rejected the request: ${details}` : "Audienti rejected the request.";
|
|
828
842
|
}
|
|
829
843
|
|
package/src/cli.js
CHANGED
|
@@ -68,6 +68,8 @@ const OPERATOR_FAILED_DRAFTS_REQUEUE_USAGE = "Usage: audienti operator failed-dr
|
|
|
68
68
|
const INBOX_OPS_QUEUE_USAGE = "Usage: audienti inbox-ops queue [--page <n>] [--json] [--account <acct_id>]";
|
|
69
69
|
const INBOX_OPS_FILTERS_USAGE = "Usage: audienti inbox-ops filters [--json] [--account <acct_id>]";
|
|
70
70
|
const INBOX_OPS_RULE_USAGE = "Usage: audienti inbox-ops rule <row_id> --scope <sender|domain> --disposition <allow|filter> [--json] [--account <acct_id>]";
|
|
71
|
+
const INBOX_OPS_RULE_SET_USAGE = "Usage: audienti inbox-ops rule set --scope <sender|domain> --key <email|domain> --disposition <allow|filter> [--json] [--account <acct_id>]";
|
|
72
|
+
const INBOX_OPS_RULE_REMOVE_USAGE = "Usage: audienti inbox-ops rule remove --scope <sender|domain> --key <email|domain> [--json] [--account <acct_id>]";
|
|
71
73
|
const INBOX_OPS_ROW_ID_PATTERN = /^inbox_ops_message_[1-9]\d*$/;
|
|
72
74
|
const DNC_ADD_USAGE = "Usage: audienti dnc add <email|citation_id|profile_url> [--json] [--account <acct_id>]";
|
|
73
75
|
const DNC_IMPORT_USAGE = "Usage: audienti dnc import --file <txt|csv> [--json] [--account <acct_id>]";
|
|
@@ -3251,6 +3253,10 @@ async function inboxOpsFilters(args, context, { accountOverride } = {}) {
|
|
|
3251
3253
|
}
|
|
3252
3254
|
|
|
3253
3255
|
async function inboxOpsRule(args, context, { accountOverride } = {}) {
|
|
3256
|
+
if (args[0] === "set" || args[0] === "remove") {
|
|
3257
|
+
return inboxOpsRuleKeyMutation(args[0], args.slice(1), context, { accountOverride });
|
|
3258
|
+
}
|
|
3259
|
+
|
|
3254
3260
|
const { values, positionals } = parseCommandArgs(args, {
|
|
3255
3261
|
...jsonOptions(),
|
|
3256
3262
|
scope: { type: "string" },
|
|
@@ -3275,6 +3281,38 @@ async function inboxOpsRule(args, context, { accountOverride } = {}) {
|
|
|
3275
3281
|
renderInboxOpsRule(payload, context);
|
|
3276
3282
|
}
|
|
3277
3283
|
|
|
3284
|
+
async function inboxOpsRuleKeyMutation(action, args, context, { accountOverride } = {}) {
|
|
3285
|
+
const usage = action === "set" ? INBOX_OPS_RULE_SET_USAGE : INBOX_OPS_RULE_REMOVE_USAGE;
|
|
3286
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
3287
|
+
...jsonOptions(),
|
|
3288
|
+
scope: { type: "string" },
|
|
3289
|
+
key: { type: "string" },
|
|
3290
|
+
disposition: { type: "string" }
|
|
3291
|
+
});
|
|
3292
|
+
if (positionals.length > 0) throw new CommandError(usage);
|
|
3293
|
+
if (!["sender", "domain"].includes(values.scope)) throw new CommandError("--scope must be sender or domain.");
|
|
3294
|
+
if (!String(values.key || "").trim()) throw new CommandError("--key is required.");
|
|
3295
|
+
if (action === "set" && !["allow", "filter"].includes(values.disposition)) {
|
|
3296
|
+
throw new CommandError("--disposition must be allow or filter.");
|
|
3297
|
+
}
|
|
3298
|
+
if (action === "remove" && values.disposition) {
|
|
3299
|
+
throw new CommandError("inbox-ops rule remove does not accept --disposition.");
|
|
3300
|
+
}
|
|
3301
|
+
|
|
3302
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
3303
|
+
const body = compactObject({
|
|
3304
|
+
scope: values.scope,
|
|
3305
|
+
key: values.key,
|
|
3306
|
+
disposition: action === "set" ? values.disposition : undefined
|
|
3307
|
+
});
|
|
3308
|
+
const payload = action === "set"
|
|
3309
|
+
? await client.setInboxOpsRule(accountId, body)
|
|
3310
|
+
: await client.removeInboxOpsRule(accountId, body);
|
|
3311
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
3312
|
+
|
|
3313
|
+
renderInboxOpsRule(payload, context);
|
|
3314
|
+
}
|
|
3315
|
+
|
|
3278
3316
|
async function operatorFailedDrafts(args, context, { accountOverride } = {}) {
|
|
3279
3317
|
if (args[0] === "requeue") {
|
|
3280
3318
|
return operatorFailedDraftsRequeue(args.slice(1), context, { accountOverride });
|
|
@@ -6252,6 +6290,11 @@ function writeInboxOpsRules(context, heading, rules) {
|
|
|
6252
6290
|
|
|
6253
6291
|
function renderInboxOpsRule(payload, context) {
|
|
6254
6292
|
const rule = payload?.rule || {};
|
|
6293
|
+
if (rule.action === "remove") {
|
|
6294
|
+
writeLine(context.stdout, `Removed ${display(rule.scope)} rule ${display(rule.normalized_key)}.`);
|
|
6295
|
+
return writeLine(context.stdout, "Re-run `audienti inbox-ops queue` to inspect the current queue.");
|
|
6296
|
+
}
|
|
6297
|
+
|
|
6255
6298
|
const action = rule.disposition === "allow" ? "Always showing" : "Always filtering";
|
|
6256
6299
|
writeLine(context.stdout, `${action} ${display(rule.scope)} ${display(rule.normalized_key)}.`);
|
|
6257
6300
|
writeLine(context.stdout, "Re-run `audienti inbox-ops queue` to inspect the current queue.");
|
|
@@ -10443,15 +10486,17 @@ const HELP_TOPICS = new Map([
|
|
|
10443
10486
|
` ${INBOX_OPS_QUEUE_USAGE.slice("Usage: ".length)}`,
|
|
10444
10487
|
` ${INBOX_OPS_FILTERS_USAGE.slice("Usage: ".length)}`,
|
|
10445
10488
|
` ${INBOX_OPS_RULE_USAGE.slice("Usage: ".length)}`,
|
|
10489
|
+
` ${INBOX_OPS_RULE_SET_USAGE.slice("Usage: ".length)}`,
|
|
10490
|
+
` ${INBOX_OPS_RULE_REMOVE_USAGE.slice("Usage: ".length)}`,
|
|
10446
10491
|
"",
|
|
10447
10492
|
"Status: implemented",
|
|
10448
10493
|
"",
|
|
10449
10494
|
"Purpose:",
|
|
10450
|
-
" Inspect the authenticated owner's private Inbox Ops queue and personal/global email rules, then set
|
|
10495
|
+
" Inspect the authenticated owner's private Inbox Ops queue and personal/global email rules, then set or remove sender and domain rules.",
|
|
10451
10496
|
"",
|
|
10452
10497
|
"Safety:",
|
|
10453
|
-
" Rules always apply to the token owner.
|
|
10454
|
-
"
|
|
10498
|
+
" Rules always apply to the token owner. Row-based updates derive identity from an authorized current Inbox Ops row.",
|
|
10499
|
+
" Key-based set/remove commands normalize and validate the supplied sender or domain on the server.",
|
|
10455
10500
|
"",
|
|
10456
10501
|
"Rule values:",
|
|
10457
10502
|
" --scope sender|domain",
|
|
@@ -10460,7 +10505,8 @@ const HELP_TOPICS = new Map([
|
|
|
10460
10505
|
"API:",
|
|
10461
10506
|
" queue: GET /api/v1/accounts/:account_id/operator.json?opportunity_kind=inbox",
|
|
10462
10507
|
" filters: GET /api/v1/accounts/:account_id/inbox_ops/filters.json",
|
|
10463
|
-
" rule: PATCH /api/v1/accounts/:account_id/inbox_ops/:row_id/rule.json"
|
|
10508
|
+
" rule: PATCH /api/v1/accounts/:account_id/inbox_ops/:row_id/rule.json",
|
|
10509
|
+
" keyed rules: PATCH|DELETE /api/v1/accounts/:account_id/inbox_ops/rules.json"
|
|
10464
10510
|
].join("\n")],
|
|
10465
10511
|
|
|
10466
10512
|
["inbox-ops queue", [
|
|
@@ -10489,19 +10535,27 @@ const HELP_TOPICS = new Map([
|
|
|
10489
10535
|
].join("\n")],
|
|
10490
10536
|
|
|
10491
10537
|
["inbox-ops rule", [
|
|
10492
|
-
|
|
10538
|
+
"Usage:",
|
|
10539
|
+
` ${INBOX_OPS_RULE_USAGE.slice("Usage: ".length)}`,
|
|
10540
|
+
` ${INBOX_OPS_RULE_SET_USAGE.slice("Usage: ".length)}`,
|
|
10541
|
+
` ${INBOX_OPS_RULE_REMOVE_USAGE.slice("Usage: ".length)}`,
|
|
10493
10542
|
"",
|
|
10494
10543
|
"Status: implemented",
|
|
10495
10544
|
"",
|
|
10496
10545
|
"Purpose:",
|
|
10497
|
-
" Set one allow or filter rule from an authorized current Inbox Ops row
|
|
10546
|
+
" Set one allow or filter rule from an authorized current Inbox Ops row, or set/remove a normalized rule by key.",
|
|
10547
|
+
"",
|
|
10548
|
+
"Safety:",
|
|
10549
|
+
" The server derives row-based identities and normalizes and validates direct sender/domain keys.",
|
|
10550
|
+
" Every mutation applies only to the authenticated token owner's personal/global preferences.",
|
|
10498
10551
|
"",
|
|
10499
10552
|
"Rule values:",
|
|
10500
10553
|
" --scope sender|domain",
|
|
10501
10554
|
" --disposition allow|filter",
|
|
10502
10555
|
"",
|
|
10503
10556
|
"API:",
|
|
10504
|
-
" PATCH /api/v1/accounts/:account_id/inbox_ops/:row_id/rule.json"
|
|
10557
|
+
" row: PATCH /api/v1/accounts/:account_id/inbox_ops/:row_id/rule.json",
|
|
10558
|
+
" key: PATCH|DELETE /api/v1/accounts/:account_id/inbox_ops/rules.json"
|
|
10505
10559
|
].join("\n")],
|
|
10506
10560
|
|
|
10507
10561
|
["operator", [
|
|
@@ -11034,6 +11088,8 @@ const HELP_TOPICS = new Map([
|
|
|
11034
11088
|
" audienti inbox-ops queue",
|
|
11035
11089
|
" audienti inbox-ops filters",
|
|
11036
11090
|
" audienti inbox-ops rule <row_id> --scope sender --disposition filter",
|
|
11091
|
+
" audienti inbox-ops rule set --scope sender --key news@example.com --disposition filter",
|
|
11092
|
+
" audienti inbox-ops rule remove --scope domain --key example.com",
|
|
11037
11093
|
"",
|
|
11038
11094
|
"7. Inspect account analytics",
|
|
11039
11095
|
" audienti users activity me --window 7d",
|