Skip to content

feat(proxy): support multiple local core endpoints, one per line - #13923

Merged
diegosouzapw merged 1 commit into
diegosouzapw:release/v3.8.51from
maxmad64bis:feat/s3-plural-core-endpoints
Sep 18, 2026
Merged

diegosouzapw merged 1 commit into
diegosouzapw:release/v3.8.51from
maxmad64bis:feat/s3-plural-core-endpoints

Conversation

@maxmad64bis

@maxmad64bis maxmad64bis commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor

Summary

A subscription holding tunnelled nodes registers them as one pool member, so rotation has nothing to rotate over. This change lets an operator list several loopback core entries (one per line) and syncs each entry into its own registry row and pool member. A single entry behaves exactly as today.

On the two open questions in #13460: the delimiter is newline (one entry per line in a textarea) — a comma is legal inside userinfo (socks5://user,name:pass@127.0.0.1:1080 parses today), so splitting on commas would break a working entry. On the error shape: neither a new subscription-level code nor a per-member error/dead through the health check, but the existing LOCAL_CORE_ENDPOINT_INVALID carrying a redacted per-entry detail. The health-check branch is inert by default — resolveHealthCheckStatusWrite returns null without PROXY_HEALTH_AUTO_DEACTIVATE, and policy C in decision.ts never mutates a status — so an unreachable member would never show error/dead on a default install; the proposed signal would have had no producer.

Before: single invalid entry → NEEDS_CORE_NOT_CONFIGURED + node list. After: single invalid entry → LOCAL_CORE_ENDPOINT_INVALID + redacted entry; several entries with one rejected → LOCAL_CORE_ENDPOINT_INVALID + rejected entries while the valid ones keep syncing.

Related Issues

Validation

  • Change type: provider
  • Focused tests and category gates from the golden path
  • npm run lint
  • Reconciled with the current active release base; focused checks rerun afterward
  • Production-code changes include a new or updated automated test in this PR

Tests Added Or Updated

  • tests/unit/proxySubscription.coreEndpoint.test.ts — parse (multi-line, CRLF, blanks, comma in userinfo kept intact, null/""), redact (userinfo, malformed input, path segment kept).
  • tests/unit/proxySubscription.pluralCore.test.ts — new file: single-entry identical behavior, N entries into N rows visited by rotation, gate-rejected vs unreachable distinguished in detail, re-sync keeps row id and assignments, entry removed from the field deletes its row, scheme collision on one key keeps one row with a mention, detail carries no password or userinfo.

Coverage Notes

  • src/lib/proxySubscription/coreEndpoint.ts — covered by the extended unit table (parse + redact + gate).
  • src/lib/proxySubscription/subscriptionService.ts — covered by the new sync suite over real loopback TCP servers and closed ports (no ESM stubs): per-entry gate, dedup, informative probe (Promise.all, verdict feeds detail only), conditional naming, stale-removal unchanged. feat(proxies): show how many egress IPs actually served a proxy pool #13581 (pool egress observation) is the post-merge check that the pool finally serves distinct exits.
  • SubscriptionTab.tsx + en/vi strings — textarea swap only, no logic; placeholder/desc updated.

Reviewer Notes

  • Sync probes the normalized URL (row's effective port: https → 443 else 8080), not the raw entry, because the probe's own scheme default (socks5 → 1080) disagrees with the row rule on port-less entries.
  • Probes run under Promise.all (independent TCP reads); upserts stay sequential. Verdict feeds the warning detail only — a row is created even when its core is unreachable, so a transient outage never deletes a row and its operator assignments. This is safe at selection time since feat(proxies): stop re-serving a proxy that just failed #13578: a failing entry is skipped on its own at request time.
  • No new error code and no migration: the field stays a string, LOCAL_CORE_ENDPOINT_INVALID carries the redacted per-entry detail, one entry keeps the historic name and behavior.
  • Limits: a TCP-open non-proxy squatter still yields a false-healthy probe (same as any existing TCP check); removing userinfo from the field is a new identity under the (host, port, username) keying, so the old row is replaced like any key change.
  • CI API Route Typecheck red is inherited, not this PR: src/lib/providerModels/modelDiscovery.ts TS2345 (baseline 0, live 1) reproduces on the bare base with zero commits of this PR (ephemeral worktree at a928ea8762; PR rebased on f1e7148c19 with focused checks re-run green), introduced upstream without a rebaseline. Unit + gates qualified 2026-09-16 (§12: normalized ✖ lists vs same-base PR fix(providers): select and verify the requested gemini-web model/mode before answering (#13381) #13919 + local re-runs at the head): codex #2331 (getForcedReasoningEffort chain, tip codex commit) and settings-i18n (ReasoningRoutingRules missing EN, tip reasoning commit) both fail locally with zero PR files involved; no ✗ gate line cites a PR file — all reds inherited, none actionable in this PR.

@maxmad64bis
maxmad64bis force-pushed the feat/s3-plural-core-endpoints branch from 9f25671 to d13fca2 Compare September 16, 2026 21:06
@maxmad64bis
maxmad64bis marked this pull request as ready for review September 16, 2026 21:09
@diegosouzapw

Copy link
Copy Markdown
Owner

Thanks @maxmad64bis — merging via the release merge-train. Validated in local merge-train (.claude/worktrees/merge-train-20260918-111718-suite.log) on the devbox @ train tip 7bb373fba5e241964c0ffb17bd03a804700839bb, boarded with 55 sibling PRs: typecheck:core, file-size, complexity, cognitive-complexity, changelog-integrity green; 747/747 changed-area node:test cases + 476/476 vitest green (fast parity mode — the full suite ran today on the release tip via the base-red train and runs again on the 3b train). Merged --admin per merge-gates §7.

@diegosouzapw
diegosouzapw merged commit fc6b458 into diegosouzapw:release/v3.8.51 Sep 18, 2026
18 of 25 checks passed
@diegosouzapw diegosouzapw mentioned this pull request Sep 21, 2026
@maxmad64bis
maxmad64bis deleted the feat/s3-plural-core-endpoints branch September 24, 2026 21:11
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants