Skip to content

refactor: split src/pecans.ts into src/http route modules (Phase 7 PR C) - #45

Merged
dopry merged 4 commits into
nextfrom
claude/pecans-phase-7c-http-split
Jul 16, 2026
Merged

refactor: split src/pecans.ts into src/http route modules (Phase 7 PR C)#45
dopry merged 4 commits into
nextfrom
claude/pecans-phase-7c-http-split

Conversation

@dopry

@dopry dopry commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Summary

Third and final Phase 7 PR (backend abstraction ✅ → resolution pipeline ✅ → HTTP split), closing out the modernization roadmap. Handler bodies relocate verbatim; HTTP behavior is unchanged and the contract suite passes untouched.

Layout

src/pecans.ts (682 lines) splits into:

Module Contents
src/http/query.ts the query/param parsing helpers (getStringParam, validateReqQuery*, get*FromQuery) — re-exported from the package root, so consumer imports are unchanged
src/http/downloads.ts createDownloadHandler, createDlHandler, createDlFilenameHandler
src/http/updates.ts createUpdateRedirectHandler, createUpdateOSXHandler (Squirrel.Mac), createUpdateWinHandler (Squirrel.Windows RELEASES)
src/http/api.ts createApiChannelsHandler, createApiStatusHandler, createApiVersionsHandler
src/http/notes.ts createNotesHandler
src/http/context.ts PecansHttpContext — the narrow capability interface the handlers get from the composition root
src/pecans.ts (~300 lines) Pecans stays the composition root: router wiring, beforeDownload/afterDownload events around serveAsset, and thin delegating methods

Handler factories

Each module exports create<Route>Handler(ctx) returning a standard (req, res, next) Express handler — the ecosystem's higher-order-handler idiom (cors(), multer(opts), …): ctx binds once at composition time and the product is a plain RequestHandler, independently mountable without Pecans. Pecans builds the handler set in its constructor.

Fidelity notes

  • The class keeps thin delegating methods (handleDownloadthis.handlers.download(...)), and the router binds the methods — preserving the public/protected surface and the subclass-override point; the unit suite passes without modification. (Dropping the delegates and mounting factory outputs directly is a possible follow-up if handler overriding is declared a non-goal.)
  • dl still flows through ctx.queryReleases → Pecans.queryReleases, exactly like the old this.queryReleases call, so host overrides of that public method keep applying.
  • Route registration order (including the /download/version before /download/:tag/:filename shadowing fix) and the router-scoped errorHandler() are byte-identical.
  • Only non-move change, review-driven (d5ac57f): the deprecated /update redirect and the Squirrel.Mac feed url now guard non-string query values (single-string required + encoded) instead of interpolating raw req.query.
  • Zero module cycles (madge-verified).

Verification

  • npm test: 31 files / 718 passed, unchanged
  • lint, typecheck, format, build green; packed tarball smoke-tested from CJS and ESM (root exports of the moved query helpers intact)

🤖 Generated with Claude Code

https://claude.ai/code/session_015zUyj4PpSog9RkrYxzFRhM

Pure move, third and final Phase 7 PR: handler bodies relocate verbatim
into src/http/{downloads,updates,api,notes}.ts against a narrow
PecansHttpContext, and the query-parsing helpers into src/http/query.ts
(re-exported from the package root, so consumer imports are unchanged).

Pecans stays the composition root: router wiring, the
beforeDownload/afterDownload events around serveAsset, and thin
delegating methods that keep the class surface (and host overrides of
public methods like queryReleases) working exactly as before. HTTP
behavior is unchanged; the contract suite passes untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015zUyj4PpSog9RkrYxzFRhM

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors Pecans’ Express composition root by splitting the HTTP handler implementations out of src/pecans.ts into dedicated src/http/* modules while keeping the existing routing surface and delegation points on Pecans.

Changes:

  • Introduces PecansHttpContext and moves route handlers into src/http/{downloads,updates,api,notes}.ts as plain (ctx, req, res, next) functions.
  • Moves request query/param helpers into src/http/query.ts and re-exports them from src/pecans.ts to preserve existing import paths.
  • Keeps Pecans as the composition root with thin delegate methods that call into the new handler modules.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/pecans.ts Converts handler bodies into delegates and re-exports query helpers; builds a shared HTTP context.
src/http/context.ts Defines the narrow capability interface (PecansHttpContext) used by handlers.
src/http/query.ts Houses route param + query parsing/validation helpers (moved from Pecans).
src/http/downloads.ts Implements legacy and discrete download routes using the shared context.
src/http/updates.ts Implements Squirrel.Mac and Squirrel.Windows update endpoints using the shared context.
src/http/api.ts Implements /api/channels, /api/status, and /api/versions handlers.
src/http/notes.ts Implements /notes{/:version} handler with formatting/validation preserved.

Comment thread src/http/downloads.ts Outdated
Comment thread src/http/updates.ts Outdated
Comment thread src/http/updates.ts Outdated
The only non-move changes in this PR, driven by review: the deprecated
/update redirect and the Squirrel.Mac feed url previously interpolated
raw req.query values, so repeated params (arrays) produced malformed
urls. The redirect now requires single-string platform/version and
encodes them into the path; filetype coerces to a single string
(default zip) and is encoded into the feed url. Typo fix in a moved
comment (Copilot review x3).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015zUyj4PpSog9RkrYxzFRhM

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

Per maintainer preference: each src/http module exports
create<Route>Handler(ctx) returning a standard (req, res, next)
handler, so ctx binds once at composition time and the returned
functions are plain express RequestHandlers. Pecans builds the handler
set in its constructor and keeps the thin delegating methods, so the
class surface and host overrides are unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015zUyj4PpSog9RkrYxzFRhM

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Comment thread src/http/updates.ts
Comment thread src/http/updates.ts
Regression coverage for the d5ac57f guards (Copilot review): repeated
/update query params 400 instead of forming a malformed redirect, the
redirect path is encoded, an explicit ?filetype override lands in the
Squirrel.Mac feed url, and repeated ?filetype params fall back to zip.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015zUyj4PpSog9RkrYxzFRhM

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

@dopry
dopry merged commit 64ab341 into next Jul 16, 2026
3 checks passed
@dopry
dopry deleted the claude/pecans-phase-7c-http-split branch July 16, 2026 12:56
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.

3 participants