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
|
|
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
|
-
|
|
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
|
-
|
|
30
|
+
s2.stop(`Vercel CLI updated: ${currentVersion} \u2192 ${newVer}`);
|
|
31
31
|
} else {
|
|
32
|
-
|
|
32
|
+
s2.stop(`Vercel CLI up to date (v${currentVersion})`);
|
|
33
33
|
}
|
|
34
34
|
} else {
|
|
35
|
-
|
|
35
|
+
s2.stop(`Vercel CLI v${currentVersion} (update check failed, continuing)`);
|
|
36
36
|
}
|
|
37
37
|
return true;
|
|
38
38
|
}
|
|
39
|
-
|
|
39
|
+
s2.start("Installing Vercel CLI...");
|
|
40
40
|
const result = exec("npm install -g vercel@latest");
|
|
41
41
|
if (result.success) {
|
|
42
|
-
|
|
42
|
+
s2.stop("Vercel CLI installed");
|
|
43
43
|
return true;
|
|
44
44
|
}
|
|
45
|
-
|
|
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.
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
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
|
-
|
|
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
|
|
154
|
-
|
|
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
|
-
|
|
128
|
+
s2.stop("GitHub CLI installed");
|
|
158
129
|
return true;
|
|
159
130
|
}
|
|
160
|
-
|
|
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
|
|
174
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
162
|
+
s2.stop("GitHub repo created");
|
|
192
163
|
}
|
|
193
|
-
|
|
194
|
-
|
|
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
|
-
|
|
171
|
+
s2.stop(`Waiting for GitHub to propagate...`);
|
|
201
172
|
await new Promise((r) => setTimeout(r, delay));
|
|
202
|
-
|
|
203
|
-
|
|
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
|
-
|
|
180
|
+
s2.stop(`Could not push (try manually: git push -u origin ${branch})`);
|
|
210
181
|
} else {
|
|
211
|
-
|
|
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
|
|
405
|
-
|
|
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
|
-
|
|
379
|
+
s2.stop("Connected \u2014 every git push will auto-deploy");
|
|
409
380
|
} else {
|
|
410
|
-
|
|
381
|
+
s2.stop("Auto-connect failed (connect manually in Vercel dashboard \u2192 Git)");
|
|
411
382
|
}
|
|
412
383
|
}
|
|
413
384
|
if (databaseUrl) {
|
|
414
|
-
let
|
|
415
|
-
|
|
385
|
+
let s2 = p3.spinner();
|
|
386
|
+
s2.start("Setting DATABASE_URL \u2192 production...");
|
|
416
387
|
vercelEnvSet("DATABASE_URL", databaseUrl, "production", projectDir);
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
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
|
-
|
|
422
|
-
|
|
423
|
-
|
|
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
|
-
|
|
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.")}
|
|
447
|
-
`${pc3.bold("5.")}
|
|
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
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
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`
|
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-P3HDSFDE.js");
|
|
688
688
|
deployResult = await runDeployPipeline({
|
|
689
689
|
projectDir,
|
|
690
690
|
projectName,
|
package/dist/cli-kit.js
CHANGED