@seaverse/dataservice 1.6.2 → 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
@@ -55,10 +55,13 @@ const client = new DataServiceClient(); // This will fail!
55
55
 
56
56
  The SDK uses a **factory function pattern**. Always use `createClient()`:
57
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
+
58
60
  ```typescript
59
61
  import { createClient, debugSetToken } from '@seaverse/dataservice';
60
62
 
61
- // Production: Auto-fetch token from parent page (when running in 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
62
65
  const client = await createClient({});
63
66
 
64
67
  // Development/Testing: Use debug token
@@ -308,7 +311,6 @@ interface DataRecord<T> {
308
311
  import { createClient } from '@seaverse/dataservice';
309
312
 
310
313
  const client = await createClient({
311
- url?: string; // PostgREST API URL (default: https://dataservice-api.seaverse.ai)
312
314
  options?: {
313
315
  timeout?: number; // Request timeout in ms (default: 30000)
314
316
  tokenFetchTimeout?: number; // Token fetch timeout in ms (default: 5000)
@@ -317,6 +319,14 @@ const client = await createClient({
317
319
  });
318
320
  ```
319
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
+
320
330
  **Token Authentication Priority:**
321
331
 
322
332
  The SDK uses the following priority order for obtaining authentication tokens:
@@ -327,16 +337,22 @@ The SDK uses the following priority order for obtaining authentication tokens:
327
337
 
328
338
  **Production Usage (Auto-fetch from parent):**
329
339
 
330
- 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:
331
341
 
332
342
  ```typescript
333
- // No token needed - auto-fetches from parent
343
+ // No configuration needed - auto-fetches token and serviceHost from parent
334
344
  const client = await createClient({});
335
345
 
336
346
  // Parent page should respond to PostMessage:
347
+ // Token request:
337
348
  // Send: { type: 'seaverse:get_token' }
338
349
  // Receive: { type: 'seaverse:token', payload: { accessToken: string, expiresIn: number } }
339
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 }
340
356
  ```
341
357
 
342
358
  **Development/Testing (Debug Token):**
@@ -355,10 +371,13 @@ const client = await createClient({});
355
371
 
356
372
  **Graceful Degradation:**
357
373
 
358
- 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`
359
378
 
360
379
  ```typescript
361
- // Client creation never throws, even if token fetch fails
380
+ // Client creation never throws, even if fetch fails
362
381
  const client = await createClient({});
363
382
 
364
383
  try {
@@ -372,15 +391,6 @@ try {
372
391
  }
373
392
  ```
374
393
 
375
- **Custom Endpoint:**
376
-
377
- ```typescript
378
- // Use custom API endpoint
379
- const client = await createClient({
380
- url: 'https://your-custom-api.example.com',
381
- });
382
- ```
383
-
384
394
  ### DataTable Methods
385
395
 
386
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) */
@@ -281,21 +281,20 @@ declare function debugSetToken(token: string): void;
281
281
  /**
282
282
  * Create a new Data Service client
283
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
+ *
284
287
  * AI-friendly: Single entry point with clear configuration
285
288
  *
286
- * @param config - Client configuration
289
+ * @param config - Client configuration (optional)
287
290
  * @returns DataServiceClient instance
288
291
  *
289
292
  * @example
290
293
  * ```typescript
291
- * // 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
292
296
  * const client = await createClient({});
293
297
  *
294
- * // Custom endpoint
295
- * const client = await createClient({
296
- * url: 'https://your-postgrest-api.example.com',
297
- * });
298
- *
299
298
  * // For development/testing, use debugSetToken
300
299
  * import { debugSetToken, createClient } from '@seaverse/dataservice';
301
300
  * debugSetToken('your-test-token');
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) */
@@ -281,21 +281,20 @@ declare function debugSetToken(token: string): void;
281
281
  /**
282
282
  * Create a new Data Service client
283
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
+ *
284
287
  * AI-friendly: Single entry point with clear configuration
285
288
  *
286
- * @param config - Client configuration
289
+ * @param config - Client configuration (optional)
287
290
  * @returns DataServiceClient instance
288
291
  *
289
292
  * @example
290
293
  * ```typescript
291
- * // 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
292
296
  * const client = await createClient({});
293
297
  *
294
- * // Custom endpoint
295
- * const client = await createClient({
296
- * url: 'https://your-postgrest-api.example.com',
297
- * });
298
- *
299
298
  * // For development/testing, use debugSetToken
300
299
  * import { debugSetToken, createClient } from '@seaverse/dataservice';
301
300
  * debugSetToken('your-test-token');
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,7 +458,13 @@ 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
  }
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,7 +429,13 @@ 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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seaverse/dataservice",
3
- "version": "1.6.2",
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",