feat(wails): move the frontend onto v3's generated bindings

frontend/wailsjs/ is deleted and frontend/bindings/ takes its place —
a real TypeScript module tree nested by Go import path, generated by
wails3's static analyser rather than by building the app and running
it.  The @go alias absorbs the constant prefix, so a call site imports
'@go/library/library.js' and the codemod over all 93 sites was a
specifier rewrite plus splitting @go/models' namespaces into one
import per package.

The 12 SetContext bindings and the fake `context` model are gone, as
Phase 2's ServiceStartup port promised: 272 methods across 12
services, none of them plumbing.

@runtime/runtime is now a local shim (src/wails/runtime.ts) over
@wailsio/runtime, so the 22 EventsOn imports are untouched.  It
unwraps v3's WailsEvent into v2's callback shape, which is exact here:
nothing in backend/events passes more than one data argument, and v3
only packs arguments into a slice when there is more than one.

v3 tells the truth about two things v2 lied about, and that is most of
the diff.  A Go nil slice really does arrive as JSON null, and a Go
named string type really is an enum; v2 typed them as T[] and string.
utils/binding.ts states the app's actual contract — an absent list is
an empty list — once, at the boundary where it is true, and also drops
the CancellablePromise the app never cancels.  Four test fixtures
widen an enum field back to its value union.

Not done, and Phase 5's to fix: frontend/test/support/wails-fake.ts
still fakes window.go, which v3 does not have, so `make ui-test` is
broken and harness.test.ts fails to compile on EventsEmit.  That test
also asserts v2 ordering that no longer holds — v3's Events.Emit calls
the backend and does not notify in-page listeners at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UDCbcCZQepnpSQYJ6SxxZm
This commit is contained in:
yonluandClaude Opus 5 committed 2026-08-14 17:48:38 -04:00
1 parent c9905fbcff
commit 162c68769f
133 files changed
+5755 -5094

No files matched your search

@@ -0,0 +1,15 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
import * as Service from "./service.js";
export {
Service
};
export {
Kind
} from "./models.js";
export type {
Shelf
} from "./models.js";
@@ -0,0 +1,53 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import * as library$0 from "../library/models.js";
/**
* Kind identifies what a shelf is built from, so the frontend can pick
* an icon and the e2e suite can assert on a shelf without matching
* display copy.
*/
export enum Kind {
/**
* The Go zero value for the underlying type of the enum.
*/
$zero = "",
/**
* Shelf kinds.
*/
KindRecentlyPlayed = "recently-played",
KindRecentlyAdded = "recently-added",
KindMostPlayed = "most-played",
KindUnplayed = "unplayed",
KindStale = "stale",
KindArtist = "artist",
KindGenre = "genre",
KindRandom = "random",
};
/**
* Shelf is one horizontal row on the home page.
*/
export interface Shelf {
/**
* ID is stable within a response, for list keying.
*/
"id": string;
"kind": Kind;
/**
* Title is the row heading.
*/
"title": string;
/**
* Subtitle says why these albums are here. It is not decoration:
* without it a shelf is indistinguishable from a random grid.
*/
"subtitle": string;
"albums": library$0.Album[] | null;
}
@@ -0,0 +1,27 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
/**
* Service builds the home page's shelves.
* @module
*/
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import { Call as $Call, CancellablePromise as $CancellablePromise } from "@wailsio/runtime";
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unused imports
import * as $models from "./models.js";
/**
* GetShelves returns the home page's rows, in display order.
*
* It is a single call rather than one per shelf because the shelves
* share an album lookup and because the page has nothing useful to
* render until it knows which rows exist — a page that pops rows in one
* at a time reflows under the user's cursor.
*/
export function GetShelves(): $CancellablePromise<$models.Shelf[] | null> {
return $Call.ByID(2822423495);
}