Skip to main content

open_lark/
lib.rs

1//! OpenLark 官方入口 crate。
2//!
3//! 普通用户应优先使用 `openlark`,通过业务 feature 开启所需能力:
4//!
5//! ```toml
6//! [dependencies]
7//! openlark = { version = "0.17.0", default-features = false, features = ["auth", "docs-drive", "docs-bitable", "webhook-signature"] }
8//! ```
9//!
10//! - 统一客户端入口:[`Client`]
11//! - 高级业务模块入口:[`auth`]、[`communication`]、[`docs`]、[`workflow`] 等
12//! - 统一预导出:[`prelude`]
13//!
14//! 若只想要单一业务域的最小依赖,再直接使用 `openlark-{domain}` 子 crate。
15//!
16//! 推荐顺序:
17//!
18//! - 运行时入口:[`Client`] / [`ClientBuilder`]
19//! - 导入入口:[`prelude`]
20//! - 业务命名空间:`open_lark::auth`、`open_lark::communication`、`open_lark::docs`
21//! - 最小依赖场景:直接依赖对应 `openlark-{domain}` crate
22
23// 允许测试模块中的未使用导入(测试桩代码常见模式)
24#![allow(unused_imports)]
25
26// ============================================================================
27// 核心类型导出
28// ============================================================================
29
30#[allow(deprecated)]
31pub use openlark_client::Config;
32pub use openlark_client::{Client, ClientBuilder, Error, Result};
33pub use openlark_core::SDKResult;
34pub use openlark_core::config::Config as CoreConfig;
35pub use openlark_core::error::{CoreError, ErrorCode, ErrorSeverity, ErrorTrait, ErrorType};
36pub use openlark_core::req_option::RequestOption;
37
38#[cfg(feature = "websocket")]
39/// WebSocket 客户端相关类型导出。
40pub mod ws_client {
41    pub use openlark_client::ws_client::*;
42}
43
44// ============================================================================
45// 业务命名空间导出
46// ============================================================================
47
48#[cfg(feature = "auth")]
49pub use openlark_auth as auth;
50
51#[cfg(feature = "communication")]
52pub use openlark_communication as communication;
53
54#[cfg(any(
55    feature = "docs",
56    feature = "docs-ccm",
57    feature = "docs-base",
58    feature = "docs-bitable",
59    feature = "docs-drive",
60    feature = "docs-explorer",
61    feature = "docs-sheets",
62    feature = "docs-sheets-v2",
63    feature = "docs-sheets-v3",
64    feature = "docs-full"
65))]
66pub use openlark_docs as docs;
67
68#[cfg(feature = "hr")]
69pub use openlark_hr as hr;
70
71#[cfg(feature = "ai")]
72pub use openlark_ai as ai;
73
74#[cfg(feature = "helpdesk")]
75pub use openlark_helpdesk as helpdesk;
76
77#[cfg(feature = "mail")]
78pub use openlark_mail as mail;
79
80#[cfg(feature = "meeting")]
81pub use openlark_meeting as meeting;
82
83#[cfg(feature = "application")]
84pub use openlark_application as application;
85
86#[cfg(feature = "security")]
87pub use openlark_security as security;
88
89#[cfg(feature = "workflow")]
90pub use openlark_workflow as workflow;
91
92#[cfg(feature = "platform")]
93pub use openlark_platform as platform;
94
95#[cfg(feature = "analytics")]
96pub use openlark_analytics as analytics;
97
98#[cfg(feature = "user")]
99pub use openlark_user as user;
100
101#[cfg(feature = "webhook")]
102pub use openlark_webhook as webhook;
103
104#[cfg(feature = "cardkit")]
105pub use openlark_cardkit as cardkit;
106
107// ============================================================================
108// 预导出模块
109// ============================================================================
110
111/// 面向 `openlark` 用户的统一预导出。
112///
113/// 该模块只导出"创建客户端 + 顶层业务入口"所需的稳定公共类型。
114/// registry / feature loader / traits 等高级客户端层能力保留在 `openlark-client`。
115pub mod prelude {
116    pub use crate::SDKResult;
117    pub use crate::{Client, ClientBuilder, CoreConfig, Error, Result};
118    pub use crate::{CoreError, ErrorCode, ErrorSeverity, ErrorTrait, ErrorType, RequestOption};
119    pub use openlark_core::prelude::*;
120}
121
122#[cfg(test)]
123mod tests {
124    use super::*;
125
126    fn build_test_client() -> Result<Client> {
127        Client::builder()
128            .app_id("test_app")
129            .app_secret("test_secret")
130            .build()
131    }
132
133    #[test]
134    fn root_prelude_exposes_canonical_core_entrypoints() {
135        use crate::prelude::*;
136
137        let _builder: ClientBuilder = Client::builder();
138        let _config: CoreConfig = CoreConfig::builder()
139            .app_id("test_app")
140            .app_secret("test_secret")
141            .build();
142        let _request_option: Option<RequestOption> = None;
143    }
144
145    #[test]
146    fn root_minimal_builder_works_without_service_features() {
147        let client = build_test_client().expect("client should build with minimal features");
148        assert_eq!(client.config().app_id(), "test_app");
149    }
150
151    #[cfg(feature = "auth")]
152    #[test]
153    fn root_client_exposes_auth_entrypoint() {
154        let client = build_test_client().expect("client should build with auth feature");
155        let _auth = &client.auth;
156    }
157
158    #[cfg(feature = "communication")]
159    #[test]
160    fn root_client_exposes_communication_namespace() {
161        let client = build_test_client().expect("client should build with communication feature");
162        let _communication = &client.communication;
163        let _endpoint = crate::communication::endpoints::IM_V1_MESSAGES;
164    }
165
166    #[cfg(any(
167        feature = "docs",
168        feature = "docs-ccm",
169        feature = "docs-base",
170        feature = "docs-bitable",
171        feature = "docs-drive",
172        feature = "docs-explorer",
173        feature = "docs-sheets",
174        feature = "docs-sheets-v2",
175        feature = "docs-sheets-v3",
176        feature = "docs-full"
177    ))]
178    #[test]
179    fn root_client_exposes_docs_namespace() {
180        let client = build_test_client().expect("client should build with docs feature");
181        let _docs = &client.docs;
182    }
183
184    #[cfg(feature = "hr")]
185    #[test]
186    fn root_client_exposes_hr_entrypoint() {
187        let client = build_test_client().expect("client should build with hr feature");
188        let _hr = &client.hr;
189    }
190
191    #[cfg(feature = "security")]
192    #[test]
193    fn root_client_exposes_security_entrypoint() {
194        let client = build_test_client().expect("client should build with security feature");
195        let _security = &client.security;
196    }
197
198    #[cfg(feature = "docs-bitable")]
199    #[test]
200    fn root_docs_bitable_feature_exposes_query_helper() {
201        let query = crate::docs::BitableRecordQuery::new("app_token", "table_id")
202            .where_equals("状态", "进行中");
203
204        assert_eq!(query.app_token, "app_token");
205        assert_eq!(query.table_id, "table_id");
206    }
207
208    #[cfg(feature = "docs-drive")]
209    #[test]
210    fn root_docs_drive_feature_exposes_drive_helpers() {
211        let upload = crate::docs::DriveUploadFile::new("demo.txt", vec![1, 2, 3]);
212        let range = crate::docs::DriveDownloadRange::from_start(0).with_end(9);
213
214        assert_eq!(upload.file_name, "demo.txt");
215        assert_eq!(upload.size(), 3);
216        assert_eq!(range.to_header_value(), "bytes=0-9");
217    }
218
219    #[cfg(feature = "essential")]
220    #[test]
221    fn root_essential_feature_combines_docs_and_communication_paths() {
222        let client = build_test_client().expect("client should build with essential feature");
223
224        let _communication = &client.communication;
225        let _docs = &client.docs;
226        let recipient = crate::communication::MessageRecipient::open_id("ou_xxx");
227        let query = crate::docs::BitableRecordQuery::new("app_token", "table_id");
228
229        assert_eq!(recipient.receive_id, "ou_xxx");
230        assert_eq!(query.table_id, "table_id");
231    }
232
233    #[cfg(feature = "enterprise")]
234    #[test]
235    fn root_enterprise_feature_combines_quality_critical_domains() {
236        let client = build_test_client().expect("client should build with enterprise feature");
237
238        let _security = &client.security;
239        let _hr = &client.hr;
240        let _workflow = &client.workflow;
241        let action = crate::workflow::ApprovalTaskAction::new(
242            "approval_code",
243            "instance_code",
244            "ou_xxx",
245            "task_123",
246        )
247        .comment("同意");
248
249        assert_eq!(action.task_id, "task_123");
250        assert_eq!(action.comment.as_deref(), Some("同意"));
251    }
252
253    #[cfg(feature = "webhook-full")]
254    #[test]
255    fn root_webhook_full_feature_exposes_signature_and_robot_client() {
256        let client = crate::webhook::WebhookClient::new();
257        let signature = crate::webhook::common::signature::sign(1_700_000_000, "secret");
258
259        let _ = client;
260        assert!(!signature.is_empty());
261    }
262}