vercel-vm-factory 0.1.1 → 0.1.2

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.
Files changed (3) hide show
  1. package/README.md +5 -0
  2. package/deploy-vm.mjs +69 -14
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -6,6 +6,7 @@ Create a tiny Vercel Container deployment: copy `wsterm` from `ghcr.io/v1xingyue
6
6
  npx vercel-vm-factory create \
7
7
  --base ubuntu \
8
8
  --project ws-shell-ubuntu \
9
+ --auth-mode basic \
9
10
  --auth-user admin \
10
11
  --auth-password change-me
11
12
  ```
@@ -14,6 +15,7 @@ GitHub OAuth is optional:
14
15
 
15
16
  ```bash
16
17
  npx vercel-vm-factory create \
18
+ --auth-mode github \
17
19
  --client-id YOUR_GITHUB_CLIENT_ID \
18
20
  --client-secret YOUR_GITHUB_CLIENT_SECRET \
19
21
  --github-userid 12345678
@@ -25,6 +27,8 @@ Run without flags for prompts:
25
27
  npx vercel-vm-factory create
26
28
  ```
27
29
 
30
+ The prompt asks for authentication first: `basic`, `github`, `both`, or `none`, then only asks for the fields that mode needs.
31
+
28
32
  Check local setup:
29
33
 
