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
|
-
|
|
74
|
-
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
-
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
|
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
|
|
233
|
+
async function getCompanyId(apiKey) {
|
|
230
234
|
try {
|
|
231
|
-
const res = await fetch(`${WHOP_API}/
|
|
235
|
+
const res = await fetch(`${WHOP_API}/companies`, {
|
|
232
236
|
headers: headers(apiKey)
|
|
233
237
|
});
|
|
234
|
-
|
|
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
|
|
246
|
+
return null;
|
|
237
247
|
}
|
|
238
248
|
}
|
|
239
|
-
async function
|
|
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
|
|
464
|
-
if (!
|
|
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(
|
|
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 {
|
package/dist/cli-create.js
CHANGED
|
@@ -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-
|
|
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