create-whop-kit 0.5.1 → 0.6.0
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.
- package/dist/{chunk-BR467LBM.js → chunk-3LBG56BE.js} +3 -37
- package/dist/chunk-GFM6IVTZ.js +56 -0
- package/dist/chunk-ZADKDGR4.js +303 -0
- package/dist/cli-create.js +71 -30
- package/dist/cli-kit.js +79 -24
- package/dist/deploy-RDSYVJ3L.js +8 -0
- package/package.json +1 -1
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
exec
|
|
4
|
+
} from "./chunk-GFM6IVTZ.js";
|
|
2
5
|
|
|
3
6
|
// src/templates.ts
|
|
4
7
|
var FRAMEWORKS = {
|
|
@@ -69,39 +72,6 @@ var APP_TYPES = {
|
|
|
69
72
|
}
|
|
70
73
|
};
|
|
71
74
|
|
|
72
|
-
// src/utils/exec.ts
|
|
73
|
-
import { execSync } from "child_process";
|
|
74
|
-
function exec(cmd, cwd) {
|
|
75
|
-
try {
|
|
76
|
-
const stdout = execSync(cmd, {
|
|
77
|
-
cwd,
|
|
78
|
-
stdio: "pipe",
|
|
79
|
-
encoding: "utf-8",
|
|
80
|
-
timeout: 12e4
|
|
81
|
-
}).trim();
|
|
82
|
-
return { stdout, success: true };
|
|
83
|
-
} catch {
|
|
84
|
-
return { stdout: "", success: false };
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
function execInteractive(cmd, cwd) {
|
|
88
|
-
try {
|
|
89
|
-
execSync(cmd, { cwd, stdio: "inherit", timeout: 3e5 });
|
|
90
|
-
return true;
|
|
91
|
-
} catch {
|
|
92
|
-
return false;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
function hasCommand(cmd) {
|
|
96
|
-
return exec(`which ${cmd}`).success;
|
|
97
|
-
}
|
|
98
|
-
function detectPackageManager() {
|
|
99
|
-
if (hasCommand("pnpm")) return "pnpm";
|
|
100
|
-
if (hasCommand("yarn")) return "yarn";
|
|
101
|
-
if (hasCommand("bun")) return "bun";
|
|
102
|
-
return "npm";
|
|
103
|
-
}
|
|
104
|
-
|
|
105
75
|
// src/scaffolding/manifest.ts
|
|
106
76
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
107
77
|
import { join } from "path";
|
|
@@ -357,10 +327,6 @@ export {
|
|
|
357
327
|
TEMPLATES,
|
|
358
328
|
getTemplate,
|
|
359
329
|
APP_TYPES,
|
|
360
|
-
exec,
|
|
361
|
-
execInteractive,
|
|
362
|
-
hasCommand,
|
|
363
|
-
detectPackageManager,
|
|
364
330
|
createManifest,
|
|
365
331
|
readManifest,
|
|
366
332
|
addFeatureToManifest,
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/utils/exec.ts
|
|
4
|
+
import { execSync } from "child_process";
|
|
5
|
+
function exec(cmd, cwd) {
|
|
6
|
+
try {
|
|
7
|
+
const stdout = execSync(cmd, {
|
|
8
|
+
cwd,
|
|
9
|
+
stdio: "pipe",
|
|
10
|
+
encoding: "utf-8",
|
|
11
|
+
timeout: 12e4
|
|
12
|
+
}).trim();
|
|
13
|
+
return { stdout, success: true };
|
|
14
|
+
} catch {
|
|
15
|
+
return { stdout: "", success: false };
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function execInteractive(cmd, cwd) {
|
|
19
|
+
try {
|
|
20
|
+
execSync(cmd, { cwd, stdio: "inherit", timeout: 3e5 });
|
|
21
|
+
return true;
|
|
22
|
+
} catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function execWithStdin(cmd, input, cwd) {
|
|
27
|
+
try {
|
|
28
|
+
const stdout = execSync(cmd, {
|
|
29
|
+
cwd,
|
|
30
|
+
input,
|
|
31
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
32
|
+
encoding: "utf-8",
|
|
33
|
+
timeout: 12e4
|
|
34
|
+
}).trim();
|
|
35
|
+
return { stdout, success: true };
|
|
36
|
+
} catch {
|
|
37
|
+
return { stdout: "", success: false };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function hasCommand(cmd) {
|
|
41
|
+
return exec(`which ${cmd}`).success;
|
|
42
|
+
}
|
|
43
|
+
function detectPackageManager() {
|
|
44
|
+
if (hasCommand("pnpm")) return "pnpm";
|
|
45
|
+
if (hasCommand("yarn")) return "yarn";
|
|
46
|
+
if (hasCommand("bun")) return "bun";
|
|
47
|
+
return "npm";
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export {
|
|
51
|
+
exec,
|
|
52
|
+
execInteractive,
|
|
53
|
+
execWithStdin,
|
|
54
|
+
hasCommand,
|
|
55
|
+
detectPackageManager
|
|
56
|
+
};
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
exec,
|
|
4
|
+
execInteractive,
|
|
5
|
+
execWithStdin,
|
|
6
|
+
hasCommand
|
|
7
|
+
} from "./chunk-GFM6IVTZ.js";
|
|
8
|
+
|
|
9
|
+
// src/deploy/index.ts
|
|
10
|
+
import * as p2 from "@clack/prompts";
|
|
11
|
+
import pc2 from "picocolors";
|
|
12
|
+
|
|
13
|
+
// src/deploy/vercel.ts
|
|
14
|
+
import * as p from "@clack/prompts";
|
|
15
|
+
import pc from "picocolors";
|
|
16
|
+
function isVercelInstalled() {
|
|
17
|
+
return hasCommand("vercel");
|
|
18
|
+
}
|
|
19
|
+
async function installVercel() {
|
|
20
|
+
const s = p.spinner();
|
|
21
|
+
s.start("Installing Vercel CLI...");
|
|
22
|
+
const result = exec("npm install -g vercel");
|
|
23
|
+
if (result.success) {
|
|
24
|
+
s.stop("Vercel CLI installed");
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
s.stop("Failed to install Vercel CLI");
|
|
28
|
+
p.log.error(`Install manually: ${pc.bold("npm install -g vercel")}`);
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
function isVercelAuthenticated() {
|
|
32
|
+
const result = exec("vercel whoami");
|
|
33
|
+
return result.success;
|
|
34
|
+
}
|
|
35
|
+
async function vercelLogin() {
|
|
36
|
+
p.log.info("Authenticating with Vercel. This will open your browser.");
|
|
37
|
+
console.log("");
|
|
38
|
+
const ok = execInteractive("vercel login");
|
|
39
|
+
console.log("");
|
|
40
|
+
return ok;
|
|
41
|
+
}
|
|
42
|
+
async function vercelDeploy(projectDir) {
|
|
43
|
+
const s = p.spinner();
|
|
44
|
+
s.start("Deploying to Vercel...");
|
|
45
|
+
const result = exec("vercel deploy --prod --yes", projectDir);
|
|
46
|
+
if (!result.success || !result.stdout) {
|
|
47
|
+
s.stop("Deployment failed");
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
let url = result.stdout.trim();
|
|
51
|
+
const lines = url.split("\n");
|
|
52
|
+
url = lines[lines.length - 1].trim();
|
|
53
|
+
if (!url.startsWith("https://")) {
|
|
54
|
+
s.stop("Could not determine deployment URL");
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
s.stop(`Deployed to ${pc.cyan(url)}`);
|
|
58
|
+
return url;
|
|
59
|
+
}
|
|
60
|
+
function vercelEnvSet(key, value, environment = "production", projectDir) {
|
|
61
|
+
const result = execWithStdin(
|
|
62
|
+
`vercel env add ${key} ${environment} --force`,
|
|
63
|
+
value,
|
|
64
|
+
projectDir
|
|
65
|
+
);
|
|
66
|
+
return result.success;
|
|
67
|
+
}
|
|
68
|
+
function vercelEnvSetBatch(vars, projectDir) {
|
|
69
|
+
const success = [];
|
|
70
|
+
const failed = [];
|
|
71
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
72
|
+
if (!value) continue;
|
|
73
|
+
const ok = vercelEnvSet(key, value, "production", projectDir) && vercelEnvSet(key, value, "preview", projectDir) && vercelEnvSet(key, value, "development", projectDir);
|
|
74
|
+
if (ok) success.push(key);
|
|
75
|
+
else failed.push(key);
|
|
76
|
+
}
|
|
77
|
+
return { success, failed };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// src/deploy/whop-api.ts
|
|
81
|
+
var WHOP_API = "https://api.whop.com/api/v1";
|
|
82
|
+
function headers(apiKey) {
|
|
83
|
+
return {
|
|
84
|
+
Authorization: `Bearer ${apiKey}`,
|
|
85
|
+
"Content-Type": "application/json"
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
async function validateApiKey(apiKey) {
|
|
89
|
+
try {
|
|
90
|
+
const res = await fetch(`${WHOP_API}/apps`, {
|
|
91
|
+
headers: headers(apiKey)
|
|
92
|
+
});
|
|
93
|
+
return res.ok;
|
|
94
|
+
} catch {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
async function createWhopApp(apiKey, name, redirectUris) {
|
|
99
|
+
try {
|
|
100
|
+
const res = await fetch(`${WHOP_API}/apps`, {
|
|
101
|
+
method: "POST",
|
|
102
|
+
headers: headers(apiKey),
|
|
103
|
+
body: JSON.stringify({
|
|
104
|
+
name,
|
|
105
|
+
redirect_uris: redirectUris
|
|
106
|
+
})
|
|
107
|
+
});
|
|
108
|
+
if (!res.ok) {
|
|
109
|
+
const err = await res.text().catch(() => "");
|
|
110
|
+
console.error(`[Whop API] Create app failed (${res.status}): ${err}`);
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
const data = await res.json();
|
|
114
|
+
return {
|
|
115
|
+
id: data.id,
|
|
116
|
+
client_secret: data.client_secret
|
|
117
|
+
};
|
|
118
|
+
} catch (err) {
|
|
119
|
+
console.error("[Whop API] Create app error:", err);
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
async function createWhopWebhook(apiKey, url, events) {
|
|
124
|
+
try {
|
|
125
|
+
const res = await fetch(`${WHOP_API}/webhooks`, {
|
|
126
|
+
method: "POST",
|
|
127
|
+
headers: headers(apiKey),
|
|
128
|
+
body: JSON.stringify({
|
|
129
|
+
url,
|
|
130
|
+
events
|
|
131
|
+
})
|
|
132
|
+
});
|
|
133
|
+
if (!res.ok) {
|
|
134
|
+
const err = await res.text().catch(() => "");
|
|
135
|
+
console.error(`[Whop API] Create webhook failed (${res.status}): ${err}`);
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
const data = await res.json();
|
|
139
|
+
return {
|
|
140
|
+
id: data.id,
|
|
141
|
+
secret: data.secret || data.signing_secret || data.webhook_secret || ""
|
|
142
|
+
};
|
|
143
|
+
} catch (err) {
|
|
144
|
+
console.error("[Whop API] Create webhook error:", err);
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// src/deploy/index.ts
|
|
150
|
+
var WEBHOOK_EVENTS = [
|
|
151
|
+
"membership.activated",
|
|
152
|
+
"membership.deactivated",
|
|
153
|
+
"membership.cancel_at_period_end_changed",
|
|
154
|
+
"payment.succeeded",
|
|
155
|
+
"payment.failed",
|
|
156
|
+
"refund.created"
|
|
157
|
+
];
|
|
158
|
+
function openUrl(url) {
|
|
159
|
+
const platform = process.platform;
|
|
160
|
+
if (platform === "darwin") exec(`open "${url}"`);
|
|
161
|
+
else if (platform === "win32") exec(`start "" "${url}"`);
|
|
162
|
+
else exec(`xdg-open "${url}"`);
|
|
163
|
+
}
|
|
164
|
+
async function runDeployPipeline(options) {
|
|
165
|
+
const { projectDir, projectName, databaseUrl, framework } = options;
|
|
166
|
+
if (!isVercelInstalled()) {
|
|
167
|
+
const install = await p2.confirm({
|
|
168
|
+
message: "Vercel CLI not found. Install it now?",
|
|
169
|
+
initialValue: true
|
|
170
|
+
});
|
|
171
|
+
if (p2.isCancel(install) || !install) return null;
|
|
172
|
+
const ok = await installVercel();
|
|
173
|
+
if (!ok) return null;
|
|
174
|
+
}
|
|
175
|
+
if (!isVercelAuthenticated()) {
|
|
176
|
+
const ok = await vercelLogin();
|
|
177
|
+
if (!ok) {
|
|
178
|
+
p2.log.error("Vercel authentication failed. Deploy later with: " + pc2.bold("whop-kit deploy"));
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
p2.log.success("Vercel authenticated");
|
|
183
|
+
if (databaseUrl) {
|
|
184
|
+
const s2 = p2.spinner();
|
|
185
|
+
s2.start("Setting DATABASE_URL on Vercel...");
|
|
186
|
+
vercelEnvSet("DATABASE_URL", databaseUrl, "production", projectDir);
|
|
187
|
+
vercelEnvSet("DATABASE_URL", databaseUrl, "preview", projectDir);
|
|
188
|
+
vercelEnvSet("DATABASE_URL", databaseUrl, "development", projectDir);
|
|
189
|
+
s2.stop("DATABASE_URL configured");
|
|
190
|
+
}
|
|
191
|
+
const productionUrl = await vercelDeploy(projectDir);
|
|
192
|
+
if (!productionUrl) {
|
|
193
|
+
p2.log.error("Vercel deployment failed. Try deploying manually:");
|
|
194
|
+
p2.log.info(pc2.bold(` cd ${projectName} && vercel deploy --prod`));
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
p2.log.success(`Live at ${pc2.cyan(productionUrl)}`);
|
|
198
|
+
const connectWhop = await p2.confirm({
|
|
199
|
+
message: "Connect to Whop? (creates OAuth app + webhooks automatically)",
|
|
200
|
+
initialValue: true
|
|
201
|
+
});
|
|
202
|
+
if (p2.isCancel(connectWhop) || !connectWhop) {
|
|
203
|
+
return { productionUrl };
|
|
204
|
+
}
|
|
205
|
+
p2.log.info("");
|
|
206
|
+
p2.note(
|
|
207
|
+
[
|
|
208
|
+
`${pc2.bold("1.")} Go to the Whop Developer Dashboard`,
|
|
209
|
+
` ${pc2.cyan("https://whop.com/dashboard/developer")}`,
|
|
210
|
+
"",
|
|
211
|
+
`${pc2.bold("2.")} Click ${pc2.bold('"Create"')} under "Company API Keys"`,
|
|
212
|
+
"",
|
|
213
|
+
`${pc2.bold("3.")} Name it anything (e.g. "${projectName}")`,
|
|
214
|
+
"",
|
|
215
|
+
`${pc2.bold("4.")} Select these permissions:`,
|
|
216
|
+
` ${pc2.green("\u2022")} developer:create_app`,
|
|
217
|
+
` ${pc2.green("\u2022")} developer:manage_api_key`,
|
|
218
|
+
` ${pc2.green("\u2022")} developer:manage_webhook`,
|
|
219
|
+
"",
|
|
220
|
+
`${pc2.bold("5.")} Create the key and paste it below`
|
|
221
|
+
].join("\n"),
|
|
222
|
+
"Create a Company API Key"
|
|
223
|
+
);
|
|
224
|
+
openUrl("https://whop.com/dashboard/developer");
|
|
225
|
+
let apiKey = options.whopCompanyKey ?? "";
|
|
226
|
+
if (!apiKey) {
|
|
227
|
+
const result = await p2.text({
|
|
228
|
+
message: "Paste your Company API key",
|
|
229
|
+
placeholder: "paste the key here...",
|
|
230
|
+
validate: (v) => !v ? "API key is required" : void 0
|
|
231
|
+
});
|
|
232
|
+
if (p2.isCancel(result)) return { productionUrl };
|
|
233
|
+
apiKey = result;
|
|
234
|
+
}
|
|
235
|
+
const s = p2.spinner();
|
|
236
|
+
s.start("Validating API key...");
|
|
237
|
+
const keyValid = await validateApiKey(apiKey);
|
|
238
|
+
if (!keyValid) {
|
|
239
|
+
s.stop("Invalid API key");
|
|
240
|
+
p2.log.error("The key was rejected. Check that it has the required permissions:");
|
|
241
|
+
p2.log.info(" developer:create_app, developer:manage_api_key, developer:manage_webhook");
|
|
242
|
+
p2.log.info(` Dashboard: ${pc2.cyan("https://whop.com/dashboard/developer")}`);
|
|
243
|
+
return { productionUrl };
|
|
244
|
+
}
|
|
245
|
+
s.stop("API key valid");
|
|
246
|
+
const callbackPath = framework === "astro" ? "/api/auth/callback" : "/api/auth/callback";
|
|
247
|
+
const redirectUris = [
|
|
248
|
+
`http://localhost:3000${callbackPath}`,
|
|
249
|
+
`${productionUrl}${callbackPath}`
|
|
250
|
+
];
|
|
251
|
+
s.start("Creating Whop OAuth app...");
|
|
252
|
+
const app = await createWhopApp(apiKey, projectName, redirectUris);
|
|
253
|
+
if (!app) {
|
|
254
|
+
s.stop("Failed to create Whop app");
|
|
255
|
+
p2.log.error("Create it manually in the Whop dashboard.");
|
|
256
|
+
return { productionUrl };
|
|
257
|
+
}
|
|
258
|
+
s.stop(`Whop app created: ${pc2.bold(app.id)}`);
|
|
259
|
+
const webhookUrl = `${productionUrl}/api/webhooks/whop`;
|
|
260
|
+
s.start("Creating webhook endpoint...");
|
|
261
|
+
const webhook = await createWhopWebhook(apiKey, webhookUrl, WEBHOOK_EVENTS);
|
|
262
|
+
if (!webhook) {
|
|
263
|
+
s.stop("Failed to create webhook");
|
|
264
|
+
p2.log.warning("Create it manually in the Whop dashboard.");
|
|
265
|
+
} else {
|
|
266
|
+
s.stop("Webhook endpoint created");
|
|
267
|
+
}
|
|
268
|
+
const envVars = {};
|
|
269
|
+
if (framework === "nextjs") {
|
|
270
|
+
envVars["NEXT_PUBLIC_WHOP_APP_ID"] = app.id;
|
|
271
|
+
} else {
|
|
272
|
+
envVars["WHOP_APP_ID"] = app.id;
|
|
273
|
+
}
|
|
274
|
+
envVars["WHOP_API_KEY"] = app.client_secret;
|
|
275
|
+
if (webhook?.secret) {
|
|
276
|
+
envVars["WHOP_WEBHOOK_SECRET"] = webhook.secret;
|
|
277
|
+
}
|
|
278
|
+
s.start("Pushing credentials to Vercel...");
|
|
279
|
+
const { success, failed } = vercelEnvSetBatch(envVars, projectDir);
|
|
280
|
+
if (failed.length > 0) {
|
|
281
|
+
s.stop(`Pushed ${success.length} vars, ${failed.length} failed`);
|
|
282
|
+
p2.log.warning(`Failed to push: ${failed.join(", ")}. Add them manually in Vercel dashboard.`);
|
|
283
|
+
} else {
|
|
284
|
+
s.stop(`${success.length} environment variables pushed`);
|
|
285
|
+
}
|
|
286
|
+
s.start("Redeploying with full configuration...");
|
|
287
|
+
const redeployResult = exec("vercel deploy --prod --yes", projectDir);
|
|
288
|
+
if (redeployResult.success) {
|
|
289
|
+
s.stop("Redeployed successfully");
|
|
290
|
+
} else {
|
|
291
|
+
s.stop("Redeploy failed \u2014 will pick up env vars on next deploy");
|
|
292
|
+
}
|
|
293
|
+
return {
|
|
294
|
+
productionUrl,
|
|
295
|
+
whopAppId: app.id,
|
|
296
|
+
whopApiKey: app.client_secret,
|
|
297
|
+
webhookSecret: webhook?.secret
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
export {
|
|
302
|
+
runDeployPipeline
|
|
303
|
+
};
|
package/dist/cli-create.js
CHANGED
|
@@ -3,14 +3,16 @@ import {
|
|
|
3
3
|
APP_TYPES,
|
|
4
4
|
FRAMEWORKS,
|
|
5
5
|
createManifest,
|
|
6
|
-
detectPackageManager,
|
|
7
|
-
exec,
|
|
8
|
-
execInteractive,
|
|
9
6
|
getTemplate,
|
|
10
|
-
hasCommand,
|
|
11
7
|
installProviderSkills,
|
|
12
8
|
writeProjectContext
|
|
13
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-3LBG56BE.js";
|
|
10
|
+
import {
|
|
11
|
+
detectPackageManager,
|
|
12
|
+
exec,
|
|
13
|
+
execInteractive,
|
|
14
|
+
hasCommand
|
|
15
|
+
} from "./chunk-GFM6IVTZ.js";
|
|
14
16
|
|
|
15
17
|
// src/cli-create.ts
|
|
16
18
|
import { runMain } from "citty";
|
|
@@ -456,6 +458,15 @@ var init_default = defineCommand({
|
|
|
456
458
|
description: "Show what would be created without doing it",
|
|
457
459
|
default: false
|
|
458
460
|
},
|
|
461
|
+
"skip-deploy": {
|
|
462
|
+
type: "boolean",
|
|
463
|
+
description: "Skip Vercel deployment",
|
|
464
|
+
default: false
|
|
465
|
+
},
|
|
466
|
+
"whop-company-key": {
|
|
467
|
+
type: "string",
|
|
468
|
+
description: "Whop Company API key for automatic app creation"
|
|
469
|
+
},
|
|
459
470
|
verbose: {
|
|
460
471
|
type: "boolean",
|
|
461
472
|
description: "Show detailed output",
|
|
@@ -672,40 +683,70 @@ var init_default = defineCommand({
|
|
|
672
683
|
s.stop("Dependencies installed");
|
|
673
684
|
}
|
|
674
685
|
initGit(projectDir);
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
686
|
+
let deployResult = null;
|
|
687
|
+
if (!args["skip-deploy"] && !args["dry-run"]) {
|
|
688
|
+
const shouldDeploy = isNonInteractive ? false : await (async () => {
|
|
689
|
+
const result = await p5.confirm({
|
|
690
|
+
message: "Deploy to Vercel and connect to Whop?",
|
|
691
|
+
initialValue: true
|
|
692
|
+
});
|
|
693
|
+
return !isCancelled(result) && result;
|
|
694
|
+
})();
|
|
695
|
+
if (shouldDeploy) {
|
|
696
|
+
const { runDeployPipeline } = await import("./deploy-RDSYVJ3L.js");
|
|
697
|
+
deployResult = await runDeployPipeline({
|
|
698
|
+
projectDir,
|
|
699
|
+
projectName,
|
|
700
|
+
databaseUrl: dbUrl || void 0,
|
|
701
|
+
framework,
|
|
702
|
+
whopCompanyKey: args["whop-company-key"]
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
}
|
|
685
706
|
let summary = "";
|
|
686
|
-
if (
|
|
687
|
-
summary += `${pc5.green("\u2713")} ${
|
|
707
|
+
if (deployResult?.productionUrl) {
|
|
708
|
+
summary += `${pc5.green("\u2713")} Deployed to ${pc5.cyan(deployResult.productionUrl)}
|
|
688
709
|
`;
|
|
689
|
-
|
|
690
|
-
if (dbNote) {
|
|
691
|
-
summary += `${pc5.yellow("!")} ${dbNote}
|
|
710
|
+
if (deployResult.whopAppId) summary += `${pc5.green("\u2713")} Whop app: ${deployResult.whopAppId}
|
|
692
711
|
`;
|
|
693
|
-
|
|
694
|
-
summary += `
|
|
712
|
+
if (deployResult.webhookSecret) summary += `${pc5.green("\u2713")} Webhooks configured
|
|
695
713
|
`;
|
|
696
|
-
|
|
714
|
+
if (dbUrl) summary += `${pc5.green("\u2713")} Database connected
|
|
697
715
|
`;
|
|
698
|
-
|
|
699
|
-
summary += ` ${pc5.bold(`${pm} run db:push`)} ${pc5.dim("# push schema to database")}
|
|
716
|
+
summary += `
|
|
700
717
|
`;
|
|
701
|
-
|
|
702
|
-
|
|
718
|
+
summary += ` ${pc5.bold("cd")} ${basename2(projectName)}
|
|
719
|
+
`;
|
|
720
|
+
summary += ` ${pc5.bold(`${pm} run dev`)} ${pc5.dim("# local development")}
|
|
721
|
+
`;
|
|
722
|
+
summary += `
|
|
723
|
+
`;
|
|
724
|
+
summary += ` ${pc5.dim(`Production: ${deployResult.productionUrl}`)}`;
|
|
725
|
+
} else {
|
|
726
|
+
if (dbUrl) summary += `${pc5.green("\u2713")} Database configured
|
|
727
|
+
`;
|
|
728
|
+
if (dbNote) summary += `${pc5.yellow("!")} ${dbNote}
|
|
703
729
|
`;
|
|
704
|
-
|
|
730
|
+
summary += `
|
|
705
731
|
`;
|
|
706
|
-
|
|
732
|
+
summary += ` ${pc5.bold("cd")} ${basename2(projectName)}
|
|
707
733
|
`;
|
|
708
|
-
|
|
734
|
+
if (dbUrl) {
|
|
735
|
+
summary += ` ${pc5.bold(`${pm} run db:push`)} ${pc5.dim("# push schema to database")}
|
|
736
|
+
`;
|
|
737
|
+
}
|
|
738
|
+
summary += ` ${pc5.bold(`${pm} run dev`)} ${pc5.dim("# start dev server")}
|
|
739
|
+
`;
|
|
740
|
+
summary += `
|
|
741
|
+
`;
|
|
742
|
+
summary += ` ${pc5.dim("Open http://localhost:3000 \u2014 the setup wizard will")}
|
|
743
|
+
`;
|
|
744
|
+
summary += ` ${pc5.dim("walk you through connecting your Whop app.")}
|
|
745
|
+
`;
|
|
746
|
+
summary += `
|
|
747
|
+
`;
|
|
748
|
+
summary += ` ${pc5.dim(`Or run ${pc5.bold("whop-kit deploy")} to deploy + auto-configure.`)}`;
|
|
749
|
+
}
|
|
709
750
|
p5.note(summary, "Your app is ready");
|
|
710
751
|
p5.outro(`${pc5.green("Happy building!")} ${pc5.dim("\u2014 whop-kit")}`);
|
|
711
752
|
}
|
package/dist/cli-kit.js
CHANGED
|
@@ -4,14 +4,19 @@ import {
|
|
|
4
4
|
FRAMEWORKS,
|
|
5
5
|
TEMPLATES,
|
|
6
6
|
addFeatureToManifest,
|
|
7
|
-
detectPackageManager,
|
|
8
|
-
exec,
|
|
9
7
|
readManifest,
|
|
10
8
|
writeFeatureSkill
|
|
11
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-3LBG56BE.js";
|
|
10
|
+
import {
|
|
11
|
+
runDeployPipeline
|
|
12
|
+
} from "./chunk-ZADKDGR4.js";
|
|
13
|
+
import {
|
|
14
|
+
detectPackageManager,
|
|
15
|
+
exec
|
|
16
|
+
} from "./chunk-GFM6IVTZ.js";
|
|
12
17
|
|
|
13
18
|
// src/cli-kit.ts
|
|
14
|
-
import { defineCommand as
|
|
19
|
+
import { defineCommand as defineCommand8, runMain } from "citty";
|
|
15
20
|
|
|
16
21
|
// src/commands/add.ts
|
|
17
22
|
import * as p4 from "@clack/prompts";
|
|
@@ -452,10 +457,59 @@ var catalog_default = defineCommand4({
|
|
|
452
457
|
}
|
|
453
458
|
});
|
|
454
459
|
|
|
455
|
-
// src/commands/
|
|
460
|
+
// src/commands/deploy.ts
|
|
456
461
|
import * as p8 from "@clack/prompts";
|
|
457
462
|
import pc6 from "picocolors";
|
|
458
463
|
import { defineCommand as defineCommand5 } from "citty";
|
|
464
|
+
import { basename } from "path";
|
|
465
|
+
var deploy_default = defineCommand5({
|
|
466
|
+
meta: {
|
|
467
|
+
name: "deploy",
|
|
468
|
+
description: "Deploy your project to Vercel and connect to Whop"
|
|
469
|
+
},
|
|
470
|
+
args: {
|
|
471
|
+
"whop-company-key": {
|
|
472
|
+
type: "string",
|
|
473
|
+
description: "Whop Company API key (skips interactive prompt)"
|
|
474
|
+
},
|
|
475
|
+
"skip-whop": {
|
|
476
|
+
type: "boolean",
|
|
477
|
+
description: "Deploy without Whop configuration",
|
|
478
|
+
default: false
|
|
479
|
+
}
|
|
480
|
+
},
|
|
481
|
+
async run({ args }) {
|
|
482
|
+
console.log("");
|
|
483
|
+
p8.intro(`${pc6.bgCyan(pc6.black(" whop-kit deploy "))}`);
|
|
484
|
+
const manifest = readManifest(".");
|
|
485
|
+
if (!manifest) {
|
|
486
|
+
p8.log.error("No .whop/config.json found. Are you in a whop-kit project?");
|
|
487
|
+
process.exit(1);
|
|
488
|
+
}
|
|
489
|
+
const projectName = basename(process.cwd());
|
|
490
|
+
const result = await runDeployPipeline({
|
|
491
|
+
projectDir: ".",
|
|
492
|
+
projectName,
|
|
493
|
+
framework: manifest.framework,
|
|
494
|
+
whopCompanyKey: args["whop-company-key"]
|
|
495
|
+
});
|
|
496
|
+
if (result) {
|
|
497
|
+
let summary = `${pc6.green("\u2713")} Live at ${pc6.cyan(result.productionUrl)}
|
|
498
|
+
`;
|
|
499
|
+
if (result.whopAppId) summary += `${pc6.green("\u2713")} Whop app: ${result.whopAppId}
|
|
500
|
+
`;
|
|
501
|
+
if (result.webhookSecret) summary += `${pc6.green("\u2713")} Webhook configured
|
|
502
|
+
`;
|
|
503
|
+
p8.note(summary, "Deployment complete");
|
|
504
|
+
}
|
|
505
|
+
p8.outro("Done");
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
// src/commands/open.ts
|
|
510
|
+
import * as p9 from "@clack/prompts";
|
|
511
|
+
import pc7 from "picocolors";
|
|
512
|
+
import { defineCommand as defineCommand6 } from "citty";
|
|
459
513
|
var DASHBOARDS = {
|
|
460
514
|
whop: { name: "Whop Developer Dashboard", url: "https://whop.com/dashboard/developer" },
|
|
461
515
|
neon: { name: "Neon Console", url: "https://console.neon.tech" },
|
|
@@ -468,7 +522,7 @@ function openUrl(url) {
|
|
|
468
522
|
else if (platform === "win32") exec(`start "${url}"`);
|
|
469
523
|
else exec(`xdg-open "${url}"`);
|
|
470
524
|
}
|
|
471
|
-
var open_default =
|
|
525
|
+
var open_default = defineCommand6({
|
|
472
526
|
meta: {
|
|
473
527
|
name: "open",
|
|
474
528
|
description: "Open a provider dashboard in your browser"
|
|
@@ -483,7 +537,7 @@ var open_default = defineCommand5({
|
|
|
483
537
|
async run({ args }) {
|
|
484
538
|
let target = args.target;
|
|
485
539
|
if (!target) {
|
|
486
|
-
const result = await
|
|
540
|
+
const result = await p9.select({
|
|
487
541
|
message: "Which dashboard?",
|
|
488
542
|
options: Object.entries(DASHBOARDS).map(([value, d]) => ({
|
|
489
543
|
value,
|
|
@@ -491,43 +545,43 @@ var open_default = defineCommand5({
|
|
|
491
545
|
hint: d.url
|
|
492
546
|
}))
|
|
493
547
|
});
|
|
494
|
-
if (
|
|
495
|
-
|
|
548
|
+
if (p9.isCancel(result)) {
|
|
549
|
+
p9.cancel("Cancelled.");
|
|
496
550
|
process.exit(0);
|
|
497
551
|
}
|
|
498
552
|
target = result;
|
|
499
553
|
}
|
|
500
554
|
const dashboard = DASHBOARDS[target];
|
|
501
555
|
if (!dashboard) {
|
|
502
|
-
|
|
556
|
+
p9.log.error(`Unknown dashboard "${target}". Options: ${Object.keys(DASHBOARDS).join(", ")}`);
|
|
503
557
|
process.exit(1);
|
|
504
558
|
}
|
|
505
559
|
openUrl(dashboard.url);
|
|
506
560
|
console.log(`
|
|
507
|
-
Opening ${
|
|
561
|
+
Opening ${pc7.bold(dashboard.name)} \u2192 ${pc7.cyan(dashboard.url)}
|
|
508
562
|
`);
|
|
509
563
|
}
|
|
510
564
|
});
|
|
511
565
|
|
|
512
566
|
// src/commands/upgrade.ts
|
|
513
|
-
import * as
|
|
514
|
-
import
|
|
515
|
-
import { defineCommand as
|
|
516
|
-
var upgrade_default =
|
|
567
|
+
import * as p10 from "@clack/prompts";
|
|
568
|
+
import pc8 from "picocolors";
|
|
569
|
+
import { defineCommand as defineCommand7 } from "citty";
|
|
570
|
+
var upgrade_default = defineCommand7({
|
|
517
571
|
meta: {
|
|
518
572
|
name: "upgrade",
|
|
519
573
|
description: "Update whop-kit to the latest version in your project"
|
|
520
574
|
},
|
|
521
575
|
async run() {
|
|
522
576
|
console.log("");
|
|
523
|
-
|
|
577
|
+
p10.intro(`${pc8.bgCyan(pc8.black(" whop-kit upgrade "))}`);
|
|
524
578
|
const manifest = readManifest(".");
|
|
525
579
|
if (!manifest) {
|
|
526
|
-
|
|
580
|
+
p10.log.error("No .whop/config.json found. Are you in a whop-kit project?");
|
|
527
581
|
process.exit(1);
|
|
528
582
|
}
|
|
529
583
|
const pm = detectPackageManager();
|
|
530
|
-
const s =
|
|
584
|
+
const s = p10.spinner();
|
|
531
585
|
s.start("Checking for updates...");
|
|
532
586
|
const latest = exec("npm view whop-kit version");
|
|
533
587
|
s.stop(latest.success ? `Latest: whop-kit@${latest.stdout}` : "Could not check latest version");
|
|
@@ -535,20 +589,20 @@ var upgrade_default = defineCommand6({
|
|
|
535
589
|
const cmd = pm === "npm" ? "npm install whop-kit@latest" : pm === "yarn" ? "yarn add whop-kit@latest" : pm === "bun" ? "bun add whop-kit@latest" : "pnpm add whop-kit@latest";
|
|
536
590
|
const result = exec(cmd);
|
|
537
591
|
if (result.success) {
|
|
538
|
-
s.stop(
|
|
592
|
+
s.stop(pc8.green("whop-kit upgraded"));
|
|
539
593
|
} else {
|
|
540
|
-
s.stop(
|
|
541
|
-
|
|
594
|
+
s.stop(pc8.red("Upgrade failed"));
|
|
595
|
+
p10.log.error("Try running manually: " + pc8.bold(cmd));
|
|
542
596
|
}
|
|
543
|
-
|
|
597
|
+
p10.outro("Done");
|
|
544
598
|
}
|
|
545
599
|
});
|
|
546
600
|
|
|
547
601
|
// src/cli-kit.ts
|
|
548
|
-
var main =
|
|
602
|
+
var main = defineCommand8({
|
|
549
603
|
meta: {
|
|
550
604
|
name: "whop-kit",
|
|
551
|
-
version: "0.
|
|
605
|
+
version: "0.6.0",
|
|
552
606
|
description: "Manage your Whop project"
|
|
553
607
|
},
|
|
554
608
|
subCommands: {
|
|
@@ -556,6 +610,7 @@ var main = defineCommand7({
|
|
|
556
610
|
status: status_default,
|
|
557
611
|
env: env_default,
|
|
558
612
|
catalog: catalog_default,
|
|
613
|
+
deploy: deploy_default,
|
|
559
614
|
open: open_default,
|
|
560
615
|
upgrade: upgrade_default
|
|
561
616
|
}
|