create-paratix 0.0.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +218 -43
- package/dist/index.d.ts +57 -0
- package/dist/index.js +1183 -0
- package/package.json +25 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# create-paratix
|
|
2
2
|
|
|
3
|
-
Scaffolds a new [Paratix](https://github.com/sebastian-software/paratix) server project.
|
|
3
|
+
Scaffolds a new [Paratix](https://github.com/sebastian-software/paratix) server project. The CLI now explains which initial SSH user Paratix needs for the very first connection and lets you choose the matching bootstrap path via arrow-key selection: explicit `root` bootstrap or direct admin-user hardening.
|
|
4
4
|
|
|
5
5
|
## Quick Start
|
|
6
6
|
|
|
@@ -20,6 +20,22 @@ yarn create paratix my-server
|
|
|
20
20
|
bunx create-paratix my-server
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
+
Optional non-interactive bootstrap values:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
# npm
|
|
27
|
+
npm create paratix my-server -- --host example.com --initial-user root --admin-public-key-file ~/.ssh/id_ed25519.pub
|
|
28
|
+
|
|
29
|
+
# pnpm
|
|
30
|
+
pnpm create paratix my-server --host example.com --initial-user root --admin-public-key-file ~/.ssh/id_ed25519.pub
|
|
31
|
+
|
|
32
|
+
# yarn
|
|
33
|
+
yarn create paratix my-server --host deploy.example.com --initial-user deploy --admin-public-key "ssh-ed25519 AAAA... you@example.com"
|
|
34
|
+
|
|
35
|
+
# bun
|
|
36
|
+
bunx create-paratix my-server --host deploy.example.com --initial-user deploy --admin-public-key-file ~/.ssh/id_ed25519.pub
|
|
37
|
+
```
|
|
38
|
+
|
|
23
39
|
**Step 2 -- Enter the directory**
|
|
24
40
|
|
|
25
41
|
Dependencies are installed automatically. If installation fails, run your package manager's install command manually.
|
|
@@ -28,7 +44,15 @@ Dependencies are installed automatically. If installation fails, run your packag
|
|
|
28
44
|
cd my-server
|
|
29
45
|
```
|
|
30
46
|
|
|
31
|
-
**Step 3 --
|
|
47
|
+
**Step 3 -- Review `server.ts`** with your final hostname, admin username, selected public key or placeholder, and the modules you want to apply.
|
|
48
|
+
|
|
49
|
+
The scaffold also includes an explicit bootstrap switch driven by `PARATIX_FIRST_RUN`:
|
|
50
|
+
|
|
51
|
+
- first run: call `paratix apply ... --first-run`, which sets `PARATIX_FIRST_RUN=true`, keeps SSH on port `22`, opens firewall port `22`, and uses `strictHostKeyChecking: "accept-new"`
|
|
52
|
+
- root bootstrap path: the generated playbook also writes a dedicated `/etc/sudoers.d` drop-in so the new admin user can continue with `NOPASSWD sudo` after the first run
|
|
53
|
+
- later runs: call `paratix apply ...` without `--first-run`, so the generated playbook switches to port `2222`, closes SSH port `22` in the firewall, and returns to strict host-key checking
|
|
54
|
+
- the generated playbook still opens port `2222` before `sshd.port(2222)` runs, so the first real apply can reconnect safely
|
|
55
|
+
- the generated playbook now stops the explicit first run after SSH hardening, kernel hardening, and automatic security upgrades, so later application services run only on the hardened baseline
|
|
32
56
|
|
|
33
57
|
**Step 4 -- Apply**
|
|
34
58
|
|
|
@@ -40,67 +64,218 @@ pnpm apply # apply to the server
|
|
|
40
64
|
# npm
|
|
41
65
|
npm run apply:dry
|
|
42
66
|
npm run apply
|
|
67
|
+
npm run lint
|
|
68
|
+
npm run format:check
|
|
69
|
+
npm run format:fix
|
|
43
70
|
```
|
|
44
71
|
|
|
45
72
|
## Project Structure
|
|
46
73
|
|
|
47
|
-
| File / Directory
|
|
48
|
-
|
|
|
49
|
-
| `server.ts`
|
|
50
|
-
| `package.json`
|
|
51
|
-
| `tsconfig.json`
|
|
52
|
-
|
|
|
53
|
-
| `.
|
|
54
|
-
| `
|
|
74
|
+
| File / Directory | Purpose |
|
|
75
|
+
| ------------------ | -------------------------------------------------------------------------------- |
|
|
76
|
+
| `server.ts` | Your playbook. Edit this file. |
|
|
77
|
+
| `package.json` | Includes `apply`, `apply:dry`, `lint`, `format:check`, and `format:fix` scripts. |
|
|
78
|
+
| `tsconfig.json` | TypeScript config (ES2024, ESNext/Bundler, strict) for direct `tsx` use. |
|
|
79
|
+
| `eslint.config.ts` | ESLint config via `eslint-config-setup` for Node-based scaffold projects. |
|
|
80
|
+
| `.prettierrc` | Prettier defaults for the scaffolded project. |
|
|
81
|
+
| `.prettierignore` | Excludes lockfiles from Prettier runs. |
|
|
82
|
+
| `.gitignore` | Excludes `node_modules/`, `dist/`, `.env`, and log files. |
|
|
83
|
+
| `.env.example` | Template for secrets. Copy to `.env` and fill in values. |
|
|
84
|
+
| `files/` | Place template files here. They get uploaded to the server at apply time. |
|
|
55
85
|
|
|
56
86
|
## Writing Your Playbook
|
|
57
87
|
|
|
58
|
-
`server.ts` exports a server definition. The
|
|
88
|
+
`server.ts` exports a server definition. The generated file depends on the initial SSH user you choose:
|
|
89
|
+
|
|
90
|
+
- `root`: Bootstrap once via `root`, create a dedicated admin user, then switch `ssh.user` to that admin user and disable root login.
|
|
91
|
+
- `admin`: Connect directly as the named admin user and scaffold the hardened end state immediately.
|
|
92
|
+
|
|
93
|
+
The direct admin-user path looks like this:
|
|
59
94
|
|
|
60
95
|
```typescript
|
|
61
|
-
import {
|
|
62
|
-
import { package as
|
|
96
|
+
import { recipe, server } from "paratix"
|
|
97
|
+
import { hostname, net, package as packages, ssh, sshd, ufw, user } from "paratix/modules"
|
|
98
|
+
|
|
99
|
+
const adminUser = "paratix"
|
|
100
|
+
const adminPublicKey = "ssh-ed25519 REPLACE_ME_WITH_YOUR_PUBLIC_KEY"
|
|
101
|
+
const serverName = "my-server"
|
|
102
|
+
const FIRST_RUN = process.env["PARATIX_FIRST_RUN"] === "true"
|
|
103
|
+
const sshPorts = FIRST_RUN ? [22] : [2222]
|
|
104
|
+
const firewallTcpPorts = FIRST_RUN ? [22, 2222, 80, 443] : [2222, 80, 443]
|
|
105
|
+
const strictHostKeyChecking = FIRST_RUN ? "accept-new" : "yes"
|
|
63
106
|
|
|
64
107
|
export default server({
|
|
65
|
-
name: "my-server",
|
|
66
108
|
host: "1.2.3.4",
|
|
67
|
-
|
|
68
|
-
user: "root",
|
|
69
|
-
ports: [22],
|
|
70
|
-
privateKey: "~/.ssh/id_ed25519",
|
|
71
|
-
},
|
|
109
|
+
name: serverName,
|
|
72
110
|
env: {
|
|
73
|
-
|
|
111
|
+
FIRST_RUN,
|
|
112
|
+
SERVER_NAME: serverName,
|
|
74
113
|
SSH_PORT: 2222,
|
|
75
114
|
},
|
|
115
|
+
ssh: {
|
|
116
|
+
ports: sshPorts,
|
|
117
|
+
privateKey: "~/.ssh/id_ed25519", // "~" is expanded by Paratix
|
|
118
|
+
user: adminUser,
|
|
119
|
+
// FIRST_RUN keeps the bootstrap path explicit:
|
|
120
|
+
// - pass `paratix apply ... --first-run` for the bootstrap run
|
|
121
|
+
// - later runs omit that flag and go through port 2222 with strict host-key checking again
|
|
122
|
+
strictHostKeyChecking,
|
|
123
|
+
// expectedHostFingerprint: "SHA256:REPLACE_ME_WITH_YOUR_HOST_FINGERPRINT",
|
|
124
|
+
// expectedHostPublicKey: "ssh-ed25519 REPLACE_ME_WITH_YOUR_HOST_PUBLIC_KEY",
|
|
125
|
+
},
|
|
76
126
|
run: [
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
127
|
+
net.hosts("127.0.1.1", [serverName]),
|
|
128
|
+
hostname.set(serverName),
|
|
129
|
+
packages.upgrade("2026-03-01"),
|
|
130
|
+
packages.installed("curl", "htop", "ufw"),
|
|
131
|
+
|
|
132
|
+
recipe("admin-access", [
|
|
133
|
+
user.present(adminUser, {
|
|
134
|
+
groups: ["sudo"],
|
|
135
|
+
shell: "/bin/bash",
|
|
136
|
+
}),
|
|
137
|
+
ssh.authorizedKeys(adminUser, adminPublicKey),
|
|
138
|
+
]),
|
|
139
|
+
|
|
140
|
+
recipe("firewall", [ufw.rule("allow", firewallTcpPorts), ufw.enabled()]),
|
|
141
|
+
|
|
142
|
+
recipe("ssh-hardening", [
|
|
143
|
+
sshd.port(2222),
|
|
144
|
+
sshd.config({
|
|
145
|
+
PasswordAuthentication: "no",
|
|
146
|
+
PermitRootLogin: "no",
|
|
147
|
+
}),
|
|
148
|
+
]),
|
|
149
|
+
|
|
150
|
+
recipe("kernel-hardening", [
|
|
151
|
+
sysctl.set("fs.protected_hardlinks", "1"),
|
|
152
|
+
sysctl.set("fs.protected_symlinks", "1"),
|
|
153
|
+
sysctl.set("kernel.dmesg_restrict", "1"),
|
|
154
|
+
sysctl.set("kernel.kptr_restrict", "2"),
|
|
155
|
+
sysctl.set("net.ipv4.conf.all.rp_filter", "1"),
|
|
156
|
+
sysctl.set("net.ipv4.conf.default.rp_filter", "1"),
|
|
157
|
+
sysctl.set("net.ipv4.tcp_syncookies", "1"),
|
|
158
|
+
]),
|
|
159
|
+
|
|
160
|
+
recipe("automatic-security-upgrades", [
|
|
161
|
+
packages.installed("unattended-upgrades"),
|
|
162
|
+
file.copy("/etc/apt/apt.conf.d/20auto-upgrades", "./files/20auto-upgrades", {
|
|
163
|
+
mode: "0644",
|
|
164
|
+
owner: "root:root",
|
|
165
|
+
}),
|
|
166
|
+
file.copy("/etc/apt/apt.conf.d/50unattended-upgrades", "./files/50unattended-upgrades", {
|
|
167
|
+
mode: "0644",
|
|
168
|
+
owner: "root:root",
|
|
169
|
+
}),
|
|
170
|
+
]),
|
|
171
|
+
|
|
172
|
+
firstRun.stop("Bootstrap foundation complete; rerun without --first-run to continue."),
|
|
173
|
+
|
|
174
|
+
// Add application and user-facing services below this line.
|
|
96
175
|
],
|
|
97
176
|
})
|
|
98
177
|
```
|
|
99
178
|
|
|
179
|
+
The generated `tsconfig.json` is intentionally DX-oriented for `tsx`-executed TypeScript projects:
|
|
180
|
+
|
|
181
|
+
- `module: "ESNext"`
|
|
182
|
+
- `moduleResolution: "Bundler"`
|
|
183
|
+
- `include: ["**/*.ts"]`
|
|
184
|
+
|
|
185
|
+
That means extensionless relative imports in your `.ts` sources work without NodeNext-style `.js` suffixes. This is a deliberate trade-off in favor of authoring ergonomics over strict Node-ESM path checking.
|
|
186
|
+
|
|
187
|
+
The scaffold also includes Prettier out of the box:
|
|
188
|
+
|
|
189
|
+
- `format:check` runs `prettier --check .`
|
|
190
|
+
- `format:fix` runs `prettier --write .`
|
|
191
|
+
- `.prettierignore` excludes lockfiles such as `pnpm-lock.yaml`
|
|
192
|
+
|
|
193
|
+
The scaffold also includes ESLint:
|
|
194
|
+
|
|
195
|
+
- `lint` runs `eslint .`
|
|
196
|
+
- `eslint.config.ts` uses `await getEslintConfig({ node: true })`
|
|
197
|
+
|
|
198
|
+
Wenn dein Server initial nur `root` per SSH anbietet, wähle im Prompt `root` oder rufe das Scaffold nicht-interaktiv mit `--initial-user root` auf. Dieses Template bleibt bewusst als temporärer Bootstrap markiert, erstellt den dedizierten Admin-User, legt einen `NOPASSWD sudo`-Eintrag für ihn unter `/etc/sudoers.d/` an und lässt Root-Login nur vorübergehend auf `prohibit-password`, bis du `ssh.user` auf den Admin-User umgestellt hast.
|
|
199
|
+
|
|
200
|
+
Wenn bereits ein Admin-User wie `deploy`, `ubuntu` oder `admin` existiert, wähle diesen Namen direkt. Dann erzeugt `create-paratix` keinen Root-Bootstrap-Pfad, sondern scaffoldet sofort den gehärteten Zielzustand für genau diesen User.
|
|
201
|
+
|
|
202
|
+
### Initial user selection
|
|
203
|
+
|
|
204
|
+
Standardmäßig fragt `create-paratix` interaktiv:
|
|
205
|
+
|
|
206
|
+
1. Welche Domain oder IP soll als Zielhost in `server.ts` stehen?
|
|
207
|
+
2. Ist der initiale SSH-User `root` oder ein Admin-User?
|
|
208
|
+
3. Falls Admin-User: Wie heißt dieser User konkret?
|
|
209
|
+
4. Soll ein vorhandener Public Key aus `~/.ssh` direkt übernommen werden?
|
|
210
|
+
|
|
211
|
+
Im interaktiven Modus zeigt `create-paratix` dafür eine kurze Erklärung und eine Auswahl per Pfeiltasten:
|
|
212
|
+
|
|
213
|
+
- `Root user`: frischer Server mit SSH nur als `root`; Paratix bootstrapt zuerst einen dedizierten Admin-User
|
|
214
|
+
- `Admin user`: ein konkreter Admin-User existiert bereits; Paratix verbindet sich direkt als dieser User
|
|
215
|
+
|
|
216
|
+
Nicht-interaktiv funktioniert derselbe Vertrag über `--host`, `--initial-user` und optional einen Admin-Public-Key:
|
|
217
|
+
|
|
218
|
+
```sh
|
|
219
|
+
# Root bootstrap
|
|
220
|
+
pnpm create paratix my-server --host example.com --initial-user root --admin-public-key-file ~/.ssh/id_ed25519.pub
|
|
221
|
+
|
|
222
|
+
# Existing admin user
|
|
223
|
+
pnpm create paratix my-server --host deploy.example.com --initial-user deploy --admin-public-key "ssh-ed25519 AAAA... you@example.com"
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Wichtig für den ersten echten Lauf: Das Scaffold liest `FIRST_RUN` aus `process.env.PARATIX_FIRST_RUN`. Für den Bootstrap rufst du Paratix explizit mit `--first-run` auf. Danach lässt du den Flag bei normalen Läufen weg; dann verwendet dasselbe Playbook Port `2222`, entfernt Port `22` aus der Firewall und kehrt zu strengem Host-Key-Checking zurück. Die Firewall-Freigabe für `2222` bleibt bewusst vor dem eigentlichen SSH-Portwechsel, damit Paratix nach `sshd.port(...)` sofort sicher reconnecten kann.
|
|
227
|
+
|
|
228
|
+
### Public key bootstrap
|
|
229
|
+
|
|
230
|
+
Im interaktiven Modus bietet `create-paratix` zusätzlich an, einen vorhandenen Public Key aus
|
|
231
|
+
`~/.ssh` direkt in `server.ts` zu übernehmen.
|
|
232
|
+
|
|
233
|
+
- Wenn du zustimmst und mehrere `.pub`-Dateien existieren, kannst du den gewünschten Key per
|
|
234
|
+
Pfeiltasten auswählen.
|
|
235
|
+
- Wenn keine lesbaren `.pub`-Dateien gefunden werden, bleibt das bestehende Placeholder-Template
|
|
236
|
+
erhalten.
|
|
237
|
+
- Nicht-interaktiv kannst du denselben Wert über `--admin-public-key` oder
|
|
238
|
+
`--admin-public-key-file` setzen.
|
|
239
|
+
- Wenn kein CLI-Key gesetzt ist, bleibt in nicht-interaktiven Aufrufen weiter der Placeholder
|
|
240
|
+
erhalten.
|
|
241
|
+
|
|
242
|
+
### Host-key bootstrap
|
|
243
|
+
|
|
244
|
+
Paratix verwendet standardmäßig striktes Host-Key-Checking. `create-paratix` bietet deshalb interaktiv an, den aktuell auf SSH-Port `22` präsentierten Host-Key direkt per `ssh2` auszulesen und als `expectedHostFingerprint` in `server.ts` zu pinnen.
|
|
245
|
+
|
|
246
|
+
Wenn du diesen Schritt bestätigst, erzeugt das Scaffold direkt einen expliziten Trust Anchor:
|
|
247
|
+
|
|
248
|
+
```ts
|
|
249
|
+
const strictHostKeyChecking = "yes"
|
|
250
|
+
// ...
|
|
251
|
+
expectedHostFingerprint: "SHA256:..."
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Das ist ein bewusster TOFU-Schritt beim Scaffold-Zeitpunkt: Der Fingerprint stammt von dem Host-Key, den der Server im Moment des Scaffoldings auf Port `22` präsentiert. Du kannst ihn später jederzeit manuell prüfen oder ersetzen.
|
|
255
|
+
|
|
256
|
+
Wenn du den Abruf ablehnst oder er fehlschlägt, bleibt der bisherige Fallback erhalten:
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
const FIRST_RUN = process.env["PARATIX_FIRST_RUN"] === "true"
|
|
260
|
+
const strictHostKeyChecking = FIRST_RUN ? "accept-new" : "yes"
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Das ist ein bewusst markierter Übergangsmodus für den ersten verifizierten Kontakt mit einem frischen Host. Direkt daneben enthält das generierte `server.ts` weiterhin kommentierte Platzhalter für:
|
|
264
|
+
|
|
265
|
+
- `expectedHostFingerprint`
|
|
266
|
+
- `expectedHostPublicKey`
|
|
267
|
+
|
|
268
|
+
Empfohlener Ablauf:
|
|
269
|
+
|
|
270
|
+
1. Verifiziere den Host-Key deines Servers out of band.
|
|
271
|
+
2. Führe den ersten `apply:dry` und `apply` mit `--first-run` aus.
|
|
272
|
+
3. Führe spätere Runs ohne `--first-run` aus.
|
|
273
|
+
4. Optional: pinne zusätzlich `expectedHostFingerprint` oder `expectedHostPublicKey`.
|
|
274
|
+
|
|
100
275
|
Key concepts:
|
|
101
276
|
|
|
102
277
|
- **Modules** -- each item in `run` is a module. A module checks the current server state and applies changes only when needed (idempotent).
|
|
103
|
-
- **Recipes** -- `recipe()` groups related modules under a name. If any module in the group changes something, signals fire after the group completes
|
|
278
|
+
- **Recipes** -- `recipe()` groups related modules under a name. If any module in the group changes something, signals fire after the group completes.
|
|
104
279
|
- **Signals** -- actions that run after a recipe when at least one module in it made a change. Useful for reloading services.
|
|
105
280
|
- **Env** -- values in the `env` field are available in template files as `{{KEY}}`. See [Environment Variables](#environment-variables) below.
|
|
106
281
|
|
|
@@ -163,10 +338,10 @@ The example contains:
|
|
|
163
338
|
Env values come from three sources, merged in this order (last wins):
|
|
164
339
|
|
|
165
340
|
1. `--env-file <path>`
|
|
166
|
-
2.
|
|
167
|
-
3.
|
|
341
|
+
2. The `env` field in `server()`
|
|
342
|
+
3. `--env <key=value>` flags -- these have the highest priority
|
|
168
343
|
|
|
169
|
-
> **Note:**
|
|
344
|
+
> **Note:** CLI `--env` flags override both `.env` files and `server({ env })`. Put stable project defaults in `server({ env })`, environment-specific values in `.env` files, and one-off overrides on the CLI.
|
|
170
345
|
|
|
171
346
|
### Template files
|
|
172
347
|
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
type PackageManager = {
|
|
2
|
+
command: string;
|
|
3
|
+
name: string;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
type InitialUserConfig = {
|
|
7
|
+
kind: "admin";
|
|
8
|
+
user: string;
|
|
9
|
+
} | {
|
|
10
|
+
kind: "root";
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type SelectOption<TValue extends string> = {
|
|
14
|
+
description: string;
|
|
15
|
+
label: string;
|
|
16
|
+
value: TValue;
|
|
17
|
+
};
|
|
18
|
+
type SelectFunction<TValue extends string> = (prompt: string, options: Array<SelectOption<TValue>>) => Promise<TValue>;
|
|
19
|
+
|
|
20
|
+
type PromptFunction = (question: string) => Promise<string>;
|
|
21
|
+
declare function promptForHost(prompt?: PromptFunction, closePrompt?: () => void): Promise<string>;
|
|
22
|
+
declare function promptForInitialUserConfig(prompt?: PromptFunction, select?: SelectFunction<"admin" | "root">): Promise<InitialUserConfig>;
|
|
23
|
+
declare function promptForAdminPublicKey(select?: SelectFunction<string>, publicKeys?: Array<{
|
|
24
|
+
key: string;
|
|
25
|
+
label: string;
|
|
26
|
+
path: string;
|
|
27
|
+
}>): Promise<string | undefined>;
|
|
28
|
+
declare function promptForHostFingerprint(host: string, select?: SelectFunction<"placeholder" | "scan">, scanner?: (host: string) => Promise<string>): Promise<string | undefined>;
|
|
29
|
+
|
|
30
|
+
declare function normalizeInitialUserName(name: string): string;
|
|
31
|
+
declare function isValidInitialUserName(name: string): boolean;
|
|
32
|
+
declare function normalizeHost(value: string): string;
|
|
33
|
+
declare function isValidHost(value: string): boolean;
|
|
34
|
+
|
|
35
|
+
type ScaffoldOptions = {
|
|
36
|
+
adminPublicKey?: string;
|
|
37
|
+
expectedHostFingerprint?: string;
|
|
38
|
+
host?: string;
|
|
39
|
+
initialUser?: InitialUserConfig;
|
|
40
|
+
installer?: (projectDirectory: string, packageManager: PackageManager) => boolean;
|
|
41
|
+
};
|
|
42
|
+
declare function writeProjectFiles(projectDirectory: string, options?: ScaffoldOptions): void;
|
|
43
|
+
declare function isValidProjectName(name: string): boolean;
|
|
44
|
+
declare function normalizeProjectName(name: string): string;
|
|
45
|
+
declare function parseCliArguments(argv: string[]): {
|
|
46
|
+
adminPublicKey: string | undefined;
|
|
47
|
+
adminPublicKeyFile: string | undefined;
|
|
48
|
+
host: string | undefined;
|
|
49
|
+
initialUser: string | undefined;
|
|
50
|
+
projectName: string | undefined;
|
|
51
|
+
};
|
|
52
|
+
declare function parseInitialUserConfig(value: string): InitialUserConfig;
|
|
53
|
+
declare function validateHost(value: string): string;
|
|
54
|
+
declare function scaffoldProject(projectName: string, pm: PackageManager, options?: ScaffoldOptions): boolean;
|
|
55
|
+
declare function isDirectExecution(moduleUrl: string, argv1: null | string | undefined): boolean;
|
|
56
|
+
|
|
57
|
+
export { type InitialUserConfig, isDirectExecution, isValidHost, isValidInitialUserName, isValidProjectName, normalizeHost, normalizeInitialUserName, normalizeProjectName, parseCliArguments, parseInitialUserConfig, promptForAdminPublicKey, promptForHost, promptForHostFingerprint, promptForInitialUserConfig, scaffoldProject, validateHost, writeProjectFiles };
|