@seaverse/dataservice 1.6.1 → 1.7.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/README.md CHANGED
@@ -17,19 +17,61 @@ A TypeScript/JavaScript SDK for universal data storage with PostgREST backend. S
17
17
  npm install @seaverse/dataservice
18
18
  ```
19
19
 
20
- ## Quick Start
20
+ ## Package Exports
21
+
22
+ This package uses a **factory pattern** for client creation. Here's what it exports:
23
+
24
+ **Functions:**
25
+ - `createClient(config)` - Factory function to create a client instance (async)
26
+ - `debugSetToken(token)` - Set debug token for testing (call before createClient)
27
+
28
+ **Types (TypeScript):**
29
+ - `DataServiceClient` - Type of the client instance (**not a constructor**)
30
+ - `DataRecord<T>` - Type of stored records
31
+ - `Collection<T>` - Type of collection instances
32
+ - `QueryBuilder<T>` - Type of query builder instances
33
+ - `DataTable` - Type of data table instances
34
+ - `ClientConfig` - Configuration options for createClient
35
+ - `DataServiceError` - Error class for API errors
36
+
37
+ **Constants:**
38
+ - `VERSION` - SDK version string
39
+
40
+ **Important:** Always use `createClient()` to create clients. `DataServiceClient` is a TypeScript type, not a class constructor.
21
41
 
22
42
  ```typescript
43
+ // ✓ CORRECT
23
44
  import { createClient } from '@seaverse/dataservice';
45
+ const client = await createClient({});
46
+
47
+ // ✗ WRONG - DataServiceClient is not a constructor
48
+ import { DataServiceClient } from '@seaverse/dataservice';
49
+ const client = new DataServiceClient(); // This will fail!
50
+ ```
51
+
52
+ ## Quick Start
53
+
54
+ ### Creating a Client
55
+
56
+ The SDK uses a **factory function pattern**. Always use `createClient()`:
57
+
58
+ **Important:** The SDK automatically obtains the service host from the parent page via PostMessage (500ms timeout). If the fetch fails, it defaults to `https://dataservice-api.seaverse.ai`. No configuration is needed.
59
+
60
+ ```typescript
61
+ import { createClient, debugSetToken } from '@seaverse/dataservice';
24
62
 
25
- // Auto-fetch token from parent page (iframe)
63
+ // Production: Auto-fetch token and serviceHost from parent page (when running in iframe)
64
+ // Falls back to https://dataservice-api.seaverse.ai if fetch fails
26
65
  const client = await createClient({});
27
66
 
28
- // For development/testing, use debugSetToken
29
- import { debugSetToken } from '@seaverse/dataservice';
67
+ // Development/Testing: Use debug token
30
68
  debugSetToken('your-test-token');
31
69
  const client = await createClient({});
70
+ ```
32
71
 
72
+ ### Basic Operations
73
+
74
+ ```typescript
33
75
  // Store user preferences (single record)
34
76
  const userPrefs = client.userData.collection('user_preferences');
35
77
  await userPrefs.insert({
@@ -269,7 +311,6 @@ interface DataRecord<T> {
269
311
  import { createClient } from '@seaverse/dataservice';
270
312
 
271
313
  const client = await createClient({
272
- url?: string; // PostgREST API URL (default: https://dataservice-api.seaverse.ai)
273
314
  options?: {
274
315
  timeout?: number; // Request timeout in ms (default: 30000)
275
316
  tokenFetchTimeout?: number; // Token fetch timeout in ms (default: 5000)
@@ -278,6 +319,14 @@ const client = await createClient({
278
319
  });
279
320
  ```
280
321
 
322
+ **ServiceHost Auto-Detection:**
323
+
324
+ The SDK automatically fetches the service host from the parent page via PostMessage:
325
+ - **Timeout**: 500ms (hardcoded, not configurable)
326
+ - **Protocol**: Sends `{ type: 'seaverse:get_service_host', payload: { serviceName: 'dataservice' } }`
327
+ - **Fallback**: If fetch fails, defaults to `https://dataservice-api.seaverse.ai`
328
+ - **No user configuration**: ServiceHost is managed internally to prevent request failures
329
+
281
330
  **Token Authentication Priority:**
