Skip to content

v1.39.0.0 feat: buildFetchHandler factory unblocks gbrowser submodule consumption#1511

Merged
garrytan merged 5 commits into
mainfrom
garrytan/boston-v2
May 15, 2026
Merged

v1.39.0.0 feat: buildFetchHandler factory unblocks gbrowser submodule consumption#1511
garrytan merged 5 commits into
mainfrom
garrytan/boston-v2

Conversation

@garrytan
Copy link
Copy Markdown
Owner

Summary

buildFetchHandler ships — gbrowser v0.6.0.0 (phoenix overlay) can now consume gstack as a submodule and compose overlay routes on top of the browse server's dispatch.

  • Exports buildFetchHandler(cfg: ServerConfig): ServerHandle from browse/src/server.ts. CLI delegates to the same factory.
  • Auth is now cfg-driven end-to-end. Module-level AUTH_TOKEN const + boot initRegistry call, validateAuth, and shutdown are deleted; factory closure owns them so embedders' browsers actually get closed on shutdown.
  • beforeRoute hook wired: runs after the tunnel surface filter, before per-route dispatch. Returns Response → short-circuit; returns null → fall through to gstack. JSDoc now includes a security warning about not returning privileged data from the hook without re-checking auth (the hook fires for missing AND invalid bearer).
  • initRegistry gains idempotency: same token = no-op, different token = throws clearly. New __resetRegistry() test helper mirrors __resetConnectRateLimit.
  • 14 new factory contract tests in browse/test/server-factory.test.ts cover the ServerHandle shape, auth wiring, validation throws, hook semantics across both surfaces, and registry idempotency.

Test Coverage

CODE PATHS                                                       USER FLOWS / EMBEDDER FLOWS
[+] browse/src/server.ts                                          [+] CLI start path
  ├── buildFetchHandler(cfg)                                        ├── [★★★ TESTED] start() smoke + bun test full
  │   ├── cfg.authToken short                  [★★★ TESTED]         └── [★★★ TESTED] /command POST flow
  │   ├── cfg.browserManager missing           [★★★ TESTED]
  │   ├── initRegistry init                    [★★★ TESTED]       [+] Embedder boot path
  │   ├── factory validateAuth                 [★★★ TESTED]         ├── [★★★ TESTED] cfg.authToken throws on short
  │   ├── factory shutdown                     [★  TESTED]           ├── [★★★ TESTED] missing browserManager throws
  │   └── beforeRoute hook                     [★★★ TESTED]         └── [★★★ TESTED] same-token idempotent
[+] browse/src/token-registry.ts                                  [+] beforeRoute hook contract
  ├── initRegistry idempotent                  [★★★ TESTED]         ├── [★★★ TESTED] Response short-circuits
  ├── initRegistry mismatch throws             [★★★ TESTED]         ├── [★★★ TESTED] null falls through
  └── __resetRegistry()                        [★★★ TESTED]         └── [★★★ TESTED] valid TokenInfo + null

COVERAGE: 14/14 new paths tested (100%) | 28 server-factory tests pass | 154 tests across 6 directly-affected files pass

Pre-Landing Review

Pre-landing review ran during /plan-eng-review (clean) and Codex outside-voice in plan mode. All findings incorporated into the plan and the implementation. Key Codex findings addressed:

Eval Results

No prompt-related files changed — evals skipped.

Plan Completion

All plan decisions (D1 through D14) accepted by the user and implemented. The CEO scope-expansion decision (D12) pulled the "real factory" refactor into this PR rather than deferring — module-level AUTH_TOKEN/validateAuth/shutdown all deleted in favor of factory-scoped equivalents.

Pre-existing test failures (not caused by this PR)

browse/test/server-auth.test.ts has 4 pre-existing failures verified against origin/main (via git stash) before this branch's work began:

  • /activity/history requires authentication (marker mismatch: Sidebar endpointsSidebar chat endpoints ripped)
  • /activity/history has no wildcard CORS header (same root cause)
  • connect command status fetch body has no undefined variable references (CLI_SRC marker mismatch)
  • pair-agent disables parent PID monitoring via BROWSE_PARENT_PID=0 (CLI_SRC marker mismatch)

These are source-pattern test drift unrelated to the factory work. Captured for a future cleanup PR.

Test plan

  • bun test browse/test/server-factory.test.ts — 28/28 pass
  • bun test browse/test/token-registry.test.ts — 49/49 pass
  • bun test browse/test/skill-token.test.ts — 15/15 pass
  • bun test browse/test/browser-skills-e2e.test.ts — 8/8 pass
  • bun test browse/test/browser-skill-commands.test.ts — 29/29 pass
  • bun test browse/test/dual-listener.test.ts — 25/25 pass (was 25/25 on main, no regression)
  • Confirmed zero new regressions vs origin/main across the broader suite

🤖 Generated with Claude Code

