papermark 0.9.0 → 0.10.1
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 +211 -44
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -94,6 +94,86 @@ function getRuntime() {
|
|
|
94
94
|
return current;
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
// package.json
|
|
98
|
+
var package_default = {
|
|
99
|
+
name: "papermark",
|
|
100
|
+
version: "0.10.1",
|
|
101
|
+
description: "Command-line interface for Papermark \u2014 share documents, create data rooms, generate access links, and read analytics.",
|
|
102
|
+
license: "MIT",
|
|
103
|
+
homepage: "https://www.papermark.com",
|
|
104
|
+
repository: {
|
|
105
|
+
type: "git",
|
|
106
|
+
url: "git+https://github.com/papermark/papermark-cli.git"
|
|
107
|
+
},
|
|
108
|
+
bugs: {
|
|
109
|
+
url: "https://github.com/papermark/papermark-cli/issues"
|
|
110
|
+
},
|
|
111
|
+
keywords: [
|
|
112
|
+
"papermark",
|
|
113
|
+
"dataroom",
|
|
114
|
+
"datarooms",
|
|
115
|
+
"data room",
|
|
116
|
+
"virtual data room",
|
|
117
|
+
"document sharing",
|
|
118
|
+
"secure file sharing",
|
|
119
|
+
"access links",
|
|
120
|
+
"analytics",
|
|
121
|
+
"cli"
|
|
122
|
+
],
|
|
123
|
+
type: "module",
|
|
124
|
+
bin: {
|
|
125
|
+
papermark: "dist/index.js"
|
|
126
|
+
},
|
|
127
|
+
files: [
|
|
128
|
+
"dist",
|
|
129
|
+
"docs",
|
|
130
|
+
"skills",
|
|
131
|
+
"openai.yaml",
|
|
132
|
+
"README.md",
|
|
133
|
+
"LICENSE"
|
|
134
|
+
],
|
|
135
|
+
engines: {
|
|
136
|
+
node: ">=24"
|
|
137
|
+
},
|
|
138
|
+
scripts: {
|
|
139
|
+
build: "tsup",
|
|
140
|
+
dev: "tsx src/index.ts",
|
|
141
|
+
typecheck: "tsc --noEmit",
|
|
142
|
+
test: "vitest run",
|
|
143
|
+
"test:watch": "vitest",
|
|
144
|
+
changeset: "changeset",
|
|
145
|
+
version: "changeset version",
|
|
146
|
+
release: "npm run build && changeset publish",
|
|
147
|
+
prepublishOnly: "npm run build"
|
|
148
|
+
},
|
|
149
|
+
dependencies: {
|
|
150
|
+
chalk: "^5.3.0",
|
|
151
|
+
commander: "^14.0.3",
|
|
152
|
+
conf: "^13.0.1",
|
|
153
|
+
"mime-types": "^3.0.2",
|
|
154
|
+
oauth4webapi: "^3.8.5",
|
|
155
|
+
open: "^11.0.0",
|
|
156
|
+
ora: "^9.4.0",
|
|
157
|
+
prompts: "^2.4.2"
|
|
158
|
+
},
|
|
159
|
+
devDependencies: {
|
|
160
|
+
"@changesets/changelog-github": "^0.6.0",
|
|
161
|
+
"@changesets/cli": "^2.31.0",
|
|
162
|
+
"@types/mime-types": "^3.0.1",
|
|
163
|
+
"@types/node": "^22.13.5",
|
|
164
|
+
"@types/prompts": "^2.4.9",
|
|
165
|
+
tsup: "^8.3.5",
|
|
166
|
+
tsx: "^4.21.0",
|
|
167
|
+
typescript: "^5.7.2",
|
|
168
|
+
vitest: "^4.1.5"
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// src/version.ts
|
|
173
|
+
var VERSION = package_default.version;
|
|
174
|
+
var CLIENT_ID = "cli";
|
|
175
|
+
var USER_AGENT = `papermark-cli/${VERSION} (node ${process.version}; ${process.platform} ${process.arch})`;
|
|
176
|
+
|
|
97
177
|
// src/client.ts
|
|
98
178
|
var ApiError = class extends Error {
|
|
99
179
|
code;
|
|
@@ -161,7 +241,15 @@ function buildUrl(path, query) {
|
|
|
161
241
|
async function request(path, opts = {}) {
|
|
162
242
|
const headers = {
|
|
163
243
|
Accept: "application/json",
|
|
164
|
-
...opts.headers ?? {}
|
|
244
|
+
...opts.headers ?? {},
|
|
245
|
+
// Identify the caller so the API can attribute usage to the CLI (vs the
|
|
246
|
+
// MCP server or raw HTTP) and the client version. Dedicated headers keep
|
|
247
|
+
// server-side parsing unambiguous; the User-Agent mirrors them for
|
|
248
|
+
// proxy/access logs. Set last so attribution can't be spoofed or dropped
|
|
249
|
+
// by caller-supplied headers.
|
|
250
|
+
"User-Agent": USER_AGENT,
|
|
251
|
+
"x-papermark-client": CLIENT_ID,
|
|
252
|
+
"x-papermark-client-version": VERSION
|
|
165
253
|
};
|
|
166
254
|
if (!opts.anonymous) {
|
|
167
255
|
const token = getToken();
|
|
@@ -205,7 +293,8 @@ async function request(path, opts = {}) {
|
|
|
205
293
|
debug("http", "network error after", `${Date.now() - started}ms`, String(err));
|
|
206
294
|
throw new NetworkError(url, err);
|
|
207
295
|
}
|
|
208
|
-
|
|
296
|
+
const requestId = res.headers.get("x-request-id") ?? "";
|
|
297
|
+
debug("http", method, url, `\u2192 ${res.status}`, requestId, `(${Date.now() - started}ms)`);
|
|
209
298
|
if (res.status === 204) return void 0;
|
|
210
299
|
const text = await res.text();
|
|
211
300
|
const parsed = text ? safeParseJson(text) : null;
|
|
@@ -656,7 +745,7 @@ import ora from "ora";
|
|
|
656
745
|
// src/oauth.ts
|
|
657
746
|
import * as oauth from "oauth4webapi";
|
|
658
747
|
import open from "open";
|
|
659
|
-
var
|
|
748
|
+
var CLIENT_ID2 = "papermark-cli";
|
|
660
749
|
var DEFAULT_SCOPES = [
|
|
661
750
|
"openid",
|
|
662
751
|
"offline_access",
|
|
@@ -697,7 +786,7 @@ async function requestDeviceAuthorization(as, scopes) {
|
|
|
697
786
|
);
|
|
698
787
|
}
|
|
699
788
|
const body = new URLSearchParams({
|
|
700
|
-
client_id:
|
|
789
|
+
client_id: CLIENT_ID2,
|
|
701
790
|
scope: scopes.join(" ")
|
|
702
791
|
});
|
|
703
792
|
const json2 = await postFormJson(
|
|
@@ -765,7 +854,7 @@ async function pollForToken(as, deviceCode, {
|
|
|
765
854
|
const body = new URLSearchParams({
|
|
766
855
|
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
767
856
|
device_code: deviceCode,
|
|
768
|
-
client_id:
|
|
857
|
+
client_id: CLIENT_ID2
|
|
769
858
|
});
|
|
770
859
|
let parsed;
|
|
771
860
|
try {
|
|
@@ -790,6 +879,28 @@ async function tryOpenBrowser(url) {
|
|
|
790
879
|
} catch {
|
|
791
880
|
}
|
|
792
881
|
}
|
|
882
|
+
async function revokeToken(token) {
|
|
883
|
+
try {
|
|
884
|
+
const issuer = deriveIssuer();
|
|
885
|
+
const as = await discover(issuer);
|
|
886
|
+
if (!as.revocation_endpoint) return "unsupported";
|
|
887
|
+
const res = await fetch(as.revocation_endpoint, {
|
|
888
|
+
method: "POST",
|
|
889
|
+
headers: {
|
|
890
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
891
|
+
Accept: "application/json"
|
|
892
|
+
},
|
|
893
|
+
body: new URLSearchParams({
|
|
894
|
+
token,
|
|
895
|
+
token_type_hint: "access_token",
|
|
896
|
+
client_id: CLIENT_ID2
|
|
897
|
+
})
|
|
898
|
+
});
|
|
899
|
+
return res.ok ? "revoked" : "failed";
|
|
900
|
+
} catch {
|
|
901
|
+
return "failed";
|
|
902
|
+
}
|
|
903
|
+
}
|
|
793
904
|
|
|
794
905
|
// src/commands/auth.ts
|
|
795
906
|
function registerAuthCommands(program2) {
|
|
@@ -814,9 +925,24 @@ function registerAuthCommands(program2) {
|
|
|
814
925
|
}
|
|
815
926
|
}
|
|
816
927
|
);
|
|
817
|
-
program2.command("logout").description("Remove the stored API token").action(() => {
|
|
928
|
+
program2.command("logout").description("Remove the stored API token").action(async () => {
|
|
929
|
+
const token = getToken();
|
|
930
|
+
const source = getTokenSource();
|
|
931
|
+
const revocation = token && source === "config" ? await revokeToken(token) : "skipped";
|
|
818
932
|
clearToken();
|
|
819
|
-
|
|
933
|
+
if (revocation === "skipped" && (source === "env" || source === "credentials-file")) {
|
|
934
|
+
process.stderr.write(
|
|
935
|
+
chalk3.dim(`Note: token comes from ${source}; not revoked server-side.`) + "\n"
|
|
936
|
+
);
|
|
937
|
+
} else if (revocation === "failed") {
|
|
938
|
+
process.stderr.write(
|
|
939
|
+
chalk3.yellow("! ") + "Could not revoke the token server-side; it remains valid until expiry.\n"
|
|
940
|
+
);
|
|
941
|
+
}
|
|
942
|
+
emit(
|
|
943
|
+
{ removed: true, revocation },
|
|
944
|
+
() => revocation === "revoked" ? chalk3.green("\u2713") + " Token revoked and removed." : chalk3.green("\u2713") + " Token removed."
|
|
945
|
+
);
|
|
820
946
|
});
|
|
821
947
|
program2.command("whoami").description("Show the active token and API URL").action(() => {
|
|
822
948
|
const token = getToken();
|
|
@@ -1203,6 +1329,18 @@ function parsePermissionEntries(opts) {
|
|
|
1203
1329
|
);
|
|
1204
1330
|
}
|
|
1205
1331
|
|
|
1332
|
+
// src/validate.ts
|
|
1333
|
+
function parseLimit(value) {
|
|
1334
|
+
if (value === void 0) return void 0;
|
|
1335
|
+
const n = Number(value);
|
|
1336
|
+
if (!Number.isInteger(n) || n < 1 || n > 100) {
|
|
1337
|
+
throw new ValidationError(
|
|
1338
|
+
`Invalid --limit ${JSON.stringify(value)}. Expected an integer 1-100.`
|
|
1339
|
+
);
|
|
1340
|
+
}
|
|
1341
|
+
return n;
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1206
1344
|
// src/commands/datarooms.ts
|
|
1207
1345
|
function registerDataroomsCommands(program2) {
|
|
1208
1346
|
const dr = program2.command("datarooms").alias("dr").description("Manage datarooms");
|
|
@@ -1211,7 +1349,7 @@ function registerDataroomsCommands(program2) {
|
|
|
1211
1349
|
if (opts.json) setRuntime({ json: true });
|
|
1212
1350
|
try {
|
|
1213
1351
|
const res = await api.listDatarooms({
|
|
1214
|
-
limit:
|
|
1352
|
+
limit: parseLimit(opts.limit),
|
|
1215
1353
|
cursor: opts.cursor,
|
|
1216
1354
|
query: opts.query
|
|
1217
1355
|
});
|
|
@@ -1280,14 +1418,14 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
1280
1418
|
const norm = v.toLowerCase();
|
|
1281
1419
|
if (norm === "on") return true;
|
|
1282
1420
|
if (norm === "off") return false;
|
|
1283
|
-
throw new
|
|
1421
|
+
throw new ValidationError(
|
|
1284
1422
|
`Invalid value for ${flag}: ${JSON.stringify(v)} (expected "on" or "off").`
|
|
1285
1423
|
);
|
|
1286
1424
|
};
|
|
1287
1425
|
const bulk = tri(opts.bulkDownload, "--bulk-download");
|
|
1288
1426
|
if (bulk !== void 0) body.allow_bulk_download = bulk;
|
|
1289
1427
|
if (Object.keys(body).length === 0) {
|
|
1290
|
-
throw new
|
|
1428
|
+
throw new ValidationError(
|
|
1291
1429
|
"Pass at least one field to update (e.g. --name, --description, --bulk-download off)."
|
|
1292
1430
|
);
|
|
1293
1431
|
}
|
|
@@ -1310,7 +1448,7 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
1310
1448
|
try {
|
|
1311
1449
|
const res = await api.listLinks({
|
|
1312
1450
|
dataroom_id: id,
|
|
1313
|
-
limit:
|
|
1451
|
+
limit: parseLimit(opts.limit),
|
|
1314
1452
|
cursor: opts.cursor
|
|
1315
1453
|
});
|
|
1316
1454
|
emit(res, () => {
|
|
@@ -1339,7 +1477,7 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
1339
1477
|
try {
|
|
1340
1478
|
const res = await api.listVisitors({
|
|
1341
1479
|
dataroom_id: id,
|
|
1342
|
-
limit:
|
|
1480
|
+
limit: parseLimit(opts.limit),
|
|
1343
1481
|
cursor: opts.cursor,
|
|
1344
1482
|
email: opts.email
|
|
1345
1483
|
});
|
|
@@ -1454,12 +1592,12 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
1454
1592
|
try {
|
|
1455
1593
|
const folderIsRoot = opts.folderId === "" || opts.folderId === "root";
|
|
1456
1594
|
if (opts.root && opts.folderId !== void 0 && !folderIsRoot) {
|
|
1457
|
-
throw new
|
|
1595
|
+
throw new ValidationError(
|
|
1458
1596
|
"Pass either --root or --folder-id <fid>, not both."
|
|
1459
1597
|
);
|
|
1460
1598
|
}
|
|
1461
1599
|
if (!opts.root && opts.folderId === void 0) {
|
|
1462
|
-
throw new
|
|
1600
|
+
throw new ValidationError(
|
|
1463
1601
|
'Pass --folder-id <fid>, or --root (or --folder-id "") to move to the dataroom root.'
|
|
1464
1602
|
);
|
|
1465
1603
|
}
|
|
@@ -1727,7 +1865,7 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
1727
1865
|
if (opts.json) setRuntime({ json: true });
|
|
1728
1866
|
try {
|
|
1729
1867
|
const res = await api.listDataroomFolders(id, {
|
|
1730
|
-
limit:
|
|
1868
|
+
limit: parseLimit(opts.limit),
|
|
1731
1869
|
cursor: opts.cursor,
|
|
1732
1870
|
parent_id: opts.parent
|
|
1733
1871
|
});
|
|
@@ -1786,7 +1924,7 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
1786
1924
|
if (opts.color !== void 0)
|
|
1787
1925
|
body.color = opts.color === "" ? null : opts.color;
|
|
1788
1926
|
if (Object.keys(body).length === 0) {
|
|
1789
|
-
throw new
|
|
1927
|
+
throw new ValidationError(
|
|
1790
1928
|
"Pass at least one of --name, --icon, --color to update."
|
|
1791
1929
|
);
|
|
1792
1930
|
}
|
|
@@ -1827,7 +1965,7 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
1827
1965
|
async (id, fid, opts) => {
|
|
1828
1966
|
try {
|
|
1829
1967
|
if (opts.parent === void 0) {
|
|
1830
|
-
throw new
|
|
1968
|
+
throw new ValidationError(
|
|
1831
1969
|
"Pass --parent <fid> (use empty string to move to the root)."
|
|
1832
1970
|
);
|
|
1833
1971
|
}
|
|
@@ -1850,7 +1988,7 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
1850
1988
|
if (opts.json) setRuntime({ json: true });
|
|
1851
1989
|
try {
|
|
1852
1990
|
const res = await api.listDataroomDocuments(id, {
|
|
1853
|
-
limit:
|
|
1991
|
+
limit: parseLimit(opts.limit),
|
|
1854
1992
|
cursor: opts.cursor,
|
|
1855
1993
|
folder_id: opts.folder
|
|
1856
1994
|
});
|
|
@@ -1986,7 +2124,7 @@ function registerDocumentsCommands(program2) {
|
|
|
1986
2124
|
if (opts.json) setRuntime({ json: true });
|
|
1987
2125
|
try {
|
|
1988
2126
|
const res = await api.listDocuments({
|
|
1989
|
-
limit:
|
|
2127
|
+
limit: parseLimit(opts.limit),
|
|
1990
2128
|
cursor: opts.cursor
|
|
1991
2129
|
});
|
|
1992
2130
|
emit(res, () => {
|
|
@@ -2019,7 +2157,7 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
2019
2157
|
try {
|
|
2020
2158
|
const res = await api.searchDocuments(
|
|
2021
2159
|
query,
|
|
2022
|
-
|
|
2160
|
+
parseLimit(opts.limit)
|
|
2023
2161
|
);
|
|
2024
2162
|
emit(res, () => {
|
|
2025
2163
|
const rows = res.data.map((d) => ({
|
|
@@ -2043,7 +2181,7 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
2043
2181
|
body.folder_id = opts.folderId === "" ? null : opts.folderId;
|
|
2044
2182
|
}
|
|
2045
2183
|
if (Object.keys(body).length === 0) {
|
|
2046
|
-
throw new
|
|
2184
|
+
throw new ValidationError(
|
|
2047
2185
|
"Pass at least one of --name or --folder-id to update."
|
|
2048
2186
|
);
|
|
2049
2187
|
}
|
|
@@ -2073,8 +2211,13 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
2073
2211
|
async (filePath, opts) => {
|
|
2074
2212
|
const spinner = ora2();
|
|
2075
2213
|
try {
|
|
2076
|
-
const stats = await stat(filePath)
|
|
2077
|
-
|
|
2214
|
+
const stats = await stat(filePath).catch((statErr) => {
|
|
2215
|
+
throw new ValidationError(
|
|
2216
|
+
`Cannot read ${filePath}: ${statErr.message}`,
|
|
2217
|
+
{ code: statErr.code }
|
|
2218
|
+
);
|
|
2219
|
+
});
|
|
2220
|
+
if (!stats.isFile()) throw new ValidationError(`${filePath} is not a file.`);
|
|
2078
2221
|
const fileName = opts.name ?? basename(filePath);
|
|
2079
2222
|
const contentType = lookupMimeType(filePath) || "application/octet-stream";
|
|
2080
2223
|
spinner.start("Requesting upload URL");
|
|
@@ -2083,6 +2226,15 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
2083
2226
|
content_type: contentType,
|
|
2084
2227
|
content_length: stats.size
|
|
2085
2228
|
});
|
|
2229
|
+
if (getRuntime().dryRun) {
|
|
2230
|
+
spinner.stop();
|
|
2231
|
+
process.stderr.write(
|
|
2232
|
+
`[dry-run] PUT <presigned upload_url from the response above> (file: ${filePath}, ${humanSize(stats.size)})
|
|
2233
|
+
[dry-run] POST ${"/v1/documents"} (name, upload_id, folder_id, create_link)
|
|
2234
|
+
`
|
|
2235
|
+
);
|
|
2236
|
+
return;
|
|
2237
|
+
}
|
|
2086
2238
|
spinner.succeed("Got presigned URL");
|
|
2087
2239
|
spinner.start(`Uploading ${humanSize(stats.size)}`);
|
|
2088
2240
|
const fileStream = Readable.toWeb(createReadStream(filePath));
|
|
@@ -2193,8 +2345,13 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
2193
2345
|
versions.command("add <id> <file>").description("Upload a new version of an existing document").action(async (id, filePath) => {
|
|
2194
2346
|
const spinner = ora2();
|
|
2195
2347
|
try {
|
|
2196
|
-
const stats = await stat(filePath)
|
|
2197
|
-
|
|
2348
|
+
const stats = await stat(filePath).catch((statErr) => {
|
|
2349
|
+
throw new ValidationError(
|
|
2350
|
+
`Cannot read ${filePath}: ${statErr.message}`,
|
|
2351
|
+
{ code: statErr.code }
|
|
2352
|
+
);
|
|
2353
|
+
});
|
|
2354
|
+
if (!stats.isFile()) throw new ValidationError(`${filePath} is not a file.`);
|
|
2198
2355
|
const fileName = basename(filePath);
|
|
2199
2356
|
const contentType = lookupMimeType(filePath) || "application/octet-stream";
|
|
2200
2357
|
spinner.start("Requesting upload URL");
|
|
@@ -2203,6 +2360,15 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
2203
2360
|
content_type: contentType,
|
|
2204
2361
|
content_length: stats.size
|
|
2205
2362
|
});
|
|
2363
|
+
if (getRuntime().dryRun) {
|
|
2364
|
+
spinner.stop();
|
|
2365
|
+
process.stderr.write(
|
|
2366
|
+
`[dry-run] PUT <presigned upload_url from the response above> (file: ${filePath}, ${humanSize(stats.size)})
|
|
2367
|
+
[dry-run] POST /v1/documents/${id}/versions (upload_id)
|
|
2368
|
+
`
|
|
2369
|
+
);
|
|
2370
|
+
return;
|
|
2371
|
+
}
|
|
2206
2372
|
spinner.succeed("Got presigned URL");
|
|
2207
2373
|
spinner.start(`Uploading ${humanSize(stats.size)}`);
|
|
2208
2374
|
const fileStream = Readable.toWeb(createReadStream(filePath));
|
|
@@ -2271,6 +2437,7 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
2271
2437
|
});
|
|
2272
2438
|
}
|
|
2273
2439
|
async function finalizeDocumentCreation(doc, wantLink) {
|
|
2440
|
+
if (getRuntime().dryRun) return;
|
|
2274
2441
|
let link = null;
|
|
2275
2442
|
let linkWarning = null;
|
|
2276
2443
|
if (wantLink) {
|
|
@@ -2322,7 +2489,7 @@ function registerFoldersCommands(program2) {
|
|
|
2322
2489
|
if (opts.json) setRuntime({ json: true });
|
|
2323
2490
|
try {
|
|
2324
2491
|
const res = await api.listFolders({
|
|
2325
|
-
limit:
|
|
2492
|
+
limit: parseLimit(opts.limit),
|
|
2326
2493
|
cursor: opts.cursor,
|
|
2327
2494
|
parent_id: opts.parent
|
|
2328
2495
|
});
|
|
@@ -2381,7 +2548,7 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
2381
2548
|
if (opts.color !== void 0)
|
|
2382
2549
|
body.color = opts.color === "" ? null : opts.color;
|
|
2383
2550
|
if (Object.keys(body).length === 0) {
|
|
2384
|
-
throw new
|
|
2551
|
+
throw new ValidationError(
|
|
2385
2552
|
"Pass at least one of --name, --icon, --color to update."
|
|
2386
2553
|
);
|
|
2387
2554
|
}
|
|
@@ -2417,7 +2584,7 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
2417
2584
|
).action(async (id, opts) => {
|
|
2418
2585
|
try {
|
|
2419
2586
|
if (opts.parent === void 0) {
|
|
2420
|
-
throw new
|
|
2587
|
+
throw new ValidationError(
|
|
2421
2588
|
"Pass --parent <id> (use empty string to move to the root)."
|
|
2422
2589
|
);
|
|
2423
2590
|
}
|
|
@@ -2475,42 +2642,42 @@ function parseWatermarkConfig(opts) {
|
|
|
2475
2642
|
if (provided.length === 0) return void 0;
|
|
2476
2643
|
const missing = Object.entries(fields).filter(([, v]) => v === void 0).map(([k]) => flagNames[k]);
|
|
2477
2644
|
if (missing.length > 0) {
|
|
2478
|
-
throw new
|
|
2645
|
+
throw new ValidationError(
|
|
2479
2646
|
`Watermark config is partial. Missing: ${missing.join(", ")}.`
|
|
2480
2647
|
);
|
|
2481
2648
|
}
|
|
2482
2649
|
const tiled = fields.is_tiled.toLowerCase() === "true" || fields.is_tiled.toLowerCase() === "on";
|
|
2483
2650
|
const tiledOff = fields.is_tiled.toLowerCase() === "false" || fields.is_tiled.toLowerCase() === "off";
|
|
2484
2651
|
if (!tiled && !tiledOff) {
|
|
2485
|
-
throw new
|
|
2652
|
+
throw new ValidationError(
|
|
2486
2653
|
`Invalid --watermark-tiled value ${JSON.stringify(fields.is_tiled)} (expected on/off).`
|
|
2487
2654
|
);
|
|
2488
2655
|
}
|
|
2489
2656
|
if (!WATERMARK_POSITIONS.includes(fields.position)) {
|
|
2490
|
-
throw new
|
|
2657
|
+
throw new ValidationError(
|
|
2491
2658
|
`Invalid --watermark-position ${JSON.stringify(fields.position)}. Expected one of: ${WATERMARK_POSITIONS.join(", ")}.`
|
|
2492
2659
|
);
|
|
2493
2660
|
}
|
|
2494
2661
|
const rotation = Number(fields.rotation);
|
|
2495
2662
|
if (!Number.isFinite(rotation) || !WATERMARK_ROTATIONS.includes(rotation)) {
|
|
2496
|
-
throw new
|
|
2663
|
+
throw new ValidationError(
|
|
2497
2664
|
`Invalid --watermark-rotation ${JSON.stringify(fields.rotation)}. Expected one of: ${WATERMARK_ROTATIONS.join(", ")}.`
|
|
2498
2665
|
);
|
|
2499
2666
|
}
|
|
2500
2667
|
if (!/^#([0-9A-Fa-f]{3}){1,2}$/.test(fields.color)) {
|
|
2501
|
-
throw new
|
|
2668
|
+
throw new ValidationError(
|
|
2502
2669
|
`Invalid --watermark-color ${JSON.stringify(fields.color)}. Expected #RGB or #RRGGBB.`
|
|
2503
2670
|
);
|
|
2504
2671
|
}
|
|
2505
2672
|
const fontSize = Number(fields.font_size);
|
|
2506
2673
|
if (!Number.isInteger(fontSize) || fontSize < 1 || fontSize > 96) {
|
|
2507
|
-
throw new
|
|
2674
|
+
throw new ValidationError(
|
|
2508
2675
|
`Invalid --watermark-font-size ${JSON.stringify(fields.font_size)}. Expected integer 1-96.`
|
|
2509
2676
|
);
|
|
2510
2677
|
}
|
|
2511
2678
|
const opacity = Number(fields.opacity);
|
|
2512
2679
|
if (!Number.isFinite(opacity) || opacity < 0 || opacity > 1) {
|
|
2513
|
-
throw new
|
|
2680
|
+
throw new ValidationError(
|
|
2514
2681
|
`Invalid --watermark-opacity ${JSON.stringify(fields.opacity)}. Expected 0-1.`
|
|
2515
2682
|
);
|
|
2516
2683
|
}
|
|
@@ -2543,7 +2710,7 @@ function registerLinksCommands(program2) {
|
|
|
2543
2710
|
if (opts.json) setRuntime({ json: true });
|
|
2544
2711
|
try {
|
|
2545
2712
|
const res = await api.listLinks({
|
|
2546
|
-
limit:
|
|
2713
|
+
limit: parseLimit(opts.limit),
|
|
2547
2714
|
cursor: opts.cursor,
|
|
2548
2715
|
document_id: opts.document,
|
|
2549
2716
|
dataroom_id: opts.dataroom,
|
|
@@ -2608,7 +2775,7 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
2608
2775
|
async (opts) => {
|
|
2609
2776
|
try {
|
|
2610
2777
|
if (!opts.document && !opts.dataroom) {
|
|
2611
|
-
throw new
|
|
2778
|
+
throw new ValidationError("Either --document <id> or --dataroom <id> is required.");
|
|
2612
2779
|
}
|
|
2613
2780
|
if (opts.group && !opts.dataroom) {
|
|
2614
2781
|
throw new Error("--group requires --dataroom <id>.");
|
|
@@ -2677,7 +2844,7 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
2677
2844
|
const norm = v.toLowerCase();
|
|
2678
2845
|
if (norm === "on") return true;
|
|
2679
2846
|
if (norm === "off") return false;
|
|
2680
|
-
throw new
|
|
2847
|
+
throw new ValidationError(
|
|
2681
2848
|
`Invalid value for ${flag}: ${JSON.stringify(v)} (expected "on" or "off").`
|
|
2682
2849
|
);
|
|
2683
2850
|
};
|
|
@@ -2712,7 +2879,7 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
2712
2879
|
if (wm !== void 0) body.enable_watermark = wm;
|
|
2713
2880
|
const watermarkConfig = parseWatermarkConfig(opts);
|
|
2714
2881
|
if (opts.watermarkClear && watermarkConfig !== void 0) {
|
|
2715
|
-
throw new
|
|
2882
|
+
throw new ValidationError(
|
|
2716
2883
|
"Pass either --watermark-clear or --watermark-* flags, not both."
|
|
2717
2884
|
);
|
|
2718
2885
|
}
|
|
@@ -2733,7 +2900,7 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
2733
2900
|
if (opts.domain !== void 0) body.domain = opts.domain;
|
|
2734
2901
|
if (opts.slug !== void 0) body.slug = opts.slug;
|
|
2735
2902
|
if (Object.keys(body).length === 0) {
|
|
2736
|
-
throw new
|
|
2903
|
+
throw new ValidationError(
|
|
2737
2904
|
"Pass at least one field to update (e.g. --name, --expires, --password)."
|
|
2738
2905
|
);
|
|
2739
2906
|
}
|
|
@@ -2832,7 +2999,7 @@ function registerViewsCommands(program2) {
|
|
|
2832
2999
|
if (opts.json) setRuntime({ json: true });
|
|
2833
3000
|
try {
|
|
2834
3001
|
const res = await api.listViews(opts.link, {
|
|
2835
|
-
limit:
|
|
3002
|
+
limit: parseLimit(opts.limit),
|
|
2836
3003
|
cursor: opts.cursor
|
|
2837
3004
|
});
|
|
2838
3005
|
emit(res, () => {
|
|
@@ -2864,7 +3031,7 @@ function registerVisitorsCommands(program2) {
|
|
|
2864
3031
|
if (opts.json) setRuntime({ json: true });
|
|
2865
3032
|
try {
|
|
2866
3033
|
const res = await api.listVisitors({
|
|
2867
|
-
limit:
|
|
3034
|
+
limit: parseLimit(opts.limit),
|
|
2868
3035
|
cursor: opts.cursor,
|
|
2869
3036
|
email: opts.email,
|
|
2870
3037
|
dataroom_id: opts.dataroom
|
|
@@ -2900,7 +3067,7 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
2900
3067
|
if (opts.json) setRuntime({ json: true });
|
|
2901
3068
|
try {
|
|
2902
3069
|
const res = await api.listVisitorViews(id, {
|
|
2903
|
-
limit:
|
|
3070
|
+
limit: parseLimit(opts.limit),
|
|
2904
3071
|
cursor: opts.cursor
|
|
2905
3072
|
});
|
|
2906
3073
|
emit(res, () => {
|
|
@@ -2925,7 +3092,7 @@ More results: --cursor ${res.next_cursor}`) : out;
|
|
|
2925
3092
|
|
|
2926
3093
|
// src/index.ts
|
|
2927
3094
|
var program = new Command2();
|
|
2928
|
-
program.name("papermark").description("Papermark CLI \u2014 manage documents, links, and views").version(
|
|
3095
|
+
program.name("papermark").description("Papermark CLI \u2014 manage documents, links, and views").version(VERSION).option(
|
|
2929
3096
|
"--json",
|
|
2930
3097
|
"emit machine-readable JSON on stdout (auto-enabled when piped)"
|
|
2931
3098
|
).option(
|