30
34
  ```bash
@@ -72,6 +76,7 @@ https://x-shell.vercel.app/auth/github/callback
72
76
 
73
77
  GitHub OAuth fields:
74
78
 
79
+ - Auth mode -> `--auth-mode basic|github|both|none`
75
80
  - Username -> `--auth-user`
76
81
  - Password -> `--auth-password`
77
82
  - Client ID -> `--client-id`
package/deploy-vm.mjs CHANGED
@@ -64,6 +64,7 @@ async function main() {
64
64
  const prod = args.prod !== "false";
65
65
  const dryRun = Boolean(args["dry-run"]);
66
66
  const skipLink = Boolean(args["skip-link"]);
67
+ const authMode = await chooseAuthMode(defaultAuthMode());
67
68
 
68
69
  const oauthRedirectUrl =
69
70
  args["redirect-url"] ??
@@ -83,7 +84,8 @@ async function main() {
83
84
  project,
84
85
  scope: scope || "default",
85
86
  source: wsShellImage,
86
- callback: oauthRedirectUrl,
87
+ auth: authMode,
88
+ ...(usesGitHubAuth(authMode) ? { callback: oauthRedirectUrl } : {}),
87
89
  dockerfile: path.join(appDir, "Dockerfile.vercel"),
88
90
  target: prod ? "production" : "preview",
89
91
  });
@@ -94,17 +96,23 @@ async function main() {
94
96
  }
95
97
 
96
98
  await ensureVercelReady();
97
- printOAuthGuide(oauthRedirectUrl);
98
-
99
- const authUsername = await secret("auth-user", "Basic auth username", process.env.AUTH_USERNAME ?? defaults["auth-user"]);
100
- const authPassword = await secret("auth-password", "Basic auth password", process.env.AUTH_PASSWORD ?? defaults["auth-password"]);
101
- const githubClientId = await secret("client-id", "GitHub client id", process.env.GITHUB_CLIENT_ID ?? defaults["client-id"]);
102
- const githubClientSecret = await secret(
103
- "client-secret",
104
- "GitHub client secret",
105
- process.env.GITHUB_CLIENT_SECRET ?? defaults["client-secret"],
106
- );
107
- const allowedUserIds = await secret("github-userid", "Allowed GitHub numeric user id(s)", process.env.ALLOWED_USER_IDS ?? defaults["github-userid"]);
99
+ if (usesGitHubAuth(authMode)) printOAuthGuide(oauthRedirectUrl);
100
+
101
+ const authUsername = usesBasicAuth(authMode)
102
+ ? await secret("auth-user", "Basic auth username", process.env.AUTH_USERNAME ?? defaults["auth-user"])
103
+ : "";
104
+ const authPassword = usesBasicAuth(authMode)
105
+ ? await secret("auth-password", "Basic auth password", process.env.AUTH_PASSWORD ?? defaults["auth-password"])
106
+ : "";
107
+ const githubClientId = usesGitHubAuth(authMode)
108
+ ? await secret("client-id", "GitHub client id", process.env.GITHUB_CLIENT_ID ?? defaults["client-id"])
109
+ : "";
110
+ const githubClientSecret = usesGitHubAuth(authMode)
111
+ ? await secret("client-secret", "GitHub client secret", process.env.GITHUB_CLIENT_SECRET ?? defaults["client-secret"])
112
+ : "";
113
+ const allowedUserIds = usesGitHubAuth(authMode)
114
+ ? await secret("github-userid", "Allowed GitHub numeric user id(s)", process.env.ALLOWED_USER_IDS ?? defaults["github-userid"])
115
+ : "";
108
116
 
109
117
  await writeDefaults(defaultsPath, {
110
118
  ...defaults,
@@ -112,6 +120,7 @@ async function main() {
112
120
  scope: scope || undefined,
113
121
  project,
114
122
  from: wsShellImage,
123
+ "auth-mode": authMode,
115
124
  "auth-user": authUsername,
116
125
  "auth-password": authPassword,
117
126
  "client-id": githubClientId,
@@ -138,12 +147,11 @@ async function main() {
138
147
  appDir,
139
148
  "--yes",
140
149
  "--logs",
141
- "--env",
142
- `OAUTH_REDIRECT_URL=${oauthRedirectUrl}`,
143
150
  ];
144
151
 
145
152
  if (authUsername) vercelArgs.push("--env", `AUTH_USERNAME=${authUsername}`);
146
153
  if (authPassword) vercelArgs.push("--env", `AUTH_PASSWORD=${authPassword}`);
154
+ if (usesGitHubAuth(authMode)) vercelArgs.push("--env", `OAUTH_REDIRECT_URL=${oauthRedirectUrl}`);
147
155
  if (githubClientId) vercelArgs.push("--env", `GITHUB_CLIENT_ID=${githubClientId}`);
148
156
  if (githubClientSecret) vercelArgs.push("--env", `GITHUB_CLIENT_SECRET=${githubClientSecret}`);
149
157
  if (allowedUserIds) vercelArgs.push("--env", `ALLOWED_USER_IDS=${allowedUserIds}`);
@@ -199,6 +207,7 @@ async function doctor() {
199
207
  printKeyValue("project", defaults.project || "not set");
200
208
  printKeyValue("scope", defaults.scope || "not set");
201
209
  printKeyValue("source image", defaults.from || "ghcr.io/v1xingyue/ws-shell:v1.1.alpine");
210
+ printKeyValue("auth mode", defaults["auth-mode"] || "not set");
202
211
  printKeyValue("auth user", defaults["auth-user"] ? mask(defaults["auth-user"]) : "not set");
203
212
  printKeyValue("auth password", defaults["auth-password"] ? mask(defaults["auth-password"]) : "not set");
204
213
  printKeyValue("client id", defaults["client-id"] ? mask(defaults["client-id"]) : "not set");
@@ -256,6 +265,51 @@ async function optionalValue(name, question, fallback) {
256
265
  return answer;
257
266
  }
258
267
 
268
+ function defaultAuthMode() {
269
+ if (args["auth-mode"]) return args["auth-mode"];
270
+ const hasBasic = Boolean(args["auth-user"] || args["auth-password"] || process.env.AUTH_USERNAME || process.env.AUTH_PASSWORD);
271
+ const hasGitHub = Boolean(args["client-id"] || args["client-secret"] || args["github-userid"] || process.env.GITHUB_CLIENT_ID || process.env.GITHUB_CLIENT_SECRET);
272
+ if (hasBasic && hasGitHub) return "both";
273
+ if (hasBasic) return "basic";
274
+ if (hasGitHub) return "github";
275
+ return defaults["auth-mode"] || (input.isTTY ? "basic" : "none");
276
+ }
277
+
278
+ async function chooseAuthMode(fallback) {
279
+ const modes = new Set(["basic", "github", "both", "none"]);
280
+ if (args["auth-mode"]) {
281
+ if (!modes.has(args["auth-mode"])) throw new Error("--auth-mode must be basic, github, both, or none");
282
+ return args["auth-mode"];
283
+ }
284
+ if (!input.isTTY) return modes.has(fallback) ? fallback : "basic";
285
+
286
+ console.log(color.bold("Choose authentication"));
287
+ console.log(` ${color.cyan("1")}. basic username/password`);
288
+ console.log(` ${color.cyan("2")}. GitHub OAuth`);
289
+ console.log(` ${color.cyan("3")}. both`);
290
+ console.log(` ${color.cyan("4")}. none`);
291
+
292
+ const rl = createInterface({ input, output });
293
+ const answer = (await rl.question(`Authentication [${fallback}]: `)).trim();
294
+ rl.close();
295
+
296
+ if (!answer) return modes.has(fallback) ? fallback : "basic";
297
+ if (modes.has(answer)) return answer;
298
+ if (answer === "1") return "basic";
299
+ if (answer === "2") return "github";
300
+ if (answer === "3") return "both";
301
+ if (answer === "4") return "none";
302
+ throw new Error("Authentication must be basic, github, both, or none");
303
+ }
304
+
305
+ function usesBasicAuth(mode) {
306
+ return mode === "basic" || mode === "both";
307
+ }
308
+
309
+ function usesGitHubAuth(mode) {
310
+ return mode === "github" || mode === "both";
311
+ }
312
+
259
313
  async function chooseBase(fallback) {
260
314
  if (args.base) return args.base;
261
315
  if (!input.isTTY) return fallback;
@@ -432,6 +486,7 @@ Options:
432
486
  --project NAME Vercel project name
433
487
  --scope SLUG Optional Vercel team/user scope slug
434
488
  --from IMAGE Source image for /app/bin/wsterm
489
+ --auth-mode MODE basic, github, both, or none
435
490
  --auth-user VALUE Username/password auth user
436
491
  --auth-password VAL Username/password auth password
437
492
  --client-id VALUE GitHub OAuth client id
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vercel-vm-factory",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Create Vercel Container deployments for ws-shell from selectable base images.",
5
5
  "license": "MIT",
6
6
  "type": "module",