- compose: camofox service on by default (internal only, volume umt-camofox, healthcheck, CAMOFOX_REPLICAS=0 to skip); app depends on it with service_started/required=false and auto-registers camofox-env from BROWSER_PROVIDER_URL / BROWSER_ACCESS_KEY / BROWSER_ENABLED - docker/camofox/Dockerfile: builds upstream tag v1.17.0 (389c996); fixes the upstream Dockerfile (missing postinstall.js before npm ci, sh -c not forwarding SIGTERM so logins were never persisted on restart) - adapter fixes from the real container: coordinate click via evaluate + selector, focus typing with mode=keyboard, password values redacted from ARIA snapshots/extract, downloads field names, 410 after browser restart treated as lost tab; navigate reopens a tab in the same session - verified-capability table keyed by upstream version (1.17.0 all ten); other versions stay unverified; probe reports auth failures - settings: browser providers block (create/edit/delete/probe, capability table); API POST/PATCH/DELETE /browser/providers, POST .../probe - scripts/browser-verify: umtbr stack + mock NexusPHP run of REQ 4.7.4 items - docs: runbook browser §1/§7 (real-instance record), deploy §2.1 Co-Authored-By: Claude Opus 5.5 <[email protected]>
36 lines
1.7 KiB
TypeScript
36 lines
1.7 KiB
TypeScript
/**
|
|
* 真机核验用的 mock NexusPHP 站(testkit mock-nexusphp,观众风格),在 compose 网络里以 mocknexus:8080 提供给 camofox。
|
|
* testkit 的 mock 只监听 127.0.0.1 随机端口,这里在 0.0.0.0:8080 做一层 TCP 转发。
|
|
* 控制端点(只供核验脚本):POST /__mock/login?v=0|1 切换登录态;GET /__mock/infohash?id= 取种子 infohash;
|
|
* GET /__mock/stats 取 takelogin 次数。
|
|
*/
|
|
import { createServer } from "node:http";
|
|
import { connect, createServer as createTcp } from "node:net";
|
|
import { createMockNexusPhpSite } from "../../packages/testkit/src/sites/mock-nexusphp.ts";
|
|
|
|
const site = await createMockNexusPhpSite({ siteName: "观众(mock)", loginMode: "redirect" });
|
|
const upstream = new URL(site.baseUrl);
|
|
|
|
const control = createServer((req, res) => {
|
|
const u = new URL(req.url ?? "/", "http://x");
|
|
res.setHeader("content-type", "application/json");
|
|
if (u.pathname === "/__mock/login") {
|
|
site.setLoggedIn(u.searchParams.get("v") !== "0");
|
|
return res.end(JSON.stringify({ ok: true }));
|
|
}
|
|
if (u.pathname === "/__mock/infohash")
|
|
return res.end(JSON.stringify({ infohash: site.infoHashOf(u.searchParams.get("id") ?? "") }));
|
|
if (u.pathname === "/__mock/stats")
|
|
return res.end(JSON.stringify({ loginAttempts: site.loginAttempts, releases: site.releases.length }));
|
|
res.statusCode = 404;
|
|
res.end("{}");
|
|
});
|
|
control.listen(8081, "0.0.0.0");
|
|
|
|
createTcp((client) => {
|
|
const up = connect(Number(upstream.port), upstream.hostname);
|
|
client.pipe(up).pipe(client);
|
|
client.on("error", () => up.destroy());
|
|
up.on("error", () => client.destroy());
|
|
}).listen(8080, "0.0.0.0", () => console.log(`mock nexus ${site.baseUrl} → 0.0.0.0:8080(控制 8081)`));
|