create-whop-kit 0.8.0 → 0.9.1

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.
@@ -135,17 +135,6 @@ function vercelEnvSet(key, value, environment = "production", projectDir) {
135
135
  );
136
136
  return result.success;
137
137
  }
138
- function vercelEnvSetBatch(vars, projectDir) {
139
- const success = [];
140
- const failed = [];
141
- for (const [key, value] of Object.entries(vars)) {
142
- if (!value) continue;
143
- const ok = vercelEnvSet(key, value, "production", projectDir) && vercelEnvSet(key, value, "preview", projectDir) && vercelEnvSet(key, value, "development", projectDir);
144
- if (ok) success.push(key);
145
- else failed.push(key);
146
- }
147
- return { success, failed };
148
- }
149
138
 
150
139
  // src/deploy/github.ts
151
140
  import * as p2 from "@clack/prompts";
@@ -207,6 +196,11 @@ async function createGitHubRepo(projectDir, projectName) {
207
196
  s.stop("GitHub repo created");
208
197
  return `https://github.com/${projectName}`;
209
198
  }
199
+ function getGitHubOrgs() {
200
+ const result = exec("gh api user/orgs --jq '.[].login'");
201
+ if (!result.success || !result.stdout.trim()) return [];
202
+ return result.stdout.trim().split("\n").filter(Boolean);
203
+ }
210
204
 
211
205
  // src/deploy/whop-api.ts
212
206
  var WHOP_API = "https://api.whop.com/api/v1";
@@ -294,175 +288,218 @@ function openUrl(url) {
294
288
  }
