create-whop-kit 1.0.4 → 1.0.6

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.
@@ -17,32 +17,32 @@ function isVercelInstalled() {
17
17
  return hasCommand("vercel");
18
18
  }
19
19
  async function installOrUpdateVercel() {
20
- const s = p.spinner();
20
+ const s2 = p.spinner();
21
21
  if (isVercelInstalled()) {
22
22
  const versionResult = exec("vercel --version");
23
23
  const currentVersion = versionResult.stdout.replace(/[^0-9.]/g, "");
24
- s.start("Checking for Vercel CLI updates...");
24
+ s2.start("Checking for Vercel CLI updates...");
25
25
  const updateResult = exec("npm install -g vercel@latest", void 0, 6e4);
26
26
  if (updateResult.success) {
27
27
  const newVersion = exec("vercel --version");
28
28
  const newVer = newVersion.stdout.replace(/[^0-9.]/g, "");
29
29
  if (newVer !== currentVersion) {
30
- s.stop(`Vercel CLI updated: ${currentVersion} \u2192 ${newVer}`);
30
+ s2.stop(`Vercel CLI updated: ${currentVersion} \u2192 ${newVer}`);
31
31
  } else {
32
- s.stop(`Vercel CLI up to date (v${currentVersion})`);
32
+ s2.stop(`Vercel CLI up to date (v${currentVersion})`);
33
33
  }
34
34
  } else {
35
- s.stop(`Vercel CLI v${currentVersion} (update check failed, continuing)`);
35
+ s2.stop(`Vercel CLI v${currentVersion} (update check failed, continuing)`);
36
36
  }
37
37
  return true;
38
38
  }
39
- s.start("Installing Vercel CLI...");
39
+ s2.start("Installing Vercel CLI...");
40
40
  const result = exec("npm install -g vercel@latest");
41
41
  if (result.success) {
42
- s.stop("Vercel CLI installed");
42
+ s2.stop("Vercel CLI installed");
43
43
  return true;
44
44
  }
45
- s.stop("Failed to install Vercel CLI");
45
+ s2.stop("Failed to install Vercel CLI");
46
46
  p.log.error(`Install manually: ${pc.bold("npm install -g vercel@latest")}`);
47
47
  return false;
48
48
  }
@@ -77,49 +77,20 @@ async function vercelDeploy(projectDir) {
77
77
  p.log.error("Vercel deployment failed. Check the build output above.");
78
78
  return null;
79
79
  }
