@fdcn/sourcefed 0.3.6 → 0.3.7

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/cli.js CHANGED
@@ -11363,36 +11363,10 @@ async function writeResponse(outgoing, response) {
11363
11363
  stream.pipe(outgoing);
11364
11364
  });
11365
11365
  }
11366
- var RequestRouter = class {
11367
- pending = /* @__PURE__ */ new Map();
11368
- cursor = 1;
11369
- nextID() {
11370
- return this.cursor++;
11371
- }
11372
- register(id) {
11373
- return new Promise((resolve, reject) => {
11374
- this.pending.set(id, { resolve, reject });
11375
- });
11376
- }
11377
- settle(id, frame) {
11378
- const pending = this.pending.get(id);
11379
- if (!pending) return;
11380
- this.pending.delete(id);
11381
- if (frame.error) pending.reject(new Error(frame.error));
11382
- else pending.resolve(frame.result);
11383
- }
11384
- rejectAll(error2) {
11385
- for (const { reject } of this.pending.values()) reject(error2);
11386
- this.pending.clear();
11387
- }
11388
- };
11389
11366
  function defaultDaemonUrl() {
11390
11367
  const port = process.env.SOURCEFED_DAEMON_PORT ?? 18787;
11391
11368
  return `http://127.0.0.1:${port}`;
11392
11369
  }
