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.
@@ -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(`/api/spaces/${spaceId}/diff/${encodeURIComponent(filePath)}?${params}`);
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, dirname } from "path";
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) throw new Error(`Invalid expires format: "${value}". Use e.g. 7d, 24h, 30d`);
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
- const content = await client.cat(spaceId, path);
337
- process.stdout.write(content);
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)").action(async (target, content) => {
350
- const { space, path } = parseTarget([target]);
351
- if (!path) {
352
- console.error(
353
- "Error: path is required. Usage: docz write <space>:<dir/filename> <content>"
354
- );
355
- process.exit(1);
356
- }
357
- const client = getClient();
358
- const s = await client.resolveSpace(space);
359
- const filename = basename(path);
360
- const dir = dirname(path);
361
- let body;
362
- if (content === "-") {
363
- const chunks = [];
364
- for await (const chunk of process.stdin) {
365
- chunks.push(chunk);
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
- const result = await client.upload(
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
- const share = program.command("share").description("Manage share links");
439
- 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(async (target, opts) => {
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. Usage: docz share create <space>:<path>");
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 apiOpts = {};
448
- if (opts.expires) apiOpts.expiresAt = parseExpires(opts.expires);
449
- if (opts.users) apiOpts.userIds = opts.users.split(",").map((s2) => s2.trim());
450
- if (opts.groups) apiOpts.groupIds = opts.groups.split(",").map((s2) => s2.trim());
451
- const link = await client.createShareLink(s.id, path, apiOpts);
452
- const baseUrl = getBaseUrl();
453
- console.log(`Created share link:`);
454
- console.log(` id: ${link.id}`);
455
- console.log(` token: ${link.token}`);
456
- console.log(` url: ${baseUrl}/share/${link.token}`);
457
- console.log(` expires: ${link.expires_at ?? "never"}`);
458
- if (link.user_ids?.length) console.log(` users: ${link.user_ids.join(", ")}`);
459
- if (link.group_ids?.length) console.log(` groups: ${link.group_ids.length}`);
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(`${l.id} ${l.token} ${l.file_path} ${expires} ${creator}`);
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(async (spaceName, linkId, opts) => {
476
- const client = getClient();
477
- const s = await client.resolveSpace(spaceName);
478
- const apiOpts = {};
479
- if (opts.expires) apiOpts.expiresAt = parseExpires(opts.expires);
480
- if (opts.users) apiOpts.userIds = opts.users.split(",").map((s2) => s2.trim());
481
- if (opts.groups) apiOpts.groupIds = opts.groups.split(",").map((s2) => s2.trim());
482
- await client.updateShareLink(s.id, linkId, apiOpts);
483
- console.log(`Updated share link: ${linkId}`);
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(`Shared by: ${info.created_by_name} | Expires: ${info.expires_at ?? "never"}`);
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-EBJ32KUL.js.map
793
+ //# sourceMappingURL=chunk-XUT76ACQ.js.map