@moneydevkit/create 0.3.2 → 0.4.0-beta.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/index.cjs CHANGED
@@ -28,8 +28,8 @@ var import_client = require("@orpc/client");
28
28
  var import_fetch = require("@orpc/client/fetch");
29
29
  var p = __toESM(require("@clack/prompts"), 1);
30
30
  var import_minimist = __toESM(require("minimist"), 1);
31
- var import_node_path2 = __toESM(require("path"), 1);
32
- var import_node_fs = __toESM(require("fs"), 1);
31
+ var import_node_path6 = __toESM(require("path"), 1);
32
+ var import_node_fs5 = __toESM(require("fs"), 1);
33
33
  var import_node_os = __toESM(require("os"), 1);
34
34
  var import_open = __toESM(require("open"), 1);
35
35
  var import_clipboardy = __toESM(require("clipboardy"), 1);
@@ -72,6 +72,392 @@ function deriveProjectName(input, webhookUrl) {
72
72
  return webhookUrl;
73
73
  }
74
74
 
75
+ // src/utils/nextjs-detector.ts
76
+ var import_node_fs = __toESM(require("fs"), 1);
77
+ var import_node_path2 = __toESM(require("path"), 1);
78
+ var import_semver = __toESM(require("semver"), 1);
79
+ var NEXT_CONFIG_BASENAMES = [
80
+ "next.config.js",
81
+ "next.config.cjs",
82
+ "next.config.mjs",
83
+ "next.config.ts",
84
+ "next.config.mts"
85
+ ];
86
+ var APP_DIR_CANDIDATES = ["app", import_node_path2.default.join("src", "app")];
87
+ var PAGES_DIR_CANDIDATES = ["pages", import_node_path2.default.join("src", "pages")];
88
+ function fileExists(target) {
89
+ try {
90
+ return import_node_fs.default.existsSync(target);
91
+ } catch {
92
+ return false;
93
+ }
94
+ }
95
+ function readPackageJson(pkgPath) {
96
+ try {
97
+ const content = import_node_fs.default.readFileSync(pkgPath, "utf8");
98
+ return JSON.parse(content);
99
+ } catch {
100
+ return null;
101
+ }
102
+ }
103
+ function hasNextDependency(pkg) {
104
+ const deps = pkg.dependencies;
105
+ const devDeps = pkg.devDependencies;
106
+ return Boolean(deps?.next || devDeps?.next);
107
+ }
108
+ function extractNextVersion(pkg) {
109
+ const deps = pkg.dependencies;
110
+ const devDeps = pkg.devDependencies;
111
+ return deps?.next ?? devDeps?.next ?? void 0;
112
+ }
113
+ function findNearestPackageJson(startDir) {
114
+ let current = import_node_path2.default.resolve(startDir);
115
+ while (true) {
116
+ const candidate = import_node_path2.default.join(current, "package.json");
117
+ if (fileExists(candidate)) {
118
+ return candidate;
119
+ }
120
+ const parent = import_node_path2.default.dirname(current);
121
+ if (parent === current) {
122
+ return void 0;
123
+ }
124
+ current = parent;
125
+ }
126
+ }
127
+ function findNextConfig(rootDir) {
128
+ for (const basename of NEXT_CONFIG_BASENAMES) {
129
+ const candidate = import_node_path2.default.join(rootDir, basename);
130
+ if (fileExists(candidate)) {
131
+ return candidate;
132
+ }
133
+ }
134
+ return void 0;
135
+ }
136
+ function detectNextJsProject(startDir) {
137
+ const pkgPath = findNearestPackageJson(startDir);
138
+ const rootDir = pkgPath ? import_node_path2.default.dirname(pkgPath) : import_node_path2.default.resolve(startDir);
139
+ const pkg = pkgPath ? readPackageJson(pkgPath) : null;
140
+ const hasNext = pkg ? hasNextDependency(pkg) : false;
141
+ const nextVersion = pkg ? extractNextVersion(pkg) : void 0;
142
+ let versionIsSupported = true;
143
+ if (nextVersion) {
144
+ const minVersion = import_semver.default.minVersion(nextVersion);
145
+ if (minVersion) {
146
+ versionIsSupported = import_semver.default.gte(minVersion, "15.0.0");
147
+ }
148
+ }
149
+ const nextConfigPath = findNextConfig(rootDir);
150
+ const appDir = APP_DIR_CANDIDATES.map((candidate) => import_node_path2.default.join(rootDir, candidate)).find(
151
+ (candidate) => fileExists(candidate)
152
+ );
153
+ const pagesDir = PAGES_DIR_CANDIDATES.map((candidate) => import_node_path2.default.join(rootDir, candidate)).find(
154
+ (candidate) => fileExists(candidate)
155
+ );
156
+ const usesTypeScript = fileExists(import_node_path2.default.join(rootDir, "tsconfig.json")) || fileExists(import_node_path2.default.join(rootDir, "next-env.d.ts"));
157
+ const found = Boolean(hasNext || nextConfigPath || appDir || pagesDir);
158
+ return {
159
+ found,
160
+ rootDir: found ? rootDir : void 0,
161
+ nextConfigPath,
162
+ appDir,
163
+ pagesDir,
164
+ usesTypeScript,
165
+ nextVersion,
166
+ versionIsSupported
167
+ };
168
+ }
169
+
170
+ // src/scaffold/nextjs.ts
171
+ var import_node_fs4 = __toESM(require("fs"), 1);
172
+ var import_node_path5 = __toESM(require("path"), 1);
173
+ var import_node_child_process = require("child_process");
174
+
175
+ // src/utils/package-manager.ts
176
+ var import_node_fs2 = __toESM(require("fs"), 1);
177
+ var import_node_path3 = __toESM(require("path"), 1);
178
+ function detectPackageManager(rootDir) {
179
+ if (import_node_fs2.default.existsSync(import_node_path3.default.join(rootDir, "pnpm-lock.yaml"))) return "pnpm";
180
+ if (import_node_fs2.default.existsSync(import_node_path3.default.join(rootDir, "yarn.lock"))) return "yarn";
181
+ if (import_node_fs2.default.existsSync(import_node_path3.default.join(rootDir, "bun.lockb"))) return "bun";
182
+ if (import_node_fs2.default.existsSync(import_node_path3.default.join(rootDir, "package-lock.json"))) return "npm";
183
+ return "npm";
184
+ }
185
+ function hasDependency(rootDir, depName) {
186
+ try {
187
+ const pkg = JSON.parse(import_node_fs2.default.readFileSync(import_node_path3.default.join(rootDir, "package.json"), "utf8"));
188
+ return Boolean(pkg.dependencies?.[depName] || pkg.devDependencies?.[depName]);
189
+ } catch {
190
+ return false;
191
+ }
192
+ }
193
+
194
+ // src/utils/fs-utils.ts
195
+ var import_node_fs3 = __toESM(require("fs"), 1);
196
+ var import_node_path4 = __toESM(require("path"), 1);
197
+ function ensureDir(filePath) {
198
+ const dir = import_node_path4.default.dirname(filePath);
199
+ import_node_fs3.default.mkdirSync(dir, { recursive: true });
200
+ }
201
+ function readFileSafe(filePath) {
202
+ try {
203
+ return import_node_fs3.default.readFileSync(filePath, "utf8");
204
+ } catch {
205
+ return null;
206
+ }
207
+ }
208
+ function writeFileIfAbsent(filePath, content) {
209
+ if (import_node_fs3.default.existsSync(filePath)) {
210
+ const existing = readFileSafe(filePath);
211
+ if (existing?.trim() === content.trim()) {
212
+ return { status: "skipped-exists", path: filePath };
213
+ }
214
+ return { status: "skipped-different", path: filePath };
215
+ }
216
+ ensureDir(filePath);
217
+ import_node_fs3.default.writeFileSync(filePath, content, "utf8");
218
+ return { status: "created", path: filePath };
219
+ }
220
+ function writeFileWithBackup(filePath, content) {
221
+ if (!import_node_fs3.default.existsSync(filePath)) {
222
+ ensureDir(filePath);
223
+ import_node_fs3.default.writeFileSync(filePath, content, "utf8");
224
+ return { status: "created", path: filePath };
225
+ }
226
+ const existing = readFileSafe(filePath) ?? "";
227
+ if (existing.trim() === content.trim()) {
228
+ return { status: "skipped-exists", path: filePath };
229
+ }
230
+ const backupPath = `${filePath}.mdk-backup`;
231
+ import_node_fs3.default.writeFileSync(backupPath, existing, "utf8");
232
+ import_node_fs3.default.writeFileSync(filePath, content, "utf8");
233
+ return { status: "updated-with-backup", path: filePath, backupPath };
234
+ }
235
+
236
+ // src/scaffold/nextjs.ts
237
+ var import_meta = {};
238
+ var templateRoot = new URL("../templates/nextjs/", import_meta.url);
239
+ function readTemplate(relativePath) {
240
+ return import_node_fs4.default.readFileSync(new URL(relativePath, templateRoot), "utf8");
241
+ }
242
+ function findExistingConfig(rootDir, preferred) {
243
+ if (preferred && import_node_fs4.default.existsSync(preferred)) return preferred;
244
+ const candidates = [
245
+ "next.config.js",
246
+ "next.config.cjs",
247
+ "next.config.mjs",
248
+ "next.config.ts",
249
+ "next.config.mts"
250
+ ];
251
+ for (const candidate of candidates) {
252
+ const fullPath = import_node_path5.default.join(rootDir, candidate);
253
+ if (import_node_fs4.default.existsSync(fullPath)) {
254
+ return fullPath;
255
+ }
256
+ }
257
+ return void 0;
258
+ }
259
+ async function installNextjsPackage(rootDir, packageManager) {
260
+ if (hasDependency(rootDir, "@moneydevkit/nextjs")) {
261
+ return { installed: false, skipped: true };
262
+ }
263
+ const commandForPm = {
264
+ pnpm: ["pnpm", ["add", "@moneydevkit/nextjs"]],
265
+ yarn: ["yarn", ["add", "@moneydevkit/nextjs"]],
266
+ npm: ["npm", ["install", "@moneydevkit/nextjs"]],
267
+ bun: ["bun", ["add", "@moneydevkit/nextjs"]]
268
+ };
269
+ const [cmd, args] = commandForPm[packageManager];
270
+ await new Promise((resolve, reject) => {
271
+ const child = (0, import_node_child_process.spawn)(cmd, args, { stdio: "inherit", cwd: rootDir });
272
+ child.on("exit", (code) => {
273
+ if (code === 0) {
274
+ resolve();
275
+ } else {
276
+ reject(new Error(`${cmd} ${args.join(" ")} failed with code ${code}`));
277
+ }
278
+ });
279
+ child.on("error", reject);
280
+ });
281
+ return { installed: true, skipped: false };
282
+ }
283
+ function createAppRouteContent(isTypeScript) {
284
+ return readTemplate(`app/api/mdk/route.${isTypeScript ? "ts" : "js"}`);
285
+ }
286
+ function createAppCheckoutPageContent(isTypeScript) {
287
+ return readTemplate(
288
+ `app/checkout/[id]/page.${isTypeScript ? "tsx" : "js"}`
289
+ );
290
+ }
291
+ function isTypeScriptConfig(configPath) {
292
+ return configPath.endsWith(".ts") || configPath.endsWith(".mts");
293
+ }
294
+ function patchNextConfigTypes(source) {
295
+ let patched = source.replace(
296
+ /import\s+type\s+\{\s*NextConfig\s*\}\s+from\s+["']next["'];?\s*\n?/g,
297
+ ""
298
+ );
299
+ patched = patched.replace(/:\s*NextConfig\b/g, ": NextConfigOverrides");
300
+ return patched;
301
+ }
302
+ function updateConfigFile(configPath) {
303
+ const isTs = isTypeScriptConfig(configPath);
304
+ const pluginImport = isTs ? 'import withMdkCheckout, { type NextConfigOverrides } from "@moneydevkit/nextjs/next-plugin";' : 'import withMdkCheckout from "@moneydevkit/nextjs/next-plugin";';
305
+ if (!import_node_fs4.default.existsSync(configPath)) {
306
+ const content = [
307
+ pluginImport,
308
+ "",
309
+ "// Wrap your existing Next.js config with withMdkCheckout to enable Money Dev Kit.",
310
+ "// Example: export default withMdkCheckout(yourConfig)",
311
+ isTs ? "const nextConfig: NextConfigOverrides = {};" : "const nextConfig = {};",
312
+ "",
313
+ "export default withMdkCheckout(nextConfig);",
314
+ ""
315
+ ].join("\n");
316
+ const writeResult = writeFileWithBackup(configPath, content);
317
+ return {
318
+ status: "created",
319
+ path: configPath,
320
+ backupPath: writeResult.status === "updated-with-backup" ? writeResult.backupPath : void 0
321
+ };
322
+ }
323
+ const original = readFileSafe(configPath) ?? "";
324
+ if (original.includes("@moneydevkit/nextjs/next-plugin") || original.includes("withMdkCheckout")) {
325
+ return { status: "skipped", path: configPath, reason: "already configured" };
326
+ }
327
+ if (original.includes("module.exports")) {
328
+ const re = /module\.exports\s*=\s*(\{[\s\S]*?\});?/;
329
+ const match = original.match(re);
330
+ if (match) {
331
+ const prefix = 'const withMdkCheckout = require("@moneydevkit/nextjs/next-plugin").default ?? require("@moneydevkit/nextjs/next-plugin");\n';
332
+ const replaced = original.replace(
333
+ re,
334
+ `module.exports = withMdkCheckout(${match[1]});`
335
+ );
336
+ const result = writeFileWithBackup(configPath, `${prefix}${replaced}`);
337
+ return {
338
+ status: "updated",
339
+ path: configPath,
340
+ backupPath: result.status === "updated-with-backup" ? result.backupPath : void 0
341
+ };
342
+ }
343
+ }
344
+ if (original.includes("export default")) {
345
+ const reDefaultObject = /export\s+default\s+(\{[\s\S]*?\});?/;
346
+ const objectMatch = original.match(reDefaultObject);
347
+ if (objectMatch) {
348
+ const content = [
349
+ pluginImport,
350
+ "",
351
+ isTs ? "const nextConfig: NextConfigOverrides = " + objectMatch[1] + ";" : "const nextConfig = " + objectMatch[1] + ";",
352
+ "",
353
+ "export default withMdkCheckout(nextConfig);",
354
+ ""
355
+ ].join("\n");
356
+ const writeResult = writeFileWithBackup(configPath, content);
357
+ return {
358
+ status: "updated",
359
+ path: configPath,
360
+ backupPath: writeResult.status === "updated-with-backup" ? writeResult.backupPath : void 0
361
+ };
362
+ }
363
+ const reNamed = /export\s+default\s+([a-zA-Z0-9_]+)\s*;?/;
364
+ const namedMatch = original.match(reNamed);
365
+ if (namedMatch) {
366
+ const name = namedMatch[1];
367
+ const patched = isTs && original.includes("NextConfig") ? patchNextConfigTypes(original) : original;
368
+ const lines = [
369
+ pluginImport,
370
+ patched.replace(reNamed, `export default withMdkCheckout(${name});`)
371
+ ];
372
+ const writeResult = writeFileWithBackup(configPath, lines.join("\n"));
373
+ return {
374
+ status: "updated",
375
+ path: configPath,
376
+ backupPath: writeResult.status === "updated-with-backup" ? writeResult.backupPath : void 0
377
+ };
378
+ }
379
+ }
380
+ return {
381
+ status: "skipped",
382
+ path: configPath,
383
+ reason: "unrecognized format; wrap your export with withMdkCheckout, e.g. export default withMdkCheckout(yourConfig)"
384
+ };
385
+ }
386
+ function scaffoldAppRouter(appDir, isTypeScript) {
387
+ const added = [];
388
+ const skipped = [];
389
+ const routePath = import_node_path5.default.join(
390
+ appDir,
391
+ "api",
392
+ "mdk",
393
+ `route.${isTypeScript ? "ts" : "js"}`
394
+ );
395
+ const routeResult = writeFileIfAbsent(
396
+ routePath,
397
+ createAppRouteContent(isTypeScript)
398
+ );
399
+ if (routeResult.status === "created") {
400
+ added.push(routeResult.path);
401
+ } else {
402
+ skipped.push(routeResult.path);
403
+ }
404
+ const pagePath = import_node_path5.default.join(
405
+ appDir,
406
+ "checkout",
407
+ "[id]",
408
+ `page.${isTypeScript ? "tsx" : "js"}`
409
+ );
410
+ const pageResult = writeFileIfAbsent(
411
+ pagePath,
412
+ createAppCheckoutPageContent(isTypeScript)
413
+ );
414
+ if (pageResult.status === "created") {
415
+ added.push(pageResult.path);
416
+ } else {
417
+ skipped.push(pageResult.path);
418
+ }
419
+ return { added, skipped };
420
+ }
421
+ async function scaffoldNextJs(options) {
422
+ const { detection, jsonMode, skipInstall } = options;
423
+ if (!detection.rootDir) {
424
+ throw new Error("Next.js project root not found for scaffolding.");
425
+ }
426
+ const warnings = [];
427
+ const rootDir = detection.rootDir;
428
+ const packageManager = detectPackageManager(rootDir);
429
+ const installResult = skipInstall ? { installed: false, skipped: true } : await installNextjsPackage(rootDir, packageManager);
430
+ const configPath = findExistingConfig(rootDir, detection.nextConfigPath) ?? import_node_path5.default.join(rootDir, "next.config.js");
431
+ const configResult = updateConfigFile(configPath);
432
+ if (configResult.status === "skipped") {
433
+ warnings.push(
434
+ `Could not automatically update ${import_node_path5.default.basename(configPath)} (${configResult.reason}). Please wrap your Next.js config with withMdkCheckout manually.`
435
+ );
436
+ }
437
+ const appDir = detection.appDir ?? import_node_path5.default.join(rootDir, "app");
438
+ const fileResults = scaffoldAppRouter(appDir, detection.usesTypeScript);
439
+ if (!detection.appDir) {
440
+ warnings.push(
441
+ "No app/ directory detected; created App Router scaffolding in app/."
442
+ );
443
+ }
444
+ if (!jsonMode) {
445
+ if (!installResult.installed && installResult.skipped) {
446
+ console.log("@moneydevkit/nextjs already present; skipping install.");
447
+ }
448
+ }
449
+ return {
450
+ rootDir,
451
+ packageManager,
452
+ installedPackage: installResult.installed,
453
+ installSkipped: installResult.skipped,
454
+ addedFiles: fileResults.added,
455
+ skippedFiles: fileResults.skipped,
456
+ config: configResult,
457
+ warnings
458
+ };
459
+ }
460
+
75
461
  // src/index.ts
76
462
  var DEFAULT_BASE_URL = "https://moneydevkit.com";
77
463
  var DEFAULT_ENV_FILE = ".env.local";
@@ -109,7 +495,7 @@ var CookieJar = class {
109
495
  };
110
496
  function parseFlags(argv) {
111
497
  const result = (0, import_minimist.default)(argv, {
112
- boolean: ["json", "no-clipboard", "no-open", "force-new-webhook", "yes"],
498
+ boolean: ["json", "no-clipboard", "no-open", "force-new-webhook", "scaffold-nextjs"],
113
499
  string: [
114
500
  "base-url",
115
501
  "env-target",
@@ -125,14 +511,14 @@ function parseFlags(argv) {
125
511
  "no-open": false,
126
512
  json: false,
127
513
  "force-new-webhook": false,
128
- yes: false
514
+ "scaffold-nextjs": false
129
515
  }
130
516
  });
131
517
  return {
132
518
  json: Boolean(result.json),
133
519
  noClipboard: Boolean(result["no-clipboard"]),
134
520
  noOpen: Boolean(result["no-open"]),
135
- yes: Boolean(result.yes),
521
+ scaffoldNextjs: Boolean(result["scaffold-nextjs"]),
136
522
  baseUrl: result["base-url"],
137
523
  envFile: result["env-target"],
138
524
  projectName: typeof result["project-name"] === "string" ? result["project-name"] : void 0,
@@ -142,20 +528,20 @@ function parseFlags(argv) {
142
528
  };
143
529
  }
144
530
  function normalizeDirectory(dir) {
145
- if (import_node_path2.default.isAbsolute(dir)) return dir;
146
- return import_node_path2.default.resolve(process.cwd(), dir);
531
+ if (import_node_path6.default.isAbsolute(dir)) return dir;
532
+ return import_node_path6.default.resolve(process.cwd(), dir);
147
533
  }
148
534
  function ensureDirectoryExists(dir) {
149
- if (!import_node_fs.default.existsSync(dir)) {
150
- import_node_fs.default.mkdirSync(dir, { recursive: true });
535
+ if (!import_node_fs5.default.existsSync(dir)) {
536
+ import_node_fs5.default.mkdirSync(dir, { recursive: true });
151
537
  }
152
538
  }
153
539
  function readEnvFile(filePath) {
154
540
  const env = /* @__PURE__ */ new Map();
155
- if (!import_node_fs.default.existsSync(filePath)) {
541
+ if (!import_node_fs5.default.existsSync(filePath)) {
156
542
  return env;
157
543
  }
158
- const contents = import_node_fs.default.readFileSync(filePath, "utf8");
544
+ const contents = import_node_fs5.default.readFileSync(filePath, "utf8");
159
545
  for (const line of contents.split(/\r?\n/)) {
160
546
  if (!line || line.startsWith("#")) continue;
161
547
  const [key, ...rest] = line.split("=");
@@ -176,22 +562,23 @@ function writeEnvFile(filePath, existing, updates) {
176
562
  existing.set(key, value);
177
563
  }
178
564
  const content = Array.from(existing.entries()).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => `${key}=${value}`).join(import_node_os.default.EOL) + import_node_os.default.EOL;
179
- import_node_fs.default.writeFileSync(filePath, content, "utf8");
565
+ import_node_fs5.default.writeFileSync(filePath, content, "utf8");
180
566
  }
181
567
  function ensureEnvFileExists(filePath) {
182
- const dir = import_node_path2.default.dirname(filePath);
568
+ const dir = import_node_path6.default.dirname(filePath);
183
569
  ensureDirectoryExists(dir);
184
- if (!import_node_fs.default.existsSync(filePath)) {
185
- import_node_fs.default.writeFileSync(filePath, "", "utf8");
570
+ if (!import_node_fs5.default.existsSync(filePath)) {
571
+ import_node_fs5.default.writeFileSync(filePath, "", "utf8");
186
572
  }
187
573
  }
188
574
  function resolveLocalEnvPath(options) {
189
- const trimmed = options.organizationId?.trim();
190
- if (!trimmed) {
575
+ const organization = options.organizationId?.trim();
576
+ const apiKey = options.apiKeyId?.trim();
577
+ if (!organization || !apiKey) {
191
578
  return void 0;
192
579
  }
193
580
  const homeDir = import_node_os.default.homedir();
194
- return import_node_path2.default.join(homeDir, ".mdk", trimmed, ".env");
581
+ return import_node_path6.default.join(homeDir, ".mdk", organization, apiKey, ".env");
195
582
  }
196
583
  function isValidHttpUrl(value) {
197
584
  if (!value) return false;
@@ -255,7 +642,7 @@ async function runDeviceFlow(options) {
255
642
  p.note(
256
643
  [
257
644
  `Device code: ${device.userCode}`,
258
- `Webhook URL: ${webhookUrl}`,
645
+ `Domain: ${webhookUrl}`,
259
646
  "Open the authorization page, click Authorize, then return to this terminal."
260
647
  ].join("\n"),
261
648
  "Authorize this device"
@@ -384,7 +771,7 @@ async function main() {
384
771
  }
385
772
  envFile = envPrompt.trim() || DEFAULT_ENV_FILE;
386
773
  }
387
- const envPath = import_node_path2.default.join(projectDir, envFile);
774
+ const envPath = import_node_path6.default.join(projectDir, envFile);
388
775
  const existingEnvValues = readEnvFile(envPath);
389
776
  const mnemonicAlreadySet = existingEnvValues.get("MDK_MNEMONIC")?.trim();
390
777
  if (mnemonicAlreadySet) {
@@ -411,7 +798,7 @@ async function main() {
411
798
  }
412
799
  while (!webhookUrl) {
413
800
  const webhookInput = await p.text({
414
- message: "Webhook URL for your application",
801
+ message: "Domain for your application",
415
802
  initialValue: "https://",
416
803
  placeholder: "https://yourapp.com",
417
804
  validate: (value) => isValidHttpUrl(value?.trim()) ? void 0 : "Enter a valid http(s) URL (e.g. https://yourapp.com)"
@@ -435,6 +822,39 @@ async function main() {
435
822
  projectName = namePrompt.trim() || void 0;
436
823
  }
437
824
  projectName = deriveProjectName(projectName, webhookUrl);
825
+ const nextJsDetection = detectNextJsProject(projectDir);
826
+ let shouldScaffoldNextJs = false;
827
+ if (flags.scaffoldNextjs) {
828
+ if (nextJsDetection.found) {
829
+ if (nextJsDetection.versionIsSupported) {
830
+ shouldScaffoldNextJs = true;
831
+ } else {
832
+ console.warn(
833
+ `Next.js version ${nextJsDetection.nextVersion ?? "unknown"} detected, but @moneydevkit/nextjs requires Next.js 15+. Skipping installation and scaffolding.`
834
+ );
835
+ }
836
+ } else {
837
+ console.warn(
838
+ "No NextJS app found, skipping @moneydevkit/nextjs installation. Please install manually."
839
+ );
840
+ }
841
+ } else if (!jsonMode && nextJsDetection.found) {
842
+ if (!nextJsDetection.versionIsSupported) {
843
+ console.warn(
844
+ `Next.js version ${nextJsDetection.nextVersion ?? "unknown"} detected, but @moneydevkit/nextjs requires Next.js 15+. Skipping scaffolding prompt.`
845
+ );
846
+ } else {
847
+ const scaffoldPrompt = await p.confirm({
848
+ message: `Next.js application detected at ${nextJsDetection.rootDir ?? projectDir} (version ${nextJsDetection.nextVersion ?? "unknown"}). Install and scaffold @moneydevkit/nextjs?`,
849
+ initialValue: true
850
+ });
851
+ if (p.isCancel(scaffoldPrompt)) {
852
+ p.cancel("Aborted.");
853
+ process.exit(1);
854
+ }
855
+ shouldScaffoldNextJs = Boolean(scaffoldPrompt);
856
+ }
857
+ }
438
858
  try {
439
859
  const result = await runDeviceFlow({
440
860
  flags,
@@ -445,7 +865,6 @@ async function main() {
445
865
  });
446
866
  const updates = {
447
867
  MDK_ACCESS_TOKEN: result.credentials.apiKey,
448
- MDK_WEBHOOK_SECRET: result.credentials.webhookSecret,
449
868
  MDK_MNEMONIC: result.mnemonic
450
869
  };
451
870
  ensureEnvFileExists(envPath);
@@ -453,7 +872,8 @@ async function main() {
453
872
  const preview = renderEnvPreview(existingEnv, updates);
454
873
  writeEnvFile(envPath, existingEnv, updates);
455
874
  const localEnvPath = resolveLocalEnvPath({
456
- organizationId: result.credentials.organizationId
875
+ organizationId: result.credentials.organizationId,
876
+ apiKeyId: result.credentials.apiKeyId
457
877
  });
458
878
  if (localEnvPath) {
459
879
  ensureEnvFileExists(localEnvPath);
@@ -465,11 +885,77 @@ async function main() {
465
885
  }
466
886
  if (!flags.noClipboard) {
467
887
  await import_clipboardy.default.write(
468
- [`MDK_ACCESS_TOKEN=${updates.MDK_ACCESS_TOKEN}`, `MDK_WEBHOOK_SECRET=${updates.MDK_WEBHOOK_SECRET}`, `MDK_MNEMONIC=${updates.MDK_MNEMONIC}`].join(
888
+ [`MDK_ACCESS_TOKEN=${updates.MDK_ACCESS_TOKEN}`, `MDK_MNEMONIC=${updates.MDK_MNEMONIC}`].join(
469
889
  "\n"
470
890
  )
471
891
  );
472
892
  }
893
+ let scaffoldSummary = null;
894
+ if (shouldScaffoldNextJs && nextJsDetection.found) {
895
+ try {
896
+ scaffoldSummary = await scaffoldNextJs({
897
+ detection: nextJsDetection,
898
+ jsonMode
899
+ });
900
+ if (!jsonMode && scaffoldSummary) {
901
+ const lines = [
902
+ scaffoldSummary.installedPackage ? `Installed @moneydevkit/nextjs with ${scaffoldSummary.packageManager}.` : scaffoldSummary.installSkipped ? "@moneydevkit/nextjs already installed; skipped package install." : "Skipped @moneydevkit/nextjs installation."
903
+ ];
904
+ if (scaffoldSummary.config) {
905
+ const cfg = scaffoldSummary.config;
906
+ if (cfg.status === "created") {
907
+ lines.push(`Created ${cfg.path} with withMdkCheckout().`);
908
+ if (cfg.backupPath) {
909
+ lines.push(`Created backup at ${cfg.backupPath}.`);
910
+ }
911
+ } else if (cfg.status === "updated") {
912
+ lines.push(`Updated ${cfg.path} with withMdkCheckout().`);
913
+ if (cfg.backupPath) {
914
+ lines.push(`Created backup at ${cfg.backupPath}.`);
915
+ }
916
+ } else {
917
+ lines.push(
918
+ `Could not update ${cfg.path} automatically (${cfg.reason ?? "unknown reason"}).`
919
+ );
920
+ }
921
+ }
922
+ if (scaffoldSummary.addedFiles.length > 0) {
923
+ lines.push(
924
+ `Added: ${scaffoldSummary.addedFiles.map((p2) => import_node_path6.default.relative(projectDir, p2)).join(", ")}`
925
+ );
926
+ }
927
+ if (scaffoldSummary.skippedFiles.length > 0) {
928
+ lines.push(
929
+ `Skipped existing files: ${scaffoldSummary.skippedFiles.map((p2) => import_node_path6.default.relative(projectDir, p2)).join(", ")}`
930
+ );
931
+ }
932
+ p.note(lines.join("\n"), "Next.js scaffolding");
933
+ }
934
+ if (scaffoldSummary?.warnings.length) {
935
+ for (const warning of scaffoldSummary.warnings) {
936
+ console.warn(warning);
937
+ }
938
+ }
939
+ } catch (error) {
940
+ const message = error instanceof Error ? error.message : String(error);
941
+ if (jsonMode) {
942
+ console.error(
943
+ JSON.stringify(
944
+ {
945
+ status: "error",
946
+ error: {
947
+ message: `Next.js scaffolding failed: ${message}`
948
+ }
949
+ },
950
+ null,
951
+ 2
952
+ )
953
+ );
954
+ } else {
955
+ console.warn(`Next.js scaffolding failed: ${message}`);
956
+ }
957
+ }
958
+ }
473
959
  const summary = {
474
960
  projectDir,
475
961
  envFile: envPath,
@@ -477,7 +963,8 @@ async function main() {
477
963
  webhookId: result.credentials.webhookId,
478
964
  organizationId: result.credentials.organizationId,
479
965
  webhookUrl: result.credentials.webhookUrl,
480
- mnemonic: updates.MDK_MNEMONIC
966
+ mnemonic: updates.MDK_MNEMONIC,
967
+ scaffoldedNextjs: Boolean(scaffoldSummary)
481
968
  };
482
969
  if (jsonMode) {
483
970
  console.log(
@@ -492,7 +979,8 @@ async function main() {
492
979
  webhookSecret: result.credentials.webhookSecret,
493
980
  webhookUrl: result.credentials.webhookUrl,
494
981
  organizationId: result.credentials.organizationId,
495
- mnemonic: updates.MDK_MNEMONIC
982
+ mnemonic: updates.MDK_MNEMONIC,
983
+ scaffoldedNextjs: Boolean(scaffoldSummary)
496
984
  }
497
985
  },
498
986
  null,