vercel-vm-factory 0.1.0 → 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 +36 -1
  2. package/deploy-vm.mjs +90 -11
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -6,6 +6,16 @@ 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 \
10
+ --auth-user admin \
11
+ --auth-password change-me
12
+ ```
13
+
14
+ GitHub OAuth is optional:
15
+
16
+ ```bash
17
+ npx vercel-vm-factory create \
18
+ --auth-mode github \
9
19
  --client-id YOUR_GITHUB_CLIENT_ID \
10
20
  --client-secret YOUR_GITHUB_CLIENT_SECRET \
11
21
  --github-userid 12345678
@@ -17,6 +27,8 @@ Run without flags for prompts:
17
27
  npx vercel-vm-factory create
18
28
  ```
19
29
 
30
+ The prompt asks for authentication first: `basic`, `github`, `both`, or `none`, then only asks for the fields that mode needs.
31
+
20
32
  Check local setup:
21
33
 
22
34
  ```bash
@@ -27,7 +39,7 @@ The script checks `vercel --version` and `vercel whoami`; if you are not logged
27
39
 
28
40
  Use `--help` to show all flags.
29
41
 
30
- Entered GitHub values are reused from `~/.vercel-vm-factory/defaults.json`; press Enter to keep the placeholder value or skip an empty one.
42
+ Entered auth values are reused from `~/.vercel-vm-factory/defaults.json`; press Enter to keep the placeholder value or skip an empty one.
31
43
 
32
44
  The generated project contains only `Dockerfile.vercel`.
33
45
 
@@ -56,4 +68,27 @@ Before deploying, set the GitHub OAuth callback URL to:
56
68
  https://PROJECT.vercel.app/auth/github/callback
