@chainpatrol/cli 0.21.0 → 0.23.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/CHANGELOG.md +13 -0
- package/dist/{breakdown-3LJBT3JQ.js → breakdown-XA6UUD3T.js} +1 -1
- package/dist/{check-G64UQCEL.js → check-NQZPNAUF.js} +1 -1
- package/dist/{chunk-2JZAPTY6.js → chunk-DVNTYW7L.js} +1 -1
- package/dist/{chunk-O7TMOF4W.js → chunk-GOQL7UCG.js} +3 -0
- package/dist/{chunk-4N2YKTJ5.js → chunk-LKITFBIG.js} +81 -6
- package/dist/cli.js +91 -43
- package/dist/{configs-update-MVX7Q5NW.js → configs-update-VDZVBTIF.js} +1 -1
- package/dist/{create-ANCO4FXB.js → create-DGCWT2YJ.js} +1 -1
- package/dist/{drift-SHPMEJDU.js → drift-YZHCIQ5O.js} +1 -1
- package/dist/{found-OPL4HWOW.js → found-6JAOLM6M.js} +1 -1
- package/dist/{get-XN752KSL.js → get-RC75EJFC.js} +25 -3
- package/dist/{healthcheck-QNLFKAXM.js → healthcheck-7YWSOY6Y.js} +1 -1
- package/dist/{list-X4Z3CPO7.js → list-4HX2R7HU.js} +1 -1
- package/dist/{list-XSIXAHOG.js → list-4KIZLIVN.js} +1 -1
- package/dist/{list-AQ7E23T3.js → list-EJDWUF6W.js} +1 -1
- package/dist/{list-WPPNX7G3.js → list-H7NVUX42.js} +1 -1
- package/dist/{list-FJBWSGTD.js → list-IDR7WH5J.js} +2 -2
- package/dist/{list-SWHKM5R6.js → list-Q3MMBL4Y.js} +1 -1
- package/dist/{list-MHICJ2TK.js → list-SRVNEUHC.js} +57 -5
- package/dist/{list-FVFF4VW3.js → list-UDT5MDQZ.js} +1 -1
- package/dist/{list-QHEFB4KE.js → list-WQFDRXHD.js} +1 -1
- package/dist/{list-Q5PRMAN5.js → list-YNQ6VSYV.js} +1 -1
- package/dist/{list-4VKMEKZS.js → list-ZARZ72DG.js} +1 -1
- package/dist/{list-FWXQUOCP.js → list-ZBC53OYA.js} +1 -1
- package/dist/{list-json-B5L5PXKH.js → list-json-7FDHNRYP.js} +1 -1
- package/dist/{organization-SOMHMGTM.js → organization-NEZA6JX2.js} +1 -1
- package/dist/{run-J5TQ2YC2.js → run-5QV3YD7V.js} +1 -1
- package/dist/{run-RV6P2OCD.js → run-CCVJIK7L.js} +1 -1
- package/dist/{run-YAAMSWKK.js → run-JLTNFOJK.js} +2 -2
- package/dist/{search-FQUR75WR.js → search-JXJLBV43.js} +1 -1
- package/dist/search-ZXTJPVM6.js +221 -0
- package/dist/{setup-skill-UEOROLCF.js → setup-skill-V3HDWN7T.js} +1 -1
- package/dist/{snapshot-2GDJMN3L.js → snapshot-NYOLPGRW.js} +1 -1
- package/dist/{summary-LF53KXRR.js → summary-FE6ROSOO.js} +1 -1
- package/dist/{types-PTMFLYUV.js → types-M6QMFNUS.js} +2 -1
- package/dist/{validate-UYKOMUEI.js → validate-RPQEEQ36.js} +1 -1
- package/dist/{whoami-OYOG63BX.js → whoami-ZIWZCBGI.js} +1 -1
- package/package.json +1 -1
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "./chunk-VFT3TD3E.js";
|
|
9
9
|
import {
|
|
10
10
|
createApiClient
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-GOQL7UCG.js";
|
|
12
12
|
import "./chunk-EGWK6SRQ.js";
|
|
13
13
|
import "./chunk-TFCNKBRC.js";
|
|
14
14
|
import "./chunk-U73SABXK.js";
|
|
@@ -31,6 +31,13 @@ function summarizeObligatoryAdminApproval(org) {
|
|
|
31
31
|
const types = org.obligatoryAdminApproval.assetTypes;
|
|
32
32
|
return types.length === 0 ? "on (all asset types)" : `on (${types.join(", ")})`;
|
|
33
33
|
}
|
|
34
|
+
function summarizePendingApprovals(org) {
|
|
35
|
+
if (org.pendingServiceApprovals.length === 0) return "none";
|
|
36
|
+
const labels = Array.from(
|
|
37
|
+
new Set(org.pendingServiceApprovals.map((approval) => approval.serviceName))
|
|
38
|
+
);
|
|
39
|
+
return labels.join(", ");
|
|
40
|
+
}
|
|
34
41
|
async function runOrgsGet(options) {
|
|
35
42
|
const slug = options.slug?.trim();
|
|
36
43
|
if (!slug) {
|
|
@@ -49,14 +56,17 @@ async function runOrgsGet(options) {
|
|
|
49
56
|
markdown: [
|
|
50
57
|
`# ${organization.name} (\`${organization.slug}\`)`,
|
|
51
58
|
"",
|
|
59
|
+
`- Contact URL: ${organization.contactUrl ?? "(not set)"}`,
|
|
52
60
|
`- Subscription status: ${organization.subscriptionStatus}`,
|
|
53
61
|
`- Services: ${summarizeServices(organization)}`,
|
|
54
|
-
`- Obligatory admin approval: ${summarizeObligatoryAdminApproval(organization)}
|
|
62
|
+
`- Obligatory admin approval: ${summarizeObligatoryAdminApproval(organization)}`,
|
|
63
|
+
`- Pending service approvals: ${summarizePendingApprovals(organization)}`
|
|
55
64
|
].join("\n"),
|
|
56
65
|
csv: toCsvRows([
|
|
57
66
|
{
|
|
58
67
|
slug: organization.slug,
|
|
59
68
|
name: organization.name,
|
|
69
|
+
contactUrl: organization.contactUrl ?? "",
|
|
60
70
|
subscriptionStatus: organization.subscriptionStatus,
|
|
61
71
|
reportingActive: organization.services.reporting.active,
|
|
62
72
|
reviewingActive: organization.services.reviewing.active,
|
|
@@ -69,16 +79,28 @@ async function runOrgsGet(options) {
|
|
|
69
79
|
obligatoryAdminApprovalActive: organization.obligatoryAdminApproval.active,
|
|
70
80
|
// Empty list + active=true means "applies to all asset types" — read
|
|
71
81
|
// the active column alongside this one to interpret.
|
|
72
|
-
obligatoryAdminApprovalAssetTypes: organization.obligatoryAdminApproval.assetTypes.join("|")
|
|
82
|
+
obligatoryAdminApprovalAssetTypes: organization.obligatoryAdminApproval.assetTypes.join("|"),
|
|
83
|
+
// Pending staff requests to enable Wallet Blocking / Takedowns that a
|
|
84
|
+
// higher-up has not yet approved. Raw `serviceType` enum values,
|
|
85
|
+
// de-duplicated; an empty cell means nothing is awaiting approval.
|
|
86
|
+
pendingServiceApprovals: Array.from(
|
|
87
|
+
new Set(
|
|
88
|
+
organization.pendingServiceApprovals.map((approval) => approval.serviceType)
|
|
89
|
+
)
|
|
90
|
+
).join("|")
|
|
73
91
|
}
|
|
74
92
|
]),
|
|
75
93
|
human: () => {
|
|
76
94
|
console.log(`${organization.name} (slug: ${organization.slug})`);
|
|
95
|
+
console.log(` contactUrl: ${organization.contactUrl ?? "(not set)"}`);
|
|
77
96
|
console.log(` subscriptionStatus: ${organization.subscriptionStatus}`);
|
|
78
97
|
console.log(` services: ${summarizeServices(organization)}`);
|
|
79
98
|
console.log(
|
|
80
99
|
` obligatoryAdminApproval: ${summarizeObligatoryAdminApproval(organization)}`
|
|
81
100
|
);
|
|
101
|
+
console.log(
|
|
102
|
+
` pendingServiceApprovals: ${summarizePendingApprovals(organization)}`
|
|
103
|
+
);
|
|
82
104
|
}
|
|
83
105
|
});
|
|
84
106
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PRESETS
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-DVNTYW7L.js";
|
|
4
4
|
import "./chunk-E2LAMILJ.js";
|
|
5
5
|
import {
|
|
6
6
|
printOutput,
|
|
7
7
|
toCsvRows
|
|
8
8
|
} from "./chunk-VFT3TD3E.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-GOQL7UCG.js";
|
|
10
10
|
import "./chunk-EGWK6SRQ.js";
|
|
11
11
|
import "./chunk-TFCNKBRC.js";
|
|
12
12
|
import "./chunk-U73SABXK.js";
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "./chunk-VFT3TD3E.js";
|
|
9
9
|
import {
|
|
10
10
|
createApiClient
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-GOQL7UCG.js";
|
|
12
12
|
import "./chunk-EGWK6SRQ.js";
|
|
13
13
|
import "./chunk-TFCNKBRC.js";
|
|
14
14
|
import "./chunk-U73SABXK.js";
|
|
@@ -29,6 +29,7 @@ var SINGLE_SERVICES = [
|
|
|
29
29
|
"darkWebMonitoring"
|
|
30
30
|
];
|
|
31
31
|
var ALL_SERVICES = [...DUAL_SERVICES, ...SINGLE_SERVICES];
|
|
32
|
+
var PENDING_APPROVAL_SERVICES = ["protection", "takedowns"];
|
|
32
33
|
function splitCsv(value) {
|
|
33
34
|
if (!value) return [];
|
|
34
35
|
return value.split(",").map((part) => part.trim()).filter(Boolean);
|
|
@@ -155,6 +156,47 @@ function buildObligatoryAdminApprovalFilter(options) {
|
|
|
155
156
|
if (assetTypeStrings.length > 0) filter.assetTypes = assetTypeStrings;
|
|
156
157
|
return Object.keys(filter).length > 0 ? filter : void 0;
|
|
157
158
|
}
|
|
159
|
+
function parsePendingApprovalServices(raw) {
|
|
160
|
+
const parts = splitCsv(raw);
|
|
161
|
+
const result = [];
|
|
162
|
+
for (const part of parts) {
|
|
163
|
+
if (!PENDING_APPROVAL_SERVICES.includes(part)) {
|
|
164
|
+
throw new CliExitError(
|
|
165
|
+
`Unknown service '${part}' in --pending-approval-service. Only ${PENDING_APPROVAL_SERVICES.join(", ")} can require approval.`,
|
|
166
|
+
ExitCode.USAGE
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
result.push(part);
|
|
170
|
+
}
|
|
171
|
+
return result;
|
|
172
|
+
}
|
|
173
|
+
function buildPendingServiceApprovalFilter(options) {
|
|
174
|
+
if (options.pendingApprovalActive && options.pendingApprovalInactive) {
|
|
175
|
+
throw new CliExitError(
|
|
176
|
+
"Conflicting flags: --pending-approval-active and --pending-approval-inactive can't both be passed.",
|
|
177
|
+
ExitCode.USAGE
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
const services = parsePendingApprovalServices(options.pendingApprovalService);
|
|
181
|
+
if (services.length > 0 && options.pendingApprovalInactive) {
|
|
182
|
+
throw new CliExitError(
|
|
183
|
+
"Conflicting flags: --pending-approval-service implies a pending approval exists, so it can't be combined with --pending-approval-inactive.",
|
|
184
|
+
ExitCode.USAGE
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
const filter = {};
|
|
188
|
+
if (options.pendingApprovalActive) filter.active = true;
|
|
189
|
+
if (options.pendingApprovalInactive) filter.active = false;
|
|
190
|
+
if (services.length > 0) filter.services = services;
|
|
191
|
+
return Object.keys(filter).length > 0 ? filter : void 0;
|
|
192
|
+
}
|
|
193
|
+
function summarizePendingApprovals(org) {
|
|
194
|
+
if (org.pendingServiceApprovals.length === 0) return "none";
|
|
195
|
+
const labels = Array.from(
|
|
196
|
+
new Set(org.pendingServiceApprovals.map((approval) => approval.serviceName))
|
|
197
|
+
);
|
|
198
|
+
return labels.join(", ");
|
|
199
|
+
}
|
|
158
200
|
async function runOrgsList(options) {
|
|
159
201
|
const client = options.apiClient ?? createApiClient();
|
|
160
202
|
const outputFormat = options.outputFormat ?? (options.json ? "json" : "human");
|
|
@@ -162,7 +204,8 @@ async function runOrgsList(options) {
|
|
|
162
204
|
query: options.query ?? "",
|
|
163
205
|
subscriptionStatus: parseSubscriptionStatuses(options.subscriptionStatus),
|
|
164
206
|
services: buildServicesFilter(options),
|
|
165
|
-
obligatoryAdminApproval: buildObligatoryAdminApprovalFilter(options)
|
|
207
|
+
obligatoryAdminApproval: buildObligatoryAdminApprovalFilter(options),
|
|
208
|
+
pendingServiceApproval: buildPendingServiceApprovalFilter(options)
|
|
166
209
|
};
|
|
167
210
|
const result = await client.getUserOrgs(input);
|
|
168
211
|
const organizations = result.organizations;
|
|
@@ -173,13 +216,14 @@ async function runOrgsList(options) {
|
|
|
173
216
|
`# Organizations (${organizations.length})`,
|
|
174
217
|
"",
|
|
175
218
|
...organizations.map(
|
|
176
|
-
(org) => `- \`${org.slug}\` \u2014 ${org.name} \u2014 ${org.subscriptionStatus} \u2014 ${summarizeServices(org)} \u2014 admin-approval: ${summarizeObligatoryAdminApproval(org)}`
|
|
219
|
+
(org) => `- \`${org.slug}\` \u2014 ${org.name} \u2014 ${org.subscriptionStatus} \u2014 contact: ${org.contactUrl ?? "(not set)"} \u2014 ${summarizeServices(org)} \u2014 admin-approval: ${summarizeObligatoryAdminApproval(org)} \u2014 pending-approval: ${summarizePendingApprovals(org)}`
|
|
177
220
|
)
|
|
178
221
|
].join("\n"),
|
|
179
222
|
csv: toCsvRows(
|
|
180
223
|
organizations.map((org) => ({
|
|
181
224
|
slug: org.slug,
|
|
182
225
|
name: org.name,
|
|
226
|
+
contactUrl: org.contactUrl ?? "",
|
|
183
227
|
subscriptionStatus: org.subscriptionStatus,
|
|
184
228
|
reportingActive: org.services.reporting.active,
|
|
185
229
|
reviewingActive: org.services.reviewing.active,
|
|
@@ -193,7 +237,14 @@ async function runOrgsList(options) {
|
|
|
193
237
|
// Empty list + active means "applies to all asset types"; we keep
|
|
194
238
|
// the cell empty in CSV so spreadsheets render it as the natural
|
|
195
239
|
// "no narrowing" value — pair it with the active column.
|
|
196
|
-
obligatoryAdminApprovalAssetTypes: org.obligatoryAdminApproval.assetTypes.join("|")
|
|
240
|
+
obligatoryAdminApprovalAssetTypes: org.obligatoryAdminApproval.assetTypes.join("|"),
|
|
241
|
+
// Pending staff requests to enable Wallet Blocking / Takedowns that
|
|
242
|
+
// a higher-up has not yet approved. We emit the raw `serviceType`
|
|
243
|
+
// enum values (de-duplicated) so the column is machine-filterable;
|
|
244
|
+
// an empty cell means nothing is awaiting approval.
|
|
245
|
+
pendingServiceApprovals: Array.from(
|
|
246
|
+
new Set(org.pendingServiceApprovals.map((approval) => approval.serviceType))
|
|
247
|
+
).join("|")
|
|
197
248
|
}))
|
|
198
249
|
),
|
|
199
250
|
human: () => {
|
|
@@ -205,8 +256,9 @@ async function runOrgsList(options) {
|
|
|
205
256
|
const slugWidth = Math.max(...organizations.map((org) => org.slug.length), 4);
|
|
206
257
|
const nameWidth = Math.max(...organizations.map((org) => org.name.length), 4);
|
|
207
258
|
for (const org of organizations) {
|
|
259
|
+
const contact = org.contactUrl ?? "(no contact)";
|
|
208
260
|
console.log(
|
|
209
|
-
` ${org.slug.padEnd(slugWidth)} ${org.name.padEnd(nameWidth)} ${org.subscriptionStatus.padEnd(11)} ${summarizeServices(org)} admin-approval=${summarizeObligatoryAdminApproval(org)}`
|
|
261
|
+
` ${org.slug.padEnd(slugWidth)} ${org.name.padEnd(nameWidth)} ${org.subscriptionStatus.padEnd(11)} ${contact} ${summarizeServices(org)} admin-approval=${summarizeObligatoryAdminApproval(org)} pending-approval=${summarizePendingApprovals(org)}`
|
|
210
262
|
);
|
|
211
263
|
}
|
|
212
264
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getPresetDefinition,
|
|
3
3
|
runPreset
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-DVNTYW7L.js";
|
|
5
5
|
import {
|
|
6
6
|
CliExitError,
|
|
7
7
|
ExitCode
|
|
8
8
|
} from "./chunk-E2LAMILJ.js";
|
|
9
9
|
import "./chunk-VFT3TD3E.js";
|
|
10
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-GOQL7UCG.js";
|
|
11
11
|
import "./chunk-EGWK6SRQ.js";
|
|
12
12
|
import "./chunk-TFCNKBRC.js";
|
|
13
13
|
import "./chunk-U73SABXK.js";
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CliExitError,
|
|
3
|
+
ExitCode
|
|
4
|
+
} from "./chunk-E2LAMILJ.js";
|
|
5
|
+
import {
|
|
6
|
+
printOutput,
|
|
7
|
+
toCsvRows
|
|
8
|
+
} from "./chunk-VFT3TD3E.js";
|
|
9
|
+
import {
|
|
10
|
+
createApiClient
|
|
11
|
+
} from "./chunk-GOQL7UCG.js";
|
|
12
|
+
import "./chunk-EGWK6SRQ.js";
|
|
13
|
+
import "./chunk-TFCNKBRC.js";
|
|
14
|
+
import "./chunk-U73SABXK.js";
|
|
15
|
+
|
|
16
|
+
// src/commands/asset/search.ts
|
|
17
|
+
function formatAssetRow(item) {
|
|
18
|
+
if (!item.asset) {
|
|
19
|
+
return " (not found)";
|
|
20
|
+
}
|
|
21
|
+
const a = item.asset;
|
|
22
|
+
const lines = [
|
|
23
|
+
` [${a.status}] ${a.content} (id=${a.id}, type=${a.type}, watch=${a.watchStatus})`
|
|
24
|
+
];
|
|
25
|
+
if (item.reports.length > 0) {
|
|
26
|
+
lines.push(` Reports: ${item.reports.length}`);
|
|
27
|
+
}
|
|
28
|
+
if (item.takedown) {
|
|
29
|
+
lines.push(
|
|
30
|
+
` Takedown: ${item.takedown.status} (${item.takedown.tasks.length} task(s))`
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
if (item.blockedBy.length > 0) {
|
|
34
|
+
lines.push(` Blocked by: ${item.blockedBy.map((b) => b.consumer).join(", ")}`);
|
|
35
|
+
}
|
|
36
|
+
return lines.join("\n");
|
|
37
|
+
}
|
|
38
|
+
function toMarkdownRow(item, label) {
|
|
39
|
+
if (!item.asset) {
|
|
40
|
+
return `| ${label ?? "unknown"} | \u2014 | \u2014 | \u2014 | not found |`;
|
|
41
|
+
}
|
|
42
|
+
const a = item.asset;
|
|
43
|
+
return `| ${a.id} | ${a.content} | ${a.type} | ${a.status} | ${a.watchStatus} |`;
|
|
44
|
+
}
|
|
45
|
+
function toCsvRow(item, label) {
|
|
46
|
+
if (!item.asset) {
|
|
47
|
+
return {
|
|
48
|
+
id: label ?? "",
|
|
49
|
+
content: label ?? "",
|
|
50
|
+
type: "",
|
|
51
|
+
status: "NOT_FOUND",
|
|
52
|
+
watchStatus: "",
|
|
53
|
+
reports: 0,
|
|
54
|
+
takedownStatus: "",
|
|
55
|
+
blockedByCount: 0
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const a = item.asset;
|
|
59
|
+
return {
|
|
60
|
+
id: a.id,
|
|
61
|
+
content: a.content,
|
|
62
|
+
type: a.type,
|
|
63
|
+
status: a.status,
|
|
64
|
+
watchStatus: a.watchStatus,
|
|
65
|
+
reports: item.reports.length,
|
|
66
|
+
takedownStatus: item.takedown?.status ?? "",
|
|
67
|
+
blockedByCount: item.blockedBy.length
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
async function runAssetSearch(options) {
|
|
71
|
+
const contents = (options.contents ?? []).map((v) => v.trim()).filter((v) => v.length > 0);
|
|
72
|
+
const ids = options.ids ?? [];
|
|
73
|
+
if (contents.length === 0 && ids.length === 0) {
|
|
74
|
+
throw new CliExitError(
|
|
75
|
+
"asset search requires at least one asset content or --id. Example: chainpatrol asset search https://example.com or chainpatrol asset search --id 12345",
|
|
76
|
+
ExitCode.USAGE
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
if (contents.length > 0 && ids.length > 0) {
|
|
80
|
+
throw new CliExitError(
|
|
81
|
+
"asset search does not support mixing content and --id in the same call. Use one or the other.",
|
|
82
|
+
ExitCode.USAGE
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
const outputFormat = options.outputFormat ?? (options.json ? "json" : "human");
|
|
86
|
+
const client = options.apiClient ?? createApiClient();
|
|
87
|
+
let items;
|
|
88
|
+
let labels = [];
|
|
89
|
+
if (ids.length > 0) {
|
|
90
|
+
labels = ids.map((id) => `ID ${id}`);
|
|
91
|
+
const result = await client.assetSearch({ assetIds: ids });
|
|
92
|
+
items = result.results ?? [result];
|
|
93
|
+
} else if (contents.length === 1) {
|
|
94
|
+
labels = [contents[0]];
|
|
95
|
+
const result = await client.assetSearch({ content: contents[0] });
|
|
96
|
+
items = [result];
|
|
97
|
+
} else {
|
|
98
|
+
labels = contents;
|
|
99
|
+
const settled = await Promise.allSettled(
|
|
100
|
+
contents.map((content) => client.assetSearch({ content }))
|
|
101
|
+
);
|
|
102
|
+
let errored = 0;
|
|
103
|
+
items = settled.map((r, i) => {
|
|
104
|
+
if (r.status === "fulfilled") return r.value;
|
|
105
|
+
errored += 1;
|
|
106
|
+
console.error(
|
|
107
|
+
`Error searching ${contents[i]}: ${r.reason instanceof Error ? r.reason.message : String(r.reason)}`
|
|
108
|
+
);
|
|
109
|
+
return { asset: null, reports: [], takedown: null, blockedBy: [] };
|
|
110
|
+
});
|
|
111
|
+
if (errored === contents.length) {
|
|
112
|
+
throw new CliExitError(
|
|
113
|
+
`asset search: all ${errored} request(s) failed.`,
|
|
114
|
+
ExitCode.UNKNOWN
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const found = items.filter((i) => i.asset !== null).length;
|
|
119
|
+
const notFound = items.length - found;
|
|
120
|
+
const jsonPayload = items.length === 1 ? items[0] : {
|
|
121
|
+
results: items,
|
|
122
|
+
summary: { total: items.length, found, notFound }
|
|
123
|
+
};
|
|
124
|
+
const markdown = items.length === 1 && items[0].asset ? buildSingleMarkdown(items[0]) : [
|
|
125
|
+
`# Asset Search (${items.length})`,
|
|
126
|
+
"",
|
|
127
|
+
`- Found: ${found}`,
|
|
128
|
+
`- Not found: ${notFound}`,
|
|
129
|
+
"",
|
|
130
|
+
"| ID | Content | Type | Status | Watch |",
|
|
131
|
+
"| --- | --- | --- | --- | --- |",
|
|
132
|
+
...items.map((item, i) => toMarkdownRow(item, labels[i]))
|
|
133
|
+
].join("\n");
|
|
134
|
+
const csv = toCsvRows(items.map((item, i) => toCsvRow(item, labels[i])));
|
|
135
|
+
printOutput({
|
|
136
|
+
outputFormat,
|
|
137
|
+
json: jsonPayload,
|
|
138
|
+
markdown,
|
|
139
|
+
csv,
|
|
140
|
+
human: () => {
|
|
141
|
+
if (items.length === 1) {
|
|
142
|
+
const item = items[0];
|
|
143
|
+
if (!item.asset) {
|
|
144
|
+
console.log(`${labels[0] ?? "Asset"} not found.`);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
console.log(formatAssetRow(item));
|
|
148
|
+
if (item.reports.length > 0) {
|
|
149
|
+
console.log(" Reports:");
|
|
150
|
+
for (const r of item.reports) {
|
|
151
|
+
console.log(
|
|
152
|
+
` #${r.id} [${r.status}] ${r.title ?? "(untitled)"} \u2014 ${r.createdAt}`
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (item.takedown) {
|
|
157
|
+
console.log(` Takedown #${item.takedown.id} [${item.takedown.status}]`);
|
|
158
|
+
for (const t of item.takedown.tasks) {
|
|
159
|
+
console.log(
|
|
160
|
+
` Task #${t.id} [${t.status}] ${t.takedownProvider?.name ?? "unknown provider"}`
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
console.log(
|
|
167
|
+
`Asset Search \u2014 ${found} found, ${notFound} not found (${items.length} total)`
|
|
168
|
+
);
|
|
169
|
+
for (let i = 0; i < items.length; i++) {
|
|
170
|
+
const item = items[i];
|
|
171
|
+
if (!item.asset) {
|
|
172
|
+
console.log(`${labels[i] ?? "unknown"} -> NOT FOUND`);
|
|
173
|
+
} else {
|
|
174
|
+
console.log(formatAssetRow(item));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
function buildSingleMarkdown(item) {
|
|
181
|
+
if (!item.asset) {
|
|
182
|
+
return "# Asset Search\n\nAsset not found.";
|
|
183
|
+
}
|
|
184
|
+
const a = item.asset;
|
|
185
|
+
const lines = [
|
|
186
|
+
`# Asset Search: ${a.content}`,
|
|
187
|
+
"",
|
|
188
|
+
`- ID: ${a.id}`,
|
|
189
|
+
`- Type: ${a.type}`,
|
|
190
|
+
`- Status: **${a.status}**`,
|
|
191
|
+
`- Watch: ${a.watchStatus}`,
|
|
192
|
+
`- Created: ${a.createdAt}`,
|
|
193
|
+
`- Updated: ${a.updatedAt}`
|
|
194
|
+
];
|
|
195
|
+
if (item.reports.length > 0) {
|
|
196
|
+
lines.push("", "## Reports", "");
|
|
197
|
+
for (const r of item.reports) {
|
|
198
|
+
lines.push(`- #${r.id} [${r.status}] ${r.title ?? "(untitled)"} \u2014 ${r.createdAt}`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (item.takedown) {
|
|
202
|
+
lines.push("", `## Takedown #${item.takedown.id} [${item.takedown.status}]`, "");
|
|
203
|
+
for (const t of item.takedown.tasks) {
|
|
204
|
+
lines.push(
|
|
205
|
+
`- Task #${t.id} [${t.status}] ${t.takedownProvider?.name ?? "unknown provider"}`
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (item.blockedBy.length > 0) {
|
|
210
|
+
lines.push("", "## Blocked By", "");
|
|
211
|
+
for (const b of item.blockedBy) {
|
|
212
|
+
lines.push(
|
|
213
|
+
`- ${b.consumer}${b.name ? ` (${b.name})` : ""} \u2014 since ${b.consumedAt}`
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return lines.join("\n");
|
|
218
|
+
}
|
|
219
|
+
export {
|
|
220
|
+
runAssetSearch
|
|
221
|
+
};
|
|
@@ -217,7 +217,8 @@ var ASSET_TYPES = [
|
|
|
217
217
|
type: "FIVE_HUNDRED_PX",
|
|
218
218
|
label: "500px",
|
|
219
219
|
description: "A 500px photographer profile."
|
|
220
|
-
}
|
|
220
|
+
},
|
|
221
|
+
{ type: "LUMA", label: "Luma", description: "A Luma page or profile." }
|
|
221
222
|
];
|
|
222
223
|
var ASSET_TYPE_LABELS = Object.freeze(
|
|
223
224
|
Object.fromEntries(ASSET_TYPES.map((entry) => [entry.type, entry.label]))
|