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