80
- const s = p.spinner();
81
- s.start("Getting deployment URL...");
82
- const ls = exec("vercel ls --json", projectDir, 15e3);
83
- if (ls.success) {
84
- try {
85
- const data = JSON.parse(ls.stdout);
86
- const prod = Array.isArray(data) ? data.find((d) => d.target === "production") : null;
87
- if (prod?.url) {
88
- const url = `https://${prod.url}`;
89
- s.stop(`Deployed to ${pc.cyan(url)}`);
90
- return url;
91
- }
92
- } catch {
93
- }
94
- }
95
- const inspect = exec("vercel inspect --json", projectDir, 15e3);
96
- if (inspect.success) {
97
- const urlMatch = inspect.stdout.match(/https:\/\/[^\s"]+\.vercel\.app/);
98
- if (urlMatch) {
99
- s.stop(`Deployed to ${pc.cyan(urlMatch[0])}`);
100
- return urlMatch[0];
101
- }
102
- }
103
80
  try {
104
81
  const { readFileSync } = await import("fs");
105
82
  const { join } = await import("path");
106
83
  const projectJson = JSON.parse(
107
84
  readFileSync(join(projectDir, ".vercel", "project.json"), "utf-8")
108
85
  );
109
- if (projectJson.projectId) {
110
- const proj = exec(`vercel project inspect ${projectJson.projectId} --json`, projectDir, 15e3);
111
- if (proj.success) {
112
- const urlMatch = proj.stdout.match(/https:\/\/[^\s"]+\.vercel\.app/);
113
- if (urlMatch) {
114
- s.stop(`Deployed to ${pc.cyan(urlMatch[0])}`);
115
- return urlMatch[0];
116
- }
117
- }
86
+ if (projectJson.projectName) {
87
+ const url = `https://${projectJson.projectName}.vercel.app`;
88
+ p.log.success(`Deployed to ${pc.cyan(url)}`);
89
+ return url;
118
90
  }
119
91
  } catch {
120
92
  }
121
- s.stop("Deployed (extracting URL...)");
122
- p.log.info("The deployment URL was shown in the build output above.");
93
+ p.log.info("The deployment URL was shown in the build output above (after 'Aliased:')");
123
94
  const manual = await p.text({
124
95
  message: "Paste your Vercel production URL",
125
96
  placeholder: "https://your-app.vercel.app",
@@ -150,14 +121,14 @@ function isGhAuthenticated() {
150
121
  return result.success;
151
122
  }
152
123
  async function installGh() {
153
- const s = p2.spinner();
154
- s.start("Installing GitHub CLI...");
124
+ const s2 = p2.spinner();
125
+ s2.start("Installing GitHub CLI...");
155
126
  const result = exec("npm install -g gh", void 0, 6e4);
156
127
  if (result.success && hasCommand("gh")) {
157
- s.stop("GitHub CLI installed");
128
+ s2.stop("GitHub CLI installed");
158
129
  return true;
159
130
  }
160
- s.stop("Could not auto-install GitHub CLI");
131
+ s2.stop("Could not auto-install GitHub CLI");
161
132
  p2.log.info("Install manually:");
162
133
  p2.log.info(pc2.bold(" https://cli.github.com"));
163
134
  return false;
@@ -170,8 +141,8 @@ async function ghLogin() {
170
141
  return ok;
171
142
  }
172
143
  async function createGitHubRepo(projectDir, projectName) {
173
- let s = p2.spinner();
174
- s.start("Creating private GitHub repository...");
144
+ let s2 = p2.spinner();
145
+ s2.start("Creating private GitHub repository...");
175
146
  const createResult = exec(
176
147
  `gh repo create ${projectName} --private --source=.`,
177
148
  projectDir,
@@ -180,35 +151,35 @@ async function createGitHubRepo(projectDir, projectName) {
180
151
  if (!createResult.success) {
181
152
  const stderr = createResult.stderr || createResult.stdout;
182
153
  if (stderr.includes("already exists")) {
183
- s.stop(`Repository "${projectName}" already exists`);
154
+ s2.stop(`Repository "${projectName}" already exists`);
184
155
  exec(`git remote add origin https://github.com/$(gh api user --jq .login)/${projectName}.git`, projectDir);
185
156
  } else {
186
- s.stop("Could not create GitHub repo");
157
+ s2.stop("Could not create GitHub repo");
187
158
  if (stderr) p2.log.error(pc2.dim(stderr.substring(0, 200)));
188
159
  return null;
189
160
  }
190
161
  } else {
191
- s.stop("GitHub repo created");
162
+ s2.stop("GitHub repo created");
192
163
  }
193
- s = p2.spinner();
194
- s.start("Pushing code to GitHub...");
164
+ s2 = p2.spinner();
165
+ s2.start("Pushing code to GitHub...");
195
166
  const branchResult = exec("git branch --show-current", projectDir);
196
167
  const branch = branchResult.success ? branchResult.stdout.trim() : "main";
197
168
  let pushOk = false;
198
169
  for (const delay of [0, 3e3, 7e3]) {
199
170
  if (delay > 0) {
200
- s.stop(`Waiting for GitHub to propagate...`);
171
+ s2.stop(`Waiting for GitHub to propagate...`);
201
172
  await new Promise((r) => setTimeout(r, delay));
202
- s = p2.spinner();
203
- s.start("Pushing code to GitHub...");
173
+ s2 = p2.spinner();
174
+ s2.start("Pushing code to GitHub...");
204
175
  }
205
176
  pushOk = exec(`git push -u origin ${branch}`, projectDir, 3e4).success;
206
177
  if (pushOk) break;
207
178
  }
208
179
  if (!pushOk) {
209
- s.stop(`Could not push (try manually: git push -u origin ${branch})`);
180
+ s2.stop(`Could not push (try manually: git push -u origin ${branch})`);
210
181
  } else {
211
- s.stop("Code pushed to GitHub");
182
+ s2.stop("Code pushed to GitHub");
212
183
  }
213
184
  const repoUrl = exec("gh repo view --json url --jq .url", projectDir);
214
185
  if (repoUrl.success && repoUrl.stdout.trim()) {
@@ -401,28 +372,28 @@ async function runDeployPipeline(options) {
401
372
  p3.log.success(`Signed in${vercelUser ? ` as ${pc3.bold(vercelUser)}` : ""}`);
402
373
  await vercelLink(projectDir);
403
374
  if (githubRepoUrl) {
404
- const s = p3.spinner();
405
- s.start("Connecting GitHub to Vercel (auto-deploy on push)...");
375
+ const s2 = p3.spinner();
376
+ s2.start("Connecting GitHub to Vercel (auto-deploy on push)...");
406
377
  const connectResult = exec(`vercel git connect ${githubRepoUrl}`, projectDir, 3e4);
407
378
  if (connectResult.success) {
408
- s.stop("Connected \u2014 every git push will auto-deploy");
379
+ s2.stop("Connected \u2014 every git push will auto-deploy");
409
380
  } else {
410
- s.stop("Auto-connect failed (connect manually in Vercel dashboard \u2192 Git)");
381
+ s2.stop("Auto-connect failed (connect manually in Vercel dashboard \u2192 Git)");
411
382
  }
412
383
  }
413
384
  if (databaseUrl) {
414
- let s = p3.spinner();
415
- s.start("Setting DATABASE_URL \u2192 production...");
385
+ let s2 = p3.spinner();
386
+ s2.start("Setting DATABASE_URL \u2192 production...");
416
387
  vercelEnvSet("DATABASE_URL", databaseUrl, "production", projectDir);
417
- s.stop("DATABASE_URL \u2192 production \u2713");
418
- s = p3.spinner();
419
- s.start("Setting DATABASE_URL \u2192 preview...");
388
+ s2.stop("DATABASE_URL \u2192 production \u2713");
389
+ s2 = p3.spinner();
390
+ s2.start("Setting DATABASE_URL \u2192 preview...");
420
391
  vercelEnvSet("DATABASE_URL", databaseUrl, "preview", projectDir);
421
- s.stop("DATABASE_URL \u2192 preview \u2713");
422
- s = p3.spinner();
423
- s.start("Setting DATABASE_URL \u2192 development...");
392
+ s2.stop("DATABASE_URL \u2192 preview \u2713");
393
+ s2 = p3.spinner();
394
+ s2.start("Setting DATABASE_URL \u2192 development...");
424
395
  vercelEnvSet("DATABASE_URL", databaseUrl, "development", projectDir);
425
- s.stop("DATABASE_URL \u2192 development \u2713");
396
+ s2.stop("DATABASE_URL \u2192 development \u2713");
426
397
  }
427
398
  productionUrl = await vercelDeploy(projectDir);
428
399
  if (!productionUrl) {
@@ -443,33 +414,52 @@ async function runDeployPipeline(options) {
443
414
  `${pc3.bold("1.")} Go to ${pc3.cyan("https://whop.com/dashboard/developer")}`,
444
415
  `${pc3.bold("2.")} Click ${pc3.bold('"Create"')} under "Company API Keys"`,
445
416
  `${pc3.bold("3.")} Give it a name (e.g. "${projectName}")`,
446
- `${pc3.bold("4.")} Click Create ${pc3.dim("(default permissions are fine)")}`,
447
- `${pc3.bold("5.")} Copy the key and paste it below`
417
+ `${pc3.bold("4.")} Set role to ${pc3.bold('"Owner"')} ${pc3.dim("(ensures all permissions)")}`,
418
+ `${pc3.bold("5.")} Click Create, copy the key, and paste it below`
448
419
  ].join("\n"),
449
420
  "Whop Company API Key"
450
421
  );
451
422
  openUrl("https://whop.com/dashboard/developer");
452
423
  let apiKey = options.whopCompanyKey ?? "";
453
- if (!apiKey) {
454
- const result = await p3.text({
455
- message: "Paste your Company API key",
456
- placeholder: "paste the key here...",
457
- validate: (v) => !v ? "API key is required" : void 0
458
- });
459
- if (p3.isCancel(result)) {
424
+ let companyId = null;
425
+ for (let attempt = 0; attempt < 3; attempt++) {
426
+ if (!apiKey) {
427
+ const result = await p3.text({
428
+ message: attempt === 0 ? "Paste your Company API key" : "Paste a new Company API key (make sure role is set to Owner)",
429
+ placeholder: "paste the key here...",
430
+ validate: (v) => !v ? "API key is required" : void 0
431
+ });
432
+ if (p3.isCancel(result)) {
433
+ return { productionUrl, githubUrl: githubRepoUrl ?? void 0 };
434
+ }
435
+ apiKey = result;
436
+ }
437
+ const s2 = p3.spinner();
438
+ s2.start("Validating API key...");
439
+ companyId = await validateApiKey(apiKey);
440
+ if (companyId) {
441
+ s2.stop(`API key valid (company: ${pc3.dim(companyId)})`);
442
+ break;
443
+ }
444
+ s2.stop("API key invalid or missing permissions");
445
+ if (attempt < 2) {
446
+ p3.log.warning(`Make sure the key's role is set to "Owner" (not Admin).`);
447
+ const retry = await p3.confirm({
448
+ message: "Try a different key?",
449
+ initialValue: true
450
+ });
451
+ if (p3.isCancel(retry) || !retry) {
452
+ return { productionUrl, githubUrl: githubRepoUrl ?? void 0 };
453
+ }
454
+ apiKey = "";
455
+ } else {
456
+ p3.log.error("Could not validate after 3 attempts. Configure Whop manually via the setup wizard.");
460
457
  return { productionUrl, githubUrl: githubRepoUrl ?? void 0 };
461
458
  }
462
- apiKey = result;
463
459
  }
464
- const s = p3.spinner();
465
- s.start("Validating API key...");
466
- const companyId = await validateApiKey(apiKey);
467
460
  if (!companyId) {
468
- s.stop("Invalid API key");
469
- p3.log.error("Check that the key has permissions: developer:create_app, developer:manage_api_key, developer:manage_webhook, company:basic:read");
470
461
  return { productionUrl, githubUrl: githubRepoUrl ?? void 0 };
471
462
  }
472
- s.stop(`API key valid (company: ${pc3.dim(companyId)})`);
473
463
  const redirectUris = [
474
464
  "http://localhost:3000/api/auth/callback",
475
465
  `${productionUrl}/api/auth/callback`
@@ -684,7 +684,7 @@ var init_default = defineCommand({
684
684
  });
685
685
  if (!isCancelled(deployChoice) && deployChoice === "deploy") {
686
686
  deployAttempted = true;
687
- const { runDeployPipeline } = await import("./deploy-REOQQOZH.js");
687
+ const { runDeployPipeline } = await import("./deploy-P3HDSFDE.js");
688
688
  deployResult = await runDeployPipeline({
689
689
  projectDir,
690
690
  projectName,
package/dist/cli-kit.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-HOQ5QQ2M.js";
10
10
  import {
11
11
  runDeployPipeline
12
- } from "./chunk-V7PERVEX.js";
12
+ } from "./chunk-XTFE7H37.js";
13
13
  import {
14
14
  detectPackageManager,
15
15
  exec
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runDeployPipeline
4
- } from "./chunk-V7PERVEX.js";
4
+ } from "./chunk-XTFE7H37.js";
5
5
  import "./chunk-42L7PRMT.js";
6
6
  export {
7
7
  runDeployPipeline
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-whop-kit",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Scaffold and manage Whop-powered apps with whop-kit",
5
5
  "type": "module",
6
6
  "license": "MIT",