orchestrator-client 5.7.1 → 5.7.3

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.cjs CHANGED
@@ -148,6 +148,7 @@ var OrchestratorAsync = class {
148
148
  this._getToken = opts.getToken;
149
149
  this._timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
150
150
  this._maxRetries = opts.maxRetries ?? DEFAULT_MAX_RETRIES;
151
+ this._locale = opts.locale;
151
152
  this._fetch = opts.fetch ?? globalThis.fetch;
152
153
  if (opts.insecure && !opts.fetch && typeof process !== "undefined" && process.versions?.node) {
153
154
  this._insecure = true;
@@ -172,6 +173,9 @@ var OrchestratorAsync = class {
172
173
  headers.Authorization = `Bearer ${token}`;
173
174
  }
174
175
  }
176
+ if (this._locale) {
177
+ headers["X-Locale"] = this._locale;
178
+ }
175
179
  return headers;
176
180
  }
177
181
  async _request(method, path, opts) {
@@ -402,10 +406,9 @@ var OrchestratorAsync = class {
402
406
  );
403
407
  }
404
408
  async getTaskCompactions(taskId) {
405
- const data = await this._get("/task/compactions", {
409
+ return this._get("/task/compactions", {
406
410
  task_id: taskId
407
411
  });
408
- return data.compactions ?? [];
409
412
  }
410
413
  async getTaskJournal(taskId) {
411
414
  const data = await this._get("/task/journal", {
@@ -982,8 +985,10 @@ var OrchestratorAsync = class {
982
985
  async getErrorDetail(errorId) {
983
986
  return this._get(`/errors/${errorId}`);
984
987
  }
985
- async getErrorStats(since) {
986
- const params = {};
988
+ async getErrorStats(since, topN = 10) {
989
+ const params = {
990
+ top_n: topN
991
+ };
987
992
  if (since) params.since = since;
988
993
  return this._get("/errors/stats", params);
989
994
  }
@@ -1693,9 +1698,15 @@ var RealtimeClient = class {
1693
1698
  this._socket = null;
1694
1699
  this._handlers = /* @__PURE__ */ new Map();
1695
1700
  this._connected = false;
1701
+ // Multi-subscriber room-diffing state (mirrors WebSocketProvider)
1702
+ this._subscriptions = /* @__PURE__ */ new Map();
1703
+ this._currentRooms = /* @__PURE__ */ new Set();
1704
+ this._subIdCounter = 0;
1696
1705
  this._baseUrl = baseUrl.replace(/\/+$/, "");
1697
1706
  this._socketOptions = opts.socketOptions ?? {};
1698
1707
  this._getToken = opts.getToken;
1708
+ this._clientId = opts.clientId ?? "orchestrator-client";
1709
+ this._locale = opts.locale;
1699
1710
  if (opts.autoConnect) {
1700
1711
  this.connect();
1701
1712
  }
@@ -1708,18 +1719,26 @@ var RealtimeClient = class {
1708
1719
  if (this._getToken) {
1709
1720
  auth.token = typeof this._getToken === "function" ? await this._getToken() : this._getToken;
1710
1721
  }
1722
+ const query = { client_id: this._clientId };
1723
+ if (this._locale) {
1724
+ query.locale = this._locale;
1725
+ }
1711
1726
  const { io } = await import("socket.io-client");
1712
1727
  this._socket = io(this._baseUrl, {
1713
1728
  path: "/socket.io",
1714
1729
  auth,
1730
+ query,
1715
1731
  transports: ["websocket", "polling"],
1716
1732
  ...this._socketOptions
1717
1733
  });
1718
1734
  this._socket.on("connect", () => {
1719
1735
  this._connected = true;
1736
+ this._currentRooms = /* @__PURE__ */ new Set();
1737
+ this._syncRooms();
1720
1738
  });
1721
1739
  this._socket.on("disconnect", () => {
1722
1740
  this._connected = false;
1741
+ this._currentRooms = /* @__PURE__ */ new Set();
1723
1742
  });
1724
1743
  this._socket.on("message", (payload) => this._dispatch(payload));
1725
1744
  return new Promise((resolve, reject) => {
@@ -1742,7 +1761,7 @@ var RealtimeClient = class {
1742
1761
  this._connected = false;
1743
1762
  }
1744
1763
  /**
1745
- * Dispatch a message envelope to registered handlers.
1764
+ * Dispatch a message envelope to registered handlers and subscribers.
1746
1765
  * The server sends: socket.emit("message", {type: "message", event: {..., event_type: "...", ...}})
1747
1766
  */
1748
1767
  _dispatch(payload) {
@@ -1756,6 +1775,9 @@ var RealtimeClient = class {
1756
1775
  h(event);
1757
1776
  }
1758
1777
  }
1778
+ for (const sub of this._subscriptions.values()) {
1779
+ sub.handler(event);
1780
+ }
1759
1781
  }
1760
1782
  /**
1761
1783
  * Subscribe to realtime events for a specific task.
@@ -1825,6 +1847,64 @@ var RealtimeClient = class {
1825
1847
  if (!this._socket) throw new Error("RealtimeClient not connected");
1826
1848
  this._socket.emit("leave", { rooms });
1827
1849
  }
1850
+ // ------------------------------------------------------------------
1851
+ // Multi-subscriber API (mirrors WebSocketProvider room-diffing)
1852
+ // ------------------------------------------------------------------
1853
+ /**
1854
+ * Register a subscriber that receives all events from the given rooms.
1855
+ *
1856
+ * Room membership is managed automatically: the client joins the union
1857
+ * of all active subscribers' rooms and leaves rooms that are no longer
1858
+ * needed when the last subscriber referencing them is removed.
1859
+ *
1860
+ * The `handler` receives the unwrapped event dict (same object that
1861
+ * `on()` handlers receive).
1862
+ *
1863
+ * Returns an opaque subscription id that must be passed to
1864
+ * `unsubscribe()` to remove the subscription.
1865
+ *
1866
+ * Example — mirror the webui's per-component subscription pattern:
1867
+ *
1868
+ * const id = rt.subscribe((event) => {
1869
+ * if (event.event_type === "task_status_changed") { ... }
1870
+ * }, [`task:${taskId}`]);
1871
+ *
1872
+ * // later, on cleanup:
1873
+ * rt.unsubscribe(id);
1874
+ */
1875
+ subscribe(handler, rooms) {
1876
+ const id = `sub_${++this._subIdCounter}`;
1877
+ this._subscriptions.set(id, { handler, rooms });
1878
+ this._syncRooms();
1879
+ return id;
1880
+ }
1881
+ /**
1882
+ * Remove a subscription registered via `subscribe()`.
1883
+ *
1884
+ * Rooms that are no longer referenced by any remaining subscriber are
1885
+ * left automatically.
1886
+ */
1887
+ unsubscribe(id) {
1888
+ this._subscriptions.delete(id);
1889
+ this._syncRooms();
1890
+ }
1891
+ /**
1892
+ * Diff the union of all subscribers' rooms against the currently joined
1893
+ * rooms and emit `join`/`leave` for the delta. No-ops when not connected.
1894
+ */
1895
+ _syncRooms() {
1896
+ const socket = this._socket;
1897
+ if (!socket?.connected) return;
1898
+ const needed = /* @__PURE__ */ new Set();
1899
+ for (const sub of this._subscriptions.values()) {
1900
+ for (const r of sub.rooms) needed.add(r);
1901
+ }
1902
+ const toJoin = [...needed].filter((r) => !this._currentRooms.has(r));
1903
+ const toLeave = [...this._currentRooms].filter((r) => !needed.has(r));
1904
+ if (toJoin.length) socket.emit("join", { rooms: toJoin });
1905
+ if (toLeave.length) socket.emit("leave", { rooms: toLeave });
1906
+ this._currentRooms = needed;
1907
+ }
1828
1908
  /**
1829
1909
  * Send a ping to the server.
1830
1910
  */