feishu-docs-cli 0.1.0-beta.10

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 (120) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +403 -0
  3. package/README.zh.md +402 -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 +197 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/client.d.ts +28 -0
  12. package/dist/client.js +256 -0
  13. package/dist/client.js.map +1 -0
  14. package/dist/commands/authorize.d.ts +12 -0
  15. package/dist/commands/authorize.js +73 -0
  16. package/dist/commands/authorize.js.map +1 -0
  17. package/dist/commands/cat.d.ts +6 -0
  18. package/dist/commands/cat.js +159 -0
  19. package/dist/commands/cat.js.map +1 -0
  20. package/dist/commands/cp.d.ts +9 -0
  21. package/dist/commands/cp.js +70 -0
  22. package/dist/commands/cp.js.map +1 -0
  23. package/dist/commands/create.d.ts +6 -0
  24. package/dist/commands/create.js +120 -0
  25. package/dist/commands/create.js.map +1 -0
  26. package/dist/commands/delete.d.ts +6 -0
  27. package/dist/commands/delete.js +91 -0
  28. package/dist/commands/delete.js.map +1 -0
  29. package/dist/commands/info.d.ts +6 -0
  30. package/dist/commands/info.js +69 -0
  31. package/dist/commands/info.js.map +1 -0
  32. package/dist/commands/install-skill.d.ts +5 -0
  33. package/dist/commands/install-skill.js +28 -0
  34. package/dist/commands/install-skill.js.map +1 -0
  35. package/dist/commands/login.d.ts +10 -0
  36. package/dist/commands/login.js +93 -0
  37. package/dist/commands/login.js.map +1 -0
  38. package/dist/commands/ls.d.ts +6 -0
  39. package/dist/commands/ls.js +79 -0
  40. package/dist/commands/ls.js.map +1 -0
  41. package/dist/commands/mkdir.d.ts +6 -0
  42. package/dist/commands/mkdir.js +49 -0
  43. package/dist/commands/mkdir.js.map +1 -0
  44. package/dist/commands/mv.d.ts +9 -0
  45. package/dist/commands/mv.js +72 -0
  46. package/dist/commands/mv.js.map +1 -0
  47. package/dist/commands/read.d.ts +6 -0
  48. package/dist/commands/read.js +439 -0
  49. package/dist/commands/read.js.map +1 -0
  50. package/dist/commands/search.d.ts +7 -0
  51. package/dist/commands/search.js +92 -0
  52. package/dist/commands/search.js.map +1 -0
  53. package/dist/commands/share.d.ts +13 -0
  54. package/dist/commands/share.js +266 -0
  55. package/dist/commands/share.js.map +1 -0
  56. package/dist/commands/spaces.d.ts +6 -0
  57. package/dist/commands/spaces.js +43 -0
  58. package/dist/commands/spaces.js.map +1 -0
  59. package/dist/commands/tree.d.ts +6 -0
  60. package/dist/commands/tree.js +101 -0
  61. package/dist/commands/tree.js.map +1 -0
  62. package/dist/commands/update.d.ts +9 -0
  63. package/dist/commands/update.js +217 -0
  64. package/dist/commands/update.js.map +1 -0
  65. package/dist/commands/wiki.d.ts +6 -0
  66. package/dist/commands/wiki.js +286 -0
  67. package/dist/commands/wiki.js.map +1 -0
  68. package/dist/parser/block-types.d.ts +141 -0
  69. package/dist/parser/block-types.js +167 -0
  70. package/dist/parser/block-types.js.map +1 -0
  71. package/dist/parser/blocks-to-md.d.ts +26 -0
  72. package/dist/parser/blocks-to-md.js +666 -0
  73. package/dist/parser/blocks-to-md.js.map +1 -0
  74. package/dist/parser/text-elements.d.ts +13 -0
  75. package/dist/parser/text-elements.js +91 -0
  76. package/dist/parser/text-elements.js.map +1 -0
  77. package/dist/scopes.d.ts +21 -0
  78. package/dist/scopes.js +48 -0
  79. package/dist/scopes.js.map +1 -0
  80. package/dist/services/block-writer.d.ts +29 -0
  81. package/dist/services/block-writer.js +131 -0
  82. package/dist/services/block-writer.js.map +1 -0
  83. package/dist/services/doc-blocks.d.ts +8 -0
  84. package/dist/services/doc-blocks.js +26 -0
  85. package/dist/services/doc-blocks.js.map +1 -0
  86. package/dist/services/markdown-convert.d.ts +68 -0
  87. package/dist/services/markdown-convert.js +217 -0
  88. package/dist/services/markdown-convert.js.map +1 -0
  89. package/dist/services/wiki-nodes.d.ts +20 -0
  90. package/dist/services/wiki-nodes.js +46 -0
  91. package/dist/services/wiki-nodes.js.map +1 -0
  92. package/dist/types/index.d.ts +236 -0
  93. package/dist/types/index.js +5 -0
  94. package/dist/types/index.js.map +1 -0
  95. package/dist/utils/document-resolver.d.ts +26 -0
  96. package/dist/utils/document-resolver.js +46 -0
  97. package/dist/utils/document-resolver.js.map +1 -0
  98. package/dist/utils/drive-types.d.ts +4 -0
  99. package/dist/utils/drive-types.js +16 -0
  100. package/dist/utils/drive-types.js.map +1 -0
  101. package/dist/utils/errors.d.ts +23 -0
  102. package/dist/utils/errors.js +114 -0
  103. package/dist/utils/errors.js.map +1 -0
  104. package/dist/utils/member.d.ts +11 -0
  105. package/dist/utils/member.js +30 -0
  106. package/dist/utils/member.js.map +1 -0
  107. package/dist/utils/scope-prompt.d.ts +39 -0
  108. package/dist/utils/scope-prompt.js +134 -0
  109. package/dist/utils/scope-prompt.js.map +1 -0
  110. package/dist/utils/url-parser.d.ts +5 -0
  111. package/dist/utils/url-parser.js +55 -0
  112. package/dist/utils/url-parser.js.map +1 -0
  113. package/dist/utils/validate.d.ts +8 -0
  114. package/dist/utils/validate.js +15 -0
  115. package/dist/utils/validate.js.map +1 -0
  116. package/dist/utils/version.d.ts +12 -0
  117. package/dist/utils/version.js +128 -0
  118. package/dist/utils/version.js.map +1 -0
  119. package/package.json +53 -0
  120. package/skills/feishu-docs/SKILL.md +194 -0
