@yushaw/sanqian-sdk 0.3.21 → 0.3.23

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.mjs CHANGED
@@ -502,6 +502,8 @@ var SanqianSDK = class _SanqianSDK {
502
502
  ]);
503
503
  // Connection promise for deduplication (prevents multiple concurrent connect attempts)
504
504
  connectingPromise = null;
505
+ // HTTP readiness promise for deduplication (prevents concurrent discovery/launch)
506
+ httpReadyPromise = null;
505
507
  // Reconnect reference count - when > 0, auto-reconnect is enabled
506
508
  // This allows multiple components to request persistent connections
507
509
  reconnectRefCount = 0;
@@ -628,6 +630,38 @@ var SanqianSDK = class _SanqianSDK {
628
630
  const token = info?.token;
629
631
  return token ? { "X-App-Token": token } : {};
630
632
  }
633
+ async ensureHttpReady() {
634
+ if (this.connectionInfo || this.config.connectionInfo) {
635
+ return;
636
+ }
637
+ if (this.httpReadyPromise) {
638
+ this.log("HTTP readiness already in progress, waiting...");
639
+ return this.httpReadyPromise;
640
+ }
641
+ this.httpReadyPromise = this.doEnsureHttpReady();
642
+ try {
643
+ await this.httpReadyPromise;
644
+ } finally {
645
+ this.httpReadyPromise = null;
646
+ }
647
+ }
648
+ async doEnsureHttpReady() {
649
+ const discovery = await this.getDiscovery();
650
+ let info = discovery.read();
651
+ if (!info) {
652
+ if (!this.config.autoLaunchSanqian) {
653
+ throw createSDKError("NOT_RUNNING" /* NOT_RUNNING */);
654
+ }
655
+ this.log("Sanqian not running, attempting to launch for HTTP API...");
656
+ const launched = discovery.launchSanqian(this.config.sanqianPath);
657
+ if (!launched) {
658
+ throw createSDKError("NOT_INSTALLED" /* NOT_INSTALLED */);
659
+ }
660
+ this.log("Sanqian launch initiated, waiting for startup...");
661
+ info = await this.waitForSanqianStartup();
662
+ }
663
+ this.connectionInfo = info;
664
+ }
631
665
  /**
632
666
  * Get the port number for the Sanqian backend
633
667
  * @throws Error if not connected
@@ -639,6 +673,14 @@ var SanqianSDK = class _SanqianSDK {
639
673
  }
640
674
  return info.port;
641
675
  }
676
+ /**
677
+ * Get the HTTP base URL for Sanqian backend.
678
+ *
679
+ * @throws Error if connection info is not available
680
+ */
681
+ getBaseUrl() {
682
+ return this.getHttpBaseUrl();
683
+ }
642
684
  constructor(config) {
643
685
  const requestedSecurityLevel = this.normalizeRequestedSecurityLevel(
644
686
  config.requestedSecurityLevel
@@ -1529,26 +1571,10 @@ var SanqianSDK = class _SanqianSDK {
1529
1571
  */
1530
1572
  async doFullConnect() {
1531
1573
  this.log("Starting full connection flow...");
1532
- let info = null;
1533
- if (this.config.connectionInfo) {
1534
- this.log("Using pre-configured connection info (browser mode)");
1535
- info = this.config.connectionInfo;
1536
- } else {
1537
- const discovery = await this.getDiscovery();
1538
- info = discovery.read();
1539
- if (!info) {
1540
- if (this.config.autoLaunchSanqian) {
1541
- this.log("Sanqian not running, attempting to launch...");
1542
- const launched = discovery.launchSanqian(this.config.sanqianPath);
1543
- if (!launched) {
1544
- throw createSDKError("NOT_INSTALLED" /* NOT_INSTALLED */);
1545
- }
1546
- this.log("Sanqian launch initiated, waiting for startup...");
1547
- info = await this.waitForSanqianStartup();
1548
- } else {
1549
- throw createSDKError("NOT_RUNNING" /* NOT_RUNNING */);
1550
- }
1551
- }
1574
+ await this.ensureHttpReady();
1575
+ const info = this.connectionInfo || this.config.connectionInfo;
1576
+ if (!info) {
1577
+ throw createSDKError("NOT_RUNNING" /* NOT_RUNNING */);
1552
1578
  }
1553
1579
  await this.connectWithInfo(info);
1554
1580
  }
@@ -2437,7 +2463,7 @@ var SanqianSDK = class _SanqianSDK {
2437
2463
  // Channels
2438
2464
  // ============================================
2439
2465
  async listChannelPlugins() {
2440
- await this.ensureReady();
2466
+ await this.ensureHttpReady();
2441
2467
  const url = `${this.getHttpBaseUrl()}/api/channels/plugins`;
2442
2468
  const response = await fetch(url, { headers: this.getHttpAuthHeaders() });
2443
2469
  if (!response.ok) {
@@ -2446,7 +2472,7 @@ var SanqianSDK = class _SanqianSDK {
2446
2472
  return response.json();
2447
2473
  }
2448
2474
  async listChannelAccounts() {
2449
- await this.ensureReady();
2475
+ await this.ensureHttpReady();
2450
2476
  const url = `${this.getHttpBaseUrl()}/api/channels/accounts`;
2451
2477
  const response = await fetch(url, { headers: this.getHttpAuthHeaders() });
2452
2478
  if (!response.ok) {
@@ -2455,7 +2481,7 @@ var SanqianSDK = class _SanqianSDK {
2455
2481
  return response.json();
2456
2482
  }
2457
2483
  async createChannelAccount(req) {
2458
- await this.ensureReady();
2484
+ await this.ensureHttpReady();
2459
2485
  const url = `${this.getHttpBaseUrl()}/api/channels/accounts`;
2460
2486
  const response = await fetch(url, {
2461
2487
  method: "POST",
@@ -2469,7 +2495,7 @@ var SanqianSDK = class _SanqianSDK {
2469
2495
  return response.json();
2470
2496
  }
2471
2497
  async getChannelAccount(id) {
2472
- await this.ensureReady();
2498
+ await this.ensureHttpReady();
2473
2499
  const url = `${this.getHttpBaseUrl()}/api/channels/accounts/${encodeURIComponent(id)}`;
2474
2500
  const response = await fetch(url, { headers: this.getHttpAuthHeaders() });
2475
2501
  if (!response.ok) {
@@ -2478,7 +2504,7 @@ var SanqianSDK = class _SanqianSDK {
2478
2504
  return response.json();
2479
2505
  }
2480
2506
  async updateChannelAccount(id, req) {
2481
- await this.ensureReady();
2507
+ await this.ensureHttpReady();
2482
2508
  const url = `${this.getHttpBaseUrl()}/api/channels/accounts/${encodeURIComponent(id)}`;
2483
2509
  const response = await fetch(url, {
2484
2510
  method: "PUT",
@@ -2492,7 +2518,7 @@ var SanqianSDK = class _SanqianSDK {
2492
2518
  return response.json();
2493
2519
  }
2494
2520
  async deleteChannelAccount(id) {
2495
- await this.ensureReady();
2521
+ await this.ensureHttpReady();
2496
2522
  const url = `${this.getHttpBaseUrl()}/api/channels/accounts/${encodeURIComponent(id)}`;
2497
2523
  const response = await fetch(url, { method: "DELETE", headers: this.getHttpAuthHeaders() });
2498
2524
  if (!response.ok) {
@@ -2500,7 +2526,7 @@ var SanqianSDK = class _SanqianSDK {
2500
2526
  }
2501
2527
  }
2502
2528
  async startChannelAccount(id) {
2503
- await this.ensureReady();
2529
+ await this.ensureHttpReady();
2504
2530
  const url = `${this.getHttpBaseUrl()}/api/channels/accounts/${encodeURIComponent(id)}/start`;
2505
2531
  const response = await fetch(url, { method: "POST", headers: this.getHttpAuthHeaders() });
2506
2532
  if (!response.ok) {
@@ -2510,7 +2536,7 @@ var SanqianSDK = class _SanqianSDK {
2510
2536
  return response.json();
2511
2537
  }
2512
2538
  async stopChannelAccount(id) {
2513
- await this.ensureReady();
2539
+ await this.ensureHttpReady();
2514
2540
  const url = `${this.getHttpBaseUrl()}/api/channels/accounts/${encodeURIComponent(id)}/stop`;
2515
2541
  const response = await fetch(url, { method: "POST", headers: this.getHttpAuthHeaders() });
2516
2542
  if (!response.ok) {
@@ -2519,7 +2545,7 @@ var SanqianSDK = class _SanqianSDK {
2519
2545
  return response.json();
2520
2546
  }
2521
2547
  async getChannelStatus(id) {
2522
- await this.ensureReady();
2548
+ await this.ensureHttpReady();
2523
2549
  const url = `${this.getHttpBaseUrl()}/api/channels/accounts/${encodeURIComponent(id)}/status`;
2524
2550
  const response = await fetch(url, { headers: this.getHttpAuthHeaders() });
2525
2551
  if (!response.ok) {
@@ -2528,7 +2554,7 @@ var SanqianSDK = class _SanqianSDK {
2528
2554
  return response.json();
2529
2555
  }
2530
2556
  async probeChannelAccount(id) {
2531
- await this.ensureReady();
2557
+ await this.ensureHttpReady();
2532
2558
  const url = `${this.getHttpBaseUrl()}/api/channels/accounts/${encodeURIComponent(id)}/probe`;
2533
2559
  const response = await fetch(url, { method: "POST", headers: this.getHttpAuthHeaders() });
2534
2560
  if (!response.ok) {
@@ -2537,8 +2563,32 @@ var SanqianSDK = class _SanqianSDK {
2537
2563
  }
2538
2564
  return response.json();
2539
2565
  }
2566
+ async probeChannelConfig(req) {
2567
+ await this.ensureHttpReady();
2568
+ const url = `${this.getHttpBaseUrl()}/api/channels/probe-config`;
2569
+ const response = await fetch(url, {
2570
+ method: "POST",
2571
+ headers: { ...this.getHttpAuthHeaders(), "Content-Type": "application/json" },
2572
+ body: JSON.stringify(req)
2573
+ });
2574
+ if (!response.ok) {
2575
+ const detail = await response.text();
2576
+ throw createSDKError("REQUEST_FAILED" /* REQUEST_FAILED */, `Failed to probe channel config: ${detail}`);
2577
+ }
2578
+ return response.json();
2579
+ }
2580
+ async getChannelConfigSchema(channelType) {
2581
+ await this.ensureHttpReady();
2582
+ const url = `${this.getHttpBaseUrl()}/api/channels/plugins/${encodeURIComponent(channelType)}/config-schema`;
2583
+ const response = await fetch(url, { headers: this.getHttpAuthHeaders() });
2584
+ if (!response.ok) {
2585
+ const detail = await response.text();
2586
+ throw createSDKError("REQUEST_FAILED" /* REQUEST_FAILED */, `Failed to get channel config schema: ${detail}`);
2587
+ }
2588
+ return response.json();
2589
+ }
2540
2590
  async listChannelBindings(accountId) {
2541
- await this.ensureReady();
2591
+ await this.ensureHttpReady();
2542
2592
  const params = accountId ? `?account_id=${encodeURIComponent(accountId)}` : "";
2543
2593
  const url = `${this.getHttpBaseUrl()}/api/channels/bindings${params}`;
2544
2594
  const response = await fetch(url, { headers: this.getHttpAuthHeaders() });
@@ -2548,7 +2598,7 @@ var SanqianSDK = class _SanqianSDK {
2548
2598
  return response.json();
2549
2599
  }
2550
2600
  async createChannelBinding(req) {
2551
- await this.ensureReady();
2601
+ await this.ensureHttpReady();
2552
2602
  const url = `${this.getHttpBaseUrl()}/api/channels/bindings`;
2553
2603
  const response = await fetch(url, {
2554
2604
  method: "POST",
@@ -2562,7 +2612,7 @@ var SanqianSDK = class _SanqianSDK {
2562
2612
  return response.json();
2563
2613
  }
2564
2614
  async updateChannelBinding(id, req) {
2565
- await this.ensureReady();
2615
+ await this.ensureHttpReady();
2566
2616
  const url = `${this.getHttpBaseUrl()}/api/channels/bindings/${encodeURIComponent(id)}`;
2567
2617
  const response = await fetch(url, {
2568
2618
  method: "PUT",
@@ -2576,7 +2626,7 @@ var SanqianSDK = class _SanqianSDK {
2576
2626
  return response.json();
2577
2627
  }
2578
2628
  async deleteChannelBinding(id) {
2579
- await this.ensureReady();
2629
+ await this.ensureHttpReady();
2580
2630
  const url = `${this.getHttpBaseUrl()}/api/channels/bindings/${encodeURIComponent(id)}`;
2581
2631
  const response = await fetch(url, { method: "DELETE", headers: this.getHttpAuthHeaders() });
2582
2632
  if (!response.ok) {
@@ -2584,7 +2634,7 @@ var SanqianSDK = class _SanqianSDK {
2584
2634
  }
2585
2635
  }
2586
2636
  async sendChannelMessage(req) {
2587
- await this.ensureReady();
2637
+ await this.ensureHttpReady();
2588
2638
  const url = `${this.getHttpBaseUrl()}/api/channels/send`;
2589
2639
  const response = await fetch(url, {
2590
2640
  method: "POST",