create-whop-kit 1.0.1 → 1.0.3

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.
@@ -56,7 +56,6 @@ function getVercelUser() {
56
56
  }
57
57
  async function vercelLogin() {
58
58
  p.log.info("You'll be redirected to Vercel to sign in (or create an account).");
59
- p.log.info(pc.dim("This is needed to deploy your app."));
60
59
  console.log("");
61
60
  const ok = execInteractive("vercel login");
62
61
  console.log("");
@@ -70,52 +69,57 @@ async function vercelLink(projectDir) {
70
69
  return ok;
71
70
  }
72
71
  async function vercelDeploy(projectDir) {
73
- const s = p.spinner();
74
- s.start("Vercel: deploying to production (this may take a few minutes)...");
75
- const result = exec("vercel deploy --prod --yes", projectDir, 3e5);
76
- if (!result.success) {
77
- s.stop("Vercel deployment failed");
78
- const errorOutput = result.stderr || result.stdout;
79
- if (errorOutput) {
80
- const trimmed = errorOutput.length > 600 ? "..." + errorOutput.slice(-600) : errorOutput;
81
- p.log.error(pc.dim(trimmed));
82
- }
72
+ p.log.step("Vercel: deploying to production...");
73
+ console.log("");
74
+ const ok = execInteractive("vercel deploy --prod --yes", projectDir);
75
+ console.log("");
76
+ if (!ok) {
77
+ p.log.error("Vercel deployment failed. Check the build output above.");
83
78
  return null;
84
79
  }
85
- const lines = result.stdout.split("\n");
86
- let url = "";
87
- for (const line of lines) {
88
- if (line.includes("Aliased:") || line.includes("Production:")) {
89
- const match = line.match(/https:\/\/[^\s\[\]]+/);
90
- if (match) {
91
- url = match[0];
92
- if (line.includes("Aliased:")) break;
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;
93
91
  }
92
+ } catch {
94
93
  }
95
94
  }
96
- if (!url) {
97
- const urls = [];
98
- for (const line of lines) {
99
- const match = line.match(/https:\/\/[^\s\[\]]+\.vercel\.app/);
100
- if (match) urls.push(match[0]);
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
101
  }
102
- if (urls.length > 0) {
103
- urls.sort((a, b) => a.length - b.length);
104
- url = urls[0];
105
- }
106
- }
107
- if (url) {
108
- s.stop(`Deployed to ${pc.cyan(url)}`);
109
- return url;
110
102
  }
111
- for (const line of lines) {
112
- const match = line.match(/https:\/\/[^\s\[\]]+/);
113
- if (match && !match[0].includes("github.com") && !match[0].includes("vercel.com/")) {
114
- s.stop(`Deployed to ${pc.cyan(match[0])}`);
115
- return match[0];
103
+ try {
104
+ const { readFileSync } = await import("fs");
105
+ const { join } = await import("path");
106
+ const projectJson = JSON.parse(
107
+ readFileSync(join(projectDir, ".vercel", "project.json"), "utf-8")
108
+ );
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
+ }
116
118
  }
119
+ } catch {
117
120
  }
118
- s.stop("Deployed but could not extract URL");
121
+ s.stop("Deployed (extracting URL...)");
122
+ p.log.info("The deployment URL was shown in the build output above.");
119
123
  const manual = await p.text({
120
124
  message: "Paste your Vercel production URL",
121
125
  placeholder: "https://your-app.vercel.app",
@@ -226,23 +230,33 @@ function headers(apiKey) {
226
230
  "Content-Type": "application/json"
227
231
  };
228
232
  }
229
- async function validateApiKey(apiKey) {
233
+ async function getCompanyId(apiKey) {
230
234
  try {
231
- const res = await fetch(`${WHOP_API}/apps`, {
235
+ const res = await fetch(`${WHOP_API}/companies`, {
232
236
  headers: headers(apiKey)
233
237
  });
234
- return res.ok;
238
+ if (!res.ok) return null;
239
+ const data = await res.json();
240
+ const companies = data.data || data;
241
+ if (Array.isArray(companies) && companies.length > 0) {
242
+ return companies[0].id;
243
+ }
244
+ return null;
235
245
  } catch {
236
- return false;
246
+ return null;
237
247
  }
238
248
  }
239
- async function createWhopApp(apiKey, name, redirectUris) {
249
+ async function validateApiKey(apiKey) {
250
+ return getCompanyId(apiKey);
251
+ }
252
+ async function createWhopApp(apiKey, name, redirectUris, companyId) {
240
253
  try {
241
254
  const res = await fetch(`${WHOP_API}/apps`, {
242
255
  method: "POST",
243
256
  headers: headers(apiKey),
244
257
  body: JSON.stringify({
245
258
  name,
259
+ company_id: companyId,
246
260
  redirect_uris: redirectUris
247
261
  })
248
262
  });
@@ -261,14 +275,15 @@ async function createWhopApp(apiKey, name, redirectUris) {
261
275
  return null;
262
276
  }
263
277
  }
264
- async function createWhopWebhook(apiKey, url, events) {
278
+ async function createWhopWebhook(apiKey, url, events, companyId) {
265
279
  try {
266
280
  const res = await fetch(`${WHOP_API}/webhooks`, {
267
281
  method: "POST",
268
282
  headers: headers(apiKey),
269
283
  body: JSON.stringify({
270
284
  url,
271
- events
285
+ events,
286
+ company_id: companyId
272
287
  })
273
288
  });
274
289
  if (!res.ok) {
@@ -433,6 +448,7 @@ async function runDeployPipeline(options) {
433
448
  `${pc3.bold("3.")} Name it anything (e.g. "${projectName}")`,
434
449
  "",
435
450
  `${pc3.bold("4.")} Select these permissions:`,
451
+ ` ${pc3.green("\u2022")} company:basic:read ${pc3.dim("\u2014 identify your company")}`,
436
452
  ` ${pc3.green("\u2022")} developer:create_app ${pc3.dim("\u2014 create the OAuth app")}`,
437
453
  ` ${pc3.green("\u2022")} developer:update_app ${pc3.dim("\u2014 configure redirect URIs")}`,
438
454
  ` ${pc3.green("\u2022")} developer:manage_api_key ${pc3.dim("\u2014 get the app credentials")}`,
@@ -460,27 +476,27 @@ async function runDeployPipeline(options) {
460
476
  }
461
477
  const s = p3.spinner();
462
478
  s.start("Validating API key...");
463
- const keyValid = await validateApiKey(apiKey);
464
- if (!keyValid) {
479
+ const companyId = await validateApiKey(apiKey);
480
+ if (!companyId) {
465
481
  s.stop("Invalid API key");
466
- p3.log.error("Check permissions: developer:create_app, developer:manage_api_key, developer:manage_webhook");
482
+ p3.log.error("Check that the key has permissions: developer:create_app, developer:manage_api_key, developer:manage_webhook, company:basic:read");
467
483
  return { productionUrl, githubUrl: githubRepoUrl ?? void 0 };
468
484
  }
469
- s.stop("API key valid");
485
+ s.stop(`API key valid (company: ${pc3.dim(companyId)})`);
470
486
  const redirectUris = [
471
487
  "http://localhost:3000/api/auth/callback",
472
488
  `${productionUrl}/api/auth/callback`
473
489
  ];
474
490
  s.start("Creating Whop OAuth app...");
475
- const app = await createWhopApp(apiKey, projectName, redirectUris);
491
+ const app = await createWhopApp(apiKey, projectName, redirectUris, companyId);
476
492
  if (!app) {
477
- s.stop("Failed");
493
+ s.stop("Failed to create app");
478
494
  p3.log.error("Create manually: " + pc3.cyan("https://whop.com/dashboard/developer"));
479
495
  return { productionUrl, githubUrl: githubRepoUrl ?? void 0 };
480
496
  }
481
497
  s.stop(`OAuth app created: ${pc3.bold(app.id)}`);
482
498
  s.start("Creating webhook...");
483
- const webhook = await createWhopWebhook(apiKey, `${productionUrl}/api/webhooks/whop`, WEBHOOK_EVENTS);
499
+ const webhook = await createWhopWebhook(apiKey, `${productionUrl}/api/webhooks/whop`, WEBHOOK_EVENTS, companyId);
484
500
  if (!webhook) {
485
501
  s.stop("Failed (create manually in Whop dashboard)");
486
502
  } else {
@@ -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-4OQC445A.js");
687
+ const { runDeployPipeline } = await import("./deploy-GJATOBW4.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-BQZUZXDZ.js";
12
+ } from "./chunk-FS63S7SD.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-BQZUZXDZ.js";
4
+ } from "./chunk-FS63S7SD.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.1",
3
+ "version": "1.0.3",
4
4
  "description": "Scaffold and manage Whop-powered apps with whop-kit",
5
5
  "type": "module",
6
6
  "license": "MIT",