@moneydevkit/create 0.3.3 → 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/README.md CHANGED
@@ -5,8 +5,8 @@ Developer onboarding CLI for Money Dev Kit. This package publishes the interacti
5
5
  ## Getting Started
6
6
 
7
7
  1. Run `npx @moneydevkit/create@latest` from the root of your project. The CLI walks you through login, webhook verification, and writes your secrets to `.env.local` (or a path you pick) while also copying them to the clipboard by default.
8
- 2. If we detect a Next.js app (package.json `next` dependency, `next.config.*`, or an `app/`/`pages/` directory), well offer to install and scaffold `@moneydevkit/nextjs` for you.
9
- 3. Follow the prompts. When you reach your editor again, `MDK_ACCESS_TOKEN`, `MDK_WEBHOOK_SECRET`, and `MDK_MNEMONIC` are ready to go.
8
+ 2. If we detect a Next.js app (package.json `next` dependency, `next.config.*`, or an `app/` directory), we'll offer to install and scaffold `@moneydevkit/nextjs` for you.
9
+ 3. Follow the prompts. When you reach your editor again, `MDK_ACCESS_TOKEN` and `MDK_MNEMONIC` are ready to go.
10
10
 
11
11
  ### Customize the flow with flags
12
12
 
@@ -16,7 +16,7 @@ Pass any of the options from the table below to skip prompts or run non-interact
16
16
  npx @moneydevkit/create@latest \
17
17
  --dir ./apps/storefront \
18
18
  --env-target .env.production \
19
- --webhook-url https://example.com/webhooks/mdk \
19
+ --webhook-url https://example.com \
20
20
  --project-name "Storefront" \
21
21
  --no-open --no-clipboard