11393
- function sleep(ms) {
11394
- return new Promise((resolve) => setTimeout(resolve, ms));
11395
- }
11396
11370
  async function withTimeout(promise, ms, message) {
11397
11371
  let timer;
11398
11372
  try {
@@ -11725,164 +11699,225 @@ function parseDaemonFrame(line) {
11725
11699
  return void 0;
11726
11700
  }
11727
11701
  }
11702
+ var DaemonEventStream = class {
11703
+ constructor(url2, headers, onEvents, acknowledge, onClose) {
11704
+ this.url = url2;
11705
+ this.headers = headers;
11706
+ this.onEvents = onEvents;
11707
+ this.acknowledge = acknowledge;
11708
+ this.onClose = onClose;
11709
+ }
11710
+ controller = new AbortController();
11711
+ subscribed = Promise.withResolvers();
11712
+ stream;
11713
+ delivering = Promise.resolve();
11714
+ closing;
11715
+ ready = false;
11716
+ failedDelivery = false;
11717
+ async start(signal) {
11718
+ const abort = () => {
11719
+ void this.close();
11720
+ };
11721
+ signal?.addEventListener("abort", abort, { once: true });
11722
+ const setup = withTimeout(this.subscribed.promise, 15e3, `sourcefed event stream did not subscribe at ${this.url}`);
11723
+ if (signal?.aborted) abort();
11724
+ const running = this.run();
11725
+ void running.finally(() => signal?.removeEventListener("abort", abort));
11726
+ try {
11727
+ await setup;
11728
+ } catch (error2) {
11729
+ await this.close();
11730
+ throw error2;
11731
+ }
11732
+ }
11733
+ close() {
11734
+ if (!this.closing) {
11735
+ this.subscribed.reject(new Error("sourcefed event stream closed"));
11736
+ if (!this.ready) this.controller.abort();
11737
+ this.closing = this.drain();
11738
+ }
11739
+ return this.closing;
11740
+ }
11741
+ async drain() {
11742
+ try {
11743
+ await withTimeout(this.delivering, 15e3, "sourcefed event delivery did not drain");
11744
+ } catch (error2) {
11745
+ console.error(`[sourcefed] closing event stream: ${String(error2)}`);
11746
+ } finally {
11747
+ this.controller.abort();
11748
+ this.stream?.abort();
11749
+ this.onClose();
11750
+ }
11751
+ }
11752
+ async run() {
11753
+ let consecutiveFailures = 0;
11754
+ while (!this.controller.signal.aborted) {
11755
+ this.failedDelivery = false;
11756
+ try {
11757
+ await this.read();
11758
+ consecutiveFailures = 0;
11759
+ } catch (error2) {
11760
+ if (!this.controller.signal.aborted && !this.failedDelivery && ++consecutiveFailures === 1) {
11761
+ console.error(`[sourcefed] event stream ended: ${String(error2)}`);
11762
+ }
11763
+ }
11764
+ await this.waitForDelivery();
11765
+ if (!this.controller.signal.aborted) await pause(500, this.controller.signal);
11766
+ }
11767
+ }
11768
+ async read() {
11769
+ const controller = new AbortController();
11770
+ const abort = () => controller.abort();
11771
+ this.stream = controller;
11772
+ this.controller.signal.addEventListener("abort", abort, { once: true });
11773
+ let reader;
11774
+ try {
11775
+ this.controller.signal.throwIfAborted();
11776
+ const response = await fetch(this.url, { signal: controller.signal, headers: this.headers });
11777
+ if (!response.ok || !response.body) {
11778
+ await response.body?.cancel();
11779
+ throw new Error(`event stream failed: ${response.status}`);
11780
+ }
11781
+ reader = response.body.getReader();
11782
+ const decoder = new TextDecoder();
11783
+ let buffer = "";
11784
+ while (!controller.signal.aborted) {
11785
+ const { done, value } = await reader.read();
11786
+ if (done) return;
11787
+ buffer += decoder.decode(value, { stream: true });
11788
+ const frames = buffer.split("\n\n");
11789
+ buffer = frames.pop() ?? "";
11790
+ for (const chunk of frames) await this.frame(chunk);
11791
+ }
11792
+ } finally {
11793
+ await reader?.cancel().catch(() => void 0);
11794
+ reader?.releaseLock();
11795
+ this.controller.signal.removeEventListener("abort", abort);
11796
+ if (this.stream === controller) this.stream = void 0;
11797
+ }
11798
+ }
11799
+ async frame(chunk) {
11800
+ if (this.closing || this.controller.signal.aborted) return;
11801
+ for (const line of chunk.split("\n")) {
11802
+ if (!line.startsWith("data: ")) continue;
11803
+ const frame = parseDaemonFrame(line.slice(6));
11804
+ if (!frame || !("type" in frame)) continue;
11805
+ if (frame.type === "subscribed") {
11806
+ this.ready = true;
11807
+ this.subscribed.resolve();
11808
+ }
11809
+ if (frame.type === "event" && frame.events.length > 0) {
11810
+ this.deliver(frame.events);
11811
+ await this.waitForDelivery();
11812
+ }
11813
+ }
11814
+ }
11815
+ deliver(events2) {
11816
+ this.delivering = this.delivering.then(async () => {
11817
+ if (this.failedDelivery || this.controller.signal.aborted) return;
11818
+ try {
11819
+ await this.onEvents(events2);
11820
+ await this.acknowledge(events2, this.controller.signal);
11821
+ } catch (error2) {
11822
+ if (!this.controller.signal.aborted) console.error(`[sourcefed] event delivery failed: ${String(error2)}`);
11823
+ this.failedDelivery = true;
11824
+ this.stream?.abort();
11825
+ }
11826
+ });
11827
+ }
11828
+ async waitForDelivery() {
11829
+ if (this.controller.signal.aborted) return;
11830
+ const stopped = Promise.withResolvers();
11831
+ const abort = () => stopped.resolve();
11832
+ this.controller.signal.addEventListener("abort", abort, { once: true });
11833
+ try {
11834
+ await Promise.race([this.delivering, stopped.promise]);
11835
+ } finally {
11836
+ this.controller.signal.removeEventListener("abort", abort);
11837
+ }
11838
+ }
11839
+ };
11840
+ function pause(ms, signal) {
11841
+ return new Promise((resolve) => {
11842
+ const finish = () => {
11843
+ clearTimeout(timer);
11844
+ signal.removeEventListener("abort", finish);
11845
+ resolve();
11846
+ };
11847
+ const timer = setTimeout(finish, ms);
11848
+ signal.addEventListener("abort", finish, { once: true });
11849
+ if (signal.aborted) finish();
11850
+ });
11851
+ }
11728
11852
  async function connectDaemonClient(options) {
11729
11853
  const url2 = options.url ?? process.env.SOURCEFED_DAEMON_URL ?? defaultDaemonUrl();
11730
11854
  return new HttpDaemonClient(url2, options.token ?? process.env.SOURCEFED_DAEMON_TOKEN);
11731
11855
  }
11732
11856
  var HttpDaemonClient = class {
11733
- baseURL;
11734
- token;
11735
- router = new RequestRouter();
11736
- listeners = /* @__PURE__ */ new Map();
11737
- streams = /* @__PURE__ */ new Set();
11738
11857
  constructor(baseURL, token) {
11739
- this.baseURL = baseURL.replace(/\/+$/, "");
11740
11858
  this.token = token;
11859
+ this.baseURL = baseURL.replace(/\/+$/, "");
11741
11860
  }
11861
+ baseURL;
11862
+ streams = /* @__PURE__ */ new Set();
11863
+ lifetime = new AbortController();
11864
+ cursor = 0;
11865
+ closing;
11742
11866
  headers() {
11743
11867
  return this.token ? { authorization: `Bearer ${this.token}` } : {};
11744
11868
  }
11745
- async request(method, params) {
11746
- const id = this.router.nextID();
11747
- const promise = this.router.register(id);
11869
+ async request(method, params, signal = this.lifetime.signal) {
11870
+ if (this.closing && signal === this.lifetime.signal) throw new Error("daemon closed");
11871
+ signal.throwIfAborted();
11872
+ const response = await fetch(`${this.baseURL}/rpc`, {
11873
+ method: "POST",
11874
+ headers: { "content-type": "application/json", ...this.headers() },
11875
+ body: JSON.stringify({ id: ++this.cursor, method, params }),
11876
+ signal: AbortSignal.any([signal, this.lifetime.signal, AbortSignal.timeout(15e3)])
11877
+ });
11878
+ const frame = await response.json();
11879
+ if (!response.ok || frame.error) throw new Error(frame.error ?? `daemon request failed: ${response.status}`);
11880
+ return frame.result;
11881
+ }
11882
+ async subscribe(target, onEvents, options) {
11883
+ if (this.closing) throw new Error("daemon closed");
11884
+ this.lifetime.signal.throwIfAborted();
11885
+ const stream = new DaemonEventStream(
11886
+ `${this.baseURL}/events?target=${encodeTarget(target)}`,
11887
+ this.headers(),
11888
+ onEvents,
11889
+ (events2, signal) => this.acknowledge(target, events2, signal),
11890
+ () => this.streams.delete(stream)
11891
+ );
11892
+ this.streams.add(stream);
11748
11893
  try {
11749
- const response = await fetch(`${this.baseURL}/rpc`, {
11750
- method: "POST",
11751
- headers: { "content-type": "application/json", ...this.headers() },
11752
- body: JSON.stringify({ id, method, params })
11753
- });
11754
- const frame = await response.json();
11755
- if (!response.ok || frame.error) throw new Error(frame.error ?? `daemon request failed: ${response.status}`);
11756
- this.router.settle(id, { result: frame.result });
11894
+ await stream.start(options?.signal);
11895
+ return { close: () => stream.close() };
11757
11896
  } catch (error2) {
11758
- this.router.settle(id, { error: error2 instanceof Error ? error2.message : String(error2) });
11897
+ await stream.close();
11898
+ throw error2;
11759
11899
  }
11760
- return promise;
11761
11900
  }
11762
- async subscribe(target, onEvents) {
11763
- const key = targetKey(target);
11764
- let callbacks = this.listeners.get(key);
11765
- if (!callbacks) {
11766
- callbacks = /* @__PURE__ */ new Set();
11767
- this.listeners.set(key, callbacks);
11768
- }
11769
- callbacks.add(onEvents);
11770
- const controller = new AbortController();
11771
- this.streams.add(controller);
11772
- const url2 = `${this.baseURL}/events?target=${encodeTarget(target)}`;
11773
- let markSubscribed;
11774
- const subscribed = new Promise((resolve) => {
11775
- markSubscribed = () => resolve();
11776
- });
11777
- let delivering = Promise.resolve();
11778
- let activeStream;
11779
- let retryStream = false;
11780
- const deliver = (events2) => {
11781
- if (!callbacks?.has(onEvents) || events2.length === 0) return Promise.resolve();
11782
- delivering = delivering.then(async () => {
11783
- try {
11784
- await onEvents(events2);
11785
- } catch (error2) {
11786
- console.error(`[sourcefed] event delivery failed: ${error2 instanceof Error ? error2.message : String(error2)}`);
11787
- retryStream = true;
11788
- activeStream?.abort();
11789
- return;
11790
- }
11791
- await acknowledge(events2);
11792
- }).catch((error2) => {
11793
- console.error(`[sourcefed] event delivery failed: ${error2 instanceof Error ? error2.message : String(error2)}`);
11794
- });
11795
- return delivering;
11796
- };
11797
- const acknowledge = async (events2) => {
11798
- let attempt = 0;
11799
- while (!controller.signal.aborted && callbacks?.has(onEvents)) {
11800
- try {
11801
- await this.request("monitor.ack", { target, eventIDs: events2.map((event) => event.id) });
11802
- return;
11803
- } catch (error2) {
11804
- attempt += 1;
11805
- if (attempt === 3) {
11806
- console.error(`[sourcefed] event acknowledgement still failing; retrying without repeating delivery: ${error2 instanceof Error ? error2.message : String(error2)}`);
11807
- }
11808
- await sleep(Math.min(250 * 2 ** (attempt - 1), 4e3));
11809
- }
11810
- }
11811
- };
11812
- const runStream = async () => {
11813
- const streamController = new AbortController();
11814
- const closeStream = () => streamController.abort();
11815
- activeStream = streamController;
11816
- controller.signal.addEventListener("abort", closeStream, { once: true });
11901
+ async acknowledge(target, events2, signal) {
11902
+ let attempt = 0;
11903
+ while (!signal.aborted) {
11817
11904
  try {
11818
- const response = await fetch(url2, { signal: streamController.signal, headers: this.headers() });
11819
- if (!response.ok || !response.body) throw new Error(`event stream failed: ${response.status}`);
11820
- const reader = response.body.getReader();
11821
- const decoder = new TextDecoder();
11822
- let buffer = "";
11823
- while (true) {
11824
- const { done, value } = await reader.read();
11825
- if (done) break;
11826
- buffer += decoder.decode(value, { stream: true });
11827
- const frames = buffer.split("\n\n");
11828
- buffer = frames.pop() ?? "";
11829
- for (const chunk of frames) {
11830
- for (const line of chunk.split("\n")) {
11831
- if (!line.startsWith("data: ")) continue;
11832
- const frame = parseDaemonFrame(line.slice(6));
11833
- if (!frame || !("type" in frame)) continue;
11834
- if (frame.type === "subscribed") markSubscribed();
11835
- if (frame.type === "event") void deliver(frame.events);
11836
- }
11837
- }
11838
- }
11839
- consecutiveFailures = 0;
11905
+ await this.request("monitor.ack", { target, eventIDs: events2.map((event) => event.id) }, signal);
11906
+ return;
11840
11907
  } catch (error2) {
11841
- if (!controller.signal.aborted && !retryStream) {
11842
- consecutiveFailures += 1;
11843
- if (consecutiveFailures === 1) {
11844
- console.error(`[sourcefed] event stream ended: ${error2 instanceof Error ? error2.message : String(error2)}`);
11845
- }
11908
+ if (++attempt === 3) {
11909
+ console.error(`[sourcefed] event acknowledgement still failing; retrying without repeating delivery: ${String(error2)}`);
11846
11910
  }
11847
- } finally {
11848
- controller.signal.removeEventListener("abort", closeStream);
11849
- if (activeStream === streamController) activeStream = void 0;
11850
- retryStream = false;
11851
- }
11852
- };
11853
- let consecutiveFailures = 0;
11854
- void (async () => {
11855
- while (!controller.signal.aborted && callbacks?.has(onEvents)) {
11856
- await runStream();
11857
- if (controller.signal.aborted) break;
11858
- await sleep(500);
11911
+ await pause(Math.min(250 * 2 ** Math.min(attempt - 1, 4), 4e3), signal);
11859
11912
  }
11860
- })();
11861
- try {
11862
- await withTimeout(subscribed, 15e3, `sourcefed event stream did not subscribe at ${url2}`);
11863
- } catch (error2) {
11864
- const callbacks2 = this.listeners.get(key);
11865
- callbacks2?.delete(onEvents);
11866
- if (callbacks2 && callbacks2.size === 0) this.listeners.delete(key);
11867
- controller.abort();
11868
- this.streams.delete(controller);
11869
- throw error2;
11870
11913
  }
11871
- return {
11872
- close: async () => {
11873
- const callbacks2 = this.listeners.get(key);
11874
- callbacks2?.delete(onEvents);
11875
- if (callbacks2 && callbacks2.size === 0) this.listeners.delete(key);
11876
- controller.abort();
11877
- this.streams.delete(controller);
11878
- }
11879
- };
11880
11914
  }
11881
- async close() {
11882
- for (const controller of this.streams) controller.abort();
11883
- this.streams.clear();
11884
- this.router.rejectAll(new Error("daemon closed"));
11885
- this.listeners.clear();
11915
+ close() {
11916
+ this.closing ??= Promise.all([...this.streams].map((stream) => stream.close())).then(() => {
11917
+ this.lifetime.abort();
11918
+ this.streams.clear();
11919
+ });
11920
+ return this.closing;
11886
11921
  }
11887
11922
  };
11888
11923
  async function dispatchDaemonRequest(daemon, method, params) {
@@ -22324,7 +22359,7 @@ var REQUEST_STATE_ONLY_LEG_PACING_MS = 250;
22324
22359
  function inputRequiredRoundsExceededMessage(method, maxRounds) {
22325
22360
  return `Multi-round-trip request '${method}' still required input after ${maxRounds} rounds (inputRequired.maxRounds)`;
22326
22361
  }
22327
- function sleep2(ms, signal) {
22362
+ function sleep(ms, signal) {
22328
22363
  return new Promise((resolve, reject) => {
22329
22364
  if (signal?.aborted) {
22330
22365
  reject(signal.reason instanceof SdkError ? signal.reason : new SdkError(SdkErrorCode.RequestTimeout, String(signal.reason)));
@@ -31059,7 +31094,7 @@ var LegacyInputRequiredShim = class {
31059
31094
  } finally {
31060
31095
  roundAbort.dispose();
31061
31096
  }
31062
- } else await sleep2(REQUEST_STATE_ONLY_LEG_PACING_MS, outerSignal);
31097
+ } else await sleep(REQUEST_STATE_ONLY_LEG_PACING_MS, outerSignal);
31063
31098
  let ctxNext = {
31064
31099
  ...ctx,
31065
31100
  mcpReq: {