aipexbase-js 1.0.1 → 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 CHANGED
@@ -1,13 +1,41 @@
1
1
  # AipexBase JS SDK
2
2
 
3
- 一个简洁易用的 BaaS (Backend as a Service) JavaScript SDK,提供认证、数据库操作和自定义 API 调用功能。
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
+ - [开发指南](#开发指南)
4
25
 
5
26
  ## 特性
6
27
 
7
28
  - 🔐 **用户认证** - 登录、注册、登出和用户信息管理
8
29
  - 📊 **数据库操作** - 支持链式调用的 CRUD 操作
9
- - 🔌 **自定义 API** - 灵活的 API 调用接口
10
- - 🎯 **链式调用** - 优雅的 API 设计,支持流式编程
30
+ - 🤖 **AI 能力** - 文本对话、文生图、文生音频/视频等
31
+ - 📄 **文档处理** - PDF 转图片等功能
32
+ - 💰 **商品比价** - 商品搜索和最低价查询
33
+ - 📦 **物流查询** - 快递跟踪查询
34
+ - 📍 **地理服务** - 地址解析、路线规划、附近搜索
35
+ - 🚄 **出行服务** - 火车票和航班查询
36
+ - 📢 **消息通知** - 飞书机器人、企业微信、邮件发送
37
+ - 🔌 **插件系统** - 支持自定义插件扩展
38
+ - 🎯 **链式调用** - 优雅的 API 设计
11
39
  - 🔑 **自动 Token 管理** - 自动存储和管理用户认证 Token
12
40
  - 📦 **多格式支持** - 同时支持 CommonJS 和 ES Module
13
41
 
@@ -30,7 +58,27 @@ const client = createClient({
30
58
  });
31
59
  ```
32
60
 
33
- ## API 文档
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 文档
34
82
 
35
83
  ### 认证模块 (Auth)
36
84
 
@@ -65,8 +113,7 @@ const result = await client.auth.register({
65
113
  user_name: 'newuser',
66
114
  phone: '13800138000',
67
115
  email: 'user@example.com',
68
- password: 'your-password',
69
- // 其他自定义字段.这里与AipexBase管理后台是否开发登录有关联。
116
+ password: 'your-password'
70
117
  });
71
118
  ```
72
119
 
@@ -90,11 +137,9 @@ client.setToken('your-auth-token');
90
137
 
91
138
  ### 数据库模块 (DB)
92
139
 
93
- 数据库模块提供了丰富的链式查询接口。
140
+ #### 查询操作
94
141
 
95
- #### 查询数据
96
-
97
- ##### 列表查询
142
+ **列表查询**
98
143
 
99
144
  ```javascript
100
145
  // 简单查询
@@ -102,70 +147,50 @@ const result = await client.db
102
147
  .from('users')
103
148
  .list();
104
149
 
105
- // 带过滤条件
150
+ // 带多个过滤条件
106
151
  const result = await client.db
107
152
  .from('users')
108
153
  .list()
109
154
  .eq('status', 'active')
110
- .gt('age', 18);
111
-
112
- // 排序
113
- const result = await client.db
114
- .from('users')
115
- .list()
155
+ .gt('age', 18)
116
156
  .order('created_at', 'desc');
117
- ```
118
157
 
119
- ##### 分页查询
120
-
121
- ```javascript
158
+ // 分页查询
122
159
  const result = await client.db
123
160
  .from('users')
124
161
  .page()
125
162
  .page(1, 20) // 页码,每页数量
126
163
  .eq('status', 'active');
127
- ```
128
-
129
- ##### 获取单条数据
130
164
 
131
- ```javascript
165
+ // 获取单条数据
132
166
  const result = await client.db
133
167
  .from('users')
134
168
  .get()
135
169
  .eq('id', 123);
136
170
  ```
137
171
 
138
- #### 过滤条件
139
-
140
- 支持多种过滤操作符:
172
+ **过滤操作符**
141
173
 
142
174
  ```javascript
143
175
  // 等于
144
176
  .eq('field', value)
145
-
146
177
  // 不等于
147
178
  .neq('field', value)
148
-
149
179
  // 大于
150
180
  .gt('field', value)
151
-
152
181
  // 大于等于
153
182
  .gte('field', value)
154
-
155
183
  // 小于
156
184
  .lt('field', value)
157
-
158
185
  // 小于等于
159
186
  .lte('field', value)
160
-
161
187
  // 在范围内
162
188
  .in('field', [value1, value2, value3])
163
-
164
189
  // 在区间内
165
190
  .between('field', [min, max])
166
191
  ```
167
192
 
168
- #### OR 条件查询
193
+ **OR 条件查询**
169
194
 
170
195
  ```javascript
171
196
  const result = await client.db
@@ -178,7 +203,7 @@ const result = await client.db
178
203
  });
179
204
  ```
180
205
 
181
- #### 排序
206
+ **排序**
182
207
 
183
208
  ```javascript
184
209
  // 升序
@@ -230,47 +255,306 @@ const result = await client.db
230
255
 
231
256
  用于调用自定义 API 接口。
232
257
 
233
- #### 基本调用
234
-
235
258
  ```javascript
259
+ // 基本调用
236
260
  const result = await client.api
237
261
  .call('yourApiName')
238
262
  .param('key1', 'value1')
239
263
  .param('key2', 'value2');
240
- ```
241
264
 
242
- #### 批量设置参数
243
-
244
- ```javascript
265
+ // 批量设置参数
245
266
  const result = await client.api
246
267
  .call('yourApiName')
247
268
  .params({
248
269
  key1: 'value1',
249
- key2: 'value2',
250
- key3: 'value3'
270
+ key2: 'value2'
251
271
  });
252
- ```
253
-
254
- #### 自定义请求头
255
-
256
- ```javascript
257
- const result = await client.api
258
- .call('yourApiName')
259
- .header('X-Custom-Header', 'value')
260
- .params({ data: 'value' });
261
272
 
262
- // 批量设置请求头
273
+ // 自定义请求头
263
274
  const result = await client.api
264
275
  .call('yourApiName')
265
276
  .headers({
266
- 'X-Custom-Header-1': 'value1',
267
- 'X-Custom-Header-2': 'value2'
277
+ 'X-Custom-Header': 'value'
268
278
  })
269
279
  .params({ data: 'value' });
270
280
  ```
271
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
+
272
554
  ## 完整示例
273
555
 
556
+ ### 用户认证和数据处理流程
557
+
274
558
  ```javascript
275
559
  import { createClient } from 'aipexbase-js';
276
560
 
@@ -280,88 +564,222 @@ const client = createClient({
280
564
  apiKey: 'your-api-key'
281
565
  });
282
566
 
283
- // 用户登录
284
- async function login() {
567
+ async function main() {
285
568
  try {
286
- const result = await client.auth.login({
287
- phone: '13800138000',
288
- password: 'password123'
569
+ // 1. 用户注册
570
+ const registerResult = await client.auth.register({
571
+ user_name: 'john_doe',
572
+ email: 'john@example.com',
573
+ password: 'securePassword123'
289
574
  });
290
-
291
- if (result.success) {
292
- console.log('登录成功!');
293
- }
294
- } catch (error) {
295
- console.error('登录失败:', error);
296
- }
297
- }
575
+ console.log('注册成功:', registerResult);
298
576
 
299
- // 查询用户列表
300
- async function getUserList() {
301
- try {
302
- const result = await client.db
303
- .from('users')
304
- .page()
305
- .page(1, 20)
306
- .eq('status', 'active')
307
- .gte('age', 18)
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)
308
604
  .order('created_at', 'desc');
309
-
310
- console.log('用户列表:', result);
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
+
311
619
  } catch (error) {
312
- console.error('查询失败:', error);
620
+ console.error('操作失败:', error);
313
621
  }
314
622
  }
315
623
 
316
- // 创建新用户
317
- async function createUser() {
624
+ main();
625
+ ```
626
+
627
+ ### AI 功能集成示例
628
+
629
+ ```javascript
630
+ async function aiExample() {
318
631
  try {
319
- const result = await client.db
320
- .from('users')
321
- .insert()
322
- .values({
323
- name: 'John Doe',
324
- email: 'john@example.com',
325
- age: 25,
326
- status: 'active'
327
- });
328
-
329
- console.log('用户创建成功:', result);
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
+
330
654
  } catch (error) {
331
- console.error('创建失败:', error);
655
+ console.error('AI 功能失败:', error);
332
656
  }
333
657
  }
658
+ ```
659
+
660
+ ### 物流和位置服务示例
334
661
 
335
- // 调用自定义 API
336
- async function callCustomApi() {
662
+ ```javascript
663
+ async function logisticsAndLocation() {
337
664
  try {
338
- const result = await client.api
339
- .call('sendEmail')
340
- .params({
341
- to: 'user@example.com',
342
- subject: 'Hello',
343
- body: 'Welcome to our service!'
344
- });
345
-
346
- console.log('API 调用成功:', result);
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
+
347
690
  } catch (error) {
348
- console.error('API 调用失败:', error);
691
+ console.error('服务调用失败:', error);
349
692
  }
350
693
  }
351
694
  ```
352
695
 
353
- ## 开发
696
+ ## 进阶用法
354
697
 
355
- ### 本地开发
698
+ ### 自定义请求拦截器
356
699
 
357
- ```bash
358
- # 安装依赖
359
- npm install
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
+ }
360
718
 
361
- # 构建项目
362
- npm run build
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
+ }
363
779
  ```
364
780
 
781
+ ## 开发指南
782
+
365
783
  ### 项目结构
366
784
 
367
785
  ```
@@ -369,30 +787,82 @@ aipexbase-js/
369
787
  ├── src/
370
788
  │ ├── client.js # 核心客户端
371
789
  │ ├── index.js # 入口文件
372
- └── modules/
373
- ├── auth.js # 认证模块
374
- ├── db.js # 数据库模块
375
- ├── api.js # API 模块
376
- └── ai.js # AI 模块(开发中)
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
377
804
  ├── dist/ # 构建输出
378
805
  │ ├── index.cjs.js # CommonJS 格式
379
806
  │ └── index.esm.js # ES Module 格式
807
+ ├── tests/ # 测试文件
380
808
  ├── package.json
381
809
  ├── rollup.config.mjs
382
810
  └── README.md
383
811
  ```
384
812
 
385
- ## 技术栈
813
+ ### 本地开发
386
814
 
387
- - **构建工具**: Rollup
388
- - **模块格式**: CommonJS & ES Module
389
- - **代码压缩**: Terser
815
+ ```bash
816
+ # 安装依赖
817
+ npm install
390
818
 
391
- ## License
819
+ # 构建项目
820
+ npm run build
392
821
 
393
- ISC
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
+ ```
394
840
 
395
841
  ## 贡献
396
842
 
397
843
  欢迎提交 Issue 和 Pull Request!
398
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.1",
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
  }