@seaverse/data-sdk 0.2.4 → 0.2.6

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,32 +5,9 @@
5
5
 
6
6
  高性能数据服务 SDK,基于 PostgreSQL/AlloyDB + PostgREST + RLS 架构。
7
7
 
8
- ## 核心特性:零配置使用
8
+ ## 🚀 核心概念
9
9
 
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 是什么?
10
+ ### App ID 是什么?
34
11
 
35
12
  **App ID** 是您在 SeaVerse 平台上创建的应用的唯一标识符。它用于:
36
13
  - ✅ 多租户数据隔离(每个应用的数据互不干扰)
@@ -55,7 +32,6 @@ const newNote = await client.create({
55
32
  - ✅ 支持过滤、排序、分页
56
33
  - ✅ 支持标签和 JSONB 字段查询
57
34
  - ✅ **零配置使用** - 自动从 PostMessage 获取配置
58
- - ✅ **类实例 API** - 清晰的面向对象设计
59
35
 
60
36
  ## 安装
61
37
 
@@ -65,17 +41,26 @@ npm install @seaverse/data-sdk
65
41
 
66
42
  ## 快速开始
67
43
 
68
- ### 方式 1:零配置使用(推荐)
69
-
70
- **最简单的方式 - 无需传参!** SDK 会自动通过 PostMessage 从父页面获取 `appId` 和 `token`。
44
+ ### 使用 DataClient
71
45
 
72
46
  ```typescript
73
47
  import { DataClient } from '@seaverse/data-sdk';
74
48
 
75
- // 无需传参,自动获取配置
49
+ // 方式1: 零配置(推荐)- 自动从 PostMessage 获取 appId 和 token
76
50
  const client = await DataClient.create();
77
51
 
78
- // 查询数据
52
+ // 方式2: 只提供 appId,token 自动获取
53
+ const client = await DataClient.create({
54
+ appId: 'my-app-123',
55
+ });
56
+
57
+ // 方式3: 显式提供所有配置
58
+ const client = new DataClient({
59
+ appId: 'my-app-123',
60
+ token: 'user-jwt-token',
61
+ });
62
+
63
+ // 使用 client 实例
79
64
  const notes = await client.query({
80
65
  table_name: 'notes',
81
66
  filters: { category: 'work' },
@@ -90,7 +75,7 @@ const newNote = await client.create({
90
75
  });
91
76
 
92
77
  // 更新数据
93
- const updated = await client.update('note-id-123', {
78
+ await client.update('note-id-123', {
94
79
  data_value: { title: 'Updated' },
95
80
  });
96
81
 
@@ -98,41 +83,6 @@ const updated = await client.update('note-id-123', {
98
83
  await client.delete('note-id-123');
99
84
  ```
100
85
 
101
- > 📡 **自动配置获取**:`DataClient.create()` 会自动向父页面发送 PostMessage 请求获取配置
102
- > 🎯 **适用场景**:iframe 嵌入应用、SeaVerse 平台应用
103
- > ⚠️ **前置条件**:父页面需要监听并响应 PostMessage 请求(详见 [PostMessage 协议集成](#postmessage-协议集成))
104
-
105
- ### 方式 2:显式传参
106
-
107
- **适合非 iframe 环境或需要自定义配置的场景**
108
-
109
- ```typescript
110
- import { DataClient } from '@seaverse/data-sdk';
111
-
112
- // 方式 2.1: 显式提供所有配置
113
- const client = await DataClient.create({
114
- appId: 'my-app-123',
115
- token: 'user-jwt-token',
116
- });
117
-
118
- // 方式 2.2: 指定环境
119
- const client = await DataClient.create({
120
- appId: 'my-app-123',
121
- token: 'user-jwt-token',
122
- environment: 'production', // 'production' | 'staging' | 'development' | 'local'
123
- });
124
-
125
- // 方式 2.3: 自定义 API 地址
126
- const client = await DataClient.create({
127
- appId: 'my-app-123',
128
- token: 'user-jwt-token',
129
- baseURL: 'https://custom-api.example.com',
130
- });
131
-
132
- // 使用 client 实例
133
- const notes = await client.query({ table_name: 'notes' });
134
- ```
135
-
136
86
  **配置选项说明:**
137
87
 
138
88
  | 参数 | 类型 | 必需 | 说明 |
@@ -151,50 +101,26 @@ const notes = await client.query({ table_name: 'notes' });
151
101
  > ```
152
102
  > 如果启用 `debug: true`,还会打印完整的 token 和详细的配置信息(⚠️ 注意:生产环境建议关闭 debug 模式)。
153
103
 
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
- ### 获取优先级
104
+ ### 配置自动获取
165
105
 
166
- **Token 获取优先级:**
167
- 1. 显式传入的 `token` 参数(最高优先级)
168
- 2. PostMessage 从父窗口获取(使用 `seaverse:get_token` 协议)
106
+ SDK 支持零配置使用,会自动从以下来源获取配置:
169
107
 
170
- **AppId 获取优先级:**
171
- 1. 显式传入的 `appId` 参数(最高优先级)
172
- 2. PostMessage 从父窗口获取(使用 `seaverse:get_appId` 协议)
173
-
174
- ### PostMessage 协议说明
108
+ - **Token & AppId**: 通过 PostMessage 从父窗口获取,或显式传入
109
+ - **BaseURL**: 自动检测运行环境,或通过 `environment` 参数指定
110
+ - **环境变量**: Node.js 环境支持 `DATA_SDK_BASE_URL` 覆盖默认配置
175
111
 
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 }` |
112
+ **支持的环境类型:**
113
+ ```typescript
114
+ environment?: 'production' | 'staging' | 'development' | 'local'
115
+ ```
181
116
 
182
- > ⚠️ **重要提示**:
183
- > - 父页面**必须**监听并响应上述 PostMessage 消息,否则 SDK 无法自动获取配置
184
- > - 如果父页面未响应,需要显式传入 `appId` 和 `token` 参数
185
- > - 详细的父页面集成代码请参见 [PostMessage 协议集成](#postmessage-协议集成)
117
+ > 💡 **iframe 集成提示**:在 iframe 中使用时,SDK 会通过 PostMessage 与父页面通信获取配置(token、appId、环境标识),无需手动传递。
186
118
 
187
119
  ## API 文档
188
120
 
189
- ### 初始化
190
-
191
- | 方法 | 说明 | 参数 | 返回值 |
192
- |------|------|------|--------|
193
- | `DataClient.create(options?)` | 创建客户端实例(支持零配置) | `DataClientOptions?` | `Promise<DataClient>` |
194
-
195
- ### 数据操作方法
121
+ ### DataClient 方法
196
122
 
197
- 使用 `await DataClient.create()` 创建实例后可用的方法:
123
+ 使用 `DataClient.create()` 或 `new DataClient(options)` 创建实例后可用的方法:
198
124
 
199
125
  | 方法 | 说明 | 参数 | 返回值 |
200
126
  |------|------|------|--------|
@@ -206,19 +132,17 @@ const notes = await client.query({ table_name: 'notes' });
206
132
  | `batchDelete(ids)` | 批量删除 | `ids: string[]` | `Promise<void>` |
207
133
  | `queryWithPagination(options)` | 查询带分页信息 | `QueryOptions` | `Promise<PaginatedResponse<DataRecord>>` |
208
134
  | `isAdmin()` | 检查管理员权限 | - | `Promise<boolean>` |
209
-
210
- ### 配置查询方法
211
-
212
- | 方法 | 说明 | 参数 | 返回值 |
213
- |------|------|------|--------|
214
- | `getConfig()` | 获取当前 SDK 配置 | - | `{ appId: string; token: string; url: string }` |
135
+ | `updateToken(token)` | 更新实例 token | `token: string` | `void` |
136
+ | `updateAppId(appId)` | 更新实例 appId | `appId: string` | `void` |
137
+ | `getAppId()` | 获取实例 appId | - | `string` |
138
+ | `getUserId()` | 获取当前用户 ID | - | `string` |
215
139
 
216
140
  ### 查询选项(QueryOptions)
217
141
 
218
142
  ```typescript
219
143
  interface QueryOptions {
220
144
  // 表名(必填)
221
- table: string;
145
+ table_name: string;
222
146
 
223
147
  // 过滤条件
224
148
  filters?: {
@@ -226,7 +150,7 @@ interface QueryOptions {
226
150
  category?: string; // 分类
227
151
  visibility?: 'public' | 'private'; // 可见性
228
152
  tags?: string[]; // 标签
229
- data?: Record<string, any>; // data_value 字段过滤
153
+ data_value?: Record<string, any>; // data_value 字段过滤
230
154
  created_after?: string; // 创建时间(之后)
231
155
  created_before?: string; // 创建时间(之前)
232
156
  };
@@ -291,7 +215,7 @@ const note = await client.create({
291
215
  title: '我的笔记',
292
216
  content: '笔记内容...',
293
217
  author: 'Alice',
294
- metadata: {
218
+ metadata_value: {
295
219
  wordCount: 1000,
296
220
  tags: ['work']
297
221
  }
@@ -454,25 +378,25 @@ try {
454
378
  data-sdk 通过 PostMessage 协议与父页面通信获取配置:
455
379
 
456
380
  ```typescript
457
- import { initData, query } from '@seaverse/data-sdk';
381
+ import { DataClient } from '@seaverse/data-sdk';
458
382
 
459
383
  // SDK 会自动通过 PostMessage 从父页面获取 appId 和 token
460
384
  // 父页面需要响应以下消息:
461
385
  // - seaverse:get_token → 返回 token
462
386
  // - seaverse:get_appId → 返回 appId
463
387
 
464
- // 初始化(会自动通过 PostMessage 获取配置)
465
- await initData();
388
+ // 零配置初始化(会自动通过 PostMessage 获取配置)
389
+ const client = await DataClient.create();
466
390
 
467
391
  // 使用 data-sdk
468
- const notes = await query({ table_name: 'notes' });
392
+ const notes = await client.query({ table_name: 'notes' });
469
393
  ```
470
394
 
471
- **Token 获取优先级:**
472
- 1. 显式传入的 `token` 参数(最高优先级)
473
- 2. PostMessage 从父窗口获取(使用 `seaverse:get_token` 协议)
395
+ **配置获取优先级:**
396
+ 1. 显式传入的参数(最高优先级)
397
+ 2. PostMessage 从父窗口获取(使用 `seaverse:get_token` 和 `seaverse:get_appId` 协议)
474
398
 
475
- ### 使用场景示例
399
+ ### 无缝接入场景
476
400
 
477
401
  #### React 应用中使用
478
402
 
@@ -484,7 +408,8 @@ function App() {
484
408
  const [client, setClient] = useState<DataClient | null>(null);
485
409
 
486
410
  useEffect(() => {
487
- // 应用启动时初始化 SDK
411
+ // 应用启动时初始化客户端
412
+ // SDK 会自动通过 PostMessage 从父页面获取配置
488
413
  DataClient.create({ debug: true }).then(setClient);
489
414
  }, []);
490
415
 
@@ -557,7 +482,7 @@ window.addEventListener('message', (event) => {
557
482
  ```typescript
558
483
  import { DataClient } from '@seaverse/data-sdk';
559
484
 
560
- // 无需传参,SDK 会自动通过 PostMessage 从父页面获取配置
485
+ // 零配置创建客户端,SDK 会自动通过 PostMessage 从父页面获取 appId 和 token
561
486
  const client = await DataClient.create();
562
487
  const notes = await client.query({ table_name: 'notes' });
563
488
  ```
@@ -577,7 +502,7 @@ import { DataClient } from '@seaverse/data-sdk';
577
502
 
578
503
  export async function getServerSideProps() {
579
504
  // 服务端需要显式提供配置
580
- const client = await DataClient.create({
505
+ const client = new DataClient({
581
506
  appId: process.env.APP_ID,
582
507
  token: process.env.API_SERVICE_TOKEN,
583
508
  });
@@ -591,18 +516,18 @@ export async function getServerSideProps() {
591
516
  }
592
517
  ```
593
518
 
594
- ### 获取当前配置
519
+ ### 动态更新 Token
595
520
 
596
521
  ```typescript
597
- import { DataClient } from '@seaverse/data-sdk';
522
+ // JWT 过期后更新 token
523
+ client.updateToken('new-jwt-token');
524
+ ```
598
525
 
599
- const client = await DataClient.create();
526
+ ### 切换应用
600
527
 
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);
528
+ ```typescript
529
+ // 切换到其他应用
530
+ client.updateAppId('another-app-id');
606
531
  ```
607
532
 
608
533
  ### JSONB 字段查询
package/dist/index.cjs CHANGED
@@ -138,13 +138,14 @@ function detectEnvironment() {
138
138
  /**
139
139
  * 解析用户配置,返回最终的 baseURL
140
140
  *
141
- * 优先级:
141
+ * 优先级(同步版本,用于向后兼容):
142
142
  * 1. 显式传入的 baseURL(最高优先级)
143
143
  * 2. environment 参数指定的环境
144
144
  * 3. 自动检测环境(最低优先级)
145
145
  *
146
146
  * @param options 用户配置选项
147
147
  * @returns 最终使用的 baseURL
148
+ * @deprecated 推荐使用异步版本 resolveBaseURLAsync 以支持 PostMessage 和环境变量
148
149
  */
149
150
  function resolveBaseURL(options) {
150
151
  // 优先级 1: 显式传入的 baseURL
@@ -159,6 +160,52 @@ function resolveBaseURL(options) {
159
160
  const detectedEnv = detectEnvironment();
160
161
  return ENVIRONMENT_CONFIGS[detectedEnv].baseURL;
161
162
  }
163
+ /**
164
+ * 解析用户配置,返回最终的 baseURL(异步版本)
165
+ *
166
+ * 优先级:
167
+ * 1. 显式传入的 baseURL(最高优先级)
168
+ * 2. 环境变量 DATA_SDK_BASE_URL
169
+ * 3. environment 参数指定的环境
170
+ * 4. iframe 环境 - 从父页面获取环境标识
171
+ * - 父页面返回 'develop' → development 环境
172
+ * - 父页面返回 'production' → production 环境
173
+ * - 父页面返回其他值 → 自动检测环境
174
+ * 5. 非 iframe 环境 - 自动检测环境
175
+ *
176
+ * @param options 用户配置选项
177
+ * @returns 最终使用的 baseURL
178
+ */
179
+ async function resolveBaseURLAsync(options) {
180
+ // 优先级 1: 显式传入的 baseURL
181
+ if (options.baseURL) {
182
+ return options.baseURL;
183
+ }
184
+ // 优先级 2: 环境变量 DATA_SDK_BASE_URL
185
+ if (typeof process !== 'undefined' && process.env?.DATA_SDK_BASE_URL) {
186
+ return process.env.DATA_SDK_BASE_URL;
187
+ }
188
+ // 优先级 3: environment 参数
189
+ if (options.environment) {
190
+ return ENVIRONMENT_CONFIGS[options.environment].baseURL;
191
+ }
192
+ // 优先级 4: iframe 环境 - 从父页面获取环境标识
193
+ if (isInIframe()) {
194
+ const parentEnv = await getEnvFromParent(3000);
195
+ if (parentEnv === 'develop') {
196
+ console.log('[DataSDK] iframe 环境:父页面返回开发环境,使用 development baseURL');
197
+ return ENVIRONMENT_CONFIGS.development.baseURL;
198
+ }
199
+ else if (parentEnv === 'production') {
200
+ console.log('[DataSDK] iframe 环境:父页面返回生产环境,使用 production baseURL');
201
+ return ENVIRONMENT_CONFIGS.production.baseURL;
202
+ }
203
+ // 如果获取到其他值或没有获取到,继续自动检测
204
+ }
205
+ // 优先级 5: 自动检测环境
206
+ const detectedEnv = detectEnvironment();
207
+ return ENVIRONMENT_CONFIGS[detectedEnv].baseURL;
208
+ }
162
209
  /**
163
210
  * 默认超时时间(毫秒)
164
211
  */
@@ -199,10 +246,8 @@ function isInIframe() {
199
246
  */
200
247
  async function getTokenFromParent(timeout = 5000) {
201
248
  if (!isInIframe()) {
202
- console.log('[DataSDK] Token: not in iframe, skipping PostMessage');
203
249
  return null;
204
250
  }
205
- console.log('[DataSDK] Token: requesting from parent via PostMessage');
206
251
  return new Promise((resolve) => {
207
252
  const messageHandler = (event) => {
208
253
  // 验证消息格式
@@ -210,24 +255,17 @@ async function getTokenFromParent(timeout = 5000) {
210
255
  cleanup();
211
256
  // 从 payload.accessToken 中获取 token
212
257
  const token = event.data.payload?.accessToken;
213
- if (token) {
214
- console.log('[DataSDK] Token: ✓ received from parent');
215
- }
216
- else {
217
- console.warn('[DataSDK] Token: received but accessToken is empty');
218
- }
219
258
  resolve(token || null);
220
259
  }
221
260
  else if (event.data && event.data.type === 'seaverse:error') {
222
261
  // 处理错误响应
223
262
  cleanup();
224
- console.warn('[DataSDK] Token: error from parent:', event.data.error);
263
+ console.warn('[DataSDK] Error getting token from parent:', event.data.error);
225
264
  resolve(null);
226
265
  }
227
266
  };
228
267
  const timeoutId = setTimeout(() => {
229
268
  cleanup();
230
- console.warn('[DataSDK] Token: ✗ timeout (5s), no response from parent');
231
269
  resolve(null);
232
270
  }, timeout);
233
271
  const cleanup = () => {
@@ -243,7 +281,6 @@ async function getTokenFromParent(timeout = 5000) {
243
281
  }
244
282
  catch (e) {
245
283
  cleanup();
246
- console.error('[DataSDK] Token: ✗ failed to send PostMessage:', e);
247
284
  resolve(null);
248
285
  }
249
286
  });
@@ -262,10 +299,8 @@ async function getTokenFromParent(timeout = 5000) {
262
299
  */
263
300
  async function getAppIdFromParent(timeout = 5000) {
264
301
  if (!isInIframe()) {
265
- console.log('[DataSDK] AppId: not in iframe, skipping PostMessage');
266
302
  return null;
267
303
  }
268
- console.log('[DataSDK] AppId: requesting from parent via PostMessage');
269
304
  return new Promise((resolve) => {
270
305
  const messageHandler = (event) => {
271
306
  // 验证消息格式
@@ -273,24 +308,17 @@ async function getAppIdFromParent(timeout = 5000) {
273
308
  cleanup();
274
309
  // 从 payload.appId 中获取 appId
275
310
  const appId = event.data.payload?.appId;
276
- if (appId) {
277
- console.log('[DataSDK] AppId: ✓ received from parent');
278
- }
279
- else {
280
- console.warn('[DataSDK] AppId: received but appId is empty');
281
- }
282
311
  resolve(appId || null);
283
312
  }
284
313
  else if (event.data && event.data.type === 'seaverse:error') {
285
314
  // 处理错误响应
286
315
  cleanup();
287
- console.warn('[DataSDK] AppId: error from parent:', event.data.error);
316
+ console.warn('[DataSDK] Error getting appId from parent:', event.data.error);
288
317
  resolve(null);
289
318
  }
290
319
  };
291
320
  const timeoutId = setTimeout(() => {
292
321
  cleanup();
293
- console.warn('[DataSDK] AppId: ✗ timeout (5s), no response from parent');
294
322
  resolve(null);
295
323
  }, timeout);
296
324
  const cleanup = () => {
@@ -306,7 +334,59 @@ async function getAppIdFromParent(timeout = 5000) {
306
334
  }
307
335
  catch (e) {
308
336
  cleanup();
309
- console.error('[DataSDK] AppId: ✗ failed to send PostMessage:', e);
337
+ resolve(null);
338
+ }
339
+ });
340
+ }
341
+ /**
342
+ * 通过 PostMessage 从父页面获取环境标识
343
+ *
344
+ * 此函数允许接收来自任何源的 PostMessage 消息,便于跨域 iframe 集成。
345
+ * 使用 seaverse 协议与父页面通信:
346
+ * - 发送: { type: 'seaverse:get_env' }
347
+ * - 接收: { type: 'seaverse:env', payload: { env: string } }
348
+ * - 错误: { type: 'seaverse:error', error: string }
349
+ *
350
+ * @param timeout 超时时间(毫秒),默认 5000ms
351
+ * @returns 环境标识字符串 (如 "develop", "production") 或 null
352
+ */
353
+ async function getEnvFromParent(timeout = 5000) {
354
+ if (!isInIframe()) {
355
+ return null;
356
+ }
357
+ return new Promise((resolve) => {
358
+ const messageHandler = (event) => {
359
+ // 验证消息格式
360
+ if (event.data && event.data.type === 'seaverse:env') {
361
+ cleanup();
362
+ // 从 payload.env 中获取环境标识
363
+ const env = event.data.payload?.env;
364
+ resolve(env || null);
365
+ }
366
+ else if (event.data && event.data.type === 'seaverse:error') {
367
+ // 处理错误响应
368
+ cleanup();
369
+ console.warn('[DataSDK] Error getting env from parent:', event.data.error);
370
+ resolve(null);
371
+ }
372
+ };
373
+ const timeoutId = setTimeout(() => {
374
+ cleanup();
375
+ resolve(null);
376
+ }, timeout);
377
+ const cleanup = () => {
378
+ clearTimeout(timeoutId);
379
+ globalThis.window.removeEventListener('message', messageHandler);
380
+ };
381
+ // 监听父页面的响应(不限制来源)
382
+ globalThis.window.addEventListener('message', messageHandler);
383
+ // 向父页面发送请求(允许任何源接收)
384
+ try {
385
+ globalThis.window.parent.postMessage({ type: 'seaverse:get_env' }, '*' // 允许任何源,支持跨域场景
386
+ );
387
+ }
388
+ catch (e) {
389
+ cleanup();
310
390
  resolve(null);
311
391
  }
312
392
  });
@@ -330,7 +410,6 @@ async function getApiToken(providedApiKey) {
330
410
  }
331
411
  }
332
412
  // 3. 返回'',让调用方处理
333
- console.warn('[DataSDK] Token: not found, returning empty string');
334
413
  return '';
335
414
  }
336
415
  /**
@@ -352,7 +431,6 @@ async function getAppId(providedAppId) {
352
431
  }
353
432
  }
354
433
  // 3. 返回'',让调用方处理
355
- console.warn('[DataSDK] AppId: not found, returning empty string');
356
434
  return '';
357
435
  }
358
436
 
@@ -375,21 +453,21 @@ async function getAppId(providedAppId) {
375
453
  *
376
454
  * // Query data
377
455
  * const notes = await client.query({
378
- * table: 'notes',
456
+ * table_name: 'notes',
379
457
  * filters: { category: 'work' },
380
458
  * order: { field: 'created_at', direction: 'desc' },
381
459
  * });
382
460
  *
383
461
  * // Create data
384
462
  * const note = await client.create({
385
- * table: 'notes',
386
- * data: { title: 'My Note', content: '...' },
463
+ * table_name: 'notes',
464
+ * data_value: { title: 'My Note', content: '...' },
387
465
  * visibility: 'private',
388
466
  * });
389
467
  *
390
468
  * // Update data
391
469
  * await client.update('note-id', {
392
- * data: { title: 'Updated' },
470
+ * data_value: { title: 'Updated' },
393
471
  * });
394
472
  *
395
473
  * // Delete data
@@ -400,14 +478,14 @@ class DataClient {
400
478
  /**
401
479
  * 创建 DataClient 实例(异步工厂方法)
402
480
  *
403
- * 支持自动从 localStorage/环境变量/PostMessage 获取 appId 和 token
481
+ * 支持自动从 localStorage/环境变量/PostMessage 获取 appId、tokenbaseURL
404
482
  *
405
483
  * @param options - 配置选项(appId 和 token 可选)
406
484
  * @returns DataClient 实例
407
485
  *
408
486
  * @example
409
487
  * ```typescript
410
- * // 自动获取 appId 和 token
488
+ * // 自动获取 appId 和 token,并通过 PostMessage 获取环境配置
411
489
  * const client = await DataClient.create();
412
490
  *
413
491
  * // 提供 appId,自动获取 token
@@ -416,7 +494,8 @@ class DataClient {
416
494
  * // 显式提供所有配置
417
495
  * const client = await DataClient.create({
418
496
  * appId: 'my-app-123',
419
- * token: 'user-jwt-token'
497
+ * token: 'user-jwt-token',
498
+ * environment: 'production'
420
499
  * });
421
500
  * ```
422
501
  */
@@ -429,10 +508,16 @@ class DataClient {
429
508
  if (!token) {
430
509
  throw new ValidationError('token is required. Please ensure it is available in localStorage.auth_token, provide token explicitly, or configure parent page to provide it via PostMessage.');
431
510
  }
511
+ // 使用异步版本解析 baseURL,支持环境变量和 PostMessage
512
+ const baseURL = await resolveBaseURLAsync({
513
+ baseURL: options.baseURL,
514
+ environment: options.environment,
515
+ });
432
516
  return new DataClient({
433
517
  ...options,
434
518
  appId,
435
519
  token,
520
+ baseURL, // 传递已解析的 baseURL
436
521
  });
437
522
  }
438
523
  constructor(options) {
@@ -590,7 +675,7 @@ class DataClient {
590
675
  * @example
591
676
  * ```typescript
592
677
  * const notes = await client.query({
593
- * table: 'notes',
678
+ * table_name: 'notes',
594
679
  * filters: {
595
680
  * category: 'work',
596
681
  * visibility: 'private',
@@ -860,7 +945,7 @@ class DataClient {
860
945
  * @example
861
946
  * ```typescript
862
947
  * const result = await client.queryWithPagination({
863
- * table_name: 'posts',
948
+ * table: 'posts',
864
949
  * pagination: { limit: 10, offset: 0 },
865
950
  * });
866
951
  *
@@ -985,26 +1070,39 @@ class DataClient {
985
1070
  // Configuration Methods
986
1071
  // ============================================
987
1072
  /**
988
- * Get current SDK configuration
1073
+ * Update token
989
1074
  *
990
- * 获取当前 SDK 配置信息
1075
+ * 更新 JWT token
991
1076
  *
992
- * @returns SDK 配置对象(包含 appId、token、url)
1077
+ * @param token - New JWT token
1078
+ */
1079
+ updateToken(token) {
1080
+ this.token = token;
1081
+ this.axiosInstance.defaults.headers['Authorization'] = `Bearer ${token}`;
1082
+ this.log('Token updated');
1083
+ }
1084
+ /**
1085
+ * Update app ID
993
1086
  *
994
- * @example
995
- * ```typescript
996
- * const config = client.getConfig();
997
- * console.log('App ID:', config.appId);
998
- * console.log('Token:', config.token);
999
- * console.log('API URL:', config.url);
1000
- * ```
1087
+ * 更新应用 ID
1088
+ *
1089
+ * @param appId - New application ID
1001
1090
  */
1002
- getConfig() {
1003
- return {
1004
- appId: this.appId,
1005
- token: this.token,
1006
- url: this.axiosInstance.defaults.baseURL || '',
1007
- };
1091
+ updateAppId(appId) {
1092
+ this.appId = appId;
1093
+ this.log('AppId updated', { appId });
1094
+ }
1095
+ /**
1096
+ * Get current app ID
1097
+ */
1098
+ getAppId() {
1099
+ return this.appId;
1100
+ }
1101
+ /**
1102
+ * Get current user ID
1103
+ */
1104
+ getUserId() {
1105
+ return this.getUserIdFromToken();
1008
1106
  }
1009
1107
  }
1010
1108