openclaw-abacusai-auth 1.2.5 → 1.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.
Files changed (2) hide show
  1. package/index.ts +78 -0
  2. package/package.json +1 -1
package/index.ts CHANGED
@@ -270,6 +270,8 @@ async function validateApiKey(
270
270
 
271
271
  let proxyServer: ReturnType<typeof createServer> | null = null;
272
272
  let proxyApiKey = "";
273
+ let activeProxyRequests = 0;
274
+ let proxyShuttingDown = false;
273
275
 
274
276
  function readBody(req: IncomingMessage): Promise<Buffer> {
275
277
  return new Promise((resolve, reject) => {
@@ -554,6 +556,19 @@ function normalizeResponseToolCalls(json: Record<string, unknown>): Record<strin
554
556
  }
555
557
 
556
558
  async function handleProxyRequest(req: IncomingMessage, res: ServerResponse) {
559
+ if (proxyShuttingDown) {
560
+ sendJsonResponse(res, 503, { error: { message: "Proxy is shutting down", type: "service_unavailable" } });
561
+ return;
562
+ }
563
+ activeProxyRequests++;
564
+ try {
565
+ await handleProxyRequestInner(req, res);
566
+ } finally {
567
+ activeProxyRequests--;
568
+ }
569
+ }
570
+
571
+ async function handleProxyRequestInner(req: IncomingMessage, res: ServerResponse) {
557
572
  const path = req.url ?? "/";
558
573
  const target = `${ROUTELLM_BASE}${path}`;
559
574
  const headers: Record<string, string> = {
@@ -718,6 +733,48 @@ function startProxy(apiKey: string): Promise<void> {
718
733
  });
719
734
  }
720
735
 
736
+ /**
737
+ * Gracefully stop the RouteLLM proxy server.
738
+ * 1. Stop accepting new connections
739
+ * 2. Wait for all in-flight requests to complete (up to 10s timeout)
740
+ * 3. Close the server and release the port
741
+ */
742
+ function stopProxy(): Promise<void> {
743
+ return new Promise((resolve) => {
744
+ if (!proxyServer) {
745
+ resolve();
746
+ return;
747
+ }
748
+
749
+ proxyShuttingDown = true;
750
+ console.log(`[abacusai] Proxy shutting down (${activeProxyRequests} active requests)...`);
751
+
752
+ // Stop accepting new connections immediately
753
+ proxyServer.close(() => {
754
+ console.log("[abacusai] Proxy server closed, port released.");
755
+ proxyServer = null;
756
+ proxyShuttingDown = false;
757
+ activeProxyRequests = 0;
758
+ resolve();
759
+ });
760
+
761
+ // Force-close after 10s if requests don't drain
762
+ const forceTimeout = setTimeout(() => {
763
+ console.warn(`[abacusai] Force-closing proxy (${activeProxyRequests} requests still active after 10s).`);
764
+ proxyServer?.closeAllConnections?.();
765
+ }, 10_000);
766
+
767
+ // Poll for active requests to finish, resolve early if all done
768
+ const drainInterval = setInterval(() => {
769
+ if (activeProxyRequests <= 0) {
770
+ clearInterval(drainInterval);
771
+ clearTimeout(forceTimeout);
772
+ // server.close callback will resolve
773
+ }
774
+ }, 200);
775
+ });
776
+ }
777
+
721
778
  // ---------------------------------------------------------------------------
722
779
  // Helpers
723
780
  // ---------------------------------------------------------------------------
@@ -818,11 +875,32 @@ const abacusaiPlugin = {
818
875
  register(api: unknown) {
819
876
  const pluginApi = api as {
820
877
  registerProvider: (config: unknown) => void;
878
+ registerHook?: (events: string | string[], handler: Function, opts?: { name?: string }) => void;
821
879
  config?: {
822
880
  models?: { providers?: { abacusai?: { compat?: { supportsStrictMode?: boolean } } } };
823
881
  };
824
882
  };
825
883
 
884
+ // ================================================================
885
+ // Register gateway_stop hook for graceful proxy shutdown
886
+ // ================================================================
887
+ if (typeof pluginApi.registerHook === "function") {
888
+ pluginApi.registerHook(
889
+ "gateway_stop",
890
+ async () => {
891
+ await stopProxy();
892
+ },
893
+ { name: "openclaw-abacusai-auth:gateway-stop" },
894
+ );
895
+ }
896
+
897
+ // Fallback: handle process signals if gateway_stop hook is unavailable
898
+ const shutdownHandler = () => {
899
+ stopProxy().then(() => process.exit(0));
900
+ };
901
+ process.once("SIGTERM", shutdownHandler);
902
+ process.once("SIGINT", shutdownHandler);
903
+
826
904
  // Use local proxy mode to handle schema cleaning internally
827
905
  // This is required because OpenClaw core may not support requiresCleanSchema yet
828
906
  // The proxy normalizes tool schemas before forwarding to RouteLLM
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-abacusai-auth",
3
- "version": "1.2.5",
3
+ "version": "1.2.6",
4
4
  "description": "OpenClaw AbacusAI provider plugin - Third-party plugin for AbacusAI RouteLLM integration",
5
5
  "type": "module",
6
6
  "main": "index.ts",