mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-06 07:12:12 +03:00
fix(muse-spark-web): document the ecto1: WS auth token requirement in credential hint, spec, and error message (#9502)
Closes #9502
This commit is contained in:
committed by
GitHub
parent
d931b907bf
commit
dc06bf558e
1
changelog.d/fixes/9502-muse-ecto1-auth-token.md
Normal file
1
changelog.d/fixes/9502-muse-ecto1-auth-token.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(muse-spark-web): document the ecto1: WS auth token requirement in the credential hint, spec, and error message (#9502)
|
||||
@@ -1,16 +1,16 @@
|
||||
---
|
||||
title: "Provider Reference"
|
||||
version: 3.8.50
|
||||
lastUpdated: 2026-07-30
|
||||
lastUpdated: 2026-08-05
|
||||
---
|
||||
|
||||
# Provider Reference
|
||||
|
||||
> **Auto-generated** from `src/shared/constants/providers.ts` — do not edit by hand.
|
||||
> Regenerate with: `npm run gen:provider-reference`
|
||||
> **Last generated:** 2026-07-30
|
||||
> **Last generated:** 2026-08-05
|
||||
|
||||
Total providers: **290**. See category breakdown below.
|
||||
Total providers: **291**. See category breakdown below.
|
||||
|
||||
## Categories
|
||||
|
||||
@@ -84,7 +84,7 @@ Use the dashboard at `/dashboard/providers` to enable, configure, and test each
|
||||
| `kimi-web` | `kimi-web` | Kimi Web | Web cookie | [link](https://www.kimi.com/code?aff=omniroute) | Paste access_token from www.kimi.com DevTools → Application → Local Storage. A legacy kimi-auth cookie is also accepted. | — |
|
||||
| `lmarena` | `lma` | Arena (Free) | Web cookie | [link](https://arena.ai) | Paste the full Cookie header from arena.ai (DevTools → Network → request → Cookie). Include arena-auth-prod-v1.0/.1… and cf_clearance/__cf_bm when present. OmniRoute uses Chrome TLS impersonation; if Arena still 403s, set providerSpecificData.recaptchaV3Token from a live browser session. | — |
|
||||
| `microsoft-designer-web` | `msdesigner` | Microsoft Designer (Image Generation) | Web cookie | [link](https://designer.microsoft.com) | Sign in at designer.microsoft.com, then open DevTools → Network, generate an image, and find the request to DallE.ashx?action=GetDallEImagesCogSci. Copy the value of its Authorization: Bearer header (the access_token — no 'Bearer ' prefix). The token is short-lived; this is an unofficial, reverse-engineered integration. | — |
|
||||
| `muse-spark-web` | `ms-web` | Muse Spark Web (Meta AI) | Web cookie | [link](https://www.meta.ai) | Paste your ecto_1_sess value or full cookie header from meta.ai | emulated |
|
||||
| `muse-spark-web` | `ms-web` | Muse Spark Web (Meta AI) | Web cookie | [link](https://www.meta.ai) | Paste your ecto_1_sess cookie AND the ecto1:... WS auth token from meta.ai. Capture the ecto1: token in DevTools → Network → WS → the clippy request's Authorization query param. Example: ecto_1_sess=4240a308...NVDg0; ecto1:ABCD... | emulated |
|
||||
| `notion-web` | `nw` | Notion AI Web (Unofficial/Experimental) | Web cookie | [link](https://www.notion.so) | Paste only the token_v2 cookie VALUE from app.notion.com (DevTools → Application → Cookies → token_v2). Do not paste token_v2= or the full Cookie header. Workspace is auto-detected; space_id / notion_user_id are optional. | — |
|
||||
| `perplexity-web` | `pplx-web` | Perplexity Web (Pro/Max) | Web cookie | [link](https://www.perplexity.ai) | Paste your __Secure-next-auth.session-token cookie value from perplexity.ai | emulated |
|
||||
| `poe-web` | `poe` | Poe Web (Subscription) | Web cookie | [link](https://poe.com) | Paste your p-b cookie value from poe.com (DevTools → Application → Cookies → p-b) | — |
|
||||
@@ -97,7 +97,7 @@ Use the dashboard at `/dashboard/providers` to enable, configure, and test each
|
||||
| `zai-web` | `zw` | Z.ai Web (Free) | Web cookie | [link](https://chat.z.ai) | Paste the full Cookie header from chat.z.ai (must include the token=<JWT> cookie) | — |
|
||||
| `zenmux-free` | `zmf` | ZenMux Free (Web) | Web cookie | [link](https://zenmux.ai) | Login at zenmux.ai, then export all cookies using EditThisCookie or Cookie-Editor and paste the full Cookie header string here. Refresh every ~30 days. | — |
|
||||
|
||||
## API Key Providers (paid / paid-with-free-credits) (195)
|
||||
## API Key Providers (paid / paid-with-free-credits) (196)
|
||||
|
||||
| ID | Alias | Name | Tags | Website | Notes |
|
||||
|----|-------|------|------|---------|-------|
|
||||
@@ -130,6 +130,7 @@ Use the dashboard at `/dashboard/providers` to enable, configure, and test each
|
||||
| `bytez` | `bytez` | Bytez | API key | [link](https://bytez.com) | $1 free credits, refreshes every 4 weeks |
|
||||
| `cerebras` | `cerebras` | Cerebras | API key | [link](https://inference.cerebras.ai) | Free Trial: 1M tokens/day, 30K TPM, 5 RPM — no credit card. |
|
||||
| `charm-hyper` | `charm-hyper` | Charm Hyper | API key | [link](https://hyper.charm.land) | 100 free monthly Hypercredits on signup |
|
||||
| `cheaperinference` | `cinf` | Cheaper Inference | API key | [link](https://cheaperinference.com/?utm_source=omniroute) | — |
|
||||
| `chenzk` | `chenzk` | Chenzk API | API key | [link](https://chenzk.top) | — |
|
||||
| `chutes` | `chutes` | Chutes.ai | API key, aggregator | [link](https://chutes.ai) | Bearer API key for the Chutes OpenAI-compatible gateway. |
|
||||
| `clarifai` | `clarifai` | Clarifai | API key, enterprise | [link](https://docs.clarifai.com) | Use your Clarifai PAT or app-specific API key. OmniRoute targets the OpenAI-compatible endpoint at https://api.clarifai.com/v2/ext/openai/v1 and authenticates with Authorization: Key <token>. |
|
||||
|
||||
@@ -1287,7 +1287,7 @@ export class MuseSparkWebExecutor extends BaseExecutor {
|
||||
if (!authorization) {
|
||||
return errorResult(
|
||||
400,
|
||||
"Missing Authorization for Meta AI WebSocket — your cookie must include an ecto1:... auth token.",
|
||||
"Missing Authorization for Meta AI WebSocket — paste the ecto1:... WS auth token from meta.ai DevTools (Network → WS → clippy request Authorization param), alongside your ecto_1_sess cookie.",
|
||||
"missing_authorization",
|
||||
{},
|
||||
body
|
||||
|
||||
@@ -50,14 +50,14 @@ export async function validateMuseSparkWebProvider({ apiKey, providerSpecificDat
|
||||
if (response.status === 401 || response.status === 403) {
|
||||
return {
|
||||
valid: false,
|
||||
error: "Invalid Meta AI session cookie — re-paste abra_sess from meta.ai",
|
||||
error: "Invalid Meta AI session cookie — re-paste ecto_1_sess from meta.ai",
|
||||
};
|
||||
}
|
||||
|
||||
if (/authentication required to send messages|login is required|sign in/i.test(responseText)) {
|
||||
return {
|
||||
valid: false,
|
||||
error: "Invalid Meta AI session cookie — re-paste abra_sess from meta.ai",
|
||||
error: "Invalid Meta AI session cookie — re-paste ecto_1_sess from meta.ai",
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,10 @@ export const WEB_COOKIE_PROVIDERS = {
|
||||
website: "https://www.meta.ai",
|
||||
hasFree: true,
|
||||
freeNote: "Free with login — Meta AI platform with Llama models.",
|
||||
authHint: "Paste your ecto_1_sess value or full cookie header from meta.ai",
|
||||
authHint:
|
||||
"Paste your ecto_1_sess cookie AND the ecto1:... WS auth token from meta.ai. " +
|
||||
"Capture the ecto1: token in DevTools → Network → WS → the clippy request's Authorization query param. " +
|
||||
"Example: ecto_1_sess=4240a308...NVDg0; ecto1:ABCD...",
|
||||
toolCalling: "emulated",
|
||||
},
|
||||
"claude-web": {
|
||||
|
||||
@@ -98,10 +98,14 @@ export const WEB_SESSION_CREDENTIAL_REQUIREMENTS = {
|
||||
},
|
||||
"muse-spark-web": {
|
||||
kind: "cookie",
|
||||
credentialName: "abra_sess",
|
||||
placeholder: "abra_sess=...; other=value",
|
||||
// #9502: the WS protocol (#7528) needs both the ecto_1_sess cookie (GraphQL
|
||||
// warmup/mode-switch) and a separate ecto1:... WS auth token (Authorization
|
||||
// query param on wss://gateway.meta.ai/ws/clippy). The executor extracts the
|
||||
// ecto1: token from the apiKey field via /ecto1:[^\s;]+/i.
|
||||
credentialName: "ecto_1_sess + ecto1: WS auth token",
|
||||
placeholder: "ecto_1_sess=...; ecto1:... (WS auth token from meta.ai DevTools → Network → WS → clippy)",
|
||||
acceptsFullCookieHeader: true,
|
||||
storageKeys: ["cookie", "abra_sess"],
|
||||
storageKeys: ["cookie", "ecto_1_sess", "abra_sess"],
|
||||
},
|
||||
"hailuo-web": {
|
||||
kind: "token",
|
||||
|
||||
@@ -19,12 +19,15 @@ const webCookie = readFileSync(
|
||||
const executor = readFileSync(join(root, "open-sse", "executors", "muse-spark-web.ts"), "utf8");
|
||||
|
||||
test("provider form hint points at the live ecto_1_sess cookie, not retired abra_sess", () => {
|
||||
// #9502: the hint now names BOTH the ecto_1_sess cookie and the ecto1: WS auth
|
||||
// token; the live-cookie-name guard (ecto_1_sess present, retired abra_sess
|
||||
// absent) still holds.
|
||||
assert.ok(
|
||||
webCookie.includes("Paste your ecto_1_sess value"),
|
||||
webCookie.includes("ecto_1_sess"),
|
||||
"muse-spark authHint must name ecto_1_sess"
|
||||
);
|
||||
assert.ok(
|
||||
!webCookie.includes("Paste your abra_sess"),
|
||||
!/Paste your abra_sess/.test(webCookie),
|
||||
"muse-spark authHint must not name the retired abra_sess cookie"
|
||||
);
|
||||
});
|
||||
|
||||
62
tests/unit/muse-spark-ws-auth-token-9502.test.ts
Normal file
62
tests/unit/muse-spark-ws-auth-token-9502.test.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { dirname, join } from "node:path";
|
||||
import { MuseSparkWebExecutor } from "../../open-sse/executors/muse-spark-web.ts";
|
||||
|
||||
// #9502: the WS migration (#7528) requires a separate ecto1:... auth token the
|
||||
// guidance never mentions, so a cookie-only credential (the documented input)
|
||||
// always fails with 400 "Missing Authorization".
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const root = join(__dirname, "..", "..");
|
||||
|
||||
const webCookie = readFileSync(
|
||||
join(root, "src", "shared", "constants", "providers", "web-cookie.ts"),
|
||||
"utf8"
|
||||
);
|
||||
const webSessionCredentials = readFileSync(
|
||||
join(root, "src", "shared", "providers", "webSessionCredentials.ts"),
|
||||
"utf8"
|
||||
);
|
||||
const executor = readFileSync(join(root, "open-sse", "executors", "muse-spark-web.ts"), "utf8");
|
||||
|
||||
test("#9502: provider authHint mentions the ecto1: WS auth token, not only the ecto_1_sess cookie", () => {
|
||||
// Extract the muse-spark-web block from the first `"muse-spark-web": {` (the
|
||||
// key declaration, not the `id:` value) up to the next top-level provider key.
|
||||
const startIdx = webCookie.indexOf('"muse-spark-web": {');
|
||||
assert.ok(startIdx >= 0, "muse-spark-web block not found");
|
||||
const museSection = webCookie.slice(startIdx, webCookie.indexOf('"claude-web"', startIdx));
|
||||
assert.match(museSection, /ecto1/, "authHint must mention the ecto1: WS auth token");
|
||||
});
|
||||
|
||||
test("#9502: web-session credential spec for muse-spark-web mentions the ecto1: WS auth token", () => {
|
||||
const startIdx = webSessionCredentials.indexOf('"muse-spark-web": {');
|
||||
assert.ok(startIdx >= 0, "muse-spark-web credential spec not found");
|
||||
const museSection = webSessionCredentials.slice(
|
||||
startIdx,
|
||||
webSessionCredentials.indexOf('"hailuo-web"', startIdx)
|
||||
);
|
||||
assert.match(museSection, /ecto1/, "credential spec must mention the ecto1: WS auth token");
|
||||
});
|
||||
|
||||
test("#9502: the Missing Authorization error message guides the user to the ecto1: token", () => {
|
||||
assert.ok(/Missing Authorization.*ecto1:/.test(executor), "missing-auth error must name the ecto1: token");
|
||||
});
|
||||
|
||||
test("#9502: a cookie-only credential (no ecto1: token) is rejected with 400 — the actual user failure", async () => {
|
||||
const exec = new MuseSparkWebExecutor();
|
||||
const result = await exec.execute({
|
||||
model: "muse-spark",
|
||||
body: { messages: [{ role: "user", content: "hello" }] },
|
||||
stream: false,
|
||||
credentials: { apiKey: "ecto_1_sess=4240a308abcdefNVDg0", connectionId: "conn-9502" },
|
||||
signal: null,
|
||||
log: null,
|
||||
upstreamExtraHeaders: undefined,
|
||||
} as Parameters<typeof exec.execute>[0]);
|
||||
assert.equal(result.response.status, 400, "cookie-only credential is rejected");
|
||||
const body = await result.response.json();
|
||||
assert.match(body.error.message, /Missing Authorization for Meta AI WebSocket/);
|
||||
});
|
||||
Reference in New Issue
Block a user