cc-lark 0.1.1

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 (298) hide show
  1. package/.github/workflows/ci.yml +47 -0
  2. package/.github/workflows/release.yml +47 -0
  3. package/.github/workflows/sync-upstream.yml +127 -0
  4. package/.prettierrc.json +7 -0
  5. package/README.md +214 -0
  6. package/dist/core/api-error.d.ts +193 -0
  7. package/dist/core/api-error.d.ts.map +1 -0
  8. package/dist/core/api-error.js +263 -0
  9. package/dist/core/api-error.js.map +1 -0
  10. package/dist/core/auth-errors.d.ts +13 -0
  11. package/dist/core/auth-errors.d.ts.map +1 -0
  12. package/dist/core/auth-errors.js +14 -0
  13. package/dist/core/auth-errors.js.map +1 -0
  14. package/dist/core/config.d.ts +60 -0
  15. package/dist/core/config.d.ts.map +1 -0
  16. package/dist/core/config.js +115 -0
  17. package/dist/core/config.js.map +1 -0
  18. package/dist/core/device-flow.d.ts +80 -0
  19. package/dist/core/device-flow.d.ts.map +1 -0
  20. package/dist/core/device-flow.js +231 -0
  21. package/dist/core/device-flow.js.map +1 -0
  22. package/dist/core/index.d.ts +16 -0
  23. package/dist/core/index.d.ts.map +1 -0
  24. package/dist/core/index.js +16 -0
  25. package/dist/core/index.js.map +1 -0
  26. package/dist/core/lark-client.d.ts +136 -0
  27. package/dist/core/lark-client.d.ts.map +1 -0
  28. package/dist/core/lark-client.js +315 -0
  29. package/dist/core/lark-client.js.map +1 -0
  30. package/dist/core/token-store.d.ts +67 -0
  31. package/dist/core/token-store.d.ts.map +1 -0
  32. package/dist/core/token-store.js +215 -0
  33. package/dist/core/token-store.js.map +1 -0
  34. package/dist/core/types.d.ts +286 -0
  35. package/dist/core/types.d.ts.map +1 -0
  36. package/dist/core/types.js +11 -0
  37. package/dist/core/types.js.map +1 -0
  38. package/dist/core/uat-client.d.ts +64 -0
  39. package/dist/core/uat-client.d.ts.map +1 -0
  40. package/dist/core/uat-client.js +227 -0
  41. package/dist/core/uat-client.js.map +1 -0
  42. package/dist/core/version.d.ts +26 -0
  43. package/dist/core/version.d.ts.map +1 -0
  44. package/dist/core/version.js +50 -0
  45. package/dist/core/version.js.map +1 -0
  46. package/dist/index.d.ts +12 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +116 -0
  49. package/dist/index.js.map +1 -0
  50. package/dist/tools/bitable/app.d.ts +20 -0
  51. package/dist/tools/bitable/app.d.ts.map +1 -0
  52. package/dist/tools/bitable/app.js +301 -0
  53. package/dist/tools/bitable/app.js.map +1 -0
  54. package/dist/tools/bitable/field.d.ts +19 -0
  55. package/dist/tools/bitable/field.d.ts.map +1 -0
  56. package/dist/tools/bitable/field.js +315 -0
  57. package/dist/tools/bitable/field.js.map +1 -0
  58. package/dist/tools/bitable/index.d.ts +21 -0
  59. package/dist/tools/bitable/index.d.ts.map +1 -0
  60. package/dist/tools/bitable/index.js +39 -0
  61. package/dist/tools/bitable/index.js.map +1 -0
  62. package/dist/tools/bitable/record.d.ts +22 -0
  63. package/dist/tools/bitable/record.d.ts.map +1 -0
  64. package/dist/tools/bitable/record.js +434 -0
  65. package/dist/tools/bitable/record.js.map +1 -0
  66. package/dist/tools/bitable/table.d.ts +21 -0
  67. package/dist/tools/bitable/table.d.ts.map +1 -0
  68. package/dist/tools/bitable/table.js +361 -0
  69. package/dist/tools/bitable/table.js.map +1 -0
  70. package/dist/tools/calendar/calendar.d.ts +18 -0
  71. package/dist/tools/calendar/calendar.d.ts.map +1 -0
  72. package/dist/tools/calendar/calendar.js +192 -0
  73. package/dist/tools/calendar/calendar.js.map +1 -0
  74. package/dist/tools/calendar/event.d.ts +20 -0
  75. package/dist/tools/calendar/event.d.ts.map +1 -0
  76. package/dist/tools/calendar/event.js +465 -0
  77. package/dist/tools/calendar/event.js.map +1 -0
  78. package/dist/tools/calendar/index.d.ts +19 -0
  79. package/dist/tools/calendar/index.d.ts.map +1 -0
  80. package/dist/tools/calendar/index.js +37 -0
  81. package/dist/tools/calendar/index.js.map +1 -0
  82. package/dist/tools/chat/chat.d.ts +11 -0
  83. package/dist/tools/chat/chat.d.ts.map +1 -0
  84. package/dist/tools/chat/chat.js +106 -0
  85. package/dist/tools/chat/chat.js.map +1 -0
  86. package/dist/tools/chat/index.d.ts +11 -0
  87. package/dist/tools/chat/index.d.ts.map +1 -0
  88. package/dist/tools/chat/index.js +20 -0
  89. package/dist/tools/chat/index.js.map +1 -0
  90. package/dist/tools/chat/members.d.ts +9 -0
  91. package/dist/tools/chat/members.d.ts.map +1 -0
  92. package/dist/tools/chat/members.js +80 -0
  93. package/dist/tools/chat/members.js.map +1 -0
  94. package/dist/tools/common/get-user.d.ts +11 -0
  95. package/dist/tools/common/get-user.d.ts.map +1 -0
  96. package/dist/tools/common/get-user.js +112 -0
  97. package/dist/tools/common/get-user.js.map +1 -0
  98. package/dist/tools/common/index.d.ts +11 -0
  99. package/dist/tools/common/index.d.ts.map +1 -0
  100. package/dist/tools/common/index.js +20 -0
  101. package/dist/tools/common/index.js.map +1 -0
  102. package/dist/tools/common/search-user.d.ts +9 -0
  103. package/dist/tools/common/search-user.d.ts.map +1 -0
  104. package/dist/tools/common/search-user.js +88 -0
  105. package/dist/tools/common/search-user.js.map +1 -0
  106. package/dist/tools/doc/create.d.ts +17 -0
  107. package/dist/tools/doc/create.d.ts.map +1 -0
  108. package/dist/tools/doc/create.js +159 -0
  109. package/dist/tools/doc/create.js.map +1 -0
  110. package/dist/tools/doc/fetch.d.ts +17 -0
  111. package/dist/tools/doc/fetch.d.ts.map +1 -0
  112. package/dist/tools/doc/fetch.js +123 -0
  113. package/dist/tools/doc/fetch.js.map +1 -0
  114. package/dist/tools/doc/index.d.ts +21 -0
  115. package/dist/tools/doc/index.d.ts.map +1 -0
  116. package/dist/tools/doc/index.js +33 -0
  117. package/dist/tools/doc/index.js.map +1 -0
  118. package/dist/tools/doc/shared.d.ts +69 -0
  119. package/dist/tools/doc/shared.d.ts.map +1 -0
  120. package/dist/tools/doc/shared.js +172 -0
  121. package/dist/tools/doc/shared.js.map +1 -0
  122. package/dist/tools/doc/update.d.ts +25 -0
  123. package/dist/tools/doc/update.d.ts.map +1 -0
  124. package/dist/tools/doc/update.js +208 -0
  125. package/dist/tools/doc/update.js.map +1 -0
  126. package/dist/tools/drive/file.d.ts +13 -0
  127. package/dist/tools/drive/file.d.ts.map +1 -0
  128. package/dist/tools/drive/file.js +212 -0
  129. package/dist/tools/drive/file.js.map +1 -0
  130. package/dist/tools/drive/index.d.ts +12 -0
  131. package/dist/tools/drive/index.d.ts.map +1 -0
  132. package/dist/tools/drive/index.js +25 -0
  133. package/dist/tools/drive/index.js.map +1 -0
  134. package/dist/tools/im/format-messages.d.ts +99 -0
  135. package/dist/tools/im/format-messages.d.ts.map +1 -0
  136. package/dist/tools/im/format-messages.js +277 -0
  137. package/dist/tools/im/format-messages.js.map +1 -0
  138. package/dist/tools/im/helpers.d.ts +53 -0
  139. package/dist/tools/im/helpers.d.ts.map +1 -0
  140. package/dist/tools/im/helpers.js +85 -0
  141. package/dist/tools/im/helpers.js.map +1 -0
  142. package/dist/tools/im/index.d.ts +25 -0
  143. package/dist/tools/im/index.d.ts.map +1 -0
  144. package/dist/tools/im/index.js +44 -0
  145. package/dist/tools/im/index.js.map +1 -0
  146. package/dist/tools/im/message-read.d.ts +19 -0
  147. package/dist/tools/im/message-read.d.ts.map +1 -0
  148. package/dist/tools/im/message-read.js +526 -0
  149. package/dist/tools/im/message-read.js.map +1 -0
  150. package/dist/tools/im/message.d.ts +22 -0
  151. package/dist/tools/im/message.d.ts.map +1 -0
  152. package/dist/tools/im/message.js +233 -0
  153. package/dist/tools/im/message.js.map +1 -0
  154. package/dist/tools/im/resource.d.ts +19 -0
  155. package/dist/tools/im/resource.d.ts.map +1 -0
  156. package/dist/tools/im/resource.js +185 -0
  157. package/dist/tools/im/resource.js.map +1 -0
  158. package/dist/tools/im/time-utils.d.ts +70 -0
  159. package/dist/tools/im/time-utils.d.ts.map +1 -0
  160. package/dist/tools/im/time-utils.js +277 -0
  161. package/dist/tools/im/time-utils.js.map +1 -0
  162. package/dist/tools/index.d.ts +85 -0
  163. package/dist/tools/index.d.ts.map +1 -0
  164. package/dist/tools/index.js +135 -0
  165. package/dist/tools/index.js.map +1 -0
  166. package/dist/tools/oauth.d.ts +15 -0
  167. package/dist/tools/oauth.d.ts.map +1 -0
  168. package/dist/tools/oauth.js +379 -0
  169. package/dist/tools/oauth.js.map +1 -0
  170. package/dist/tools/search/doc-search.d.ts +9 -0
  171. package/dist/tools/search/doc-search.d.ts.map +1 -0
  172. package/dist/tools/search/doc-search.js +219 -0
  173. package/dist/tools/search/doc-search.js.map +1 -0
  174. package/dist/tools/search/index.d.ts +11 -0
  175. package/dist/tools/search/index.d.ts.map +1 -0
  176. package/dist/tools/search/index.js +18 -0
  177. package/dist/tools/search/index.js.map +1 -0
  178. package/dist/tools/sheets/index.d.ts +11 -0
  179. package/dist/tools/sheets/index.d.ts.map +1 -0
  180. package/dist/tools/sheets/index.js +18 -0
  181. package/dist/tools/sheets/index.js.map +1 -0
  182. package/dist/tools/sheets/sheet.d.ts +11 -0
  183. package/dist/tools/sheets/sheet.d.ts.map +1 -0
  184. package/dist/tools/sheets/sheet.js +332 -0
  185. package/dist/tools/sheets/sheet.js.map +1 -0
  186. package/dist/tools/task/index.d.ts +12 -0
  187. package/dist/tools/task/index.d.ts.map +1 -0
  188. package/dist/tools/task/index.js +30 -0
  189. package/dist/tools/task/index.js.map +1 -0
  190. package/dist/tools/task/task.d.ts +13 -0
  191. package/dist/tools/task/task.d.ts.map +1 -0
  192. package/dist/tools/task/task.js +225 -0
  193. package/dist/tools/task/task.js.map +1 -0
  194. package/dist/tools/task/tasklist.d.ts +13 -0
  195. package/dist/tools/task/tasklist.d.ts.map +1 -0
  196. package/dist/tools/task/tasklist.js +206 -0
  197. package/dist/tools/task/tasklist.js.map +1 -0
  198. package/dist/tools/wiki/index.d.ts +11 -0
  199. package/dist/tools/wiki/index.d.ts.map +1 -0
  200. package/dist/tools/wiki/index.js +20 -0
  201. package/dist/tools/wiki/index.js.map +1 -0
  202. package/dist/tools/wiki/node.d.ts +11 -0
  203. package/dist/tools/wiki/node.d.ts.map +1 -0
  204. package/dist/tools/wiki/node.js +112 -0
  205. package/dist/tools/wiki/node.js.map +1 -0
  206. package/dist/tools/wiki/space.d.ts +11 -0
  207. package/dist/tools/wiki/space.d.ts.map +1 -0
  208. package/dist/tools/wiki/space.js +125 -0
  209. package/dist/tools/wiki/space.js.map +1 -0
  210. package/dist/utils/index.d.ts +8 -0
  211. package/dist/utils/index.d.ts.map +1 -0
  212. package/dist/utils/index.js +8 -0
  213. package/dist/utils/index.js.map +1 -0
  214. package/dist/utils/logger.d.ts +36 -0
  215. package/dist/utils/logger.d.ts.map +1 -0
  216. package/dist/utils/logger.js +101 -0
  217. package/dist/utils/logger.js.map +1 -0
  218. package/eslint.config.js +13 -0
  219. package/package.json +54 -0
  220. package/skills/feishu-bitable/SKILL.md +248 -0
  221. package/skills/feishu-bitable/references/examples.md +813 -0
  222. package/skills/feishu-bitable/references/field-properties.md +763 -0
  223. package/skills/feishu-bitable/references/record-values.md +911 -0
  224. package/skills/feishu-calendar/SKILL.md +244 -0
  225. package/skills/feishu-channel-rules/SKILL.md +18 -0
  226. package/skills/feishu-channel-rules/references/markdown-syntax.md +138 -0
  227. package/skills/feishu-create-doc/SKILL.md +719 -0
  228. package/skills/feishu-fetch-doc/SKILL.md +93 -0
  229. package/skills/feishu-im-read/SKILL.md +163 -0
  230. package/skills/feishu-task/SKILL.md +293 -0
  231. package/skills/feishu-troubleshoot/SKILL.md +70 -0
  232. package/skills/feishu-update-doc/SKILL.md +285 -0
  233. package/src/core/api-error.ts +342 -0
  234. package/src/core/auth-errors.ts +27 -0
  235. package/src/core/config.ts +134 -0
  236. package/src/core/device-flow.ts +314 -0
  237. package/src/core/index.ts +16 -0
  238. package/src/core/lark-client.ts +391 -0
  239. package/src/core/token-store.ts +249 -0
  240. package/src/core/types.ts +302 -0
  241. package/src/core/uat-client.ts +298 -0
  242. package/src/core/version.ts +53 -0
  243. package/src/index.ts +138 -0
  244. package/src/tools/bitable/app.ts +390 -0
  245. package/src/tools/bitable/field.ts +406 -0
  246. package/src/tools/bitable/index.ts +43 -0
  247. package/src/tools/bitable/record.ts +559 -0
  248. package/src/tools/bitable/table.ts +472 -0
  249. package/src/tools/calendar/calendar.ts +254 -0
  250. package/src/tools/calendar/event.ts +606 -0
  251. package/src/tools/calendar/index.ts +41 -0
  252. package/src/tools/chat/chat.ts +127 -0
  253. package/src/tools/chat/index.ts +24 -0
  254. package/src/tools/chat/members.ts +93 -0
  255. package/src/tools/common/get-user.ts +127 -0
  256. package/src/tools/common/index.ts +24 -0
  257. package/src/tools/common/search-user.ts +99 -0
  258. package/src/tools/doc/create.ts +184 -0
  259. package/src/tools/doc/fetch.ts +149 -0
  260. package/src/tools/doc/index.ts +38 -0
  261. package/src/tools/doc/shared.ts +228 -0
  262. package/src/tools/doc/update.ts +240 -0
  263. package/src/tools/drive/file.ts +265 -0
  264. package/src/tools/drive/index.ts +29 -0
  265. package/src/tools/im/format-messages.ts +391 -0
  266. package/src/tools/im/helpers.ts +109 -0
  267. package/src/tools/im/index.ts +49 -0
  268. package/src/tools/im/message-read.ts +676 -0
  269. package/src/tools/im/message.ts +303 -0
  270. package/src/tools/im/resource.ts +225 -0
  271. package/src/tools/im/time-utils.ts +347 -0
  272. package/src/tools/index.ts +205 -0
  273. package/src/tools/oauth.ts +460 -0
  274. package/src/tools/search/doc-search.ts +250 -0
  275. package/src/tools/search/index.ts +22 -0
  276. package/src/tools/sheets/index.ts +22 -0
  277. package/src/tools/sheets/sheet.ts +382 -0
  278. package/src/tools/task/index.ts +34 -0
  279. package/src/tools/task/task.ts +265 -0
  280. package/src/tools/task/tasklist.ts +262 -0
  281. package/src/tools/wiki/index.ts +24 -0
  282. package/src/tools/wiki/node.ts +131 -0
  283. package/src/tools/wiki/space.ts +152 -0
  284. package/src/utils/index.ts +8 -0
  285. package/src/utils/logger.ts +132 -0
  286. package/tests/core/config.test.ts +238 -0
  287. package/tests/core/device-flow.test.ts +490 -0
  288. package/tests/core/lark-client.test.ts +378 -0
  289. package/tests/core/token-store.test.ts +438 -0
  290. package/tests/index.test.ts +360 -0
  291. package/tests/tools/doc/create.test.ts +224 -0
  292. package/tests/tools/doc/fetch.test.ts +182 -0
  293. package/tests/tools/doc/shared.test.ts +183 -0
  294. package/tests/tools/doc/update.test.ts +330 -0
  295. package/tests/tools/im/format-messages.test.ts +184 -0
  296. package/tests/tools/im/time-utils.test.ts +178 -0
  297. package/tests/utils/logger.test.ts +140 -0
  298. package/tsconfig.json +20 -0