57
69
  ```
58
70
 
71
+ For example, if `--project x-shell`, set:
72
+
73
+ ```text
74
+ https://x-shell.vercel.app/auth/github/callback
75
+ ```
76
+
77
+ GitHub OAuth fields:
78
+
79
+ - Auth mode -> `--auth-mode basic|github|both|none`
80
+ - Username -> `--auth-user`
81
+ - Password -> `--auth-password`
82
+ - Client ID -> `--client-id`
83
+ - Client Secret -> `--client-secret`
84
+ - Numeric GitHub user ID -> `--github-userid`
85
+
86
+ Get your numeric user ID:
87
+
88
+ ```text
89
+ https://api.github.com/users/YOUR_LOGIN
90
+ ```
91
+
92
+ The callback URL must match exactly. If you deploy under another project name or custom domain, update the GitHub OAuth App or pass `--redirect-url`.
93
+
59
94
  Use `--dry-run` to generate files without deploying.
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,14 +96,23 @@ async function main() {
94
96
  }
95
97
 
96
98
  await ensureVercelReady();
97
-
98
- const githubClientId = await secret("client-id", "GitHub client id", process.env.GITHUB_CLIENT_ID ?? defaults["client-id"]);
99
- const githubClientSecret = await secret(
100
- "client-secret",
101
- "GitHub client secret",
102
- process.env.GITHUB_CLIENT_SECRET ?? defaults["client-secret"],
103
- );
104
- 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
+ : "";
105
116
 
106
117
  await writeDefaults(defaultsPath, {
107
118
  ...defaults,
@@ -109,6 +120,9 @@ async function main() {
109
120
  scope: scope || undefined,
110
121
  project,
111
122
  from: wsShellImage,
123
+ "auth-mode": authMode,
124
+ "auth-user": authUsername,
125
+ "auth-password": authPassword,
112
126
  "client-id": githubClientId,
113
127
  "client-secret": githubClientSecret,
114
128
  "github-userid": allowedUserIds,
@@ -133,10 +147,11 @@ async function main() {
133
147
  appDir,
134
148
  "--yes",
135
149
  "--logs",
136
- "--env",
137
- `OAUTH_REDIRECT_URL=${oauthRedirectUrl}`,
138
150
  ];
139
151
 
152
+ if (authUsername) vercelArgs.push("--env", `AUTH_USERNAME=${authUsername}`);
153
+ if (authPassword) vercelArgs.push("--env", `AUTH_PASSWORD=${authPassword}`);
154
+ if (usesGitHubAuth(authMode)) vercelArgs.push("--env", `OAUTH_REDIRECT_URL=${oauthRedirectUrl}`);
140
155
  if (githubClientId) vercelArgs.push("--env", `GITHUB_CLIENT_ID=${githubClientId}`);
141
156
  if (githubClientSecret) vercelArgs.push("--env", `GITHUB_CLIENT_SECRET=${githubClientSecret}`);
142
157
  if (allowedUserIds) vercelArgs.push("--env", `ALLOWED_USER_IDS=${allowedUserIds}`);
@@ -192,6 +207,9 @@ async function doctor() {
192
207
  printKeyValue("project", defaults.project || "not set");
193
208
  printKeyValue("scope", defaults.scope || "not set");
194
209
  printKeyValue("source image", defaults.from || "ghcr.io/v1xingyue/ws-shell:v1.1.alpine");
210
+ printKeyValue("auth mode", defaults["auth-mode"] || "not set");
211
+ printKeyValue("auth user", defaults["auth-user"] ? mask(defaults["auth-user"]) : "not set");
212
+ printKeyValue("auth password", defaults["auth-password"] ? mask(defaults["auth-password"]) : "not set");
195
213
  printKeyValue("client id", defaults["client-id"] ? mask(defaults["client-id"]) : "not set");
196
214
  printKeyValue("client secret", defaults["client-secret"] ? mask(defaults["client-secret"]) : "not set");
197
215
  printKeyValue("github userid", defaults["github-userid"] ? mask(defaults["github-userid"]) : "not set");
@@ -247,6 +265,51 @@ async function optionalValue(name, question, fallback) {
247
265
  return answer;
248
266
  }
249
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
+
250
313
  async function chooseBase(fallback) {
251
314
  if (args.base) return args.base;
252
315
  if (!input.isTTY) return fallback;
@@ -381,6 +444,15 @@ function printSummary(items) {
381
444
  console.log("");
382
445
  }
383
446
 
447
+ function printOAuthGuide(callbackUrl) {
448
+ console.log(color.bold("GitHub OAuth"));
449
+ console.log(`${color.yellow("!")} Set this callback URL in your GitHub OAuth App before deploying:`);
450
+ console.log(` ${color.bold(callbackUrl)}`);
451
+ console.log(color.dim(" GitHub: Settings -> Developer settings -> OAuth Apps -> Authorization callback URL"));
452
+ console.log(color.dim(" User ID: open https://api.github.com/users/YOUR_LOGIN and copy the numeric id"));
453
+ console.log("");
454
+ }
455
+
384
456
  function printKeyValue(key, value) {
385
457
  console.log(`${color.dim(`${key.padEnd(14)} `)}${value}`);
386
458
  }
@@ -414,6 +486,9 @@ Options:
414
486
  --project NAME Vercel project name
415
487
  --scope SLUG Optional Vercel team/user scope slug
416
488
  --from IMAGE Source image for /app/bin/wsterm
489
+ --auth-mode MODE basic, github, both, or none
490
+ --auth-user VALUE Username/password auth user
491
+ --auth-password VAL Username/password auth password
417
492
  --client-id VALUE GitHub OAuth client id
418
493
  --client-secret VAL GitHub OAuth client secret
419
494
  --github-userid VAL Allowed GitHub numeric user id(s)
@@ -423,5 +498,9 @@ Options:
423
498
  --dry-run Generate Dockerfile.vercel only
424
499
  --doctor Check Vercel CLI/login and saved defaults
425
500
  --help Show this help
501
+
502
+ GitHub OAuth:
503
+ Callback URL must match the deployed project:
504
+ https://PROJECT.vercel.app/auth/github/callback
426
505
  `);
427
506
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vercel-vm-factory",
3
- "version": "0.1.0",
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",