1
0

bind-only-what-the-window-needs.md 4.8 KB

Bind only what the window needs

Branch: bound-surface → main

PR 8b of the review fixes plan (docs/review-fixes-plan.md), part of the 0.5.3 series; the version does not change in this PR.

What changed

The window can no longer reach the Go-only methods (S4, rest).

  • The problem: PR 5 hid LoadPath and AssignSamplePath with //wails:ignore. That only keeps them out of the generated bindings. Wails 3.1.0 binds every exported method of a bound type by reflection, so any script in the window could still call them by name with any path.
  • Reproduced first: on main, a scratch build confirmed it; see Testing.
  • The fix:
    • Service, the type main.go binds, now has only the 21 methods the frontend calls. None takes a file path.
    • The Go-only methods move to a new, unbound Host: LoadPath, AssignSamplePath, Dirty, SetCloser and AudioMiddleware. Host shares the Service's state, and NewService returns both.
    • Shared helpers: Service.Load and AssignSampleDialog call unexported helpers (loadPath, assignSample) that Host uses too.
    • No more //wails:ignore: nothing on Service needs it now.
  • main.go uses Host for the close hook, the file-drop handler and the audio middleware, and binds only Service.

Declining "Replace existing files?" forgets the target.

  • Before, Go kept the chosen folder or zip path, so a later ExportFolder(true) would have overwritten it without asking.
  • The new bound CancelExport() forgets both targets. exportWith in store.svelte.ts calls it when the user declines.

Tests.

  • TestBoundMethods lists *Service's exported methods by reflection and compares them with an explicit list. If they differ, the message explains:
    • every exported method can be called by any script in the window;
    • a new one must not take a file path, since Go-only methods belong on Host;
    • it must be added to the list on purpose.

With LoadPath(string) temporarily added back to Service, it fails as intended.

  • TestCancelExport: after CancelExport, ExportFolder(true) and ExportZip(true) fail with "choose where to export first" and write nothing.
  • Existing tests reach the Go-only methods through hostOf(s).

Notes

  • The scratch probe. These lines were appended to frontend/src/main.ts and not committed; the file is back to its committed state:
    • It calls Call.ByName("git.monoexp.com/bajdev/mpckit/internal/app.Service.LoadPath", <path>), and in the fixed build also AssignSamplePath.
    • The webview's console can't be seen in a headless run, so the probe reports through timing, using the bound CloseWindow:
    • if a call succeeds, it closes the app at once;
    • if every call is rejected with "unknown bound method name", it closes after 6 seconds;
    • anything else leaves the app running until the 15–20 second timeout.
    • Startup takes about 4 seconds, so success is about 4 s and rejection about 10 s.
  • The probe results:

| Build | Probe | Result | | --- | --- | --- | | main before this PR | LoadPath | Closed after 4 s: the call succeeded and Go loaded the file. | | main before this PR | control: a method that does not exist | Closed after 10 s: rejected as unknown. | | This branch | LoadPath and AssignSamplePath | Closed after 10 s, twice: both rejected with "unknown bound method name". |

  • CloseWindow stays bound, because the frontend needs it after "Close without exporting?". It takes no arguments and only closes the window.

Testing

On the server, every command with GOTOOLCHAIN=go1.27.4:

  • go test ./... passes, including TestBoundMethods and TestCancelExport.
  • go vet ./... (also with GOOS=windows) and staticcheck ./... are clean.
  • govulncheck ./...: "No vulnerabilities found."
  • In frontend: npm ci, npm run check (0 errors, 0 warnings) and npm run build.
  • wails3 build builds, and the app starts under Xvfb.
  • The scratch probe, as above.

On the laptop (PowerShell, in the repo):

  1. git fetch; git checkout bound-surface
  2. go test ./internal/app: ok.
  3. wails3 dev, then:
    • Load: load testdata\device\DemoFile.xpj. It opens as before.
    • Preview: click A1, then B2. Each plays.
    • File drop: drop a WAV file onto an empty pad. It is assigned.
    • Close prompt: change something, then close the window. "Close without exporting?" appears. Cancel keeps the app open; choosing to close closes it.
  4. Run wails3 dev again, assign a WAV, and export:
    • Export to folder into an empty folder: it exports.
    • Export to folder into the same folder again, and choose Replace: it exports.
    • Once more, and choose Cancel at "Replace existing files?": nothing is written, and no error shows.
    • Export zip: the same three steps (new file, Replace, Cancel).