garrytan and others added 3 commits May 14, 2026 19:56
Add buildFetchHandler(cfg: ServerConfig): ServerHandle in browse/src/server.ts.
Refactor start() to delegate handler construction to the factory and read env
once via resolveConfigFromEnv(). Wire the beforeRoute hook (runs after the
tunnel surface filter, before per-route dispatch).

Auth is now cfg-driven end-to-end. Module-level AUTH_TOKEN const +
initRegistry(AUTH_TOKEN) boot call, validateAuth, and shutdown are deleted;
factory closure owns them. start() threads cfg.authToken into launchHeaded,
the state-file write, and the factory.

initRegistry is idempotent for same-token re-init; throws clearly for
different-token re-init. __resetRegistry() test helper added (mirrors
__resetConnectRateLimit). Existing tests that did rotateRoot() ->
initRegistry('fixed-token') swap to __resetRegistry() to avoid the new guard.

14 factory contract tests added covering ServerHandle shape, auth wiring,
validation throws, hook semantics across both surfaces, and registry
idempotency.

Source-pattern tests in dual-listener.test.ts and server-auth.test.ts
updated for the new identifiers (handle.fetchLocal/fetchTunnel, authToken,
shutdownFn).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 15, 2026

E2E Evals: ✅ PASS

8/8 tests passed | $1.40 total cost | 12 parallel runners

Suite Result Status Cost
e2e-browse 2/2 $0.13
e2e-deploy 2/2 $0.32
e2e-qa-workflow 1/1 $0.61
llm-judge 1/1 $0.02
e2e-deploy 2/2 $0.32

12x ubicloud-standard-8 (Docker: pre-baked toolchain + deps) | wall clock ≈ slowest suite

garrytan added 2 commits May 14, 2026 21:26
# Conflicts:
#	CHANGELOG.md
#	VERSION
#	package.json
# Conflicts:
#	CHANGELOG.md
#	VERSION
#	browse/src/server.ts
#	package.json
@garrytan garrytan merged commit 25cf5ed into main May 15, 2026
23 checks passed
kairin pushed a commit to kairin/gstack that referenced this pull request May 17, 2026
… consumption (garrytan#1511)

* feat: buildFetchHandler factory unblocks gbrowser submodule consumption

Add buildFetchHandler(cfg: ServerConfig): ServerHandle in browse/src/server.ts.
Refactor start() to delegate handler construction to the factory and read env
once via resolveConfigFromEnv(). Wire the beforeRoute hook (runs after the
tunnel surface filter, before per-route dispatch).

Auth is now cfg-driven end-to-end. Module-level AUTH_TOKEN const +
initRegistry(AUTH_TOKEN) boot call, validateAuth, and shutdown are deleted;
factory closure owns them. start() threads cfg.authToken into launchHeaded,
the state-file write, and the factory.

initRegistry is idempotent for same-token re-init; throws clearly for
different-token re-init. __resetRegistry() test helper added (mirrors
__resetConnectRateLimit). Existing tests that did rotateRoot() ->
initRegistry('fixed-token') swap to __resetRegistry() to avoid the new guard.

14 factory contract tests added covering ServerHandle shape, auth wiring,
validation throws, hook semantics across both surfaces, and registry
idempotency.

Source-pattern tests in dual-listener.test.ts and server-auth.test.ts
updated for the new identifiers (handle.fetchLocal/fetchTunnel, authToken,
shutdownFn).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* chore: bump version and changelog (v1.39.0.0)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
RyotaKun pushed a commit to RyotaKun/gstack that referenced this pull request May 18, 2026
… consumption (garrytan#1511)

* feat: buildFetchHandler factory unblocks gbrowser submodule consumption

Add buildFetchHandler(cfg: ServerConfig): ServerHandle in browse/src/server.ts.
Refactor start() to delegate handler construction to the factory and read env
once via resolveConfigFromEnv(). Wire the beforeRoute hook (runs after the
tunnel surface filter, before per-route dispatch).

Auth is now cfg-driven end-to-end. Module-level AUTH_TOKEN const +
initRegistry(AUTH_TOKEN) boot call, validateAuth, and shutdown are deleted;
factory closure owns them. start() threads cfg.authToken into launchHeaded,
the state-file write, and the factory.

initRegistry is idempotent for same-token re-init; throws clearly for
different-token re-init. __resetRegistry() test helper added (mirrors
__resetConnectRateLimit). Existing tests that did rotateRoot() ->
initRegistry('fixed-token') swap to __resetRegistry() to avoid the new guard.

14 factory contract tests added covering ServerHandle shape, auth wiring,
validation throws, hook semantics across both surfaces, and registry
idempotency.

Source-pattern tests in dual-listener.test.ts and server-auth.test.ts
updated for the new identifiers (handle.fetchLocal/fetchTunnel, authToken,
shutdownFn).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* chore: bump version and changelog (v1.39.0.0)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
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.

1 participant