# 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", )`, 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).