You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 5d0ca91
Browse filesBrowse the repository at this point in the historyBrowse files
fix(hub-ui-onboard): confirm installs in the terminal (#445)
* fix(hub-ui-onboard): require a terminal code to install or disable
* fix(hub-ui-onboard): confirm installs in the terminal through a configurable hook
* refactor(hub-ui-onboard): rename confirm option to onConfirm
Copy file name to clipboardExpand all lines: docs/content/1.guide/23.hub-ui-onboard.md
+26-3Lines changed: 26 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -15,7 +15,7 @@ A hub UI provider, its Vue runtime, and the devframes it mounts add tens of mega
15
15
16
16
The button sits at the bottom left, dimmed until hovered. It opens a panel with the product name and logo, one sentence, the exact command the install will run (for example `pnpm add -D @nuxt/devtools`), and three actions:
17
17
18
-
-**Install** runs the command in the project. The panel shows progress, then either the real dock replaces the button in place, or the panel asks for a restart.
18
+
-**Install** runs the command in the project after the developer allows it in the terminal (below). The panel shows progress, then either the real dock replaces the button in place, or the panel asks for a restart.
19
19
-**Hide for now** removes the button for the current browser tab.
20
20
-**Disable entirely** writes a state file so the host stops injecting the button on every later start.
-`scriptSrc`: `<base>embedded.js`, the URL to inject as `<script type="module">`.
40
40
-`disabled` and `installed`: what the host needs to decide whether to inject the script at all (below).
41
41
42
-
`packages` are package specs as the package manager accepts them. The package manager comes from the lockfile (`npm`, `pnpm`, `yarn`, `bun`, `deno`), `dev: true` adds `-D`, and `cwd` (default `process.cwd()`) is the project that receives the dependency. In a workspace, point `cwd` at the package that runs the dev server. The packages are fixed at creation, and a `POST` from another origin is refused.
42
+
`packages` are package specs as the package manager accepts them. The package manager comes from the lockfile (`npm`, `pnpm`, `yarn`, `bun`, `deno`), `dev: true` adds `-D`, and `cwd` (default `process.cwd()`) is the project that receives the dependency. In a workspace, point `cwd` at the package that runs the dev server. The packages are fixed at creation.
43
+
44
+
## Confirm the install
45
+
46
+
Install changes `package.json` and the lockfile, and a dev server can be reachable from other devices. So each install that the panel asks for needs the developer's permission. By default, the onboarding asks in the terminal that runs the dev server:
47
+
48
+
1. The user clicks Install. The panel shows "Confirm in your terminal..." and its request waits.
49
+
2. The terminal prints [DF9005](/errors/DF9005). The developer types `y` and presses Enter to allow the install. Any other answer refuses it.
50
+
3. The install runs. After a refusal, the panel says that the dev server did not allow the install.
51
+
52
+
When stdin is not a TTY (CI, a detached container, a task runner that pipes stdin), nobody can answer. The onboarding then refuses at once with [DF9006](/errors/DF9006). Only one question is open at a time: more clicks while it is open share its answer. A `POST` from another origin is refused with `403` before any question.
53
+
54
+
To ask in another way, pass `onConfirm`. It gets the `packages`, the exact `command`, and the panel's `request`, and returns `true` to allow the install. For example, a Nuxt module can ask through `consola`:
55
+
56
+
```ts
57
+
import { consola } from'consola'
58
+
59
+
const onboarding =createOnboarding({
60
+
packages: ['@nuxt/devtools'],
61
+
onConfirm: ({ command }) =>consola.prompt(`Run \`${command.join('')}\` for the browser that asked?`, { type: 'confirm' }),
62
+
})
63
+
```
64
+
65
+
Disable entirely does not ask. It changes only the state file in `node_modules/.devframe`.
43
66
44
67
## Hand the base to the hub
45
68
@@ -184,4 +207,4 @@ Frameworks with a `Request => Response` surface (Hono, Nitro, Deno) mount `onboa
184
207
185
208
## Errors
186
209
187
-
The Node side reports through `DF9000` to `DF9004`. An install failure or a throwing `onInstalled` also reaches the panel as `{ state: 'error', error: { code, message } }`, with a Retry button. See the [error reference](/errors).
210
+
The Node side reports through `DF9000` to `DF9006`. An install failure or a throwing `onInstalled` also reaches the panel as `{ state: 'error', error: { code, message } }`, with a Retry button. See the [error reference](/errors).
description: 'A browser asked to run `{command}`. Type y and press Enter to allow it.'
4
+
---
5
+
6
+
## Message
7
+
8
+
> A browser asked to run `{command}`. Type y and press Enter to allow it.
9
+
10
+
## Cause
11
+
12
+
Install changes `package.json` and the lockfile, and a dev server can be reachable from other devices. So each install that the panel asks for needs the developer's permission. The panel's `POST <base>__onboard/install` waits until you answer. Without an `onConfirm` option, `createOnboarding()` asks in the terminal that runs the dev server.
13
+
14
+
## Fix
15
+
16
+
If you clicked Install, type `y` and press Enter. Any other answer refuses the install, and the panel tells the user. If you did not click Install, press Enter. Another device or page can reach this dev server, so bind it to `localhost`.
17
+
18
+
To ask in another way, for example with your own logger, pass an `onConfirm` function to `createOnboarding()`.
19
+
20
+
## Source
21
+
22
+
-[`packages/hub-ui-onboard/src/terminal-confirm.ts`](https://github.com/devframes/devframe/blob/main/packages/hub-ui-onboard/src/terminal-confirm.ts): `confirmInTerminal()` prints this, then reads one line from stdin.
title: 'DF9006: No Terminal to Confirm the Install'
3
+
description: 'A browser asked to run `{command}`, but no interactive terminal can confirm it. The install was refused.'
4
+
---
5
+
6
+
## Message
7
+
8
+
> A browser asked to run `{command}`, but no interactive terminal can confirm it. The install was refused.
9
+
10
+
## Cause
11
+
12
+
Each install that the panel asks for needs the developer's permission ([DF9005](/errors/DF9005)). Without an `onConfirm` option, `createOnboarding()` asks in the terminal. Here stdin is not a TTY, so nobody can answer. This happens in CI, in a detached container, or when a task runner pipes stdin. The install is refused at once, and the panel tells the user.
13
+
14
+
## Fix
15
+
16
+
Run the command from the panel in a terminal yourself. Or pass an `onConfirm` function to `createOnboarding()` that asks in another way.
17
+
18
+
## Source
19
+
20
+
-[`packages/hub-ui-onboard/src/terminal-confirm.ts`](https://github.com/devframes/devframe/blob/main/packages/hub-ui-onboard/src/terminal-confirm.ts): `confirmInTerminal()` reports this and returns `false` when stdin is not a TTY.
Copy file name to clipboardExpand all lines: docs/content/8.references/6.hub-api.md
+3-2Lines changed: 3 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -96,14 +96,15 @@ What `createOnboarding()` from `@devframes/hub-ui-onboard` accepts and serves: [
96
96
|`stateDir`|`<cwd>/node_modules/.devframe`| Directory of the `hub-ui-onboard.json` state file |
97
97
|`dev`|`true`| Install as a devDependency |
98
98
|`branding`|`{}`|`productName` (default `Devframes`), `logo` (URL or `{ light, dark }`), `primaryColor`|
99
-
|`messages`| derived from `productName`| Overrides for `title`, `description`, `install`, `hide`, `disable`, `installing`, `restart`, `retry`|
99
+
|`messages`| derived from `productName`| Overrides for `title`, `description`, `install`, `confirming`, `refused`, `hide`, `disable`, `installing`, `restart`, `retry`|
100
100
|`onInstalled`| none | Runs after a verified install, or on the first request when the packages already exist; a returned handler takes over `base`|
101
+
|`onConfirm`|`y/N` in the terminal | Gets `{ packages, command, request }` before each install the panel asks for; return `true` to allow it. Refuses when stdin is not a TTY |
101
102
102
103
| Route | Serves |
103
104
| --- | --- |
104
105
|`GET <base>embedded.js`| the floating button, a self-contained ES module |
Copy file name to clipboardExpand all lines: examples/hub-onboard-vite/README.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,7 +8,7 @@ pnpm --filter hub-onboard-vite dev
8
8
9
9
Open the printed URL. The button at the bottom left opens a panel with two actions:
10
10
11
-
- Install runs `pnpm add -D @devframes/hub @devframes/hub-ui @devframes/plugin-git` in this directory. When it finishes, the host starts the real hub on `/__devframes/` in the same process and the button swaps itself for the floating dock.
11
+
- Install asks you to type `y` in the terminal that runs Vite, then runs `pnpm add -D @devframes/hub @devframes/hub-ui @devframes/plugin-git` in this directory. When it finishes, the host starts the real hub on `/__devframes/` in the same process and the button swaps itself for the floating dock.
12
12
- Hide for now hides the button for this browser tab.
13
13
- Disable entirely writes `node_modules/.devframe/hub-ui-onboard.json`. The host reads `onboarding.disabled` on the next start and injects no script.
0 commit comments