282
331
 
283
332
  The SDK uses the following priority order for obtaining authentication tokens:
@@ -288,16 +337,22 @@ The SDK uses the following priority order for obtaining authentication tokens:
288
337
 
289
338
  **Production Usage (Auto-fetch from parent):**
290
339
 
291
- The SDK automatically fetches the authentication token from the parent page via PostMessage when running in an iframe:
340
+ The SDK automatically fetches the authentication token and service host from the parent page via PostMessage when running in an iframe:
292
341
 
293
342
  ```typescript
294
- // No token needed - auto-fetches from parent
343
+ // No configuration needed - auto-fetches token and serviceHost from parent
295
344
  const client = await createClient({});
296
345
 
297
346
  // Parent page should respond to PostMessage:
347
+ // Token request:
298
348
  // Send: { type: 'seaverse:get_token' }
299
349
  // Receive: { type: 'seaverse:token', payload: { accessToken: string, expiresIn: number } }
300
350
  // Error: { type: 'seaverse:error', error: string }
351
+
352
+ // ServiceHost request:
353
+ // Send: { type: 'seaverse:get_service_host', payload: { serviceName: 'dataservice' } }
354
+ // Receive: { type: 'seaverse:service_host', payload: { serviceHost: string } }
355
+ // Error: { type: 'seaverse:error', error: string }
301
356
  ```
302
357
 
303
358
  **Development/Testing (Debug Token):**
@@ -316,10 +371,13 @@ const client = await createClient({});
316
371
 
317
372
  **Graceful Degradation:**
318
373
 