295
289
  async function runDeployPipeline(options) {
296
290
  const { projectDir, projectName, databaseUrl, framework } = options;
297
- p3.log.info(pc3.bold("\n\u2500\u2500 GitHub \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
298
- if (!isGhInstalled()) {
299
- const install = await p3.confirm({
300
- message: "GitHub CLI (gh) not found. Install it?",
301
- initialValue: true
302
- });
303
- if (p3.isCancel(install) || !install) {
304
- p3.log.warning("Skipping GitHub. Deploy will upload directly (no auto-deploy on push).");
305
- } else {
306
- await installGh();
291
+ const setupMode = await p3.select({
292
+ message: "How would you like to deploy?",
293
+ options: [
294
+ {
295
+ value: "github-vercel",
296
+ label: "GitHub + Vercel (recommended)",
297
+ hint: "Private repo, auto-deploy on every push"
298
+ },
299
+ {
300
+ value: "github-only",
301
+ label: "GitHub only",
302
+ hint: "Push code to GitHub, deploy later"
303
+ },
304
+ {
305
+ value: "vercel-only",
306
+ label: "Vercel only",
307
+ hint: "Deploy without GitHub (no auto-deploy on push)"
308
+ }
309
+ ]
310
+ });
311
+ if (p3.isCancel(setupMode)) return null;
312
+ const useGithub = setupMode === "github-vercel" || setupMode === "github-only";
313
+ const useVercel = setupMode === "github-vercel" || setupMode === "vercel-only";
314
+ let githubRepoUrl = null;
315
+ let productionUrl = null;
316
+ if (useGithub) {
317
+ p3.log.info(pc3.bold("\n\u2500\u2500 GitHub \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
318
+ if (!isGhInstalled()) {
319
+ p3.log.info("The GitHub CLI (gh) is needed to create your repo.");
320
+ const installed = await installGh();
321
+ if (!installed) {
322
+ p3.log.warning("Skipping GitHub \u2014 install gh manually: https://cli.github.com");
323
+ }
324
+ }
325
+ if (isGhInstalled()) {
326
+ if (!isGhAuthenticated()) {
327
+ const loginOk = await ghLogin();
328
+ if (!loginOk) {
329
+ p3.log.warning("GitHub auth failed. Skipping repo creation.");
330
+ }
331
+ }
332
+ if (isGhAuthenticated()) {
333
+ const orgs = getGitHubOrgs();
334
+ let repoFullName = projectName;
335
+ if (orgs.length > 0) {
336
+ const orgChoice = await p3.select({
337
+ message: "Which GitHub account?",
338
+ options: [
339
+ { value: "", label: "Personal account", hint: "your personal GitHub" },
340
+ ...orgs.map((org) => ({
341
+ value: org,
342
+ label: org,
343
+ hint: "organization"
344
+ }))
345
+ ]
346
+ });
347
+ if (!p3.isCancel(orgChoice) && orgChoice) {
348
+ repoFullName = `${orgChoice}/${projectName}`;
349
+ }
350
+ }
351
+ githubRepoUrl = await createGitHubRepo(projectDir, repoFullName);
352
+ if (githubRepoUrl) {
353
+ p3.log.success(`Code pushed to ${pc3.cyan(githubRepoUrl)}`);
354
+ }
355
+ }
307
356
  }
308
357
  }
309
- let githubRepoUrl = null;
310
- if (isGhInstalled()) {
311
- if (!isGhAuthenticated()) {
312
- const loginOk = await ghLogin();
358
+ if (useVercel) {
359
+ p3.log.info(pc3.bold("\n\u2500\u2500 Vercel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
360
+ const vercelOk = await installOrUpdateVercel();
361
+ if (!vercelOk) {
362
+ p3.log.error("Could not set up Vercel CLI.");
363
+ return githubRepoUrl ? { productionUrl: "", githubUrl: githubRepoUrl } : null;
364
+ }
365
+ if (!isVercelAuthenticated()) {
366
+ const loginOk = await vercelLogin();
313
367
  if (!loginOk) {
314
- p3.log.warning("GitHub auth failed. Skipping GitHub repo creation.");
368
+ p3.log.error("Vercel auth failed. Run " + pc3.bold("whop-kit deploy") + " later.");
369
+ return githubRepoUrl ? { productionUrl: "", githubUrl: githubRepoUrl } : null;
315
370
  }
316
371
  }
317
- if (isGhAuthenticated()) {
318
- githubRepoUrl = await createGitHubRepo(projectDir, projectName);
319
- if (githubRepoUrl) {
320
- p3.log.success(`Code pushed to ${pc3.cyan(githubRepoUrl)}`);
372
+ const vercelUser = getVercelUser();
373
+ p3.log.success(`Signed in${vercelUser ? ` as ${pc3.bold(vercelUser)}` : ""}`);
374
+ await vercelLink(projectDir);
375
+ if (githubRepoUrl) {
376
+ const s = p3.spinner();
377
+ s.start("Connecting GitHub to Vercel (auto-deploy on push)...");
378
+ const connectResult = exec(`vercel git connect ${githubRepoUrl}`, projectDir, 3e4);
379
+ if (connectResult.success) {
380
+ s.stop("Connected \u2014 every git push will auto-deploy");
321
381
  } else {
322
- p3.log.warning("Could not create GitHub repo. Continuing without it.");
382
+ s.stop("Auto-connect failed (connect manually in Vercel dashboard \u2192 Git)");
323
383
  }
324
384
  }
325
- }
326
- p3.log.info(pc3.bold("\n\u2500\u2500 Vercel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
327
- const vercelOk = await installOrUpdateVercel();
328
- if (!vercelOk) return null;
329
- if (!isVercelAuthenticated()) {
330
- const loginOk = await vercelLogin();
331
- if (!loginOk) {
332
- p3.log.error("Vercel auth failed. Run " + pc3.bold("whop-kit deploy") + " later.");
333
- return null;
385
+ if (databaseUrl) {
386
+ let s = p3.spinner();
387
+ s.start("Setting DATABASE_URL \u2192 production...");
388
+ vercelEnvSet("DATABASE_URL", databaseUrl, "production", projectDir);
389
+ s.stop("DATABASE_URL \u2192 production \u2713");
390
+ s = p3.spinner();
391
+ s.start("Setting DATABASE_URL \u2192 preview...");
392
+ vercelEnvSet("DATABASE_URL", databaseUrl, "preview", projectDir);
393
+ s.stop("DATABASE_URL \u2192 preview \u2713");
394
+ s = p3.spinner();
395
+ s.start("Setting DATABASE_URL \u2192 development...");
396
+ vercelEnvSet("DATABASE_URL", databaseUrl, "development", projectDir);
397
+ s.stop("DATABASE_URL \u2192 development \u2713");
334
398
  }
335
- }
336
- const vercelUser = getVercelUser();
337
- p3.log.success(`Signed in${vercelUser ? ` as ${pc3.bold(vercelUser)}` : ""}`);
338
- const linkOk = await vercelLink(projectDir);
339
- if (!linkOk) {
340
- p3.log.warning("Could not link project.");
341
- }
342
- if (githubRepoUrl) {
343
- const s2 = p3.spinner();
344
- s2.start("Connecting GitHub repo to Vercel (enables auto-deploy on push)...");
345
- const connectResult = exec(
346
- `vercel git connect ${githubRepoUrl}`,
347
- projectDir,
348
- 3e4
349
- );
350
- if (connectResult.success) {
351
- s2.stop("GitHub connected \u2014 future pushes will auto-deploy");
352
- } else {
353
- s2.stop("Could not auto-connect GitHub (connect manually in Vercel dashboard)");
399
+ productionUrl = await vercelDeploy(projectDir);
400
+ if (!productionUrl) {
401
+ p3.log.error("Deploy failed. Try: " + pc3.bold(`cd ${projectName} && vercel deploy --prod`));
354
402
  }
355
403
  }
356
- if (databaseUrl) {
357
- const s2 = p3.spinner();
358
- s2.start("Setting DATABASE_URL on Vercel...");
359
- vercelEnvSet("DATABASE_URL", databaseUrl, "production", projectDir);
360
- vercelEnvSet("DATABASE_URL", databaseUrl, "preview", projectDir);
361
- vercelEnvSet("DATABASE_URL", databaseUrl, "development", projectDir);
362
- s2.stop("DATABASE_URL configured");
363
- }
364
- const productionUrl = await vercelDeploy(projectDir);
365
- if (!productionUrl) {
366
- p3.log.error("Deployment failed. Try: " + pc3.bold(`cd ${projectName} && vercel deploy --prod`));
367
- return null;
368
- }
369
- p3.log.info(pc3.bold("\n\u2500\u2500 Whop \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
370
- const connectWhop = await p3.confirm({
371
- message: "Connect to Whop? (creates OAuth app + webhooks automatically)",
372
- initialValue: true
373
- });
374
- if (p3.isCancel(connectWhop) || !connectWhop) {
375
- return { productionUrl };
376
- }
377
- p3.note(
378
- [
379
- `${pc3.bold("1.")} Go to the Whop Developer Dashboard`,
380
- ` ${pc3.cyan("https://whop.com/dashboard/developer")}`,
381
- "",
382
- `${pc3.bold("2.")} Click ${pc3.bold('"Create"')} under "Company API Keys"`,
383
- "",
384
- `${pc3.bold("3.")} Name it anything (e.g. "${projectName}")`,
385
- "",
386
- `${pc3.bold("4.")} Select these permissions:`,
387
- ` ${pc3.green("\u2022")} developer:create_app`,
388
- ` ${pc3.green("\u2022")} developer:manage_api_key`,
389
- ` ${pc3.green("\u2022")} developer:manage_webhook`,
390
- "",
391
- `${pc3.bold("5.")} Create the key and paste it below`
392
- ].join("\n"),
393
- "Create a Company API Key"
394
- );
395
- openUrl("https://whop.com/dashboard/developer");
396
- let apiKey = options.whopCompanyKey ?? "";
397
- if (!apiKey) {
398
- const result = await p3.text({
399
- message: "Paste your Company API key",
400
- placeholder: "paste the key here...",
401
- validate: (v) => !v ? "API key is required" : void 0
404
+ if (productionUrl) {
405
+ p3.log.info(pc3.bold("\n\u2500\u2500 Whop \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
406
+ const connectWhop = await p3.confirm({
407
+ message: "Connect to Whop? (creates OAuth app + webhooks automatically)",
408
+ initialValue: true
402
409
  });
403
- if (p3.isCancel(result)) return { productionUrl };
404
- apiKey = result;
405
- }
406
- const s = p3.spinner();
407
- s.start("Validating API key...");
408
- const keyValid = await validateApiKey(apiKey);
409
- if (!keyValid) {
410
- s.stop("Invalid API key");
411
- p3.log.error("Check permissions: developer:create_app, developer:manage_api_key, developer:manage_webhook");
412
- return { productionUrl };
413
- }
414
- s.stop("API key valid");
415
- const callbackPath = "/api/auth/callback";
416
- const redirectUris = [
417
- `http://localhost:3000${callbackPath}`,
418
- `${productionUrl}${callbackPath}`
419
- ];
420
- s.start("Creating Whop OAuth app...");
421
- const app = await createWhopApp(apiKey, projectName, redirectUris);
422
- if (!app) {
423
- s.stop("Failed to create app");
424
- p3.log.error("Create manually at: " + pc3.cyan("https://whop.com/dashboard/developer"));
425
- return { productionUrl };
426
- }
427
- s.stop(`OAuth app created: ${pc3.bold(app.id)}`);
428
- const webhookUrl = `${productionUrl}/api/webhooks/whop`;
429
- s.start("Creating webhook endpoint...");
430
- const webhook = await createWhopWebhook(apiKey, webhookUrl, WEBHOOK_EVENTS);
431
- if (!webhook) {
432
- s.stop("Failed to create webhook");
433
- p3.log.warning("Create manually in the Whop dashboard.");
434
- } else {
435
- s.stop("Webhook created");
436
- }
437
- const envVars = {};
438
- if (framework === "nextjs") {
439
- envVars["NEXT_PUBLIC_WHOP_APP_ID"] = app.id;
440
- } else {
441
- envVars["WHOP_APP_ID"] = app.id;
442
- }
443
- envVars["WHOP_API_KEY"] = app.client_secret;
444
- if (webhook?.secret) {
445
- envVars["WHOP_WEBHOOK_SECRET"] = webhook.secret;
446
- }
447
- s.start("Pushing Whop credentials to Vercel...");
448
- const { success, failed } = vercelEnvSetBatch(envVars, projectDir);
449
- if (failed.length > 0) {
450
- s.stop(`${success.length} pushed, ${failed.length} failed`);
451
- } else {
452
- s.stop("Credentials pushed to Vercel");
453
- }
454
- s.start("Redeploying with full configuration...");
455
- const redeployResult = exec("vercel deploy --prod --yes", projectDir, 3e5);
456
- if (redeployResult.success) {
457
- s.stop("Redeployed successfully");
458
- } else {
459
- s.stop("Redeploy pending \u2014 will apply on next git push");
410
+ if (!p3.isCancel(connectWhop) && connectWhop) {
411
+ p3.note(
412
+ [
413
+ `${pc3.bold("1.")} Go to the Whop Developer Dashboard`,
414
+ ` ${pc3.cyan("https://whop.com/dashboard/developer")}`,
415
+ "",
416
+ `${pc3.bold("2.")} Click ${pc3.bold('"Create"')} under "Company API Keys"`,
417
+ "",
418
+ `${pc3.bold("3.")} Name it anything (e.g. "${projectName}")`,
419
+ "",
420
+ `${pc3.bold("4.")} Select these permissions:`,
421
+ ` ${pc3.green("\u2022")} developer:create_app`,
422
+ ` ${pc3.green("\u2022")} developer:manage_api_key`,
423
+ ` ${pc3.green("\u2022")} developer:manage_webhook`,
424
+ "",
425
+ `${pc3.bold("5.")} Create the key and paste it below`
426
+ ].join("\n"),
427
+ "Create a Company API Key"
428
+ );
429
+ openUrl("https://whop.com/dashboard/developer");
430
+ let apiKey = options.whopCompanyKey ?? "";
431
+ if (!apiKey) {
432
+ const result = await p3.text({
433
+ message: "Paste your Company API key",
434
+ placeholder: "paste the key here...",
435
+ validate: (v) => !v ? "API key is required" : void 0
436
+ });
437
+ if (p3.isCancel(result)) {
438
+ return { productionUrl, githubUrl: githubRepoUrl ?? void 0 };
439
+ }
440
+ apiKey = result;
441
+ }
442
+ const s = p3.spinner();
443
+ s.start("Validating API key...");
444
+ const keyValid = await validateApiKey(apiKey);
445
+ if (!keyValid) {
446
+ s.stop("Invalid API key");
447
+ p3.log.error("Check permissions: developer:create_app, developer:manage_api_key, developer:manage_webhook");
448
+ return { productionUrl, githubUrl: githubRepoUrl ?? void 0 };
449
+ }
450
+ s.stop("API key valid");
451
+ const redirectUris = [
452
+ "http://localhost:3000/api/auth/callback",
453
+ `${productionUrl}/api/auth/callback`
454
+ ];
455
+ s.start("Creating Whop OAuth app...");
456
+ const app = await createWhopApp(apiKey, projectName, redirectUris);
457
+ if (!app) {
458
+ s.stop("Failed");
459
+ p3.log.error("Create manually: " + pc3.cyan("https://whop.com/dashboard/developer"));
460
+ return { productionUrl, githubUrl: githubRepoUrl ?? void 0 };
461
+ }
462
+ s.stop(`OAuth app created: ${pc3.bold(app.id)}`);
463
+ s.start("Creating webhook...");
464
+ const webhook = await createWhopWebhook(apiKey, `${productionUrl}/api/webhooks/whop`, WEBHOOK_EVENTS);
465
+ if (!webhook) {
466
+ s.stop("Failed (create manually in Whop dashboard)");
467
+ } else {
468
+ s.stop("Webhook created");
469
+ }
470
+ if (useVercel) {
471
+ const envVars = {};
472
+ if (framework === "nextjs") {
473
+ envVars["NEXT_PUBLIC_WHOP_APP_ID"] = app.id;
474
+ } else {
475
+ envVars["WHOP_APP_ID"] = app.id;
476
+ }
477
+ envVars["WHOP_API_KEY"] = app.client_secret;
478
+ if (webhook?.secret) envVars["WHOP_WEBHOOK_SECRET"] = webhook.secret;
479
+ for (const [key, value] of Object.entries(envVars)) {
480
+ const vs = p3.spinner();
481
+ vs.start(`Pushing ${key}...`);
482
+ vercelEnvSet(key, value, "production", projectDir);
483
+ vercelEnvSet(key, value, "preview", projectDir);
484
+ vercelEnvSet(key, value, "development", projectDir);
485
+ vs.stop(`${key} \u2713`);
486
+ }
487
+ s.start("Redeploying with full configuration...");
488
+ const redeploy = exec("vercel deploy --prod --yes", projectDir, 3e5);
489
+ s.stop(redeploy.success ? "Redeployed" : "Redeploy pending \u2014 will apply on next git push");
490
+ }
491
+ return {
492
+ productionUrl,
493
+ githubUrl: githubRepoUrl ?? void 0,
494
+ whopAppId: app.id,
495
+ whopApiKey: app.client_secret,
496
+ webhookSecret: webhook?.secret
497
+ };
498
+ }
460
499
  }
461
500
  return {
462
- productionUrl,
463
- whopAppId: app.id,
464
- whopApiKey: app.client_secret,
465
- webhookSecret: webhook?.secret
501
+ productionUrl: productionUrl ?? "",
502
+ githubUrl: githubRepoUrl ?? void 0
466
503
  };
467
504
  }
468
505
 
@@ -675,7 +675,7 @@ var init_default = defineCommand({
675
675
  })();
676
676
  if (shouldDeploy) {
677
677
  deployAttempted = true;
678
- const { runDeployPipeline } = await import("./deploy-4GLNQM3I.js");
678
+ const { runDeployPipeline } = await import("./deploy-64CNJIBD.js");
679
679
  deployResult = await runDeployPipeline({
680
680
  projectDir,
681
681
  projectName,
@@ -690,23 +690,23 @@ var init_default = defineCommand({
690
690
  if (deployResult?.productionUrl) {
691
691
  if (dbUrl) summary += `${pc5.green("\u2713")} Database connected
692
692
  `;
693
- summary += `${pc5.green("\u2713")} Deployed to Vercel
693
+ if (deployResult.githubUrl) summary += `${pc5.green("\u2713")} GitHub: ${pc5.dim(deployResult.githubUrl)}
694
+ `;
695
+ summary += `${pc5.green("\u2713")} Vercel: ${pc5.cyan(deployResult.productionUrl)}
694
696
  `;
695
697
  if (deployResult.whopAppId) summary += `${pc5.green("\u2713")} Whop app: ${deployResult.whopAppId}
696
698
  `;
697
699
  if (deployResult.webhookSecret) summary += `${pc5.green("\u2713")} Webhooks configured
698
700
  `;
699
701
  summary += `
700
- `;
701
- summary += ` ${pc5.bold("Production:")} ${pc5.cyan(deployResult.productionUrl)}
702
- `;
703
- summary += ` ${pc5.bold("Local dev:")} ${pc5.cyan("http://localhost:3000")}
704
- `;
705
- summary += `
706
702
  `;
707
703
  summary += ` ${pc5.bold("cd")} ${basename2(projectName)}
708
704
  `;
709
- summary += ` ${pc5.bold(`${pm} run dev`)} ${pc5.dim("# start local dev server")}`;
705
+ summary += ` ${pc5.bold(`${pm} run dev`)} ${pc5.dim("# local development at localhost:3000")}
706
+ `;
707
+ if (deployResult.githubUrl) {
708
+ summary += ` ${pc5.bold("git push")} ${pc5.dim("# auto-deploys to Vercel")}`;
709
+ }
710
710
  } else if (deployFailed) {
711
711
  if (dbUrl) summary += `${pc5.green("\u2713")} Database configured
712
712
  `;
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-TNUTE5L4.js";
12
+ } from "./chunk-KXM3AHGK.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-TNUTE5L4.js";
4
+ } from "./chunk-KXM3AHGK.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": "0.8.0",
3
+ "version": "0.9.1",
4
4
  "description": "Scaffold and manage Whop-powered apps with whop-kit",
5
5
  "type": "module",
6
6
  "license": "MIT",