@askalf/dario 6.0.28 → 6.0.29

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/dist/proxy.js +43 -0
  2. package/package.json +1 -1
package/dist/proxy.js CHANGED
@@ -2715,6 +2715,49 @@ export async function startProxy(opts = {}) {
2715
2715
  clearTimeout(bodyTimeout);
2716
2716
  }
2717
2717
  let body = Buffer.concat(chunks);
2718
+ // A body that is not a JSON object cannot be routed — every decision
2719
+ // below (alias, provider prefix, codex slug, template) peeks at `.model`
2720
+ // and each peek swallows its parse error and falls through. So `{` used
2721
+ // to reach the Claude pool as if it were a Claude request and, on a
2722
+ // --no-claude-auth proxy, came back as the pool's 503 "No account
2723
+ // configured" with `error` as a string — which the codex drift watcher's
2724
+ // wire-contract check flagged (run 34044346444): an OpenAI-shape client
2725
+ // reads `.error.message`. Answer here instead: 400, the endpoint's own
2726
+ // wire shape, and no upstream round-trip for a request nothing can serve.
2727
+ // Upstreams do the same (Anthropic: "The request body is not valid
2728
+ // JSON"; OpenAI: "We could not parse the JSON body of your request").
2729
+ {
2730
+ let invalid = null;
2731
+ if (body.length === 0)
2732
+ invalid = 'request body is empty';
2733
+ else {
2734
+ try {
2735
+ // Fatal decode: Buffer.toString() replaces malformed UTF-8 with
2736
+ // U+FFFD, so `{"x":"\xff"}` would parse here as a clean object
2737
+ // while the ORIGINAL bytes went on to be forwarded (review on
2738
+ // #1231). The bytes on the wire are what must be valid.
2739
+ const text = new TextDecoder('utf-8', { fatal: true }).decode(body);
2740
+ const v = JSON.parse(text);
2741
+ if (v === null || typeof v !== 'object' || Array.isArray(v))
2742
+ invalid = 'request body must be a JSON object';
2743
+ }
2744
+ catch (err) {
2745
+ invalid = `request body is not valid JSON: ${err instanceof Error ? err.message : String(err)}`;
2746
+ }
2747
+ }
2748
+ if (invalid !== null) {
2749
+ requestCount++;
2750
+ writeLogLine(logFileStream, {
2751
+ ts: new Date().toISOString(), req: requestCount,
2752
+ method: req.method ?? '', path: urlPath, status: 400, reject: 'invalid-body',
2753
+ });
2754
+ res.writeHead(400, { ...JSON_HEADERS, 'Access-Control-Allow-Origin': corsOrigin });
2755
+ res.end(JSON.stringify(isOpenAI
2756
+ ? { error: { message: invalid, type: 'invalid_request_error', param: null, code: null } }
2757
+ : { type: 'error', error: { type: 'invalid_request_error', message: invalid } }));
2758
+ return;
2759
+ }
2760
+ }
2718
2761
  // Provider prefix (v3.10.0). If the body's model field is `<provider>:<model>`
2719
2762
  // with a recognized prefix, strip the prefix and force routing regardless of
2720
2763
  // regex. CLI-level `--model=<provider>:<name>` applies the same override
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askalf/dario",
3
- "version": "6.0.28",
3
+ "version": "6.0.29",
4
4
  "description": "Use your Claude Pro/Max subscription in any tool — Cursor, Cline, Aider, the Agent SDK, your scripts — at subscription pricing, not per-token API bills. One local Anthropic + OpenAI-compatible endpoint.",
5
5
  "type": "module",
6
6
  "bin": {