@h-ai/capacitor 0.1.0-alpha5

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.
package/LICENSE ADDED
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [2026] [idealworld.group]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,139 @@
1
+ # @h-ai/capacitor
2
+
3
+ Capacitor 原生桥接模块,为 hai Framework 移动应用提供安全 Token 存储、设备信息、推送通知、相机与状态栏等原生能力的统一封装。
4
+
5
+ ## 支持的能力
6
+
7
+ | 能力 | 依赖插件 | 说明 |
8
+ | ---------- | --------------------------------------- | ------------------------------------------------------------- |
9
+ | Token 存储 | `@capacitor/preferences`(必需) | 基于 SharedPreferences / UserDefaults,比 localStorage 更安全 |
10
+ | 设备信息 | `@capacitor/device`(可选) | 平台、版本、型号检测 |
11
+ | 应用版本 | `@capacitor/app`(可选) | 读取 appVersion / appBuild |
12
+ | 推送通知 | `@capacitor/push-notifications`(可选) | 注册 FCM/APNs Token、监听推送事件 |
13
+ | 相机/相册 | `@capacitor/camera`(可选) | 拍照、选取相册图片 |
14
+ | 状态栏 | `@capacitor/status-bar`(可选) | 沉浸式、背景色、样式配置 |
15
+
16
+ ## 快速开始
17
+
18
+ ```ts
19
+ import { capacitor } from '@h-ai/capacitor'
20
+
21
+ // 应用启动时初始化(检测 Capacitor 环境)
22
+ const result = await capacitor.init()
23
+ if (!result.success) {
24
+ // 非 Capacitor 环境(纯 Web)
25
+ }
26
+ ```
27
+
28
+ ### 与 api-client 配合的 Token 安全存储
29
+
30
+ ```ts
31
+ import { api } from '@h-ai/api-client'
32
+ import { createCapacitorTokenStorage } from '@h-ai/capacitor'
33
+
34
+ await api.init({
35
+ baseUrl: 'https://api.example.com/v1',
36
+ auth: {
37
+ storage: createCapacitorTokenStorage(),
38
+ refreshUrl: '/auth/refresh',
39
+ },
40
+ })
41
+ ```
42
+
43
+ ### 设备信息与推送
44
+
45
+ ```ts
46
+ import { capacitor } from '@h-ai/capacitor'
47
+
48
+ const info = await capacitor.device.getInfo()
49
+ if (info.success) {
50
+ // info.data.platform — 'android' | 'ios' | 'web'
51
+ }
52
+
53
+ const reg = await capacitor.push.register()
54
+ if (reg.success) {
55
+ // reg.data.token — FCM/APNs 推送 Token
56
+ }
57
+ ```
58
+
59
+ ### 状态栏
60
+
61
+ ```ts
62
+ import { capacitor } from '@h-ai/capacitor'
63
+
64
+ await capacitor.statusBar.configure({
65
+ style: 'dark',
66
+ overlay: true,
67
+ backgroundColor: '#ffffff',
68
+ })
69
+ ```
70
+
71
+ ### 相机
72
+
73
+ ```ts
74
+ const photo = await capacitor.camera.takePhoto({
75
+ source: 'camera',
76
+ resultType: 'base64',
77
+ quality: 80,
78
+ })
79
+ ```
80
+
81
+ ### Preferences
82
+
83
+ ```ts
84
+ await capacitor.preferences.set('my_key', 'value')
85
+ const result = await capacitor.preferences.get('my_key')
86
+ await capacitor.preferences.remove('my_key')
87
+ ```
88
+
89
+ ## 配置
90
+
91
+ 本模块无配置文件。`capacitor.init()` 仅检测 Capacitor 运行环境是否可用。
92
+
93
+ Capacitor 应用必须使用 SPA 模式:
94
+
95
+ ```ts
96
+ // src/routes/+layout.ts
97
+ export const prerender = true
98
+ export const ssr = false
99
+ ```
100
+
101
+ ## 错误处理
102
+
103
+ 所有异步 API 返回 `HaiResult<T>`,不会直接 throw:
104
+
105
+ ```ts
106
+ import { capacitor, HaiCapacitorError } from '@h-ai/capacitor'
107
+
108
+ const result = await capacitor.camera.takePhoto({ source: 'camera' })
109
+ if (!result.success) {
110
+ if (result.error.code === HaiCapacitorError.CAMERA_FAILED.code) {
111
+ // 相机权限被拒绝或插件未安装
112
+ }
113
+ }
114
+ ```
115
+
116
+ 常用错误码:
117
+
118
+ | 错误码 | code | 说明 |
119
+ | ------------------------------------------ | ------------------- | -------------------- |
120
+ | `HaiCapacitorError.INIT_FAILED` | `hai:capacitor:001` | 初始化失败 |
121
+ | `HaiCapacitorError.NOT_AVAILABLE` | `hai:capacitor:002` | 能力不可用 |
122
+ | `HaiCapacitorError.NOT_INITIALIZED` | `hai:capacitor:060` | 未初始化 |
123
+ | `HaiCapacitorError.INIT_IN_PROGRESS` | `hai:capacitor:061` | 初始化进行中 |
124
+ | `HaiCapacitorError.DEVICE_INFO_FAILED` | `hai:capacitor:010` | 设备信息获取失败 |
125
+ | `HaiCapacitorError.PUSH_REGISTER_FAILED` | `hai:capacitor:020` | 推送注册失败 |
126
+ | `HaiCapacitorError.CAMERA_FAILED` | `hai:capacitor:030` | 相机操作失败 |
127
+ | `HaiCapacitorError.PREFERENCES_GET_FAILED` | `hai:capacitor:050` | Preferences 读取失败 |
128
+
129
+ ## 测试
130
+
131
+ ```bash
132
+ pnpm --filter @h-ai/capacitor test
133
+ ```
134
+
135
+ > 由于原生插件依赖,测试中需 mock `@capacitor/*` 模块。
136
+
137
+ ## License
138
+
139
+ Apache-2.0
@@ -0,0 +1,257 @@
1
+ import * as _h_ai_core from '@h-ai/core';
2
+ import { HaiResult } from '@h-ai/core';
3
+ import { TokenStorage } from '@h-ai/api-client';
4
+
5
+ declare const HaiCapacitorError: {
6
+ readonly INIT_FAILED: _h_ai_core.HaiErrorDef;
7
+ readonly NOT_AVAILABLE: _h_ai_core.HaiErrorDef;
8
+ readonly INIT_IN_PROGRESS: _h_ai_core.HaiErrorDef;
9
+ readonly NOT_INITIALIZED: _h_ai_core.HaiErrorDef;
10
+ readonly PREFERENCES_GET_FAILED: _h_ai_core.HaiErrorDef;
11
+ readonly PREFERENCES_SET_FAILED: _h_ai_core.HaiErrorDef;
12
+ readonly PREFERENCES_REMOVE_FAILED: _h_ai_core.HaiErrorDef;
13
+ readonly DEVICE_INFO_FAILED: _h_ai_core.HaiErrorDef;
14
+ readonly PUSH_REGISTER_FAILED: _h_ai_core.HaiErrorDef;
15
+ readonly PUSH_LISTEN_FAILED: _h_ai_core.HaiErrorDef;
16
+ readonly CAMERA_FAILED: _h_ai_core.HaiErrorDef;
17
+ readonly STATUS_BAR_FAILED: _h_ai_core.HaiErrorDef;
18
+ };
19
+ /** 设备信息操作 */
20
+ interface DeviceOperations {
21
+ /** 获取设备信息(平台、型号、系统版本等) */
22
+ getInfo: () => Promise<HaiResult<DeviceInfo>>;
23
+ /** 获取应用版本信息 */
24
+ getAppVersion: () => Promise<HaiResult<{
25
+ version: string;
26
+ build: string;
27
+ }>>;
28
+ }
29
+ /** 相机操作 */
30
+ interface CameraOperations {
31
+ /** 拍照或选取相册图片 */
32
+ takePhoto: (options?: PhotoOptions) => Promise<HaiResult<PhotoResult>>;
33
+ }
34
+ /** 推送通知操作 */
35
+ interface PushOperations {
36
+ /** 注册推送通知,返回设备 Token */
37
+ register: () => Promise<HaiResult<PushRegistration>>;
38
+ /** 监听推送通知事件,返回清理函数 */
39
+ listen: (callbacks: PushNotificationCallbacks) => Promise<HaiResult<() => Promise<void>>>;
40
+ }
41
+ /** 状态栏操作 */
42
+ interface StatusBarOperations {
43
+ /** 配置状态栏(样式、背景色、沉浸式) */
44
+ configure: (config: StatusBarConfig) => Promise<HaiResult<void>>;
45
+ /** 显示状态栏 */
46
+ show: () => Promise<HaiResult<void>>;
47
+ /** 隐藏状态栏 */
48
+ hide: () => Promise<HaiResult<void>>;
49
+ }
50
+ /** Preferences 操作(安全读写,返回 HaiResult) */
51
+ interface PreferencesOperations {
52
+ /** 安全读取 Preference 值 */
53
+ get: (key: string) => Promise<HaiResult<string | null>>;
54
+ /** 安全写入 Preference 值 */
55
+ set: (key: string, value: string) => Promise<HaiResult<void>>;
56
+ /** 安全删除 Preference 值 */
57
+ remove: (key: string) => Promise<HaiResult<void>>;
58
+ }
59
+ /** Capacitor 模块服务对象接口 */
60
+ interface CapacitorFunctions {
61
+ /** 初始化 Capacitor 模块 */
62
+ init: () => Promise<HaiResult<void>>;
63
+ /** 关闭模块,重置状态 */
64
+ close: () => Promise<void>;
65
+ /** 获取当前平台 */
66
+ getPlatform: () => string;
67
+ /** 是否运行在原生 App 中 */
68
+ isNative: () => boolean;
69
+ /** 是否已初始化 */
70
+ readonly isInitialized: boolean;
71
+ /** 设备信息操作 */
72
+ readonly device: DeviceOperations;
73
+ /** 相机操作 */
74
+ readonly camera: CameraOperations;
75
+ /** 推送通知操作 */
76
+ readonly push: PushOperations;
77
+ /** 状态栏操作 */
78
+ readonly statusBar: StatusBarOperations;
79
+ /** Preferences 安全读写操作 */
80
+ readonly preferences: PreferencesOperations;
81
+ }
82
+ /** 设备平台 */
83
+ type DevicePlatform = 'ios' | 'android' | 'web';
84
+ /** 设备信息 */
85
+ interface DeviceInfo {
86
+ /** 平台(ios / android / web) */
87
+ platform: DevicePlatform;
88
+ /** 操作系统版本(如 '14.5') */
89
+ osVersion: string;
90
+ /** 设备型号(如 'iPhone 14 Pro') */
91
+ model: string;
92
+ /** 设备制造商 */
93
+ manufacturer: string;
94
+ /** 是否为虚拟设备(模拟器) */
95
+ isVirtual: boolean;
96
+ /** 应用版本 */
97
+ appVersion?: string;
98
+ /** 应用 Build 号 */
99
+ appBuild?: string;
100
+ }
101
+ /** 推送通知数据 */
102
+ interface PushNotification {
103
+ /** 通知 ID */
104
+ id: string;
105
+ /** 标题 */
106
+ title?: string;
107
+ /** 正文 */
108
+ body?: string;
109
+ /** 附加数据 */
110
+ data?: Record<string, unknown>;
111
+ }
112
+ /** 推送注册结果 */
113
+ interface PushRegistration {
114
+ /** 设备推送 Token */
115
+ token: string;
116
+ }
117
+ /** 推送通知回调 */
118
+ interface PushNotificationCallbacks {
119
+ /** 收到推送时调用 */
120
+ onReceived?: (notification: PushNotification) => void;
121
+ /** 用户点击推送时调用 */
122
+ onActionPerformed?: (notification: PushNotification) => void;
123
+ }
124
+ /** 照片来源 */
125
+ type PhotoSource = 'camera' | 'photos' | 'prompt';
126
+ /** 照片选项 */
127
+ interface PhotoOptions {
128
+ /** 来源(默认 'prompt') */
129
+ source?: PhotoSource;
130
+ /** 图片质量 0-100(默认 90) */
131
+ quality?: number;
132
+ /** 最大宽度(像素) */
133
+ width?: number;
134
+ /** 最大高度(像素) */
135
+ height?: number;
136
+ /** 返回格式 */
137
+ resultType?: 'uri' | 'base64' | 'dataUrl';
138
+ }
139
+ /** 照片结果 */
140
+ interface PhotoResult {
141
+ /** 图片路径或 base64 数据 */
142
+ data: string;
143
+ /** MIME 类型 */
144
+ format: string;
145
+ }
146
+ /** 状态栏样式 */
147
+ type StatusBarStyle = 'dark' | 'light' | 'default';
148
+ /** 状态栏配置 */
149
+ interface StatusBarConfig {
150
+ /** 状态栏文字样式 */
151
+ style?: StatusBarStyle;
152
+ /** 背景颜色(十六进制) */
153
+ backgroundColor?: string;
154
+ /** 是否覆盖在内容上(沉浸式) */
155
+ overlay?: boolean;
156
+ }
157
+
158
+ /**
159
+ * @h-ai/capacitor — 模块入口(生命周期管理)
160
+ *
161
+ * 提供 Capacitor 原生桥接的初始化与环境检测。
162
+ * `capacitor.init()` 应在应用启动时调用,用于检测 Capacitor 环境可用性。
163
+ *
164
+ * @module capacitor-main
165
+ */
166
+
167
+ /**
168
+ * Capacitor 模块服务对象
169
+ *
170
+ * @example
171
+ * ```ts
172
+ * import { capacitor } from '@h-ai/capacitor'
173
+ *
174
+ * const result = await capacitor.init()
175
+ * if (result.success) {
176
+ * const info = await capacitor.device.getInfo()
177
+ * await capacitor.statusBar.configure({ style: 'dark', overlay: true })
178
+ * }
179
+ * ```
180
+ */
181
+ declare const capacitor: CapacitorFunctions;
182
+
183
+ /**
184
+ * @h-ai/capacitor — Token 存储
185
+ *
186
+ * 基于 Capacitor Preferences 的 TokenStorage 实现,
187
+ * 比浏览器 localStorage 更安全,适用于原生 App 场景。
188
+ *
189
+ * @module capacitor-token-storage
190
+ */
191
+
192
+ /**
193
+ * 创建基于 Capacitor Preferences 的 TokenStorage
194
+ *
195
+ * 使用 `@capacitor/preferences` 插件进行持久化存储,
196
+ * 在 Android 使用 SharedPreferences,iOS 使用 UserDefaults,
197
+ * 比 localStorage 有更好的安全性。
198
+ *
199
+ * @returns TokenStorage 实例
200
+ *
201
+ * @example
202
+ * ```ts
203
+ * import { createCapacitorTokenStorage } from '@h-ai/capacitor'
204
+ * import { api } from '@h-ai/api-client'
205
+ *
206
+ * await api.init({
207
+ * baseUrl: 'https://api.example.com/v1',
208
+ * auth: {
209
+ * storage: createCapacitorTokenStorage(),
210
+ * refreshUrl: '/auth/refresh',
211
+ * },
212
+ * })
213
+ * ```
214
+ */
215
+ declare function createCapacitorTokenStorage(): TokenStorage;
216
+ /**
217
+ * 安全读取 Preference 值(返回 HaiResult)
218
+ *
219
+ * @param key - Preference Key
220
+ * @returns HaiResult 包裹的值
221
+ *
222
+ * @example
223
+ * ```ts
224
+ * const result = await capacitor.preferences.get('my_key')
225
+ * if (result.success) {
226
+ * result.data // 值或 null
227
+ * }
228
+ * ```
229
+ */
230
+ declare function safeGetPreference(key: string): Promise<HaiResult<string | null>>;
231
+ /**
232
+ * 安全写入 Preference 值
233
+ *
234
+ * @param key - Preference Key
235
+ * @param value - 要写入的值
236
+ * @returns HaiResult
237
+ *
238
+ * @example
239
+ * ```ts
240
+ * await capacitor.preferences.set('my_key', 'value')
241
+ * ```
242
+ */
243
+ declare function safeSetPreference(key: string, value: string): Promise<HaiResult<void>>;
244
+ /**
245
+ * 安全删除 Preference 值
246
+ *
247
+ * @param key - Preference Key
248
+ * @returns HaiResult
249
+ *
250
+ * @example
251
+ * ```ts
252
+ * await capacitor.preferences.remove('my_key')
253
+ * ```
254
+ */
255
+ declare function safeRemovePreference(key: string): Promise<HaiResult<void>>;
256
+
257
+ export { type CameraOperations, type CapacitorFunctions, type DeviceInfo, type DeviceOperations, type DevicePlatform, HaiCapacitorError, type PhotoOptions, type PhotoResult, type PhotoSource, type PreferencesOperations, type PushNotification, type PushNotificationCallbacks, type PushOperations, type PushRegistration, type StatusBarConfig, type StatusBarOperations, type StatusBarStyle, capacitor, createCapacitorTokenStorage, safeGetPreference, safeRemovePreference, safeSetPreference };
package/dist/index.js ADDED
@@ -0,0 +1,505 @@
1
+ import { core, ok, err } from '@h-ai/core';
2
+ import { Preferences } from '@capacitor/preferences';
3
+
4
+ // src/capacitor-main.ts
5
+
6
+ // messages/en-US.json
7
+ var en_US_default = {
8
+ capacitor_initFailed: "Capacitor initialization failed",
9
+ capacitor_initInProgress: "Capacitor initialization is already in progress",
10
+ capacitor_notAvailable: "Capacitor is not available in this environment",
11
+ capacitor_preferencesGetFailed: "Failed to read from Capacitor Preferences",
12
+ capacitor_preferencesSetFailed: "Failed to write to Capacitor Preferences",
13
+ capacitor_preferencesRemoveFailed: "Failed to remove from Capacitor Preferences",
14
+ capacitor_deviceInfoFailed: "Failed to get device info",
15
+ capacitor_pushRegisterFailed: "Failed to register push notifications",
16
+ capacitor_pushListenFailed: "Failed to listen for push notifications",
17
+ capacitor_cameraFailed: "Failed to access camera",
18
+ capacitor_statusBarFailed: "Failed to configure status bar",
19
+ capacitor_notInitialized: "Capacitor module is not initialized"
20
+ };
21
+
22
+ // messages/zh-CN.json
23
+ var zh_CN_default = {
24
+ capacitor_initFailed: "Capacitor \u521D\u59CB\u5316\u5931\u8D25",
25
+ capacitor_initInProgress: "Capacitor \u6B63\u5728\u521D\u59CB\u5316\u4E2D",
26
+ capacitor_notAvailable: "\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301 Capacitor",
27
+ capacitor_preferencesGetFailed: "\u8BFB\u53D6 Capacitor Preferences \u5931\u8D25",
28
+ capacitor_preferencesSetFailed: "\u5199\u5165 Capacitor Preferences \u5931\u8D25",
29
+ capacitor_preferencesRemoveFailed: "\u5220\u9664 Capacitor Preferences \u5931\u8D25",
30
+ capacitor_deviceInfoFailed: "\u83B7\u53D6\u8BBE\u5907\u4FE1\u606F\u5931\u8D25",
31
+ capacitor_pushRegisterFailed: "\u6CE8\u518C\u63A8\u9001\u901A\u77E5\u5931\u8D25",
32
+ capacitor_pushListenFailed: "\u76D1\u542C\u63A8\u9001\u901A\u77E5\u5931\u8D25",
33
+ capacitor_cameraFailed: "\u8BBF\u95EE\u76F8\u673A\u5931\u8D25",
34
+ capacitor_statusBarFailed: "\u914D\u7F6E\u72B6\u6001\u680F\u5931\u8D25",
35
+ capacitor_notInitialized: "Capacitor \u6A21\u5757\u672A\u521D\u59CB\u5316"
36
+ };
37
+
38
+ // src/capacitor-i18n.ts
39
+ var capacitorM = core.i18n.createMessageGetter({
40
+ "zh-CN": zh_CN_default,
41
+ "en-US": en_US_default
42
+ });
43
+ var CapacitorErrorInfo = {
44
+ INIT_FAILED: "001:500",
45
+ NOT_AVAILABLE: "002:400",
46
+ INIT_IN_PROGRESS: "003:409",
47
+ NOT_INITIALIZED: "010:500",
48
+ PREFERENCES_GET_FAILED: "011:500",
49
+ PREFERENCES_SET_FAILED: "012:500",
50
+ PREFERENCES_REMOVE_FAILED: "013:500",
51
+ DEVICE_INFO_FAILED: "020:500",
52
+ PUSH_REGISTER_FAILED: "030:500",
53
+ PUSH_LISTEN_FAILED: "031:500",
54
+ CAMERA_FAILED: "040:500",
55
+ STATUS_BAR_FAILED: "050:500"
56
+ };
57
+ var HaiCapacitorError = core.error.buildHaiErrorsDef("capacitor", CapacitorErrorInfo);
58
+
59
+ // src/capacitor-camera.ts
60
+ var SOURCE_MAP = {
61
+ camera: "Camera",
62
+ photos: "Photos",
63
+ prompt: "Prompt"
64
+ };
65
+ var RESULT_TYPE_MAP = {
66
+ uri: "Uri",
67
+ base64: "Base64",
68
+ dataUrl: "DataUrl"
69
+ };
70
+ async function takePhoto(options) {
71
+ try {
72
+ const { Camera, CameraSource, CameraResultType } = await import('@capacitor/camera');
73
+ const source = options?.source ?? "prompt";
74
+ const resultType = options?.resultType ?? "uri";
75
+ const photo = await Camera.getPhoto({
76
+ quality: options?.quality ?? 90,
77
+ source: CameraSource[SOURCE_MAP[source]],
78
+ resultType: CameraResultType[RESULT_TYPE_MAP[resultType]],
79
+ width: options?.width,
80
+ height: options?.height
81
+ });
82
+ let data;
83
+ if (resultType === "base64") {
84
+ data = photo.base64String ?? "";
85
+ } else if (resultType === "dataUrl") {
86
+ data = photo.dataUrl ?? "";
87
+ } else {
88
+ data = photo.webPath ?? "";
89
+ }
90
+ return ok({
91
+ data,
92
+ format: photo.format
93
+ });
94
+ } catch (cause) {
95
+ return err(
96
+ HaiCapacitorError.CAMERA_FAILED,
97
+ capacitorM("capacitor_cameraFailed"),
98
+ cause
99
+ );
100
+ }
101
+ }
102
+ async function getDeviceInfo() {
103
+ try {
104
+ const { Device } = await import('@capacitor/device');
105
+ const info = await Device.getInfo();
106
+ return ok({
107
+ platform: info.platform,
108
+ osVersion: info.osVersion,
109
+ model: info.model,
110
+ manufacturer: info.manufacturer,
111
+ isVirtual: info.isVirtual
112
+ });
113
+ } catch (cause) {
114
+ return err(
115
+ HaiCapacitorError.DEVICE_INFO_FAILED,
116
+ capacitorM("capacitor_deviceInfoFailed"),
117
+ cause
118
+ );
119
+ }
120
+ }
121
+ async function getAppVersion() {
122
+ try {
123
+ const { App } = await import('@capacitor/app');
124
+ const info = await App.getInfo();
125
+ return ok({
126
+ version: info.version,
127
+ build: info.build
128
+ });
129
+ } catch (cause) {
130
+ return err(
131
+ HaiCapacitorError.DEVICE_INFO_FAILED,
132
+ capacitorM("capacitor_deviceInfoFailed"),
133
+ cause
134
+ );
135
+ }
136
+ }
137
+ async function registerPush() {
138
+ try {
139
+ const { PushNotifications } = await import('@capacitor/push-notifications');
140
+ const permResult = await PushNotifications.requestPermissions();
141
+ if (permResult.receive !== "granted") {
142
+ return err(
143
+ HaiCapacitorError.PUSH_REGISTER_FAILED,
144
+ capacitorM("capacitor_pushRegisterFailed")
145
+ );
146
+ }
147
+ const REGISTER_TIMEOUT_MS = 3e4;
148
+ const token = await new Promise((resolve, reject) => {
149
+ let regListener;
150
+ let errListener;
151
+ const timer = setTimeout(() => {
152
+ cleanup();
153
+ reject(new Error("Push registration timed out"));
154
+ }, REGISTER_TIMEOUT_MS);
155
+ function cleanup() {
156
+ clearTimeout(timer);
157
+ regListener?.remove();
158
+ errListener?.remove();
159
+ }
160
+ PushNotifications.addListener("registration", (t) => {
161
+ cleanup();
162
+ resolve(t.value);
163
+ }).then((l) => {
164
+ regListener = l;
165
+ });
166
+ PushNotifications.addListener("registrationError", (error) => {
167
+ cleanup();
168
+ reject(error);
169
+ }).then((l) => {
170
+ errListener = l;
171
+ });
172
+ PushNotifications.register();
173
+ });
174
+ return ok({ token });
175
+ } catch (cause) {
176
+ return err(
177
+ HaiCapacitorError.PUSH_REGISTER_FAILED,
178
+ capacitorM("capacitor_pushRegisterFailed"),
179
+ cause
180
+ );
181
+ }
182
+ }
183
+ async function listenPush(callbacks) {
184
+ try {
185
+ const { PushNotifications } = await import('@capacitor/push-notifications');
186
+ const listeners = [];
187
+ if (callbacks.onReceived) {
188
+ const listener = await PushNotifications.addListener(
189
+ "pushNotificationReceived",
190
+ (notification) => {
191
+ callbacks.onReceived?.({
192
+ id: notification.id,
193
+ title: notification.title,
194
+ body: notification.body,
195
+ data: notification.data
196
+ });
197
+ }
198
+ );
199
+ listeners.push(listener);
200
+ }
201
+ if (callbacks.onActionPerformed) {
202
+ const listener = await PushNotifications.addListener(
203
+ "pushNotificationActionPerformed",
204
+ (action) => {
205
+ callbacks.onActionPerformed?.({
206
+ id: action.notification.id,
207
+ title: action.notification.title,
208
+ body: action.notification.body,
209
+ data: action.notification.data
210
+ });
211
+ }
212
+ );
213
+ listeners.push(listener);
214
+ }
215
+ const cleanup = async () => {
216
+ await Promise.all(listeners.map((l) => l.remove()));
217
+ };
218
+ return ok(cleanup);
219
+ } catch (cause) {
220
+ return err(
221
+ HaiCapacitorError.PUSH_LISTEN_FAILED,
222
+ capacitorM("capacitor_pushListenFailed"),
223
+ cause
224
+ );
225
+ }
226
+ }
227
+ async function configureStatusBar(config) {
228
+ try {
229
+ const { StatusBar, Style } = await import('@capacitor/status-bar');
230
+ if (config.style) {
231
+ const styleMap = {
232
+ dark: Style.Dark,
233
+ light: Style.Light,
234
+ default: Style.Default
235
+ };
236
+ await StatusBar.setStyle({ style: styleMap[config.style] ?? Style.Default });
237
+ }
238
+ if (config.backgroundColor) {
239
+ await StatusBar.setBackgroundColor({ color: config.backgroundColor });
240
+ }
241
+ if (config.overlay !== void 0) {
242
+ await StatusBar.setOverlaysWebView({ overlay: config.overlay });
243
+ }
244
+ return ok(void 0);
245
+ } catch (cause) {
246
+ return err(
247
+ HaiCapacitorError.STATUS_BAR_FAILED,
248
+ capacitorM("capacitor_statusBarFailed"),
249
+ cause
250
+ );
251
+ }
252
+ }
253
+ async function showStatusBar() {
254
+ try {
255
+ const { StatusBar } = await import('@capacitor/status-bar');
256
+ await StatusBar.show();
257
+ return ok(void 0);
258
+ } catch (cause) {
259
+ return err(
260
+ HaiCapacitorError.STATUS_BAR_FAILED,
261
+ capacitorM("capacitor_statusBarFailed"),
262
+ cause
263
+ );
264
+ }
265
+ }
266
+ async function hideStatusBar() {
267
+ try {
268
+ const { StatusBar } = await import('@capacitor/status-bar');
269
+ await StatusBar.hide();
270
+ return ok(void 0);
271
+ } catch (cause) {
272
+ return err(
273
+ HaiCapacitorError.STATUS_BAR_FAILED,
274
+ capacitorM("capacitor_statusBarFailed"),
275
+ cause
276
+ );
277
+ }
278
+ }
279
+ var logger = core.logger.child({ module: "capacitor", scope: "token-storage" });
280
+ var PREF_ACCESS_TOKEN = "hai_access_token";
281
+ var PREF_REFRESH_TOKEN = "hai_refresh_token";
282
+ function createCapacitorTokenStorage() {
283
+ return {
284
+ async getAccessToken() {
285
+ try {
286
+ const { value } = await Preferences.get({ key: PREF_ACCESS_TOKEN });
287
+ return value;
288
+ } catch (error) {
289
+ logger.error("Failed to get access token from Preferences", { error });
290
+ return null;
291
+ }
292
+ },
293
+ async getRefreshToken() {
294
+ try {
295
+ const { value } = await Preferences.get({ key: PREF_REFRESH_TOKEN });
296
+ return value;
297
+ } catch (error) {
298
+ logger.error("Failed to get refresh token from Preferences", { error });
299
+ return null;
300
+ }
301
+ },
302
+ async setAccessToken(token) {
303
+ try {
304
+ await Preferences.set({ key: PREF_ACCESS_TOKEN, value: token });
305
+ } catch (error) {
306
+ logger.error("Failed to set access token in Preferences", { error });
307
+ }
308
+ },
309
+ async setRefreshToken(token) {
310
+ try {
311
+ await Preferences.set({ key: PREF_REFRESH_TOKEN, value: token });
312
+ } catch (error) {
313
+ logger.error("Failed to set refresh token in Preferences", { error });
314
+ }
315
+ },
316
+ async clear() {
317
+ try {
318
+ await Promise.all([
319
+ Preferences.remove({ key: PREF_ACCESS_TOKEN }),
320
+ Preferences.remove({ key: PREF_REFRESH_TOKEN })
321
+ ]);
322
+ } catch (error) {
323
+ logger.error("Failed to clear tokens from Preferences", { error });
324
+ }
325
+ }
326
+ };
327
+ }
328
+ async function safeGetPreference(key) {
329
+ try {
330
+ const { value } = await Preferences.get({ key });
331
+ return ok(value);
332
+ } catch (cause) {
333
+ return err(
334
+ HaiCapacitorError.PREFERENCES_GET_FAILED,
335
+ capacitorM("capacitor_preferencesGetFailed"),
336
+ cause
337
+ );
338
+ }
339
+ }
340
+ async function safeSetPreference(key, value) {
341
+ try {
342
+ await Preferences.set({ key, value });
343
+ return ok(void 0);
344
+ } catch (cause) {
345
+ return err(
346
+ HaiCapacitorError.PREFERENCES_SET_FAILED,
347
+ capacitorM("capacitor_preferencesSetFailed"),
348
+ cause
349
+ );
350
+ }
351
+ }
352
+ async function safeRemovePreference(key) {
353
+ try {
354
+ await Preferences.remove({ key });
355
+ return ok(void 0);
356
+ } catch (cause) {
357
+ return err(
358
+ HaiCapacitorError.PREFERENCES_REMOVE_FAILED,
359
+ capacitorM("capacitor_preferencesRemoveFailed"),
360
+ cause
361
+ );
362
+ }
363
+ }
364
+
365
+ // src/capacitor-main.ts
366
+ var logger2 = core.logger.child({ module: "capacitor", scope: "main" });
367
+ var initialized = false;
368
+ var initInProgress = false;
369
+ var cachedPlatform = null;
370
+ var notInitialized = core.module.createNotInitializedKit(
371
+ HaiCapacitorError.NOT_INITIALIZED,
372
+ () => capacitorM("capacitor_notInitialized")
373
+ );
374
+ var notInitializedDevice = notInitialized.proxy();
375
+ var notInitializedCamera = notInitialized.proxy();
376
+ var notInitializedPush = notInitialized.proxy();
377
+ var notInitializedStatusBar = notInitialized.proxy();
378
+ var notInitializedPreferences = notInitialized.proxy();
379
+ var deviceOps = {
380
+ getInfo: getDeviceInfo,
381
+ getAppVersion
382
+ };
383
+ var cameraOps = {
384
+ takePhoto
385
+ };
386
+ var pushOps = {
387
+ register: registerPush,
388
+ listen: listenPush
389
+ };
390
+ var statusBarOps = {
391
+ configure: configureStatusBar,
392
+ show: showStatusBar,
393
+ hide: hideStatusBar
394
+ };
395
+ var preferencesOps = {
396
+ get: safeGetPreference,
397
+ set: safeSetPreference,
398
+ remove: safeRemovePreference
399
+ };
400
+ function isCapacitorAvailable() {
401
+ try {
402
+ return typeof window !== "undefined" && window.Capacitor !== void 0;
403
+ } catch {
404
+ return false;
405
+ }
406
+ }
407
+ var capacitor = {
408
+ async init() {
409
+ if (initInProgress) {
410
+ logger2.warn("Capacitor init already in progress, skipping concurrent call");
411
+ return err(
412
+ HaiCapacitorError.INIT_IN_PROGRESS,
413
+ capacitorM("capacitor_initInProgress")
414
+ );
415
+ }
416
+ initInProgress = true;
417
+ try {
418
+ if (initialized) {
419
+ logger2.warn("Capacitor module is already initialized, reinitializing");
420
+ await capacitor.close();
421
+ }
422
+ logger2.info("Initializing capacitor module");
423
+ if (!isCapacitorAvailable()) {
424
+ logger2.error("Capacitor is not available in current environment");
425
+ return err(
426
+ HaiCapacitorError.NOT_AVAILABLE,
427
+ capacitorM("capacitor_notAvailable")
428
+ );
429
+ }
430
+ const { Capacitor } = await import('@capacitor/core');
431
+ const platform = Capacitor.getPlatform();
432
+ if (!platform) {
433
+ logger2.error("Capacitor initialization failed, platform not detected");
434
+ return err(
435
+ HaiCapacitorError.INIT_FAILED,
436
+ capacitorM("capacitor_initFailed")
437
+ );
438
+ }
439
+ cachedPlatform = platform;
440
+ initialized = true;
441
+ logger2.info("Capacitor module initialized", { platform });
442
+ return ok(void 0);
443
+ } catch (cause) {
444
+ logger2.error("Capacitor module initialization failed", { error: cause });
445
+ return err(
446
+ HaiCapacitorError.INIT_FAILED,
447
+ capacitorM("capacitor_initFailed"),
448
+ cause
449
+ );
450
+ } finally {
451
+ initInProgress = false;
452
+ }
453
+ },
454
+ async close() {
455
+ if (!initialized) {
456
+ logger2.info("Capacitor module is already closed, skipping");
457
+ return;
458
+ }
459
+ logger2.info("Closing capacitor module");
460
+ initialized = false;
461
+ cachedPlatform = null;
462
+ logger2.info("Capacitor module closed");
463
+ },
464
+ getPlatform() {
465
+ if (cachedPlatform) {
466
+ return cachedPlatform;
467
+ }
468
+ try {
469
+ const cap = window.Capacitor;
470
+ return cap?.getPlatform?.() ?? "web";
471
+ } catch {
472
+ return "web";
473
+ }
474
+ },
475
+ isNative() {
476
+ try {
477
+ const cap = window.Capacitor;
478
+ return cap?.isNativePlatform?.() ?? false;
479
+ } catch {
480
+ return false;
481
+ }
482
+ },
483
+ get isInitialized() {
484
+ return initialized;
485
+ },
486
+ get device() {
487
+ return initialized ? deviceOps : notInitializedDevice;
488
+ },
489
+ get camera() {
490
+ return initialized ? cameraOps : notInitializedCamera;
491
+ },
492
+ get push() {
493
+ return initialized ? pushOps : notInitializedPush;
494
+ },
495
+ get statusBar() {
496
+ return initialized ? statusBarOps : notInitializedStatusBar;
497
+ },
498
+ get preferences() {
499
+ return initialized ? preferencesOps : notInitializedPreferences;
500
+ }
501
+ };
502
+
503
+ export { HaiCapacitorError, capacitor, createCapacitorTokenStorage, safeGetPreference, safeRemovePreference, safeSetPreference };
504
+ //# sourceMappingURL=index.js.map
505
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../messages/en-US.json","../messages/zh-CN.json","../src/capacitor-i18n.ts","../src/capacitor-types.ts","../src/capacitor-camera.ts","../src/capacitor-device.ts","../src/capacitor-push.ts","../src/capacitor-status-bar.ts","../src/capacitor-token-storage.ts","../src/capacitor-main.ts"],"names":["core","ok","err","logger"],"mappings":"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","file":"index.js","sourcesContent":["{\n \"capacitor_initFailed\": \"Capacitor initialization failed\",\n \"capacitor_initInProgress\": \"Capacitor initialization is already in progress\",\n \"capacitor_notAvailable\": \"Capacitor is not available in this environment\",\n \"capacitor_preferencesGetFailed\": \"Failed to read from Capacitor Preferences\",\n \"capacitor_preferencesSetFailed\": \"Failed to write to Capacitor Preferences\",\n \"capacitor_preferencesRemoveFailed\": \"Failed to remove from Capacitor Preferences\",\n \"capacitor_deviceInfoFailed\": \"Failed to get device info\",\n \"capacitor_pushRegisterFailed\": \"Failed to register push notifications\",\n \"capacitor_pushListenFailed\": \"Failed to listen for push notifications\",\n \"capacitor_cameraFailed\": \"Failed to access camera\",\n \"capacitor_statusBarFailed\": \"Failed to configure status bar\",\n \"capacitor_notInitialized\": \"Capacitor module is not initialized\"\n}\n","{\n \"capacitor_initFailed\": \"Capacitor 初始化失败\",\n \"capacitor_initInProgress\": \"Capacitor 正在初始化中\",\n \"capacitor_notAvailable\": \"当前环境不支持 Capacitor\",\n \"capacitor_preferencesGetFailed\": \"读取 Capacitor Preferences 失败\",\n \"capacitor_preferencesSetFailed\": \"写入 Capacitor Preferences 失败\",\n \"capacitor_preferencesRemoveFailed\": \"删除 Capacitor Preferences 失败\",\n \"capacitor_deviceInfoFailed\": \"获取设备信息失败\",\n \"capacitor_pushRegisterFailed\": \"注册推送通知失败\",\n \"capacitor_pushListenFailed\": \"监听推送通知失败\",\n \"capacitor_cameraFailed\": \"访问相机失败\",\n \"capacitor_statusBarFailed\": \"配置状态栏失败\",\n \"capacitor_notInitialized\": \"Capacitor 模块未初始化\"\n}\n","/**\n * @h-ai/capacitor — i18n\n *\n * 模块 i18n 文案访问入口。\n * @module capacitor-i18n\n */\n\nimport { core } from '@h-ai/core'\nimport messagesEnUS from '../messages/en-US.json'\nimport messagesZhCN from '../messages/zh-CN.json'\n\ntype CapacitorMessageKey = keyof typeof messagesZhCN\n\n/**\n * capacitor 模块 i18n 文案获取器\n *\n * @param key - 文案 Key\n * @returns 本地化后的文案字符串\n */\nexport const capacitorM = core.i18n.createMessageGetter<CapacitorMessageKey>({\n 'zh-CN': messagesZhCN,\n 'en-US': messagesEnUS,\n})\n","/**\n * @h-ai/capacitor — 类型定义\n *\n * Capacitor 原生桥接模块的公共类型。\n * @module capacitor-types\n */\n\nimport type { ErrorInfo, HaiResult } from '@h-ai/core'\nimport { core } from '@h-ai/core'\n\nconst CapacitorErrorInfo = {\n INIT_FAILED: '001:500',\n NOT_AVAILABLE: '002:400',\n INIT_IN_PROGRESS: '003:409',\n NOT_INITIALIZED: '010:500',\n PREFERENCES_GET_FAILED: '011:500',\n PREFERENCES_SET_FAILED: '012:500',\n PREFERENCES_REMOVE_FAILED: '013:500',\n DEVICE_INFO_FAILED: '020:500',\n PUSH_REGISTER_FAILED: '030:500',\n PUSH_LISTEN_FAILED: '031:500',\n CAMERA_FAILED: '040:500',\n STATUS_BAR_FAILED: '050:500',\n} as const satisfies ErrorInfo\n\nexport const HaiCapacitorError = core.error.buildHaiErrorsDef('capacitor', CapacitorErrorInfo)\n\n// ─── 子操作接口 ───\n\n/** 设备信息操作 */\nexport interface DeviceOperations {\n /** 获取设备信息(平台、型号、系统版本等) */\n getInfo: () => Promise<HaiResult<DeviceInfo>>\n /** 获取应用版本信息 */\n getAppVersion: () => Promise<HaiResult<{ version: string, build: string }>>\n}\n\n/** 相机操作 */\nexport interface CameraOperations {\n /** 拍照或选取相册图片 */\n takePhoto: (options?: PhotoOptions) => Promise<HaiResult<PhotoResult>>\n}\n\n/** 推送通知操作 */\nexport interface PushOperations {\n /** 注册推送通知,返回设备 Token */\n register: () => Promise<HaiResult<PushRegistration>>\n /** 监听推送通知事件,返回清理函数 */\n listen: (callbacks: PushNotificationCallbacks) => Promise<HaiResult<() => Promise<void>>>\n}\n\n/** 状态栏操作 */\nexport interface StatusBarOperations {\n /** 配置状态栏(样式、背景色、沉浸式) */\n configure: (config: StatusBarConfig) => Promise<HaiResult<void>>\n /** 显示状态栏 */\n show: () => Promise<HaiResult<void>>\n /** 隐藏状态栏 */\n hide: () => Promise<HaiResult<void>>\n}\n\n/** Preferences 操作(安全读写,返回 HaiResult) */\nexport interface PreferencesOperations {\n /** 安全读取 Preference 值 */\n get: (key: string) => Promise<HaiResult<string | null>>\n /** 安全写入 Preference 值 */\n set: (key: string, value: string) => Promise<HaiResult<void>>\n /** 安全删除 Preference 值 */\n remove: (key: string) => Promise<HaiResult<void>>\n}\n\n// ─── 函数接口 ───\n\n/** Capacitor 模块服务对象接口 */\nexport interface CapacitorFunctions {\n /** 初始化 Capacitor 模块 */\n init: () => Promise<HaiResult<void>>\n /** 关闭模块,重置状态 */\n close: () => Promise<void>\n /** 获取当前平台 */\n getPlatform: () => string\n /** 是否运行在原生 App 中 */\n isNative: () => boolean\n /** 是否已初始化 */\n readonly isInitialized: boolean\n\n /** 设备信息操作 */\n readonly device: DeviceOperations\n /** 相机操作 */\n readonly camera: CameraOperations\n /** 推送通知操作 */\n readonly push: PushOperations\n /** 状态栏操作 */\n readonly statusBar: StatusBarOperations\n /** Preferences 安全读写操作 */\n readonly preferences: PreferencesOperations\n}\n\n// ─── 设备信息 ───\n\n/** 设备平台 */\nexport type DevicePlatform = 'ios' | 'android' | 'web'\n\n/** 设备信息 */\nexport interface DeviceInfo {\n /** 平台(ios / android / web) */\n platform: DevicePlatform\n /** 操作系统版本(如 '14.5') */\n osVersion: string\n /** 设备型号(如 'iPhone 14 Pro') */\n model: string\n /** 设备制造商 */\n manufacturer: string\n /** 是否为虚拟设备(模拟器) */\n isVirtual: boolean\n /** 应用版本 */\n appVersion?: string\n /** 应用 Build 号 */\n appBuild?: string\n}\n\n// ─── 推送通知 ───\n\n/** 推送通知数据 */\nexport interface PushNotification {\n /** 通知 ID */\n id: string\n /** 标题 */\n title?: string\n /** 正文 */\n body?: string\n /** 附加数据 */\n data?: Record<string, unknown>\n}\n\n/** 推送注册结果 */\nexport interface PushRegistration {\n /** 设备推送 Token */\n token: string\n}\n\n/** 推送通知回调 */\nexport interface PushNotificationCallbacks {\n /** 收到推送时调用 */\n onReceived?: (notification: PushNotification) => void\n /** 用户点击推送时调用 */\n onActionPerformed?: (notification: PushNotification) => void\n}\n\n// ─── 相机 ───\n\n/** 照片来源 */\nexport type PhotoSource = 'camera' | 'photos' | 'prompt'\n\n/** 照片选项 */\nexport interface PhotoOptions {\n /** 来源(默认 'prompt') */\n source?: PhotoSource\n /** 图片质量 0-100(默认 90) */\n quality?: number\n /** 最大宽度(像素) */\n width?: number\n /** 最大高度(像素) */\n height?: number\n /** 返回格式 */\n resultType?: 'uri' | 'base64' | 'dataUrl'\n}\n\n/** 照片结果 */\nexport interface PhotoResult {\n /** 图片路径或 base64 数据 */\n data: string\n /** MIME 类型 */\n format: string\n}\n\n// ─── 状态栏 ───\n\n/** 状态栏样式 */\nexport type StatusBarStyle = 'dark' | 'light' | 'default'\n\n/** 状态栏配置 */\nexport interface StatusBarConfig {\n /** 状态栏文字样式 */\n style?: StatusBarStyle\n /** 背景颜色(十六进制) */\n backgroundColor?: string\n /** 是否覆盖在内容上(沉浸式) */\n overlay?: boolean\n}\n","/**\n * @h-ai/capacitor — 相机 / 相册\n *\n * 封装 `@capacitor/camera` 插件,提供拍照与相册选择能力。\n *\n * @module capacitor-camera\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { PhotoOptions, PhotoResult } from './capacitor-types.js'\nimport { err, ok } from '@h-ai/core'\nimport { capacitorM } from './capacitor-i18n.js'\nimport { HaiCapacitorError } from './capacitor-types.js'\n\n/** 照片来源映射(内部使用) */\nconst SOURCE_MAP = {\n camera: 'Camera',\n photos: 'Photos',\n prompt: 'Prompt',\n} as const\n\n/** 结果类型映射(内部使用) */\nconst RESULT_TYPE_MAP = {\n uri: 'Uri',\n base64: 'Base64',\n dataUrl: 'DataUrl',\n} as const\n\n/**\n * 拍照或选取相册图片\n *\n * 需要安装 `@capacitor/camera` 插件。\n *\n * @param options - 照片选项\n * @returns 照片结果\n *\n * @example\n * ```ts\n * const result = await capacitor.camera.takePhoto({ source: 'camera', quality: 80 })\n * if (result.success) {\n * imageUrl = result.data.data\n * }\n * ```\n */\nexport async function takePhoto(options?: PhotoOptions): Promise<HaiResult<PhotoResult>> {\n try {\n const { Camera, CameraSource, CameraResultType } = await import('@capacitor/camera')\n\n const source = options?.source ?? 'prompt'\n const resultType = options?.resultType ?? 'uri'\n\n const photo = await Camera.getPhoto({\n quality: options?.quality ?? 90,\n source: CameraSource[SOURCE_MAP[source] as keyof typeof CameraSource],\n resultType: CameraResultType[RESULT_TYPE_MAP[resultType] as keyof typeof CameraResultType],\n width: options?.width,\n height: options?.height,\n })\n\n // 根据 resultType 返回对应数据\n let data: string\n if (resultType === 'base64') {\n data = photo.base64String ?? ''\n }\n else if (resultType === 'dataUrl') {\n data = photo.dataUrl ?? ''\n }\n else {\n data = photo.webPath ?? ''\n }\n\n return ok({\n data,\n format: photo.format,\n })\n }\n catch (cause) {\n return err(\n HaiCapacitorError.CAMERA_FAILED,\n capacitorM('capacitor_cameraFailed'),\n cause,\n )\n }\n}\n","/**\n * @h-ai/capacitor — 设备信息\n *\n * 封装 `@capacitor/device` 插件,提供统一的设备信息读取接口。\n *\n * @module capacitor-device\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { DeviceInfo } from './capacitor-types.js'\nimport { err, ok } from '@h-ai/core'\nimport { capacitorM } from './capacitor-i18n.js'\nimport { HaiCapacitorError } from './capacitor-types.js'\n\n/**\n * 获取设备信息\n *\n * 需要安装 `@capacitor/device` 插件。\n *\n * @returns 设备信息(平台、系统版本、型号等)\n *\n * @example\n * ```ts\n * const result = await capacitor.device.getInfo()\n * if (result.success) {\n * result.data.platform // 'android' | 'ios' | 'web'\n * }\n * ```\n */\nexport async function getDeviceInfo(): Promise<HaiResult<DeviceInfo>> {\n try {\n const { Device } = await import('@capacitor/device')\n const info = await Device.getInfo()\n\n return ok({\n platform: info.platform as DeviceInfo['platform'],\n osVersion: info.osVersion,\n model: info.model,\n manufacturer: info.manufacturer,\n isVirtual: info.isVirtual,\n })\n }\n catch (cause) {\n return err(\n HaiCapacitorError.DEVICE_INFO_FAILED,\n capacitorM('capacitor_deviceInfoFailed'),\n cause,\n )\n }\n}\n\n/**\n * 获取应用版本信息\n *\n * @returns appVersion 与 appBuild\n *\n * @example\n * ```ts\n * const result = await capacitor.device.getAppVersion()\n * if (result.success) {\n * result.data.version // '1.0.0'\n * result.data.build // '42'\n * }\n * ```\n */\nexport async function getAppVersion(): Promise<HaiResult<{ version: string, build: string }>> {\n try {\n const { App } = await import('@capacitor/app')\n const info = await App.getInfo()\n\n return ok({\n version: info.version,\n build: info.build,\n })\n }\n catch (cause) {\n return err(\n HaiCapacitorError.DEVICE_INFO_FAILED,\n capacitorM('capacitor_deviceInfoFailed'),\n cause,\n )\n }\n}\n","/**\n * @h-ai/capacitor — 推送通知\n *\n * 封装 `@capacitor/push-notifications` 插件,提供推送注册与消息监听。\n *\n * @module capacitor-push\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { PushNotificationCallbacks, PushRegistration } from './capacitor-types.js'\nimport { err, ok } from '@h-ai/core'\nimport { capacitorM } from './capacitor-i18n.js'\nimport { HaiCapacitorError } from './capacitor-types.js'\n\n/**\n * 注册推送通知\n *\n * 请求推送权限并注册设备 Token。需要安装 `@capacitor/push-notifications`。\n * 注册超过 30 秒未响应时自动超时。\n *\n * @returns 设备推送 Token\n *\n * @example\n * ```ts\n * const result = await capacitor.push.register()\n * if (result.success) {\n * await api.post('/push/register', { token: result.data.token })\n * }\n * ```\n */\nexport async function registerPush(): Promise<HaiResult<PushRegistration>> {\n try {\n const { PushNotifications } = await import('@capacitor/push-notifications')\n\n // 请求权限\n const permResult = await PushNotifications.requestPermissions()\n if (permResult.receive !== 'granted') {\n return err(\n HaiCapacitorError.PUSH_REGISTER_FAILED,\n capacitorM('capacitor_pushRegisterFailed'),\n )\n }\n\n // 注册并等待 Token(带超时防护)\n const REGISTER_TIMEOUT_MS = 30_000\n const token = await new Promise<string>((resolve, reject) => {\n let regListener: { remove: () => Promise<void> } | undefined\n let errListener: { remove: () => Promise<void> } | undefined\n\n const timer = setTimeout(() => {\n cleanup()\n reject(new Error('Push registration timed out'))\n }, REGISTER_TIMEOUT_MS)\n\n function cleanup() {\n clearTimeout(timer)\n regListener?.remove()\n errListener?.remove()\n }\n\n PushNotifications.addListener('registration', (t) => {\n cleanup()\n resolve(t.value)\n }).then((l) => { regListener = l })\n\n PushNotifications.addListener('registrationError', (error) => {\n cleanup()\n reject(error)\n }).then((l) => { errListener = l })\n\n PushNotifications.register()\n })\n\n return ok({ token })\n }\n catch (cause) {\n return err(\n HaiCapacitorError.PUSH_REGISTER_FAILED,\n capacitorM('capacitor_pushRegisterFailed'),\n cause,\n )\n }\n}\n\n/**\n * 监听推送通知事件\n *\n * @param callbacks - 回调配置(收到推送、点击推送)\n * @returns 包含清理函数的 HaiResult\n *\n * @example\n * ```ts\n * const result = await capacitor.push.listen({\n * onReceived: (n) => handlePushReceived(n),\n * onActionPerformed: (n) => router.goto('/notifications'),\n * })\n * if (result.success) {\n * // 停止监听\n * await result.data()\n * }\n * ```\n */\nexport async function listenPush(callbacks: PushNotificationCallbacks): Promise<HaiResult<() => Promise<void>>> {\n try {\n const { PushNotifications } = await import('@capacitor/push-notifications')\n const listeners: Array<{ remove: () => Promise<void> }> = []\n\n if (callbacks.onReceived) {\n const listener = await PushNotifications.addListener(\n 'pushNotificationReceived',\n (notification) => {\n callbacks.onReceived?.({\n id: notification.id,\n title: notification.title,\n body: notification.body,\n data: notification.data as Record<string, unknown>,\n })\n },\n )\n listeners.push(listener)\n }\n\n if (callbacks.onActionPerformed) {\n const listener = await PushNotifications.addListener(\n 'pushNotificationActionPerformed',\n (action) => {\n callbacks.onActionPerformed?.({\n id: action.notification.id,\n title: action.notification.title,\n body: action.notification.body,\n data: action.notification.data as Record<string, unknown>,\n })\n },\n )\n listeners.push(listener)\n }\n\n const cleanup = async () => {\n await Promise.all(listeners.map(l => l.remove()))\n }\n return ok(cleanup)\n }\n catch (cause) {\n return err(\n HaiCapacitorError.PUSH_LISTEN_FAILED,\n capacitorM('capacitor_pushListenFailed'),\n cause,\n )\n }\n}\n","/**\n * @h-ai/capacitor — 状态栏\n *\n * 封装 `@capacitor/status-bar` 插件,支持沉浸式状态栏配置。\n *\n * @module capacitor-status-bar\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { StatusBarConfig } from './capacitor-types.js'\nimport { err, ok } from '@h-ai/core'\nimport { capacitorM } from './capacitor-i18n.js'\nimport { HaiCapacitorError } from './capacitor-types.js'\n\n/**\n * 配置状态栏\n *\n * 需要安装 `@capacitor/status-bar` 插件。\n *\n * @param config - 状态栏配置\n * @returns HaiResult\n *\n * @example\n * ```ts\n * await capacitor.statusBar.configure({\n * style: 'dark',\n * overlay: true,\n * backgroundColor: '#ffffff',\n * })\n * ```\n */\nexport async function configureStatusBar(config: StatusBarConfig): Promise<HaiResult<void>> {\n try {\n const { StatusBar, Style } = await import('@capacitor/status-bar')\n\n // 设置样式\n if (config.style) {\n const styleMap: Record<string, typeof Style[keyof typeof Style]> = {\n dark: Style.Dark,\n light: Style.Light,\n default: Style.Default,\n }\n await StatusBar.setStyle({ style: styleMap[config.style] ?? Style.Default })\n }\n\n // 设置背景色\n if (config.backgroundColor) {\n await StatusBar.setBackgroundColor({ color: config.backgroundColor })\n }\n\n // 设置覆盖模式\n if (config.overlay !== undefined) {\n await StatusBar.setOverlaysWebView({ overlay: config.overlay })\n }\n\n return ok(undefined)\n }\n catch (cause) {\n return err(\n HaiCapacitorError.STATUS_BAR_FAILED,\n capacitorM('capacitor_statusBarFailed'),\n cause,\n )\n }\n}\n\n/**\n * 显示状态栏\n *\n * @returns HaiResult\n *\n * @example\n * ```ts\n * await capacitor.statusBar.show()\n * ```\n */\nexport async function showStatusBar(): Promise<HaiResult<void>> {\n try {\n const { StatusBar } = await import('@capacitor/status-bar')\n await StatusBar.show()\n return ok(undefined)\n }\n catch (cause) {\n return err(\n HaiCapacitorError.STATUS_BAR_FAILED,\n capacitorM('capacitor_statusBarFailed'),\n cause,\n )\n }\n}\n\n/**\n * 隐藏状态栏\n *\n * @returns HaiResult\n *\n * @example\n * ```ts\n * await capacitor.statusBar.hide()\n * ```\n */\nexport async function hideStatusBar(): Promise<HaiResult<void>> {\n try {\n const { StatusBar } = await import('@capacitor/status-bar')\n await StatusBar.hide()\n return ok(undefined)\n }\n catch (cause) {\n return err(\n HaiCapacitorError.STATUS_BAR_FAILED,\n capacitorM('capacitor_statusBarFailed'),\n cause,\n )\n }\n}\n","/**\n * @h-ai/capacitor — Token 存储\n *\n * 基于 Capacitor Preferences 的 TokenStorage 实现,\n * 比浏览器 localStorage 更安全,适用于原生 App 场景。\n *\n * @module capacitor-token-storage\n */\n\nimport type { TokenStorage } from '@h-ai/api-client'\nimport type { HaiResult } from '@h-ai/core'\nimport { Preferences } from '@capacitor/preferences'\nimport { core, err, ok } from '@h-ai/core'\nimport { capacitorM } from './capacitor-i18n.js'\nimport { HaiCapacitorError } from './capacitor-types.js'\n\nconst logger = core.logger.child({ module: 'capacitor', scope: 'token-storage' })\n\n/** Preferences 存储 Key */\nconst PREF_ACCESS_TOKEN = 'hai_access_token'\nconst PREF_REFRESH_TOKEN = 'hai_refresh_token'\n\n/**\n * 创建基于 Capacitor Preferences 的 TokenStorage\n *\n * 使用 `@capacitor/preferences` 插件进行持久化存储,\n * 在 Android 使用 SharedPreferences,iOS 使用 UserDefaults,\n * 比 localStorage 有更好的安全性。\n *\n * @returns TokenStorage 实例\n *\n * @example\n * ```ts\n * import { createCapacitorTokenStorage } from '@h-ai/capacitor'\n * import { api } from '@h-ai/api-client'\n *\n * await api.init({\n * baseUrl: 'https://api.example.com/v1',\n * auth: {\n * storage: createCapacitorTokenStorage(),\n * refreshUrl: '/auth/refresh',\n * },\n * })\n * ```\n */\nexport function createCapacitorTokenStorage(): TokenStorage {\n return {\n async getAccessToken(): Promise<string | null> {\n try {\n const { value } = await Preferences.get({ key: PREF_ACCESS_TOKEN })\n return value\n }\n catch (error) {\n logger.error('Failed to get access token from Preferences', { error })\n return null\n }\n },\n\n async getRefreshToken(): Promise<string | null> {\n try {\n const { value } = await Preferences.get({ key: PREF_REFRESH_TOKEN })\n return value\n }\n catch (error) {\n logger.error('Failed to get refresh token from Preferences', { error })\n return null\n }\n },\n\n async setAccessToken(token: string): Promise<void> {\n try {\n await Preferences.set({ key: PREF_ACCESS_TOKEN, value: token })\n }\n catch (error) {\n logger.error('Failed to set access token in Preferences', { error })\n }\n },\n\n async setRefreshToken(token: string): Promise<void> {\n try {\n await Preferences.set({ key: PREF_REFRESH_TOKEN, value: token })\n }\n catch (error) {\n logger.error('Failed to set refresh token in Preferences', { error })\n }\n },\n\n async clear(): Promise<void> {\n try {\n await Promise.all([\n Preferences.remove({ key: PREF_ACCESS_TOKEN }),\n Preferences.remove({ key: PREF_REFRESH_TOKEN }),\n ])\n }\n catch (error) {\n logger.error('Failed to clear tokens from Preferences', { error })\n }\n },\n }\n}\n\n/**\n * 安全读取 Preference 值(返回 HaiResult)\n *\n * @param key - Preference Key\n * @returns HaiResult 包裹的值\n *\n * @example\n * ```ts\n * const result = await capacitor.preferences.get('my_key')\n * if (result.success) {\n * result.data // 值或 null\n * }\n * ```\n */\nexport async function safeGetPreference(key: string): Promise<HaiResult<string | null>> {\n try {\n const { value } = await Preferences.get({ key })\n return ok(value)\n }\n catch (cause) {\n return err(\n HaiCapacitorError.PREFERENCES_GET_FAILED,\n capacitorM('capacitor_preferencesGetFailed'),\n cause,\n )\n }\n}\n\n/**\n * 安全写入 Preference 值\n *\n * @param key - Preference Key\n * @param value - 要写入的值\n * @returns HaiResult\n *\n * @example\n * ```ts\n * await capacitor.preferences.set('my_key', 'value')\n * ```\n */\nexport async function safeSetPreference(key: string, value: string): Promise<HaiResult<void>> {\n try {\n await Preferences.set({ key, value })\n return ok(undefined)\n }\n catch (cause) {\n return err(\n HaiCapacitorError.PREFERENCES_SET_FAILED,\n capacitorM('capacitor_preferencesSetFailed'),\n cause,\n )\n }\n}\n\n/**\n * 安全删除 Preference 值\n *\n * @param key - Preference Key\n * @returns HaiResult\n *\n * @example\n * ```ts\n * await capacitor.preferences.remove('my_key')\n * ```\n */\nexport async function safeRemovePreference(key: string): Promise<HaiResult<void>> {\n try {\n await Preferences.remove({ key })\n return ok(undefined)\n }\n catch (cause) {\n return err(\n HaiCapacitorError.PREFERENCES_REMOVE_FAILED,\n capacitorM('capacitor_preferencesRemoveFailed'),\n cause,\n )\n }\n}\n","/**\n * @h-ai/capacitor — 模块入口(生命周期管理)\n *\n * 提供 Capacitor 原生桥接的初始化与环境检测。\n * `capacitor.init()` 应在应用启动时调用,用于检测 Capacitor 环境可用性。\n *\n * @module capacitor-main\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { CameraOperations, CapacitorFunctions, DeviceOperations, PreferencesOperations, PushOperations, StatusBarOperations } from './capacitor-types.js'\nimport { core, err, ok } from '@h-ai/core'\nimport { takePhoto } from './capacitor-camera.js'\nimport { getAppVersion, getDeviceInfo } from './capacitor-device.js'\nimport { capacitorM } from './capacitor-i18n.js'\nimport { listenPush, registerPush } from './capacitor-push.js'\nimport { configureStatusBar, hideStatusBar, showStatusBar } from './capacitor-status-bar.js'\nimport { safeGetPreference, safeRemovePreference, safeSetPreference } from './capacitor-token-storage.js'\nimport { HaiCapacitorError } from './capacitor-types.js'\n\nconst logger = core.logger.child({ module: 'capacitor', scope: 'main' })\n\n/** 是否已初始化 */\nlet initialized = false\n\n/** 是否正在初始化中(并发防护) */\nlet initInProgress = false\n\n/** 缓存平台信息 */\nlet cachedPlatform: string | null = null\n\n// ─── 未初始化代理 ───\n\nconst notInitialized = core.module.createNotInitializedKit(\n HaiCapacitorError.NOT_INITIALIZED,\n () => capacitorM('capacitor_notInitialized'),\n)\n\nconst notInitializedDevice = notInitialized.proxy<DeviceOperations>()\nconst notInitializedCamera = notInitialized.proxy<CameraOperations>()\nconst notInitializedPush = notInitialized.proxy<PushOperations>()\nconst notInitializedStatusBar = notInitialized.proxy<StatusBarOperations>()\nconst notInitializedPreferences = notInitialized.proxy<PreferencesOperations>()\n\n// ─── 已初始化时的操作实现 ───\n\nconst deviceOps: DeviceOperations = {\n getInfo: getDeviceInfo,\n getAppVersion,\n}\n\nconst cameraOps: CameraOperations = {\n takePhoto,\n}\n\nconst pushOps: PushOperations = {\n register: registerPush,\n listen: listenPush,\n}\n\nconst statusBarOps: StatusBarOperations = {\n configure: configureStatusBar,\n show: showStatusBar,\n hide: hideStatusBar,\n}\n\nconst preferencesOps: PreferencesOperations = {\n get: safeGetPreference,\n set: safeSetPreference,\n remove: safeRemovePreference,\n}\n\n// ─── 检测 Capacitor 是否可用(模块内部使用) ───\n\nfunction isCapacitorAvailable(): boolean {\n try {\n return typeof window !== 'undefined'\n && (window as unknown as Record<string, unknown>).Capacitor !== undefined\n }\n catch {\n return false\n }\n}\n\n// ─── 服务对象 ───\n\n/**\n * Capacitor 模块服务对象\n *\n * @example\n * ```ts\n * import { capacitor } from '@h-ai/capacitor'\n *\n * const result = await capacitor.init()\n * if (result.success) {\n * const info = await capacitor.device.getInfo()\n * await capacitor.statusBar.configure({ style: 'dark', overlay: true })\n * }\n * ```\n */\nexport const capacitor: CapacitorFunctions = {\n async init(): Promise<HaiResult<void>> {\n // 并发初始化防护:避免多次 init 同时执行导致资源泄漏\n if (initInProgress) {\n logger.warn('Capacitor init already in progress, skipping concurrent call')\n return err(\n HaiCapacitorError.INIT_IN_PROGRESS,\n capacitorM('capacitor_initInProgress'),\n )\n }\n initInProgress = true\n\n try {\n if (initialized) {\n logger.warn('Capacitor module is already initialized, reinitializing')\n await capacitor.close()\n }\n\n logger.info('Initializing capacitor module')\n\n if (!isCapacitorAvailable()) {\n logger.error('Capacitor is not available in current environment')\n return err(\n HaiCapacitorError.NOT_AVAILABLE,\n capacitorM('capacitor_notAvailable'),\n )\n }\n\n const { Capacitor } = await import('@capacitor/core')\n const platform = Capacitor.getPlatform()\n\n if (!platform) {\n logger.error('Capacitor initialization failed, platform not detected')\n return err(\n HaiCapacitorError.INIT_FAILED,\n capacitorM('capacitor_initFailed'),\n )\n }\n\n cachedPlatform = platform\n initialized = true\n logger.info('Capacitor module initialized', { platform })\n return ok(undefined)\n }\n catch (cause) {\n logger.error('Capacitor module initialization failed', { error: cause })\n return err(\n HaiCapacitorError.INIT_FAILED,\n capacitorM('capacitor_initFailed'),\n cause,\n )\n }\n finally {\n initInProgress = false\n }\n },\n\n async close() {\n if (!initialized) {\n logger.info('Capacitor module is already closed, skipping')\n return\n }\n logger.info('Closing capacitor module')\n initialized = false\n cachedPlatform = null\n logger.info('Capacitor module closed')\n },\n\n getPlatform(): string {\n if (cachedPlatform) {\n return cachedPlatform\n }\n try {\n const cap = (window as unknown as Record<string, unknown>).Capacitor as { getPlatform?: () => string } | undefined\n return cap?.getPlatform?.() ?? 'web'\n }\n catch {\n return 'web'\n }\n },\n\n isNative(): boolean {\n try {\n const cap = (window as unknown as Record<string, unknown>).Capacitor as { isNativePlatform?: () => boolean } | undefined\n return cap?.isNativePlatform?.() ?? false\n }\n catch {\n return false\n }\n },\n\n get isInitialized(): boolean {\n return initialized\n },\n\n get device(): DeviceOperations {\n return initialized ? deviceOps : notInitializedDevice\n },\n\n get camera(): CameraOperations {\n return initialized ? cameraOps : notInitializedCamera\n },\n\n get push(): PushOperations {\n return initialized ? pushOps : notInitializedPush\n },\n\n get statusBar(): StatusBarOperations {\n return initialized ? statusBarOps : notInitializedStatusBar\n },\n\n get preferences(): PreferencesOperations {\n return initialized ? preferencesOps : notInitializedPreferences\n },\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@h-ai/capacitor",
3
+ "type": "module",
4
+ "version": "0.1.0-alpha5",
5
+ "description": "Hai Framework Capacitor bridge module for native mobile capabilities.",
6
+ "license": "Apache-2.0",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js"
11
+ }
12
+ },
13
+ "main": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "publishConfig": {
19
+ "access": "public"
20
+ },
21
+ "peerDependencies": {
22
+ "@capacitor/core": "^8.2.0",
23
+ "@capacitor/preferences": "^8.0.1"
24
+ },
25
+ "peerDependenciesMeta": {
26
+ "@capacitor/app": {
27
+ "optional": true
28
+ },
29
+ "@capacitor/camera": {
30
+ "optional": true
31
+ },
32
+ "@capacitor/device": {
33
+ "optional": true
34
+ },
35
+ "@capacitor/push-notifications": {
36
+ "optional": true
37
+ },
38
+ "@capacitor/status-bar": {
39
+ "optional": true
40
+ }
41
+ },
42
+ "dependencies": {
43
+ "@h-ai/api-client": "0.1.0-alpha5",
44
+ "@h-ai/core": "0.1.0-alpha5"
45
+ },
46
+ "devDependencies": {
47
+ "@capacitor/app": "^8.0.1",
48
+ "@capacitor/camera": "^8.0.2",
49
+ "@capacitor/device": "^8.0.1",
50
+ "@capacitor/push-notifications": "^8.0.2",
51
+ "@capacitor/status-bar": "^8.0.1",
52
+ "@types/node": "^25.1.0",
53
+ "rimraf": "^6.0.1",
54
+ "tsup": "^8.3.5",
55
+ "typescript": "^5.7.2",
56
+ "vitest": "^4.0.18"
57
+ },
58
+ "scripts": {
59
+ "build": "tsup",
60
+ "dev": "tsup --watch",
61
+ "test": "vitest run",
62
+ "test:watch": "vitest",
63
+ "typecheck": "tsc --noEmit",
64
+ "lint": "eslint .",
65
+ "lint:fix": "eslint . --fix",
66
+ "clean": "rimraf dist .turbo"
67
+ }
68
+ }