319
- If token fetching fails (e.g., not in an iframe, parent doesn't respond), the SDK will create a client without a token. API calls that require authentication will return 401 errors:
374
+ If token or serviceHost fetching fails, the SDK gracefully handles the failure:
375
+
376
+ - **Token fetch failure**: Creates client without authentication (API calls will return 401)
377
+ - **ServiceHost fetch failure**: Falls back to default `https://dataservice-api.seaverse.ai`
320
378
 
321
379
  ```typescript
322
- // Client creation never throws, even if token fetch fails
380
+ // Client creation never throws, even if fetch fails
323
381
  const client = await createClient({});
324
382
 
325
383
  try {
@@ -333,15 +391,6 @@ try {
333
391
  }
334
392
  ```
335
393
 
336
- **Custom Endpoint:**
337
-
338
- ```typescript
339
- // Use custom API endpoint
340
- const client = await createClient({
341
- url: 'https://your-custom-api.example.com',
342
- });
343
- ```
344
-
345
394
  ### DataTable Methods
346
395
 
347
396
  ```typescript
package/dist/index.d.mts CHANGED
@@ -12,13 +12,13 @@
12
12
  * @example
13
13
  * ```typescript
14
14
  * const config: ClientConfig = {
15
- * url: 'https://dataservice-api.seaverse.ai',
15
+ * options: {
16
+ * timeout: 10000,
17
+ * }
16
18
  * };
17
19
  * ```
18
20
  */
19
21
  interface ClientConfig {
20
- /** PostgREST API base URL (default: https://dataservice-api.seaverse.ai) */
21
- url?: string;
22
22
  /** Optional configuration */
23
23
  options?: {
24
24
  /** Custom fetch implementation (useful for Node.js < 18) */
@@ -214,7 +214,27 @@ interface DataTable {
214
214
  /**
215
215
  * Main client interface
216
216
  *
217
+ * **IMPORTANT:** This is a TypeScript type definition, NOT a class constructor.
218
+ * Use the `createClient()` factory function to create client instances.
219
+ *
217
220
  * AI-friendly: Entry point with clear hierarchy
221
+ *
222
+ * @example Correct Usage
223
+ * ```typescript
224
+ * import { createClient } from '@seaverse/dataservice';
225
+ *
226
+ * // ✓ CORRECT - Use factory function
227
+ * const client = await createClient({});
228
+ * console.log(client.appId);
229
+ * ```
230
+ *
231
+ * @example INCORRECT Usage
232
+ * ```typescript
233
+ * import { DataServiceClient } from '@seaverse/dataservice';
234
+ *
235
+ * // ✗ WRONG - DataServiceClient is NOT a constructor
236
+ * const client = new DataServiceClient(); // This will throw an error!
237
+ * ```
218
238
  */
219
239
  interface DataServiceClient {
220
240
  /** Automatically extracted application ID from current URL */
@@ -261,21 +281,20 @@ declare function debugSetToken(token: string): void;
261
281
  /**
262
282
  * Create a new Data Service client
263
283
  *
284
+ * The SDK automatically obtains the service host from the parent page via PostMessage (500ms timeout).
285
+ * If the fetch fails, it falls back to the default host: https://dataservice-api.seaverse.ai
286
+ *
264
287
  * AI-friendly: Single entry point with clear configuration
265
288
  *
266
- * @param config - Client configuration
289
+ * @param config - Client configuration (optional)
267
290
  * @returns DataServiceClient instance
268
291
  *
269
292
  * @example
270
293
  * ```typescript
271
- * // Auto-fetch token from parent page (iframe)
294
+ * // Auto-fetch token and serviceHost from parent page (iframe)
295
+ * // ServiceHost fetch: 500ms timeout, falls back to https://dataservice-api.seaverse.ai
272
296
  * const client = await createClient({});
273
297
  *
274
- * // Custom endpoint
275
- * const client = await createClient({
276
- * url: 'https://your-postgrest-api.example.com',
277
- * });
278
- *
279
298
  * // For development/testing, use debugSetToken
280
299
  * import { debugSetToken, createClient } from '@seaverse/dataservice';
281
300
  * debugSetToken('your-test-token');
@@ -293,13 +312,15 @@ declare function createClient(config?: ClientConfig): Promise<DataServiceClient>
293
312
  *
294
313
  * AI-Friendly Universal Data Storage for TypeScript/JavaScript
295
314
  *
315
+ * **IMPORTANT:** This SDK uses a factory pattern. Use `createClient()` to create instances.
316
+ *
296
317
  * @packageDocumentation
297
318
  *
298
319
  * @example Basic Usage with Auto Token Fetch
299
320
  * ```typescript
300
321
  * import { createClient, debugSetToken } from '@seaverse/dataservice';
301
322
  *
302
- * // Auto-fetch token from parent page (iframe)
323
+ * // CORRECT - Use factory function
303
324
  * const client = await createClient({});
304
325
  *
305
326
  * // For development/testing, use debugSetToken
@@ -323,8 +344,15 @@ declare function createClient(config?: ClientConfig): Promise<DataServiceClient>
323
344
  * .limit(10)
324
345
  * .execute();
325
346
  * ```
347
+ *
348
+ * @example INCORRECT Usage - Do NOT do this
349
+ * ```typescript
350
+ * // ✗ WRONG - DataServiceClient is a type, not a constructor
351
+ * import { DataServiceClient } from '@seaverse/dataservice';
352
+ * const client = new DataServiceClient(); // This will fail!
353
+ * ```
326
354
  */
327
355
 
328
- declare const VERSION = "1.0.0";
356
+ declare const VERSION = "1.6.2";
329
357
 
330
358
  export { type APIError, type ClientConfig, type Collection, type DataRecord, type DataServiceClient, DataServiceError, type DataTable, type OrderOptions, type QueryBuilder, type QueryFilter, type UserDataStats, VERSION, createClient, debugSetToken };
package/dist/index.d.ts CHANGED
@@ -12,13 +12,13 @@
12
12
  * @example
13
13
  * ```typescript
14
14
  * const config: ClientConfig = {
15
- * url: 'https://dataservice-api.seaverse.ai',
15
+ * options: {
16
+ * timeout: 10000,
17
+ * }
16
18
  * };
17
19
  * ```
18
20
  */
19
21
  interface ClientConfig {
20
- /** PostgREST API base URL (default: https://dataservice-api.seaverse.ai) */
21
- url?: string;
22
22
  /** Optional configuration */
23
23
  options?: {
24
24
  /** Custom fetch implementation (useful for Node.js < 18) */
@@ -214,7 +214,27 @@ interface DataTable {
214
214
  /**
215
215
  * Main client interface
216
216
  *
217
+ * **IMPORTANT:** This is a TypeScript type definition, NOT a class constructor.
218
+ * Use the `createClient()` factory function to create client instances.
219
+ *
217
220
  * AI-friendly: Entry point with clear hierarchy
221
+ *
222
+ * @example Correct Usage
223
+ * ```typescript
224
+ * import { createClient } from '@seaverse/dataservice';
225
+ *
226
+ * // ✓ CORRECT - Use factory function
227
+ * const client = await createClient({});
228
+ * console.log(client.appId);
229
+ * ```
230
+ *
231
+ * @example INCORRECT Usage
232
+ * ```typescript
233
+ * import { DataServiceClient } from '@seaverse/dataservice';
234
+ *
235
+ * // ✗ WRONG - DataServiceClient is NOT a constructor
236
+ * const client = new DataServiceClient(); // This will throw an error!
237
+ * ```
218
238
  */
219
239
  interface DataServiceClient {
220
240
  /** Automatically extracted application ID from current URL */
@@ -261,21 +281,20 @@ declare function debugSetToken(token: string): void;
261
281
  /**
262
282
  * Create a new Data Service client
263
283
  *
284
+ * The SDK automatically obtains the service host from the parent page via PostMessage (500ms timeout).
285
+ * If the fetch fails, it falls back to the default host: https://dataservice-api.seaverse.ai
286
+ *
264
287
  * AI-friendly: Single entry point with clear configuration
265
288
  *
266
- * @param config - Client configuration
289
+ * @param config - Client configuration (optional)
267
290
  * @returns DataServiceClient instance
268
291
  *
269
292
  * @example
270
293
  * ```typescript
271
- * // Auto-fetch token from parent page (iframe)
294
+ * // Auto-fetch token and serviceHost from parent page (iframe)
295
+ * // ServiceHost fetch: 500ms timeout, falls back to https://dataservice-api.seaverse.ai
272
296
  * const client = await createClient({});
273
297
  *
274
- * // Custom endpoint
275
- * const client = await createClient({
276
- * url: 'https://your-postgrest-api.example.com',
277
- * });
278
- *
279
298
  * // For development/testing, use debugSetToken
280
299
  * import { debugSetToken, createClient } from '@seaverse/dataservice';
281
300
  * debugSetToken('your-test-token');
@@ -293,13 +312,15 @@ declare function createClient(config?: ClientConfig): Promise<DataServiceClient>
293
312
  *
294
313
  * AI-Friendly Universal Data Storage for TypeScript/JavaScript
295
314
  *
315
+ * **IMPORTANT:** This SDK uses a factory pattern. Use `createClient()` to create instances.
316
+ *
296
317
  * @packageDocumentation
297
318
  *
298
319
  * @example Basic Usage with Auto Token Fetch
299
320
  * ```typescript
300
321
  * import { createClient, debugSetToken } from '@seaverse/dataservice';
301
322
  *
302
- * // Auto-fetch token from parent page (iframe)
323
+ * // CORRECT - Use factory function
303
324
  * const client = await createClient({});
304
325
  *
305
326
  * // For development/testing, use debugSetToken
@@ -323,8 +344,15 @@ declare function createClient(config?: ClientConfig): Promise<DataServiceClient>
323
344
  * .limit(10)
324
345
  * .execute();
325
346
  * ```
347
+ *
348
+ * @example INCORRECT Usage - Do NOT do this
349
+ * ```typescript
350
+ * // ✗ WRONG - DataServiceClient is a type, not a constructor
351
+ * import { DataServiceClient } from '@seaverse/dataservice';
352
+ * const client = new DataServiceClient(); // This will fail!
353
+ * ```
326
354
  */
327
355
 
328
- declare const VERSION = "1.0.0";
356
+ declare const VERSION = "1.6.2";
329
357
 
330
358
  export { type APIError, type ClientConfig, type Collection, type DataRecord, type DataServiceClient, DataServiceError, type DataTable, type OrderOptions, type QueryBuilder, type QueryFilter, type UserDataStats, VERSION, createClient, debugSetToken };
package/dist/index.js CHANGED
@@ -88,6 +88,43 @@ async function getTokenFromParent(timeout = 5e3) {
88
88
  }
89
89
  });
90
90
  }
91
+ async function getServiceHostFromParent(timeout = 500, serviceName = "dataservice") {
92
+ if (!isInIframe()) {
93
+ return null;
94
+ }
95
+ return new Promise((resolve) => {
96
+ const messageHandler = (event) => {
97
+ if (event.data && event.data.type === "seaverse:service_host") {
98
+ cleanup();
99
+ const serviceHost = event.data.payload?.serviceHost;
100
+ resolve(serviceHost || null);
101
+ } else if (event.data && event.data.type === "seaverse:error") {
102
+ cleanup();
103
+ console.warn("[SeaVerse DataService SDK] Error getting serviceHost from parent:", event.data.error);
104
+ resolve(null);
105
+ }
106
+ };
107
+ const timeoutId = setTimeout(() => {
108
+ cleanup();
109
+ resolve(null);
110
+ }, timeout);
111
+ const cleanup = () => {
112
+ clearTimeout(timeoutId);
113
+ globalThis.window.removeEventListener("message", messageHandler);
114
+ };
115
+ globalThis.window.addEventListener("message", messageHandler);
116
+ try {
117
+ globalThis.window.parent.postMessage(
118
+ { type: "seaverse:get_service_host", payload: { serviceName } },
119
+ "*"
120
+ // Allow any origin, supports cross-domain scenarios
121
+ );
122
+ } catch (e) {
123
+ cleanup();
124
+ resolve(null);
125
+ }
126
+ });
127
+ }
91
128
  function extractAppId() {
92
129
  if (typeof globalThis !== "undefined" && "location" in globalThis) {
93
130
  const location = globalThis.location;
@@ -106,8 +143,9 @@ var HTTPClient = class {
106
143
  fetchFn;
107
144
  timeout;
108
145
  tokenPromise = null;
109
- constructor(config, token) {
110
- this.baseUrl = (config.url || "https://dataservice-api.seaverse.ai").replace(/\/$/, "");
146
+ constructor(config, token, serviceHost) {
147
+ const defaultHost = "https://dataservice-api.seaverse.ai";
148
+ this.baseUrl = (serviceHost || defaultHost).replace(/\/$/, "");
111
149
  const customFetch = config.options?.fetch;
112
150
  this.fetchFn = customFetch ? customFetch.bind(customFetch) : globalThis.fetch.bind(globalThis);
113
151
  this.timeout = config.options?.timeout || 3e4;
@@ -408,6 +446,7 @@ var DataServiceClientImpl = class {
408
446
  };
409
447
  async function createClient(config = {}) {
410
448
  let token = null;
449
+ let serviceHost = null;
411
450
  if (debugToken) {
412
451
  token = debugToken;
413
452
  } else {
@@ -419,13 +458,19 @@ async function createClient(config = {}) {
419
458
  token = null;
420
459
  }
421
460
  }
422
- const httpClient = new HTTPClient(config, token || void 0);
461
+ try {
462
+ serviceHost = await getServiceHostFromParent(500, "dataservice");
463
+ } catch (error) {
464
+ console.warn("[SeaVerse DataService SDK] Failed to fetch serviceHost:", error);
465
+ serviceHost = null;
466
+ }
467
+ const httpClient = new HTTPClient(config, token || void 0, serviceHost || void 0);
423
468
  const appId = extractAppId();
424
469
  return new DataServiceClientImpl(httpClient, appId);
425
470
  }
426
471
 
427
472
  // src/index.ts
428
- var VERSION = "1.0.0";
473
+ var VERSION = "1.6.2";
429
474
  // Annotate the CommonJS export names for ESM import in node:
430
475
  0 && (module.exports = {
431
476
  DataServiceError,
package/dist/index.mjs CHANGED
@@ -59,6 +59,43 @@ async function getTokenFromParent(timeout = 5e3) {
59
59
  }
60
60
  });
61
61
  }
62
+ async function getServiceHostFromParent(timeout = 500, serviceName = "dataservice") {
63
+ if (!isInIframe()) {
64
+ return null;
65
+ }
66
+ return new Promise((resolve) => {
67
+ const messageHandler = (event) => {
68
+ if (event.data && event.data.type === "seaverse:service_host") {
69
+ cleanup();
70
+ const serviceHost = event.data.payload?.serviceHost;
71
+ resolve(serviceHost || null);
72
+ } else if (event.data && event.data.type === "seaverse:error") {
73
+ cleanup();
74
+ console.warn("[SeaVerse DataService SDK] Error getting serviceHost from parent:", event.data.error);
75
+ resolve(null);
76
+ }
77
+ };
78
+ const timeoutId = setTimeout(() => {
79
+ cleanup();
80
+ resolve(null);
81
+ }, timeout);
82
+ const cleanup = () => {
83
+ clearTimeout(timeoutId);
84
+ globalThis.window.removeEventListener("message", messageHandler);
85
+ };
86
+ globalThis.window.addEventListener("message", messageHandler);
87
+ try {
88
+ globalThis.window.parent.postMessage(
89
+ { type: "seaverse:get_service_host", payload: { serviceName } },
90
+ "*"
91
+ // Allow any origin, supports cross-domain scenarios
92
+ );
93
+ } catch (e) {
94
+ cleanup();
95
+ resolve(null);
96
+ }
97
+ });
98
+ }
62
99
  function extractAppId() {
63
100
  if (typeof globalThis !== "undefined" && "location" in globalThis) {
64
101
  const location = globalThis.location;
@@ -77,8 +114,9 @@ var HTTPClient = class {
77
114
  fetchFn;
78
115
  timeout;
79
116
  tokenPromise = null;
80
- constructor(config, token) {
81
- this.baseUrl = (config.url || "https://dataservice-api.seaverse.ai").replace(/\/$/, "");
117
+ constructor(config, token, serviceHost) {
118
+ const defaultHost = "https://dataservice-api.seaverse.ai";
119
+ this.baseUrl = (serviceHost || defaultHost).replace(/\/$/, "");
82
120
  const customFetch = config.options?.fetch;
83
121
  this.fetchFn = customFetch ? customFetch.bind(customFetch) : globalThis.fetch.bind(globalThis);
84
122
  this.timeout = config.options?.timeout || 3e4;
@@ -379,6 +417,7 @@ var DataServiceClientImpl = class {
379
417
  };
380
418
  async function createClient(config = {}) {
381
419
  let token = null;
420
+ let serviceHost = null;
382
421
  if (debugToken) {
383
422
  token = debugToken;
384
423
  } else {
@@ -390,13 +429,19 @@ async function createClient(config = {}) {
390
429
  token = null;
391
430
  }
392
431
  }
393
- const httpClient = new HTTPClient(config, token || void 0);
432
+ try {
433
+ serviceHost = await getServiceHostFromParent(500, "dataservice");
434
+ } catch (error) {
435
+ console.warn("[SeaVerse DataService SDK] Failed to fetch serviceHost:", error);
436
+ serviceHost = null;
437
+ }
438
+ const httpClient = new HTTPClient(config, token || void 0, serviceHost || void 0);
394
439
  const appId = extractAppId();
395
440
  return new DataServiceClientImpl(httpClient, appId);
396
441
  }
397
442
 
398
443
  // src/index.ts
399
- var VERSION = "1.0.0";
444
+ var VERSION = "1.6.2";
400
445
  export {
401
446
  DataServiceError,
402
447
  VERSION,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seaverse/dataservice",
3
- "version": "1.6.1",
3
+ "version": "1.7.0",
4
4
  "description": "AI-Friendly Universal Data Storage SDK for TypeScript/JavaScript",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",