feat: let an app launch another app in the background

`puter.ui.launchApp(name, args)` had no way to say "I need this app's API,
not its window". That matters because we create and show an app's window
before the app's own code runs, so an app launched purely to serve another
one cannot avoid appearing on screen: the best it can do is call
`puter.ui.hideWindow()` once it boots, which reads as a window flashing
open and shut. In dashboard mode it was worse than a flash — the child
maximized into the tab and minimized its parent behind it, so asking a
service app a question took the user's app away from them.

So `launchApp` now accepts `background: true`, and the window starts
hidden. The app is otherwise entirely normal: it keeps its taskbar item,
so a user can see that it is running, show it, or close it, and it can
show itself with `puter.ui.showWindow()` whenever it has something to say.
Only a literal `true` counts, since the flag arrives over IPC from another
app.

The decision now lives in one predicate, `starts_hidden(app_info, options)`,
which folds this together with the existing app-level `background` flag and
is used everywhere the old flag was read — including the dashboard's
minimize-the-parent branch. `show_in_taskbar` deliberately still keys on the
app-level flag alone: an app that is always windowless has nothing to put in
the taskbar, while a background *launch* should stay visible there.

Existing callers are unaffected: with `background` unset, both paths
evaluate exactly as they did.
This commit is contained in:
Nariman Jelveh
2026-08-13 09:47:35 -07:00
parent 8ed8feed4b
commit e273431f14
6 changed files with 132 additions and 4 deletions
+33
View File
@@ -38,6 +38,17 @@ Paths of existing files to open with the launched app.
#### `options.pseudonym` (String)
A pseudonym to launch the app under.
#### `options.background` (Boolean)
If `true`, the app starts with its window hidden — for an app launched to do work
rather than to be looked at, such as one serving an API to yours over its
[`AppConnection`](/Objects/AppConnection). Without this, Puter creates and shows
the window before the app's own code runs, so a service app cannot avoid briefly
appearing on screen.
The app still appears in the taskbar, so the user can see it is running, show it,
or close it, and it can show itself at any time with
[`puter.ui.showWindow()`](/UI/showWindow). Defaults to `false`.
## Return value
A `Promise` that will resolve to an [`AppConnection`](/Objects/AppConnection) once the app is launched.
@@ -61,3 +72,25 @@ When private-access routing applies, the resolved connection may include
</body>
</html>
```
Launching an app in the background to use it as a service, with no window
appearing on screen:
```html
<html>
<body>
<script src="https://js.puter.com/v2/"></script>
<script>
(async () => {
const service = await puter.ui.launchApp({
name: 'contacts',
args: { service: 'contacts-api' },
background: true,
});
service.on('message', (msg) => console.log('from contacts:', msg));
service.postMessage({ hello: 'there' });
})();
</script>
</body>
</html>
```