@askalf/dario 6.6.6 → 6.6.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/compare.d.ts CHANGED
@@ -81,6 +81,23 @@ export declare function withModel(body: Buffer, model: string): Buffer | null;
81
81
  export declare function teeResponse(res: ServerResponse): {
82
82
  captured: () => CompareSide;
83
83
  };
84
+ /**
85
+ * A ServerResponse stand-in that keeps what was written instead of sending it.
86
+ * The comparison has no socket of its own — it is answering nobody.
87
+ *
88
+ * It must satisfy EVERY member the forwarder touches, not just the ones that
89
+ * carry the body. The forwarders register a client-close listener and remove
90
+ * it in their `finally`; this stub had `on`/`once` but no `removeListener`, so
91
+ * every comparison threw a TypeError on the way out and was recorded as
92
+ * `compare failed: res.removeListener is not a function`. The request had
93
+ * already been sent and paid for by then — 919 of 919 records on the box over
94
+ * a week, every one of them empty, with the skip reason sitting in a file
95
+ * nobody reads. Exported so a test can hold it to that surface.
96
+ */
97
+ export declare function captureSink(): {
98
+ sink: ServerResponse;
99
+ side: () => CompareSide;
100
+ };
84
101
  /**
85
102
  * Run the comparison against the ChatGPT subscription.
86
103
  *
package/dist/compare.js CHANGED
@@ -110,21 +110,44 @@ export function teeResponse(res) {
110
110
  /**
111
111
  * A ServerResponse stand-in that keeps what was written instead of sending it.
112
112
  * The comparison has no socket of its own — it is answering nobody.
113
+ *
114
+ * It must satisfy EVERY member the forwarder touches, not just the ones that
115
+ * carry the body. The forwarders register a client-close listener and remove
116
+ * it in their `finally`; this stub had `on`/`once` but no `removeListener`, so
117
+ * every comparison threw a TypeError on the way out and was recorded as
118
+ * `compare failed: res.removeListener is not a function`. The request had
119
+ * already been sent and paid for by then — 919 of 919 records on the box over
120
+ * a week, every one of them empty, with the skip reason sitting in a file
121
+ * nobody reads. Exported so a test can hold it to that surface.
113
122
  */
114
- function captureSink() {
123
+ export function captureSink() {
115
124
  const started = Date.now();
116
125
  const state = { status: null, chunks: [], headersSent: false };
117
126
  const sink = {
118
127
  statusCode: 0,
119
128
  headersSent: false,
129
+ // A comparison's client never goes away: it is the proxy itself, and the
130
+ // request it shadows has already been answered.
131
+ writableEnded: false,
132
+ destroyed: false,
120
133
  writeHead(code) { state.status = code; state.headersSent = true; this.headersSent = true; return this; },
121
134
  setHeader() { return this; },
135
+ getHeader() { return undefined; },
136
+ flushHeaders() { return undefined; },
122
137
  write(s) { if (s !== undefined && s !== null)
123
138
  state.chunks.push(String(s)); return true; },
124
139
  end(s) { if (s !== undefined && s !== null)
125
140
  state.chunks.push(String(s)); return this; },
141
+ // The EventEmitter surface, in full: a forwarder that adds a listener
142
+ // removes it again, and a stub that can only add is a crash waiting for
143
+ // the `finally`.
126
144
  on() { return this; },
127
145
  once() { return this; },
146
+ off() { return this; },
147
+ addListener() { return this; },
148
+ removeListener() { return this; },
149
+ removeAllListeners() { return this; },
150
+ listenerCount() { return 0; },
128
151
  emit() { return false; },
129
152
  };
130
153
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askalf/dario",
3
- "version": "6.6.6",
3
+ "version": "6.6.7",
4
4
  "description": "Use your Claude and ChatGPT subscriptions in Cursor, Cline, Aider, Claude Code and the Agent SDK — at subscription pricing, not per-token API bills. One local Anthropic + OpenAI-compatible endpoint: either plan answers either wire shape, with automatic failover when one hits its limit.",
5
5
  "type": "module",
6
6
  "bin": {