aipexbase-js 1.0.0 → 1.0.2

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/README.md ADDED
@@ -0,0 +1,868 @@
1
+ # AipexBase JS SDK
2
+
3
+ 一个功能丰富的 BaaS (Backend as a Service) JavaScript SDK,提供完整的后端服务能力。
4
+
5
+ ## 📋 目录
6
+
7
+ - [特性](#特性)
8
+ - [安装](#安装)
9
+ - [快速开始](#快速开始)
10
+ - [完整 API 文档](#完整-api-文档)
11
+ - [认证模块 (Auth)](#认证模块-auth)
12
+ - [数据库模块 (DB)](#数据库模块-db)
13
+ - [API 模块](#api-模块)
14
+ - [AI 模块](#ai-模块)
15
+ - [文档处理模块](#文档处理模块)
16
+ - [比价模块](#比价模块)
17
+ - [物流模块](#物流模块)
18
+ - [地理位置模块](#地理位置模块)
19
+ - [出行模块](#出行模块)
20
+ - [通知模块](#通知模块)
21
+ - [插件系统](#插件系统)
22
+ - [完整示例](#完整示例)
23
+ - [进阶用法](#进阶用法)
24
+ - [开发指南](#开发指南)
25
+
26
+ ## 特性
27
+
28
+ - 🔐 **用户认证** - 登录、注册、登出和用户信息管理
29
+ - 📊 **数据库操作** - 支持链式调用的 CRUD 操作
30
+ - 🤖 **AI 能力** - 文本对话、文生图、文生音频/视频等
31
+ - 📄 **文档处理** - PDF 转图片等功能
32
+ - 💰 **商品比价** - 商品搜索和最低价查询
33
+ - 📦 **物流查询** - 快递跟踪查询
34
+ - 📍 **地理服务** - 地址解析、路线规划、附近搜索
35
+ - 🚄 **出行服务** - 火车票和航班查询
36
+ - 📢 **消息通知** - 飞书机器人、企业微信、邮件发送
37
+ - 🔌 **插件系统** - 支持自定义插件扩展
38
+ - 🎯 **链式调用** - 优雅的 API 设计
39
+ - 🔑 **自动 Token 管理** - 自动存储和管理用户认证 Token
40
+ - 📦 **多格式支持** - 同时支持 CommonJS 和 ES Module
41
+
42
+ ## 安装
43
+
44
+ ```bash
45
+ npm install aipexbase-js
46
+ ```
47
+
48
+ ## 快速开始
49
+
50
+ ### 初始化客户端
51
+
52
+ ```javascript
53
+ import { createClient } from 'aipexbase-js';
54
+
55
+ const client = createClient({
56
+ baseUrl: 'https://your-api-endpoint.com',
57
+ apiKey: 'your-api-key'
58
+ });
59
+ ```
60
+
61
+ ### 自定义存储和请求
62
+
63
+ 如果你需要在 Node.js 环境或其他环境中使用,可以自定义存储和请求实现:
64
+
65
+ ```javascript
66
+ import { createClient } from 'aipexbase-js';
67
+ import { NodeStorage } from 'your-storage-lib';
68
+ import axios from 'axios';
69
+
70
+ const client = createClient({
71
+ baseUrl: 'https://your-api-endpoint.com',
72
+ apiKey: 'your-api-key',
73
+ storage: new NodeStorage(), // 自定义存储实现
74
+ request: async (url, options) => {
75
+ const res = await axios({ url, ...options });
76
+ return res.data;
77
+ }
78
+ });
79
+ ```
80
+
81
+ ## 完整 API 文档
82
+
83
+ ### 认证模块 (Auth)
84
+
85
+ #### 登录
86
+
87
+ 支持用户名、手机号或邮箱登录:
88
+
89
+ ```javascript
90
+ // 使用手机号登录
91
+ const result = await client.auth.login({
92
+ phone: '13800138000',
93
+ password: 'your-password'
94
+ });
95
+
96
+ // 使用邮箱登录
97
+ const result = await client.auth.login({
98
+ email: 'user@example.com',
99
+ password: 'your-password'
100
+ });
101
+
102
+ // 使用用户名登录
103
+ const result = await client.auth.login({
104
+ user_name: 'username',
105
+ password: 'your-password'
106
+ });
107
+ ```
108
+
109
+ #### 注册
110
+
111
+ ```javascript
112
+ const result = await client.auth.register({
113
+ user_name: 'newuser',
114
+ phone: '13800138000',
115
+ email: 'user@example.com',
116
+ password: 'your-password'
117
+ });
118
+ ```
119
+
120
+ #### 获取用户信息
121
+
122
+ ```javascript
123
+ const user = await client.auth.getUser();
124
+ ```
125
+
126
+ #### 登出
127
+
128
+ ```javascript
129
+ await client.auth.logout();
130
+ ```
131
+
132
+ #### 手动设置 Token
133
+
134
+ ```javascript
135
+ client.setToken('your-auth-token');
136
+ ```
137
+
138
+ ### 数据库模块 (DB)
139
+
140
+ #### 查询操作
141
+
142
+ **列表查询**
143
+
144
+ ```javascript
145
+ // 简单查询
146
+ const result = await client.db
147
+ .from('users')
148
+ .list();
149
+
150
+ // 带多个过滤条件
151
+ const result = await client.db
152
+ .from('users')
153
+ .list()
154
+ .eq('status', 'active')
155
+ .gt('age', 18)
156
+ .order('created_at', 'desc');
157
+
158
+ // 分页查询
159
+ const result = await client.db
160
+ .from('users')
161
+ .page()
162
+ .page(1, 20) // 页码,每页数量
163
+ .eq('status', 'active');
164
+
165
+ // 获取单条数据
166
+ const result = await client.db
167
+ .from('users')
168
+ .get()
169
+ .eq('id', 123);
170
+ ```
171
+
172
+ **过滤操作符**
173
+
174
+ ```javascript
175
+ // 等于
176
+ .eq('field', value)
177
+ // 不等于
178
+ .neq('field', value)
179
+ // 大于
180
+ .gt('field', value)
181
+ // 大于等于
182
+ .gte('field', value)
183
+ // 小于
184
+ .lt('field', value)
185
+ // 小于等于
186
+ .lte('field', value)
187
+ // 在范围内
188
+ .in('field', [value1, value2, value3])
189
+ // 在区间内
190
+ .between('field', [min, max])
191
+ ```
192
+
193
+ **OR 条件查询**
194
+
195
+ ```javascript
196
+ const result = await client.db
197
+ .from('users')
198
+ .list()
199
+ .eq('status', 'active')
200
+ .or((q) => {
201
+ q.eq('role', 'admin')
202
+ .eq('role', 'moderator');
203
+ });
204
+ ```
205
+
206
+ **排序**
207
+
208
+ ```javascript
209
+ // 升序
210
+ .order('created_at', 'asc')
211
+
212
+ // 降序
213
+ .order('created_at', 'desc')
214
+
215
+ // 对象形式
216
+ .order('created_at', { ascending: true })
217
+ .order('created_at', { direction: 'desc' })
218
+ ```
219
+
220
+ #### 插入数据
221
+
222
+ ```javascript
223
+ const result = await client.db
224
+ .from('users')
225
+ .insert()
226
+ .values({
227
+ name: 'John Doe',
228
+ email: 'john@example.com',
229
+ age: 25
230
+ });
231
+ ```
232
+
233
+ #### 更新数据
234
+
235
+ ```javascript
236
+ const result = await client.db
237
+ .from('users')
238
+ .update()
239
+ .set({
240
+ status: 'inactive'
241
+ })
242
+ .eq('id', 123);
243
+ ```
244
+
245
+ #### 删除数据
246
+
247
+ ```javascript
248
+ const result = await client.db
249
+ .from('users')
250
+ .delete()
251
+ .eq('id', 123);
252
+ ```
253
+
254
+ ### API 模块
255
+
256
+ 用于调用自定义 API 接口。
257
+
258
+ ```javascript
259
+ // 基本调用
260
+ const result = await client.api
261
+ .call('yourApiName')
262
+ .param('key1', 'value1')
263
+ .param('key2', 'value2');
264
+
265
+ // 批量设置参数
266
+ const result = await client.api
267
+ .call('yourApiName')
268
+ .params({
269
+ key1: 'value1',
270
+ key2: 'value2'
271
+ });
272
+
273
+ // 自定义请求头
274
+ const result = await client.api
275
+ .call('yourApiName')
276
+ .headers({
277
+ 'X-Custom-Header': 'value'
278
+ })
279
+ .params({ data: 'value' });
280
+ ```
281
+
282
+ ### AI 模块
283
+
284
+ #### 文本对话
285
+
286
+ ```javascript
287
+ // 基本对话
288
+ const result = await client.ai.chat()
289
+ .text('你好,介绍一下你自己');
290
+
291
+ // 带提示词和会话ID的对话
292
+ const result = await client.ai.chat()
293
+ .text('今天天气怎么样?')
294
+ .prompt('你是一个天气预报助手')
295
+ .conversationId('session-123');
296
+ ```
297
+
298
+ #### 图片对话(图生文)
299
+
300
+ ```javascript
301
+ const result = await client.ai.imageToText()
302
+ .url('https://example.com/image.jpg')
303
+ .text('这张图片里有什么?')
304
+ .prompt('请详细描述图片内容');
305
+ ```
306
+
307
+ #### 文生图
308
+
309
+ ```javascript
310
+ const result = await client.ai.textToImage()
311
+ .text('一只可爱的熊猫在竹林里');
312
+ ```
313
+
314
+ #### 文本转语音
315
+
316
+ ```javascript
317
+ const result = await client.ai.textToSpeech()
318
+ .text('你好,欢迎使用语音合成服务');
319
+ ```
320
+
321
+ #### 文本转视频
322
+
323
+ ```javascript
324
+ // 方式1:自动执行(创建任务并轮询直到完成)
325
+ const result = await client.ai.textToVideo()
326
+ .text('一只小猫在草地上玩耍');
327
+
328
+ // 方式2:手动控制
329
+ const videoTask = client.ai.textToVideo().text('一只小猫在草地上玩耍');
330
+
331
+ // 创建任务
332
+ const createResult = await videoTask.createTask();
333
+ console.log('任务ID:', createResult.data);
334
+
335
+ // 查询任务状态
336
+ const queryResult = await videoTask.queryTask(createResult.data);
337
+ console.log('任务状态:', queryResult.data);
338
+ ```
339
+
340
+ #### 文本转音频
341
+
342
+ ```javascript
343
+ // 方式1:自动执行
344
+ const result = await client.ai.textToAudio()
345
+ .text('一段优美的旋律');
346
+
347
+ // 方式2:手动控制
348
+ const audioTask = client.ai.textToAudio().text('一段优美的旋律');
349
+ const createResult = await audioTask.createTask();
350
+ const queryResult = await audioTask.queryTask(createResult.data);
351
+ ```
352
+
353
+ ### 文档处理模块
354
+
355
+ #### PDF 转图片
356
+
357
+ ```javascript
358
+ // 基本用法
359
+ const result = await client.document.convertPdf()
360
+ .url('https://example.com/document.pdf')
361
+ .convert();
362
+
363
+ // 自定义配置
364
+ const result = await client.document.convertPdf()
365
+ .url('https://example.com/document.pdf')
366
+ .format('pdf-to-image')
367
+ .pollingInterval(3000) // 轮询间隔(毫秒)
368
+ .maxRetries(50) // 最大重试次数
369
+ .convert();
370
+
371
+ // 手动控制
372
+ const pdfTask = client.document.convertPdf()
373
+ .url('https://example.com/document.pdf');
374
+
375
+ // 创建任务
376
+ const createResult = await pdfTask.createTask();
377
+
378
+ // 查询任务
379
+ const queryResult = await pdfTask.queryTask(createResult.data);
380
+
381
+ // 快捷方式
382
+ const result = await client.document.quickConvert({
383
+ url: 'https://example.com/document.pdf',
384
+ format: 'pdf-to-image',
385
+ pollingInterval: 3000,
386
+ maxRetries: 50
387
+ });
388
+ ```
389
+
390
+ ### 比价模块
391
+
392
+ #### 商品搜索
393
+
394
+ ```javascript
395
+ const result = await client.comparison.searchProduct()
396
+ .keyword('苹果手机');
397
+
398
+ // 自定义参数
399
+ const result = await client.comparison.searchProduct()
400
+ .keyword('苹果手机')
401
+ .setParams({ sort: 'price' });
402
+ ```
403
+
404
+ #### 最低价查询
405
+
406
+ ```javascript
407
+ const result = await client.comparison.findLowestPrice()
408
+ .keyword('华为 Mate 60');
409
+ ```
410
+
411
+ ### 物流模块
412
+
413
+ #### 快递查询
414
+
415
+ ```javascript
416
+ // 普通快递查询
417
+ const result = await client.logistics.trackPackage()
418
+ .company('yuantong') // 快递公司代码
419
+ .trackingNumber('123456789')
420
+ .track();
421
+
422
+ // 顺丰快递(必须提供手机号)
423
+ const result = await client.logistics.trackPackage()
424
+ .company('shunfeng')
425
+ .trackingNumber('SF123456789')
426
+ .phone('13800138000')
427
+ .track();
428
+ ```
429
+
430
+ **常见快递公司代码**:
431
+ - `yuantong` - 圆通速递
432
+ - `shentong` - 申通快递
433
+ - `zhongtong` - 中通快递
434
+ - `yunda` - 韵达速递
435
+ - `shunfeng` - 顺丰速运
436
+ - `shunfengkuaiyun` - 顺丰快运
437
+
438
+ ### 地理位置模块
439
+
440
+ #### 经纬度转地址(逆地理编码)
441
+
442
+ ```javascript
443
+ const result = await client.location.locationToAddress()
444
+ .latitude(39.9042)
445
+ .longitude(116.4074);
446
+ ```
447
+
448
+ #### 地址转经纬度(地理编码)
449
+
450
+ ```javascript
451
+ const result = await client.location.addressToLocation()
452
+ .address('北京市天安门广场');
453
+ ```
454
+
455
+ #### 获取当前IP位置
456
+
457
+ ```javascript
458
+ const result = await client.location.currentLocation();
459
+ ```
460
+
461
+ #### 路线规划
462
+
463
+ ```javascript
464
+ const result = await client.location.driving()
465
+ .from(39.9042, 116.4074) // 起点经纬度
466
+ .to(40.0076, 116.4929); // 终点经纬度
467
+ ```
468
+
469
+ #### 附近搜索
470
+
471
+ ```javascript
472
+ const result = await client.location.nearby()
473
+ .lat(39.9042)
474
+ .lng(116.4074)
475
+ .radius(1000) // 搜索半径(米)
476
+ .keyword('餐厅'); // 搜索关键词
477
+ ```
478
+
479
+ ### 出行模块
480
+
481
+ #### 火车票查询
482
+
483
+ ```javascript
484
+ const result = await client.travel.train()
485
+ .from('北京')
486
+ .to('上海')
487
+ .date('2024-01-01');
488
+ ```
489
+
490
+ #### 航班查询
491
+
492
+ ```javascript
493
+ const result = await client.travel.flight()
494
+ .from('北京')
495
+ .to('上海')
496
+ .date('2024-01-01');
497
+ ```
498
+
499
+ ### 通知模块
500
+
501
+ #### 飞书机器人
502
+
503
+ ```javascript
504
+ await client.notification.feishuRobot()
505
+ .content('这是一条来自飞书机器人的消息');
506
+ ```
507
+
508
+ #### 企业微信机器人
509
+
510
+ ```javascript
511
+ await client.notification.wechatRobot()
512
+ .content('这是一条来自企业微信的消息');
513
+ ```
514
+
515
+ #### 邮件发送
516
+
517
+ ```javascript
518
+ // 简单邮件
519
+ await client.notification.mail()
520
+ .to('user@example.com')
521
+ .title('测试邮件')
522
+ .content('这是一封测试邮件');
523
+
524
+ // 模板邮件
525
+ await client.notification.mail()
526
+ .to('user@example.com')
527
+ .title('欢迎注册')
528
+ .content('欢迎加入我们!')
529
+ .params({
530
+ username: 'John Doe',
531
+ activationCode: 'ABC123'
532
+ });
533
+ ```
534
+
535
+ ### 插件系统
536
+
537
+ AipexBase 支持插件扩展功能。
538
+
539
+ #### 注册插件
540
+
541
+ #### 检查插件状态
542
+
543
+ ```javascript
544
+ // 检查插件是否已注册
545
+ pluginLoader.isRegistered('myPlugin');
546
+
547
+ // 获取所有已注册的插件
548
+ pluginLoader.getRegisteredPlugins();
549
+
550
+ // 移除插件
551
+ pluginLoader.unregister('myPlugin');
552
+ ```
553
+
554
+ ## 完整示例
555
+
556
+ ### 用户认证和数据处理流程
557
+
558
+ ```javascript
559
+ import { createClient } from 'aipexbase-js';
560
+
561
+ // 初始化客户端
562
+ const client = createClient({
563
+ baseUrl: 'https://your-api-endpoint.com',
564
+ apiKey: 'your-api-key'
565
+ });
566
+
567
+ async function main() {
568
+ try {
569
+ // 1. 用户注册
570
+ const registerResult = await client.auth.register({
571
+ user_name: 'john_doe',
572
+ email: 'john@example.com',
573
+ password: 'securePassword123'
574
+ });
575
+ console.log('注册成功:', registerResult);
576
+
577
+ // 2. 用户登录
578
+ const loginResult = await client.auth.login({
579
+ email: 'john@example.com',
580
+ password: 'securePassword123'
581
+ });
582
+ console.log('登录成功');
583
+
584
+ // 3. 获取用户信息
585
+ const user = await client.auth.getUser();
586
+ console.log('用户信息:', user);
587
+
588
+ // 4. 创建数据
589
+ const createResult = await client.db
590
+ .from('posts')
591
+ .insert()
592
+ .values({
593
+ title: '我的第一篇文章',
594
+ content: '这是文章内容...',
595
+ author_id: user.data.id
596
+ });
597
+ console.log('创建成功:', createResult);
598
+
599
+ // 5. 查询数据
600
+ const posts = await client.db
601
+ .from('posts')
602
+ .list()
603
+ .eq('author_id', user.data.id)
604
+ .order('created_at', 'desc');
605
+ console.log('文章列表:', posts);
606
+
607
+ // 6. 更新数据
608
+ const updateResult = await client.db
609
+ .from('posts')
610
+ .update()
611
+ .set({ title: '更新的标题' })
612
+ .eq('id', createResult.data.id);
613
+ console.log('更新成功:', updateResult);
614
+
615
+ // 7. 登出
616
+ await client.auth.logout();
617
+ console.log('已登出');
618
+
619
+ } catch (error) {
620
+ console.error('操作失败:', error);
621
+ }
622
+ }
623
+
624
+ main();
625
+ ```
626
+
627
+ ### AI 功能集成示例
628
+
629
+ ```javascript
630
+ async function aiExample() {
631
+ try {
632
+ // 1. AI 对话
633
+ const chatResult = await client.ai.chat()
634
+ .text('你好,介绍一下你自己')
635
+ .prompt('你是一个友好的AI助手');
636
+ console.log('AI回复:', chatResult);
637
+
638
+ // 2. 图生文
639
+ const imageResult = await client.ai.imageToText()
640
+ .url('https://example.com/image.jpg')
641
+ .text('这张图片里有什么?');
642
+ console.log('图片分析:', imageResult);
643
+
644
+ // 3. 文生图
645
+ const imageGen = await client.ai.textToImage()
646
+ .text('一只可爱的熊猫在竹林里');
647
+ console.log('生成图片:', imageGen);
648
+
649
+ // 4. 文本转视频
650
+ const video = await client.ai.textToVideo()
651
+ .text('一只小猫在草地上玩耍');
652
+ console.log('生成视频:', video);
653
+
654
+ } catch (error) {
655
+ console.error('AI 功能失败:', error);
656
+ }
657
+ }
658
+ ```
659
+
660
+ ### 物流和位置服务示例
661
+
662
+ ```javascript
663
+ async function logisticsAndLocation() {
664
+ try {
665
+ // 1. 查询快递
666
+ const tracking = await client.logistics.trackPackage()
667
+ .company('yuantong')
668
+ .trackingNumber('123456789');
669
+ console.log('快递信息:', tracking);
670
+
671
+ // 2. 地址转经纬度
672
+ const location = await client.location.addressToLocation()
673
+ .address('北京市天安门广场');
674
+ console.log('经纬度:', location);
675
+
676
+ // 3. 路线规划
677
+ const route = await client.location.driving()
678
+ .from(39.9042, 116.4074)
679
+ .to(40.0076, 116.4929);
680
+ console.log('路线信息:', route);
681
+
682
+ // 4. 附近搜索
683
+ const nearby = await client.location.nearby()
684
+ .lat(39.9042)
685
+ .lng(116.4074)
686
+ .radius(1000)
687
+ .keyword('餐厅');
688
+ console.log('附近餐厅:', nearby);
689
+
690
+ } catch (error) {
691
+ console.error('服务调用失败:', error);
692
+ }
693
+ }
694
+ ```
695
+
696
+ ## 进阶用法
697
+
698
+ ### 自定义请求拦截器
699
+
700
+ ```javascript
701
+ const customRequest = async (url, options) => {
702
+ // 添加自定义请求头
703
+ options.headers = {
704
+ ...options.headers,
705
+ 'X-Custom-Header': 'value'
706
+ };
707
+
708
+ // 记录请求日志
709
+ console.log('Request:', url, options);
710
+
711
+ const res = await fetch(url, options);
712
+ const data = await res.json();
713
+
714
+ // 处理错误
715
+ if (!res.ok) {
716
+ throw new Error(data.message || 'Request failed');
717
+ }
718
+
719
+ return data;
720
+ };
721
+
722
+ const client = createClient({
723
+ baseUrl: 'https://api.example.com',
724
+ apiKey: 'your-key',
725
+ request: customRequest
726
+ });
727
+ ```
728
+
729
+ ### 自定义存储实现
730
+
731
+ ```javascript
732
+ // Node.js 环境
733
+ class NodeStorage {
734
+ constructor() {
735
+ this.data = {};
736
+ }
737
+
738
+ getItem(key) {
739
+ return this.data[key] || null;
740
+ }
741
+
742
+ setItem(key, value) {
743
+ this.data[key] = value;
744
+ }
745
+
746
+ removeItem(key) {
747
+ delete this.data[key];
748
+ }
749
+ }
750
+
751
+ const client = createClient({
752
+ baseUrl: 'https://api.example.com',
753
+ apiKey: 'your-key',
754
+ storage: new NodeStorage()
755
+ });
756
+ ```
757
+
758
+ ### 错误处理最佳实践
759
+
760
+ ```javascript
761
+ async function safeOperation() {
762
+ try {
763
+ const result = await client.db
764
+ .from('users')
765
+ .list();
766
+ return { success: true, data: result };
767
+ } catch (error) {
768
+ console.error('操作失败:', error);
769
+
770
+ // 根据错误类型处理
771
+ if (error.message.includes('unauthorized')) {
772
+ // 重新登录
773
+ await client.auth.login({ ... });
774
+ }
775
+
776
+ return { success: false, error: error.message };
777
+ }
778
+ }
779
+ ```
780
+
781
+ ## 开发指南
782
+
783
+ ### 项目结构
784
+
785
+ ```
786
+ aipexbase-js/
787
+ ├── src/
788
+ │ ├── client.js # 核心客户端
789
+ │ ├── index.js # 入口文件
790
+ │ ├── modules/ # 功能模块
791
+ │ │ ├── auth.js # 认证模块
792
+ │ │ ├── db.js # 数据库模块
793
+ │ │ ├── api.js # API 模块
794
+ │ │ ├── ai.js # AI 模块
795
+ │ │ ├── document.js # 文档处理模块
796
+ │ │ ├── comparison.js # 比价模块
797
+ │ │ ├── logistics.js # 物流模块
798
+ │ │ ├── location.js # 地理位置模块
799
+ │ │ ├── travel.js # 出行模块
800
+ │ │ └── notification.js # 通知模块
801
+ │ └── plugins/ # 插件系统
802
+ │ ├── plugin-loader.js
803
+ │ └── README.md
804
+ ├── dist/ # 构建输出
805
+ │ ├── index.cjs.js # CommonJS 格式
806
+ │ └── index.esm.js # ES Module 格式
807
+ ├── tests/ # 测试文件
808
+ ├── package.json
809
+ ├── rollup.config.mjs
810
+ └── README.md
811
+ ```
812
+
813
+ ### 本地开发
814
+
815
+ ```bash
816
+ # 安装依赖
817
+ npm install
818
+
819
+ # 构建项目
820
+ npm run build
821
+
822
+ # 运行测试
823
+ npm test
824
+
825
+ # 运行真实 API 测试
826
+ npm run test:real
827
+
828
+ # 监听模式运行测试
829
+ npm run test:watch
830
+ ```
831
+
832
+ ### 构建和发布
833
+
834
+ ```bash
835
+ # 构建
836
+ npm run build
837
+
838
+ # 发布的文件在 dist 目录
839
+ ```
840
+
841
+ ## 贡献
842
+
843
+ 欢迎提交 Issue 和 Pull Request!
844
+
845
+ ### 开发流程
846
+
847
+ 1. Fork 项目
848
+ 2. 创建特性分支
849
+ 3. 提交更改
850
+ 4. 推送到分支
851
+ 5. 创建 Pull Request
852
+
853
+ ## License
854
+
855
+ ISC
856
+
857
+ ## 支持
858
+
859
+ 如果您在使用过程中遇到问题,请:
860
+
861
+ 1. 查看文档和示例
862
+ 2. 搜索已有的 Issue
863
+ 3. 创建新的 Issue 并提供详细的错误信息
864
+
865
+ ---
866
+
867
+ **AipexBase JS SDK** - 让后端开发更简单 🚀
868
+
package/dist/index.cjs.js CHANGED
@@ -1 +1 @@
1
- "use strict";class t{constructor({baseUrl:t,apiKey:e}){this.baseUrl=t,this.apiKey=e,this.token=localStorage.getItem("baas_token")||null}setToken(t){this.token=t,t?localStorage.setItem("baas_token",t):localStorage.removeItem("baas_token")}async request(t,e={}){const s=`${this.baseUrl}${t}`,i={"Content-Type":"application/json",CODE_FLYING:`${this.apiKey}`,...this.token?{Authorization:`Bearer ${this.token}`}:{},...e.headers||{}};return(await fetch(s,{...e,headers:i})).json()}}function e(t){return{async login({user_name:e,phone:s,email:i,password:r}={}){const n=e||s||i;if(!n)throw new Error("必须提供 user_name、phone 或 email 之一");if(!r)throw new Error("必须提供 password");const a=await t.request("/login/passwd",{method:"POST",body:JSON.stringify({phone:n,password:r})});return a.success&&t.setToken(a.data),a},getUser:async()=>t.request("/getUserInfo",{method:"GET"}),register:async e=>await t.request("/login/register",{method:"POST",body:JSON.stringify(e)}),logout:async()=>(t.setToken(null),t.request("/logout",{method:"GET"}))}}class s{constructor(t,e){this.client=t,this.table=e,this._body=null,this._method=""}list(){return new i(this.client,this.table,"list")}page(){return new i(this.client,this.table,"page")}get(){return new i(this.client,this.table,"get")}insert(){return new r(this.client,this.table,"add")}update(){return new r(this.client,this.table,"update")}delete(){return new i(this.client,this.table,"delete")}}class i{constructor(t,e,s){this.client=t,this.table=e,this.method=s,this.filters={}}_addFilter(t,e,s){return this.filters.hasOwnProperty(t)||(this.filters[t]={}),this.filters[t][e]=s,this}eq(t,e){return this._addFilter(t,"eq",e)}neq(t,e){return this._addFilter(t,"neq",e)}gt(t,e){return this._addFilter(t,"gt",e)}gte(t,e){return this._addFilter(t,"gte",e)}lt(t,e){return this._addFilter(t,"lt",e)}lte(t,e){return this._addFilter(t,"lte",e)}in(t,e){return this._addFilter(t,"in",e)}between(t,e){return this._addFilter(t,"between",e)}or(t){this.filters.or||(this.filters.or=[]);const e=new i(this.client,this.table,"or");return t(e),this.filters.or.push(e.build()),this}limit(t){return this}page(t,e){return this.filters.current=t,this.filters.pageSize=e,this}order(t,e="asc"){this.filters.order_by||(this.filters.order_by=[]);let s="asc";return"string"==typeof e?s=e.toLowerCase():"object"==typeof e&&null!==e&&("ascending"in e?s=e.ascending?"asc":"desc":"direction"in e&&(s=e.direction.toLowerCase())),this.filters.order_by.push({field:t,direction:s}),this}build(){return this.filters}async _execute(){return await this.client.request(`/api/data/invoke?table=${this.table}&method=${this.method}`,{method:"POST",body:this.filters?JSON.stringify(this.filters):void 0})}then(t,e){this._execute().then(t,e)}}class r extends i{constructor(t,e,s){super(t,e,s),this.data={}}values(t){return this.data={...t},this}set(t){return this.data={...t},this}build(){return{...this.filters,...this.data}}async _execute(){return await this.client.request(`/api/data/invoke?table=${this.table}&method=${this.method}`,{method:"POST",body:JSON.stringify(this.build())})}then(t,e){this._execute().then(t,e)}}function n(t){return{from:e=>new s(t,e)}}class a{constructor(t,e){this.client=t,this.apiName=e,this._params={},this._headers={},this._method="POST"}param(t,e){return this._params[t]=e,this}params(t){return Object.assign(this._params,t),this}header(t,e){return this._headers[t]=e,this}headers(t){return Object.assign(this._headers,t),this}async _execute(){const t=JSON.stringify(this._params),e=`/api/${this.apiName}`;return await this.client.request(e,{method:this._method,headers:this._headers,body:t})}then(t,e){this._execute().then(t,e)}}function h(t){return{call:e=>new a(t,e)}}exports.createClient=function(s){const i=new t(s);return{setToken:t=>i.setToken(t),auth:e(i),db:n(i),api:h(i)}};
1
+ "use strict";const t={getItem(t){try{return localStorage.getItem(t)}catch(t){return console.warn("No localStorage available"),null}},setItem(t,e){try{localStorage.setItem(t,e)}catch(t){console.warn("Cannot write to localStorage")}},removeItem(t){try{localStorage.removeItem(t)}catch(t){console.warn("Cannot remove from localStorage")}}},e=async(t,e)=>(await fetch(t,e)).json();class s{constructor({baseUrl:s,apiKey:r,storage:i,request:a}){this.baseUrl=s,this.apiKey=r,this.storage=i||t,this.requestImpl=a||e,this.token=this.storage.getItem("baas_token")||null}getApiKey(){return this.apiKey}setToken(t){this.token=t||null,t?this.storage.setItem("baas_token",t):this.storage.removeItem("baas_token")}async request(t,e={}){const s=`${this.baseUrl}${t}`,r={"Content-Type":"application/json",CODE_FLYING:`${this.apiKey}`,...this.token?{Authorization:`Bearer ${this.token}`}:{},...e.headers||{}},i=await this.requestImpl(s,{...e,headers:r});return console.log("request======",i),i}}function r(t){return{async login({user_name:e,phone:s,email:r,password:i}={}){const a=e||s||r;if(!a)throw new Error("必须提供 user_name、phone 或 email 之一");if(!i)throw new Error("必须提供 password");const n=await t.request("/login/passwd",{method:"POST",body:JSON.stringify({phone:a,password:i})});return n.success&&t.setToken(n.data),n},getUser:async()=>t.request("/getUserInfo",{method:"GET"}),register:async e=>await t.request("/login/register",{method:"POST",body:JSON.stringify(e)}),logout:async()=>(t.setToken(null),t.request("/logout",{method:"GET"}))}}class i{constructor(t,e){this.client=t,this.table=e,this._body=null,this._method=""}list(){return new a(this.client,this.table,"list")}page(){return new a(this.client,this.table,"page")}get(){return new a(this.client,this.table,"get")}insert(){return new n(this.client,this.table,"add")}update(){return new n(this.client,this.table,"update")}delete(){return new a(this.client,this.table,"delete")}}class a{constructor(t,e,s){this.client=t,this.table=e,this.method=s,this.filters={}}_addFilter(t,e,s){return this.filters.hasOwnProperty(t)||(this.filters[t]={}),this.filters[t][e]=s,this}eq(t,e){return this._addFilter(t,"eq",e)}neq(t,e){return this._addFilter(t,"neq",e)}gt(t,e){return this._addFilter(t,"gt",e)}gte(t,e){return this._addFilter(t,"gte",e)}lt(t,e){return this._addFilter(t,"lt",e)}lte(t,e){return this._addFilter(t,"lte",e)}like(t,e){return this._addFilter(t,"like",e)}in(t,e){return this._addFilter(t,"in",e)}between(t,e){return this._addFilter(t,"between",e)}or(t){this.filters.or||(this.filters.or=[]);const e=new a(this.client,this.table,"or");return t(e),this.filters.or.push(e.build()),this}limit(t){return this}page(t,e){return this.filters.current=t,this.filters.pageSize=e,this}order(t,e="asc"){this.filters.order_by||(this.filters.order_by=[]);let s="asc";return"string"==typeof e?s=e.toLowerCase():"object"==typeof e&&null!==e&&("ascending"in e?s=e.ascending?"asc":"desc":"direction"in e&&(s=e.direction.toLowerCase())),this.filters.order_by.push({field:t,direction:s}),this}build(){return this.filters}async _execute(){return await this.client.request(`/api/data/invoke?table=${this.table}&method=${this.method}`,{method:"POST",body:this.filters?JSON.stringify(this.filters):void 0})}then(t,e){this._execute().then(t,e)}}class n extends a{constructor(t,e,s){super(t,e,s),this.data={}}values(t){return this.data={...t},this}set(t){return this.data={...t},this}build(){return{...this.filters,...this.data}}async _execute(){return await this.client.request(`/api/data/invoke?table=${this.table}&method=${this.method}`,{method:"POST",body:JSON.stringify(this.build())})}then(t,e){this._execute().then(t,e)}}function o(t){return{from:e=>new i(t,e)}}class h{constructor(t,e){this.client=t,this.apiName=e,this._params={},this._headers={},this._method="POST"}param(t,e){return this._params[t]=e,this}params(t){return Object.assign(this._params,t),this}header(t,e){return this._headers[t]=e,this}headers(t){return Object.assign(this._headers,t),this}async _execute(){const t=JSON.stringify(this._params),e=`/api/${this.apiName}`;return await this.client.request(e,{method:this._method,headers:this._headers,body:t})}then(t,e){this._execute().then(t,e)}}function c(t){return{call:e=>new h(t,e)}}class l{static API_MAP={search:"/api/bijia_spu_search",compare:"/api/bijia_spu_goods_search"};constructor(t,e){this.client=t,this._params={},this.type=e}keyword(t){return this._params.query=t,this}setParams(t={}){return Object.assign(this._params,t),this}type(t){if(!l.API_MAP[t])throw new Error(`Unsupported comparison type: ${t}`);return this.type=t,this}async _execute(){const t=l.API_MAP[this.type];return await this.client.request(t,{method:"POST",body:JSON.stringify(this._params)})}then(t,e){this._execute().then(t,e)}}function u(t){return{searchProduct:()=>new l(t,"search"),findLowestPrice:()=>new l(t,"compare")}}class d{constructor(t){this.client=t,this._params={},this._taskId=null,this._pollingInterval=2e3,this._maxRetries=30}url(t){return this._params.url=t,this._params.format="pdf-to-image",this}format(t="pdf-to-image"){return this._params.format=t,this}pollingInterval(t){return this._pollingInterval=t,this}maxRetries(t){return this._maxRetries=t,this}async createTask(){if(!this._params.url)throw new Error("PDF文件URL不能为空");const t=await this.client.request("/api/pdf2image",{method:"POST",body:JSON.stringify({url:this._params.url,format:this._params.format})});return this._taskId=t.data,t}async queryTask(t=null){const e=t||this._taskId;if(!e)throw new Error("任务ID不能为空,请先创建任务");return await this.client.request("/api/queryPDF2ImageTask",{method:"POST",body:JSON.stringify({taskId:e})})}async convert(){try{console.log("开始创建PDF转图片任务...");const t=await this.createTask();console.log("任务创建成功:",t);const e=t.data;if(!e)throw new Error("任务创建失败,未返回任务ID");console.log("开始轮询查询任务状态...");let s=0;for(;s<this._maxRetries;){const t=await this.queryTask(e);console.log(`第${s+1}次查询结果:`,t);const r=t.data?.state;if(1===r)return console.log("PDF转图片任务完成:",t.data),t;if(r<0)return console.log("PDF转图片任务失败,状态码:",r),t;s++,s<this._maxRetries&&(console.log(`等待${this._pollingInterval}ms后进行第${s+1}次查询...`),await new Promise(t=>setTimeout(t,this._pollingInterval)))}throw new Error(`PDF转图片任务超时,已重试${this._maxRetries}次`)}catch(t){throw console.error("PDF转图片失败:",t),t}}then(t,e){return this.convert().then(t,e)}catch(t){return this.convert().catch(t)}}function p(t){return{convertPdf:()=>new d(t),async quickConvert(e={}){const s=new d(t);return e.url&&s.url(e.url),e.format&&s.format(e.format),e.pollingInterval&&s.pollingInterval(e.pollingInterval),e.maxRetries&&s.maxRetries(e.maxRetries),await s.convert()}}}class m{constructor(t){this.client=t,this._params={}}company(t){return this._params.com=t,this}trackingNumber(t){return this._params.num=t,this}phone(t){return this._params.phone=t,this}_validateParams(){if(!this._params.com)throw new Error("快递公司代码不能为空");if(!this._params.num)throw new Error("快递单号不能为空");if(("shunfeng"===this._params.com||"shunfengkuaiyun"===this._params.com)&&!this._params.phone)throw new Error("顺丰快递必须提供手机号参数")}async track(){return this._validateParams(),await this.client.request("/api/expressInquiry",{method:"POST",body:JSON.stringify({com:this._params.com,num:this._params.num,resultv2:4,...this._params.phone?{phone:this._params.phone}:{}})})}then(t,e){return this.track().then(t,e)}catch(t){return this.track().catch(t)}}function g(t){return{trackPackage:()=>new m(t)}}class _{static LOCATION_MAP={location:"/api/geocoder",address:"/api/geoaddress"};constructor(t,e){this.client=t,this._params={},this.type=e}latitude(t){return this._params.latitude=t,this}longitude(t){return this._params.longitude=t,this}address(t){return this._params.address=t,this}_validateLocationParams(){if(!this._params.latitude||!this._params.longitude)throw new Error("经纬度参数不能为空")}_validateAddressParams(){if(!this._params.address)throw new Error("地址参数不能为空")}_data(){return"location"===this.type?(this._validateLocationParams(),{location:`${this._params.latitude},${this._params.longitude}`}):(this._validateAddressParams(),{address:this._params.address})}async _execute(){const t=_.LOCATION_MAP[this.type],e=this._data();return await this.client.request(t,{method:"POST",body:JSON.stringify(e)})}then(t,e){this._execute().then(t,e)}}class y{constructor(t){this.client=t}async _execute(){const t=await this.client.request("/api/amap_ip_location",{method:"POST",body:JSON.stringify({})}),e=t?.data?.rectangle;if(!e)throw new Error("返回数据中缺少 rectangle 字段");const[s,r]=e.split(";"),[i,a]=s.split(",").map(Number),[n,o]=r.split(",").map(Number);return{success:!0,latitude:(a+o)/2,longitude:(i+n)/2,speed:0,altitude:0,horizontalAccuracy:1e3}}then(t,e){this._execute().then(t,e)}}class f{constructor(t){this.client=t,this._params={}}from(t,e){return this._params.from={lat:t,lng:e},this}to(t,e){return this._params.to={lat:t,lng:e},this}decodePolyline(t){for(let e=2;e<t.length;e++)t[e]=t[e-2]+t[e]/1e6;return t}async _execute(){const{from:t,to:e}=this._params;if(!t||!e)throw new Error("必须提供起点和终点坐标");const s={from:`${t.lat},${t.lng}`,to:`${e.lat},${e.lng}`},r=await this.client.request("/api/driving",{method:"POST",body:JSON.stringify(s)}),{routes:i}=r.data.result;return{success:!0,data:{paths:i.map(t=>{const e=this.decodePolyline([...t.polyline]),s=t.steps.map(t=>{const{polyline_idx:[s,r]}=t,i=[];for(let t=s;t<=r;t+=2)i.push({latitude:e[t],longitude:e[t+1]});return{...t,polylines:i}});return{distance:t.distance,duration:t.duration,steps:s}})}}}then(t,e){this._execute().then(t,e)}}class w{constructor(t){this.client=t,this._params={}}lat(t){return this._params.lat=t,this}lng(t){return this._params.lng=t,this}radius(t){return this._params.radius=t,this}keyword(t){return this._params.keyword=t,this}async _execute(){const{lat:t,lng:e,radius:s=1e3,keyword:r}=this._params;if(!t||!e)throw new Error("必须提供经纬度参数");const i={boundary:`nearby(${t},${e},${s})`,...r&&{keyword:r}},a=await this.client.request("/api/mapsearch",{method:"POST",body:JSON.stringify(i)}),{data:n}=a.data;return{success:!0,data:n.map(t=>({...t,latitude:t.location.lat,longitude:t.location.lng}))}}then(t,e){this._execute().then(t,e)}}function P(t){return{locationToAddress:()=>new _(t,"location"),addressToLocation:()=>new _(t,"address"),currentLocation:()=>new y(t),driving:()=>new f(t),nearby:()=>new w(t)}}class b{static API_MAP={train:"/api/queryTickets",flight:"/api/queryFlight"};constructor(t,e){this.client=t,this.params={},this.mode=e}from(t){return this.params.from=t,this}to(t){return this.params.to=t,this}date(t){return this.params.date=t,this}async _execute(){const t=b.API_MAP[this.mode];return await this.client.request(t,{method:"POST",body:JSON.stringify(this.params)})}then(t,e){this._execute().then(t,e)}}function x(t){return{train:()=>new b(t,"train"),flight:()=>new b(t,"flight")}}class I{static API_MAP={feishu:"/api/feishuRobotText",wechat:"/api/wechatRobotText"};constructor(t,e){this.client=t,this.params={},this.mode=e}content(t){return this.params.content=t?.replace(/\r?\n/g," "),this}async _execute(){const t=I.API_MAP[this.mode];return await this.client.request(t,{method:"POST",body:JSON.stringify(this.params)})}then(t,e){this._execute().then(t,e)}}class T{constructor(t){this.client=t,this.payload={}}title(t){return this.payload.title=t,this}content(t){return this.payload.content=t?.replace(/\r?\n/g," "),this}to(t){return this.payload.to=t,this}params(t={}){return this.payload.params=t,this}async _execute(){return await this.client.request("/common/mail/send",{method:"POST",body:JSON.stringify(this.payload)})}then(t,e){this._execute().then(t,e)}}function O(t){return{feishuRobot:()=>new I(t,"feishu"),wechatRobot:()=>new I(t,"wechat"),mail:()=>new T(t)}}class S{static API_MAP={text2pic:"/api/pic/word2pic",text2tts:"/api/text/tts"};constructor(t,e){this.client=t,this.params={},this.mode=e}text(t){return this.params.text=t,this}async _execute(){const t=S.API_MAP[this.mode];return await this.client.request(t,{method:"POST",body:JSON.stringify(this.params)})}then(t,e){this._execute().then(t,e)}}class v{constructor(t){this.client=t,this.params={}}text(t){return this.params.text=t,this}prompt(t){return this.params.prompt=t,this}conversationId(t){return this.params.conversationId=t,this}async _execute(){const{text:t,prompt:e="",conversationId:s=""}=this.params,r={prompt:e,query:t,conversation_id:s,user:this.client.getApiKey(),files:[]};return await this.client.request("/api/AiAnalysis",{method:"POST",body:JSON.stringify(r)})}then(t,e){this._execute().then(t,e)}}class k extends v{constructor(t){super(t)}url(t){return this.params.url=t,this}async _execute(){const{url:t,prompt:e,text:s,conversationId:r=""}=this.params,i=[{type:"image",transfer_method:"remote_url",url:t}],a={prompt:e,query:s,conversation_id:r,user:this.client.getApiKey(),files:t?i:[]};return await this.client.request("/api/AiAnalysis",{method:"POST",body:JSON.stringify(a)})}then(t,e){this._execute().then(t,e)}}class A{static CREATE_API_MAP={video:"/api/text2video",audio:"/api/text2music"};static QUERY_API_MAP={video:"/api/queryVideo",audio:"/api/queryMusic"};constructor(t,e){this.client=t,this.params={},this.mode=e,this._taskId=null}text(t){this.params.text=t}createTask(){const t=this.params.text;if(!t)throw new Error("文本内容不能为空");const e=A.CREATE_API_MAP[this.mode];let s={};s="video"===this.mode?{text:t}:{prompt:this.cleanString(t)};const r=this.client.request(e,{method:"POST",body:JSON.stringify(s)});return this._taskId=r.data,r}async queryTask(t=null){const e=t||this._taskId;if(!e)throw new Error("任务ID不能为空,请先创建任务");const s=A.QUERY_API_MAP[this.mode];let r={};return r="video"===this.mode?{id:e}:{item_ids:e},await this.client.request(s,{method:"POST",body:JSON.stringify(r)})}async _execute(){const t=await this.createTask();console.log("任务创建成功:",t);const e=t.data;if(!e)throw new Error("任务创建失败,未返回任务ID");let s="";for(;"succeeded"!==s;){const t=await this.queryTask(e);if(s=t.data?.status||"","succeeded"===s)return t;if("failed"===s)return t;await new Promise(t=>setTimeout(t,2e3))}}then(t,e){this._execute().then(t,e)}cleanString(t){return t?(t=(t=(t=t.toString()).replace(/[\n\r\t]+/g,",")).replace(/\s{2,}/g,",")).trim():t}}function q(t){return{textToImage:()=>new S(t,"text2pic"),textToSpeech:()=>new S(t,"text2tts"),imageToText:()=>new k(t),chat:()=>new v(t),textToVideo:()=>new A(t,"video"),textToAudio:()=>new A(t,"audio")}}const $=new class{constructor(){this.plugins=new Map,this.pluginModules=new Map}register(t,e){if(this.plugins.has(t))console.warn(`Plugin ${t} is already registered`);else{if(!this.validatePlugin(e))throw console.log(`Invalid plugin module for ${t}:`,{type:typeof e,value:e,constructor:e?.constructor?.name,keys:"object"==typeof e?Object.keys(e):"N/A"}),new Error(`Invalid plugin module structure for ${t}`);this.plugins.set(t,{name:t,module:e,initialized:!1}),console.log(`Plugin ${t} registered successfully`)}}validatePlugin(t){return null!=t&&("function"==typeof t||"object"==typeof t&&!Array.isArray(t))}init(t,e){const s=this.plugins.get(t);if(!s)throw new Error(`Plugin ${t} not found`);let r;if("function"!=typeof s.module&&"object"!=typeof s.module)throw new Error(`Invalid plugin module type for ${t}`);return r=s.module,s.initialized=!0,"function"==typeof r.init&&r.init(),r}getRegisteredPlugins(){return Array.from(this.plugins.keys())}isRegistered(t){return this.plugins.has(t)}unregister(t){this.plugins.has(t)&&(this.plugins.delete(t),console.log(`Plugin ${t} unregistered`))}};exports.createClient=function(t){const e=new s(t),i={setToken:t=>e.setToken(t),auth:r(e),db:o(e),api:c(e),comparison:u(e),document:p(e),logistics:g(e),location:P(e),travel:x(e),notification:O(e),ai:q(e)};return $.getRegisteredPlugins().forEach(t=>{try{const s=$.init(t,e);i[t]?(console.warn(`Plugin "${t}" conflicts with built-in module. Merging plugin methods into existing module.`),Object.assign(i[t],s)):i[t]=s}catch(e){console.error(`Failed to load plugin ${t}:`,e)}}),i},exports.pluginLoader=$;
package/dist/index.esm.js CHANGED
@@ -1 +1 @@
1
- class t{constructor({baseUrl:t,apiKey:e}){this.baseUrl=t,this.apiKey=e,this.token=localStorage.getItem("baas_token")||null}setToken(t){this.token=t,t?localStorage.setItem("baas_token",t):localStorage.removeItem("baas_token")}async request(t,e={}){const s=`${this.baseUrl}${t}`,i={"Content-Type":"application/json",CODE_FLYING:`${this.apiKey}`,...this.token?{Authorization:`Bearer ${this.token}`}:{},...e.headers||{}};return(await fetch(s,{...e,headers:i})).json()}}function e(t){return{async login({user_name:e,phone:s,email:i,password:r}={}){const n=e||s||i;if(!n)throw new Error("必须提供 user_name、phone 或 email 之一");if(!r)throw new Error("必须提供 password");const a=await t.request("/login/passwd",{method:"POST",body:JSON.stringify({phone:n,password:r})});return a.success&&t.setToken(a.data),a},getUser:async()=>t.request("/getUserInfo",{method:"GET"}),register:async e=>await t.request("/login/register",{method:"POST",body:JSON.stringify(e)}),logout:async()=>(t.setToken(null),t.request("/logout",{method:"GET"}))}}class s{constructor(t,e){this.client=t,this.table=e,this._body=null,this._method=""}list(){return new i(this.client,this.table,"list")}page(){return new i(this.client,this.table,"page")}get(){return new i(this.client,this.table,"get")}insert(){return new r(this.client,this.table,"add")}update(){return new r(this.client,this.table,"update")}delete(){return new i(this.client,this.table,"delete")}}class i{constructor(t,e,s){this.client=t,this.table=e,this.method=s,this.filters={}}_addFilter(t,e,s){return this.filters.hasOwnProperty(t)||(this.filters[t]={}),this.filters[t][e]=s,this}eq(t,e){return this._addFilter(t,"eq",e)}neq(t,e){return this._addFilter(t,"neq",e)}gt(t,e){return this._addFilter(t,"gt",e)}gte(t,e){return this._addFilter(t,"gte",e)}lt(t,e){return this._addFilter(t,"lt",e)}lte(t,e){return this._addFilter(t,"lte",e)}in(t,e){return this._addFilter(t,"in",e)}between(t,e){return this._addFilter(t,"between",e)}or(t){this.filters.or||(this.filters.or=[]);const e=new i(this.client,this.table,"or");return t(e),this.filters.or.push(e.build()),this}limit(t){return this}page(t,e){return this.filters.current=t,this.filters.pageSize=e,this}order(t,e="asc"){this.filters.order_by||(this.filters.order_by=[]);let s="asc";return"string"==typeof e?s=e.toLowerCase():"object"==typeof e&&null!==e&&("ascending"in e?s=e.ascending?"asc":"desc":"direction"in e&&(s=e.direction.toLowerCase())),this.filters.order_by.push({field:t,direction:s}),this}build(){return this.filters}async _execute(){return await this.client.request(`/api/data/invoke?table=${this.table}&method=${this.method}`,{method:"POST",body:this.filters?JSON.stringify(this.filters):void 0})}then(t,e){this._execute().then(t,e)}}class r extends i{constructor(t,e,s){super(t,e,s),this.data={}}values(t){return this.data={...t},this}set(t){return this.data={...t},this}build(){return{...this.filters,...this.data}}async _execute(){return await this.client.request(`/api/data/invoke?table=${this.table}&method=${this.method}`,{method:"POST",body:JSON.stringify(this.build())})}then(t,e){this._execute().then(t,e)}}function n(t){return{from:e=>new s(t,e)}}class a{constructor(t,e){this.client=t,this.apiName=e,this._params={},this._headers={},this._method="POST"}param(t,e){return this._params[t]=e,this}params(t){return Object.assign(this._params,t),this}header(t,e){return this._headers[t]=e,this}headers(t){return Object.assign(this._headers,t),this}async _execute(){const t=JSON.stringify(this._params),e=`/api/${this.apiName}`;return await this.client.request(e,{method:this._method,headers:this._headers,body:t})}then(t,e){this._execute().then(t,e)}}function h(t){return{call:e=>new a(t,e)}}function o(s){const i=new t(s);return{setToken:t=>i.setToken(t),auth:e(i),db:n(i),api:h(i)}}export{o as createClient};
1
+ const t={getItem(t){try{return localStorage.getItem(t)}catch(t){return console.warn("No localStorage available"),null}},setItem(t,e){try{localStorage.setItem(t,e)}catch(t){console.warn("Cannot write to localStorage")}},removeItem(t){try{localStorage.removeItem(t)}catch(t){console.warn("Cannot remove from localStorage")}}},e=async(t,e)=>(await fetch(t,e)).json();class s{constructor({baseUrl:s,apiKey:r,storage:i,request:a}){this.baseUrl=s,this.apiKey=r,this.storage=i||t,this.requestImpl=a||e,this.token=this.storage.getItem("baas_token")||null}getApiKey(){return this.apiKey}setToken(t){this.token=t||null,t?this.storage.setItem("baas_token",t):this.storage.removeItem("baas_token")}async request(t,e={}){const s=`${this.baseUrl}${t}`,r={"Content-Type":"application/json",CODE_FLYING:`${this.apiKey}`,...this.token?{Authorization:`Bearer ${this.token}`}:{},...e.headers||{}},i=await this.requestImpl(s,{...e,headers:r});return console.log("request======",i),i}}function r(t){return{async login({user_name:e,phone:s,email:r,password:i}={}){const a=e||s||r;if(!a)throw new Error("必须提供 user_name、phone 或 email 之一");if(!i)throw new Error("必须提供 password");const n=await t.request("/login/passwd",{method:"POST",body:JSON.stringify({phone:a,password:i})});return n.success&&t.setToken(n.data),n},getUser:async()=>t.request("/getUserInfo",{method:"GET"}),register:async e=>await t.request("/login/register",{method:"POST",body:JSON.stringify(e)}),logout:async()=>(t.setToken(null),t.request("/logout",{method:"GET"}))}}class i{constructor(t,e){this.client=t,this.table=e,this._body=null,this._method=""}list(){return new a(this.client,this.table,"list")}page(){return new a(this.client,this.table,"page")}get(){return new a(this.client,this.table,"get")}insert(){return new n(this.client,this.table,"add")}update(){return new n(this.client,this.table,"update")}delete(){return new a(this.client,this.table,"delete")}}class a{constructor(t,e,s){this.client=t,this.table=e,this.method=s,this.filters={}}_addFilter(t,e,s){return this.filters.hasOwnProperty(t)||(this.filters[t]={}),this.filters[t][e]=s,this}eq(t,e){return this._addFilter(t,"eq",e)}neq(t,e){return this._addFilter(t,"neq",e)}gt(t,e){return this._addFilter(t,"gt",e)}gte(t,e){return this._addFilter(t,"gte",e)}lt(t,e){return this._addFilter(t,"lt",e)}lte(t,e){return this._addFilter(t,"lte",e)}like(t,e){return this._addFilter(t,"like",e)}in(t,e){return this._addFilter(t,"in",e)}between(t,e){return this._addFilter(t,"between",e)}or(t){this.filters.or||(this.filters.or=[]);const e=new a(this.client,this.table,"or");return t(e),this.filters.or.push(e.build()),this}limit(t){return this}page(t,e){return this.filters.current=t,this.filters.pageSize=e,this}order(t,e="asc"){this.filters.order_by||(this.filters.order_by=[]);let s="asc";return"string"==typeof e?s=e.toLowerCase():"object"==typeof e&&null!==e&&("ascending"in e?s=e.ascending?"asc":"desc":"direction"in e&&(s=e.direction.toLowerCase())),this.filters.order_by.push({field:t,direction:s}),this}build(){return this.filters}async _execute(){return await this.client.request(`/api/data/invoke?table=${this.table}&method=${this.method}`,{method:"POST",body:this.filters?JSON.stringify(this.filters):void 0})}then(t,e){this._execute().then(t,e)}}class n extends a{constructor(t,e,s){super(t,e,s),this.data={}}values(t){return this.data={...t},this}set(t){return this.data={...t},this}build(){return{...this.filters,...this.data}}async _execute(){return await this.client.request(`/api/data/invoke?table=${this.table}&method=${this.method}`,{method:"POST",body:JSON.stringify(this.build())})}then(t,e){this._execute().then(t,e)}}function o(t){return{from:e=>new i(t,e)}}class h{constructor(t,e){this.client=t,this.apiName=e,this._params={},this._headers={},this._method="POST"}param(t,e){return this._params[t]=e,this}params(t){return Object.assign(this._params,t),this}header(t,e){return this._headers[t]=e,this}headers(t){return Object.assign(this._headers,t),this}async _execute(){const t=JSON.stringify(this._params),e=`/api/${this.apiName}`;return await this.client.request(e,{method:this._method,headers:this._headers,body:t})}then(t,e){this._execute().then(t,e)}}function c(t){return{call:e=>new h(t,e)}}class l{static API_MAP={search:"/api/bijia_spu_search",compare:"/api/bijia_spu_goods_search"};constructor(t,e){this.client=t,this._params={},this.type=e}keyword(t){return this._params.query=t,this}setParams(t={}){return Object.assign(this._params,t),this}type(t){if(!l.API_MAP[t])throw new Error(`Unsupported comparison type: ${t}`);return this.type=t,this}async _execute(){const t=l.API_MAP[this.type];return await this.client.request(t,{method:"POST",body:JSON.stringify(this._params)})}then(t,e){this._execute().then(t,e)}}function u(t){return{searchProduct:()=>new l(t,"search"),findLowestPrice:()=>new l(t,"compare")}}class d{constructor(t){this.client=t,this._params={},this._taskId=null,this._pollingInterval=2e3,this._maxRetries=30}url(t){return this._params.url=t,this._params.format="pdf-to-image",this}format(t="pdf-to-image"){return this._params.format=t,this}pollingInterval(t){return this._pollingInterval=t,this}maxRetries(t){return this._maxRetries=t,this}async createTask(){if(!this._params.url)throw new Error("PDF文件URL不能为空");const t=await this.client.request("/api/pdf2image",{method:"POST",body:JSON.stringify({url:this._params.url,format:this._params.format})});return this._taskId=t.data,t}async queryTask(t=null){const e=t||this._taskId;if(!e)throw new Error("任务ID不能为空,请先创建任务");return await this.client.request("/api/queryPDF2ImageTask",{method:"POST",body:JSON.stringify({taskId:e})})}async convert(){try{console.log("开始创建PDF转图片任务...");const t=await this.createTask();console.log("任务创建成功:",t);const e=t.data;if(!e)throw new Error("任务创建失败,未返回任务ID");console.log("开始轮询查询任务状态...");let s=0;for(;s<this._maxRetries;){const t=await this.queryTask(e);console.log(`第${s+1}次查询结果:`,t);const r=t.data?.state;if(1===r)return console.log("PDF转图片任务完成:",t.data),t;if(r<0)return console.log("PDF转图片任务失败,状态码:",r),t;s++,s<this._maxRetries&&(console.log(`等待${this._pollingInterval}ms后进行第${s+1}次查询...`),await new Promise(t=>setTimeout(t,this._pollingInterval)))}throw new Error(`PDF转图片任务超时,已重试${this._maxRetries}次`)}catch(t){throw console.error("PDF转图片失败:",t),t}}then(t,e){return this.convert().then(t,e)}catch(t){return this.convert().catch(t)}}function p(t){return{convertPdf:()=>new d(t),async quickConvert(e={}){const s=new d(t);return e.url&&s.url(e.url),e.format&&s.format(e.format),e.pollingInterval&&s.pollingInterval(e.pollingInterval),e.maxRetries&&s.maxRetries(e.maxRetries),await s.convert()}}}class m{constructor(t){this.client=t,this._params={}}company(t){return this._params.com=t,this}trackingNumber(t){return this._params.num=t,this}phone(t){return this._params.phone=t,this}_validateParams(){if(!this._params.com)throw new Error("快递公司代码不能为空");if(!this._params.num)throw new Error("快递单号不能为空");if(("shunfeng"===this._params.com||"shunfengkuaiyun"===this._params.com)&&!this._params.phone)throw new Error("顺丰快递必须提供手机号参数")}async track(){return this._validateParams(),await this.client.request("/api/expressInquiry",{method:"POST",body:JSON.stringify({com:this._params.com,num:this._params.num,resultv2:4,...this._params.phone?{phone:this._params.phone}:{}})})}then(t,e){return this.track().then(t,e)}catch(t){return this.track().catch(t)}}function g(t){return{trackPackage:()=>new m(t)}}class _{static LOCATION_MAP={location:"/api/geocoder",address:"/api/geoaddress"};constructor(t,e){this.client=t,this._params={},this.type=e}latitude(t){return this._params.latitude=t,this}longitude(t){return this._params.longitude=t,this}address(t){return this._params.address=t,this}_validateLocationParams(){if(!this._params.latitude||!this._params.longitude)throw new Error("经纬度参数不能为空")}_validateAddressParams(){if(!this._params.address)throw new Error("地址参数不能为空")}_data(){return"location"===this.type?(this._validateLocationParams(),{location:`${this._params.latitude},${this._params.longitude}`}):(this._validateAddressParams(),{address:this._params.address})}async _execute(){const t=_.LOCATION_MAP[this.type],e=this._data();return await this.client.request(t,{method:"POST",body:JSON.stringify(e)})}then(t,e){this._execute().then(t,e)}}class y{constructor(t){this.client=t}async _execute(){const t=await this.client.request("/api/amap_ip_location",{method:"POST",body:JSON.stringify({})}),e=t?.data?.rectangle;if(!e)throw new Error("返回数据中缺少 rectangle 字段");const[s,r]=e.split(";"),[i,a]=s.split(",").map(Number),[n,o]=r.split(",").map(Number);return{success:!0,latitude:(a+o)/2,longitude:(i+n)/2,speed:0,altitude:0,horizontalAccuracy:1e3}}then(t,e){this._execute().then(t,e)}}class f{constructor(t){this.client=t,this._params={}}from(t,e){return this._params.from={lat:t,lng:e},this}to(t,e){return this._params.to={lat:t,lng:e},this}decodePolyline(t){for(let e=2;e<t.length;e++)t[e]=t[e-2]+t[e]/1e6;return t}async _execute(){const{from:t,to:e}=this._params;if(!t||!e)throw new Error("必须提供起点和终点坐标");const s={from:`${t.lat},${t.lng}`,to:`${e.lat},${e.lng}`},r=await this.client.request("/api/driving",{method:"POST",body:JSON.stringify(s)}),{routes:i}=r.data.result;return{success:!0,data:{paths:i.map(t=>{const e=this.decodePolyline([...t.polyline]),s=t.steps.map(t=>{const{polyline_idx:[s,r]}=t,i=[];for(let t=s;t<=r;t+=2)i.push({latitude:e[t],longitude:e[t+1]});return{...t,polylines:i}});return{distance:t.distance,duration:t.duration,steps:s}})}}}then(t,e){this._execute().then(t,e)}}class w{constructor(t){this.client=t,this._params={}}lat(t){return this._params.lat=t,this}lng(t){return this._params.lng=t,this}radius(t){return this._params.radius=t,this}keyword(t){return this._params.keyword=t,this}async _execute(){const{lat:t,lng:e,radius:s=1e3,keyword:r}=this._params;if(!t||!e)throw new Error("必须提供经纬度参数");const i={boundary:`nearby(${t},${e},${s})`,...r&&{keyword:r}},a=await this.client.request("/api/mapsearch",{method:"POST",body:JSON.stringify(i)}),{data:n}=a.data;return{success:!0,data:n.map(t=>({...t,latitude:t.location.lat,longitude:t.location.lng}))}}then(t,e){this._execute().then(t,e)}}function P(t){return{locationToAddress:()=>new _(t,"location"),addressToLocation:()=>new _(t,"address"),currentLocation:()=>new y(t),driving:()=>new f(t),nearby:()=>new w(t)}}class b{static API_MAP={train:"/api/queryTickets",flight:"/api/queryFlight"};constructor(t,e){this.client=t,this.params={},this.mode=e}from(t){return this.params.from=t,this}to(t){return this.params.to=t,this}date(t){return this.params.date=t,this}async _execute(){const t=b.API_MAP[this.mode];return await this.client.request(t,{method:"POST",body:JSON.stringify(this.params)})}then(t,e){this._execute().then(t,e)}}function x(t){return{train:()=>new b(t,"train"),flight:()=>new b(t,"flight")}}class I{static API_MAP={feishu:"/api/feishuRobotText",wechat:"/api/wechatRobotText"};constructor(t,e){this.client=t,this.params={},this.mode=e}content(t){return this.params.content=t?.replace(/\r?\n/g," "),this}async _execute(){const t=I.API_MAP[this.mode];return await this.client.request(t,{method:"POST",body:JSON.stringify(this.params)})}then(t,e){this._execute().then(t,e)}}class T{constructor(t){this.client=t,this.payload={}}title(t){return this.payload.title=t,this}content(t){return this.payload.content=t?.replace(/\r?\n/g," "),this}to(t){return this.payload.to=t,this}params(t={}){return this.payload.params=t,this}async _execute(){return await this.client.request("/common/mail/send",{method:"POST",body:JSON.stringify(this.payload)})}then(t,e){this._execute().then(t,e)}}function O(t){return{feishuRobot:()=>new I(t,"feishu"),wechatRobot:()=>new I(t,"wechat"),mail:()=>new T(t)}}class S{static API_MAP={text2pic:"/api/pic/word2pic",text2tts:"/api/text/tts"};constructor(t,e){this.client=t,this.params={},this.mode=e}text(t){return this.params.text=t,this}async _execute(){const t=S.API_MAP[this.mode];return await this.client.request(t,{method:"POST",body:JSON.stringify(this.params)})}then(t,e){this._execute().then(t,e)}}class v{constructor(t){this.client=t,this.params={}}text(t){return this.params.text=t,this}prompt(t){return this.params.prompt=t,this}conversationId(t){return this.params.conversationId=t,this}async _execute(){const{text:t,prompt:e="",conversationId:s=""}=this.params,r={prompt:e,query:t,conversation_id:s,user:this.client.getApiKey(),files:[]};return await this.client.request("/api/AiAnalysis",{method:"POST",body:JSON.stringify(r)})}then(t,e){this._execute().then(t,e)}}class k extends v{constructor(t){super(t)}url(t){return this.params.url=t,this}async _execute(){const{url:t,prompt:e,text:s,conversationId:r=""}=this.params,i=[{type:"image",transfer_method:"remote_url",url:t}],a={prompt:e,query:s,conversation_id:r,user:this.client.getApiKey(),files:t?i:[]};return await this.client.request("/api/AiAnalysis",{method:"POST",body:JSON.stringify(a)})}then(t,e){this._execute().then(t,e)}}class A{static CREATE_API_MAP={video:"/api/text2video",audio:"/api/text2music"};static QUERY_API_MAP={video:"/api/queryVideo",audio:"/api/queryMusic"};constructor(t,e){this.client=t,this.params={},this.mode=e,this._taskId=null}text(t){this.params.text=t}createTask(){const t=this.params.text;if(!t)throw new Error("文本内容不能为空");const e=A.CREATE_API_MAP[this.mode];let s={};s="video"===this.mode?{text:t}:{prompt:this.cleanString(t)};const r=this.client.request(e,{method:"POST",body:JSON.stringify(s)});return this._taskId=r.data,r}async queryTask(t=null){const e=t||this._taskId;if(!e)throw new Error("任务ID不能为空,请先创建任务");const s=A.QUERY_API_MAP[this.mode];let r={};return r="video"===this.mode?{id:e}:{item_ids:e},await this.client.request(s,{method:"POST",body:JSON.stringify(r)})}async _execute(){const t=await this.createTask();console.log("任务创建成功:",t);const e=t.data;if(!e)throw new Error("任务创建失败,未返回任务ID");let s="";for(;"succeeded"!==s;){const t=await this.queryTask(e);if(s=t.data?.status||"","succeeded"===s)return t;if("failed"===s)return t;await new Promise(t=>setTimeout(t,2e3))}}then(t,e){this._execute().then(t,e)}cleanString(t){return t?(t=(t=(t=t.toString()).replace(/[\n\r\t]+/g,",")).replace(/\s{2,}/g,",")).trim():t}}function q(t){return{textToImage:()=>new S(t,"text2pic"),textToSpeech:()=>new S(t,"text2tts"),imageToText:()=>new k(t),chat:()=>new v(t),textToVideo:()=>new A(t,"video"),textToAudio:()=>new A(t,"audio")}}const $=new class{constructor(){this.plugins=new Map,this.pluginModules=new Map}register(t,e){if(this.plugins.has(t))console.warn(`Plugin ${t} is already registered`);else{if(!this.validatePlugin(e))throw console.log(`Invalid plugin module for ${t}:`,{type:typeof e,value:e,constructor:e?.constructor?.name,keys:"object"==typeof e?Object.keys(e):"N/A"}),new Error(`Invalid plugin module structure for ${t}`);this.plugins.set(t,{name:t,module:e,initialized:!1}),console.log(`Plugin ${t} registered successfully`)}}validatePlugin(t){return null!=t&&("function"==typeof t||"object"==typeof t&&!Array.isArray(t))}init(t,e){const s=this.plugins.get(t);if(!s)throw new Error(`Plugin ${t} not found`);let r;if("function"!=typeof s.module&&"object"!=typeof s.module)throw new Error(`Invalid plugin module type for ${t}`);return r=s.module,s.initialized=!0,"function"==typeof r.init&&r.init(),r}getRegisteredPlugins(){return Array.from(this.plugins.keys())}isRegistered(t){return this.plugins.has(t)}unregister(t){this.plugins.has(t)&&(this.plugins.delete(t),console.log(`Plugin ${t} unregistered`))}};function E(t){const e=new s(t),i={setToken:t=>e.setToken(t),auth:r(e),db:o(e),api:c(e),comparison:u(e),document:p(e),logistics:g(e),location:P(e),travel:x(e),notification:O(e),ai:q(e)};return $.getRegisteredPlugins().forEach(t=>{try{const s=$.init(t,e);i[t]?(console.warn(`Plugin "${t}" conflicts with built-in module. Merging plugin methods into existing module.`),Object.assign(i[t],s)):i[t]=s}catch(e){console.error(`Failed to load plugin ${t}:`,e)}}),i}export{E as createClient,$ as pluginLoader};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aipexbase-js",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.esm.js",
@@ -9,17 +9,27 @@
9
9
  "dist"
10
10
  ],
11
11
  "scripts": {
12
- "test": "echo \"Error: no test specified\" && exit 1",
12
+ "test": "jest",
13
+ "test:watch": "jest --watch",
14
+ "test:coverage": "jest --coverage",
15
+ "test:mock": "jest --testPathIgnorePatterns=tests/real-api",
16
+ "test:real": "jest tests/real-api",
17
+ "test:real:watch": "jest tests/real-api --watch",
13
18
  "build": "rollup -c"
14
19
  },
15
20
  "keywords": [],
16
21
  "author": "",
17
22
  "license": "ISC",
18
23
  "devDependencies": {
24
+ "@babel/preset-env": "^7.23.0",
19
25
  "@rollup/plugin-babel": "^6.0.4",
20
26
  "@rollup/plugin-commonjs": "^28.0.6",
21
27
  "@rollup/plugin-node-resolve": "^16.0.1",
22
28
  "@rollup/plugin-terser": "^0.4.4",
29
+ "babel-jest": "^29.7.0",
30
+ "jest": "^29.7.0",
31
+ "jest-environment-jsdom": "^29.7.0",
32
+ "node-fetch": "^2.7.0",
23
33
  "rollup": "^4.52.2"
24
34
  }
25
35
  }