docz-cli 0.5.0 → 0.6.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/{chunk-EBJ32KUL.js → chunk-XUT76ACQ.js} +296 -65
- package/dist/chunk-XUT76ACQ.js.map +1 -0
- package/dist/index.js +3 -3
- package/dist/mcp-OHEL4DCQ.js +685 -0
- package/dist/mcp-OHEL4DCQ.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-EBJ32KUL.js.map +0 -1
- package/dist/mcp-26HFT6SQ.js +0 -384
- package/dist/mcp-26HFT6SQ.js.map +0 -1
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/client.ts
|
|
4
|
+
var ConflictError = class extends Error {
|
|
5
|
+
constructor(detail) {
|
|
6
|
+
super(
|
|
7
|
+
"Conflict: file has been modified by others. Please re-read the latest content and re-apply your changes."
|
|
8
|
+
);
|
|
9
|
+
this.detail = detail;
|
|
10
|
+
this.name = "ConflictError";
|
|
11
|
+
}
|
|
12
|
+
};
|
|
4
13
|
var DocSyncClient = class {
|
|
5
14
|
constructor(baseUrl, token) {
|
|
6
15
|
this.baseUrl = baseUrl;
|
|
@@ -48,12 +57,28 @@ var DocSyncClient = class {
|
|
|
48
57
|
`/api/spaces/${spaceId}/tree?path=${encodeURIComponent(path)}`
|
|
49
58
|
);
|
|
50
59
|
}
|
|
60
|
+
async treeFull(spaceId) {
|
|
61
|
+
return this.request(`/api/spaces/${spaceId}/tree/full`);
|
|
62
|
+
}
|
|
51
63
|
// --- Blob ---
|
|
52
64
|
async cat(spaceId, filepath) {
|
|
53
65
|
return this.request(
|
|
54
66
|
`/api/spaces/${spaceId}/blob/${encodeURIComponent(filepath)}`
|
|
55
67
|
);
|
|
56
68
|
}
|
|
69
|
+
async catWithRef(spaceId, filepath) {
|
|
70
|
+
const res = await fetch(
|
|
71
|
+
`${this.baseUrl}/api/spaces/${spaceId}/blob/${encodeURIComponent(filepath)}`,
|
|
72
|
+
{ headers: { Authorization: `Bearer ${this.token}` } }
|
|
73
|
+
);
|
|
74
|
+
if (!res.ok) {
|
|
75
|
+
const body = await res.text().catch(() => "");
|
|
76
|
+
throw new Error(`${res.status} ${res.statusText}: ${body}`.trim());
|
|
77
|
+
}
|
|
78
|
+
const content = await res.text();
|
|
79
|
+
const ref = res.headers.get("X-Git-Ref") ?? "";
|
|
80
|
+
return { content, ref };
|
|
81
|
+
}
|
|
57
82
|
// --- Write ---
|
|
58
83
|
async upload(spaceId, dir, filename, content) {
|
|
59
84
|
const blob = typeof content === "string" ? new Blob([content], { type: "application/octet-stream" }) : new Blob([content], { type: "application/octet-stream" });
|
|
@@ -65,6 +90,31 @@ var DocSyncClient = class {
|
|
|
65
90
|
body: form
|
|
66
91
|
});
|
|
67
92
|
}
|
|
93
|
+
async save(spaceId, path, content, opts) {
|
|
94
|
+
const body = { path, content };
|
|
95
|
+
if (opts?.baseRef) body.base_ref = opts.baseRef;
|
|
96
|
+
if (opts?.message) body.message = opts.message;
|
|
97
|
+
const res = await fetch(
|
|
98
|
+
`${this.baseUrl}/api/spaces/${spaceId}/files/save`,
|
|
99
|
+
{
|
|
100
|
+
method: "POST",
|
|
101
|
+
headers: {
|
|
102
|
+
Authorization: `Bearer ${this.token}`,
|
|
103
|
+
"Content-Type": "application/json"
|
|
104
|
+
},
|
|
105
|
+
body: JSON.stringify(body)
|
|
106
|
+
}
|
|
107
|
+
);
|
|
108
|
+
if (res.status === 409) {
|
|
109
|
+
const data = await res.json();
|
|
110
|
+
throw new ConflictError(data);
|
|
111
|
+
}
|
|
112
|
+
if (!res.ok) {
|
|
113
|
+
const text = await res.text().catch(() => "");
|
|
114
|
+
throw new Error(`${res.status} ${res.statusText}: ${text}`.trim());
|
|
115
|
+
}
|
|
116
|
+
return res.json();
|
|
117
|
+
}
|
|
68
118
|
async mkdir(spaceId, path) {
|
|
69
119
|
await this.request(`/api/spaces/${spaceId}/files/mkdir`, {
|
|
70
120
|
method: "POST",
|
|
@@ -86,6 +136,13 @@ var DocSyncClient = class {
|
|
|
86
136
|
body: JSON.stringify({ old_path: from, new_path: to })
|
|
87
137
|
});
|
|
88
138
|
}
|
|
139
|
+
async rollback(spaceId, filePath, commitHash) {
|
|
140
|
+
await this.request(`/api/spaces/${spaceId}/files/rollback`, {
|
|
141
|
+
method: "POST",
|
|
142
|
+
headers: { "Content-Type": "application/json" },
|
|
143
|
+
body: JSON.stringify({ file_path: filePath, commit_hash: commitHash })
|
|
144
|
+
});
|
|
145
|
+
}
|
|
89
146
|
// --- History ---
|
|
90
147
|
async log(spaceId, filepath) {
|
|
91
148
|
const path = filepath ? `/api/spaces/${spaceId}/log/${encodeURIComponent(filepath)}` : `/api/spaces/${spaceId}/log/`;
|
|
@@ -95,6 +152,48 @@ var DocSyncClient = class {
|
|
|
95
152
|
async trash(spaceId) {
|
|
96
153
|
return this.request(`/api/spaces/${spaceId}/trash`);
|
|
97
154
|
}
|
|
155
|
+
async restore(spaceId, path, commit) {
|
|
156
|
+
await this.request(`/api/spaces/${spaceId}/trash/restore`, {
|
|
157
|
+
method: "POST",
|
|
158
|
+
headers: { "Content-Type": "application/json" },
|
|
159
|
+
body: JSON.stringify({ path, commit })
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
// --- Comments ---
|
|
163
|
+
async listComments(spaceId, filePath) {
|
|
164
|
+
return this.request(
|
|
165
|
+
`/api/spaces/${spaceId}/comments?path=${encodeURIComponent(filePath)}`
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
async createComment(spaceId, filePath, content) {
|
|
169
|
+
return this.request(`/api/spaces/${spaceId}/comments`, {
|
|
170
|
+
method: "POST",
|
|
171
|
+
headers: { "Content-Type": "application/json" },
|
|
172
|
+
body: JSON.stringify({ file_path: filePath, content })
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
async replyComment(spaceId, commentId, content) {
|
|
176
|
+
return this.request(
|
|
177
|
+
`/api/spaces/${spaceId}/comments/${commentId}/replies`,
|
|
178
|
+
{
|
|
179
|
+
method: "POST",
|
|
180
|
+
headers: { "Content-Type": "application/json" },
|
|
181
|
+
body: JSON.stringify({ content })
|
|
182
|
+
}
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
async closeComment(spaceId, commentId) {
|
|
186
|
+
return this.request(`/api/spaces/${spaceId}/comments/${commentId}`, {
|
|
187
|
+
method: "PUT",
|
|
188
|
+
headers: { "Content-Type": "application/json" },
|
|
189
|
+
body: JSON.stringify({ is_closed: true })
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
async deleteComment(spaceId, commentId) {
|
|
193
|
+
await this.request(`/api/spaces/${spaceId}/comments/${commentId}`, {
|
|
194
|
+
method: "DELETE"
|
|
195
|
+
});
|
|
196
|
+
}
|
|
98
197
|
// --- Share Links ---
|
|
99
198
|
async createShareLink(spaceId, filePath, opts) {
|
|
100
199
|
const body = { file_path: filePath };
|
|
@@ -137,7 +236,9 @@ var DocSyncClient = class {
|
|
|
137
236
|
async diffFile(spaceId, filePath, to, from) {
|
|
138
237
|
const params = new URLSearchParams({ to });
|
|
139
238
|
if (from) params.set("from", from);
|
|
140
|
-
return this.request(
|
|
239
|
+
return this.request(
|
|
240
|
+
`/api/spaces/${spaceId}/diff/${encodeURIComponent(filePath)}?${params}`
|
|
241
|
+
);
|
|
141
242
|
}
|
|
142
243
|
async diffSummary(spaceId, to, from) {
|
|
143
244
|
const params = new URLSearchParams({ to });
|
|
@@ -192,7 +293,7 @@ function getConfigPath() {
|
|
|
192
293
|
|
|
193
294
|
// src/commands.ts
|
|
194
295
|
import { readFileSync as readFileSync2 } from "fs";
|
|
195
|
-
import { basename
|
|
296
|
+
import { basename } from "path";
|
|
196
297
|
function getClient() {
|
|
197
298
|
const token = getToken();
|
|
198
299
|
if (!token) {
|
|
@@ -262,7 +363,10 @@ async function resolveTarget(client, args) {
|
|
|
262
363
|
}
|
|
263
364
|
function parseExpires(value) {
|
|
264
365
|
const match = value.match(/^(\d+)([dh])$/);
|
|
265
|
-
if (!match)
|
|
366
|
+
if (!match)
|
|
367
|
+
throw new Error(
|
|
368
|
+
`Invalid expires format: "${value}". Use e.g. 7d, 24h, 30d`
|
|
369
|
+
);
|
|
266
370
|
const [, num, unit] = match;
|
|
267
371
|
const ms = unit === "d" ? Number(num) * 864e5 : Number(num) * 36e5;
|
|
268
372
|
return new Date(Date.now() + ms).toISOString();
|
|
@@ -272,6 +376,14 @@ function extractShareToken(input) {
|
|
|
272
376
|
if (m) return m[1];
|
|
273
377
|
return input;
|
|
274
378
|
}
|
|
379
|
+
async function readStdin() {
|
|
380
|
+
const chunks = [];
|
|
381
|
+
for await (const chunk of process.stdin) {
|
|
382
|
+
chunks.push(chunk);
|
|
383
|
+
}
|
|
384
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
385
|
+
}
|
|
386
|
+
var MAX_SAVE_SIZE = 2 * 1024 * 1024;
|
|
275
387
|
function registerCommands(program) {
|
|
276
388
|
program.command("login").description("Configure DocSync credentials").option("-u, --url <url>", "DocSync server URL").option("-t, --token <token>", "API token").action(async (opts) => {
|
|
277
389
|
const url = opts.url ?? getBaseUrl();
|
|
@@ -308,10 +420,10 @@ function registerCommands(program) {
|
|
|
308
420
|
console.log(`${s.name} ${tag} ${s.member_count} members ${s.id}`);
|
|
309
421
|
}
|
|
310
422
|
});
|
|
311
|
-
program.command("ls").description("List files \u2014 docz ls <space>[:<path>] or <url>").argument("<target...>").action(async (args) => {
|
|
423
|
+
program.command("ls").description("List files \u2014 docz ls <space>[:<path>] or <url>").argument("<target...>").option("-R, --recursive", "Recursively list all files").action(async (args, opts) => {
|
|
312
424
|
const client = getClient();
|
|
313
425
|
const { spaceId, path } = await resolveTarget(client, args);
|
|
314
|
-
const entries = await client.ls(spaceId, path);
|
|
426
|
+
const entries = opts.recursive ? await client.treeFull(spaceId) : await client.ls(spaceId, path);
|
|
315
427
|
if (entries.length === 0) {
|
|
316
428
|
console.log("(empty)");
|
|
317
429
|
return;
|
|
@@ -324,7 +436,7 @@ function registerCommands(program) {
|
|
|
324
436
|
}
|
|
325
437
|
}
|
|
326
438
|
});
|
|
327
|
-
program.command("cat").description("Read file content \u2014 docz cat <space>:<path> or <url>").argument("<target...>").action(async (args) => {
|
|
439
|
+
program.command("cat").description("Read file content \u2014 docz cat <space>:<path> or <url>").argument("<target...>").option("--ref", "Also output Git ref to stderr").action(async (args, opts) => {
|
|
328
440
|
const client = getClient();
|
|
329
441
|
const { spaceId, path } = await resolveTarget(client, args);
|
|
330
442
|
if (!path) {
|
|
@@ -333,8 +445,14 @@ function registerCommands(program) {
|
|
|
333
445
|
);
|
|
334
446
|
process.exit(1);
|
|
335
447
|
}
|
|
336
|
-
|
|
337
|
-
|
|
448
|
+
if (opts.ref) {
|
|
449
|
+
const result = await client.catWithRef(spaceId, path);
|
|
450
|
+
console.error(`ref: ${result.ref}`);
|
|
451
|
+
process.stdout.write(result.content);
|
|
452
|
+
} else {
|
|
453
|
+
const content = await client.cat(spaceId, path);
|
|
454
|
+
process.stdout.write(content);
|
|
455
|
+
}
|
|
338
456
|
});
|
|
339
457
|
program.command("upload").description("Upload file \u2014 docz upload <local-file> <space>[:<dir>]").argument("<file>", "Local file to upload").argument("<target...>").action(async (file, args) => {
|
|
340
458
|
const { space, path: dir } = parseTarget(args);
|
|
@@ -346,36 +464,51 @@ function registerCommands(program) {
|
|
|
346
464
|
const result = await client.upload(s.id, targetDir, filename, content);
|
|
347
465
|
console.log(`Uploaded: ${result.path}`);
|
|
348
466
|
});
|
|
349
|
-
program.command("write").description("Write content to file \u2014 docz write <space>:<path> <content>").argument("<target>", "space:dir/filename.md").argument("<content>", "File content (or - for stdin)").
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
467
|
+
program.command("write").description("Write content to file \u2014 docz write <space>:<path> <content>").argument("<target>", "space:dir/filename.md").argument("<content>", "File content (or - for stdin)").option("--force", "Skip conflict detection").option("-m, --message <msg>", "Custom commit message").action(
|
|
468
|
+
async (target, content, opts) => {
|
|
469
|
+
const { space, path } = parseTarget([target]);
|
|
470
|
+
if (!path) {
|
|
471
|
+
console.error(
|
|
472
|
+
"Error: path is required. Usage: docz write <space>:<dir/filename> <content>"
|
|
473
|
+
);
|
|
474
|
+
process.exit(1);
|
|
475
|
+
}
|
|
476
|
+
const client = getClient();
|
|
477
|
+
const s = await client.resolveSpace(space);
|
|
478
|
+
const body = content === "-" ? await readStdin() : content;
|
|
479
|
+
if (Buffer.byteLength(body, "utf-8") > MAX_SAVE_SIZE) {
|
|
480
|
+
console.error(
|
|
481
|
+
"Error: content exceeds 2MB limit. Use `docz upload` for large files."
|
|
482
|
+
);
|
|
483
|
+
process.exit(1);
|
|
484
|
+
}
|
|
485
|
+
let baseRef;
|
|
486
|
+
if (!opts.force) {
|
|
487
|
+
try {
|
|
488
|
+
const existing = await client.catWithRef(s.id, path);
|
|
489
|
+
baseRef = existing.ref;
|
|
490
|
+
} catch (err) {
|
|
491
|
+
const msg = err instanceof Error ? err.message : "";
|
|
492
|
+
if (!msg.includes("404")) throw err;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
try {
|
|
496
|
+
const result = await client.save(s.id, path, body, {
|
|
497
|
+
baseRef,
|
|
498
|
+
message: opts.message
|
|
499
|
+
});
|
|
500
|
+
console.log(`Written: ${result.path} (ref: ${result.ref})`);
|
|
501
|
+
} catch (err) {
|
|
502
|
+
if (err instanceof ConflictError) {
|
|
503
|
+
console.error(
|
|
504
|
+
"Error: file was modified by someone else. Please re-read the latest content and try again."
|
|
505
|
+
);
|
|
506
|
+
process.exit(1);
|
|
507
|
+
}
|
|
508
|
+
throw err;
|
|
366
509
|
}
|
|
367
|
-
body = Buffer.concat(chunks).toString("utf-8");
|
|
368
|
-
} else {
|
|
369
|
-
body = content;
|
|
370
510
|
}
|
|
371
|
-
|
|
372
|
-
s.id,
|
|
373
|
-
dir === "." ? "" : dir,
|
|
374
|
-
filename,
|
|
375
|
-
body
|
|
376
|
-
);
|
|
377
|
-
console.log(`Written: ${result.path}`);
|
|
378
|
-
});
|
|
511
|
+
);
|
|
379
512
|
program.command("mkdir").description("Create folder \u2014 docz mkdir <space>:<path>").argument("<target...>").action(async (args) => {
|
|
380
513
|
const { space, path } = parseTarget(args);
|
|
381
514
|
if (!path) {
|
|
@@ -421,6 +554,19 @@ function registerCommands(program) {
|
|
|
421
554
|
console.log(`${l.hash} ${l.date} ${l.message}`);
|
|
422
555
|
}
|
|
423
556
|
});
|
|
557
|
+
program.command("rollback").description(
|
|
558
|
+
"Rollback file to a previous version \u2014 docz rollback <space>:<path> <commit>"
|
|
559
|
+
).argument("<target>", "space:path").argument("<commit>", "Commit hash to rollback to").action(async (target, commit) => {
|
|
560
|
+
const { space, path } = parseTarget([target]);
|
|
561
|
+
if (!path) {
|
|
562
|
+
console.error("Error: file path is required.");
|
|
563
|
+
process.exit(1);
|
|
564
|
+
}
|
|
565
|
+
const client = getClient();
|
|
566
|
+
const s = await client.resolveSpace(space);
|
|
567
|
+
await client.rollback(s.id, path, commit);
|
|
568
|
+
console.log(`Rolled back: ${path} \u2192 ${commit.substring(0, 7)}`);
|
|
569
|
+
});
|
|
424
570
|
program.command("trash").description("Show deleted files \u2014 docz trash <space>").argument("<space>").action(async (spaceName) => {
|
|
425
571
|
const client = getClient();
|
|
426
572
|
const s = await client.resolveSpace(spaceName);
|
|
@@ -435,29 +581,105 @@ function registerCommands(program) {
|
|
|
435
581
|
);
|
|
436
582
|
}
|
|
437
583
|
});
|
|
438
|
-
|
|
439
|
-
|
|
584
|
+
program.command("restore").description(
|
|
585
|
+
"Restore file from trash \u2014 docz restore <space>:<path> <commit>"
|
|
586
|
+
).argument("<target>", "space:path").argument("<commit>", "Commit hash from trash listing").action(async (target, commit) => {
|
|
587
|
+
const { space, path } = parseTarget([target]);
|
|
588
|
+
if (!path) {
|
|
589
|
+
console.error("Error: path is required.");
|
|
590
|
+
process.exit(1);
|
|
591
|
+
}
|
|
592
|
+
const client = getClient();
|
|
593
|
+
const s = await client.resolveSpace(space);
|
|
594
|
+
await client.restore(s.id, path, commit);
|
|
595
|
+
console.log(`Restored: ${path}`);
|
|
596
|
+
});
|
|
597
|
+
const comment = program.command("comment").description("Manage file comments");
|
|
598
|
+
comment.command("list").description("List comments \u2014 docz comment list <space>:<path>").argument("<target...>").action(async (args) => {
|
|
599
|
+
const client = getClient();
|
|
600
|
+
const { spaceId, path } = await resolveTarget(client, args);
|
|
601
|
+
if (!path) {
|
|
602
|
+
console.error("Error: file path is required.");
|
|
603
|
+
process.exit(1);
|
|
604
|
+
}
|
|
605
|
+
const comments = await client.listComments(spaceId, path);
|
|
606
|
+
if (comments.length === 0) {
|
|
607
|
+
console.log("No comments.");
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
for (const c of comments) {
|
|
611
|
+
const status = c.is_closed ? " [closed]" : "";
|
|
612
|
+
console.log(`#${c.id} ${c.user_name} (${c.created_at})${status}`);
|
|
613
|
+
console.log(` ${c.content}`);
|
|
614
|
+
for (const r of c.replies) {
|
|
615
|
+
console.log(` \u2192 ${r.user_name}: ${r.content}`);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
comment.command("add").description("Add comment \u2014 docz comment add <space>:<path> <content>").argument("<target>", "space:path").argument("<content>", "Comment text (or - for stdin)").action(async (target, content) => {
|
|
440
620
|
const { space, path } = parseTarget([target]);
|
|
441
621
|
if (!path) {
|
|
442
|
-
console.error("Error: file path is required.
|
|
622
|
+
console.error("Error: file path is required.");
|
|
443
623
|
process.exit(1);
|
|
444
624
|
}
|
|
445
625
|
const client = getClient();
|
|
446
626
|
const s = await client.resolveSpace(space);
|
|
447
|
-
const
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
627
|
+
const body = content === "-" ? await readStdin() : content;
|
|
628
|
+
const c = await client.createComment(s.id, path, body);
|
|
629
|
+
console.log(`Comment #${c.id} created.`);
|
|
630
|
+
});
|
|
631
|
+
comment.command("reply").description(
|
|
632
|
+
"Reply to comment \u2014 docz comment reply <space> <commentId> <content>"
|
|
633
|
+
).argument("<space>").argument("<commentId>").argument("<content>", "Reply text (or - for stdin)").action(async (spaceName, commentId, content) => {
|
|
634
|
+
const client = getClient();
|
|
635
|
+
const s = await client.resolveSpace(spaceName);
|
|
636
|
+
const body = content === "-" ? await readStdin() : content;
|
|
637
|
+
const r = await client.replyComment(s.id, Number(commentId), body);
|
|
638
|
+
console.log(`Reply #${r.id} created.`);
|
|
639
|
+
});
|
|
640
|
+
comment.command("close").description("Close comment \u2014 docz comment close <space> <commentId>").argument("<space>").argument("<commentId>").action(async (spaceName, commentId) => {
|
|
641
|
+
const client = getClient();
|
|
642
|
+
const s = await client.resolveSpace(spaceName);
|
|
643
|
+
await client.closeComment(s.id, Number(commentId));
|
|
644
|
+
console.log(`Comment #${commentId} closed.`);
|
|
460
645
|
});
|
|
646
|
+
comment.command("rm").description("Delete comment \u2014 docz comment rm <space> <commentId>").argument("<space>").argument("<commentId>").action(async (spaceName, commentId) => {
|
|
647
|
+
const client = getClient();
|
|
648
|
+
const s = await client.resolveSpace(spaceName);
|
|
649
|
+
await client.deleteComment(s.id, Number(commentId));
|
|
650
|
+
console.log(`Comment #${commentId} deleted.`);
|
|
651
|
+
});
|
|
652
|
+
const share = program.command("share").description("Manage share links");
|
|
653
|
+
share.command("create").description("Create share link \u2014 docz share create <space>:<path>").argument("<target>", "space:path").option("--expires <duration>", "Expiry duration (e.g. 7d, 24h)").option("--users <emails>", "Comma-separated user emails or IDs").option("--groups <ids>", "Comma-separated group IDs").action(
|
|
654
|
+
async (target, opts) => {
|
|
655
|
+
const { space, path } = parseTarget([target]);
|
|
656
|
+
if (!path) {
|
|
657
|
+
console.error(
|
|
658
|
+
"Error: file path is required. Usage: docz share create <space>:<path>"
|
|
659
|
+
);
|
|
660
|
+
process.exit(1);
|
|
661
|
+
}
|
|
662
|
+
const client = getClient();
|
|
663
|
+
const s = await client.resolveSpace(space);
|
|
664
|
+
const apiOpts = {};
|
|
665
|
+
if (opts.expires) apiOpts.expiresAt = parseExpires(opts.expires);
|
|
666
|
+
if (opts.users)
|
|
667
|
+
apiOpts.userIds = opts.users.split(",").map((s2) => s2.trim());
|
|
668
|
+
if (opts.groups)
|
|
669
|
+
apiOpts.groupIds = opts.groups.split(",").map((s2) => s2.trim());
|
|
670
|
+
const link = await client.createShareLink(s.id, path, apiOpts);
|
|
671
|
+
const baseUrl = getBaseUrl();
|
|
672
|
+
console.log("Created share link:");
|
|
673
|
+
console.log(` id: ${link.id}`);
|
|
674
|
+
console.log(` token: ${link.token}`);
|
|
675
|
+
console.log(` url: ${baseUrl}/share/${link.token}`);
|
|
676
|
+
console.log(` expires: ${link.expires_at ?? "never"}`);
|
|
677
|
+
if (link.user_ids?.length)
|
|
678
|
+
console.log(` users: ${link.user_ids.join(", ")}`);
|
|
679
|
+
if (link.group_ids?.length)
|
|
680
|
+
console.log(` groups: ${link.group_ids.length}`);
|
|
681
|
+
}
|
|
682
|
+
);
|
|
461
683
|
share.command("list").description("List share links \u2014 docz share list <space>").argument("<space>").option("--file <path>", "Filter by file path").action(async (spaceName, opts) => {
|
|
462
684
|
const client = getClient();
|
|
463
685
|
const s = await client.resolveSpace(spaceName);
|
|
@@ -469,19 +691,25 @@ function registerCommands(program) {
|
|
|
469
691
|
for (const l of links) {
|
|
470
692
|
const expires = l.expires_at ?? "never";
|
|
471
693
|
const creator = l.created_by_name ?? l.created_by_email ?? l.created_by;
|
|
472
|
-
console.log(
|
|
694
|
+
console.log(
|
|
695
|
+
`${l.id} ${l.token} ${l.file_path} ${expires} ${creator}`
|
|
696
|
+
);
|
|
473
697
|
}
|
|
474
698
|
});
|
|
475
|
-
share.command("update").description("Update share link \u2014 docz share update <space> <link-id>").argument("<space>").argument("<linkId>").option("--expires <duration>", "New expiry duration (e.g. 30d)").option("--users <emails>", "Comma-separated user emails or IDs").option("--groups <ids>", "Comma-separated group IDs").action(
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
699
|
+
share.command("update").description("Update share link \u2014 docz share update <space> <link-id>").argument("<space>").argument("<linkId>").option("--expires <duration>", "New expiry duration (e.g. 30d)").option("--users <emails>", "Comma-separated user emails or IDs").option("--groups <ids>", "Comma-separated group IDs").action(
|
|
700
|
+
async (spaceName, linkId, opts) => {
|
|
701
|
+
const client = getClient();
|
|
702
|
+
const s = await client.resolveSpace(spaceName);
|
|
703
|
+
const apiOpts = {};
|
|
704
|
+
if (opts.expires) apiOpts.expiresAt = parseExpires(opts.expires);
|
|
705
|
+
if (opts.users)
|
|
706
|
+
apiOpts.userIds = opts.users.split(",").map((s2) => s2.trim());
|
|
707
|
+
if (opts.groups)
|
|
708
|
+
apiOpts.groupIds = opts.groups.split(",").map((s2) => s2.trim());
|
|
709
|
+
await client.updateShareLink(s.id, linkId, apiOpts);
|
|
710
|
+
console.log(`Updated share link: ${linkId}`);
|
|
711
|
+
}
|
|
712
|
+
);
|
|
485
713
|
share.command("cat").description("Read shared file \u2014 docz share cat <token-or-url>").argument("<token>", "Share token or full URL").option("--raw", "Output raw content only").action(async (tokenArg, opts) => {
|
|
486
714
|
const client = getClient();
|
|
487
715
|
const token = extractShareToken(tokenArg);
|
|
@@ -489,7 +717,9 @@ function registerCommands(program) {
|
|
|
489
717
|
try {
|
|
490
718
|
const info = await client.getSharedFileInfo(token);
|
|
491
719
|
console.log(`File: ${info.file_path} (${info.space_name})`);
|
|
492
|
-
console.log(
|
|
720
|
+
console.log(
|
|
721
|
+
`Shared by: ${info.created_by_name} | Expires: ${info.expires_at ?? "never"}`
|
|
722
|
+
);
|
|
493
723
|
console.log("---");
|
|
494
724
|
} catch (err) {
|
|
495
725
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -553,10 +783,11 @@ function registerCommands(program) {
|
|
|
553
783
|
}
|
|
554
784
|
|
|
555
785
|
export {
|
|
786
|
+
ConflictError,
|
|
556
787
|
DocSyncClient,
|
|
557
788
|
getBaseUrl,
|
|
558
789
|
getToken,
|
|
559
790
|
parseExpires,
|
|
560
791
|
registerCommands
|
|
561
792
|
};
|
|
562
|
-
//# sourceMappingURL=chunk-
|
|
793
|
+
//# sourceMappingURL=chunk-XUT76ACQ.js.map
|