papermark 0.7.0 → 0.8.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 +461 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -269,6 +269,13 @@ var api = {
|
|
|
269
269
|
createLink: (body) => request("/v1/links", { method: "POST", body }),
|
|
270
270
|
updateLink: (id, body) => request(`/v1/links/${id}`, { method: "PATCH", body }),
|
|
271
271
|
deleteLink: (id) => request(`/v1/links/${id}`, { method: "DELETE" }),
|
|
272
|
+
getLinkPermissions: (id) => request(`/v1/links/${id}/permissions`),
|
|
273
|
+
// Full-replace semantics: the payload is the complete desired state;
|
|
274
|
+
// items not listed lose their override.
|
|
275
|
+
setLinkPermissions: (id, body) => request(`/v1/links/${id}/permissions`, {
|
|
276
|
+
method: "PUT",
|
|
277
|
+
body
|
|
278
|
+
}),
|
|
272
279
|
// Views
|
|
273
280
|
listViews: (linkId, query) => request(`/v1/links/${linkId}/views`, { query }),
|
|
274
281
|
// Datarooms
|
|
@@ -308,6 +315,44 @@ var api = {
|
|
|
308
315
|
method: "POST",
|
|
309
316
|
body
|
|
310
317
|
}),
|
|
318
|
+
// Dataroom groups
|
|
319
|
+
listDataroomGroups: (id, query) => request(`/v1/datarooms/${id}/groups`, { query }),
|
|
320
|
+
createDataroomGroup: (id, body) => request(`/v1/datarooms/${id}/groups`, {
|
|
321
|
+
method: "POST",
|
|
322
|
+
body
|
|
323
|
+
}),
|
|
324
|
+
getDataroomGroup: (id, gid) => request(`/v1/datarooms/${id}/groups/${gid}`),
|
|
325
|
+
updateDataroomGroup: (id, gid, body) => request(`/v1/datarooms/${id}/groups/${gid}`, {
|
|
326
|
+
method: "PATCH",
|
|
327
|
+
body
|
|
328
|
+
}),
|
|
329
|
+
// Also deletes every share link pointing at the group (matching the
|
|
330
|
+
// dashboard).
|
|
331
|
+
deleteDataroomGroup: (id, gid) => request(`/v1/datarooms/${id}/groups/${gid}`, {
|
|
332
|
+
method: "DELETE"
|
|
333
|
+
}),
|
|
334
|
+
listDataroomGroupMembers: (id, gid, query) => request(
|
|
335
|
+
`/v1/datarooms/${id}/groups/${gid}/members`,
|
|
336
|
+
{ query }
|
|
337
|
+
),
|
|
338
|
+
addDataroomGroupMembers: (id, gid, body) => request(
|
|
339
|
+
`/v1/datarooms/${id}/groups/${gid}/members`,
|
|
340
|
+
{ method: "POST", body }
|
|
341
|
+
),
|
|
342
|
+
removeDataroomGroupMember: (id, gid, mid) => request(
|
|
343
|
+
`/v1/datarooms/${id}/groups/${gid}/members/${mid}`,
|
|
344
|
+
{ method: "DELETE" }
|
|
345
|
+
),
|
|
346
|
+
listDataroomGroupPermissions: (id, gid, query) => request(
|
|
347
|
+
`/v1/datarooms/${id}/groups/${gid}/permissions`,
|
|
348
|
+
{ query }
|
|
349
|
+
),
|
|
350
|
+
// Upsert-delta semantics: entries sent are upserted, entries omitted keep
|
|
351
|
+
// their current state; ancestor folders of visible items are auto-shown.
|
|
352
|
+
setDataroomGroupPermissions: (id, gid, body) => request(
|
|
353
|
+
`/v1/datarooms/${id}/groups/${gid}/permissions`,
|
|
354
|
+
{ method: "PUT", body }
|
|
355
|
+
),
|
|
311
356
|
// Visitors
|
|
312
357
|
listVisitors: (query) => request("/v1/visitors", { query }),
|
|
313
358
|
getVisitor: (id) => request(`/v1/visitors/${id}`),
|
|
@@ -1073,6 +1118,92 @@ function registerConfigCommands(program2) {
|
|
|
1073
1118
|
|
|
1074
1119
|
// src/commands/datarooms.ts
|
|
1075
1120
|
import chalk5 from "chalk";
|
|
1121
|
+
|
|
1122
|
+
// src/commands/permissions-input.ts
|
|
1123
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
1124
|
+
var ITEM_TYPES = {
|
|
1125
|
+
document: "dataroom_document",
|
|
1126
|
+
dataroom_document: "dataroom_document",
|
|
1127
|
+
folder: "dataroom_folder",
|
|
1128
|
+
dataroom_folder: "dataroom_folder"
|
|
1129
|
+
};
|
|
1130
|
+
function onOff(v, flag, fallback) {
|
|
1131
|
+
if (v === void 0) return fallback;
|
|
1132
|
+
const norm = v.toLowerCase();
|
|
1133
|
+
if (norm === "on") return true;
|
|
1134
|
+
if (norm === "off") return false;
|
|
1135
|
+
throw new Error(
|
|
1136
|
+
`Invalid value for ${flag}: ${JSON.stringify(v)} (expected "on" or "off").`
|
|
1137
|
+
);
|
|
1138
|
+
}
|
|
1139
|
+
function parsePermissionEntries(opts) {
|
|
1140
|
+
if (opts.file && opts.item) {
|
|
1141
|
+
throw new Error("Pass either --file or --item, not both.");
|
|
1142
|
+
}
|
|
1143
|
+
if (opts.file) {
|
|
1144
|
+
let raw;
|
|
1145
|
+
try {
|
|
1146
|
+
raw = readFileSync2(opts.file, "utf8");
|
|
1147
|
+
} catch (err) {
|
|
1148
|
+
throw new Error(
|
|
1149
|
+
`Could not read ${opts.file}: ${err instanceof Error ? err.message : String(err)}`
|
|
1150
|
+
);
|
|
1151
|
+
}
|
|
1152
|
+
let parsed;
|
|
1153
|
+
try {
|
|
1154
|
+
parsed = JSON.parse(raw);
|
|
1155
|
+
} catch {
|
|
1156
|
+
throw new Error(`${opts.file} is not valid JSON.`);
|
|
1157
|
+
}
|
|
1158
|
+
if (!Array.isArray(parsed)) {
|
|
1159
|
+
throw new Error(
|
|
1160
|
+
`${opts.file} must contain a JSON array of { item_id, item_type, can_view, can_download }.`
|
|
1161
|
+
);
|
|
1162
|
+
}
|
|
1163
|
+
return parsed.map((entry, i) => {
|
|
1164
|
+
const e = entry;
|
|
1165
|
+
const itemType = ITEM_TYPES[String(e.item_type)];
|
|
1166
|
+
if (typeof e.item_id !== "string" || !e.item_id) {
|
|
1167
|
+
throw new Error(`Entry ${i}: missing or invalid item_id.`);
|
|
1168
|
+
}
|
|
1169
|
+
if (!itemType) {
|
|
1170
|
+
throw new Error(
|
|
1171
|
+
`Entry ${i}: invalid item_type ${JSON.stringify(e.item_type)} (expected dataroom_document or dataroom_folder).`
|
|
1172
|
+
);
|
|
1173
|
+
}
|
|
1174
|
+
if (typeof e.can_view !== "boolean" || typeof e.can_download !== "boolean") {
|
|
1175
|
+
throw new Error(`Entry ${i}: can_view and can_download must be booleans.`);
|
|
1176
|
+
}
|
|
1177
|
+
return {
|
|
1178
|
+
item_id: e.item_id,
|
|
1179
|
+
item_type: itemType,
|
|
1180
|
+
can_view: e.can_view,
|
|
1181
|
+
can_download: e.can_download
|
|
1182
|
+
};
|
|
1183
|
+
});
|
|
1184
|
+
}
|
|
1185
|
+
if (opts.item) {
|
|
1186
|
+
const itemType = ITEM_TYPES[String(opts.type ?? "")];
|
|
1187
|
+
if (!itemType) {
|
|
1188
|
+
throw new Error(
|
|
1189
|
+
"Pass --type document or --type folder together with --item."
|
|
1190
|
+
);
|
|
1191
|
+
}
|
|
1192
|
+
return [
|
|
1193
|
+
{
|
|
1194
|
+
item_id: opts.item,
|
|
1195
|
+
item_type: itemType,
|
|
1196
|
+
can_view: onOff(opts.view, "--view", true),
|
|
1197
|
+
can_download: onOff(opts.download, "--download", false)
|
|
1198
|
+
}
|
|
1199
|
+
];
|
|
1200
|
+
}
|
|
1201
|
+
throw new Error(
|
|
1202
|
+
"Pass --file <path> (JSON array) or --item <id> --type <document|folder> [--view on|off] [--download on|off]."
|
|
1203
|
+
);
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
// src/commands/datarooms.ts
|
|
1076
1207
|
function registerDataroomsCommands(program2) {
|
|
1077
1208
|
const dr = program2.command("datarooms").alias("dr").description("Manage datarooms");
|
|
1078
1209
|
dr.command("list").description("List datarooms").option("-l, --limit <n>", "max results (1-100)", "25").option("-c, --cursor <id>", "pagination cursor").option("-q, --query <substring>", "filter by dataroom name").option("--json", "output raw JSON (same as --json on the root command)").action(
|
|
@@ -1344,6 +1475,249 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
1344
1475
|
}
|
|
1345
1476
|
}
|
|
1346
1477
|
);
|
|
1478
|
+
const drGroups = dr.command("groups").description(
|
|
1479
|
+
"Manage viewer groups: audiences with per-item permissions, shared via group links"
|
|
1480
|
+
);
|
|
1481
|
+
drGroups.command("list <id>").description("List viewer groups in a dataroom").option("-l, --limit <n>", "max results (1-100)", "25").option("-c, --cursor <id>", "pagination cursor").option("--json", "output raw JSON").action(
|
|
1482
|
+
async (id, opts) => {
|
|
1483
|
+
if (opts.json) setRuntime({ json: true });
|
|
1484
|
+
try {
|
|
1485
|
+
const res = await api.listDataroomGroups(id, {
|
|
1486
|
+
limit: opts.limit ? Number(opts.limit) : void 0,
|
|
1487
|
+
cursor: opts.cursor
|
|
1488
|
+
});
|
|
1489
|
+
emit(res, () => {
|
|
1490
|
+
const rows = res.data.map((g) => ({
|
|
1491
|
+
id: g.id,
|
|
1492
|
+
name: truncate2(g.name, 30),
|
|
1493
|
+
members: String(g.member_count),
|
|
1494
|
+
links: String(g.link_count),
|
|
1495
|
+
domains: truncate2(g.domains.join(","), 30),
|
|
1496
|
+
allow_all: g.allow_all ? "yes" : ""
|
|
1497
|
+
}));
|
|
1498
|
+
const out = table(rows, [
|
|
1499
|
+
"id",
|
|
1500
|
+
"name",
|
|
1501
|
+
"members",
|
|
1502
|
+
"links",
|
|
1503
|
+
"domains",
|
|
1504
|
+
"allow_all"
|
|
1505
|
+
]);
|
|
1506
|
+
return res.next_cursor ? out + chalk5.dim(`
|
|
1507
|
+
|
|
1508
|
+
More results: --cursor ${res.next_cursor}`) : out;
|
|
1509
|
+
});
|
|
1510
|
+
} catch (err) {
|
|
1511
|
+
die(err);
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
);
|
|
1515
|
+
drGroups.command("get <id> <gid>").description("Fetch one viewer group").action(async (id, gid) => {
|
|
1516
|
+
try {
|
|
1517
|
+
const g = await api.getDataroomGroup(id, gid);
|
|
1518
|
+
emit(g, () => json(g));
|
|
1519
|
+
} catch (err) {
|
|
1520
|
+
die(err);
|
|
1521
|
+
}
|
|
1522
|
+
});
|
|
1523
|
+
drGroups.command("create <id>").description("Create a viewer group in a dataroom").requiredOption("-n, --name <name>", "group name").option(
|
|
1524
|
+
"--domains <domains>",
|
|
1525
|
+
"comma-separated email domains treated as members (e.g. 'acme.com')"
|
|
1526
|
+
).option(
|
|
1527
|
+
"--allow-all",
|
|
1528
|
+
"treat anyone passing the link's access gates as a member",
|
|
1529
|
+
false
|
|
1530
|
+
).action(
|
|
1531
|
+
async (id, opts) => {
|
|
1532
|
+
try {
|
|
1533
|
+
const g = await api.createDataroomGroup(id, {
|
|
1534
|
+
name: opts.name,
|
|
1535
|
+
allow_all: opts.allowAll || void 0,
|
|
1536
|
+
domains: opts.domains ? opts.domains.split(",").map((s) => s.trim()).filter(Boolean) : void 0
|
|
1537
|
+
});
|
|
1538
|
+
emit(
|
|
1539
|
+
g,
|
|
1540
|
+
() => chalk5.green("\u2713") + ` Group created: ${chalk5.bold(g.id)}
|
|
1541
|
+
` + json(g)
|
|
1542
|
+
);
|
|
1543
|
+
} catch (err) {
|
|
1544
|
+
die(err);
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
);
|
|
1548
|
+
drGroups.command("update <id> <gid>").description("Update a viewer group").option("-n, --name <name>").option(
|
|
1549
|
+
"--domains <domains>",
|
|
1550
|
+
"comma-separated email domains (empty string to clear)"
|
|
1551
|
+
).option("--allow-all <on|off>", "toggle the allow-anyone flag").action(
|
|
1552
|
+
async (id, gid, opts) => {
|
|
1553
|
+
try {
|
|
1554
|
+
const body = {};
|
|
1555
|
+
if (opts.name !== void 0) body.name = opts.name;
|
|
1556
|
+
if (opts.domains !== void 0)
|
|
1557
|
+
body.domains = opts.domains === "" ? [] : opts.domains.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1558
|
+
if (opts.allowAll !== void 0) {
|
|
1559
|
+
const norm = opts.allowAll.toLowerCase();
|
|
1560
|
+
if (norm !== "on" && norm !== "off") {
|
|
1561
|
+
throw new Error(
|
|
1562
|
+
`Invalid value for --allow-all: ${JSON.stringify(opts.allowAll)} (expected "on" or "off").`
|
|
1563
|
+
);
|
|
1564
|
+
}
|
|
1565
|
+
body.allow_all = norm === "on";
|
|
1566
|
+
}
|
|
1567
|
+
if (Object.keys(body).length === 0) {
|
|
1568
|
+
throw new Error(
|
|
1569
|
+
"Pass at least one of --name, --domains, --allow-all to update."
|
|
1570
|
+
);
|
|
1571
|
+
}
|
|
1572
|
+
const g = await api.updateDataroomGroup(id, gid, body);
|
|
1573
|
+
emit(
|
|
1574
|
+
g,
|
|
1575
|
+
() => chalk5.green("\u2713") + ` Group updated: ${chalk5.bold(g.id)}
|
|
1576
|
+
` + json(g)
|
|
1577
|
+
);
|
|
1578
|
+
} catch (err) {
|
|
1579
|
+
die(err);
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
);
|
|
1583
|
+
drGroups.command("delete <id> <gid>").description(
|
|
1584
|
+
"Delete a viewer group. WARNING: also deletes every share link pointing at the group \u2014 active group links stop resolving immediately."
|
|
1585
|
+
).action(async (id, gid) => {
|
|
1586
|
+
try {
|
|
1587
|
+
const deleted = await api.deleteDataroomGroup(id, gid);
|
|
1588
|
+
emit(
|
|
1589
|
+
deleted,
|
|
1590
|
+
() => chalk5.green("\u2713") + ` Group ${gid} deleted (including its share links).`
|
|
1591
|
+
);
|
|
1592
|
+
} catch (err) {
|
|
1593
|
+
die(err);
|
|
1594
|
+
}
|
|
1595
|
+
});
|
|
1596
|
+
const drGroupMembers = drGroups.command("members").description("Manage a group's email members");
|
|
1597
|
+
drGroupMembers.command("list <id> <gid>").description(
|
|
1598
|
+
"List a group's explicit email members (domain/allow-all admissions are not listed)"
|
|
1599
|
+
).option("-l, --limit <n>", "max results (1-100)", "50").option("-c, --cursor <id>", "pagination cursor").option("--json", "output raw JSON").action(
|
|
1600
|
+
async (id, gid, opts) => {
|
|
1601
|
+
if (opts.json) setRuntime({ json: true });
|
|
1602
|
+
try {
|
|
1603
|
+
const res = await api.listDataroomGroupMembers(id, gid, {
|
|
1604
|
+
limit: opts.limit ? Number(opts.limit) : void 0,
|
|
1605
|
+
cursor: opts.cursor
|
|
1606
|
+
});
|
|
1607
|
+
emit(res, () => {
|
|
1608
|
+
const rows = res.data.map((m) => ({
|
|
1609
|
+
id: m.id,
|
|
1610
|
+
email: sanitizeForTerminal(m.email),
|
|
1611
|
+
added: m.created.slice(0, 10)
|
|
1612
|
+
}));
|
|
1613
|
+
const out = table(rows, ["id", "email", "added"]);
|
|
1614
|
+
return res.next_cursor ? out + chalk5.dim(`
|
|
1615
|
+
|
|
1616
|
+
More results: --cursor ${res.next_cursor}`) : out;
|
|
1617
|
+
});
|
|
1618
|
+
} catch (err) {
|
|
1619
|
+
die(err);
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
);
|
|
1623
|
+
drGroupMembers.command("add <id> <gid>").description(
|
|
1624
|
+
"Add members by email (idempotent; no invitation emails are sent)"
|
|
1625
|
+
).requiredOption(
|
|
1626
|
+
"-e, --emails <emails>",
|
|
1627
|
+
"comma-separated email addresses (max 500)"
|
|
1628
|
+
).action(async (id, gid, opts) => {
|
|
1629
|
+
try {
|
|
1630
|
+
const emails = opts.emails.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1631
|
+
if (emails.length === 0) {
|
|
1632
|
+
throw new Error("Pass at least one email via --emails.");
|
|
1633
|
+
}
|
|
1634
|
+
const res = await api.addDataroomGroupMembers(id, gid, { emails });
|
|
1635
|
+
emit(
|
|
1636
|
+
res,
|
|
1637
|
+
() => chalk5.green("\u2713") + ` ${res.data.length} member(s) in group after add:
|
|
1638
|
+
` + table(
|
|
1639
|
+
res.data.map((m) => ({
|
|
1640
|
+
id: m.id,
|
|
1641
|
+
email: sanitizeForTerminal(m.email)
|
|
1642
|
+
})),
|
|
1643
|
+
["id", "email"]
|
|
1644
|
+
)
|
|
1645
|
+
);
|
|
1646
|
+
} catch (err) {
|
|
1647
|
+
die(err);
|
|
1648
|
+
}
|
|
1649
|
+
});
|
|
1650
|
+
drGroupMembers.command("remove <id> <gid> <mid>").description(
|
|
1651
|
+
"Remove a member by membership id (from `members list`). The viewer itself is kept."
|
|
1652
|
+
).action(async (id, gid, mid) => {
|
|
1653
|
+
try {
|
|
1654
|
+
const deleted = await api.removeDataroomGroupMember(id, gid, mid);
|
|
1655
|
+
emit(
|
|
1656
|
+
deleted,
|
|
1657
|
+
() => chalk5.green("\u2713") + ` Member ${mid} removed from group.`
|
|
1658
|
+
);
|
|
1659
|
+
} catch (err) {
|
|
1660
|
+
die(err);
|
|
1661
|
+
}
|
|
1662
|
+
});
|
|
1663
|
+
const drGroupPermissions = drGroups.command("permissions").description("Manage a group's per-item view/download permissions");
|
|
1664
|
+
drGroupPermissions.command("get <id> <gid>").description(
|
|
1665
|
+
"List the group's access controls. Items without an entry are invisible to the group."
|
|
1666
|
+
).option("-l, --limit <n>", "max results (1-100)", "100").option("-c, --cursor <id>", "pagination cursor").option("--json", "output raw JSON").action(
|
|
1667
|
+
async (id, gid, opts) => {
|
|
1668
|
+
if (opts.json) setRuntime({ json: true });
|
|
1669
|
+
try {
|
|
1670
|
+
const res = await api.listDataroomGroupPermissions(id, gid, {
|
|
1671
|
+
limit: opts.limit ? Number(opts.limit) : void 0,
|
|
1672
|
+
cursor: opts.cursor
|
|
1673
|
+
});
|
|
1674
|
+
emit(res, () => {
|
|
1675
|
+
const rows = res.data.map((p) => ({
|
|
1676
|
+
item_id: p.item_id,
|
|
1677
|
+
type: p.item_type === "dataroom_document" ? "document" : "folder",
|
|
1678
|
+
view: p.can_view ? "yes" : "",
|
|
1679
|
+
download: p.can_download ? "yes" : ""
|
|
1680
|
+
}));
|
|
1681
|
+
const out = table(rows, ["item_id", "type", "view", "download"]);
|
|
1682
|
+
return res.next_cursor ? out + chalk5.dim(`
|
|
1683
|
+
|
|
1684
|
+
More results: --cursor ${res.next_cursor}`) : out;
|
|
1685
|
+
});
|
|
1686
|
+
} catch (err) {
|
|
1687
|
+
die(err);
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
);
|
|
1691
|
+
drGroupPermissions.command("set <id> <gid>").description(
|
|
1692
|
+
"Upsert per-item permissions (delta: omitted items keep their state; ancestor folders of visible items are auto-shown). Item ids come from `datarooms documents` / `datarooms folders list`."
|
|
1693
|
+
).option(
|
|
1694
|
+
"--file <path>",
|
|
1695
|
+
"JSON array of { item_id, item_type, can_view, can_download }"
|
|
1696
|
+
).option("--item <itemId>", "single item id (use with --type/--view/--download)").option("--type <document|folder>", "item type for --item").option("--view <on|off>", "allow viewing (default on)").option("--download <on|off>", "allow downloading (default off)").action(
|
|
1697
|
+
async (id, gid, opts) => {
|
|
1698
|
+
try {
|
|
1699
|
+
const permissions = parsePermissionEntries(opts);
|
|
1700
|
+
const res = await api.setDataroomGroupPermissions(id, gid, {
|
|
1701
|
+
permissions
|
|
1702
|
+
});
|
|
1703
|
+
emit(
|
|
1704
|
+
res,
|
|
1705
|
+
() => chalk5.green("\u2713") + ` ${res.data.length} permission row(s) now effective:
|
|
1706
|
+
` + table(
|
|
1707
|
+
res.data.map((p) => ({
|
|
1708
|
+
item_id: p.item_id,
|
|
1709
|
+
type: p.item_type === "dataroom_document" ? "document" : "folder",
|
|
1710
|
+
view: p.can_view ? "yes" : "",
|
|
1711
|
+
download: p.can_download ? "yes" : ""
|
|
1712
|
+
})),
|
|
1713
|
+
["item_id", "type", "view", "download"]
|
|
1714
|
+
)
|
|
1715
|
+
);
|
|
1716
|
+
} catch (err) {
|
|
1717
|
+
die(err);
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
);
|
|
1347
1721
|
const drFolders = dr.command("folders").description("Manage folders inside a dataroom");
|
|
1348
1722
|
drFolders.command("list <id>").description("List folders in a dataroom").option(
|
|
1349
1723
|
"--parent <fid>",
|
|
@@ -2164,7 +2538,7 @@ function addWatermarkOptions(cmd) {
|
|
|
2164
2538
|
}
|
|
2165
2539
|
function registerLinksCommands(program2) {
|
|
2166
2540
|
const links = program2.command("links").description("Manage share links");
|
|
2167
|
-
links.command("list").description("List share links").option("-l, --limit <n>", "max results (1-100)", "25").option("-c, --cursor <id>", "pagination cursor").option("--document <id>", "filter by document id").option("--dataroom <id>", "filter by dataroom id").option("--json", "output raw JSON (same as --json on the root command)").action(
|
|
2541
|
+
links.command("list").description("List share links").option("-l, --limit <n>", "max results (1-100)", "25").option("-c, --cursor <id>", "pagination cursor").option("--document <id>", "filter by document id").option("--dataroom <id>", "filter by dataroom id").option("--group <gid>", "filter by dataroom group id (group links only)").option("--json", "output raw JSON (same as --json on the root command)").action(
|
|
2168
2542
|
async (opts) => {
|
|
2169
2543
|
if (opts.json) setRuntime({ json: true });
|
|
2170
2544
|
try {
|
|
@@ -2172,7 +2546,8 @@ function registerLinksCommands(program2) {
|
|
|
2172
2546
|
limit: opts.limit ? Number(opts.limit) : void 0,
|
|
2173
2547
|
cursor: opts.cursor,
|
|
2174
2548
|
document_id: opts.document,
|
|
2175
|
-
dataroom_id: opts.dataroom
|
|
2549
|
+
dataroom_id: opts.dataroom,
|
|
2550
|
+
group_id: opts.group
|
|
2176
2551
|
});
|
|
2177
2552
|
emit(res, () => {
|
|
2178
2553
|
const rows = res.data.map((l) => ({
|
|
@@ -2201,7 +2576,10 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
2201
2576
|
}
|
|
2202
2577
|
});
|
|
2203
2578
|
addWatermarkOptions(
|
|
2204
|
-
links.command("create").description("Create a share link for a document or dataroom").option("--document <id>", "document id").option("--dataroom <id>", "dataroom id").option(
|
|
2579
|
+
links.command("create").description("Create a share link for a document or dataroom").option("--document <id>", "document id").option("--dataroom <id>", "dataroom id").option(
|
|
2580
|
+
"--group <gid>",
|
|
2581
|
+
"scope to a dataroom group (dataroom links only; forces email protection)"
|
|
2582
|
+
).option("-n, --name <name>", "link name").option("--expires <iso-date>", "expiration date (ISO 8601)").option("--password <pw>", "require a password to view").option("--email-protected", "require email before viewing", false).option("--allow-download", "allow viewer to download the file", false).option(
|
|
2205
2583
|
"--confidential-view",
|
|
2206
2584
|
"reveal only a narrow band of each page at a time; blurs the rest to prevent full-page screenshots",
|
|
2207
2585
|
false
|
|
@@ -2212,11 +2590,16 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
2212
2590
|
if (!opts.document && !opts.dataroom) {
|
|
2213
2591
|
throw new Error("Either --document <id> or --dataroom <id> is required.");
|
|
2214
2592
|
}
|
|
2593
|
+
if (opts.group && !opts.dataroom) {
|
|
2594
|
+
throw new Error("--group requires --dataroom <id>.");
|
|
2595
|
+
}
|
|
2215
2596
|
const watermarkConfig = parseWatermarkConfig(opts);
|
|
2216
2597
|
const enableWatermark = opts.watermark || watermarkConfig !== void 0;
|
|
2217
2598
|
const link = await api.createLink({
|
|
2218
2599
|
document_id: opts.document,
|
|
2219
2600
|
dataroom_id: opts.dataroom,
|
|
2601
|
+
audience_type: opts.group ? "group" : void 0,
|
|
2602
|
+
group_id: opts.group,
|
|
2220
2603
|
name: opts.name,
|
|
2221
2604
|
expires_at: opts.expires,
|
|
2222
2605
|
password: opts.password,
|
|
@@ -2236,7 +2619,13 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
2236
2619
|
}
|
|
2237
2620
|
);
|
|
2238
2621
|
addWatermarkOptions(
|
|
2239
|
-
links.command("update <id>").description("Update an existing share link").option(
|
|
2622
|
+
links.command("update <id>").description("Update an existing share link").option(
|
|
2623
|
+
"--audience <general|group>",
|
|
2624
|
+
"switch the link's audience (group links need --group or an existing group)"
|
|
2625
|
+
).option(
|
|
2626
|
+
"--group <gid>",
|
|
2627
|
+
"dataroom group id (with --audience group, or alone to swap the group of a group link)"
|
|
2628
|
+
).option("-n, --name <name>").option("--expires <iso-date>", "expiration date (ISO 8601), or empty string to clear").option("--password <pw>", "set a password (empty string to clear)").option("--email-protected <on|off>").option("--email-authenticated <on|off>").option("--allow-download <on|off>").option(
|
|
2240
2629
|
"--allow-list <items>",
|
|
2241
2630
|
"comma-separated email/domain allow list (e.g. '@acme.com,bob@x.com')"
|
|
2242
2631
|
).option("--deny-list <items>", "comma-separated email/domain deny list").option("--watermark <on|off>", "enable watermark overlay").option("--watermark-clear", "clear the existing watermark config", false).option("--screenshot-protection <on|off>", "blur on screenshot").option(
|
|
@@ -2257,6 +2646,16 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
2257
2646
|
};
|
|
2258
2647
|
const list = (v) => v === void 0 ? void 0 : v === "" ? [] : v.split(",").map((s) => s.trim()).filter(Boolean);
|
|
2259
2648
|
const body = {};
|
|
2649
|
+
if (opts.audience !== void 0) {
|
|
2650
|
+
const norm = opts.audience.toLowerCase();
|
|
2651
|
+
if (norm !== "general" && norm !== "group") {
|
|
2652
|
+
throw new Error(
|
|
2653
|
+
`Invalid value for --audience: ${JSON.stringify(opts.audience)} (expected "general" or "group").`
|
|
2654
|
+
);
|
|
2655
|
+
}
|
|
2656
|
+
body.audience_type = norm;
|
|
2657
|
+
}
|
|
2658
|
+
if (opts.group !== void 0) body.group_id = opts.group;
|
|
2260
2659
|
if (opts.name !== void 0) body.name = opts.name;
|
|
2261
2660
|
if (opts.expires !== void 0)
|
|
2262
2661
|
body.expires_at = opts.expires === "" ? null : opts.expires;
|
|
@@ -2317,6 +2716,64 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
2317
2716
|
die(err);
|
|
2318
2717
|
}
|
|
2319
2718
|
});
|
|
2719
|
+
const linkPermissions = links.command("permissions").description(
|
|
2720
|
+
"Per-item file permissions for dataroom links (ignored on group-audience links \u2014 the group's permissions win)"
|
|
2721
|
+
);
|
|
2722
|
+
linkPermissions.command("get <id>").description("List a dataroom link's per-item permission overrides").option("--json", "output raw JSON").action(async (id, opts) => {
|
|
2723
|
+
if (opts.json) setRuntime({ json: true });
|
|
2724
|
+
try {
|
|
2725
|
+
const res = await api.getLinkPermissions(id);
|
|
2726
|
+
emit(res, () => {
|
|
2727
|
+
if (res.data.length === 0) {
|
|
2728
|
+
return chalk9.dim(
|
|
2729
|
+
"No per-link overrides \u2014 viewers see the full dataroom."
|
|
2730
|
+
);
|
|
2731
|
+
}
|
|
2732
|
+
const rows = res.data.map((p) => ({
|
|
2733
|
+
item_id: p.item_id,
|
|
2734
|
+
type: p.item_type === "dataroom_document" ? "document" : "folder",
|
|
2735
|
+
view: p.can_view ? "yes" : "",
|
|
2736
|
+
download: p.can_download ? "yes" : ""
|
|
2737
|
+
}));
|
|
2738
|
+
return table(rows, ["item_id", "type", "view", "download"]);
|
|
2739
|
+
});
|
|
2740
|
+
} catch (err) {
|
|
2741
|
+
die(err);
|
|
2742
|
+
}
|
|
2743
|
+
});
|
|
2744
|
+
linkPermissions.command("set <id>").description(
|
|
2745
|
+
"Replace a dataroom link's per-item permissions (full replace: items not listed lose their override; --clear removes all overrides and hides every item). Item ids come from `datarooms documents` / `datarooms folders list`."
|
|
2746
|
+
).option(
|
|
2747
|
+
"--file <path>",
|
|
2748
|
+
"JSON array of { item_id, item_type, can_view, can_download }"
|
|
2749
|
+
).option("--item <itemId>", "single item id (use with --type/--view/--download)").option("--type <document|folder>", "item type for --item").option("--view <on|off>", "allow viewing (default on)").option("--download <on|off>", "allow downloading (default off)").option("--clear", "remove all overrides (hides every item on this link)", false).action(
|
|
2750
|
+
async (id, opts) => {
|
|
2751
|
+
try {
|
|
2752
|
+
if (opts.clear && (opts.file || opts.item)) {
|
|
2753
|
+
throw new Error("Pass either --clear or permission input, not both.");
|
|
2754
|
+
}
|
|
2755
|
+
const permissions = opts.clear ? [] : parsePermissionEntries(opts);
|
|
2756
|
+
const res = await api.setLinkPermissions(id, { permissions });
|
|
2757
|
+
emit(res, () => {
|
|
2758
|
+
if (res.data.length === 0) {
|
|
2759
|
+
return chalk9.green("\u2713") + " All overrides cleared \u2014 every item on this link is now hidden.";
|
|
2760
|
+
}
|
|
2761
|
+
return chalk9.green("\u2713") + ` ${res.data.length} permission row(s) now effective:
|
|
2762
|
+
` + table(
|
|
2763
|
+
res.data.map((p) => ({
|
|
2764
|
+
item_id: p.item_id,
|
|
2765
|
+
type: p.item_type === "dataroom_document" ? "document" : "folder",
|
|
2766
|
+
view: p.can_view ? "yes" : "",
|
|
2767
|
+
download: p.can_download ? "yes" : ""
|
|
2768
|
+
})),
|
|
2769
|
+
["item_id", "type", "view", "download"]
|
|
2770
|
+
);
|
|
2771
|
+
});
|
|
2772
|
+
} catch (err) {
|
|
2773
|
+
die(err);
|
|
2774
|
+
}
|
|
2775
|
+
}
|
|
2776
|
+
);
|
|
2320
2777
|
}
|
|
2321
2778
|
function truncate5(s, n) {
|
|
2322
2779
|
const clean = sanitizeForTerminal(s);
|