feishu-docs-cli 0.1.0-beta.2

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.
Files changed (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +333 -0
  3. package/README.zh.md +332 -0
  4. package/bin/feishu-docs.js +8 -0
  5. package/dist/auth.d.ts +76 -0
  6. package/dist/auth.js +512 -0
  7. package/dist/auth.js.map +1 -0
  8. package/dist/cli.d.ts +5 -0
  9. package/dist/cli.js +166 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/client.d.ts +42 -0
  12. package/dist/client.js +269 -0
  13. package/dist/client.js.map +1 -0
  14. package/dist/commands/cat.d.ts +6 -0
  15. package/dist/commands/cat.js +151 -0
  16. package/dist/commands/cat.js.map +1 -0
  17. package/dist/commands/create.d.ts +6 -0
  18. package/dist/commands/create.js +120 -0
  19. package/dist/commands/create.js.map +1 -0
  20. package/dist/commands/delete.d.ts +6 -0
  21. package/dist/commands/delete.js +89 -0
  22. package/dist/commands/delete.js.map +1 -0
  23. package/dist/commands/info.d.ts +6 -0
  24. package/dist/commands/info.js +69 -0
  25. package/dist/commands/info.js.map +1 -0
  26. package/dist/commands/login.d.ts +10 -0
  27. package/dist/commands/login.js +90 -0
  28. package/dist/commands/login.js.map +1 -0
  29. package/dist/commands/ls.d.ts +6 -0
  30. package/dist/commands/ls.js +76 -0
  31. package/dist/commands/ls.js.map +1 -0
  32. package/dist/commands/read.d.ts +6 -0
  33. package/dist/commands/read.js +404 -0
  34. package/dist/commands/read.js.map +1 -0
  35. package/dist/commands/search.d.ts +7 -0
  36. package/dist/commands/search.js +87 -0
  37. package/dist/commands/search.js.map +1 -0
  38. package/dist/commands/share.d.ts +13 -0
  39. package/dist/commands/share.js +210 -0
  40. package/dist/commands/share.js.map +1 -0
  41. package/dist/commands/spaces.d.ts +6 -0
  42. package/dist/commands/spaces.js +43 -0
  43. package/dist/commands/spaces.js.map +1 -0
  44. package/dist/commands/tree.d.ts +6 -0
  45. package/dist/commands/tree.js +101 -0
  46. package/dist/commands/tree.js.map +1 -0
  47. package/dist/commands/update.d.ts +9 -0
  48. package/dist/commands/update.js +211 -0
  49. package/dist/commands/update.js.map +1 -0
  50. package/dist/commands/wiki.d.ts +6 -0
  51. package/dist/commands/wiki.js +284 -0
  52. package/dist/commands/wiki.js.map +1 -0
  53. package/dist/parser/block-types.d.ts +141 -0
  54. package/dist/parser/block-types.js +167 -0
  55. package/dist/parser/block-types.js.map +1 -0
  56. package/dist/parser/blocks-to-md.d.ts +26 -0
  57. package/dist/parser/blocks-to-md.js +576 -0
  58. package/dist/parser/blocks-to-md.js.map +1 -0
  59. package/dist/parser/text-elements.d.ts +13 -0
  60. package/dist/parser/text-elements.js +91 -0
  61. package/dist/parser/text-elements.js.map +1 -0
  62. package/dist/services/block-writer.d.ts +30 -0
  63. package/dist/services/block-writer.js +131 -0
  64. package/dist/services/block-writer.js.map +1 -0
  65. package/dist/services/doc-blocks.d.ts +9 -0
  66. package/dist/services/doc-blocks.js +30 -0
  67. package/dist/services/doc-blocks.js.map +1 -0
  68. package/dist/services/markdown-convert.d.ts +51 -0
  69. package/dist/services/markdown-convert.js +109 -0
  70. package/dist/services/markdown-convert.js.map +1 -0
  71. package/dist/services/wiki-nodes.d.ts +21 -0
  72. package/dist/services/wiki-nodes.js +47 -0
  73. package/dist/services/wiki-nodes.js.map +1 -0
  74. package/dist/types/index.d.ts +234 -0
  75. package/dist/types/index.js +5 -0
  76. package/dist/types/index.js.map +1 -0
  77. package/dist/utils/document-resolver.d.ts +28 -0
  78. package/dist/utils/document-resolver.js +47 -0
  79. package/dist/utils/document-resolver.js.map +1 -0
  80. package/dist/utils/drive-types.d.ts +4 -0
  81. package/dist/utils/drive-types.js +16 -0
  82. package/dist/utils/drive-types.js.map +1 -0
  83. package/dist/utils/errors.d.ts +21 -0
  84. package/dist/utils/errors.js +110 -0
  85. package/dist/utils/errors.js.map +1 -0
  86. package/dist/utils/member.d.ts +11 -0
  87. package/dist/utils/member.js +30 -0
  88. package/dist/utils/member.js.map +1 -0
  89. package/dist/utils/url-parser.d.ts +5 -0
  90. package/dist/utils/url-parser.js +55 -0
  91. package/dist/utils/url-parser.js.map +1 -0
  92. package/dist/utils/validate.d.ts +8 -0
  93. package/dist/utils/validate.js +15 -0
  94. package/dist/utils/validate.js.map +1 -0
  95. package/package.json +54 -0
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Convert Feishu TextRun elements to/from Markdown inline format.
3
+ */
4
+ /**
5
+ * Escape Markdown special characters in plain text.
6
+ */
7
+ function escapeMarkdown(text) {
8
+ return text.replace(/([\\*_`~\[\]|<>#!])/g, "\\$1");
9
+ }
10
+ /**
11
+ * Render a list of text elements to Markdown inline string.
12
+ */
13
+ export function elementsToMarkdown(elements, ctx) {
14
+ if (!elements || elements.length === 0)
15
+ return "";
16
+ const userNameMap = ctx?.userNameMap;
17
+ return elements
18
+ .map((el) => {
19
+ if (el.text_run) {
20
+ return textRunToMarkdown(el.text_run);
21
+ }
22
+ if (el.equation) {
23
+ const content = (el.equation.content || "").trim();
24
+ // Use $$ for block-level (sole element), $ for inline
25
+ if (elements.length === 1) {
26
+ return `$$${content}$$`;
27
+ }
28
+ return `$${content}$`;
29
+ }
30
+ if (el.mention_user) {
31
+ const uid = el.mention_user.user_id || "";
32
+ const name = (userNameMap && userNameMap.get(uid)) ||
33
+ el.mention_user
34
+ .user_name ||
35
+ el.mention_user.name;
36
+ if (name)
37
+ return `@${name}`;
38
+ // Fallback: show shortened user_id
39
+ return `@[用户](feishu://user/${uid})`;
40
+ }
41
+ if (el.mention_doc) {
42
+ const title = el.mention_doc.title || "文档";
43
+ const url = el.mention_doc.url || "";
44
+ return url ? `[${title}](${url})` : title;
45
+ }
46
+ return "";
47
+ })
48
+ .join("");
49
+ }
50
+ function textRunToMarkdown(textRun) {
51
+ let text = textRun.content || "";
52
+ if (!text)
53
+ return "";
54
+ const style = textRun.text_element_style || {};
55
+ // Inline code takes priority — no other formatting inside code
56
+ if (style.inline_code) {
57
+ return `\`${text}\``;
58
+ }
59
+ // Escape Markdown special characters in plain text
60
+ text = escapeMarkdown(text);
61
+ // Apply style markers to text first (before link wrapping)
62
+ if (style.bold && style.italic) {
63
+ text = `***${text}***`;
64
+ }
65
+ else if (style.bold) {
66
+ text = `**${text}**`;
67
+ }
68
+ else if (style.italic) {
69
+ text = `*${text}*`;
70
+ }
71
+ if (style.strikethrough) {
72
+ text = `~~${text}~~`;
73
+ }
74
+ if (style.underline) {
75
+ text = `<u>${text}</u>`;
76
+ }
77
+ // Link wrapping (after style markers so bold/italic wraps text, not link syntax)
78
+ if (style.link?.url) {
79
+ let url;
80
+ try {
81
+ url = decodeURIComponent(style.link.url);
82
+ }
83
+ catch {
84
+ url = style.link.url;
85
+ }
86
+ url = url.replace(/[)"]/g, "");
87
+ text = `[${text}](${url})`;
88
+ }
89
+ return text;
90
+ }
91
+ //# sourceMappingURL=text-elements.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-elements.js","sourceRoot":"","sources":["../../src/parser/text-elements.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Document infrastructure: backup/restore, clearing, helpers.
3
+ *
4
+ * Note: The old block-level write functions (writeBlocks, writeTableBlock,
5
+ * writeNestedBlocks, writeAllBlocks) have been replaced by the Convert +
6
+ * Descendant API pipeline in markdown-convert.js.
7
+ */
8
+ import * as lark from "@larksuiteoapi/node-sdk";
9
+ import { AuthInfo, Block } from "../types/index.js";
10
+ export declare const BACKUPS_DIR: string;
11
+ export declare const BATCH_SIZE: number;
12
+ export declare const QPS_DELAY: number;
13
+ export declare function sleep(ms: number): Promise<void>;
14
+ /**
15
+ * Read body content from file path or stdin ("-").
16
+ */
17
+ export declare function readBody(bodyArg: string): Promise<string>;
18
+ export declare function getDocumentInfo(client: lark.Client, authInfo: AuthInfo, documentId: string): Promise<{
19
+ title: string;
20
+ revisionId: number;
21
+ }>;
22
+ export declare function getRootChildrenCount(client: lark.Client, authInfo: AuthInfo, documentId: string): Promise<number>;
23
+ /**
24
+ * Clear all top-level children of a document (batch delete from end).
25
+ */
26
+ export declare function clearDocument(client: lark.Client, authInfo: AuthInfo, documentId: string, revisionId: number): Promise<number>;
27
+ export declare function backupDocument(client: lark.Client, authInfo: AuthInfo, documentId: string): Promise<{
28
+ filepath: string;
29
+ blocks: Block[];
30
+ }>;
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Document infrastructure: backup/restore, clearing, helpers.
3
+ *
4
+ * Note: The old block-level write functions (writeBlocks, writeTableBlock,
5
+ * writeNestedBlocks, writeAllBlocks) have been replaced by the Convert +
6
+ * Descendant API pipeline in markdown-convert.js.
7
+ */
8
+ import { readFile, mkdir, writeFile, readdir, unlink } from "node:fs/promises";
9
+ import { existsSync } from "node:fs";
10
+ import { join, resolve, normalize } from "node:path";
11
+ import { homedir } from "node:os";
12
+ import { randomUUID } from "node:crypto";
13
+ import { fetchWithAuth } from "../client.js";
14
+ import { CliError } from "../utils/errors.js";
15
+ import { fetchAllBlocks } from "./doc-blocks.js";
16
+ export const BACKUPS_DIR = join(homedir(), ".feishu-docs", "backups");
17
+ export const BATCH_SIZE = 50;
18
+ export const QPS_DELAY = 400;
19
+ export function sleep(ms) {
20
+ return new Promise((r) => setTimeout(r, ms));
21
+ }
22
+ /**
23
+ * Read body content from file path or stdin ("-").
24
+ */
25
+ export async function readBody(bodyArg) {
26
+ if (bodyArg === "-") {
27
+ const chunks = [];
28
+ for await (const chunk of process.stdin) {
29
+ chunks.push(chunk);
30
+ }
31
+ return Buffer.concat(chunks).toString("utf8");
32
+ }
33
+ const resolvedPath = resolve(normalize(bodyArg));
34
+ if (!existsSync(resolvedPath)) {
35
+ throw new CliError("FILE_NOT_FOUND", `文件不存在: ${resolvedPath}`);
36
+ }
37
+ return readFile(resolvedPath, "utf8");
38
+ }
39
+ // --- Document info helpers ---
40
+ export async function getDocumentInfo(client, authInfo, documentId) {
41
+ const res = await fetchWithAuth(authInfo, `/open-apis/docx/v1/documents/${encodeURIComponent(documentId)}`);
42
+ const data = res?.data;
43
+ const doc = (data?.document || {});
44
+ return {
45
+ title: doc.title,
46
+ revisionId: doc.revision_id,
47
+ };
48
+ }
49
+ export async function getRootChildrenCount(client, authInfo, documentId) {
50
+ const res = await fetchWithAuth(authInfo, `/open-apis/docx/v1/documents/${encodeURIComponent(documentId)}/blocks/${encodeURIComponent(documentId)}`, { params: { document_revision_id: -1 } });
51
+ return res?.data?.block?.children
52
+ ? (res?.data).block
53
+ .children.length
54
+ : 0;
55
+ }
56
+ /**
57
+ * Clear all top-level children of a document (batch delete from end).
58
+ */
59
+ export async function clearDocument(client, authInfo, documentId, revisionId) {
60
+ let rev = revisionId;
61
+ let remaining = await getRootChildrenCount(client, authInfo, documentId);
62
+ let conflictRetries = 0;
63
+ const MAX_CONFLICT_RETRIES = 5;
64
+ while (remaining > 0) {
65
+ const end = remaining;
66
+ const start = Math.max(0, remaining - BATCH_SIZE);
67
+ try {
68
+ const res = await fetchWithAuth(authInfo, `/open-apis/docx/v1/documents/${encodeURIComponent(documentId)}/blocks/${encodeURIComponent(documentId)}/children/batch_delete`, {
69
+ method: "DELETE",
70
+ body: { start_index: start, end_index: end },
71
+ params: {
72
+ document_revision_id: rev,
73
+ client_token: randomUUID(),
74
+ },
75
+ });
76
+ rev =
77
+ res?.data
78
+ ?.document_revision_id ?? rev;
79
+ remaining = start;
80
+ conflictRetries = 0;
81
+ if (remaining > 0)
82
+ await sleep(QPS_DELAY);
83
+ }
84
+ catch (err) {
85
+ const code = err?.apiCode ||
86
+ err?.code;
87
+ if (code === 1770064) {
88
+ if (++conflictRetries > MAX_CONFLICT_RETRIES) {
89
+ throw new CliError("API_ERROR", "文档正在被并发编辑,清空操作失败,请稍后重试");
90
+ }
91
+ const doc = await getDocumentInfo(client, authInfo, documentId);
92
+ rev = doc.revisionId;
93
+ remaining = await getRootChildrenCount(client, authInfo, documentId);
94
+ }
95
+ else {
96
+ throw err;
97
+ }
98
+ }
99
+ }
100
+ return rev;
101
+ }
102
+ // --- Backup helpers ---
103
+ export async function backupDocument(client, authInfo, documentId) {
104
+ const blocks = await fetchAllBlocks(client, authInfo, documentId);
105
+ await mkdir(BACKUPS_DIR, { recursive: true, mode: 0o700 });
106
+ const filename = `${documentId}-${Date.now()}.json`;
107
+ const filepath = join(BACKUPS_DIR, filename);
108
+ await writeFile(filepath, JSON.stringify(blocks, null, 2), {
109
+ encoding: "utf8",
110
+ mode: 0o600,
111
+ });
112
+ process.stderr.write(`feishu-docs: info: 备份已保存到 ${filepath}\n`);
113
+ await rotateBackups();
114
+ return { filepath, blocks };
115
+ }
116
+ async function rotateBackups() {
117
+ try {
118
+ const files = await readdir(BACKUPS_DIR);
119
+ const jsonFiles = files.filter((f) => f.endsWith(".json")).sort();
120
+ if (jsonFiles.length > 10) {
121
+ const toDelete = jsonFiles.slice(0, jsonFiles.length - 10);
122
+ for (const f of toDelete) {
123
+ await unlink(join(BACKUPS_DIR, f));
124
+ }
125
+ }
126
+ }
127
+ catch (err) {
128
+ process.stderr.write(`feishu-docs: warning: 备份轮转失败: ${err.message}\n`);
129
+ }
130
+ }
131
+ //# sourceMappingURL=block-writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"block-writer.js","sourceRoot":"","sources":["../../src/services/block-writer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Shared document block fetching.
3
+ */
4
+ import * as lark from "@larksuiteoapi/node-sdk";
5
+ import { AuthInfo, Block } from "../types/index.js";
6
+ /**
7
+ * Fetch all blocks for a document.
8
+ */
9
+ export declare function fetchAllBlocks(client: lark.Client, authInfo: AuthInfo, documentId: string): Promise<Block[]>;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Shared document block fetching.
3
+ */
4
+ import { apiCall, withAuth } from "../client.js";
5
+ /**
6
+ * Fetch all blocks for a document.
7
+ */
8
+ export async function fetchAllBlocks(client, authInfo, documentId) {
9
+ const blocks = [];
10
+ let pageToken;
11
+ do {
12
+ const params = {
13
+ document_revision_id: -1,
14
+ page_size: 500,
15
+ ...(pageToken && { page_token: pageToken }),
16
+ };
17
+ const res = await apiCall(() => client.docx.v1.documentBlock.list({
18
+ path: { document_id: documentId },
19
+ params,
20
+ }, withAuth(authInfo)));
21
+ if (res?.data?.items) {
22
+ blocks.push(...res.data.items);
23
+ }
24
+ pageToken = res?.data?.has_more
25
+ ? res.data.page_token
26
+ : undefined;
27
+ } while (pageToken);
28
+ return blocks;
29
+ }
30
+ //# sourceMappingURL=doc-blocks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doc-blocks.js","sourceRoot":"","sources":["../../src/services/doc-blocks.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAGjD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAmB,EACnB,QAAkB,EAClB,UAAkB;IAElB,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,IAAI,SAA6B,CAAC;IAElC,GAAG,CAAC;QACF,MAAM,MAAM,GAAgD;YAC1D,oBAAoB,EAAE,CAAC,CAAC;YACxB,SAAS,EAAE,GAAG;YACd,GAAG,CAAC,SAAS,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;SAC5C,CAAC;QAEF,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,CAC7B,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,IAAI,CAC/B;YACE,IAAI,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE;YACjC,MAAM;SACP,EACD,QAAQ,CAAC,QAAQ,CAAC,CACnB,CACF,CAAC;QAEF,IAAI,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;YACrB,MAAM,CAAC,IAAI,CAAC,GAAI,GAAG,CAAC,IAAI,CAAC,KAAiB,CAAC,CAAC;QAC9C,CAAC;QACD,SAAS,GAAG,GAAG,EAAE,IAAI,EAAE,QAAQ;YAC7B,CAAC,CAAE,GAAG,CAAC,IAAI,CAAC,UAAqB;YACjC,CAAC,CAAC,SAAS,CAAC;IAChB,CAAC,QAAQ,SAAS,EAAE;IAEpB,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Convert Markdown to Feishu blocks via server-side Convert API,
3
+ * then write to document via Descendant API.
4
+ *
5
+ * This replaces the local md-to-blocks parser + multi-step block-writer
6
+ * table assembly with just 2 API calls:
7
+ * 1. Convert API: Markdown string -> block tree (server-side parsing)
8
+ * 2. Descendant API: Write entire block tree in one call (no 9-row table limit)
9
+ */
10
+ import { AuthInfo, ConvertedBlocks, Block } from "../types/index.js";
11
+ /**
12
+ * Normalize code-fence language names in markdown before sending to Convert API.
13
+ * Replaces unrecognized aliases with their recognized equivalents.
14
+ */
15
+ export declare function normalizeLangNames(markdown: string): string;
16
+ /**
17
+ * Convert markdown string to Feishu block array via Convert API.
18
+ * Requires scope: docx:document.block:convert
19
+ *
20
+ * @returns {{ blocks: Array, firstLevelBlockIds: string[], blockIdToImageUrls: Object }}
21
+ */
22
+ export declare function convertMarkdown(authInfo: AuthInfo, markdown: string): Promise<ConvertedBlocks>;
23
+ /**
24
+ * Strip merge_info from table blocks to prevent Descendant API errors.
25
+ * Returns a new array (immutable).
26
+ */
27
+ export declare function stripMergeInfo(blocks: Block[]): Block[];
28
+ /**
29
+ * Write blocks to document via Descendant API.
30
+ * Supports up to 1000 blocks per call, no table row limit.
31
+ *
32
+ * @param {object} authInfo - Auth credentials
33
+ * @param {string} documentId - Target document ID
34
+ * @param {string} parentBlockId - Parent block (usually same as documentId for top-level)
35
+ * @param {object} converted - Output from convertMarkdown()
36
+ * @param {number} revisionId - Document revision ID
37
+ * @param {number} index - Insert position (0 = beginning, -1 = append to end)
38
+ * @returns {number} Updated revision ID
39
+ */
40
+ export declare function writeDescendant(authInfo: AuthInfo, documentId: string, parentBlockId: string, converted: ConvertedBlocks, revisionId: number, index?: number): Promise<number>;
41
+ /**
42
+ * High-level: Convert markdown and write to document in 2 API calls.
43
+ *
44
+ * @param {object} authInfo - Auth credentials
45
+ * @param {string} documentId - Target document ID
46
+ * @param {string} markdown - Raw Markdown content
47
+ * @param {number} revisionId - Current document revision ID
48
+ * @param {number} index - Insert position (0 = beginning, -1 = append)
49
+ * @returns {number} Updated revision ID
50
+ */
51
+ export declare function convertAndWrite(authInfo: AuthInfo, documentId: string, markdown: string, revisionId: number, index?: number): Promise<number>;
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Convert Markdown to Feishu blocks via server-side Convert API,
3
+ * then write to document via Descendant API.
4
+ *
5
+ * This replaces the local md-to-blocks parser + multi-step block-writer
6
+ * table assembly with just 2 API calls:
7
+ * 1. Convert API: Markdown string -> block tree (server-side parsing)
8
+ * 2. Descendant API: Write entire block tree in one call (no 9-row table limit)
9
+ */
10
+ import { fetchWithAuth } from "../client.js";
11
+ import { CliError } from "../utils/errors.js";
12
+ /**
13
+ * Language aliases that Feishu Convert API does not recognize.
14
+ * Maps unrecognized names → recognized names so code blocks render correctly.
15
+ */
16
+ const LANG_ALIASES = {
17
+ "objective-c": "objc",
18
+ "obj-c": "objc",
19
+ };
20
+ /**
21
+ * Normalize code-fence language names in markdown before sending to Convert API.
22
+ * Replaces unrecognized aliases with their recognized equivalents.
23
+ */
24
+ export function normalizeLangNames(markdown) {
25
+ return markdown.replace(/^(```)([\w+#.-]+)/gm, (match, fence, lang) => {
26
+ const alias = LANG_ALIASES[lang.toLowerCase()];
27
+ return alias ? fence + alias : match;
28
+ });
29
+ }
30
+ /**
31
+ * Convert markdown string to Feishu block array via Convert API.
32
+ * Requires scope: docx:document.block:convert
33
+ *
34
+ * @returns {{ blocks: Array, firstLevelBlockIds: string[], blockIdToImageUrls: Object }}
35
+ */
36
+ export async function convertMarkdown(authInfo, markdown) {
37
+ const res = await fetchWithAuth(authInfo, "/open-apis/docx/v1/documents/blocks/convert", {
38
+ method: "POST",
39
+ body: { content: normalizeLangNames(markdown), content_type: "markdown" },
40
+ });
41
+ const data = res?.data;
42
+ if (!data?.blocks || !data?.first_level_block_ids) {
43
+ throw new CliError("API_ERROR", "Convert API 返回数据格式不正确");
44
+ }
45
+ return {
46
+ blocks: data.blocks,
47
+ firstLevelBlockIds: data.first_level_block_ids,
48
+ blockIdToImageUrls: data.block_id_to_image_urls || {},
49
+ };
50
+ }
51
+ /**
52
+ * Strip merge_info from table blocks to prevent Descendant API errors.
53
+ * Returns a new array (immutable).
54
+ */
55
+ export function stripMergeInfo(blocks) {
56
+ return blocks.map((block) => {
57
+ if (block.table?.property?.merge_info) {
58
+ const { merge_info, ...restProperty } = block.table.property;
59
+ return {
60
+ ...block,
61
+ table: { ...block.table, property: restProperty },
62
+ };
63
+ }
64
+ return block;
65
+ });
66
+ }
67
+ /**
68
+ * Write blocks to document via Descendant API.
69
+ * Supports up to 1000 blocks per call, no table row limit.
70
+ *
71
+ * @param {object} authInfo - Auth credentials
72
+ * @param {string} documentId - Target document ID
73
+ * @param {string} parentBlockId - Parent block (usually same as documentId for top-level)
74
+ * @param {object} converted - Output from convertMarkdown()
75
+ * @param {number} revisionId - Document revision ID
76
+ * @param {number} index - Insert position (0 = beginning, -1 = append to end)
77
+ * @returns {number} Updated revision ID
78
+ */
79
+ export async function writeDescendant(authInfo, documentId, parentBlockId, converted, revisionId, index = 0) {
80
+ const cleanBlocks = stripMergeInfo(converted.blocks);
81
+ const res = await fetchWithAuth(authInfo, `/open-apis/docx/v1/documents/${encodeURIComponent(documentId)}/blocks/${encodeURIComponent(parentBlockId)}/descendant`, {
82
+ method: "POST",
83
+ body: {
84
+ children_id: converted.firstLevelBlockIds,
85
+ descendants: cleanBlocks,
86
+ index,
87
+ },
88
+ params: {
89
+ document_revision_id: revisionId,
90
+ },
91
+ });
92
+ return (res?.data?.document_revision_id ??
93
+ revisionId);
94
+ }
95
+ /**
96
+ * High-level: Convert markdown and write to document in 2 API calls.
97
+ *
98
+ * @param {object} authInfo - Auth credentials
99
+ * @param {string} documentId - Target document ID
100
+ * @param {string} markdown - Raw Markdown content
101
+ * @param {number} revisionId - Current document revision ID
102
+ * @param {number} index - Insert position (0 = beginning, -1 = append)
103
+ * @returns {number} Updated revision ID
104
+ */
105
+ export async function convertAndWrite(authInfo, documentId, markdown, revisionId, index = 0) {
106
+ const converted = await convertMarkdown(authInfo, markdown);
107
+ return writeDescendant(authInfo, documentId, documentId, converted, revisionId, index);
108
+ }
109
+ //# sourceMappingURL=markdown-convert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown-convert.js","sourceRoot":"","sources":["../../src/services/markdown-convert.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Shared wiki node helpers.
3
+ */
4
+ import * as lark from "@larksuiteoapi/node-sdk";
5
+ import { AuthInfo, WikiNode } from "../types/index.js";
6
+ export interface ResolvedWikiNode {
7
+ objToken: string;
8
+ objType: string;
9
+ title: string;
10
+ nodeToken: string;
11
+ spaceId: string;
12
+ hasChild: boolean;
13
+ }
14
+ /**
15
+ * Fetch child nodes of a parent node (or space root).
16
+ */
17
+ export declare function fetchChildren(authInfo: AuthInfo, spaceId: string, parentNodeToken?: string): Promise<WikiNode[]>;
18
+ /**
19
+ * Resolve wiki token to actual document token + type.
20
+ */
21
+ export declare function resolveWikiToken(client: lark.Client, authInfo: AuthInfo, wikiToken: string): Promise<ResolvedWikiNode>;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Shared wiki node helpers.
3
+ */
4
+ import { apiCall, withAuth, fetchWithAuth } from "../client.js";
5
+ import { CliError } from "../utils/errors.js";
6
+ /**
7
+ * Fetch child nodes of a parent node (or space root).
8
+ */
9
+ export async function fetchChildren(authInfo, spaceId, parentNodeToken) {
10
+ const nodes = [];
11
+ let pageToken;
12
+ do {
13
+ const params = {
14
+ page_size: 50,
15
+ ...(pageToken && { page_token: pageToken }),
16
+ ...(parentNodeToken && { parent_node_token: parentNodeToken }),
17
+ };
18
+ const res = await fetchWithAuth(authInfo, `/open-apis/wiki/v2/spaces/${encodeURIComponent(spaceId)}/nodes`, { params });
19
+ const data = res?.data;
20
+ if (data?.items) {
21
+ nodes.push(...data.items);
22
+ }
23
+ pageToken = data?.has_more ? data.page_token : undefined;
24
+ } while (pageToken);
25
+ return nodes;
26
+ }
27
+ /**
28
+ * Resolve wiki token to actual document token + type.
29
+ */
30
+ export async function resolveWikiToken(client, authInfo, wikiToken) {
31
+ const res = await apiCall(() => client.wiki.v2.space.getNode({
32
+ params: { token: wikiToken, obj_type: "wiki" },
33
+ }, withAuth(authInfo)));
34
+ const node = res?.data?.node;
35
+ if (!node) {
36
+ throw new CliError("NOT_FOUND", `知识库节点不存在: ${wikiToken}`);
37
+ }
38
+ return {
39
+ objToken: node.obj_token ?? "",
40
+ objType: node.obj_type ?? "",
41
+ title: node.title ?? "",
42
+ nodeToken: node.node_token ?? "",
43
+ spaceId: node.space_id ?? "",
44
+ hasChild: node.has_child || false,
45
+ };
46
+ }
47
+ //# sourceMappingURL=wiki-nodes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wiki-nodes.js","sourceRoot":"","sources":["../../src/services/wiki-nodes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAY9C;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,QAAkB,EAClB,OAAe,EACf,eAAwB;IAExB,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,IAAI,SAA6B,CAAC;IAElC,GAAG,CAAC;QACF,MAAM,MAAM,GAAgD;YAC1D,SAAS,EAAE,EAAE;YACb,GAAG,CAAC,SAAS,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;YAC3C,GAAG,CAAC,eAAe,IAAI,EAAE,iBAAiB,EAAE,eAAe,EAAE,CAAC;SAC/D,CAAC;QAEF,MAAM,GAAG,GAAG,MAAM,aAAa,CAC7B,QAAQ,EACR,6BAA6B,kBAAkB,CAAC,OAAO,CAAC,QAAQ,EAChE,EAAE,MAAM,EAAE,CACX,CAAC;QAEF,MAAM,IAAI,GAAG,GAAG,EAAE,IAA2C,CAAC;QAC9D,IAAI,IAAI,EAAE,KAAK,EAAE,CAAC;YAChB,KAAK,CAAC,IAAI,CAAC,GAAI,IAAI,CAAC,KAAoB,CAAC,CAAC;QAC5C,CAAC;QACD,SAAS,GAAG,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAE,IAAI,CAAC,UAAqB,CAAC,CAAC,CAAC,SAAS,CAAC;IACvE,CAAC,QAAQ,SAAS,EAAE;IAEpB,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAmB,EACnB,QAAkB,EAClB,SAAiB;IAEjB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,CAC7B,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAC1B;QACE,MAAM,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE;KAC/C,EACD,QAAQ,CAAC,QAAQ,CAAC,CACnB,CACF,CAAC;IAEF,MAAM,IAAI,GAAG,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC;IAC7B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,QAAQ,CAAC,WAAW,EAAE,aAAa,SAAS,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,IAAI,CAAC,SAAS,IAAI,EAAE;QAC9B,OAAO,EAAE,IAAI,CAAC,QAAQ,IAAI,EAAE;QAC5B,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,EAAE;QACvB,SAAS,EAAE,IAAI,CAAC,UAAU,IAAI,EAAE;QAChC,OAAO,EAAE,IAAI,CAAC,QAAQ,IAAI,EAAE;QAC5B,QAAQ,EAAE,IAAI,CAAC,SAAS,IAAI,KAAK;KAClC,CAAC;AACJ,CAAC"}