@max1874/feishu 0.2.9 → 0.2.11

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/docx.ts +75 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@max1874/feishu",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
4
4
  "type": "module",
5
5
  "description": "OpenClaw Feishu/Lark channel plugin",
6
6
  "license": "MIT",
package/src/docx.ts CHANGED
@@ -43,6 +43,60 @@ function extractImageUrls(markdown: string): string[] {
43
43
  return urls;
44
44
  }
45
45
 
46
+ /** Extract text content from a block for sorting */
47
+ function extractBlockText(block: any): string {
48
+ const elements =
49
+ block.text?.elements ??
50
+ block.heading1?.elements ??
51
+ block.heading2?.elements ??
52
+ block.heading3?.elements ??
53
+ block.bullet?.elements ??
54
+ block.ordered?.elements ??
55
+ block.quote?.elements ??
56
+ block.todo?.elements ??
57
+ [];
58
+ return elements
59
+ .filter((e: any) => e.text_run)
60
+ .map((e: any) => e.text_run.content)
61
+ .join("");
62
+ }
63
+
64
+ /**
65
+ * Sort blocks by their position in firstLevelBlockIds.
66
+ * The Convert API returns blocks in arbitrary order, but provides
67
+ * first_level_block_ids in the correct document order.
68
+ */
69
+ function sortBlocksByFirstLevelIds(blocks: any[], firstLevelBlockIds: string[]): any[] {
70
+ // Build a map of block_id -> block
71
+ const blockMap = new Map<string, any>();
72
+ for (const block of blocks) {
73
+ if (block.block_id) {
74
+ blockMap.set(block.block_id, block);
75
+ }
76
+ }
77
+
78
+ // Reorder blocks according to firstLevelBlockIds
79
+ const sortedBlocks: any[] = [];
80
+ const usedIds = new Set<string>();
81
+
82
+ for (const id of firstLevelBlockIds) {
83
+ const block = blockMap.get(id);
84
+ if (block) {
85
+ sortedBlocks.push(block);
86
+ usedIds.add(id);
87
+ }
88
+ }
89
+
90
+ // Append any remaining blocks (e.g., child blocks like TableCell)
91
+ for (const block of blocks) {
92
+ if (block.block_id && !usedIds.has(block.block_id)) {
93
+ sortedBlocks.push(block);
94
+ }
95
+ }
96
+
97
+ return sortedBlocks;
98
+ }
99
+
46
100
  const BLOCK_TYPE_NAMES: Record<number, string> = {
47
101
  1: "Page",
48
102
  2: "Text",
@@ -183,10 +237,14 @@ async function convertMarkdown(client: Lark.Client, markdown: string) {
183
237
  data: { content_type: "markdown", content: markdown },
184
238
  });
185
239
  if (res.code !== 0) throw new Error(res.msg);
186
- return {
187
- blocks: res.data?.blocks ?? [],
188
- firstLevelBlockIds: res.data?.first_level_block_ids ?? [],
189
- };
240
+
241
+ const rawBlocks = res.data?.blocks ?? [];
242
+ const firstLevelBlockIds = res.data?.first_level_block_ids ?? [];
243
+
244
+ // Sort blocks according to first_level_block_ids (Convert API returns blocks in arbitrary order)
245
+ const blocks = sortBlocksByFirstLevelIds(rawBlocks, firstLevelBlockIds);
246
+
247
+ return { blocks, firstLevelBlockIds };
190
248
  }
191
249
 
192
250
  /** Insert blocks as children of a parent block (with batching for >50 blocks) */
@@ -207,14 +265,25 @@ async function insertBlocks(
207
265
  const BATCH_SIZE = 50;
208
266
  const allChildren: any[] = [];
209
267
 
268
+ // Get current children count to determine insert index
269
+ let insertIndex = 0;
270
+ const existing = await client.docx.documentBlockChildren.get({
271
+ path: { document_id: docToken, block_id: blockId },
272
+ });
273
+ if (existing.code === 0) {
274
+ insertIndex = existing.data?.items?.length ?? 0;
275
+ }
276
+
210
277
  for (let i = 0; i < cleaned.length; i += BATCH_SIZE) {
211
278
  const batch = cleaned.slice(i, i + BATCH_SIZE);
212
279
  const res = await client.docx.documentBlockChildren.create({
213
280
  path: { document_id: docToken, block_id: blockId },
214
- data: { children: batch },
281
+ data: { children: batch, index: insertIndex },
215
282
  });
216
283
  if (res.code !== 0) throw new Error(res.msg);
217
- allChildren.push(...(res.data?.children ?? []));
284
+ const inserted = res.data?.children ?? [];
285
+ allChildren.push(...inserted);
286
+ insertIndex += inserted.length;
218
287
  }
219
288
 
220
289
  return { children: allChildren, skipped };