@@ -0,0 +1,315 @@
1
+ /**
2
+ * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ *
5
+ * Feishu / Lark SDK client management for MCP Server.
6
+ *
7
+ * Provides `LarkClient` — a unified manager for Lark SDK client instances,
8
+ * bot identity probing, and token management.
9
+ *
10
+ * Adapted from openclaw-lark for MCP Server architecture.
11
+ * - Removed OpenClaw runtime dependencies
12
+ * - Simplified singleton pattern for MCP Server use case
13
+ * - Works standalone with environment variables
14
+ */
15
+ /* eslint-disable @typescript-eslint/no-explicit-any */
16
+ import * as Lark from '@larksuiteoapi/node-sdk';
17
+ import { loadAndValidateConfig, validateConfig } from './config.js';
18
+ import { logger } from '../utils/logger.js';
19
+ const log = logger('lark-client');
20
+ // ---------------------------------------------------------------------------
21
+ // Brand → SDK domain
22
+ // ---------------------------------------------------------------------------
23
+ const BRAND_TO_DOMAIN = {
24
+ feishu: Lark.Domain.Feishu,
25
+ lark: Lark.Domain.Lark,
26
+ };
27
+ /** Map a `LarkBrand` to the SDK `domain` parameter. */
28
+ function resolveBrand(brand) {
29
+ return BRAND_TO_DOMAIN[brand ?? 'feishu'] ?? brand.replace(/\/+$/, '');
30
+ }
31
+ // ---------------------------------------------------------------------------
32
+ // User-Agent setup
33
+ // ---------------------------------------------------------------------------
34
+ const GLOBAL_LARK_USER_AGENT_KEY = 'LARK_USER_AGENT';
35
+ const USER_AGENT = 'cc-lark/0.1.0';
36
+ function installGlobalUserAgent() {
37
+ // node-sdk built-in interceptor reads global.LARK_USER_AGENT and sets User-Agent
38
+ globalThis[GLOBAL_LARK_USER_AGENT_KEY] = USER_AGENT;
39
+ }
40
+ // Install User-Agent on module load
41
+ installGlobalUserAgent();
42
+ // Set up HTTP interceptor to add User-Agent header
43
+ Lark.defaultHttpInstance.interceptors.request.handlers = [];
44
+ Lark.defaultHttpInstance.interceptors.request.use((req) => {
45
+ if (req.headers) {
46
+ req.headers['User-Agent'] = USER_AGENT;
47
+ }
48
+ return req;
49
+ }, undefined, { synchronous: true });
50
+ // ---------------------------------------------------------------------------
51
+ // LarkClient
52
+ // ---------------------------------------------------------------------------
53
+ /**
54
+ * Lark SDK client wrapper for MCP Server.
55
+ *
56
+ * Provides:
57
+ * - Lazy SDK client initialization
58
+ * - Bot identity probing and caching
59
+ * - Singleton pattern for global access
60
+ */
61
+ export class LarkClient {
62
+ _config;
63
+ _sdk = null;
64
+ _botOpenId;
65
+ _botName;
66
+ _lastProbeResult = null;
67
+ _lastProbeAt = 0;
68
+ // ---- Singleton instance ---------------------------------------------------
69
+ static _instance = null;
70
+ /**
71
+ * Get the singleton LarkClient instance.
72
+ * Creates one from environment variables if not already created.
73
+ */
74
+ static getInstance() {
75
+ if (!LarkClient._instance) {
76
+ const config = loadAndValidateConfig();
77
+ LarkClient._instance = new LarkClient(config);
78
+ }
79
+ return LarkClient._instance;
80
+ }
81
+ /**
82
+ * Create a new LarkClient from environment variables.
83
+ * This will replace the singleton instance.
84
+ */
85
+ static fromEnv() {
86
+ const config = loadAndValidateConfig();
87
+ const instance = new LarkClient(config);
88
+ LarkClient._instance = instance;
89
+ return instance;
90
+ }
91
+ /**
92
+ * Create a LarkClient from explicit credentials.
93
+ * This replaces the singleton instance.
94
+ */
95
+ static fromCredentials(credentials) {
96
+ const config = {
97
+ appId: credentials.appId ?? '',
98
+ appSecret: credentials.appSecret ?? '',
99
+ brand: credentials.brand ?? 'feishu',
100
+ encryptKey: credentials.encryptKey,
101
+ verificationToken: credentials.verificationToken,
102
+ };
103
+ const validation = validateConfig(config);
104
+ if (!validation.valid) {
105
+ throw new Error(`Invalid credentials: ${validation.errors.join(', ')}`);
106
+ }
107
+ const instance = new LarkClient(config);
108
+ LarkClient._instance = instance;
109
+ return instance;
110
+ }
111
+ /**
112
+ * Reset the singleton instance.
113
+ * Useful for testing or when credentials change.
114
+ */
115
+ static resetInstance() {
116
+ if (LarkClient._instance) {
117
+ LarkClient._instance.dispose();
118
+ LarkClient._instance = null;
119
+ }
120
+ }
121
+ // --------------------------------------------------------------------------
122
+ /**
123
+ * Create a new LarkClient instance.
124
+ *
125
+ * @param config - Feishu configuration
126
+ */
127
+ constructor(config) {
128
+ this._config = config;
129
+ log.debug('LarkClient created', { appId: config.appId, brand: config.brand });
130
+ }
131
+ /** The configuration used by this client. */
132
+ get config() {
133
+ return this._config;
134
+ }
135
+ /** The App ID for this client. */
136
+ get appId() {
137
+ return this._config.appId;
138
+ }
139
+ /** The brand (feishu/lark) for this client. */
140
+ get brand() {
141
+ return this._config.brand ?? 'feishu';
142
+ }
143
+ // ---- SDK client (lazy) ---------------------------------------------------
144
+ /**
145
+ * Get the Lark SDK client instance.
146
+ * Lazily creates the client on first access.
147
+ */
148
+ get sdk() {
149
+ if (!this._sdk) {
150
+ const { appId, appSecret } = this.requireCredentials();
151
+ this._sdk = new Lark.Client({
152
+ appId,
153
+ appSecret,
154
+ appType: Lark.AppType.SelfBuild,
155
+ domain: resolveBrand(this._config.brand),
156
+ });
157
+ log.debug('SDK client created', { appId, brand: this._config.brand });
158
+ }
159
+ return this._sdk;
160
+ }
161
+ // ---- Bot identity ---------------------------------------------------------
162
+ /**
163
+ * Probe bot identity via the `bot/v3/info` API.
164
+ * Results are cached on the instance for subsequent access via
165
+ * `botOpenId` / `botName`.
166
+ *
167
+ * @param opts - Options including maxAgeMs for cache validity
168
+ * @returns Probe result with bot info or error
169
+ */
170
+ async probe(opts) {
171
+ const maxAge = opts?.maxAgeMs ?? 0;
172
+ if (maxAge > 0 && this._lastProbeResult && Date.now() - this._lastProbeAt < maxAge) {
173
+ return this._lastProbeResult;
174
+ }
175
+ if (!this._config.appId || !this._config.appSecret) {
176
+ return { ok: false, error: 'missing credentials (appId, appSecret)' };
177
+ }
178
+ try {
179
+ log.debug('Probing bot identity', { appId: this._config.appId });
180
+ const res = await this.sdk.request({
181
+ method: 'GET',
182
+ url: '/open-apis/bot/v3/info',
183
+ data: {},
184
+ });
185
+ if (res.code !== 0) {
186
+ const result = {
187
+ ok: false,
188
+ appId: this._config.appId,
189
+ error: `API error: ${res.msg || `code ${res.code}`}`,
190
+ };
191
+ this._lastProbeResult = result;
192
+ this._lastProbeAt = Date.now();
193
+ log.warn('Bot probe failed', { code: res.code, msg: res.msg });
194
+ return result;
195
+ }
196
+ const bot = res.bot || res.data?.bot;
197
+ this._botOpenId = bot?.open_id;
198
+ this._botName = bot?.bot_name;
199
+ const result = {
200
+ ok: true,
201
+ appId: this._config.appId,
202
+ botName: this._botName,
203
+ botOpenId: this._botOpenId,
204
+ };
205
+ this._lastProbeResult = result;
206
+ this._lastProbeAt = Date.now();
207
+ log.info('Bot identity probed', { botName: this._botName, botOpenId: this._botOpenId });
208
+ return result;
209
+ }
210
+ catch (err) {
211
+ const result = {
212
+ ok: false,
213
+ appId: this._config.appId,
214
+ error: err instanceof Error ? err.message : String(err),
215
+ };
216
+ this._lastProbeResult = result;
217
+ this._lastProbeAt = Date.now();
218
+ log.error('Bot probe error', { error: result.error });
219
+ return result;
220
+ }
221
+ }
222
+ /** Cached bot open_id (available after `probe()`). */
223
+ get botOpenId() {
224
+ return this._botOpenId;
225
+ }
226
+ /** Cached bot name (available after `probe()`). */
227
+ get botName() {
228
+ return this._botName;
229
+ }
230
+ /** Last probe result (cached). */
231
+ get lastProbeResult() {
232
+ return this._lastProbeResult;
233
+ }
234
+ // ---- Token management ----------------------------------------------------
235
+ /**
236
+ * Get tenant access token.
237
+ * This is primarily for debugging - the SDK handles tokens automatically.
238
+ */
239
+ async getTenantAccessToken() {
240
+ try {
241
+ const res = await this.sdk.request({
242
+ method: 'POST',
243
+ url: '/open-apis/auth/v3/tenant_access_token/internal',
244
+ data: {
245
+ app_id: this._config.appId,
246
+ app_secret: this._config.appSecret,
247
+ },
248
+ });
249
+ if (res.code !== 0) {
250
+ log.warn('Failed to get tenant access token', { code: res.code, msg: res.msg });
251
+ return null;
252
+ }
253
+ return res.tenant_access_token ?? null;
254
+ }
255
+ catch (err) {
256
+ log.error('Error getting tenant access token', { error: err });
257
+ return null;
258
+ }
259
+ }
260
+ // ---- Utility methods ------------------------------------------------------
261
+ /**
262
+ * Clear cached probe result.
263
+ * Call this to force a fresh probe on next call.
264
+ */
265
+ clearProbeCache() {
266
+ this._lastProbeResult = null;
267
+ this._lastProbeAt = 0;
268
+ this._botOpenId = undefined;
269
+ this._botName = undefined;
270
+ }
271
+ /**
272
+ * Dispose of the client.
273
+ * Clears all caches and the SDK client reference.
274
+ */
275
+ dispose() {
276
+ log.debug('Disposing LarkClient', { appId: this._config.appId });
277
+ this.clearProbeCache();
278
+ this._sdk = null;
279
+ }
280
+ // ---- Private helpers ------------------------------------------------------
281
+ /** Assert credentials exist or throw. */
282
+ requireCredentials() {
283
+ const appId = this._config.appId;
284
+ const appSecret = this._config.appSecret;
285
+ if (!appId || !appSecret) {
286
+ throw new Error(`LarkClient: appId and appSecret are required`);
287
+ }
288
+ return { appId, appSecret };
289
+ }
290
+ }
291
+ // ---------------------------------------------------------------------------
292
+ // Convenience functions
293
+ // ---------------------------------------------------------------------------
294
+ /**
295
+ * Get the singleton LarkClient instance.
296
+ * Creates one from environment variables if not already created.
297
+ */
298
+ export function getLarkClient() {
299
+ return LarkClient.getInstance();
300
+ }
301
+ /**
302
+ * Create a LarkClient from environment variables.
303
+ * This will replace the singleton instance.
304
+ */
305
+ export function createLarkClient() {
306
+ return LarkClient.fromEnv();
307
+ }
308
+ /**
309
+ * Reset the singleton LarkClient instance.
310
+ * Useful for testing or when credentials change.
311
+ */
312
+ export function resetLarkClient() {
313
+ LarkClient.resetInstance();
314
+ }
315
+ //# sourceMappingURL=lark-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lark-client.js","sourceRoot":"","sources":["../../src/core/lark-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ *
5
+ * UAT (User Access Token) persistent storage for cc-lark MCP Server.
6
+ *
7
+ * Stores OAuth token data in a file-based storage in the user's home directory.
8
+ * For MCP Server architecture, we use a simple JSON file approach instead of
9
+ * OS-native credential services for simplicity and portability.
10
+ *
11
+ * Storage location: ~/.cc-lark/tokens.json
12
+ *
13
+ * Adapted from openclaw-lark for MCP Server architecture.
14
+ */
15
+ export interface StoredUAToken {
16
+ userOpenId: string;
17
+ appId: string;
18
+ accessToken: string;
19
+ refreshToken: string;
20
+ expiresAt: number;
21
+ refreshExpiresAt: number;
22
+ scope: string;
23
+ grantedAt: number;
24
+ }
25
+ /** Mask a token for safe logging: only the last 4 chars are visible. */
26
+ export declare function maskToken(token: string): string;
27
+ /**
28
+ * Read the stored UAT for a given (appId, userOpenId) pair.
29
+ * Returns `null` when no entry exists or the payload is unparseable.
30
+ */
31
+ export declare function getStoredToken(appId: string, userOpenId: string): Promise<StoredUAToken | null>;
32
+ /**
33
+ * Persist a UAT using file-based storage.
34
+ *
35
+ * Overwrites any existing entry for the same (appId, userOpenId).
36
+ */
37
+ export declare function setStoredToken(token: StoredUAToken): Promise<void>;
38
+ /**
39
+ * Remove a stored UAT from the storage.
40
+ */
41
+ export declare function removeStoredToken(appId: string, userOpenId: string): Promise<void>;
42
+ /**
43
+ * List all stored tokens for a given appId.
44
+ */
45
+ export declare function listStoredTokens(appId: string): Promise<StoredUAToken[]>;
46
+ /**
47
+ * Clear all stored tokens.
48
+ * Use with caution - this removes all stored credentials.
49
+ */
50
+ export declare function clearAllTokens(): Promise<void>;
51
+ /**
52
+ * Determine the freshness of a stored token.
53
+ *
54
+ * - `"valid"` – access_token is still good (expires > 5 min from now)
55
+ * - `"needs_refresh"` – access_token expired/expiring but refresh_token is valid
56
+ * - `"expired"` – both tokens are expired; re-authorization required
57
+ */
58
+ export declare function tokenStatus(token: StoredUAToken): 'valid' | 'needs_refresh' | 'expired';
59
+ /**
60
+ * Get the path to the tokens storage file.
61
+ */
62
+ export declare function getTokensFilePath(): string;
63
+ /**
64
+ * Check if tokens storage file exists.
65
+ */
66
+ export declare function tokensStorageExists(): Promise<boolean>;
67
+ //# sourceMappingURL=token-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-store.d.ts","sourceRoot":"","sources":["../../src/core/token-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAaH,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AA0BD,wEAAwE;AACxE,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAG/C;AAkED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CASrG;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAMxE;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAUxF;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAW9E;AAED;;;GAGG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CASpD;AAMD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,GAAG,eAAe,GAAG,SAAS,CASvF;AAMD;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;GAEG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC,CAO5D"}
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ *
5
+ * UAT (User Access Token) persistent storage for cc-lark MCP Server.
6
+ *
7
+ * Stores OAuth token data in a file-based storage in the user's home directory.
8
+ * For MCP Server architecture, we use a simple JSON file approach instead of
9
+ * OS-native credential services for simplicity and portability.
10
+ *
11
+ * Storage location: ~/.cc-lark/tokens.json
12
+ *
13
+ * Adapted from openclaw-lark for MCP Server architecture.
14
+ */
15
+ import { mkdir, readFile, writeFile, unlink, chmod, stat } from 'node:fs/promises';
16
+ import { join } from 'node:path';
17
+ import { homedir } from 'node:os';
18
+ import { logger } from '../utils/logger.js';
19
+ const log = logger('token-store');
20
+ // ---------------------------------------------------------------------------
21
+ // Constants
22
+ // ---------------------------------------------------------------------------
23
+ const TOKENS_DIR = join(homedir(), '.cc-lark');
24
+ const TOKENS_FILE = join(TOKENS_DIR, 'tokens.json');
25
+ /** Refresh proactively when access_token expires within this window. */
26
+ const REFRESH_AHEAD_MS = 5 * 60 * 1000; // 5 minutes
27
+ // ---------------------------------------------------------------------------
28
+ // Helpers
29
+ // ---------------------------------------------------------------------------
30
+ function accountKey(appId, userOpenId) {
31
+ return `${appId}:${userOpenId}`;
32
+ }
33
+ /** Mask a token for safe logging: only the last 4 chars are visible. */
34
+ export function maskToken(token) {
35
+ if (token.length <= 8)
36
+ return '****';
37
+ return `****${token.slice(-4)}`;
38
+ }
39
+ // ---------------------------------------------------------------------------
40
+ // File operations
41
+ // ---------------------------------------------------------------------------
42
+ /**
43
+ * Ensure the tokens directory exists with proper permissions.
44
+ */
45
+ async function ensureTokensDir() {
46
+ try {
47
+ await mkdir(TOKENS_DIR, { recursive: true, mode: 0o700 });
48
+ }
49
+ catch (err) {
50
+ if (err.code !== 'EEXIST') {
51
+ throw err;
52
+ }
53
+ }
54
+ // Ensure directory has restrictive permissions
55
+ try {
56
+ await chmod(TOKENS_DIR, 0o700);
57
+ }
58
+ catch {
59
+ // Ignore permission errors on Windows
60
+ }
61
+ }
62
+ /**
63
+ * Read the token storage file.
64
+ * Returns null if the file doesn't exist or is invalid.
65
+ */
66
+ async function readTokenStorage() {
67
+ try {
68
+ const data = await readFile(TOKENS_FILE, 'utf8');
69
+ const parsed = JSON.parse(data);
70
+ if (parsed.version !== 1) {
71
+ log.warn('unsupported token storage version, ignoring');
72
+ return null;
73
+ }
74
+ return parsed;
75
+ }
76
+ catch (err) {
77
+ if (err.code === 'ENOENT') {
78
+ return null;
79
+ }
80
+ log.warn(`failed to read token storage: ${err instanceof Error ? err.message : err}`);
81
+ return null;
82
+ }
83
+ }
84
+ /**
85
+ * Write the token storage file.
86
+ */
87
+ async function writeTokenStorage(storage) {
88
+ await ensureTokensDir();
89
+ const data = JSON.stringify(storage, null, 2);
90
+ await writeFile(TOKENS_FILE, data, { mode: 0o600 });
91
+ // Ensure file has restrictive permissions
92
+ try {
93
+ await chmod(TOKENS_FILE, 0o600);
94
+ }
95
+ catch {
96
+ // Ignore permission errors on Windows
97
+ }
98
+ }
99
+ // ---------------------------------------------------------------------------
100
+ // Public API – Credential operations
101
+ // ---------------------------------------------------------------------------
102
+ /**
103
+ * Read the stored UAT for a given (appId, userOpenId) pair.
104
+ * Returns `null` when no entry exists or the payload is unparseable.
105
+ */
106
+ export async function getStoredToken(appId, userOpenId) {
107
+ try {
108
+ const storage = await readTokenStorage();
109
+ if (!storage)
110
+ return null;
111
+ const key = accountKey(appId, userOpenId);
112
+ return storage.tokens[key] ?? null;
113
+ }
114
+ catch {
115
+ return null;
116
+ }
117
+ }
118
+ /**
119
+ * Persist a UAT using file-based storage.
120
+ *
121
+ * Overwrites any existing entry for the same (appId, userOpenId).
122
+ */
123
+ export async function setStoredToken(token) {
124
+ const storage = (await readTokenStorage()) ?? { version: 1, tokens: {} };
125
+ const key = accountKey(token.appId, token.userOpenId);
126
+ storage.tokens[key] = token;
127
+ await writeTokenStorage(storage);
128
+ log.info(`saved UAT for ${token.userOpenId} (at:${maskToken(token.accessToken)})`);
129
+ }
130
+ /**
131
+ * Remove a stored UAT from the storage.
132
+ */
133
+ export async function removeStoredToken(appId, userOpenId) {
134
+ const storage = await readTokenStorage();
135
+ if (!storage)
136
+ return;
137
+ const key = accountKey(appId, userOpenId);
138
+ if (storage.tokens[key]) {
139
+ delete storage.tokens[key];
140
+ await writeTokenStorage(storage);
141
+ log.info(`removed UAT for ${userOpenId}`);
142
+ }
143
+ }
144
+ /**
145
+ * List all stored tokens for a given appId.
146
+ */
147
+ export async function listStoredTokens(appId) {
148
+ const storage = await readTokenStorage();
149
+ if (!storage)
150
+ return [];
151
+ const tokens = [];
152
+ for (const [key, token] of Object.entries(storage.tokens)) {
153
+ if (key.startsWith(`${appId}:`)) {
154
+ tokens.push(token);
155
+ }
156
+ }
157
+ return tokens;
158
+ }
159
+ /**
160
+ * Clear all stored tokens.
161
+ * Use with caution - this removes all stored credentials.
162
+ */
163
+ export async function clearAllTokens() {
164
+ try {
165
+ await unlink(TOKENS_FILE);
166
+ log.info('cleared all stored tokens');
167
+ }
168
+ catch (err) {
169
+ if (err.code !== 'ENOENT') {
170
+ throw err;
171
+ }
172
+ }
173
+ }
174
+ // ---------------------------------------------------------------------------
175
+ // Token validity check
176
+ // ---------------------------------------------------------------------------
177
+ /**
178
+ * Determine the freshness of a stored token.
179
+ *
180
+ * - `"valid"` – access_token is still good (expires > 5 min from now)
181
+ * - `"needs_refresh"` – access_token expired/expiring but refresh_token is valid
182
+ * - `"expired"` – both tokens are expired; re-authorization required
183
+ */
184
+ export function tokenStatus(token) {
185
+ const now = Date.now();
186
+ if (now < token.expiresAt - REFRESH_AHEAD_MS) {
187
+ return 'valid';
188
+ }
189
+ if (now < token.refreshExpiresAt) {
190
+ return 'needs_refresh';
191
+ }
192
+ return 'expired';
193
+ }
194
+ // ---------------------------------------------------------------------------
195
+ // Storage path utilities (for testing/debugging)
196
+ // ---------------------------------------------------------------------------
197
+ /**
198
+ * Get the path to the tokens storage file.
199
+ */
200
+ export function getTokensFilePath() {
201
+ return TOKENS_FILE;
202
+ }
203
+ /**
204
+ * Check if tokens storage file exists.
205
+ */
206
+ export async function tokensStorageExists() {
207
+ try {
208
+ await stat(TOKENS_FILE);
209
+ return true;
210
+ }
211
+ catch {
212
+ return false;
213
+ }
214
+ }
215
+ //# sourceMappingURL=token-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-store.js","sourceRoot":"","sources":["../../src/core/token-store.ts"],"names":[],"mappings":"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"}