@moneydevkit/create 0.3.1 → 0.3.3
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/README.md +11 -1
- package/dist/index.cjs +687 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +687 -18
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
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
|
|
32
|
-
var
|
|
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,556 @@ 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
|
+
function findExistingConfig(rootDir, preferred) {
|
|
238
|
+
if (preferred && import_node_fs4.default.existsSync(preferred)) return preferred;
|
|
239
|
+
const candidates = [
|
|
240
|
+
"next.config.js",
|
|
241
|
+
"next.config.cjs",
|
|
242
|
+
"next.config.mjs",
|
|
243
|
+
"next.config.ts",
|
|
244
|
+
"next.config.mts"
|
|
245
|
+
];
|
|
246
|
+
for (const candidate of candidates) {
|
|
247
|
+
const fullPath = import_node_path5.default.join(rootDir, candidate);
|
|
248
|
+
if (import_node_fs4.default.existsSync(fullPath)) {
|
|
249
|
+
return fullPath;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return void 0;
|
|
253
|
+
}
|
|
254
|
+
async function installNextjsPackage(rootDir, packageManager) {
|
|
255
|
+
if (hasDependency(rootDir, "@moneydevkit/nextjs")) {
|
|
256
|
+
return { installed: false, skipped: true };
|
|
257
|
+
}
|
|
258
|
+
const commandForPm = {
|
|
259
|
+
pnpm: ["pnpm", ["add", "@moneydevkit/nextjs"]],
|
|
260
|
+
yarn: ["yarn", ["add", "@moneydevkit/nextjs"]],
|
|
261
|
+
npm: ["npm", ["install", "@moneydevkit/nextjs"]],
|
|
262
|
+
bun: ["bun", ["add", "@moneydevkit/nextjs"]]
|
|
263
|
+
};
|
|
264
|
+
const [cmd, args] = commandForPm[packageManager];
|
|
265
|
+
await new Promise((resolve, reject) => {
|
|
266
|
+
const child = (0, import_node_child_process.spawn)(cmd, args, { stdio: "inherit", cwd: rootDir });
|
|
267
|
+
child.on("exit", (code) => {
|
|
268
|
+
if (code === 0) {
|
|
269
|
+
resolve();
|
|
270
|
+
} else {
|
|
271
|
+
reject(new Error(`${cmd} ${args.join(" ")} failed with code ${code}`));
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
child.on("error", reject);
|
|
275
|
+
});
|
|
276
|
+
return { installed: true, skipped: false };
|
|
277
|
+
}
|
|
278
|
+
function createAppRouteContent(isTypeScript) {
|
|
279
|
+
const ext = isTypeScript ? "ts" : "js";
|
|
280
|
+
if (ext === "ts") {
|
|
281
|
+
return 'export { POST } from "@moneydevkit/nextjs/server/route";\n';
|
|
282
|
+
}
|
|
283
|
+
return 'export { POST } from "@moneydevkit/nextjs/server/route";\n';
|
|
284
|
+
}
|
|
285
|
+
function createAppCheckoutPageContent(isTypeScript) {
|
|
286
|
+
if (isTypeScript) {
|
|
287
|
+
return [
|
|
288
|
+
'"use client";',
|
|
289
|
+
"",
|
|
290
|
+
'import { Checkout } from "@moneydevkit/nextjs";',
|
|
291
|
+
"",
|
|
292
|
+
"type CheckoutPageProps = { params: { id: string } };",
|
|
293
|
+
"",
|
|
294
|
+
"export default function CheckoutPage({ params }: CheckoutPageProps) {",
|
|
295
|
+
" return <Checkout id={params.id} />;",
|
|
296
|
+
"}",
|
|
297
|
+
""
|
|
298
|
+
].join("\n");
|
|
299
|
+
}
|
|
300
|
+
return [
|
|
301
|
+
'"use client";',
|
|
302
|
+
"",
|
|
303
|
+
'import { Checkout } from "@moneydevkit/nextjs";',
|
|
304
|
+
"",
|
|
305
|
+
"export default function CheckoutPage({ params }) {",
|
|
306
|
+
" return <Checkout id={params.id} />;",
|
|
307
|
+
"}",
|
|
308
|
+
""
|
|
309
|
+
].join("\n");
|
|
310
|
+
}
|
|
311
|
+
function createPagesApiRouteContent(isTypeScript) {
|
|
312
|
+
if (isTypeScript) {
|
|
313
|
+
return [
|
|
314
|
+
'import type { NextApiRequest, NextApiResponse } from "next";',
|
|
315
|
+
'import { POST as appRouteHandler } from "@moneydevkit/nextjs/server/route";',
|
|
316
|
+
"",
|
|
317
|
+
"export default async function handler(req: NextApiRequest, res: NextApiResponse) {",
|
|
318
|
+
' const url = `http://${req.headers.host ?? "localhost"}${req.url ?? "/api/mdk"}`;',
|
|
319
|
+
" const request = new Request(url, {",
|
|
320
|
+
' method: req.method || "POST",',
|
|
321
|
+
" headers: req.headers as Record<string, string>,",
|
|
322
|
+
" body:",
|
|
323
|
+
' req.method === "GET" || req.method === "HEAD"',
|
|
324
|
+
" ? undefined",
|
|
325
|
+
' : typeof req.body === "string"',
|
|
326
|
+
" ? req.body",
|
|
327
|
+
" : JSON.stringify(req.body ?? {}),",
|
|
328
|
+
" });",
|
|
329
|
+
"",
|
|
330
|
+
" const response = await appRouteHandler(request);",
|
|
331
|
+
" res.status(response.status);",
|
|
332
|
+
" response.headers.forEach((value, key) => {",
|
|
333
|
+
" res.setHeader(key, value);",
|
|
334
|
+
" });",
|
|
335
|
+
" const body = await response.arrayBuffer();",
|
|
336
|
+
" res.send(Buffer.from(body));",
|
|
337
|
+
"}",
|
|
338
|
+
""
|
|
339
|
+
].join("\n");
|
|
340
|
+
}
|
|
341
|
+
return [
|
|
342
|
+
'import { POST as appRouteHandler } from "@moneydevkit/nextjs/server/route";',
|
|
343
|
+
"",
|
|
344
|
+
"export default async function handler(req, res) {",
|
|
345
|
+
' const url = `http://${req.headers.host ?? "localhost"}${req.url ?? "/api/mdk"}`;',
|
|
346
|
+
" const request = new Request(url, {",
|
|
347
|
+
' method: req.method || "POST",',
|
|
348
|
+
" headers: req.headers,",
|
|
349
|
+
" body:",
|
|
350
|
+
' req.method === "GET" || req.method === "HEAD"',
|
|
351
|
+
" ? undefined",
|
|
352
|
+
' : typeof req.body === "string"',
|
|
353
|
+
" ? req.body",
|
|
354
|
+
" : JSON.stringify(req.body ?? {}),",
|
|
355
|
+
" });",
|
|
356
|
+
"",
|
|
357
|
+
" const response = await appRouteHandler(request);",
|
|
358
|
+
" res.status(response.status);",
|
|
359
|
+
" response.headers.forEach((value, key) => {",
|
|
360
|
+
" res.setHeader(key, value);",
|
|
361
|
+
" });",
|
|
362
|
+
" const body = await response.arrayBuffer();",
|
|
363
|
+
" res.send(Buffer.from(body));",
|
|
364
|
+
"}",
|
|
365
|
+
""
|
|
366
|
+
].join("\n");
|
|
367
|
+
}
|
|
368
|
+
function createPagesCheckoutContent(isTypeScript) {
|
|
369
|
+
if (isTypeScript) {
|
|
370
|
+
return [
|
|
371
|
+
'"use client";',
|
|
372
|
+
"",
|
|
373
|
+
'import { useRouter } from "next/router";',
|
|
374
|
+
'import { Checkout } from "@moneydevkit/nextjs";',
|
|
375
|
+
"",
|
|
376
|
+
"export default function CheckoutPage() {",
|
|
377
|
+
" const router = useRouter();",
|
|
378
|
+
" const id = Array.isArray(router.query.id)",
|
|
379
|
+
" ? router.query.id[0]",
|
|
380
|
+
" : router.query.id;",
|
|
381
|
+
"",
|
|
382
|
+
" if (!id) {",
|
|
383
|
+
" return null;",
|
|
384
|
+
" }",
|
|
385
|
+
"",
|
|
386
|
+
" return <Checkout id={id as string} />;",
|
|
387
|
+
"}",
|
|
388
|
+
""
|
|
389
|
+
].join("\n");
|
|
390
|
+
}
|
|
391
|
+
return [
|
|
392
|
+
'"use client";',
|
|
393
|
+
"",
|
|
394
|
+
'import { useRouter } from "next/router";',
|
|
395
|
+
'import { Checkout } from "@moneydevkit/nextjs";',
|
|
396
|
+
"",
|
|
397
|
+
"export default function CheckoutPage() {",
|
|
398
|
+
" const router = useRouter();",
|
|
399
|
+
" const id = Array.isArray(router.query.id)",
|
|
400
|
+
" ? router.query.id[0]",
|
|
401
|
+
" : router.query.id;",
|
|
402
|
+
"",
|
|
403
|
+
" if (!id) {",
|
|
404
|
+
" return null;",
|
|
405
|
+
" }",
|
|
406
|
+
"",
|
|
407
|
+
" return <Checkout id={id} />;",
|
|
408
|
+
"}",
|
|
409
|
+
""
|
|
410
|
+
].join("\n");
|
|
411
|
+
}
|
|
412
|
+
function isTypeScriptConfig(configPath) {
|
|
413
|
+
return configPath.endsWith(".ts") || configPath.endsWith(".mts");
|
|
414
|
+
}
|
|
415
|
+
function patchNextConfigTypes(source) {
|
|
416
|
+
let patched = source.replace(
|
|
417
|
+
/import\s+type\s+\{\s*NextConfig\s*\}\s+from\s+["']next["'];?\s*\n?/g,
|
|
418
|
+
""
|
|
419
|
+
);
|
|
420
|
+
patched = patched.replace(/:\s*NextConfig\b/g, ": NextConfigOverrides");
|
|
421
|
+
return patched;
|
|
422
|
+
}
|
|
423
|
+
function updateConfigFile(configPath) {
|
|
424
|
+
const isTs = isTypeScriptConfig(configPath);
|
|
425
|
+
const pluginImport = isTs ? 'import withMdkCheckout, { type NextConfigOverrides } from "@moneydevkit/nextjs/next-plugin";' : 'import withMdkCheckout from "@moneydevkit/nextjs/next-plugin";';
|
|
426
|
+
if (!import_node_fs4.default.existsSync(configPath)) {
|
|
427
|
+
const content = [
|
|
428
|
+
pluginImport,
|
|
429
|
+
"",
|
|
430
|
+
"// Wrap your existing Next.js config with withMdkCheckout to enable Money Dev Kit.",
|
|
431
|
+
"// Example: export default withMdkCheckout(yourConfig)",
|
|
432
|
+
isTs ? "const nextConfig: NextConfigOverrides = {};" : "const nextConfig = {};",
|
|
433
|
+
"",
|
|
434
|
+
"export default withMdkCheckout(nextConfig);",
|
|
435
|
+
""
|
|
436
|
+
].join("\n");
|
|
437
|
+
const writeResult = writeFileWithBackup(configPath, content);
|
|
438
|
+
return {
|
|
439
|
+
status: "created",
|
|
440
|
+
path: configPath,
|
|
441
|
+
backupPath: writeResult.status === "updated-with-backup" ? writeResult.backupPath : void 0
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
const original = readFileSafe(configPath) ?? "";
|
|
445
|
+
if (original.includes("@moneydevkit/nextjs/next-plugin") || original.includes("withMdkCheckout")) {
|
|
446
|
+
return { status: "skipped", path: configPath, reason: "already configured" };
|
|
447
|
+
}
|
|
448
|
+
if (original.includes("module.exports")) {
|
|
449
|
+
const re = /module\.exports\s*=\s*(\{[\s\S]*?\});?/;
|
|
450
|
+
const match = original.match(re);
|
|
451
|
+
if (match) {
|
|
452
|
+
const prefix = 'const withMdkCheckout = require("@moneydevkit/nextjs/next-plugin").default ?? require("@moneydevkit/nextjs/next-plugin");\n';
|
|
453
|
+
const replaced = original.replace(
|
|
454
|
+
re,
|
|
455
|
+
`module.exports = withMdkCheckout(${match[1]});`
|
|
456
|
+
);
|
|
457
|
+
const result = writeFileWithBackup(configPath, `${prefix}${replaced}`);
|
|
458
|
+
return {
|
|
459
|
+
status: "updated",
|
|
460
|
+
path: configPath,
|
|
461
|
+
backupPath: result.status === "updated-with-backup" ? result.backupPath : void 0
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
if (original.includes("export default")) {
|
|
466
|
+
const reDefaultObject = /export\s+default\s+(\{[\s\S]*?\});?/;
|
|
467
|
+
const objectMatch = original.match(reDefaultObject);
|
|
468
|
+
if (objectMatch) {
|
|
469
|
+
const content = [
|
|
470
|
+
pluginImport,
|
|
471
|
+
"",
|
|
472
|
+
isTs ? "const nextConfig: NextConfigOverrides = " + objectMatch[1] + ";" : "const nextConfig = " + objectMatch[1] + ";",
|
|
473
|
+
"",
|
|
474
|
+
"export default withMdkCheckout(nextConfig);",
|
|
475
|
+
""
|
|
476
|
+
].join("\n");
|
|
477
|
+
const writeResult = writeFileWithBackup(configPath, content);
|
|
478
|
+
return {
|
|
479
|
+
status: "updated",
|
|
480
|
+
path: configPath,
|
|
481
|
+
backupPath: writeResult.status === "updated-with-backup" ? writeResult.backupPath : void 0
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
const reNamed = /export\s+default\s+([a-zA-Z0-9_]+)\s*;?/;
|
|
485
|
+
const namedMatch = original.match(reNamed);
|
|
486
|
+
if (namedMatch) {
|
|
487
|
+
const name = namedMatch[1];
|
|
488
|
+
const patched = isTs && original.includes("NextConfig") ? patchNextConfigTypes(original) : original;
|
|
489
|
+
const lines = [
|
|
490
|
+
pluginImport,
|
|
491
|
+
patched.replace(reNamed, `export default withMdkCheckout(${name});`)
|
|
492
|
+
];
|
|
493
|
+
const writeResult = writeFileWithBackup(configPath, lines.join("\n"));
|
|
494
|
+
return {
|
|
495
|
+
status: "updated",
|
|
496
|
+
path: configPath,
|
|
497
|
+
backupPath: writeResult.status === "updated-with-backup" ? writeResult.backupPath : void 0
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return {
|
|
502
|
+
status: "skipped",
|
|
503
|
+
path: configPath,
|
|
504
|
+
reason: "unrecognized format; wrap your export with withMdkCheckout, e.g. export default withMdkCheckout(yourConfig)"
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
function scaffoldAppRouter(appDir, isTypeScript) {
|
|
508
|
+
const added = [];
|
|
509
|
+
const skipped = [];
|
|
510
|
+
const routePath = import_node_path5.default.join(
|
|
511
|
+
appDir,
|
|
512
|
+
"api",
|
|
513
|
+
"mdk",
|
|
514
|
+
`route.${isTypeScript ? "ts" : "js"}`
|
|
515
|
+
);
|
|
516
|
+
const routeResult = writeFileIfAbsent(
|
|
517
|
+
routePath,
|
|
518
|
+
createAppRouteContent(isTypeScript)
|
|
519
|
+
);
|
|
520
|
+
if (routeResult.status === "created") {
|
|
521
|
+
added.push(routeResult.path);
|
|
522
|
+
} else {
|
|
523
|
+
skipped.push(routeResult.path);
|
|
524
|
+
}
|
|
525
|
+
const pagePath = import_node_path5.default.join(
|
|
526
|
+
appDir,
|
|
527
|
+
"checkout",
|
|
528
|
+
"[id]",
|
|
529
|
+
`page.${isTypeScript ? "tsx" : "js"}`
|
|
530
|
+
);
|
|
531
|
+
const pageResult = writeFileIfAbsent(
|
|
532
|
+
pagePath,
|
|
533
|
+
createAppCheckoutPageContent(isTypeScript)
|
|
534
|
+
);
|
|
535
|
+
if (pageResult.status === "created") {
|
|
536
|
+
added.push(pageResult.path);
|
|
537
|
+
} else {
|
|
538
|
+
skipped.push(pageResult.path);
|
|
539
|
+
}
|
|
540
|
+
return { added, skipped };
|
|
541
|
+
}
|
|
542
|
+
function scaffoldPagesRouter(pagesDir, isTypeScript) {
|
|
543
|
+
const added = [];
|
|
544
|
+
const skipped = [];
|
|
545
|
+
const apiPath = import_node_path5.default.join(
|
|
546
|
+
pagesDir,
|
|
547
|
+
"api",
|
|
548
|
+
`mdk.${isTypeScript ? "ts" : "js"}`
|
|
549
|
+
);
|
|
550
|
+
const apiResult = writeFileIfAbsent(
|
|
551
|
+
apiPath,
|
|
552
|
+
createPagesApiRouteContent(isTypeScript)
|
|
553
|
+
);
|
|
554
|
+
if (apiResult.status === "created") {
|
|
555
|
+
added.push(apiResult.path);
|
|
556
|
+
} else {
|
|
557
|
+
skipped.push(apiResult.path);
|
|
558
|
+
}
|
|
559
|
+
const checkoutPath = import_node_path5.default.join(
|
|
560
|
+
pagesDir,
|
|
561
|
+
"checkout",
|
|
562
|
+
`[id].${isTypeScript ? "tsx" : "js"}`
|
|
563
|
+
);
|
|
564
|
+
const checkoutResult = writeFileIfAbsent(
|
|
565
|
+
checkoutPath,
|
|
566
|
+
createPagesCheckoutContent(isTypeScript)
|
|
567
|
+
);
|
|
568
|
+
if (checkoutResult.status === "created") {
|
|
569
|
+
added.push(checkoutResult.path);
|
|
570
|
+
} else {
|
|
571
|
+
skipped.push(checkoutResult.path);
|
|
572
|
+
}
|
|
573
|
+
return { added, skipped };
|
|
574
|
+
}
|
|
575
|
+
async function scaffoldNextJs(options) {
|
|
576
|
+
const { detection, jsonMode, skipInstall } = options;
|
|
577
|
+
if (!detection.rootDir) {
|
|
578
|
+
throw new Error("Next.js project root not found for scaffolding.");
|
|
579
|
+
}
|
|
580
|
+
const warnings = [];
|
|
581
|
+
const rootDir = detection.rootDir;
|
|
582
|
+
const packageManager = detectPackageManager(rootDir);
|
|
583
|
+
const installResult = skipInstall ? { installed: false, skipped: true } : await installNextjsPackage(rootDir, packageManager);
|
|
584
|
+
const configPath = findExistingConfig(rootDir, detection.nextConfigPath) ?? import_node_path5.default.join(rootDir, "next.config.js");
|
|
585
|
+
const configResult = updateConfigFile(configPath);
|
|
586
|
+
if (configResult.status === "skipped") {
|
|
587
|
+
warnings.push(
|
|
588
|
+
`Could not automatically update ${import_node_path5.default.basename(configPath)} (${configResult.reason}). Please wrap your Next.js config with withMdkCheckout manually.`
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
let fileResults;
|
|
592
|
+
if (detection.appDir) {
|
|
593
|
+
fileResults = scaffoldAppRouter(detection.appDir, detection.usesTypeScript);
|
|
594
|
+
} else if (detection.pagesDir) {
|
|
595
|
+
fileResults = scaffoldPagesRouter(
|
|
596
|
+
detection.pagesDir,
|
|
597
|
+
detection.usesTypeScript
|
|
598
|
+
);
|
|
599
|
+
} else {
|
|
600
|
+
fileResults = scaffoldAppRouter(
|
|
601
|
+
import_node_path5.default.join(rootDir, "app"),
|
|
602
|
+
detection.usesTypeScript
|
|
603
|
+
);
|
|
604
|
+
warnings.push(
|
|
605
|
+
"No app/ or pages/ directory detected; created App Router scaffolding in app/."
|
|
606
|
+
);
|
|
607
|
+
}
|
|
608
|
+
if (!jsonMode) {
|
|
609
|
+
if (!installResult.installed && installResult.skipped) {
|
|
610
|
+
console.log("@moneydevkit/nextjs already present; skipping install.");
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
return {
|
|
614
|
+
rootDir,
|
|
615
|
+
packageManager,
|
|
616
|
+
installedPackage: installResult.installed,
|
|
617
|
+
installSkipped: installResult.skipped,
|
|
618
|
+
addedFiles: fileResults.added,
|
|
619
|
+
skippedFiles: fileResults.skipped,
|
|
620
|
+
config: configResult,
|
|
621
|
+
warnings
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
|
|
75
625
|
// src/index.ts
|
|
76
626
|
var DEFAULT_BASE_URL = "https://moneydevkit.com";
|
|
77
627
|
var DEFAULT_ENV_FILE = ".env.local";
|
|
@@ -109,7 +659,7 @@ var CookieJar = class {
|
|
|
109
659
|
};
|
|
110
660
|
function parseFlags(argv) {
|
|
111
661
|
const result = (0, import_minimist.default)(argv, {
|
|
112
|
-
boolean: ["json", "no-clipboard", "no-open", "force-new-webhook", "
|
|
662
|
+
boolean: ["json", "no-clipboard", "no-open", "force-new-webhook", "scaffold-nextjs"],
|
|
113
663
|
string: [
|
|
114
664
|
"base-url",
|
|
115
665
|
"env-target",
|
|
@@ -125,14 +675,14 @@ function parseFlags(argv) {
|
|
|
125
675
|
"no-open": false,
|
|
126
676
|
json: false,
|
|
127
677
|
"force-new-webhook": false,
|
|
128
|
-
|
|
678
|
+
"scaffold-nextjs": false
|
|
129
679
|
}
|
|
130
680
|
});
|
|
131
681
|
return {
|
|
132
682
|
json: Boolean(result.json),
|
|
133
683
|
noClipboard: Boolean(result["no-clipboard"]),
|
|
134
684
|
noOpen: Boolean(result["no-open"]),
|
|
135
|
-
|
|
685
|
+
scaffoldNextjs: Boolean(result["scaffold-nextjs"]),
|
|
136
686
|
baseUrl: result["base-url"],
|
|
137
687
|
envFile: result["env-target"],
|
|
138
688
|
projectName: typeof result["project-name"] === "string" ? result["project-name"] : void 0,
|
|
@@ -142,20 +692,20 @@ function parseFlags(argv) {
|
|
|
142
692
|
};
|
|
143
693
|
}
|
|
144
694
|
function normalizeDirectory(dir) {
|
|
145
|
-
if (
|
|
146
|
-
return
|
|
695
|
+
if (import_node_path6.default.isAbsolute(dir)) return dir;
|
|
696
|
+
return import_node_path6.default.resolve(process.cwd(), dir);
|
|
147
697
|
}
|
|
148
698
|
function ensureDirectoryExists(dir) {
|
|
149
|
-
if (!
|
|
150
|
-
|
|
699
|
+
if (!import_node_fs5.default.existsSync(dir)) {
|
|
700
|
+
import_node_fs5.default.mkdirSync(dir, { recursive: true });
|
|
151
701
|
}
|
|
152
702
|
}
|
|
153
703
|
function readEnvFile(filePath) {
|
|
154
704
|
const env = /* @__PURE__ */ new Map();
|
|
155
|
-
if (!
|
|
705
|
+
if (!import_node_fs5.default.existsSync(filePath)) {
|
|
156
706
|
return env;
|
|
157
707
|
}
|
|
158
|
-
const contents =
|
|
708
|
+
const contents = import_node_fs5.default.readFileSync(filePath, "utf8");
|
|
159
709
|
for (const line of contents.split(/\r?\n/)) {
|
|
160
710
|
if (!line || line.startsWith("#")) continue;
|
|
161
711
|
const [key, ...rest] = line.split("=");
|
|
@@ -176,15 +726,24 @@ function writeEnvFile(filePath, existing, updates) {
|
|
|
176
726
|
existing.set(key, value);
|
|
177
727
|
}
|
|
178
728
|
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
|
-
|
|
729
|
+
import_node_fs5.default.writeFileSync(filePath, content, "utf8");
|
|
180
730
|
}
|
|
181
731
|
function ensureEnvFileExists(filePath) {
|
|
182
|
-
const dir =
|
|
732
|
+
const dir = import_node_path6.default.dirname(filePath);
|
|
183
733
|
ensureDirectoryExists(dir);
|
|
184
|
-
if (!
|
|
185
|
-
|
|
734
|
+
if (!import_node_fs5.default.existsSync(filePath)) {
|
|
735
|
+
import_node_fs5.default.writeFileSync(filePath, "", "utf8");
|
|
186
736
|
}
|
|
187
737
|
}
|
|
738
|
+
function resolveLocalEnvPath(options) {
|
|
739
|
+
const organization = options.organizationId?.trim();
|
|
740
|
+
const apiKey = options.apiKeyId?.trim();
|
|
741
|
+
if (!organization || !apiKey) {
|
|
742
|
+
return void 0;
|
|
743
|
+
}
|
|
744
|
+
const homeDir = import_node_os.default.homedir();
|
|
745
|
+
return import_node_path6.default.join(homeDir, ".mdk", organization, apiKey, ".env");
|
|
746
|
+
}
|
|
188
747
|
function isValidHttpUrl(value) {
|
|
189
748
|
if (!value) return false;
|
|
190
749
|
try {
|
|
@@ -376,7 +935,7 @@ async function main() {
|
|
|
376
935
|
}
|
|
377
936
|
envFile = envPrompt.trim() || DEFAULT_ENV_FILE;
|
|
378
937
|
}
|
|
379
|
-
const envPath =
|
|
938
|
+
const envPath = import_node_path6.default.join(projectDir, envFile);
|
|
380
939
|
const existingEnvValues = readEnvFile(envPath);
|
|
381
940
|
const mnemonicAlreadySet = existingEnvValues.get("MDK_MNEMONIC")?.trim();
|
|
382
941
|
if (mnemonicAlreadySet) {
|
|
@@ -427,6 +986,39 @@ async function main() {
|
|
|
427
986
|
projectName = namePrompt.trim() || void 0;
|
|
428
987
|
}
|
|
429
988
|
projectName = deriveProjectName(projectName, webhookUrl);
|
|
989
|
+
const nextJsDetection = detectNextJsProject(projectDir);
|
|
990
|
+
let shouldScaffoldNextJs = false;
|
|
991
|
+
if (flags.scaffoldNextjs) {
|
|
992
|
+
if (nextJsDetection.found) {
|
|
993
|
+
if (nextJsDetection.versionIsSupported) {
|
|
994
|
+
shouldScaffoldNextJs = true;
|
|
995
|
+
} else {
|
|
996
|
+
console.warn(
|
|
997
|
+
`Next.js version ${nextJsDetection.nextVersion ?? "unknown"} detected, but @moneydevkit/nextjs requires Next.js 15+. Skipping installation and scaffolding.`
|
|
998
|
+
);
|
|
999
|
+
}
|
|
1000
|
+
} else {
|
|
1001
|
+
console.warn(
|
|
1002
|
+
"No NextJS app found, skipping @moneydevkit/nextjs installation. Please install manually."
|
|
1003
|
+
);
|
|
1004
|
+
}
|
|
1005
|
+
} else if (!jsonMode && nextJsDetection.found) {
|
|
1006
|
+
if (!nextJsDetection.versionIsSupported) {
|
|
1007
|
+
console.warn(
|
|
1008
|
+
`Next.js version ${nextJsDetection.nextVersion ?? "unknown"} detected, but @moneydevkit/nextjs requires Next.js 15+. Skipping scaffolding prompt.`
|
|
1009
|
+
);
|
|
1010
|
+
} else {
|
|
1011
|
+
const scaffoldPrompt = await p.confirm({
|
|
1012
|
+
message: `Next.js application detected at ${nextJsDetection.rootDir ?? projectDir} (version ${nextJsDetection.nextVersion ?? "unknown"}). Install and scaffold @moneydevkit/nextjs?`,
|
|
1013
|
+
initialValue: true
|
|
1014
|
+
});
|
|
1015
|
+
if (p.isCancel(scaffoldPrompt)) {
|
|
1016
|
+
p.cancel("Aborted.");
|
|
1017
|
+
process.exit(1);
|
|
1018
|
+
}
|
|
1019
|
+
shouldScaffoldNextJs = Boolean(scaffoldPrompt);
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
430
1022
|
try {
|
|
431
1023
|
const result = await runDeviceFlow({
|
|
432
1024
|
flags,
|
|
@@ -444,6 +1036,15 @@ async function main() {
|
|
|
444
1036
|
const existingEnv = readEnvFile(envPath);
|
|
445
1037
|
const preview = renderEnvPreview(existingEnv, updates);
|
|
446
1038
|
writeEnvFile(envPath, existingEnv, updates);
|
|
1039
|
+
const localEnvPath = resolveLocalEnvPath({
|
|
1040
|
+
organizationId: result.credentials.organizationId,
|
|
1041
|
+
apiKeyId: result.credentials.apiKeyId
|
|
1042
|
+
});
|
|
1043
|
+
if (localEnvPath) {
|
|
1044
|
+
ensureEnvFileExists(localEnvPath);
|
|
1045
|
+
const localEnv = readEnvFile(localEnvPath);
|
|
1046
|
+
writeEnvFile(localEnvPath, localEnv, updates);
|
|
1047
|
+
}
|
|
447
1048
|
if (!jsonMode) {
|
|
448
1049
|
p.note(preview, "Env file updated");
|
|
449
1050
|
}
|
|
@@ -454,6 +1055,72 @@ async function main() {
|
|
|
454
1055
|
)
|
|
455
1056
|
);
|
|
456
1057
|
}
|
|
1058
|
+
let scaffoldSummary = null;
|
|
1059
|
+
if (shouldScaffoldNextJs && nextJsDetection.found) {
|
|
1060
|
+
try {
|
|
1061
|
+
scaffoldSummary = await scaffoldNextJs({
|
|
1062
|
+
detection: nextJsDetection,
|
|
1063
|
+
jsonMode
|
|
1064
|
+
});
|
|
1065
|
+
if (!jsonMode && scaffoldSummary) {
|
|
1066
|
+
const lines = [
|
|
1067
|
+
scaffoldSummary.installedPackage ? `Installed @moneydevkit/nextjs with ${scaffoldSummary.packageManager}.` : scaffoldSummary.installSkipped ? "@moneydevkit/nextjs already installed; skipped package install." : "Skipped @moneydevkit/nextjs installation."
|
|
1068
|
+
];
|
|
1069
|
+
if (scaffoldSummary.config) {
|
|
1070
|
+
const cfg = scaffoldSummary.config;
|
|
1071
|
+
if (cfg.status === "created") {
|
|
1072
|
+
lines.push(`Created ${cfg.path} with withMdkCheckout().`);
|
|
1073
|
+
if (cfg.backupPath) {
|
|
1074
|
+
lines.push(`Created backup at ${cfg.backupPath}.`);
|
|
1075
|
+
}
|
|
1076
|
+
} else if (cfg.status === "updated") {
|
|
1077
|
+
lines.push(`Updated ${cfg.path} with withMdkCheckout().`);
|
|
1078
|
+
if (cfg.backupPath) {
|
|
1079
|
+
lines.push(`Created backup at ${cfg.backupPath}.`);
|
|
1080
|
+
}
|
|
1081
|
+
} else {
|
|
1082
|
+
lines.push(
|
|
1083
|
+
`Could not update ${cfg.path} automatically (${cfg.reason ?? "unknown reason"}).`
|
|
1084
|
+
);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
if (scaffoldSummary.addedFiles.length > 0) {
|
|
1088
|
+
lines.push(
|
|
1089
|
+
`Added: ${scaffoldSummary.addedFiles.map((p2) => import_node_path6.default.relative(projectDir, p2)).join(", ")}`
|
|
1090
|
+
);
|
|
1091
|
+
}
|
|
1092
|
+
if (scaffoldSummary.skippedFiles.length > 0) {
|
|
1093
|
+
lines.push(
|
|
1094
|
+
`Skipped existing files: ${scaffoldSummary.skippedFiles.map((p2) => import_node_path6.default.relative(projectDir, p2)).join(", ")}`
|
|
1095
|
+
);
|
|
1096
|
+
}
|
|
1097
|
+
p.note(lines.join("\n"), "Next.js scaffolding");
|
|
1098
|
+
}
|
|
1099
|
+
if (scaffoldSummary?.warnings.length) {
|
|
1100
|
+
for (const warning of scaffoldSummary.warnings) {
|
|
1101
|
+
console.warn(warning);
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
} catch (error) {
|
|
1105
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1106
|
+
if (jsonMode) {
|
|
1107
|
+
console.error(
|
|
1108
|
+
JSON.stringify(
|
|
1109
|
+
{
|
|
1110
|
+
status: "error",
|
|
1111
|
+
error: {
|
|
1112
|
+
message: `Next.js scaffolding failed: ${message}`
|
|
1113
|
+
}
|
|
1114
|
+
},
|
|
1115
|
+
null,
|
|
1116
|
+
2
|
|
1117
|
+
)
|
|
1118
|
+
);
|
|
1119
|
+
} else {
|
|
1120
|
+
console.warn(`Next.js scaffolding failed: ${message}`);
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
457
1124
|
const summary = {
|
|
458
1125
|
projectDir,
|
|
459
1126
|
envFile: envPath,
|
|
@@ -461,7 +1128,8 @@ async function main() {
|
|
|
461
1128
|
webhookId: result.credentials.webhookId,
|
|
462
1129
|
organizationId: result.credentials.organizationId,
|
|
463
1130
|
webhookUrl: result.credentials.webhookUrl,
|
|
464
|
-
mnemonic: updates.MDK_MNEMONIC
|
|
1131
|
+
mnemonic: updates.MDK_MNEMONIC,
|
|
1132
|
+
scaffoldedNextjs: Boolean(scaffoldSummary)
|
|
465
1133
|
};
|
|
466
1134
|
if (jsonMode) {
|
|
467
1135
|
console.log(
|
|
@@ -476,7 +1144,8 @@ async function main() {
|
|
|
476
1144
|
webhookSecret: result.credentials.webhookSecret,
|
|
477
1145
|
webhookUrl: result.credentials.webhookUrl,
|
|
478
1146
|
organizationId: result.credentials.organizationId,
|
|
479
|
-
mnemonic: updates.MDK_MNEMONIC
|
|
1147
|
+
mnemonic: updates.MDK_MNEMONIC,
|
|
1148
|
+
scaffoldedNextjs: Boolean(scaffoldSummary)
|
|
480
1149
|
}
|
|
481
1150
|
},
|
|
482
1151
|
null,
|