22
22
  ```
@@ -41,9 +41,9 @@ The CLI still creates a device code but immediately authorises it using your coo
41
41
 
42
42
  ## Next.js scaffolding
43
43
 
44
- - Auto-detects Next.js via `package.json`, `next.config.*`, or `app/`/`pages/` directories. If found, youll be prompted to install and scaffold `@moneydevkit/nextjs`. Requires Next.js 15+ (per SDK peer deps).
44
+ - Auto-detects Next.js via `package.json`, `next.config.*`, or `app/` directory. If found, you'll be prompted to install and scaffold `@moneydevkit/nextjs`. Requires Next.js 15+ (per SDK peer deps).
45
45
  - `--scaffold-nextjs` forces the install/scaffold (useful for CI); if no Next.js app is found, the CLI prints a warning and skips.
46
- - Prefers the App Router (`app/api/mdk/route.(ts|js)` and `app/checkout/[id]/page.(tsx|js)`); falls back to the Pages Router paths when only `pages/` exists.
46
+ - Always scaffolds App Router files (`app/api/mdk/route.(ts|js)` and `app/checkout/[id]/page.(tsx|js)`).
47
47
  - Existing files are left untouched; `next.config.*` is backed up if we need to wrap it with `withMdkCheckout`.
48
48
 
49
49
  ## Flags
@@ -58,7 +58,7 @@ The CLI still creates a device code but immediately authorises it using your coo
58
58
  | `--no-clipboard` | Do not place secrets on the clipboard. |
59
59
  | `--json` | Emit JSON result payloads (no interactive prompts).
60
60
  | `--manual-login "<cookie>"` | Use a pre-generated dashboard session cookie instead of device flow. |
61
- | `--webhook-url "<url>"` | Provide the webhook URL when running in `--manual-login` or `--json` modes. |
61
+ | `--webhook-url "<url>"` | Provide the domain when running in `--manual-login` or `--json` modes. |
62
62
  | `--force-new-webhook` | Force creation of a new webhook even if one already exists for the URL. |
63
63
  | `--scaffold-nextjs` | Force install + scaffold `@moneydevkit/nextjs` (warns and skips if no Next.js app is detected). |
64
64
 
@@ -75,8 +75,25 @@ npm run run:local # talk to a dashboard at http://localhost:3900
75
75
 
76
76
  ## Releasing to npm
77
77
 
78
- 1. Bump the version in `packages/create/package.json` (for example: `npm version 0.2.0 --workspace packages/create --no-git-tag-version`) and commit the resulting `package-lock.json` change.
79
- 2. Push the commit, then create a GitHub release (or annotated tag) named `create-vX.Y.Z` that matches the new version string.
80
- 3. The `publish-create` workflow will detect that tag, run the build, and execute `npm publish packages/create --access public` using trusted publishing.
78
+ All `@moneydevkit/*` packages share a unified version number and are released together.
79
+
80
+ ### Beta releases (automatic)
81
+
82
+ Every push to `main` that modifies files in `packages/` triggers the `publish-beta` workflow:
83
+ 1. All packages are bumped to the next beta version (e.g., `0.4.0-beta.0` → `0.4.0-beta.1`)
84
+ 2. All packages are published to npm with the `beta` tag
85
+
86
+ Install the latest beta with:
87
+ ```bash
88
+ npx @moneydevkit/create@beta
89
+ npm install @moneydevkit/nextjs@beta
90
+ ```
91
+
92
+ ### Stable releases
93
+
94
+ 1. Create a GitHub release with a tag matching the version in package.json (e.g., if package.json has `0.4.0-beta.3`, create tag `v0.4.0`)
95
+ 2. The `publish-release` workflow validates, publishes, and bumps to the next minor version
81
96
 
82
97
  Once that workflow succeeds, `npx @moneydevkit/create@latest` automatically downloads the freshly published build.
98
+
99
+ See the [main README](../../README.md#releasing) for version flow examples and error cases.
package/dist/index.cjs CHANGED
@@ -234,6 +234,11 @@ function writeFileWithBackup(filePath, content) {
234
234
  }
235
235
 
236
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
+ }
237
242
  function findExistingConfig(rootDir, preferred) {
238
243
  if (preferred && import_node_fs4.default.existsSync(preferred)) return preferred;
239
244
  const candidates = [
@@ -276,138 +281,12 @@ async function installNextjsPackage(rootDir, packageManager) {
276
281
  return { installed: true, skipped: false };
277
282
  }
278
283
  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
+ return readTemplate(`app/api/mdk/route.${isTypeScript ? "ts" : "js"}`);
284
285
  }
285
286
  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");
287
+ return readTemplate(
288
+ `app/checkout/[id]/page.${isTypeScript ? "tsx" : "js"}`
289
+ );
411
290
  }
412
291
  function isTypeScriptConfig(configPath) {
413
292
  return configPath.endsWith(".ts") || configPath.endsWith(".mts");
@@ -539,39 +418,6 @@ function scaffoldAppRouter(appDir, isTypeScript) {
539
418
  }
540
419
  return { added, skipped };
541
420
  }
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
421
  async function scaffoldNextJs(options) {
576
422
  const { detection, jsonMode, skipInstall } = options;
577
423
  if (!detection.rootDir) {
@@ -588,21 +434,11 @@ async function scaffoldNextJs(options) {
588
434
  `Could not automatically update ${import_node_path5.default.basename(configPath)} (${configResult.reason}). Please wrap your Next.js config with withMdkCheckout manually.`
589
435
  );
590
436
  }
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
- );
437
+ const appDir = detection.appDir ?? import_node_path5.default.join(rootDir, "app");
438
+ const fileResults = scaffoldAppRouter(appDir, detection.usesTypeScript);
439
+ if (!detection.appDir) {
604
440
  warnings.push(
605
- "No app/ or pages/ directory detected; created App Router scaffolding in app/."
441
+ "No app/ directory detected; created App Router scaffolding in app/."
606
442
  );
607
443
  }
608
444
  if (!jsonMode) {
@@ -806,7 +642,7 @@ async function runDeviceFlow(options) {
806
642
  p.note(
807
643
  [
808
644
  `Device code: ${device.userCode}`,
809
- `Webhook URL: ${webhookUrl}`,
645
+ `Domain: ${webhookUrl}`,
810
646
  "Open the authorization page, click Authorize, then return to this terminal."
811
647
  ].join("\n"),
812
648
  "Authorize this device"
@@ -962,7 +798,7 @@ async function main() {
962
798
  }
963
799
  while (!webhookUrl) {
964
800
  const webhookInput = await p.text({
965
- message: "Webhook URL for your application",
801
+ message: "Domain for your application",
966
802
  initialValue: "https://",
967
803
  placeholder: "https://yourapp.com",
968
804
  validate: (value) => isValidHttpUrl(value?.trim()) ? void 0 : "Enter a valid http(s) URL (e.g. https://yourapp.com)"
@@ -1029,7 +865,6 @@ async function main() {
1029
865
  });
1030
866
  const updates = {
1031
867
  MDK_ACCESS_TOKEN: result.credentials.apiKey,
1032
- MDK_WEBHOOK_SECRET: result.credentials.webhookSecret,
1033
868
  MDK_MNEMONIC: result.mnemonic
1034
869
  };
1035
870
  ensureEnvFileExists(envPath);
@@ -1050,7 +885,7 @@ async function main() {
1050
885
  }
1051
886
  if (!flags.noClipboard) {
1052
887
  await import_clipboardy.default.write(
1053
- [`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(
1054
889
  "\n"
1055
890
  )
1056
891
  );