@seaverse/data-sdk 0.2.1 → 0.2.3

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
@@ -5,9 +5,32 @@
5
5
 
6
6
  高性能数据服务 SDK,基于 PostgreSQL/AlloyDB + PostgREST + RLS 架构。
7
7
 
8
- ## 🚀 核心概念
8
+ ## 核心特性:零配置使用
9
9
 
10
- ### App ID 是什么?
10
+ **使用 `DataClient.create()` 无需传参!** SDK 会自动通过 PostMessage 协议从父页面获取 `appId` 和 `token`。
11
+
12
+ ```typescript
13
+ import { DataClient } from '@seaverse/data-sdk';
14
+
15
+ // 无需任何配置,自动获取!
16
+ const client = await DataClient.create();
17
+
18
+ // 直接使用
19
+ const notes = await client.query({ table_name: 'notes' });
20
+ const newNote = await client.create({
21
+ table_name: 'notes',
22
+ data_value: { title: 'My Note', content: '...' },
23
+ });
24
+ ```
25
+
26
+ **工作原理:**
27
+ - 📡 **自动初始化**:`DataClient.create()` 自动向父页面发送 `seaverse:get_token` 和 `seaverse:get_appId` 消息
28
+ - 🔄 **PostMessage 协议**:父页面响应消息,返回配置信息
29
+ - ⚡ **即时可用**:适用于 iframe 嵌入场景和 SeaVerse 平台应用
30
+
31
+ > 💡 **父页面需要监听并响应 PostMessage 请求**(详见 [PostMessage 协议集成](#postmessage-协议集成))
32
+
33
+ ## 🚀 App ID 是什么?
11
34
 
12
35
  **App ID** 是您在 SeaVerse 平台上创建的应用的唯一标识符。它用于:
13
36
  - ✅ 多租户数据隔离(每个应用的数据互不干扰)
@@ -31,9 +54,8 @@
31
54
  - ✅ 完整的错误处理
32
55
  - ✅ 支持过滤、排序、分页
33
56
  - ✅ 支持标签和 JSONB 字段查询
34
- - ✅ **无缝接入** - 自动从 PostMessage 获取配置
35
- - ✅ **零配置使用** - 可选的初始化,支持开箱即用
36
- - ✅ **函数式 API** - 提供便捷的函数调用方式
57
+ - ✅ **零配置使用** - 自动从 PostMessage 获取配置
58
+ - ✅ **类实例 API** - 清晰的面向对象设计
37
59
 
38
60
  ## 安装
39
61
 
@@ -43,106 +65,72 @@ npm install @seaverse/data-sdk
43
65
 
44
66
  ## 快速开始
45
67
 
46
- ### 两种使用方式
47
-
48
- #### 方式 A:函数式 API(推荐 - 零配置)
68
+ ### 方式 1:零配置使用(推荐)
49
69
 
50
- **适合 SeaVerse 平台应用** - SDK 自动从 PostMessage 获取配置,无需手动初始化
70
+ **最简单的方式 - 无需传参!** SDK 会自动通过 PostMessage 从父页面获取 `appId` 和 `token`。
51
71
 
52
72
  ```typescript
53
- import { query, create, update, deleteData } from '@seaverse/data-sdk';
73
+ import { DataClient } from '@seaverse/data-sdk';
54
74
 
55
- // 直接使用,无需初始化!
56
- // SDK 自动从 PostMessage 获取配置(需要父页面响应相应的消息)
75
+ // 无需传参,自动获取配置
76
+ const client = await DataClient.create();
57
77
 
58
78
  // 查询数据
59
- const notes = await query({
60
- table: 'notes',
79
+ const notes = await client.query({
80
+ table_name: 'notes',
61
81
  filters: { category: 'work' },
62
82
  order: { field: 'created_at', direction: 'desc' },
63
83
  });
64
84
 
65
85
  // 创建数据
66
- const newNote = await create({
67
- table: 'notes',
68
- data: { title: 'My Note', content: '...' },
86
+ const newNote = await client.create({
87
+ table_name: 'notes',
88
+ data_value: { title: 'My Note', content: '...' },
69
89
  visibility: 'private',
70
90
  });
71
91
 
72
92
  // 更新数据
73
- await update('note-id-123', {
74
- data: { title: 'Updated' },
93
+ const updated = await client.update('note-id-123', {
94
+ data_value: { title: 'Updated' },
75
95
  });
76
96
 
77
97
  // 删除数据
78
- await deleteData('note-id-123');
98
+ await client.delete('note-id-123');
79
99
  ```
80
100
 
81
- **可选初始化(如需自定义配置):**
82
-
83
- ```typescript
84
- import { initData, query } from '@seaverse/data-sdk';
101
+ > 📡 **自动配置获取**:`DataClient.create()` 会自动向父页面发送 PostMessage 请求获取配置
102
+ > 🎯 **适用场景**:iframe 嵌入应用、SeaVerse 平台应用
103
+ > ⚠️ **前置条件**:父页面需要监听并响应 PostMessage 请求(详见 [PostMessage 协议集成](#postmessage-协议集成))
85
104
 
86
- // 方式1: 完全自动获取(零配置)
87
- await initData();
88
- // appId 和 token 都会自动获取
105
+ ### 方式 2:显式传参
89
106
 
90
- // 方式2: 只提供 appId
91
- await initData({
92
- appId: 'my-app-123', // 显式提供
93
- // token 会自动获取
94
- });
95
-
96
- // 方式3: 完全显式提供
97
- await initData({
98
- appId: 'my-app-123',
99
- token: 'user-jwt-token',
100
- debug: true,
101
- });
102
-
103
- // 然后直接使用
104
- const notes = await query({ table: 'notes' });
105
- ```
106
-
107
- #### 方式 B:类实例 API(传统方式)
108
-
109
- **适合需要多个实例或完全自定义配置的场景**
107
+ **适合非 iframe 环境或需要自定义配置的场景**
110
108
 
111
109
  ```typescript
112
110
  import { DataClient } from '@seaverse/data-sdk';
113
111
 
114
- // 方式1: 使用静态工厂方法(支持自动获取配置)
115
- const client = await DataClient.create();
116
- // appId 和 token 都会自动获取
117
-
118
- // 方式2: 部分配置 + 自动获取
112
+ // 方式 2.1: 显式提供所有配置
119
113
  const client = await DataClient.create({
120
- appId: 'my-app-123', // 显式提供 appId
121
- // token 会自动获取
122
- });
123
-
124
- // 方式3: 显式提供所有配置(传统方式)
125
- const client = new DataClient({
126
114
  appId: 'my-app-123',
127
115
  token: 'user-jwt-token',
128
116
  });
129
117
 
130
- // 方式4: 指定环境
131
- const client = new DataClient({
118
+ // 方式 2.2: 指定环境
119
+ const client = await DataClient.create({
132
120
  appId: 'my-app-123',
133
121
  token: 'user-jwt-token',
134
122
  environment: 'production', // 'production' | 'staging' | 'development' | 'local'
135
123
  });
136
124
 
137
- // 方式5: 完全自定义
138
- const client = new DataClient({
125
+ // 方式 2.3: 自定义 API 地址
126
+ const client = await DataClient.create({
139
127
  appId: 'my-app-123',
140
128
  token: 'user-jwt-token',
141
129
  baseURL: 'https://custom-api.example.com',
142
130
  });
143
131
 
144
132
  // 使用 client 实例
145
- const notes = await client.query({ table: 'notes' });
133
+ const notes = await client.query({ table_name: 'notes' });
146
134
  ```
147
135
 
148
136
  **配置选项说明:**
@@ -163,36 +151,50 @@ const notes = await client.query({ table: 'notes' });
163
151
  > ```
164
152
  > 如果启用 `debug: true`,还会打印完整的 token 和详细的配置信息(⚠️ 注意:生产环境建议关闭 debug 模式)。
165
153
 
166
- ### 配置自动获取规则
154
+ ## 📡 配置自动获取规则
155
+
156
+ ### 核心机制
157
+
158
+ **SDK 采用 PostMessage 协议自动获取配置**,首次调用任何 API 时会自动触发:
159
+
160
+ 1. **发送请求**:SDK 向父页面发送 `seaverse:get_token` 和 `seaverse:get_appId` 消息
161
+ 2. **父页面响应**:父页面监听消息并返回配置信息
162
+ 3. **完成初始化**:SDK 接收配置后立即可用
163
+
164
+ ### 获取优先级
167
165
 
168
- **Token 自动获取:**
169
- SDK 会按照以下优先级自动获取 token:
166
+ **Token 获取优先级:**
170
167
  1. 显式传入的 `token` 参数(最高优先级)
171
168
  2. PostMessage 从父窗口获取(使用 `seaverse:get_token` 协议)
172
169
 
173
- **AppId 自动获取:**
174
- SDK 会按照以下优先级自动获取 appId:
170
+ **AppId 获取优先级:**
175
171
  1. 显式传入的 `appId` 参数(最高优先级)
176
172
  2. PostMessage 从父窗口获取(使用 `seaverse:get_appId` 协议)
177
173
 
178
- > 💡 **最佳实践**:
179
- > - data-sdk 通过 PostMessage 协议与父页面通信获取配置
180
- > - 父页面需要监听并响应 `seaverse:get_token` `seaverse:get_appId` 消息
181
- > - 适用于 iframe 嵌入场景,实现安全的跨域配置传递
174
+ ### PostMessage 协议说明
175
+
176
+ | 协议 | 请求 type | 响应 type | 响应 payload |
177
+ |------|----------|----------|-------------|
178
+ | Token | `seaverse:get_token` | `seaverse:token` | `{ accessToken: string, expiresIn: number }` |
179
+ | AppId | `seaverse:get_appId` | `seaverse:appId` | `{ appId: string }` |
180
+ | 错误 | - | `seaverse:error` | `{ error: string }` |
181
+
182
+ > ⚠️ **重要提示**:
183
+ > - 父页面**必须**监听并响应上述 PostMessage 消息,否则 SDK 无法自动获取配置
184
+ > - 如果父页面未响应,需要显式传入 `appId` 和 `token` 参数
185
+ > - 详细的父页面集成代码请参见 [PostMessage 协议集成](#postmessage-协议集成)
182
186
 
183
187
  ## API 文档
184
188
 
185
- ### 初始化和配置 API
189
+ ### 初始化
186
190
 
187
191
  | 方法 | 说明 | 参数 | 返回值 |
188
192
  |------|------|------|--------|
189
- | `initData(options?)` | 初始化 SDK(可选) | `Partial<DataClientOptions>` | `Promise<void>` |
190
- | `updateToken(token)` | 更新全局 token | `token: string` | `void` |
191
- | `updateAppId(appId)` | 更新全局 appId | `appId: string` | `void` |
192
- | `getCurrentAppId()` | 获取当前 appId | - | `string \| undefined` |
193
- | `clearConfig()` | 清除全局配置 | - | `void` |
193
+ | `DataClient.create(options?)` | 创建客户端实例(支持零配置) | `DataClientOptions?` | `Promise<DataClient>` |
194
+
195
+ ### 数据操作方法
194
196
 
195
- ### 数据操作 API(函数式)
197
+ 使用 `await DataClient.create()` 创建实例后可用的方法:
196
198
 
197
199
  | 方法 | 说明 | 参数 | 返回值 |
198
200
  |------|------|------|--------|
@@ -200,29 +202,16 @@ SDK 会按照以下优先级自动获取 appId:
200
202
  | `get(id)` | 获取单条数据 | `id: string` | `Promise<DataRecord \| null>` |
201
203
  | `create(options)` | 创建数据 | `CreateDataOptions` | `Promise<DataRecord>` |
202
204
  | `update(id, options)` | 更新数据 | `id: string`, `UpdateDataOptions` | `Promise<DataRecord>` |
203
- | `deleteData(id)` | 删除数据 | `id: string` | `Promise<void>` |
205
+ | `delete(id)` | 删除数据 | `id: string` | `Promise<void>` |
204
206
  | `batchDelete(ids)` | 批量删除 | `ids: string[]` | `Promise<void>` |
205
207
  | `queryWithPagination(options)` | 查询带分页信息 | `QueryOptions` | `Promise<PaginatedResponse<DataRecord>>` |
206
208
  | `isAdmin()` | 检查管理员权限 | - | `Promise<boolean>` |
207
209
 
208
- ### DataClient 类方法
209
-
210
- 使用 `new DataClient(options)` 创建实例后可用的方法:
210
+ ### 配置查询方法
211
211
 
212
212
  | 方法 | 说明 | 参数 | 返回值 |
213
213
  |------|------|------|--------|
214
- | `query(options)` | 查询数据列表 | `QueryOptions` | `Promise<DataRecord[]>` |
215
- | `get(id)` | 获取单条数据 | `id: string` | `Promise<DataRecord \| null>` |
216
- | `create(options)` | 创建数据 | `CreateDataOptions` | `Promise<DataRecord>` |
217
- | `update(id, options)` | 更新数据 | `id: string`, `UpdateDataOptions` | `Promise<DataRecord>` |
218
- | `delete(id)` | 删除数据 | `id: string` | `Promise<void>` |
219
- | `batchDelete(ids)` | 批量删除 | `ids: string[]` | `Promise<void>` |
220
- | `queryWithPagination(options)` | 查询带分页信息 | `QueryOptions` | `Promise<PaginatedResponse<DataRecord>>` |
221
- | `isAdmin()` | 检查管理员权限 | - | `Promise<boolean>` |
222
- | `updateToken(token)` | 更新实例 token | `token: string` | `void` |
223
- | `updateAppId(appId)` | 更新实例 appId | `appId: string` | `void` |
224
- | `getAppId()` | 获取实例 appId | - | `string` |
225
- | `getUserId()` | 获取当前用户 ID | - | `string` |
214
+ | `getConfig()` | 获取当前 SDK 配置 | - | `{ appId: string; token: string; url: string }` |
226
215
 
227
216
  ### 查询选项(QueryOptions)
228
217
 
@@ -297,8 +286,8 @@ interface DataRecord {
297
286
  ```typescript
298
287
  // 创建笔记
299
288
  const note = await client.create({
300
- table: 'notes',
301
- data: { // ← 这个对象会存储到 data_value 字段
289
+ table_name: 'notes',
290
+ data_value: { // ← 这个对象会存储到 data_value 字段
302
291
  title: '我的笔记',
303
292
  content: '笔记内容...',
304
293
  author: 'Alice',
@@ -322,8 +311,8 @@ console.log(note.data_value.metadata); // { wordCount: 1000, tags: ['work'] }
322
311
  // JWT token: { "sub": "user-123", ... }
323
312
 
324
313
  const note = await client.create({
325
- table: 'notes',
326
- data: { title: 'Test' }
314
+ table_name: 'notes',
315
+ data_value: { title: 'Test' }
327
316
  // owner_user_id 自动设置为 "user-123",无需手动指定
328
317
  });
329
318
 
@@ -343,15 +332,15 @@ const note = await client.create({
343
332
  ```typescript
344
333
  // 私密数据(默认)
345
334
  const privateNote = await client.create({
346
- table: 'notes',
347
- data: { title: '私密日记' },
335
+ table_name: 'notes',
336
+ data_value: { title: '私密日记' },
348
337
  visibility: 'private' // 只有你自己和管理员可见
349
338
  });
350
339
 
351
340
  // 公开数据
352
341
  const publicPost = await client.create({
353
- table: 'posts',
354
- data: { title: '技术分享' },
342
+ table_name: 'posts',
343
+ data_value: { title: '技术分享' },
355
344
  visibility: 'public' // 所有人可以读取
356
345
  });
357
346
  ```
@@ -409,7 +398,7 @@ try {
409
398
  ```typescript
410
399
  try {
411
400
  const updated = await client.update('note-id-123', {
412
- data: { title: 'Updated Title' },
401
+ data_value: { title: 'Updated Title' },
413
402
  });
414
403
  console.log('更新成功:', updated);
415
404
  } catch (error) {
@@ -433,17 +422,17 @@ try {
433
422
  ```typescript
434
423
  try {
435
424
  // 查询操作
436
- const notes = await client.query({ table: 'notes' });
425
+ const notes = await client.query({ table_name: 'notes' });
437
426
 
438
427
  // 创建操作
439
428
  const newNote = await client.create({
440
- table: 'notes',
441
- data: { title: 'Test' }
429
+ table_name: 'notes',
430
+ data_value: { title: 'Test' }
442
431
  });
443
432
 
444
433
  // 分页查询
445
434
  const paginatedResult = await client.queryWithPagination({
446
- table: 'posts',
435
+ table_name: 'posts',
447
436
  pagination: { limit: 10, offset: 0 }
448
437
  });
449
438
  } catch (error) {
@@ -476,32 +465,34 @@ import { initData, query } from '@seaverse/data-sdk';
476
465
  await initData();
477
466
 
478
467
  // 使用 data-sdk
479
- const notes = await query({ table: 'notes' });
468
+ const notes = await query({ table_name: 'notes' });
480
469
  ```
481
470
 
482
471
  **Token 获取优先级:**
483
472
  1. 显式传入的 `token` 参数(最高优先级)
484
473
  2. PostMessage 从父窗口获取(使用 `seaverse:get_token` 协议)
485
474
 
486
- ### 无缝接入场景
475
+ ### 使用场景示例
487
476
 
488
477
  #### React 应用中使用
489
478
 
490
479
  ```typescript
491
- import { initData, query, create, updateToken } from '@seaverse/data-sdk';
492
- import { useEffect } from 'react';
480
+ import { DataClient } from '@seaverse/data-sdk';
481
+ import { useEffect, useState } from 'react';
493
482
 
494
483
  function App() {
484
+ const [client, setClient] = useState<DataClient | null>(null);
485
+
495
486
  useEffect(() => {
496
- // 可选:应用启动时初始化
497
- // SDK 会自动通过 PostMessage 从父页面获取配置
498
- initData({ debug: true });
487
+ // 应用启动时初始化 SDK
488
+ DataClient.create({ debug: true }).then(setClient);
499
489
  }, []);
500
490
 
501
491
  const loadNotes = async () => {
502
- // 直接使用,无需传递 client 实例
503
- const notes = await query({
504
- table: 'notes',
492
+ if (!client) return [];
493
+
494
+ const notes = await client.query({
495
+ table_name: 'notes',
505
496
  order: { field: 'created_at', direction: 'desc' },
506
497
  });
507
498
  return notes;
@@ -564,10 +555,11 @@ window.addEventListener('message', (event) => {
564
555
  **iframe 页面(自动获取):**
565
556
 
566
557
  ```typescript
567
- import { query } from '@seaverse/data-sdk';
558
+ import { DataClient } from '@seaverse/data-sdk';
568
559
 
569
- // 直接使用,SDK 会自动通过 PostMessage 从父页面获取 appId 和 token
570
- const notes = await query({ table: 'notes' });
560
+ // 无需传参,SDK 会自动通过 PostMessage 从父页面获取配置
561
+ const client = await DataClient.create();
562
+ const notes = await client.query({ table_name: 'notes' });
571
563
  ```
572
564
 
573
565
  **PostMessage 协议说明:**
@@ -581,17 +573,17 @@ const notes = await query({ table: 'notes' });
581
573
  #### 服务端渲染(SSR/SSG)
582
574
 
583
575
  ```typescript
584
- import { query, initData } from '@seaverse/data-sdk';
576
+ import { DataClient } from '@seaverse/data-sdk';
585
577
 
586
578
  export async function getServerSideProps() {
587
579
  // 服务端需要显式提供配置
588
- await initData({
580
+ const client = await DataClient.create({
589
581
  appId: process.env.APP_ID,
590
582
  token: process.env.API_SERVICE_TOKEN,
591
583
  });
592
584
 
593
- const notes = await query({
594
- table: 'notes',
585
+ const notes = await client.query({
586
+ table_name: 'notes',
595
587
  filters: { visibility: 'public' },
596
588
  });
597
589
 
@@ -599,37 +591,18 @@ export async function getServerSideProps() {
599
591
  }
600
592
  ```
601
593
 
602
- ### 动态更新 Token
594
+ ### 获取当前配置
603
595
 
604
596
  ```typescript
605
- import { updateToken } from '@seaverse/data-sdk';
606
-
607
- // JWT 过期后更新 token(函数式 API)
608
- updateToken('new-jwt-token');
609
-
610
- // 或使用类实例
611
- client.updateToken('new-jwt-token');
612
- ```
613
-
614
- ### 切换应用
615
-
616
- ```typescript
617
- import { updateAppId } from '@seaverse/data-sdk';
618
-
619
- // 切换到其他应用(函数式 API)
620
- updateAppId('another-app-id');
621
-
622
- // 或使用类实例
623
- client.updateAppId('another-app-id');
624
- ```
625
-
626
- ### 清除配置(登出场景)
597
+ import { DataClient } from '@seaverse/data-sdk';
627
598
 
628
- ```typescript
629
- import { clearConfig } from '@seaverse/data-sdk';
599
+ const client = await DataClient.create();
630
600
 
631
- // 用户登出时清除所有配置
632
- clearConfig();
601
+ // 获取当前 SDK 配置
602
+ const config = client.getConfig();
603
+ console.log('App ID:', config.appId);
604
+ console.log('Token:', config.token);
605
+ console.log('API URL:', config.url);
633
606
  ```
634
607
 
635
608
  ### JSONB 字段查询
@@ -637,9 +610,9 @@ clearConfig();
637
610
  ```typescript
638
611
  // 查询 data_value 中的字段
639
612
  const results = await client.query({
640
- table: 'posts',
613
+ table_name: 'posts',
641
614
  filters: {
642
- data: {
615
+ data_value: {
643
616
  title: 'Hello World', // data_value->>'title' = 'Hello World'
644
617
  author: 'Alice', // data_value->>'author' = 'Alice'
645
618
  },
@@ -652,7 +625,7 @@ const results = await client.query({
652
625
  ```typescript
653
626
  // 查询包含指定标签的数据
654
627
  const results = await client.query({
655
- table: 'posts',
628
+ table_name: 'posts',
656
629
  filters: {
657
630
  tags: ['javascript', 'typescript'], // 包含任一标签
658
631
  },
@@ -664,7 +637,7 @@ const results = await client.query({
664
637
  ```typescript
665
638
  // 查询指定时间范围的数据
666
639
  const results = await client.query({
667
- table: 'logs',
640
+ table_name: 'logs',
668
641
  filters: {
669
642
  created_after: '2026-01-01T00:00:00Z',
670
643
  created_before: '2026-01-31T23:59:59Z',
@@ -677,7 +650,7 @@ const results = await client.query({
677
650
  ```typescript
678
651
  // 查询带总数的分页数据
679
652
  const result = await client.queryWithPagination({
680
- table: 'posts',
653
+ table_name: 'posts',
681
654
  pagination: { limit: 10, offset: 0 },
682
655
  });
683
656