@@ -0,0 +1,217 @@
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
+ * Notes:
11
+ * - Descendant API accepts at most 1000 blocks per call; large content is
12
+ * automatically split into batches at top-level block boundaries.
13
+ * - Read-only fields returned by Convert API (parent_id, comment_ids,
14
+ * merge_info) are stripped before writing to avoid validation errors.
15
+ */
16
+ import { fetchWithAuth } from "../client.js";
17
+ import { CliError } from "../utils/errors.js";
18
+ /** Maximum blocks the Descendant API accepts per call. */
19
+ const MAX_BLOCKS_PER_CALL = 1000;
20
+ /**
21
+ * Language aliases that Feishu Convert API does not recognize.
22
+ * Maps unrecognized names → recognized names so code blocks render correctly.
23
+ */
24
+ const LANG_ALIASES = {
25
+ "objective-c": "objc",
26
+ "obj-c": "objc",
27
+ };
28
+ /**
29
+ * Normalize code-fence language names in markdown before sending to Convert API.
30
+ * Replaces unrecognized aliases with their recognized equivalents.
31
+ */
32
+ export function normalizeLangNames(markdown) {
33
+ return markdown.replace(/^(```)([\w+#.-]+)/gm, (match, fence, lang) => {
34
+ const alias = LANG_ALIASES[lang.toLowerCase()];
35
+ return alias ? fence + alias : match;
36
+ });
37
+ }
38
+ /**
39
+ * Convert markdown string to Feishu block array via Convert API.
40
+ * Requires scope: docx:document.block:convert
41
+ *
42
+ * @returns {{ blocks: Array, firstLevelBlockIds: string[], blockIdToImageUrls: Object }}
43
+ */
44
+ export async function convertMarkdown(authInfo, markdown) {
45
+ const res = await fetchWithAuth(authInfo, "/open-apis/docx/v1/documents/blocks/convert", {
46
+ method: "POST",
47
+ body: { content: normalizeLangNames(markdown), content_type: "markdown" },
48
+ });
49
+ const data = res?.data;
50
+ if (!data?.blocks || !data?.first_level_block_ids) {
51
+ throw new CliError("API_ERROR", "Convert API 返回数据格式不正确");
52
+ }
53
+ return {
54
+ blocks: data.blocks,
55
+ firstLevelBlockIds: data.first_level_block_ids,
56
+ blockIdToImageUrls: data.block_id_to_image_urls || {},
57
+ };
58
+ }
59
+ /**
60
+ * Read-only / server-generated fields that the Descendant API rejects.
61
+ * These are returned by the Convert API but must not be sent back.
62
+ */
63
+ const READ_ONLY_BLOCK_FIELDS = ["parent_id", "comment_ids"];
64
+ /**
65
+ * Sanitize blocks for the Descendant API by removing read-only fields.
66
+ *
67
+ * Strips:
68
+ * - top-level read-only fields: parent_id, comment_ids
69
+ * - table.property.merge_info (read-only attribute)
70
+ *
71
+ * Returns a new array (immutable).
72
+ */
73
+ export function sanitizeBlocks(blocks) {
74
+ return blocks.map((block) => {
75
+ let cleaned = block;
76
+ // Strip top-level read-only fields
77
+ for (const field of READ_ONLY_BLOCK_FIELDS) {
78
+ if (field in cleaned) {
79
+ const { [field]: _, ...rest } = cleaned;
80
+ cleaned = rest;
81
+ }
82
+ }
83
+ // Strip table.property.merge_info
84
+ if (cleaned.table?.property?.merge_info) {
85
+ const { merge_info, ...restProperty } = cleaned.table.property;
86
+ cleaned = {
87
+ ...cleaned,
88
+ table: { ...cleaned.table, property: restProperty },
89
+ };
90
+ }
91
+ return cleaned;
92
+ });
93
+ }
94
+ /**
95
+ * Collect all descendant block IDs reachable from a set of top-level IDs.
96
+ * Traverses the children tree in the block array.
97
+ */
98
+ function collectDescendantIds(topLevelIds, blockMap) {
99
+ const ids = new Set();
100
+ const queue = [...topLevelIds];
101
+ while (queue.length > 0) {
102
+ const id = queue.pop();
103
+ if (ids.has(id))
104
+ continue;
105
+ ids.add(id);
106
+ const block = blockMap.get(id);
107
+ if (block?.children) {
108
+ queue.push(...block.children);
109
+ }
110
+ }
111
+ return ids;
112
+ }
113
+ /**
114
+ * Build a ConvertedBlocks batch from a subset of blocks.
115
+ * Filters blockIdToImageUrls to only include entries for blocks in this batch.
116
+ */
117
+ function buildBatch(topIds, blockIds, allBlocks, source) {
118
+ const imageUrls = Object.fromEntries(Object.entries(source.blockIdToImageUrls).filter(([id]) => blockIds.has(id)));
119
+ return {
120
+ firstLevelBlockIds: topIds,
121
+ blocks: allBlocks.filter((b) => blockIds.has(b.block_id)),
122
+ blockIdToImageUrls: imageUrls,
123
+ };
124
+ }
125
+ /**
126
+ * Split converted blocks into batches that each stay within
127
+ * MAX_BLOCKS_PER_CALL. Splits at top-level block boundaries so
128
+ * parent–child relationships are preserved within each batch.
129
+ */
130
+ export function splitIntoBatches(converted) {
131
+ const allBlocks = sanitizeBlocks(converted.blocks);
132
+ if (allBlocks.length <= MAX_BLOCKS_PER_CALL) {
133
+ return [{ ...converted, blocks: allBlocks }];
134
+ }
135
+ const blockMap = new Map(allBlocks.map((b) => [b.block_id, b]));
136
+ const batches = [];
137
+ let batchTopIds = [];
138
+ let batchBlockCount = 0;
139
+ for (const topId of converted.firstLevelBlockIds) {
140
+ const descendantIds = collectDescendantIds([topId], blockMap);
141
+ const subtreeSize = descendantIds.size;
142
+ // A single top-level subtree that exceeds the limit cannot be split further
143
+ if (subtreeSize > MAX_BLOCKS_PER_CALL) {
144
+ throw new CliError("API_ERROR", `单个顶层块的后代数量 (${subtreeSize}) 超过 Descendant API 限制 (${MAX_BLOCKS_PER_CALL}),无法拆分`);
145
+ }
146
+ // If adding this top-level block would exceed the limit, flush current batch
147
+ if (batchBlockCount > 0 &&
148
+ batchBlockCount + subtreeSize > MAX_BLOCKS_PER_CALL) {
149
+ const batchIds = collectDescendantIds(batchTopIds, blockMap);
150
+ batches.push(buildBatch(batchTopIds, batchIds, allBlocks, converted));
151
+ batchTopIds = [];
152
+ batchBlockCount = 0;
153
+ }
154
+ batchTopIds.push(topId);
155
+ batchBlockCount += subtreeSize;
156
+ }
157
+ // Flush remaining
158
+ if (batchTopIds.length > 0) {
159
+ const batchIds = collectDescendantIds(batchTopIds, blockMap);
160
+ batches.push(buildBatch(batchTopIds, batchIds, allBlocks, converted));
161
+ }
162
+ return batches;
163
+ }
164
+ /**
165
+ * Write blocks to document via Descendant API.
166
+ * Automatically batches when block count exceeds 1000.
167
+ *
168
+ * @param {object} authInfo - Auth credentials
169
+ * @param {string} documentId - Target document ID
170
+ * @param {string} parentBlockId - Parent block (usually same as documentId for top-level)
171
+ * @param {object} converted - Output from convertMarkdown()
172
+ * @param {number} revisionId - Document revision ID
173
+ * @param {number} index - Insert position (0 = beginning, -1 = append to end)
174
+ * @returns {number} Updated revision ID
175
+ */
176
+ export async function writeDescendant(authInfo, documentId, parentBlockId, converted, revisionId, index = 0) {
177
+ const batches = splitIntoBatches(converted);
178
+ if (batches.length > 1) {
179
+ process.stderr.write(`feishu-docs: info: 内容较大 (${converted.blocks.length} blocks),分 ${batches.length} 批写入\n`);
180
+ }
181
+ let rev = revisionId;
182
+ for (let i = 0; i < batches.length; i++) {
183
+ const batch = batches[i];
184
+ // First batch uses caller-specified index; subsequent batches append
185
+ const batchIndex = i === 0 ? index : -1;
186
+ const res = await fetchWithAuth(authInfo, `/open-apis/docx/v1/documents/${encodeURIComponent(documentId)}/blocks/${encodeURIComponent(parentBlockId)}/descendant`, {
187
+ method: "POST",
188
+ body: {
189
+ children_id: batch.firstLevelBlockIds,
190
+ descendants: batch.blocks,
191
+ index: batchIndex,
192
+ },
193
+ params: {
194
+ document_revision_id: rev,
195
+ },
196
+ });
197
+ rev =
198
+ res?.data
199
+ ?.document_revision_id ?? rev;
200
+ }
201
+ return rev;
202
+ }
203
+ /**
204
+ * High-level: Convert markdown and write to document in 2 API calls.
205
+ *
206
+ * @param {object} authInfo - Auth credentials
207
+ * @param {string} documentId - Target document ID
208
+ * @param {string} markdown - Raw Markdown content
209
+ * @param {number} revisionId - Current document revision ID
210
+ * @param {number} index - Insert position (0 = beginning, -1 = append)
211
+ * @returns {number} Updated revision ID
212
+ */
213
+ export async function convertAndWrite(authInfo, documentId, markdown, revisionId, index = 0) {
214
+ const converted = await convertMarkdown(authInfo, markdown);
215
+ return writeDescendant(authInfo, documentId, documentId, converted, revisionId, index);
216
+ }
217
+ //# sourceMappingURL=markdown-convert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown-convert.js","sourceRoot":"","sources":["../../src/services/markdown-convert.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAG9C,0DAA0D;AAC1D,MAAM,mBAAmB,GAAG,IAAI,CAAC;AAEjC;;;GAGG;AACH,MAAM,YAAY,GAA2B;IAC3C,aAAa,EAAE,MAAM;IACrB,OAAO,EAAE,MAAM;CAChB,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,OAAO,QAAQ,CAAC,OAAO,CAAC,qBAAqB,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACpE,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QAC/C,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAkB,EAClB,QAAgB;IAEhB,MAAM,GAAG,GAAG,MAAM,aAAa,CAC7B,QAAQ,EACR,6CAA6C,EAC7C;QACE,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,EAAE,OAAO,EAAE,kBAAkB,CAAC,QAAQ,CAAC,EAAE,YAAY,EAAE,UAAU,EAAE;KAC1E,CACF,CAAC;IAEF,MAAM,IAAI,GAAG,GAAG,EAAE,IAA2C,CAAC;IAC9D,IAAI,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC,IAAI,EAAE,qBAAqB,EAAE,CAAC;QAClD,MAAM,IAAI,QAAQ,CAAC,WAAW,EAAE,uBAAuB,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO;QACL,MAAM,EAAE,IAAI,CAAC,MAAiB;QAC9B,kBAAkB,EAAE,IAAI,CAAC,qBAAiC;QAC1D,kBAAkB,EACf,IAAI,CAAC,sBAAiD,IAAI,EAAE;KAChE,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,sBAAsB,GAAG,CAAC,WAAW,EAAE,aAAa,CAAU,CAAC;AAErE;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,MAAe;IAC5C,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QAC1B,IAAI,OAAO,GAAU,KAAK,CAAC;QAE3B,mCAAmC;QACnC,KAAK,MAAM,KAAK,IAAI,sBAAsB,EAAE,CAAC;YAC3C,IAAI,KAAK,IAAI,OAAO,EAAE,CAAC;gBACrB,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;gBACxC,OAAO,GAAG,IAAa,CAAC;YAC1B,CAAC;QACH,CAAC;QAED,kCAAkC;QAClC,IAAI,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC;YACxC,MAAM,EAAE,UAAU,EAAE,GAAG,YAAY,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC;YAC/D,OAAO,GAAG;gBACR,GAAG,OAAO;gBACV,KAAK,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE;aACpD,CAAC;QACJ,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,SAAS,oBAAoB,CAC3B,WAAqB,EACrB,QAA4B;IAE5B,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,MAAM,KAAK,GAAG,CAAC,GAAG,WAAW,CAAC,CAAC;IAC/B,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,EAAE,GAAG,KAAK,CAAC,GAAG,EAAG,CAAC;QACxB,IAAI,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,SAAS;QAC1B,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACZ,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC/B,IAAI,KAAK,EAAE,QAAQ,EAAE,CAAC;YACpB,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;GAGG;AACH,SAAS,UAAU,CACjB,MAAgB,EAChB,QAAqB,EACrB,SAAkB,EAClB,MAAuB;IAEvB,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,CAClC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACxD,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CACjB,CACF,CAAC;IACF,OAAO;QACL,kBAAkB,EAAE,MAAM;QAC1B,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QACzD,kBAAkB,EAAE,SAAS;KAC9B,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAC9B,SAA0B;IAE1B,MAAM,SAAS,GAAG,cAAc,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAEnD,IAAI,SAAS,CAAC,MAAM,IAAI,mBAAmB,EAAE,CAAC;QAC5C,OAAO,CAAC,EAAE,GAAG,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAChE,MAAM,OAAO,GAAsB,EAAE,CAAC;IAEtC,IAAI,WAAW,GAAa,EAAE,CAAC;IAC/B,IAAI,eAAe,GAAG,CAAC,CAAC;IAExB,KAAK,MAAM,KAAK,IAAI,SAAS,CAAC,kBAAkB,EAAE,CAAC;QACjD,MAAM,aAAa,GAAG,oBAAoB,CAAC,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAC;QAC9D,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,CAAC;QAEvC,4EAA4E;QAC5E,IAAI,WAAW,GAAG,mBAAmB,EAAE,CAAC;YACtC,MAAM,IAAI,QAAQ,CAChB,WAAW,EACX,eAAe,WAAW,2BAA2B,mBAAmB,QAAQ,CACjF,CAAC;QACJ,CAAC;QAED,6EAA6E;QAC7E,IACE,eAAe,GAAG,CAAC;YACnB,eAAe,GAAG,WAAW,GAAG,mBAAmB,EACnD,CAAC;YACD,MAAM,QAAQ,GAAG,oBAAoB,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;YAC7D,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;YACtE,WAAW,GAAG,EAAE,CAAC;YACjB,eAAe,GAAG,CAAC,CAAC;QACtB,CAAC;QAED,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,eAAe,IAAI,WAAW,CAAC;IACjC,CAAC;IAED,kBAAkB;IAClB,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,oBAAoB,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QAC7D,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;IACxE,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAkB,EAClB,UAAkB,EAClB,aAAqB,EACrB,SAA0B,EAC1B,UAAkB,EAClB,QAAgB,CAAC;IAEjB,MAAM,OAAO,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAE5C,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,4BAA4B,SAAS,CAAC,MAAM,CAAC,MAAM,cAAc,OAAO,CAAC,MAAM,QAAQ,CACxF,CAAC;IACJ,CAAC;IAED,IAAI,GAAG,GAAG,UAAU,CAAC;IACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACzB,qEAAqE;QACrE,MAAM,UAAU,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAExC,MAAM,GAAG,GAAG,MAAM,aAAa,CAC7B,QAAQ,EACR,gCAAgC,kBAAkB,CAAC,UAAU,CAAC,WAAW,kBAAkB,CAAC,aAAa,CAAC,aAAa,EACvH;YACE,MAAM,EAAE,MAAM;YACd,IAAI,EAAE;gBACJ,WAAW,EAAE,KAAK,CAAC,kBAAkB;gBACrC,WAAW,EAAE,KAAK,CAAC,MAAM;gBACzB,KAAK,EAAE,UAAU;aAClB;YACD,MAAM,EAAE;gBACN,oBAAoB,EAAE,GAAG;aAC1B;SACF,CACF,CAAC;QAEF,GAAG;YACC,GAAG,EAAE,IAAgC;gBACrC,EAAE,oBAA+B,IAAI,GAAG,CAAC;IAC/C,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAkB,EAClB,UAAkB,EAClB,QAAgB,EAChB,UAAkB,EAClB,QAAgB,CAAC;IAEjB,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC5D,OAAO,eAAe,CACpB,QAAQ,EACR,UAAU,EACV,UAAU,EACV,SAAS,EACT,UAAU,EACV,KAAK,CACN,CAAC;AACJ,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Shared wiki node helpers.
3
+ */
4
+ import { AuthInfo, WikiNode } from "../types/index.js";
5
+ export interface ResolvedWikiNode {
6
+ objToken: string;
7
+ objType: string;
8
+ title: string;
9
+ nodeToken: string;
10
+ spaceId: string;
11
+ hasChild: boolean;
12
+ }
13
+ /**
14
+ * Fetch child nodes of a parent node (or space root).
15
+ */
16
+ export declare function fetchChildren(authInfo: AuthInfo, spaceId: string, parentNodeToken?: string): Promise<WikiNode[]>;
17
+ /**
18
+ * Resolve wiki token to actual document token + type.
19
+ */
20
+ export declare function resolveWikiToken(authInfo: AuthInfo, wikiToken: string): Promise<ResolvedWikiNode>;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Shared wiki node helpers.
3
+ */
4
+ import { 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(authInfo, wikiToken) {
31
+ const res = await fetchWithAuth(authInfo, "/open-apis/wiki/v2/spaces/get_node", { params: { token: wikiToken, obj_type: "wiki" } });
32
+ const data = res?.data;
33
+ const node = data?.node;
34
+ if (!node) {
35
+ throw new CliError("NOT_FOUND", `知识库节点不存在: ${wikiToken}`);
36
+ }
37
+ return {
38
+ objToken: node.obj_token ?? "",
39
+ objType: node.obj_type ?? "",
40
+ title: node.title ?? "",
41
+ nodeToken: node.node_token ?? "",
42
+ spaceId: node.space_id ?? "",
43
+ hasChild: node.has_child || false,
44
+ };
45
+ }
46
+ //# 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;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,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,QAAkB,EAClB,SAAiB;IAEjB,MAAM,GAAG,GAAG,MAAM,aAAa,CAC7B,QAAQ,EACR,oCAAoC,EACpC,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,CACnD,CAAC;IAEF,MAAM,IAAI,GAAG,GAAG,EAAE,IAA2C,CAAC;IAC9D,MAAM,IAAI,GAAG,IAAI,EAAE,IAA2C,CAAC;IAC/D,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,QAAQ,CAAC,WAAW,EAAE,aAAa,SAAS,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,OAAO;QACL,QAAQ,EAAG,IAAI,CAAC,SAAoB,IAAI,EAAE;QAC1C,OAAO,EAAG,IAAI,CAAC,QAAmB,IAAI,EAAE;QACxC,KAAK,EAAG,IAAI,CAAC,KAAgB,IAAI,EAAE;QACnC,SAAS,EAAG,IAAI,CAAC,UAAqB,IAAI,EAAE;QAC5C,OAAO,EAAG,IAAI,CAAC,QAAmB,IAAI,EAAE;QACxC,QAAQ,EAAG,IAAI,CAAC,SAAqB,IAAI,KAAK;KAC/C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,236 @@
1
+ /**
2
+ * Shared type definitions for feishu-docs CLI.
3
+ */
4
+ export type ErrorType = "INVALID_ARGS" | "FILE_NOT_FOUND" | "AUTH_REQUIRED" | "TOKEN_EXPIRED" | "PERMISSION_DENIED" | "SCOPE_MISSING" | "NOT_FOUND" | "NOT_SUPPORTED" | "RATE_LIMITED" | "API_ERROR";
5
+ export interface CliErrorOptions {
6
+ apiCode?: number;
7
+ retryable?: boolean;
8
+ recovery?: string;
9
+ /** Scope names extracted from API permission_violations (for SCOPE_MISSING errors). */
10
+ missingScopes?: string[];
11
+ }
12
+ export type AuthMode = "user" | "tenant" | "auto";
13
+ export interface AuthInfo {
14
+ mode: AuthMode;
15
+ appId?: string;
16
+ appSecret?: string;
17
+ userToken?: string;
18
+ tenantToken?: string;
19
+ expiresAt?: number;
20
+ refreshToken?: string;
21
+ useLark: boolean;
22
+ }
23
+ export interface TokenData {
24
+ user_access_token: string;
25
+ refresh_token: string;
26
+ expires_at: number;
27
+ token_type?: string;
28
+ }
29
+ export interface GlobalOpts {
30
+ auth: string;
31
+ json: boolean;
32
+ lark: boolean;
33
+ }
34
+ export interface CommandArgs {
35
+ positionals?: string[];
36
+ [key: string]: unknown;
37
+ }
38
+ export type CommandHandler = (args: CommandArgs, globalOpts: GlobalOpts) => Promise<void>;
39
+ export interface OptionDef {
40
+ type: "string" | "boolean";
41
+ default?: string | boolean;
42
+ }
43
+ export interface CommandMeta {
44
+ options: Record<string, OptionDef>;
45
+ positionals?: boolean;
46
+ handler: CommandHandler;
47
+ }
48
+ export interface SubcommandMeta {
49
+ subcommands: Record<string, CommandMeta>;
50
+ }
51
+ export type DocType = "wiki" | "docx" | "doc" | "sheet" | "bitable" | "unknown";
52
+ export interface ParsedDoc {
53
+ type: DocType;
54
+ token: string;
55
+ }
56
+ export interface DocumentInfo {
57
+ documentId: string;
58
+ objToken: string;
59
+ objType: string;
60
+ title: string;
61
+ url?: string;
62
+ revisionId?: number;
63
+ nodeToken?: string;
64
+ spaceId?: string;
65
+ }
66
+ export interface ApiResponse<T = unknown> {
67
+ code?: number;
68
+ msg?: string;
69
+ data?: T;
70
+ }
71
+ export interface FetchOptions {
72
+ method?: string;
73
+ params?: Record<string, string | number | string[] | undefined>;
74
+ body?: unknown;
75
+ headers?: Record<string, string>;
76
+ }
77
+ export interface TextElement {
78
+ text_run?: {
79
+ content: string;
80
+ text_element_style?: TextElementStyle;
81
+ };
82
+ mention_user?: {
83
+ user_id: string;
84
+ text_element_style?: TextElementStyle;
85
+ };
86
+ mention_doc?: {
87
+ token: string;
88
+ obj_type: number;
89
+ url: string;
90
+ title?: string;
91
+ text_element_style?: TextElementStyle;
92
+ };
93
+ equation?: {
94
+ content: string;
95
+ text_element_style?: TextElementStyle;
96
+ };
97
+ file?: {
98
+ file_token: string;
99
+ text_element_style?: TextElementStyle;
100
+ };
101
+ reminder?: {
102
+ timestamp: string;
103
+ };
104
+ undefined?: Record<string, unknown>;
105
+ }
106
+ export interface TextElementStyle {
107
+ bold?: boolean;
108
+ italic?: boolean;
109
+ strikethrough?: boolean;
110
+ underline?: boolean;
111
+ inline_code?: boolean;
112
+ link?: {
113
+ url: string;
114
+ };
115
+ text_color?: number;
116
+ background_color?: number;
117
+ }
118
+ export interface BlockText {
119
+ elements: TextElement[];
120
+ style?: {
121
+ align?: number;
122
+ done?: boolean;
123
+ language?: number;
124
+ wrap?: boolean;
125
+ folded?: boolean;
126
+ };
127
+ }
128
+ export interface Block {
129
+ block_id: string;
130
+ block_type: number;
131
+ parent_id?: string;
132
+ children?: string[];
133
+ text?: BlockText;
134
+ heading1?: BlockText;
135
+ heading2?: BlockText;
136
+ heading3?: BlockText;
137
+ heading4?: BlockText;
138
+ heading5?: BlockText;
139
+ heading6?: BlockText;
140
+ heading7?: BlockText;
141
+ heading8?: BlockText;
142
+ heading9?: BlockText;
143
+ bullet?: BlockText;
144
+ ordered?: BlockText;
145
+ code?: BlockText;
146
+ quote?: BlockText;
147
+ equation?: BlockText;
148
+ todo?: BlockText;
149
+ callout?: {
150
+ background_color?: number;
151
+ border_color?: number;
152
+ emoji_id?: string;
153
+ body?: BlockText;
154
+ elements?: TextElement[];
155
+ };
156
+ divider?: Record<string, never>;
157
+ image?: {
158
+ token: string;
159
+ width?: number;
160
+ height?: number;
161
+ align?: number;
162
+ };
163
+ file?: {
164
+ token: string;
165
+ name?: string;
166
+ view_type?: number;
167
+ };
168
+ table?: {
169
+ cells?: string[];
170
+ property?: {
171
+ row_size: number;
172
+ column_size: number;
173
+ column_width?: number[];
174
+ header_row?: boolean;
175
+ merge_info?: unknown[];
176
+ };
177
+ };
178
+ table_cell?: {
179
+ elements?: TextElement[];
180
+ };
181
+ grid?: {
182
+ column_size: number;
183
+ };
184
+ grid_column?: {
185
+ width_ratio?: number;
186
+ };
187
+ iframe?: {
188
+ component?: {
189
+ iframe_type?: number;
190
+ url?: string;
191
+ };
192
+ };
193
+ quote_container?: Record<string, never>;
194
+ view?: {
195
+ view_type?: number;
196
+ };
197
+ bitable?: {
198
+ token?: string;
199
+ };
200
+ sheet?: {
201
+ token?: string;
202
+ };
203
+ chat_card?: {
204
+ chat_id?: string;
205
+ };
206
+ diagram?: {
207
+ diagram_type?: number;
208
+ };
209
+ task?: {
210
+ task_id?: string;
211
+ };
212
+ [key: string]: unknown;
213
+ }
214
+ export interface WikiNode {
215
+ space_id: string;
216
+ node_token: string;
217
+ obj_token: string;
218
+ obj_type: string;
219
+ parent_node_token?: string;
220
+ title: string;
221
+ has_child: boolean;
222
+ node_type?: string;
223
+ origin_node_token?: string;
224
+ origin_space_id?: string;
225
+ }
226
+ export interface WikiSpace {
227
+ space_id: string;
228
+ name: string;
229
+ description?: string;
230
+ visibility?: string;
231
+ }
232
+ export interface ConvertedBlocks {
233
+ blocks: Block[];
234
+ firstLevelBlockIds: string[];
235
+ blockIdToImageUrls: Record<string, string>;
236
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Shared type definitions for feishu-docs CLI.
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Unified URL/token → document resolution.
3
+ * Extracts the repeated resolve logic from read.js, write.js, delete.js.
4
+ */
5
+ import { AuthInfo, ParsedDoc } from "../types/index.js";
6
+ export interface ResolvedDocument {
7
+ objToken: string;
8
+ objType: string;
9
+ title: string | undefined;
10
+ nodeToken: string | undefined;
11
+ spaceId: string | undefined;
12
+ hasChild: boolean;
13
+ parsed: ParsedDoc;
14
+ }
15
+ /**
16
+ * Resolve a URL or raw token to a fully-qualified document descriptor.
17
+ *
18
+ * @param {object} authInfo - Auth credentials
19
+ * @param {string} input - URL or raw token
20
+ * @param {object} options
21
+ * @param {boolean} options.allowFallback - If true, unknown types silently fall back to docx (default: true)
22
+ * @returns {{ objToken, objType, title, nodeToken, spaceId, hasChild, parsed }}
23
+ */
24
+ export declare function resolveDocument(authInfo: AuthInfo, input: string, options?: {
25
+ allowFallback?: boolean;
26
+ }): Promise<ResolvedDocument>;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Unified URL/token → document resolution.
3
+ * Extracts the repeated resolve logic from read.js, write.js, delete.js.
4
+ */
5
+ import { parseDocUrl } from "./url-parser.js";
6
+ import { resolveWikiToken } from "../services/wiki-nodes.js";
7
+ /**
8
+ * Resolve a URL or raw token to a fully-qualified document descriptor.
9
+ *
10
+ * @param {object} authInfo - Auth credentials
11
+ * @param {string} input - URL or raw token
12
+ * @param {object} options
13
+ * @param {boolean} options.allowFallback - If true, unknown types silently fall back to docx (default: true)
14
+ * @returns {{ objToken, objType, title, nodeToken, spaceId, hasChild, parsed }}
15
+ */
16
+ export async function resolveDocument(authInfo, input, options = {}) {
17
+ const { allowFallback = true } = options;
18
+ const parsed = parseDocUrl(input);
19
+ let objToken = parsed.token;
20
+ let objType = parsed.type === "unknown" ? "docx" : parsed.type;
21
+ let title;
22
+ let nodeToken;
23
+ let spaceId;
24
+ let hasChild = false;
25
+ if (parsed.type === "wiki" || parsed.type === "unknown") {
26
+ try {
27
+ const wiki = await resolveWikiToken(authInfo, parsed.token);
28
+ objToken = wiki.objToken;
29
+ objType = wiki.objType;
30
+ title = wiki.title;
31
+ nodeToken = wiki.nodeToken;
32
+ spaceId = wiki.spaceId;
33
+ hasChild = wiki.hasChild;
34
+ }
35
+ catch (err) {
36
+ if (parsed.type === "unknown" && allowFallback) {
37
+ objType = "docx";
38
+ }
39
+ else {
40
+ throw err;
41
+ }
42
+ }
43
+ }
44
+ return { objToken, objType, title, nodeToken, spaceId, hasChild, parsed };
45
+ }
46
+ //# sourceMappingURL=document-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document-resolver.js","sourceRoot":"","sources":["../../src/utils/document-resolver.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAa7D;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAkB,EAClB,KAAa,EACb,UAAuC,EAAE;IAEzC,MAAM,EAAE,aAAa,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IACzC,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IAClC,IAAI,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC;IAC5B,IAAI,OAAO,GAAW,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;IACvE,IAAI,KAAyB,CAAC;IAC9B,IAAI,SAA6B,CAAC;IAClC,IAAI,OAA2B,CAAC;IAChC,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QACxD,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;YAC5D,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;YACzB,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;YACvB,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;YACnB,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;YAC3B,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;YACvB,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC3B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,aAAa,EAAE,CAAC;gBAC/C,OAAO,GAAG,MAAM,CAAC;YACnB,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,CAAC;YACZ,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AAC5E,CAAC"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Map document object type to Feishu Drive API type parameter.
3
+ */
4
+ export declare function mapToDriveType(objType: string): string;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Map document object type to Feishu Drive API type parameter.
3
+ */
4
+ const DRIVE_TYPE_MAP = {
5
+ docx: "docx",
6
+ doc: "doc",
7
+ sheet: "sheet",
8
+ bitable: "bitable",
9
+ mindnote: "mindnote",
10
+ board: "board",
11
+ wiki: "wiki",
12
+ };
13
+ export function mapToDriveType(objType) {
14
+ return DRIVE_TYPE_MAP[objType] || "docx";
15
+ }
16
+ //# sourceMappingURL=drive-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drive-types.js","sourceRoot":"","sources":["../../src/utils/drive-types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,cAAc,GAA2B;IAC7C,IAAI,EAAE,MAAM;IACZ,GAAG,EAAE,KAAK;IACV,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,SAAS;IAClB,QAAQ,EAAE,UAAU;IACpB,KAAK,EAAE,OAAO;IACd,IAAI,EAAE,MAAM;CACb,CAAC;AAEF,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,OAAO,cAAc,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Unified error handling for feishu-docs CLI.
3
+ *
4
+ * Exit codes:
5
+ * 0 - success
6
+ * 1 - invalid args / file not found
7
+ * 2 - auth failure
8
+ * 3 - API error
9
+ */
10
+ import { ErrorType, CliErrorOptions } from "../types/index.js";
11
+ export declare class CliError extends Error {
12
+ exitCode: number;
13
+ errorType: string;
14
+ apiCode?: number;
15
+ retryable: boolean;
16
+ recovery?: string;
17
+ /** Scope names from API permission_violations (only for SCOPE_MISSING). */
18
+ missingScopes?: string[];
19
+ constructor(type: ErrorType, message: string, { apiCode, retryable, recovery, missingScopes, }?: CliErrorOptions);
20
+ }
21
+ export declare function formatError(err: unknown, json?: boolean): string;
22
+ export declare function handleError(err: unknown, json?: boolean): never;
23
+ export declare function mapApiError(err: unknown): CliError;