@seaverse/data-sdk 0.1.0

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/dist/index.cjs ADDED
@@ -0,0 +1,784 @@
1
+ 'use strict';
2
+
3
+ var axios = require('axios');
4
+
5
+ /**
6
+ * Type definitions for SeaVerse Data SDK
7
+ *
8
+ * 基于 PostgreSQL/AlloyDB + PostgREST + RLS 的数据类型定义
9
+ */
10
+ // ============================================================================
11
+ // Error Types
12
+ // ============================================================================
13
+ /**
14
+ * SDK Error class
15
+ */
16
+ class SDKError extends Error {
17
+ constructor(message, code, statusCode, details) {
18
+ super(message);
19
+ this.code = code;
20
+ this.statusCode = statusCode;
21
+ this.details = details;
22
+ this.name = 'SDKError';
23
+ }
24
+ }
25
+ /**
26
+ * SDK Error base class (legacy alias)
27
+ */
28
+ class DataSDKError extends SDKError {
29
+ constructor(message, code, statusCode) {
30
+ super(message, code || 'SDK_ERROR', statusCode);
31
+ this.name = 'DataSDKError';
32
+ }
33
+ }
34
+ /**
35
+ * Permission denied error (403)
36
+ */
37
+ class PermissionError extends SDKError {
38
+ constructor(message = 'Permission denied') {
39
+ super(message, 'PERMISSION_DENIED', 403);
40
+ this.name = 'PermissionError';
41
+ }
42
+ }
43
+ /**
44
+ * Resource not found error (404)
45
+ */
46
+ class NotFoundError extends SDKError {
47
+ constructor(message = 'Resource not found') {
48
+ super(message, 'NOT_FOUND', 404);
49
+ this.name = 'NotFoundError';
50
+ }
51
+ }
52
+ /**
53
+ * Rate limit exceeded error (429)
54
+ */
55
+ class RateLimitError extends SDKError {
56
+ constructor(message = 'Rate limit exceeded') {
57
+ super(message, 'RATE_LIMIT_EXCEEDED', 429);
58
+ this.name = 'RateLimitError';
59
+ }
60
+ }
61
+ /**
62
+ * Validation error (400)
63
+ */
64
+ class ValidationError extends SDKError {
65
+ constructor(message) {
66
+ super(message, 'VALIDATION_ERROR', 400);
67
+ this.name = 'ValidationError';
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Environment Configuration for Data SDK
73
+ * 环境配置模块 - 支持多环境部署
74
+ */
75
+ /**
76
+ * 预定义的环境配置
77
+ *
78
+ * 使用说明:
79
+ * - production: 正式生产环境
80
+ * - staging: 预发布环境
81
+ * - development: 开发测试环境
82
+ * - local: 本地开发环境
83
+ */
84
+ const ENVIRONMENT_CONFIGS = {
85
+ production: {
86
+ name: 'production',
87
+ baseURL: 'https://data.seaverse.ai',
88
+ isProduction: true,
89
+ },
90
+ staging: {
91
+ name: 'staging',
92
+ baseURL: 'https://data.sg.seaverse.dev',
93
+ isProduction: false,
94
+ },
95
+ development: {
96
+ name: 'development',
97
+ baseURL: 'https://data-dev.seaverse.dev',
98
+ isProduction: false,
99
+ },
100
+ local: {
101
+ name: 'local',
102
+ baseURL: 'http://localhost:3000',
103
+ isProduction: false,
104
+ },
105
+ };
106
+ /**
107
+ * 根据当前运行环境自动检测应该使用的环境配置
108
+ *
109
+ * 检测规则:
110
+ * 1. localhost/127.0.0.1 → local
111
+ * 2. 包含 -dev 或 .dev → development
112
+ * 3. 包含 staging → staging
113
+ * 4. 其他 → production (默认)
114
+ *
115
+ * @returns 检测到的环境类型
116
+ */
117
+ function detectEnvironment() {
118
+ // Node.js 环境或非浏览器环境,默认返回 staging(安全起见)
119
+ if (typeof window === 'undefined' || typeof window.location === 'undefined') {
120
+ return 'staging';
121
+ }
122
+ const hostname = window.location.hostname.toLowerCase();
123
+ // 本地开发环境
124
+ if (hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '0.0.0.0') {
125
+ return 'local';
126
+ }
127
+ // 开发环境 (包含 -dev 或 .dev)
128
+ if (hostname.includes('-dev.') || hostname.includes('.dev') || hostname.endsWith('.dev')) {
129
+ return 'development';
130
+ }
131
+ // Staging 环境
132
+ if (hostname.includes('-staging.') || hostname.includes('staging.')) {
133
+ return 'staging';
134
+ }
135
+ // 默认使用 production
136
+ return 'production';
137
+ }
138
+ /**
139
+ * 获取环境配置
140
+ *
141
+ * @param env 环境类型,如果不提供则自动检测
142
+ * @returns 环境配置对象
143
+ */
144
+ function getEnvironmentConfig(env) {
145
+ const targetEnv = env || detectEnvironment();
146
+ return ENVIRONMENT_CONFIGS[targetEnv];
147
+ }
148
+ /**
149
+ * 解析用户配置,返回最终的 baseURL
150
+ *
151
+ * 优先级:
152
+ * 1. 显式传入的 baseURL(最高优先级)
153
+ * 2. environment 参数指定的环境
154
+ * 3. 自动检测环境(最低优先级)
155
+ *
156
+ * @param options 用户配置选项
157
+ * @returns 最终使用的 baseURL
158
+ */
159
+ function resolveBaseURL(options) {
160
+ // 优先级 1: 显式传入的 baseURL
161
+ if (options.baseURL) {
162
+ return options.baseURL;
163
+ }
164
+ // 优先级 2: environment 参数
165
+ if (options.environment) {
166
+ return ENVIRONMENT_CONFIGS[options.environment].baseURL;
167
+ }
168
+ // 优先级 3: 自动检测
169
+ const detectedEnv = detectEnvironment();
170
+ return ENVIRONMENT_CONFIGS[detectedEnv].baseURL;
171
+ }
172
+ /**
173
+ * 默认超时时间(毫秒)
174
+ */
175
+ const DEFAULT_TIMEOUT = 10000; // 10 seconds
176
+ /**
177
+ * API 端点路径
178
+ */
179
+ const ENDPOINTS = {
180
+ // Data operations (PostgREST)
181
+ APP_DATA: '/app_data',
182
+ // Admin roles
183
+ APP_ADMINS: '/app_admins',
184
+ };
185
+
186
+ /**
187
+ * Data SDK Client
188
+ *
189
+ * 基于 PostgreSQL/AlloyDB + PostgREST + RLS 的数据 SDK
190
+ */
191
+ /**
192
+ * SeaVerse Data Client
193
+ *
194
+ * 高性能数据服务SDK,基于PostgREST + RLS架构
195
+ *
196
+ * @example
197
+ * ```typescript
198
+ * const client = new DataClient({
199
+ * appId: 'my-app-id',
200
+ * token: 'user-jwt-token',
201
+ * });
202
+ *
203
+ * // Query data
204
+ * const notes = await client.query({
205
+ * table: 'notes',
206
+ * filters: { category: 'work' },
207
+ * order: { field: 'created_at', direction: 'desc' },
208
+ * });
209
+ *
210
+ * // Create data
211
+ * const note = await client.create({
212
+ * table: 'notes',
213
+ * data: { title: 'My Note', content: '...' },
214
+ * visibility: 'private',
215
+ * });
216
+ *
217
+ * // Update data
218
+ * await client.update('note-id', {
219
+ * data: { title: 'Updated' },
220
+ * });
221
+ *
222
+ * // Delete data
223
+ * await client.delete('note-id');
224
+ * ```
225
+ */
226
+ class DataClient {
227
+ constructor(options) {
228
+ const { timeout = DEFAULT_TIMEOUT, headers = {}, appId, token, debug = false, } = options;
229
+ if (!appId) {
230
+ throw new ValidationError('appId is required');
231
+ }
232
+ if (!token) {
233
+ throw new ValidationError('token is required');
234
+ }
235
+ this.appId = appId;
236
+ this.token = token;
237
+ this.debug = debug;
238
+ // 解析 baseURL(支持环境自动检测)
239
+ const baseURL = resolveBaseURL({
240
+ baseURL: options.baseURL,
241
+ environment: options.environment,
242
+ });
243
+ this.axiosInstance = axios.create({
244
+ baseURL,
245
+ timeout,
246
+ headers: {
247
+ 'Content-Type': 'application/json',
248
+ 'Authorization': `Bearer ${token}`,
249
+ ...headers,
250
+ },
251
+ });
252
+ // Add response interceptor for error handling
253
+ this.axiosInstance.interceptors.response.use((response) => response, (error) => {
254
+ throw this._handleError(error);
255
+ });
256
+ this.log('SDK initialized', { apiUrl: baseURL, appId });
257
+ }
258
+ // ============================================
259
+ // Logging Methods
260
+ // ============================================
261
+ log(message, data) {
262
+ if (this.debug) {
263
+ console.log(`[DataSDK] ${message}`, data || '');
264
+ }
265
+ }
266
+ logError(message, error) {
267
+ console.error(`[DataSDK] ${message}`, error);
268
+ }
269
+ // ============================================
270
+ // Helper Methods
271
+ // ============================================
272
+ /**
273
+ * Handle axios errors and convert to SDK errors
274
+ * @private
275
+ */
276
+ _handleError(error) {
277
+ const status = error.response?.status;
278
+ const message = error.response?.data?.message || error.message;
279
+ switch (status) {
280
+ case 403:
281
+ return new PermissionError(message);
282
+ case 404:
283
+ return new NotFoundError(message);
284
+ case 429:
285
+ return new RateLimitError(message);
286
+ case 400:
287
+ return new ValidationError(message);
288
+ default:
289
+ return new SDKError(message, 'REQUEST_FAILED', status);
290
+ }
291
+ }
292
+ /**
293
+ * Get user ID from JWT token
294
+ * @private
295
+ */
296
+ getUserIdFromToken() {
297
+ try {
298
+ // JWT token format: header.payload.signature
299
+ const parts = this.token.split('.');
300
+ if (parts.length !== 3) {
301
+ throw new Error('Invalid JWT token');
302
+ }
303
+ // Decode payload (base64url)
304
+ const payload = parts[1];
305
+ // Cross-platform base64 decoding
306
+ let decodedString;
307
+ const globalObj = globalThis;
308
+ if (typeof globalObj.atob === 'function') {
309
+ // Browser environment
310
+ decodedString = globalObj.atob(payload);
311
+ }
312
+ else if (typeof globalObj.Buffer !== 'undefined') {
313
+ // Node.js environment
314
+ decodedString = globalObj.Buffer.from(payload, 'base64').toString('utf-8');
315
+ }
316
+ else {
317
+ // Fallback: manual base64 decode
318
+ decodedString = this.base64Decode(payload);
319
+ }
320
+ const claims = JSON.parse(decodedString);
321
+ return claims.sub;
322
+ }
323
+ catch (error) {
324
+ throw new SDKError('Unable to parse JWT token', 'INVALID_TOKEN', 401, error);
325
+ }
326
+ }
327
+ /**
328
+ * Base64 decode fallback
329
+ * @private
330
+ */
331
+ base64Decode(str) {
332
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
333
+ let output = '';
334
+ str = String(str).replace(/=+$/, '');
335
+ if (str.length % 4 === 1) {
336
+ throw new Error('Invalid base64 string');
337
+ }
338
+ for (let bc = 0, bs = 0, buffer, i = 0; (buffer = str.charAt(i++)); ~buffer && ((bs = bc % 4 ? bs * 64 + buffer : buffer), bc++ % 4)
339
+ ? (output += String.fromCharCode(255 & (bs >> ((-2 * bc) & 6))))
340
+ : 0) {
341
+ buffer = chars.indexOf(buffer);
342
+ }
343
+ return output;
344
+ }
345
+ // ============================================
346
+ // Data Operation Methods
347
+ // ============================================
348
+ /**
349
+ * Query data list
350
+ *
351
+ * 查询数据列表,支持过滤、排序、分页
352
+ *
353
+ * @param options - Query options
354
+ * @returns Array of data records
355
+ *
356
+ * @example
357
+ * ```typescript
358
+ * const notes = await client.query({
359
+ * table: 'notes',
360
+ * filters: {
361
+ * category: 'work',
362
+ * visibility: 'private',
363
+ * },
364
+ * order: {
365
+ * field: 'created_at',
366
+ * direction: 'desc',
367
+ * },
368
+ * pagination: {
369
+ * limit: 20,
370
+ * offset: 0,
371
+ * },
372
+ * });
373
+ * ```
374
+ */
375
+ async query(options) {
376
+ const query = {
377
+ app_id: `eq.${this.appId}`,
378
+ table_name: `eq.${options.table}`,
379
+ };
380
+ // Add filters
381
+ if (options.filters) {
382
+ const { filters } = options;
383
+ if (filters.id) {
384
+ query.id = `eq.${filters.id}`;
385
+ }
386
+ if (filters.category) {
387
+ query.category = `eq.${filters.category}`;
388
+ }
389
+ if (filters.visibility) {
390
+ query.visibility = `eq.${filters.visibility}`;
391
+ }
392
+ if (filters.tags && filters.tags.length > 0) {
393
+ // PostgREST array contains operator
394
+ query.tags = `cs.{${filters.tags.join(',')}}`;
395
+ }
396
+ if (filters.created_after) {
397
+ query.created_at = `gte.${filters.created_after}`;
398
+ }
399
+ if (filters.created_before) {
400
+ if (query.created_at) {
401
+ // If created_at already exists, use 'and' to combine
402
+ query.and = `(created_at.gte.${filters.created_after},created_at.lt.${filters.created_before})`;
403
+ delete query.created_at;
404
+ }
405
+ else {
406
+ query.created_at = `lt.${filters.created_before}`;
407
+ }
408
+ }
409
+ // JSONB field filters (data_value)
410
+ if (filters.data) {
411
+ Object.entries(filters.data).forEach(([key, value]) => {
412
+ // PostgREST JSONB query syntax: data_value->>key (text extraction)
413
+ query[`data_value->>${key}`] = `eq.${value}`;
414
+ });
415
+ }
416
+ }
417
+ // Add sorting
418
+ if (options.order) {
419
+ const direction = options.order.direction === 'asc' ? '' : '.desc';
420
+ query.order = `${options.order.field}${direction}`;
421
+ }
422
+ else {
423
+ // Default sort by created_at desc
424
+ query.order = 'created_at.desc';
425
+ }
426
+ // Add pagination
427
+ if (options.pagination) {
428
+ query.limit = options.pagination.limit.toString();
429
+ query.offset = options.pagination.offset.toString();
430
+ }
431
+ this.log('Querying data', query);
432
+ const response = await this.axiosInstance.get(ENDPOINTS.APP_DATA, { params: query });
433
+ return Array.isArray(response.data) ? response.data : [response.data];
434
+ }
435
+ /**
436
+ * Get single data record by ID
437
+ *
438
+ * 通过 ID 查询单条数据
439
+ *
440
+ * @param id - Data ID
441
+ * @returns Data record or null if not found
442
+ *
443
+ * @example
444
+ * ```typescript
445
+ * const note = await client.get('note-id-123');
446
+ * console.log(note?.data_value.title);
447
+ * ```
448
+ */
449
+ async get(id) {
450
+ try {
451
+ const response = await this.axiosInstance.get(ENDPOINTS.APP_DATA, {
452
+ params: {
453
+ id: `eq.${id}`,
454
+ },
455
+ headers: {
456
+ 'Accept': 'application/vnd.pgrst.object+json', // 返回单个对象
457
+ },
458
+ });
459
+ const results = Array.isArray(response.data) ? response.data : [response.data];
460
+ return results && results.length > 0 ? results[0] : null;
461
+ }
462
+ catch (error) {
463
+ this._handleError(error);
464
+ return null;
465
+ }
466
+ }
467
+ /**
468
+ * Create data
469
+ *
470
+ * 创建新数据
471
+ *
472
+ * @param options - Create options
473
+ * @returns Created data record
474
+ *
475
+ * @example
476
+ * ```typescript
477
+ * const newNote = await client.create({
478
+ * table: 'notes',
479
+ * data: {
480
+ * title: 'My Note',
481
+ * content: 'Note content...',
482
+ * },
483
+ * visibility: 'private',
484
+ * category: 'work',
485
+ * tags: ['important', 'todo'],
486
+ * });
487
+ * ```
488
+ */
489
+ async create(options) {
490
+ const body = {
491
+ app_id: this.appId,
492
+ table_name: options.table,
493
+ data_value: options.data,
494
+ owner_user_id: this.getUserIdFromToken(),
495
+ visibility: options.visibility || 'private',
496
+ category: options.category,
497
+ tags: options.tags,
498
+ };
499
+ this.log('Creating data', body);
500
+ const response = await this.axiosInstance.post(ENDPOINTS.APP_DATA, body, {
501
+ headers: {
502
+ 'Prefer': 'return=representation', // Return created record
503
+ },
504
+ });
505
+ const results = Array.isArray(response.data) ? response.data : [response.data];
506
+ return results[0];
507
+ }
508
+ /**
509
+ * Update data
510
+ *
511
+ * 更新数据
512
+ *
513
+ * @param id - Data ID
514
+ * @param options - Update options
515
+ * @returns Updated data record
516
+ *
517
+ * @example
518
+ * ```typescript
519
+ * const updated = await client.update('note-id-123', {
520
+ * data: {
521
+ * title: 'Updated Title',
522
+ * content: 'Updated content',
523
+ * },
524
+ * category: 'personal',
525
+ * });
526
+ * ```
527
+ */
528
+ async update(id, options) {
529
+ const body = {
530
+ updated_at: new Date().toISOString(),
531
+ };
532
+ if (options.data !== undefined) {
533
+ body.data_value = options.data;
534
+ }
535
+ if (options.visibility !== undefined) {
536
+ body.visibility = options.visibility;
537
+ }
538
+ if (options.category !== undefined) {
539
+ body.category = options.category;
540
+ }
541
+ if (options.tags !== undefined) {
542
+ body.tags = options.tags;
543
+ }
544
+ this.log('Updating data', { id, body });
545
+ const response = await this.axiosInstance.patch(ENDPOINTS.APP_DATA, body, {
546
+ params: {
547
+ id: `eq.${id}`,
548
+ },
549
+ headers: {
550
+ 'Prefer': 'return=representation',
551
+ },
552
+ });
553
+ const results = Array.isArray(response.data) ? response.data : [response.data];
554
+ if (!results || results.length === 0) {
555
+ throw new NotFoundError('Data not found or no permission to update');
556
+ }
557
+ return results[0];
558
+ }
559
+ /**
560
+ * Delete data
561
+ *
562
+ * 删除数据
563
+ *
564
+ * @param id - Data ID
565
+ *
566
+ * @example
567
+ * ```typescript
568
+ * await client.delete('note-id-123');
569
+ * ```
570
+ */
571
+ async delete(id) {
572
+ this.log('Deleting data', { id });
573
+ await this.axiosInstance.delete(ENDPOINTS.APP_DATA, {
574
+ params: {
575
+ app_id: `eq.${this.appId}`,
576
+ id: `eq.${id}`,
577
+ },
578
+ });
579
+ }
580
+ /**
581
+ * Batch delete data
582
+ *
583
+ * 批量删除数据
584
+ *
585
+ * @param ids - Array of data IDs
586
+ *
587
+ * @example
588
+ * ```typescript
589
+ * await client.batchDelete(['id-1', 'id-2', 'id-3']);
590
+ * ```
591
+ */
592
+ async batchDelete(ids) {
593
+ if (ids.length === 0)
594
+ return;
595
+ this.log('Batch deleting data', { ids });
596
+ await this.axiosInstance.delete(ENDPOINTS.APP_DATA, {
597
+ params: {
598
+ app_id: `eq.${this.appId}`,
599
+ id: `in.(${ids.join(',')})`,
600
+ },
601
+ });
602
+ }
603
+ /**
604
+ * Query with pagination metadata
605
+ *
606
+ * 查询数据并返回分页信息
607
+ *
608
+ * @param options - Query options
609
+ * @returns Paginated response with metadata
610
+ *
611
+ * @example
612
+ * ```typescript
613
+ * const result = await client.queryWithPagination({
614
+ * table: 'posts',
615
+ * pagination: { limit: 10, offset: 0 },
616
+ * });
617
+ *
618
+ * console.log(`Total: ${result.total}, Has more: ${result.hasMore}`);
619
+ * ```
620
+ */
621
+ async queryWithPagination(options) {
622
+ const limit = options.pagination?.limit || 10;
623
+ const offset = options.pagination?.offset || 0;
624
+ const query = {
625
+ app_id: `eq.${this.appId}`,
626
+ table_name: `eq.${options.table}`,
627
+ limit: limit.toString(),
628
+ offset: offset.toString(),
629
+ };
630
+ // Add filters (same as query method)
631
+ if (options.filters) {
632
+ const { filters } = options;
633
+ if (filters.id)
634
+ query.id = `eq.${filters.id}`;
635
+ if (filters.category)
636
+ query.category = `eq.${filters.category}`;
637
+ if (filters.visibility)
638
+ query.visibility = `eq.${filters.visibility}`;
639
+ if (filters.tags && filters.tags.length > 0) {
640
+ query.tags = `cs.{${filters.tags.join(',')}}`;
641
+ }
642
+ if (filters.created_after) {
643
+ query.created_at = `gte.${filters.created_after}`;
644
+ }
645
+ if (filters.created_before) {
646
+ if (query.created_at) {
647
+ query.and = `(created_at.gte.${filters.created_after},created_at.lt.${filters.created_before})`;
648
+ delete query.created_at;
649
+ }
650
+ else {
651
+ query.created_at = `lt.${filters.created_before}`;
652
+ }
653
+ }
654
+ if (filters.data) {
655
+ Object.entries(filters.data).forEach(([key, value]) => {
656
+ query[`data_value->>${key}`] = `eq.${value}`;
657
+ });
658
+ }
659
+ }
660
+ // Add sorting
661
+ if (options.order) {
662
+ const direction = options.order.direction === 'asc' ? '' : '.desc';
663
+ query.order = `${options.order.field}${direction}`;
664
+ }
665
+ else {
666
+ query.order = 'created_at.desc';
667
+ }
668
+ this.log('Querying with pagination', query);
669
+ // Request with count
670
+ const response = await this.axiosInstance.get(ENDPOINTS.APP_DATA, {
671
+ params: query,
672
+ headers: {
673
+ 'Prefer': 'count=exact', // Request total count
674
+ },
675
+ });
676
+ const data = Array.isArray(response.data) ? response.data : [response.data];
677
+ // Extract total count from Content-Range header
678
+ // Format: "0-9/100" means items 0-9, total 100
679
+ let total;
680
+ let hasMore;
681
+ const contentRange = response.headers['content-range'];
682
+ if (contentRange) {
683
+ const match = contentRange.match(/\/(\d+|\*)/);
684
+ if (match && match[1] !== '*') {
685
+ total = parseInt(match[1], 10);
686
+ hasMore = offset + data.length < total;
687
+ }
688
+ }
689
+ return {
690
+ data,
691
+ total,
692
+ limit,
693
+ offset,
694
+ hasMore,
695
+ };
696
+ }
697
+ // ============================================
698
+ // Admin Operation Methods
699
+ // ============================================
700
+ /**
701
+ * Check if current user is admin
702
+ *
703
+ * 检查当前用户是否是管理员
704
+ *
705
+ * @returns True if user is admin
706
+ *
707
+ * @example
708
+ * ```typescript
709
+ * const isAdmin = await client.isAdmin();
710
+ * if (isAdmin) {
711
+ * // User has admin privileges
712
+ * }
713
+ * ```
714
+ */
715
+ async isAdmin() {
716
+ try {
717
+ const response = await this.axiosInstance.get(ENDPOINTS.APP_ADMINS, {
718
+ params: {
719
+ app_id: `eq.${this.appId}`,
720
+ user_id: `eq.${this.getUserIdFromToken()}`,
721
+ },
722
+ });
723
+ const roles = Array.isArray(response.data) ? response.data : [response.data];
724
+ return roles.length > 0;
725
+ }
726
+ catch (error) {
727
+ this.logError('Check admin permission failed', error);
728
+ return false;
729
+ }
730
+ }
731
+ // ============================================
732
+ // Configuration Methods
733
+ // ============================================
734
+ /**
735
+ * Update token
736
+ *
737
+ * 更新 JWT token
738
+ *
739
+ * @param token - New JWT token
740
+ */
741
+ updateToken(token) {
742
+ this.token = token;
743
+ this.axiosInstance.defaults.headers['Authorization'] = `Bearer ${token}`;
744
+ this.log('Token updated');
745
+ }
746
+ /**
747
+ * Update app ID
748
+ *
749
+ * 更新应用 ID
750
+ *
751
+ * @param appId - New application ID
752
+ */
753
+ updateAppId(appId) {
754
+ this.appId = appId;
755
+ this.log('AppId updated', { appId });
756
+ }
757
+ /**
758
+ * Get current app ID
759
+ */
760
+ getAppId() {
761
+ return this.appId;
762
+ }
763
+ /**
764
+ * Get current user ID
765
+ */
766
+ getUserId() {
767
+ return this.getUserIdFromToken();
768
+ }
769
+ }
770
+
771
+ exports.DEFAULT_TIMEOUT = DEFAULT_TIMEOUT;
772
+ exports.DataClient = DataClient;
773
+ exports.DataSDKError = DataSDKError;
774
+ exports.ENDPOINTS = ENDPOINTS;
775
+ exports.ENVIRONMENT_CONFIGS = ENVIRONMENT_CONFIGS;
776
+ exports.NotFoundError = NotFoundError;
777
+ exports.PermissionError = PermissionError;
778
+ exports.RateLimitError = RateLimitError;
779
+ exports.SDKError = SDKError;
780
+ exports.ValidationError = ValidationError;
781
+ exports.detectEnvironment = detectEnvironment;
782
+ exports.getEnvironmentConfig = getEnvironmentConfig;
783
+ exports.resolveBaseURL = resolveBaseURL;
784
+ //# sourceMappingURL=index.cjs.map