create-whop-kit 1.0.6 → 1.0.7
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 s = 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
|
+
s.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
|
+
s.stop(`Vercel CLI updated: ${currentVersion} \u2192 ${newVer}`);
|
|
31
31
|
} else {
|
|
32
|
-
|
|
32
|
+
s.stop(`Vercel CLI up to date (v${currentVersion})`);
|
|
33
33
|
}
|
|
34
34
|
} else {
|
|
35
|
-
|
|
35
|
+
s.stop(`Vercel CLI v${currentVersion} (update check failed, continuing)`);
|
|
36
36
|
}
|
|
37
37
|
return true;
|
|
38
38
|
}
|
|
39
|
-
|
|
39
|
+
s.start("Installing Vercel CLI...");
|
|
40
40
|
const result = exec("npm install -g vercel@latest");
|
|
41
41
|
if (result.success) {
|
|
42
|
-
|
|
42
|
+
s.stop("Vercel CLI installed");
|
|
43
43
|
return true;
|
|
44
44
|
}
|
|
45
|
-
|
|
45
|
+
s.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
|
}
|
|
@@ -121,14 +121,14 @@ function isGhAuthenticated() {
|
|
|
121
121
|
return result.success;
|
|
122
122
|
}
|
|
123
123
|
async function installGh() {
|
|
124
|
-
const
|
|
125
|
-
|
|
124
|
+
const s = p2.spinner();
|
|
125
|
+
s.start("Installing GitHub CLI...");
|
|
126
126
|
const result = exec("npm install -g gh", void 0, 6e4);
|
|
127
127
|
if (result.success && hasCommand("gh")) {
|
|
128
|
-
|
|
128
|
+
s.stop("GitHub CLI installed");
|
|
129
129
|
return true;
|
|
130
130
|
}
|
|
131
|
-
|
|
131
|
+
s.stop("Could not auto-install GitHub CLI");
|
|
132
132
|
p2.log.info("Install manually:");
|
|
133
133
|
p2.log.info(pc2.bold(" https://cli.github.com"));
|
|
134
134
|
return false;
|
|
@@ -141,8 +141,8 @@ async function ghLogin() {
|
|
|
141
141
|
return ok;
|
|
142
142
|
}
|
|
143
143
|
async function createGitHubRepo(projectDir, projectName) {
|
|
144
|
-
let
|
|
145
|
-
|
|
144
|
+
let s = p2.spinner();
|
|
145
|
+
s.start("Creating private GitHub repository...");
|
|
146
146
|
const createResult = exec(
|
|
147
147
|
`gh repo create ${projectName} --private --source=.`,
|
|
148
148
|
projectDir,
|
|
@@ -151,35 +151,35 @@ async function createGitHubRepo(projectDir, projectName) {
|
|
|
151
151
|
if (!createResult.success) {
|
|
152
152
|
const stderr = createResult.stderr || createResult.stdout;
|
|
153
153
|
if (stderr.includes("already exists")) {
|
|
154
|
-
|
|
154
|
+
s.stop(`Repository "${projectName}" already exists`);
|
|
155
155
|
exec(`git remote add origin https://github.com/$(gh api user --jq .login)/${projectName}.git`, projectDir);
|
|
156
156
|
} else {
|
|
157
|
-
|
|
157
|
+
s.stop("Could not create GitHub repo");
|
|
158
158
|
if (stderr) p2.log.error(pc2.dim(stderr.substring(0, 200)));
|
|
159
159
|
return null;
|
|
160
160
|
}
|
|
161
161
|
} else {
|
|
162
|
-
|
|
162
|
+
s.stop("GitHub repo created");
|
|
163
163
|
}
|
|
164
|
-
|
|
165
|
-
|
|
164
|
+
s = p2.spinner();
|
|
165
|
+
s.start("Pushing code to GitHub...");
|
|
166
166
|
const branchResult = exec("git branch --show-current", projectDir);
|
|
167
167
|
const branch = branchResult.success ? branchResult.stdout.trim() : "main";
|
|
168
168
|
let pushOk = false;
|
|
169
169
|
for (const delay of [0, 3e3, 7e3]) {
|
|
170
170
|
if (delay > 0) {
|
|
171
|
-
|
|
171
|
+
s.stop(`Waiting for GitHub to propagate...`);
|
|
172
172
|
await new Promise((r) => setTimeout(r, delay));
|
|
173
|
-
|
|
174
|
-
|
|
173
|
+
s = p2.spinner();
|
|
174
|
+
s.start("Pushing code to GitHub...");
|
|
175
175
|
}
|
|
176
176
|
pushOk = exec(`git push -u origin ${branch}`, projectDir, 3e4).success;
|
|
177
177
|
if (pushOk) break;
|
|
178
178
|
}
|
|
179
179
|
if (!pushOk) {
|
|
180
|
-
|
|
180
|
+
s.stop(`Could not push (try manually: git push -u origin ${branch})`);
|
|
181
181
|
} else {
|
|
182
|
-
|
|
182
|
+
s.stop("Code pushed to GitHub");
|
|
183
183
|
}
|
|
184
184
|
const repoUrl = exec("gh repo view --json url --jq .url", projectDir);
|
|
185
185
|
if (repoUrl.success && repoUrl.stdout.trim()) {
|
|
@@ -201,72 +201,55 @@ function headers(apiKey) {
|
|
|
201
201
|
"Content-Type": "application/json"
|
|
202
202
|
};
|
|
203
203
|
}
|
|
204
|
-
async function
|
|
204
|
+
async function validateApiKey(apiKey) {
|
|
205
205
|
try {
|
|
206
|
-
const res = await fetch(`${WHOP_API}/
|
|
206
|
+
const res = await fetch(`${WHOP_API}/apps?per_page=1`, {
|
|
207
207
|
headers: headers(apiKey)
|
|
208
208
|
});
|
|
209
|
-
|
|
210
|
-
const data = await res.json();
|
|
211
|
-
const companies = data.data || data;
|
|
212
|
-
if (Array.isArray(companies) && companies.length > 0) {
|
|
213
|
-
return companies[0].id;
|
|
214
|
-
}
|
|
215
|
-
return null;
|
|
209
|
+
return res.ok;
|
|
216
210
|
} catch {
|
|
217
|
-
return
|
|
211
|
+
return false;
|
|
218
212
|
}
|
|
219
213
|
}
|
|
220
|
-
async function
|
|
221
|
-
return getCompanyId(apiKey);
|
|
222
|
-
}
|
|
223
|
-
async function createWhopApp(apiKey, name, redirectUris, companyId) {
|
|
214
|
+
async function createWhopApp(apiKey, name, redirectUris) {
|
|
224
215
|
try {
|
|
225
216
|
const res = await fetch(`${WHOP_API}/apps`, {
|
|
226
217
|
method: "POST",
|
|
227
218
|
headers: headers(apiKey),
|
|
228
219
|
body: JSON.stringify({
|
|
229
220
|
name,
|
|
230
|
-
company_id: companyId,
|
|
231
221
|
redirect_uris: redirectUris
|
|
232
222
|
})
|
|
233
223
|
});
|
|
234
|
-
if (
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
return null;
|
|
224
|
+
if (res.ok) {
|
|
225
|
+
const data = await res.json();
|
|
226
|
+
return { id: data.id, client_secret: data.client_secret };
|
|
238
227
|
}
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
client_secret: data.client_secret
|
|
243
|
-
};
|
|
228
|
+
const err = await res.text().catch(() => "");
|
|
229
|
+
console.error(`[Whop API] Create app failed (${res.status}): ${err}`);
|
|
230
|
+
return null;
|
|
244
231
|
} catch (err) {
|
|
245
232
|
console.error("[Whop API] Create app error:", err);
|
|
246
233
|
return null;
|
|
247
234
|
}
|
|
248
235
|
}
|
|
249
|
-
async function createWhopWebhook(apiKey, url, events
|
|
236
|
+
async function createWhopWebhook(apiKey, url, events) {
|
|
250
237
|
try {
|
|
251
238
|
const res = await fetch(`${WHOP_API}/webhooks`, {
|
|
252
239
|
method: "POST",
|
|
253
240
|
headers: headers(apiKey),
|
|
254
|
-
body: JSON.stringify({
|
|
255
|
-
url,
|
|
256
|
-
events,
|
|
257
|
-
company_id: companyId
|
|
258
|
-
})
|
|
241
|
+
body: JSON.stringify({ url, events })
|
|
259
242
|
});
|
|
260
|
-
if (
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
|
|
243
|
+
if (res.ok) {
|
|
244
|
+
const data = await res.json();
|
|
245
|
+
return {
|
|
246
|
+
id: data.id,
|
|
247
|
+
secret: data.secret || data.signing_secret || data.webhook_secret || ""
|
|
248
|
+
};
|
|
264
249
|
}
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
secret: data.secret || data.signing_secret || data.webhook_secret || ""
|
|
269
|
-
};
|
|
250
|
+
const err = await res.text().catch(() => "");
|
|
251
|
+
console.error(`[Whop API] Create webhook failed (${res.status}): ${err}`);
|
|
252
|
+
return null;
|
|
270
253
|
} catch (err) {
|
|
271
254
|
console.error("[Whop API] Create webhook error:", err);
|
|
272
255
|
return null;
|
|
@@ -372,28 +355,28 @@ async function runDeployPipeline(options) {
|
|
|
372
355
|
p3.log.success(`Signed in${vercelUser ? ` as ${pc3.bold(vercelUser)}` : ""}`);
|
|
373
356
|
await vercelLink(projectDir);
|
|
374
357
|
if (githubRepoUrl) {
|
|
375
|
-
const
|
|
376
|
-
|
|
358
|
+
const s = p3.spinner();
|
|
359
|
+
s.start("Connecting GitHub to Vercel (auto-deploy on push)...");
|
|
377
360
|
const connectResult = exec(`vercel git connect ${githubRepoUrl}`, projectDir, 3e4);
|
|
378
361
|
if (connectResult.success) {
|
|
379
|
-
|
|
362
|
+
s.stop("Connected \u2014 every git push will auto-deploy");
|
|
380
363
|
} else {
|
|
381
|
-
|
|
364
|
+
s.stop("Auto-connect failed (connect manually in Vercel dashboard \u2192 Git)");
|
|
382
365
|
}
|
|
383
366
|
}
|
|
384
367
|
if (databaseUrl) {
|
|
385
|
-
let
|
|
386
|
-
|
|
368
|
+
let s = p3.spinner();
|
|
369
|
+
s.start("Setting DATABASE_URL \u2192 production...");
|
|
387
370
|
vercelEnvSet("DATABASE_URL", databaseUrl, "production", projectDir);
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
371
|
+
s.stop("DATABASE_URL \u2192 production \u2713");
|
|
372
|
+
s = p3.spinner();
|
|
373
|
+
s.start("Setting DATABASE_URL \u2192 preview...");
|
|
391
374
|
vercelEnvSet("DATABASE_URL", databaseUrl, "preview", projectDir);
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
375
|
+
s.stop("DATABASE_URL \u2192 preview \u2713");
|
|
376
|
+
s = p3.spinner();
|
|
377
|
+
s.start("Setting DATABASE_URL \u2192 development...");
|
|
395
378
|
vercelEnvSet("DATABASE_URL", databaseUrl, "development", projectDir);
|
|
396
|
-
|
|
379
|
+
s.stop("DATABASE_URL \u2192 development \u2713");
|
|
397
380
|
}
|
|
398
381
|
productionUrl = await vercelDeploy(projectDir);
|
|
399
382
|
if (!productionUrl) {
|
|
@@ -414,18 +397,18 @@ async function runDeployPipeline(options) {
|
|
|
414
397
|
`${pc3.bold("1.")} Go to ${pc3.cyan("https://whop.com/dashboard/developer")}`,
|
|
415
398
|
`${pc3.bold("2.")} Click ${pc3.bold('"Create"')} under "Company API Keys"`,
|
|
416
399
|
`${pc3.bold("3.")} Give it a name (e.g. "${projectName}")`,
|
|
417
|
-
`${pc3.bold("4.")}
|
|
418
|
-
`${pc3.bold("5.")}
|
|
400
|
+
`${pc3.bold("4.")} Click Create and copy the key`,
|
|
401
|
+
`${pc3.bold("5.")} Paste it below`
|
|
419
402
|
].join("\n"),
|
|
420
403
|
"Whop Company API Key"
|
|
421
404
|
);
|
|
422
405
|
openUrl("https://whop.com/dashboard/developer");
|
|
423
406
|
let apiKey = options.whopCompanyKey ?? "";
|
|
424
|
-
let
|
|
407
|
+
let keyValid = false;
|
|
425
408
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
426
409
|
if (!apiKey) {
|
|
427
410
|
const result = await p3.text({
|
|
428
|
-
message: attempt === 0 ? "Paste your Company API key" : "Paste a new Company API key
|
|
411
|
+
message: attempt === 0 ? "Paste your Company API key" : "Paste a new Company API key",
|
|
429
412
|
placeholder: "paste the key here...",
|
|
430
413
|
validate: (v) => !v ? "API key is required" : void 0
|
|
431
414
|
});
|
|
@@ -436,14 +419,13 @@ async function runDeployPipeline(options) {
|
|
|
436
419
|
}
|
|
437
420
|
const s2 = p3.spinner();
|
|
438
421
|
s2.start("Validating API key...");
|
|
439
|
-
|
|
440
|
-
if (
|
|
441
|
-
s2.stop(
|
|
422
|
+
keyValid = await validateApiKey(apiKey);
|
|
423
|
+
if (keyValid) {
|
|
424
|
+
s2.stop("API key valid");
|
|
442
425
|
break;
|
|
443
426
|
}
|
|
444
|
-
s2.stop("API key invalid
|
|
427
|
+
s2.stop("API key invalid");
|
|
445
428
|
if (attempt < 2) {
|
|
446
|
-
p3.log.warning(`Make sure the key's role is set to "Owner" (not Admin).`);
|
|
447
429
|
const retry = await p3.confirm({
|
|
448
430
|
message: "Try a different key?",
|
|
449
431
|
initialValue: true
|
|
@@ -453,19 +435,20 @@ async function runDeployPipeline(options) {
|
|
|
453
435
|
}
|
|
454
436
|
apiKey = "";
|
|
455
437
|
} else {
|
|
456
|
-
p3.log.error("Could not validate
|
|
438
|
+
p3.log.error("Could not validate. Configure Whop manually via the setup wizard.");
|
|
457
439
|
return { productionUrl, githubUrl: githubRepoUrl ?? void 0 };
|
|
458
440
|
}
|
|
459
441
|
}
|
|
460
|
-
if (!
|
|
442
|
+
if (!keyValid) {
|
|
461
443
|
return { productionUrl, githubUrl: githubRepoUrl ?? void 0 };
|
|
462
444
|
}
|
|
463
445
|
const redirectUris = [
|
|
464
446
|
"http://localhost:3000/api/auth/callback",
|
|
465
447
|
`${productionUrl}/api/auth/callback`
|
|
466
448
|
];
|
|
449
|
+
const s = p3.spinner();
|
|
467
450
|
s.start("Creating Whop OAuth app...");
|
|
468
|
-
const app = await createWhopApp(apiKey, projectName, redirectUris
|
|
451
|
+
const app = await createWhopApp(apiKey, projectName, redirectUris);
|
|
469
452
|
if (!app) {
|
|
470
453
|
s.stop("Failed to create app");
|
|
471
454
|
p3.log.error("Create manually: " + pc3.cyan("https://whop.com/dashboard/developer"));
|
|
@@ -473,7 +456,7 @@ async function runDeployPipeline(options) {
|
|
|
473
456
|
}
|
|
474
457
|
s.stop(`OAuth app created: ${pc3.bold(app.id)}`);
|
|
475
458
|
s.start("Creating webhook...");
|
|
476
|
-
const webhook = await createWhopWebhook(apiKey, `${productionUrl}/api/webhooks/whop`, WEBHOOK_EVENTS
|
|
459
|
+
const webhook = await createWhopWebhook(apiKey, `${productionUrl}/api/webhooks/whop`, WEBHOOK_EVENTS);
|
|
477
460
|
if (!webhook) {
|
|
478
461
|
s.stop("Failed (create manually in Whop dashboard)");
|
|
479
462
|
} 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-AMH7INFV.js");
|
|
688
688
|
deployResult = await runDeployPipeline({
|
|
689
689
|
projectDir,
|
|
690
690
|
projectName,
|
package/dist/cli-kit.js
CHANGED