@appchy/jarvis 0.1.7 → 0.1.8

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/bin.js CHANGED
@@ -2519,17 +2519,77 @@ function createUpstreamClient(config) {
2519
2519
  let ws = null;
2520
2520
  let messageHandler = null;
2521
2521
  let reconnectTimer = null;
2522
+ let refreshTimer = null;
2522
2523
  let closed = false;
2523
2524
  let authFailures = 0;
2525
+ let retries = 0;
2526
+ let currentToken = config.token;
2524
2527
  const MAX_AUTH_RETRIES = 3;
2528
+ const MAX_RETRIES = 3;
2529
+ const REFRESH_BUFFER_MS = 5 * 60 * 1e3;
2530
+ function getRefreshUrl() {
2531
+ if (config.refreshUrl) return config.refreshUrl;
2532
+ if (!config.refreshToken) return null;
2533
+ return config.apiUrl.replace(/^wss:/, "https:").replace(/^ws:/, "http:") + "/refresh";
2534
+ }
2535
+ function getTokenExpiry(token) {
2536
+ try {
2537
+ const payload = JSON.parse(Buffer.from(token.split(".")[1], "base64").toString());
2538
+ return payload.exp ?? null;
2539
+ } catch {
2540
+ return null;
2541
+ }
2542
+ }
2543
+ function scheduleRefresh() {
2544
+ if (refreshTimer) clearTimeout(refreshTimer);
2545
+ if (!config.refreshToken) return;
2546
+ const exp = getTokenExpiry(currentToken);
2547
+ if (!exp) return;
2548
+ const msUntilExpiry = exp * 1e3 - Date.now();
2549
+ const refreshIn = Math.max(msUntilExpiry - REFRESH_BUFFER_MS, 0);
2550
+ logger.sys.info("[Upstream] Token refresh scheduled", {
2551
+ expiresIn: `${Math.round(msUntilExpiry / 1e3)}s`,
2552
+ refreshIn: `${Math.round(refreshIn / 1e3)}s`
2553
+ });
2554
+ refreshTimer = setTimeout(refreshToken, refreshIn);
2555
+ }
2556
+ async function refreshToken() {
2557
+ const url = getRefreshUrl();
2558
+ if (!url || !config.refreshToken) return false;
2559
+ try {
2560
+ logger.sys.info("[Upstream] Refreshing token...");
2561
+ const res = await fetch(url, {
2562
+ method: "POST",
2563
+ headers: { "Content-Type": "application/json" },
2564
+ body: JSON.stringify({ refreshToken: config.refreshToken })
2565
+ });
2566
+ if (!res.ok) {
2567
+ logger.sys.error("[Upstream] Token refresh failed", { status: res.status });
2568
+ return false;
2569
+ }
2570
+ const { token } = await res.json();
2571
+ currentToken = token;
2572
+ logger.sys.info("[Upstream] Token refreshed successfully");
2573
+ ws?.close();
2574
+ scheduleRefresh();
2575
+ return true;
2576
+ } catch (err) {
2577
+ logger.sys.error("[Upstream] Token refresh error", {
2578
+ error: err instanceof Error ? err.message : String(err)
2579
+ });
2580
+ return false;
2581
+ }
2582
+ }
2525
2583
  function connect() {
2526
2584
  if (closed) return;
2527
2585
  ws = new WebSocket2(config.apiUrl, {
2528
- headers: { authorization: `Bearer ${config.token}` }
2586
+ headers: { authorization: `Bearer ${currentToken}` }
2529
2587
  });
2530
2588
  ws.on("open", () => {
2531
2589
  authFailures = 0;
2590
+ retries = 0;
2532
2591
  logger.sys.info("[Upstream] Connected to cloud", { apiUrl: config.apiUrl });
2592
+ scheduleRefresh();
2533
2593
  });
2534
2594
  ws.on("message", (raw) => {
2535
2595
  try {
@@ -2545,6 +2605,24 @@ function createUpstreamClient(config) {
2545
2605
  ws.on("close", (code) => {
2546
2606
  if (closed) return;
2547
2607
  if (code === 4001 || code === 4003) {
2608
+ if (config.refreshToken) {
2609
+ refreshToken().then((ok) => {
2610
+ if (ok) {
2611
+ reconnectTimer = setTimeout(connect, 1e3);
2612
+ } else {
2613
+ authFailures++;
2614
+ if (authFailures >= MAX_AUTH_RETRIES) {
2615
+ logger.sys.error("[Upstream] Auth failed after max retries, giving up", {
2616
+ code,
2617
+ attempts: authFailures
2618
+ });
2619
+ return;
2620
+ }
2621
+ reconnectTimer = setTimeout(connect, 3e3);
2622
+ }
2623
+ });
2624
+ return;
2625
+ }
2548
2626
  authFailures++;
2549
2627
  if (authFailures >= MAX_AUTH_RETRIES) {
2550
2628
  logger.sys.error("[Upstream] Auth failed after max retries, giving up", {
@@ -2558,8 +2636,21 @@ function createUpstreamClient(config) {
2558
2636
  attempt: authFailures,
2559
2637
  maxRetries: MAX_AUTH_RETRIES
2560
2638
  });
2639
+ reconnectTimer = setTimeout(connect, 3e3);
2640
+ return;
2561
2641
  }
2562
- logger.sys.info("[Upstream] Disconnected, reconnecting in 3s...");
2642
+ retries++;
2643
+ if (retries >= MAX_RETRIES) {
2644
+ logger.sys.error("[Upstream] Max reconnect attempts reached, giving up", {
2645
+ attempts: retries
2646
+ });
2647
+ return;
2648
+ }
2649
+ logger.sys.info("[Upstream] Disconnected, reconnecting in 3s...", {
2650
+ code,
2651
+ attempt: retries,
2652
+ maxRetries: MAX_RETRIES
2653
+ });
2563
2654
  reconnectTimer = setTimeout(connect, 3e3);
2564
2655
  });
2565
2656
  ws.on("error", (err) => {
@@ -2582,6 +2673,7 @@ function createUpstreamClient(config) {
2582
2673
  function close() {
2583
2674
  closed = true;
2584
2675
  if (reconnectTimer) clearTimeout(reconnectTimer);
2676
+ if (refreshTimer) clearTimeout(refreshTimer);
2585
2677
  ws?.close();
2586
2678
  }
2587
2679
  return { connect, send, onMessage, isConnected, close };
@@ -4722,6 +4814,7 @@ function createCli() {
4722
4814
  ...existing,
4723
4815
  apiUrl: parsed.apiUrl,
4724
4816
  token: parsed.jwt,
4817
+ refreshToken: parsed.refreshToken,
4725
4818
  userId: parsed.userId,
4726
4819
  envId: parsed.envId,
4727
4820
  ...opts.workspace ? { workspacePath: opts.workspace } : {},
@@ -4761,7 +4854,14 @@ function createCli() {
4761
4854
  anthropicApiKey,
4762
4855
  useSubscription: !anthropicApiKey,
4763
4856
  userId,
4764
- upstream: opts.upstream && config?.apiUrl && config?.token ? { apiUrl: config.apiUrl, token: config.token } : void 0
4857
+ upstream: (() => {
4858
+ const apiUrl = process.env.JARVIS_UPSTREAM_URL ?? config?.apiUrl;
4859
+ const token = process.env.JARVIS_UPSTREAM_TOKEN ?? config?.token;
4860
+ if (opts.upstream && apiUrl && token) {
4861
+ return { apiUrl, token, refreshToken: config?.refreshToken };
4862
+ }
4863
+ return void 0;
4864
+ })()
4765
4865
  });
4766
4866
  return;
4767
4867
  }