@moneydevkit/create 0.3.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 +66 -0
- package/dist/index.cjs +522 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +499 -0
- package/dist/index.js.map +1 -0
- package/package.json +64 -0
package/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# @moneydevkit/create
|
|
2
|
+
|
|
3
|
+
Developer onboarding CLI for Money Dev Kit. This package publishes the interactive `npx @moneydevkit/create` flow that provisions API keys, webhook secrets, and a Lightning mnemonic for local development.
|
|
4
|
+
|
|
5
|
+
## Local Development
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install
|
|
9
|
+
npm run dev # watch mode via tsup
|
|
10
|
+
npm run build # produce dist/ bundle + types
|
|
11
|
+
npm run run:local # talk to a dashboard at http://localhost:3900
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Releasing to npm
|
|
15
|
+
|
|
16
|
+
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.
|
|
17
|
+
2. Push the commit, then create a GitHub release (or annotated tag) named `create-vX.Y.Z` that matches the new version string.
|
|
18
|
+
3. The `publish-create` workflow will detect that tag, run the build, and execute `npm publish packages/create --access public` using the repo’s `NPM_TOKEN`.
|
|
19
|
+
|
|
20
|
+
Once that workflow succeeds, `npx @moneydevkit/create` automatically downloads the freshly published build.
|
|
21
|
+
|
|
22
|
+
## What the CLI does
|
|
23
|
+
|
|
24
|
+
1. Calls the MDK onboarding RPC to create a device/session code.
|
|
25
|
+
2. Launches the browser for sign-in (or prints the verification URL when `--no-open` or `--json` are supplied).
|
|
26
|
+
3. Polls until the dashboard authorises the device, then provisions an API key + webhook secret, and generates a mnemonic locally via BIP-39.
|
|
27
|
+
4. Shows an env diff, writes `.env.local` (or a user-specified file), and optionally copies secrets to the clipboard.
|
|
28
|
+
|
|
29
|
+
### Running headlessly (for LLMs/automation)
|
|
30
|
+
|
|
31
|
+
Manual mode still uses the device-auth flow—the only difference is that you reuse an *existing* dashboard session instead of waiting for a browser round trip. The steps are:
|
|
32
|
+
|
|
33
|
+
1. **Sign in via the dashboard UI** (browser) and keep the tab open.
|
|
34
|
+
2. **Copy the `better-auth.session_token` cookie** from your browser’s developer tools (Application → Storage → Cookies or the Network panel). Copy the full `name=value` pair.
|
|
35
|
+
3. **Pass that cookie to the CLI** using `--manual-login`. Example:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
SESSION_COOKIE='better-auth.session_token=eyJhbGciOiJI...'
|
|
39
|
+
|
|
40
|
+
npx @moneydevkit/create \
|
|
41
|
+
--base-url http://localhost:3900 \
|
|
42
|
+
--dir /tmp/mdk-demo \
|
|
43
|
+
--env-target .env.local \
|
|
44
|
+
--webhook-url https://example.com \
|
|
45
|
+
--manual-login "$SESSION_COOKIE" \
|
|
46
|
+
--json --no-open --no-clipboard
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The CLI still requests a device code, immediately authorises it using the provided cookie, and emits a JSON payload containing the secrets plus the env-file path—no username/password ever touch the terminal.
|
|
50
|
+
|
|
51
|
+
## Flags
|
|
52
|
+
|
|
53
|
+
| Flag | Description |
|
|
54
|
+
| ---- | ----------- |
|
|
55
|
+
| `--base-url` | Override dashboard base URL (default `https://moneydevkit.com`). |
|
|
56
|
+
| `--dir` | Target project directory (defaults to `cwd`). |
|
|
57
|
+
| `--env-target` | Env file name (default `.env.local`). |
|
|
58
|
+
| `--project-name` | Friendly name used when minting the API key. |
|
|
59
|
+
| `--no-open` | Skip auto-opening the browser; prints the verification URL instead. |
|
|
60
|
+
| `--no-clipboard` | Do not place secrets on the clipboard. |
|
|
61
|
+
| `--json` | Emit JSON result payloads (no interactive prompts).
|
|
62
|
+
| `--manual-login "<cookie>"` | Use a pre-generated dashboard session cookie instead of device flow. |
|
|
63
|
+
| `--webhook-url "<url>"` | Provide the webhook URL when running in `--manual-login` or `--json` modes. |
|
|
64
|
+
| `--force-new-webhook` | Force creation of a new webhook even if one already exists for the URL. |
|
|
65
|
+
|
|
66
|
+
Manual login mode calls `POST /api/cli/device/authorize` with the supplied session cookie. When used with `--json`, pass `--webhook-url` to avoid interactive prompts.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
#!/usr/bin/env -S node --
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
// src/index.ts
|
|
27
|
+
var import_client = require("@orpc/client");
|
|
28
|
+
var import_fetch = require("@orpc/client/fetch");
|
|
29
|
+
var p = __toESM(require("@clack/prompts"), 1);
|
|
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);
|
|
33
|
+
var import_node_os = __toESM(require("os"), 1);
|
|
34
|
+
var import_open = __toESM(require("open"), 1);
|
|
35
|
+
var import_clipboardy = __toESM(require("clipboardy"), 1);
|
|
36
|
+
var import_set_cookie_parser = __toESM(require("set-cookie-parser"), 1);
|
|
37
|
+
var import_bip39 = require("bip39");
|
|
38
|
+
var import_promises = require("timers/promises");
|
|
39
|
+
|
|
40
|
+
// src/utils/env-target.ts
|
|
41
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
42
|
+
function resolveEnvTarget(options) {
|
|
43
|
+
const { explicitTarget, overrideTarget, cwd, defaultFilename } = options;
|
|
44
|
+
const rawTarget = explicitTarget ?? overrideTarget ?? defaultFilename;
|
|
45
|
+
const hasPathSeparator = rawTarget.includes("/") || rawTarget.includes("\\");
|
|
46
|
+
let projectDir = cwd;
|
|
47
|
+
let envFile = import_node_path.default.basename(rawTarget);
|
|
48
|
+
let providedExplicitly = Boolean(explicitTarget);
|
|
49
|
+
if (import_node_path.default.isAbsolute(rawTarget)) {
|
|
50
|
+
projectDir = import_node_path.default.dirname(rawTarget);
|
|
51
|
+
envFile = import_node_path.default.basename(rawTarget);
|
|
52
|
+
providedExplicitly = true;
|
|
53
|
+
} else if (hasPathSeparator) {
|
|
54
|
+
const relativeDir = import_node_path.default.dirname(rawTarget);
|
|
55
|
+
if (relativeDir && relativeDir !== "." && relativeDir !== "") {
|
|
56
|
+
projectDir = import_node_path.default.resolve(cwd, relativeDir);
|
|
57
|
+
envFile = import_node_path.default.basename(rawTarget);
|
|
58
|
+
providedExplicitly = true;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
projectDir: import_node_path.default.resolve(projectDir),
|
|
63
|
+
envFile,
|
|
64
|
+
providedExplicitly
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function deriveProjectName(input, webhookUrl) {
|
|
68
|
+
const trimmed = input?.trim();
|
|
69
|
+
if (trimmed) {
|
|
70
|
+
return trimmed;
|
|
71
|
+
}
|
|
72
|
+
return webhookUrl;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// src/index.ts
|
|
76
|
+
var DEFAULT_BASE_URL = "https://moneydevkit.com";
|
|
77
|
+
var DEFAULT_ENV_FILE = ".env.local";
|
|
78
|
+
var CookieJar = class {
|
|
79
|
+
store = /* @__PURE__ */ new Map();
|
|
80
|
+
constructor(initial) {
|
|
81
|
+
if (initial) {
|
|
82
|
+
this.add(initial);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
add(input) {
|
|
86
|
+
const cookies = Array.isArray(input) ? input : [input];
|
|
87
|
+
for (const line of cookies) {
|
|
88
|
+
const trimmed = line.trim();
|
|
89
|
+
if (!trimmed) continue;
|
|
90
|
+
const parsed = import_set_cookie_parser.default.parse(trimmed);
|
|
91
|
+
const handle = (cookie) => {
|
|
92
|
+
if (cookie?.name && cookie.value !== void 0) {
|
|
93
|
+
this.store.set(cookie.name, cookie.value);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
if (Array.isArray(parsed)) {
|
|
97
|
+
for (const cookie of parsed) {
|
|
98
|
+
handle(cookie);
|
|
99
|
+
}
|
|
100
|
+
} else if (parsed && typeof parsed === "object") {
|
|
101
|
+
handle(parsed);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
header() {
|
|
106
|
+
if (this.store.size === 0) return void 0;
|
|
107
|
+
return Array.from(this.store.entries()).map(([name, value]) => `${name}=${value}`).join("; ");
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
function parseFlags(argv) {
|
|
111
|
+
const result = (0, import_minimist.default)(argv, {
|
|
112
|
+
boolean: ["json", "no-clipboard", "no-open", "force-new-webhook", "yes"],
|
|
113
|
+
string: [
|
|
114
|
+
"base-url",
|
|
115
|
+
"env-target",
|
|
116
|
+
"project-name",
|
|
117
|
+
"manual-login",
|
|
118
|
+
"webhook-url"
|
|
119
|
+
],
|
|
120
|
+
alias: {
|
|
121
|
+
json: "j"
|
|
122
|
+
},
|
|
123
|
+
default: {
|
|
124
|
+
"no-clipboard": false,
|
|
125
|
+
"no-open": false,
|
|
126
|
+
json: false,
|
|
127
|
+
"force-new-webhook": false,
|
|
128
|
+
yes: false
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
return {
|
|
132
|
+
json: Boolean(result.json),
|
|
133
|
+
noClipboard: Boolean(result["no-clipboard"]),
|
|
134
|
+
noOpen: Boolean(result["no-open"]),
|
|
135
|
+
yes: Boolean(result.yes),
|
|
136
|
+
baseUrl: result["base-url"],
|
|
137
|
+
envFile: result["env-target"],
|
|
138
|
+
projectName: typeof result["project-name"] === "string" ? result["project-name"] : void 0,
|
|
139
|
+
manualLogin: typeof result["manual-login"] === "string" ? result["manual-login"] : void 0,
|
|
140
|
+
forceNewWebhook: Boolean(result["force-new-webhook"]),
|
|
141
|
+
webhookUrl: typeof result["webhook-url"] === "string" ? result["webhook-url"] : void 0
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function normalizeDirectory(dir) {
|
|
145
|
+
if (import_node_path2.default.isAbsolute(dir)) return dir;
|
|
146
|
+
return import_node_path2.default.resolve(process.cwd(), dir);
|
|
147
|
+
}
|
|
148
|
+
function ensureDirectoryExists(dir) {
|
|
149
|
+
if (!import_node_fs.default.existsSync(dir)) {
|
|
150
|
+
import_node_fs.default.mkdirSync(dir, { recursive: true });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function readEnvFile(filePath) {
|
|
154
|
+
const env = /* @__PURE__ */ new Map();
|
|
155
|
+
if (!import_node_fs.default.existsSync(filePath)) {
|
|
156
|
+
return env;
|
|
157
|
+
}
|
|
158
|
+
const contents = import_node_fs.default.readFileSync(filePath, "utf8");
|
|
159
|
+
for (const line of contents.split(/\r?\n/)) {
|
|
160
|
+
if (!line || line.startsWith("#")) continue;
|
|
161
|
+
const [key, ...rest] = line.split("=");
|
|
162
|
+
if (!key) continue;
|
|
163
|
+
env.set(key.trim(), rest.join("=").trim());
|
|
164
|
+
}
|
|
165
|
+
return env;
|
|
166
|
+
}
|
|
167
|
+
function renderEnvPreview(_original, updates) {
|
|
168
|
+
const lines = ["Writing the following values:", ""];
|
|
169
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
170
|
+
lines.push(` ${key}=${value}`);
|
|
171
|
+
}
|
|
172
|
+
return lines.join("\n");
|
|
173
|
+
}
|
|
174
|
+
function writeEnvFile(filePath, existing, updates) {
|
|
175
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
176
|
+
existing.set(key, value);
|
|
177
|
+
}
|
|
178
|
+
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");
|
|
180
|
+
}
|
|
181
|
+
function ensureEnvFileExists(filePath) {
|
|
182
|
+
const dir = import_node_path2.default.dirname(filePath);
|
|
183
|
+
ensureDirectoryExists(dir);
|
|
184
|
+
if (!import_node_fs.default.existsSync(filePath)) {
|
|
185
|
+
import_node_fs.default.writeFileSync(filePath, "", "utf8");
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
function isValidHttpUrl(value) {
|
|
189
|
+
if (!value) return false;
|
|
190
|
+
try {
|
|
191
|
+
const parsed = new URL(value);
|
|
192
|
+
return parsed.protocol === "https:" || parsed.protocol === "http:";
|
|
193
|
+
} catch {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
function createRpcClient(baseUrl, jar) {
|
|
198
|
+
const link = new import_fetch.RPCLink({
|
|
199
|
+
url: `${baseUrl.replace(/\/$/, "")}/rpc`,
|
|
200
|
+
headers: () => {
|
|
201
|
+
const cookieHeader = jar.header();
|
|
202
|
+
return cookieHeader ? { Cookie: cookieHeader } : {};
|
|
203
|
+
},
|
|
204
|
+
fetch: async (input, init) => {
|
|
205
|
+
const response = await fetch(input, init);
|
|
206
|
+
const setCookie = response.headers.getSetCookie?.() ?? [];
|
|
207
|
+
if (setCookie.length > 0) {
|
|
208
|
+
jar.add(setCookie);
|
|
209
|
+
}
|
|
210
|
+
return response;
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
return (0, import_client.createORPCClient)(link);
|
|
214
|
+
}
|
|
215
|
+
async function runDeviceFlow(options) {
|
|
216
|
+
const client = createRpcClient(options.baseUrl, options.cookies);
|
|
217
|
+
const manualSessionCookie = options.flags.manualLogin;
|
|
218
|
+
const webhookUrl = options.webhookUrl;
|
|
219
|
+
const device = await client.onboarding.startDeviceAuth({
|
|
220
|
+
clientDisplayName: options.projectName,
|
|
221
|
+
webhookUrl,
|
|
222
|
+
forceNewWebhook: options.flags.forceNewWebhook
|
|
223
|
+
});
|
|
224
|
+
if (manualSessionCookie) {
|
|
225
|
+
const response = await fetch(
|
|
226
|
+
`${options.baseUrl.replace(/\/$/, "")}/api/cli/device/authorize`,
|
|
227
|
+
{
|
|
228
|
+
method: "POST",
|
|
229
|
+
headers: {
|
|
230
|
+
"Content-Type": "application/json",
|
|
231
|
+
Cookie: manualSessionCookie
|
|
232
|
+
},
|
|
233
|
+
body: JSON.stringify({
|
|
234
|
+
code: device.userCode,
|
|
235
|
+
forceNewWebhook: options.flags.forceNewWebhook ?? false
|
|
236
|
+
})
|
|
237
|
+
}
|
|
238
|
+
);
|
|
239
|
+
if (!response.ok) {
|
|
240
|
+
const body = await response.json().catch(() => ({}));
|
|
241
|
+
throw new Error(
|
|
242
|
+
body.error ?? `Manual authorize failed with status ${response.status}`
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
} else {
|
|
246
|
+
if (!options.flags.json) {
|
|
247
|
+
p.note(
|
|
248
|
+
[
|
|
249
|
+
`Device code: ${device.userCode}`,
|
|
250
|
+
`Webhook URL: ${webhookUrl}`,
|
|
251
|
+
"Open the authorization page, click Authorize, then return to this terminal."
|
|
252
|
+
].join("\n"),
|
|
253
|
+
"Authorize this device"
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
if (!options.flags.noOpen && !options.flags.json) {
|
|
257
|
+
try {
|
|
258
|
+
await (0, import_open.default)(device.verificationUri, { wait: false });
|
|
259
|
+
} catch (error) {
|
|
260
|
+
console.warn(
|
|
261
|
+
`Unable to open browser automatically (${error.message}).`
|
|
262
|
+
);
|
|
263
|
+
console.warn(`Open this URL manually: ${device.verificationUri}`);
|
|
264
|
+
}
|
|
265
|
+
} else if (!options.flags.json) {
|
|
266
|
+
console.log(`Open this URL in your browser: ${device.verificationUri}`);
|
|
267
|
+
}
|
|
268
|
+
const spinner2 = options.flags.json ? null : p.spinner();
|
|
269
|
+
spinner2?.start("Waiting for authorization...");
|
|
270
|
+
const deadline = Date.now() + device.expiresIn * 1e3;
|
|
271
|
+
let bootstrapToken;
|
|
272
|
+
while (Date.now() < deadline) {
|
|
273
|
+
const poll = await client.onboarding.pollDeviceAuth({
|
|
274
|
+
deviceCode: device.deviceCode
|
|
275
|
+
});
|
|
276
|
+
if (poll.status === "authorized") {
|
|
277
|
+
bootstrapToken = poll.bootstrapToken;
|
|
278
|
+
spinner2?.stop("Device authorized.");
|
|
279
|
+
break;
|
|
280
|
+
}
|
|
281
|
+
if (poll.status === "expired") {
|
|
282
|
+
spinner2?.stop("Device code expired.");
|
|
283
|
+
throw new Error("Device code expired before authorization.");
|
|
284
|
+
}
|
|
285
|
+
if (poll.status === "denied") {
|
|
286
|
+
spinner2?.stop("Authorization denied.");
|
|
287
|
+
throw new Error("Authorization was denied in the dashboard.");
|
|
288
|
+
}
|
|
289
|
+
const secondsLeft = Math.max(
|
|
290
|
+
0,
|
|
291
|
+
Math.floor((deadline - Date.now()) / 1e3)
|
|
292
|
+
);
|
|
293
|
+
spinner2?.message(
|
|
294
|
+
`Waiting for authorization (${secondsLeft}s remaining)`
|
|
295
|
+
);
|
|
296
|
+
await (0, import_promises.setTimeout)(device.interval * 1e3);
|
|
297
|
+
}
|
|
298
|
+
if (!bootstrapToken) {
|
|
299
|
+
throw new Error("Timed out waiting for authorization.");
|
|
300
|
+
}
|
|
301
|
+
const credentials2 = await client.onboarding.bootstrap({
|
|
302
|
+
bootstrapToken,
|
|
303
|
+
projectName: options.projectName,
|
|
304
|
+
webhookUrl,
|
|
305
|
+
forceNewWebhook: options.flags.forceNewWebhook
|
|
306
|
+
});
|
|
307
|
+
const mnemonic2 = (0, import_bip39.generateMnemonic)(128);
|
|
308
|
+
return {
|
|
309
|
+
device,
|
|
310
|
+
bootstrapToken,
|
|
311
|
+
credentials: credentials2,
|
|
312
|
+
mnemonic: mnemonic2
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
const pollResult = await client.onboarding.pollDeviceAuth({
|
|
316
|
+
deviceCode: device.deviceCode
|
|
317
|
+
});
|
|
318
|
+
if (pollResult.status !== "authorized") {
|
|
319
|
+
throw new Error(
|
|
320
|
+
`Unable to obtain bootstrap token (status: ${pollResult.status}).`
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
const credentials = await client.onboarding.bootstrap({
|
|
324
|
+
bootstrapToken: pollResult.bootstrapToken,
|
|
325
|
+
projectName: options.projectName,
|
|
326
|
+
webhookUrl,
|
|
327
|
+
forceNewWebhook: options.flags.forceNewWebhook
|
|
328
|
+
});
|
|
329
|
+
const mnemonic = (0, import_bip39.generateMnemonic)(128);
|
|
330
|
+
return {
|
|
331
|
+
device,
|
|
332
|
+
bootstrapToken: pollResult.bootstrapToken,
|
|
333
|
+
credentials,
|
|
334
|
+
mnemonic
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
async function main() {
|
|
338
|
+
const flags = parseFlags(process.argv.slice(2));
|
|
339
|
+
const jsonMode = flags.json;
|
|
340
|
+
if (!jsonMode) {
|
|
341
|
+
p.intro("Money Dev Kit \u2013 @moneydevkit/create");
|
|
342
|
+
}
|
|
343
|
+
const baseUrl = flags.baseUrl ?? DEFAULT_BASE_URL;
|
|
344
|
+
const cookies = new CookieJar(flags.manualLogin);
|
|
345
|
+
const envFileOverride = process.env.MDK_ENV_FILE;
|
|
346
|
+
const envResolution = resolveEnvTarget({
|
|
347
|
+
explicitTarget: flags.envFile,
|
|
348
|
+
overrideTarget: envFileOverride,
|
|
349
|
+
cwd: process.cwd(),
|
|
350
|
+
defaultFilename: DEFAULT_ENV_FILE
|
|
351
|
+
});
|
|
352
|
+
const { providedExplicitly } = envResolution;
|
|
353
|
+
let projectDir = envResolution.projectDir;
|
|
354
|
+
let envFile = envResolution.envFile;
|
|
355
|
+
if (!providedExplicitly && !jsonMode && !flags.envFile) {
|
|
356
|
+
const dirPrompt = await p.text({
|
|
357
|
+
message: "Where should we store your MDK credentials?",
|
|
358
|
+
initialValue: projectDir
|
|
359
|
+
});
|
|
360
|
+
if (p.isCancel(dirPrompt)) {
|
|
361
|
+
p.cancel("Aborted.");
|
|
362
|
+
process.exit(1);
|
|
363
|
+
}
|
|
364
|
+
projectDir = dirPrompt;
|
|
365
|
+
}
|
|
366
|
+
projectDir = normalizeDirectory(projectDir);
|
|
367
|
+
ensureDirectoryExists(projectDir);
|
|
368
|
+
if (!flags.envFile && !envFileOverride && !jsonMode) {
|
|
369
|
+
const envPrompt = await p.text({
|
|
370
|
+
message: "Env file to update",
|
|
371
|
+
initialValue: envFile
|
|
372
|
+
});
|
|
373
|
+
if (p.isCancel(envPrompt)) {
|
|
374
|
+
p.cancel("Aborted.");
|
|
375
|
+
process.exit(1);
|
|
376
|
+
}
|
|
377
|
+
envFile = envPrompt.trim() || DEFAULT_ENV_FILE;
|
|
378
|
+
}
|
|
379
|
+
const envPath = import_node_path2.default.join(projectDir, envFile);
|
|
380
|
+
const existingEnvValues = readEnvFile(envPath);
|
|
381
|
+
const mnemonicAlreadySet = existingEnvValues.get("MDK_MNEMONIC")?.trim();
|
|
382
|
+
if (mnemonicAlreadySet) {
|
|
383
|
+
const warningMessage = "We found MDK_MNEMONIC already set in your project. Your mnemonic is the key to your wallet. If you've already deployed and taken payments with this mnemonic and change it, you will lose access to your funds. If you want to generate a new mnemonic, delete MDK_MNEMONIC from your .env and try again.";
|
|
384
|
+
if (jsonMode) {
|
|
385
|
+
console.error(
|
|
386
|
+
JSON.stringify(
|
|
387
|
+
{
|
|
388
|
+
status: "error",
|
|
389
|
+
error: { message: warningMessage }
|
|
390
|
+
},
|
|
391
|
+
null,
|
|
392
|
+
2
|
|
393
|
+
)
|
|
394
|
+
);
|
|
395
|
+
} else {
|
|
396
|
+
p.cancel(warningMessage);
|
|
397
|
+
}
|
|
398
|
+
process.exit(1);
|
|
399
|
+
}
|
|
400
|
+
let webhookUrl = flags.webhookUrl?.trim();
|
|
401
|
+
if ((!webhookUrl || !isValidHttpUrl(webhookUrl)) && jsonMode) {
|
|
402
|
+
throw new Error("Provide a valid --webhook-url when running in --json mode.");
|
|
403
|
+
}
|
|
404
|
+
while (!webhookUrl) {
|
|
405
|
+
const webhookInput = await p.text({
|
|
406
|
+
message: "Webhook URL for your application",
|
|
407
|
+
initialValue: "https://",
|
|
408
|
+
placeholder: "https://yourapp.com",
|
|
409
|
+
validate: (value) => isValidHttpUrl(value?.trim()) ? void 0 : "Enter a valid http(s) URL (e.g. https://yourapp.com)"
|
|
410
|
+
});
|
|
411
|
+
if (p.isCancel(webhookInput)) {
|
|
412
|
+
p.cancel("Aborted.");
|
|
413
|
+
process.exit(1);
|
|
414
|
+
}
|
|
415
|
+
webhookUrl = webhookInput.trim();
|
|
416
|
+
}
|
|
417
|
+
let projectName = flags.projectName?.trim();
|
|
418
|
+
if (!projectName && !jsonMode) {
|
|
419
|
+
const namePrompt = await p.text({
|
|
420
|
+
message: "Project name (used for the generated API key)",
|
|
421
|
+
placeholder: "Optional: e.g. My Next.js Store"
|
|
422
|
+
});
|
|
423
|
+
if (p.isCancel(namePrompt)) {
|
|
424
|
+
p.cancel("Aborted.");
|
|
425
|
+
process.exit(1);
|
|
426
|
+
}
|
|
427
|
+
projectName = namePrompt.trim() || void 0;
|
|
428
|
+
}
|
|
429
|
+
projectName = deriveProjectName(projectName, webhookUrl);
|
|
430
|
+
try {
|
|
431
|
+
const result = await runDeviceFlow({
|
|
432
|
+
flags,
|
|
433
|
+
baseUrl,
|
|
434
|
+
cookies,
|
|
435
|
+
projectName,
|
|
436
|
+
webhookUrl
|
|
437
|
+
});
|
|
438
|
+
const updates = {
|
|
439
|
+
MDK_ACCESS_TOKEN: result.credentials.apiKey,
|
|
440
|
+
MDK_WEBHOOK_SECRET: result.credentials.webhookSecret,
|
|
441
|
+
MDK_MNEMONIC: result.mnemonic
|
|
442
|
+
};
|
|
443
|
+
ensureEnvFileExists(envPath);
|
|
444
|
+
const existingEnv = readEnvFile(envPath);
|
|
445
|
+
const preview = renderEnvPreview(existingEnv, updates);
|
|
446
|
+
writeEnvFile(envPath, existingEnv, updates);
|
|
447
|
+
if (!jsonMode) {
|
|
448
|
+
p.note(preview, "Env file updated");
|
|
449
|
+
}
|
|
450
|
+
if (!flags.noClipboard) {
|
|
451
|
+
await import_clipboardy.default.write(
|
|
452
|
+
[`MDK_ACCESS_TOKEN=${updates.MDK_ACCESS_TOKEN}`, `MDK_WEBHOOK_SECRET=${updates.MDK_WEBHOOK_SECRET}`, `MDK_MNEMONIC=${updates.MDK_MNEMONIC}`].join(
|
|
453
|
+
"\n"
|
|
454
|
+
)
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
const summary = {
|
|
458
|
+
projectDir,
|
|
459
|
+
envFile: envPath,
|
|
460
|
+
apiKeyPreview: result.credentials.apiKeyPreview,
|
|
461
|
+
webhookId: result.credentials.webhookId,
|
|
462
|
+
organizationId: result.credentials.organizationId,
|
|
463
|
+
webhookUrl: result.credentials.webhookUrl,
|
|
464
|
+
mnemonic: updates.MDK_MNEMONIC
|
|
465
|
+
};
|
|
466
|
+
if (jsonMode) {
|
|
467
|
+
console.log(
|
|
468
|
+
JSON.stringify(
|
|
469
|
+
{
|
|
470
|
+
status: "success",
|
|
471
|
+
data: {
|
|
472
|
+
envFile: envPath,
|
|
473
|
+
apiKeyId: result.credentials.apiKeyId,
|
|
474
|
+
apiKeyPreview: result.credentials.apiKeyPreview,
|
|
475
|
+
webhookId: result.credentials.webhookId,
|
|
476
|
+
webhookSecret: result.credentials.webhookSecret,
|
|
477
|
+
webhookUrl: result.credentials.webhookUrl,
|
|
478
|
+
organizationId: result.credentials.organizationId,
|
|
479
|
+
mnemonic: updates.MDK_MNEMONIC
|
|
480
|
+
}
|
|
481
|
+
},
|
|
482
|
+
null,
|
|
483
|
+
2
|
|
484
|
+
)
|
|
485
|
+
);
|
|
486
|
+
} else {
|
|
487
|
+
p.outro(
|
|
488
|
+
[
|
|
489
|
+
"Authorized successfully!",
|
|
490
|
+
`\u2022 Credentials written to ${envPath}`,
|
|
491
|
+
`\u2022 Webhook ID: ${result.credentials.webhookId}`,
|
|
492
|
+
`\u2022 Organization: ${result.credentials.organizationId}`,
|
|
493
|
+
flags.noClipboard ? "Clipboard copy skipped (--no-clipboard)." : "Secrets copied to clipboard.",
|
|
494
|
+
"Return to your project and continue development."
|
|
495
|
+
].join("\n")
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
return summary;
|
|
499
|
+
} catch (error) {
|
|
500
|
+
if (jsonMode) {
|
|
501
|
+
console.error(
|
|
502
|
+
JSON.stringify(
|
|
503
|
+
{
|
|
504
|
+
status: "error",
|
|
505
|
+
error: {
|
|
506
|
+
message: error instanceof Error ? error.message : String(error)
|
|
507
|
+
}
|
|
508
|
+
},
|
|
509
|
+
null,
|
|
510
|
+
2
|
|
511
|
+
)
|
|
512
|
+
);
|
|
513
|
+
} else {
|
|
514
|
+
p.cancel(
|
|
515
|
+
error instanceof Error ? error.message : `Unexpected error: ${error}`
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
process.exit(1);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
void main();
|
|
522
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/utils/env-target.ts"],"sourcesContent":["import { createORPCClient } from \"@orpc/client\";\nimport { RPCLink } from \"@orpc/client/fetch\";\nimport * as p from \"@clack/prompts\";\nimport minimist from \"minimist\";\nimport path from \"node:path\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport open from \"open\";\nimport clipboard from \"clipboardy\";\nimport setCookieParser, { Cookie } from \"set-cookie-parser\";\nimport { generateMnemonic as generateBip39Mnemonic } from \"bip39\";\nimport { contract } from \"@moneydevkit/api-contract\";\nimport type { ContractRouterClient } from \"@orpc/contract\";\nimport type {\n\tBootstrapOnboardingResponse,\n\tStartDeviceAuthResponse,\n} from \"@moneydevkit/api-contract\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport { deriveProjectName, resolveEnvTarget } from \"./utils/env-target.js\";\n\ntype Flags = {\n\tjson: boolean;\n\tnoClipboard: boolean;\n\tnoOpen: boolean;\n\tyes: boolean;\n\tbaseUrl?: string;\n\tenvFile?: string;\n\tprojectName?: string;\n\tmanualLogin?: string;\n\tforceNewWebhook?: boolean;\n\twebhookUrl?: string;\n};\n\nconst DEFAULT_BASE_URL = \"https://moneydevkit.com\";\nconst DEFAULT_ENV_FILE = \".env.local\";\n\nclass CookieJar {\n\tprivate store = new Map<string, string>();\n\n\tconstructor(initial?: string) {\n\t\tif (initial) {\n\t\t\tthis.add(initial);\n\t\t}\n\t}\n\n\tadd(input: string | string[]) {\n\t\tconst cookies = Array.isArray(input) ? input : [input];\n\t\tfor (const line of cookies) {\n\t\t\tconst trimmed = line.trim();\n\t\t\tif (!trimmed) continue;\n\t\t\tconst parsed = setCookieParser.parse(trimmed);\n\t\t\tconst handle = (cookie: Cookie) => {\n\t\t\t\tif (cookie?.name && cookie.value !== undefined) {\n\t\t\t\t\tthis.store.set(cookie.name, cookie.value);\n\t\t\t\t}\n\t\t\t};\n\t\t\tif (Array.isArray(parsed)) {\n\t\t\t\tfor (const cookie of parsed) {\n\t\t\t\t\thandle(cookie);\n\t\t\t\t}\n\t\t\t} else if (parsed && typeof parsed === \"object\") {\n\t\t\t\thandle(parsed);\n\t\t\t}\n\t\t}\n\t}\n\n\theader(): string | undefined {\n\t\tif (this.store.size === 0) return undefined;\n\t\treturn Array.from(this.store.entries())\n\t\t\t.map(([name, value]) => `${name}=${value}`)\n\t\t\t.join(\"; \");\n\t}\n}\n\nfunction parseFlags(argv: string[]): Flags {\n\tconst result = minimist(argv, {\n\t\tboolean: [\"json\", \"no-clipboard\", \"no-open\", \"force-new-webhook\", \"yes\"],\n\t\tstring: [\n\t\t\t\"base-url\",\n\t\t\t\"env-target\",\n\t\t\t\"project-name\",\n\t\t\t\"manual-login\",\n\t\t\t\"webhook-url\",\n\t\t],\n\t\talias: {\n\t\t\tjson: \"j\",\n\t\t},\n\t\tdefault: {\n\t\t\t\"no-clipboard\": false,\n\t\t\t\"no-open\": false,\n\t\t\tjson: false,\n\t\t\t\"force-new-webhook\": false,\n\t\t\tyes: false,\n\t\t},\n\t});\n\nreturn {\n\tjson: Boolean(result.json),\n\tnoClipboard: Boolean(result[\"no-clipboard\"]),\n\tnoOpen: Boolean(result[\"no-open\"]),\n\tyes: Boolean(result.yes),\n\tbaseUrl: result[\"base-url\"],\n\tenvFile: result[\"env-target\"],\n\t\tprojectName:\n\t\t\ttypeof result[\"project-name\"] === \"string\"\n\t\t\t\t? result[\"project-name\"]\n\t\t\t\t: undefined,\n\t\tmanualLogin:\n\t\t\ttypeof result[\"manual-login\"] === \"string\"\n\t\t\t\t? result[\"manual-login\"]\n\t\t\t\t: undefined,\n\t\tforceNewWebhook: Boolean(result[\"force-new-webhook\"]),\n\t\twebhookUrl:\n\t\t\ttypeof result[\"webhook-url\"] === \"string\"\n\t\t\t\t? result[\"webhook-url\"]\n\t\t\t\t: undefined,\n\t};\n}\n\nfunction normalizeDirectory(dir: string): string {\n\tif (path.isAbsolute(dir)) return dir;\n\treturn path.resolve(process.cwd(), dir);\n}\n\nfunction ensureDirectoryExists(dir: string) {\n\tif (!fs.existsSync(dir)) {\n\t\tfs.mkdirSync(dir, { recursive: true });\n\t}\n}\n\nfunction readEnvFile(filePath: string): Map<string, string> {\n\tconst env = new Map<string, string>();\n\tif (!fs.existsSync(filePath)) {\n\t\treturn env;\n\t}\n\tconst contents = fs.readFileSync(filePath, \"utf8\");\n\tfor (const line of contents.split(/\\r?\\n/)) {\n\t\tif (!line || line.startsWith(\"#\")) continue;\n\t\tconst [key, ...rest] = line.split(\"=\");\n\t\tif (!key) continue;\n\t\tenv.set(key.trim(), rest.join(\"=\").trim());\n\t}\n\treturn env;\n}\n\nfunction renderEnvPreview(\n\t_original: Map<string, string>,\n\tupdates: Record<string, string>,\n): string {\n\tconst lines: string[] = [\"Writing the following values:\", \"\"];\n\tfor (const [key, value] of Object.entries(updates)) {\n\t\tlines.push(` ${key}=${value}`);\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nfunction writeEnvFile(\n\tfilePath: string,\n\texisting: Map<string, string>,\n\tupdates: Record<string, string>,\n) {\n\tfor (const [key, value] of Object.entries(updates)) {\n\t\texisting.set(key, value);\n\t}\n\tconst content =\n\t\tArray.from(existing.entries())\n\t\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t\t.map(([key, value]) => `${key}=${value}`)\n\t\t\t.join(os.EOL) + os.EOL;\n\tfs.writeFileSync(filePath, content, \"utf8\");\n}\n\nfunction ensureEnvFileExists(filePath: string) {\n\tconst dir = path.dirname(filePath);\n\tensureDirectoryExists(dir);\n\tif (!fs.existsSync(filePath)) {\n\t\tfs.writeFileSync(filePath, \"\", \"utf8\");\n\t}\n}\n\nfunction isValidHttpUrl(value?: string): boolean {\n\tif (!value) return false;\n\ttry {\n\t\tconst parsed = new URL(value);\n\t\treturn parsed.protocol === \"https:\" || parsed.protocol === \"http:\";\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction createRpcClient(\n\tbaseUrl: string,\n\tjar: CookieJar,\n): ContractRouterClient<typeof contract> {\n\tconst link = new RPCLink({\n\t\turl: `${baseUrl.replace(/\\/$/, \"\")}/rpc`,\n\t\theaders: () => {\n\t\t\tconst cookieHeader = jar.header();\n\t\t\treturn cookieHeader ? { Cookie: cookieHeader } : {};\n\t\t},\n\t\tfetch: async (input, init) => {\n\t\t\tconst response = await fetch(input, init);\n\t\t\tconst setCookie = response.headers.getSetCookie?.() ?? [];\n\t\t\tif (setCookie.length > 0) {\n\t\t\t\tjar.add(setCookie);\n\t\t\t}\n\t\t\treturn response;\n\t\t},\n\t});\n\n\treturn createORPCClient(link) as ContractRouterClient<typeof contract>;\n}\n\nasync function runDeviceFlow(options: {\n\tflags: Flags;\n\tbaseUrl: string;\n\tcookies: CookieJar;\n\tprojectName?: string;\n\twebhookUrl: string;\n}): Promise<{\n\tdevice: StartDeviceAuthResponse;\n\tbootstrapToken: string;\n\tcredentials: BootstrapOnboardingResponse;\n\tmnemonic: string;\n}> {\n\tconst client = createRpcClient(options.baseUrl, options.cookies);\nconst manualSessionCookie = options.flags.manualLogin;\nconst webhookUrl = options.webhookUrl;\n\nconst device = await client.onboarding.startDeviceAuth({\n clientDisplayName: options.projectName,\n webhookUrl,\n forceNewWebhook: options.flags.forceNewWebhook,\n});\n\n\tif (manualSessionCookie) {\n\t\tconst response = await fetch(\n\t\t\t`${options.baseUrl.replace(/\\/$/, \"\")}/api/cli/device/authorize`,\n\t\t\t{\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\tCookie: manualSessionCookie,\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tcode: device.userCode,\n\t\t\t\t\tforceNewWebhook: options.flags.forceNewWebhook ?? false,\n\t\t\t\t}),\n\t\t\t},\n\t\t);\n\n\t\tif (!response.ok) {\n\t\t\tconst body = (await response.json().catch(() => ({}))) as {\n\t\t\t\terror?: string;\n\t\t\t};\n\t\t\tthrow new Error(\n\t\t\t\tbody.error ??\n\t\t\t\t\t`Manual authorize failed with status ${response.status}`,\n\t\t\t);\n\t\t}\n\t} else {\n if (!options.flags.json) {\n p.note(\n [\n `Device code: ${device.userCode}`,\n `Webhook URL: ${webhookUrl}`,\n \"Open the authorization page, click Authorize, then return to this terminal.\",\n ].join(\"\\n\"),\n \"Authorize this device\",\n );\n }\n\n\t\tif (!options.flags.noOpen && !options.flags.json) {\n\t\t\ttry {\n\t\t\t\tawait open(device.verificationUri, { wait: false });\n\t\t\t} catch (error) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`Unable to open browser automatically (${(error as Error).message}).`,\n\t\t\t\t);\n\t\t\t\tconsole.warn(`Open this URL manually: ${device.verificationUri}`);\n\t\t\t}\n\t\t} else if (!options.flags.json) {\n\t\t\tconsole.log(`Open this URL in your browser: ${device.verificationUri}`);\n\t\t}\n\n\t\tconst spinner = options.flags.json ? null : p.spinner();\n\t\tspinner?.start(\"Waiting for authorization...\");\n\n\t\tconst deadline = Date.now() + device.expiresIn * 1000;\n\t\tlet bootstrapToken: string | undefined;\n\n\t\twhile (Date.now() < deadline) {\n\t\t\tconst poll = await client.onboarding.pollDeviceAuth({\n\t\t\t\tdeviceCode: device.deviceCode,\n\t\t\t});\n\n\t\t\tif (poll.status === \"authorized\") {\n\t\t\t\tbootstrapToken = poll.bootstrapToken;\n\t\t\t\tspinner?.stop(\"Device authorized.\");\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (poll.status === \"expired\") {\n\t\t\t\tspinner?.stop(\"Device code expired.\");\n\t\t\t\tthrow new Error(\"Device code expired before authorization.\");\n\t\t\t}\n\n\t\t\tif (poll.status === \"denied\") {\n\t\t\t\tspinner?.stop(\"Authorization denied.\");\n\t\t\t\tthrow new Error(\"Authorization was denied in the dashboard.\");\n\t\t\t}\n\n const secondsLeft = Math.max(\n 0,\n Math.floor((deadline - Date.now()) / 1000),\n );\n spinner?.message(\n `Waiting for authorization (${secondsLeft}s remaining)`,\n\t\t\t);\n\t\t\tawait delay(device.interval * 1000);\n\t\t}\n\n\t\tif (!bootstrapToken) {\n\t\t\tthrow new Error(\"Timed out waiting for authorization.\");\n\t\t}\n\n const credentials = await client.onboarding.bootstrap({\n bootstrapToken,\n projectName: options.projectName,\n webhookUrl,\n forceNewWebhook: options.flags.forceNewWebhook,\n\t\t});\n\n\t\tconst mnemonic = generateBip39Mnemonic(128);\n\n\t\treturn {\n\t\t\tdevice,\n\t\t\tbootstrapToken,\n\t\t\tcredentials,\n\t\t\tmnemonic,\n\t\t};\n\t}\n\n\t// Manual path: poll once to get the bootstrap token.\n\tconst pollResult = await client.onboarding.pollDeviceAuth({\n\t\tdeviceCode: device.deviceCode,\n\t});\n\n\tif (pollResult.status !== \"authorized\") {\n\t\tthrow new Error(\n\t\t\t`Unable to obtain bootstrap token (status: ${pollResult.status}).`,\n\t\t);\n\t}\n\n\tconst credentials = await client.onboarding.bootstrap({\n\t\tbootstrapToken: pollResult.bootstrapToken,\n\t\tprojectName: options.projectName,\n\t\twebhookUrl,\n\t\tforceNewWebhook: options.flags.forceNewWebhook,\n\t});\n\n\tconst mnemonic = generateBip39Mnemonic(128);\n\n\treturn {\n\t\tdevice,\n\t\tbootstrapToken: pollResult.bootstrapToken,\n\t\tcredentials,\n\t\tmnemonic,\n\t};\n}\n\nasync function main() {\n\tconst flags = parseFlags(process.argv.slice(2));\n\tconst jsonMode = flags.json;\n\n\tif (!jsonMode) {\n\t\tp.intro(\"Money Dev Kit – @moneydevkit/create\");\n\t}\n\n\tconst baseUrl = flags.baseUrl ?? DEFAULT_BASE_URL;\n\tconst cookies = new CookieJar(flags.manualLogin);\n\n\tconst envFileOverride = process.env.MDK_ENV_FILE;\n\tconst envResolution = resolveEnvTarget({\n\t\texplicitTarget: flags.envFile,\n\t\toverrideTarget: envFileOverride,\n\t\tcwd: process.cwd(),\n\t\tdefaultFilename: DEFAULT_ENV_FILE,\n\t});\n\tconst { providedExplicitly } = envResolution;\n\tlet projectDir = envResolution.projectDir;\n\tlet envFile = envResolution.envFile;\n\n\tif (!providedExplicitly && !jsonMode && !flags.envFile) {\n\t\tconst dirPrompt = await p.text({\n\t\t\tmessage: \"Where should we store your MDK credentials?\",\n\t\t\tinitialValue: projectDir,\n\t\t});\n\n\t\tif (p.isCancel(dirPrompt)) {\n\t\t\tp.cancel(\"Aborted.\");\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tprojectDir = dirPrompt;\n\t}\n\n\tprojectDir = normalizeDirectory(projectDir);\n\tensureDirectoryExists(projectDir);\n\n\tif (!flags.envFile && !envFileOverride && !jsonMode) {\n\t\tconst envPrompt = await p.text({\n\t\t\tmessage: \"Env file to update\",\n\t\t\tinitialValue: envFile,\n\t\t});\n\n\t\tif (p.isCancel(envPrompt)) {\n\t\t\tp.cancel(\"Aborted.\");\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tenvFile = envPrompt.trim() || DEFAULT_ENV_FILE;\n\t}\n\n\tconst envPath = path.join(projectDir, envFile);\n\tconst existingEnvValues = readEnvFile(envPath);\n\tconst mnemonicAlreadySet = existingEnvValues.get(\"MDK_MNEMONIC\")?.trim();\n\n\tif (mnemonicAlreadySet) {\n\t\tconst warningMessage =\n\t\t\t\"We found MDK_MNEMONIC already set in your project. Your mnemonic is the key to your wallet. If you've already deployed and taken payments with this mnemonic and change it, you will lose access to your funds. If you want to generate a new mnemonic, delete MDK_MNEMONIC from your .env and try again.\";\n\n\t\tif (jsonMode) {\n\t\t\tconsole.error(\n\t\t\t\tJSON.stringify(\n\t\t\t\t\t{\n\t\t\t\t\t\tstatus: \"error\",\n\t\t\t\t\t\terror: { message: warningMessage },\n\t\t\t\t\t},\n\t\t\t\t\tnull,\n\t\t\t\t\t2,\n\t\t\t\t),\n\t\t\t);\n\t\t} else {\n\t\t\tp.cancel(warningMessage);\n\t\t}\n\n\t\tprocess.exit(1);\n\t}\n\n\tlet webhookUrl = flags.webhookUrl?.trim();\n\tif ((!webhookUrl || !isValidHttpUrl(webhookUrl)) && jsonMode) {\n\t\tthrow new Error(\"Provide a valid --webhook-url when running in --json mode.\");\n\t}\n\n\twhile (!webhookUrl) {\n\t\tconst webhookInput = await p.text({\n\t\t\tmessage: \"Webhook URL for your application\",\n\t\t\tinitialValue: \"https://\",\n\t\t\tplaceholder: \"https://yourapp.com\",\n\t\t\tvalidate: (value) =>\n\t\t\t\tisValidHttpUrl(value?.trim())\n\t\t\t\t\t? undefined\n\t\t\t\t\t: \"Enter a valid http(s) URL (e.g. https://yourapp.com)\",\n\t\t});\n\n\t\tif (p.isCancel(webhookInput)) {\n\t\t\tp.cancel(\"Aborted.\");\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\twebhookUrl = webhookInput.trim();\n\t}\n\n\tlet projectName = flags.projectName?.trim();\n\tif (!projectName && !jsonMode) {\n\t\tconst namePrompt = await p.text({\n\t\t\tmessage: \"Project name (used for the generated API key)\",\n\t\t\tplaceholder: \"Optional: e.g. My Next.js Store\",\n\t\t});\n\t\tif (p.isCancel(namePrompt)) {\n\t\t\tp.cancel(\"Aborted.\");\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tprojectName = namePrompt.trim() || undefined;\n\t}\n\n\tprojectName = deriveProjectName(projectName, webhookUrl);\n\n\ttry {\n\t\tconst result = await runDeviceFlow({\n\t\t\tflags,\n\t\t\tbaseUrl,\n\t\t\tcookies,\n\t\t\tprojectName,\n\t\t\twebhookUrl,\n\t\t});\n\n\t\tconst updates: Record<string, string> = {\n\t\t\tMDK_ACCESS_TOKEN: result.credentials.apiKey,\n\t\t\tMDK_WEBHOOK_SECRET: result.credentials.webhookSecret,\n\t\t\tMDK_MNEMONIC: result.mnemonic,\n\t\t};\n\n\t\tensureEnvFileExists(envPath);\n\t\tconst existingEnv = readEnvFile(envPath);\n\t\tconst preview = renderEnvPreview(existingEnv, updates);\n\n\t\twriteEnvFile(envPath, existingEnv, updates);\n\n\t\tif (!jsonMode) {\n\t\t\tp.note(preview, \"Env file updated\");\n\t\t}\n\n if (!flags.noClipboard) {\n await clipboard.write(\n\t\t\t\t[`MDK_ACCESS_TOKEN=${updates.MDK_ACCESS_TOKEN}`, `MDK_WEBHOOK_SECRET=${updates.MDK_WEBHOOK_SECRET}`, `MDK_MNEMONIC=${updates.MDK_MNEMONIC}`].join(\n\t\t\t\t\t\"\\n\",\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tconst summary = {\n\t\t\tprojectDir,\n\t\t\tenvFile: envPath,\n\t\t\tapiKeyPreview: result.credentials.apiKeyPreview,\n\t\t\twebhookId: result.credentials.webhookId,\n\t\t\torganizationId: result.credentials.organizationId,\n\t\t\twebhookUrl: result.credentials.webhookUrl,\n\t\t\tmnemonic: updates.MDK_MNEMONIC,\n\t\t};\n\n if (jsonMode) {\n console.log(\n JSON.stringify(\n {\n status: \"success\",\n data: {\n\t\t\t\t\t\t\tenvFile: envPath,\n\t\t\t\t\t\t\tapiKeyId: result.credentials.apiKeyId,\n\t\t\t\t\t\t\tapiKeyPreview: result.credentials.apiKeyPreview,\n\t\t\t\t\t\t\twebhookId: result.credentials.webhookId,\n\t\t\t\t\t\t\twebhookSecret: result.credentials.webhookSecret,\n\t\t\t\t\t\t\twebhookUrl: result.credentials.webhookUrl,\n\t\t\t\t\t\t\torganizationId: result.credentials.organizationId,\n\t\t\t\t\t\t\tmnemonic: updates.MDK_MNEMONIC,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tnull,\n\t\t\t\t\t2,\n ),\n );\n } else {\n p.outro(\n [\n \"Authorized successfully!\",\n `• Credentials written to ${envPath}`,\n `• Webhook ID: ${result.credentials.webhookId}`,\n `• Organization: ${result.credentials.organizationId}`,\n flags.noClipboard\n ? \"Clipboard copy skipped (--no-clipboard).\"\n : \"Secrets copied to clipboard.\",\n \"Return to your project and continue development.\",\n ].join(\"\\n\"),\n );\n }\n\n return summary;\n\t} catch (error) {\n\t\tif (jsonMode) {\n\t\t\tconsole.error(\n\t\t\t\tJSON.stringify(\n\t\t\t\t\t{\n\t\t\t\t\t\tstatus: \"error\",\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\terror instanceof Error ? error.message : String(error),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tnull,\n\t\t\t\t\t2,\n\t\t\t\t),\n\t\t\t);\n\t\t} else {\n\t\t\tp.cancel(\n\t\t\t\terror instanceof Error ? error.message : `Unexpected error: ${error}`,\n\t\t\t);\n\t\t}\n\t\tprocess.exit(1);\n\t}\n}\n\nvoid main();\n","import path from \"node:path\";\n\nexport type EnvTargetResolution = {\n projectDir: string;\n envFile: string;\n providedExplicitly: boolean;\n};\n\nexport function resolveEnvTarget(options: {\n explicitTarget?: string;\n overrideTarget?: string;\n cwd: string;\n defaultFilename: string;\n}): EnvTargetResolution {\n const { explicitTarget, overrideTarget, cwd, defaultFilename } = options;\n const rawTarget = explicitTarget ?? overrideTarget ?? defaultFilename;\n const hasPathSeparator = rawTarget.includes(\"/\") || rawTarget.includes(\"\\\\\");\n\n let projectDir = cwd;\n let envFile = path.basename(rawTarget);\n let providedExplicitly = Boolean(explicitTarget);\n\n if (path.isAbsolute(rawTarget)) {\n projectDir = path.dirname(rawTarget);\n envFile = path.basename(rawTarget);\n providedExplicitly = true;\n } else if (hasPathSeparator) {\n const relativeDir = path.dirname(rawTarget);\n if (relativeDir && relativeDir !== \".\" && relativeDir !== \"\") {\n projectDir = path.resolve(cwd, relativeDir);\n envFile = path.basename(rawTarget);\n providedExplicitly = true;\n }\n }\n\n return {\n projectDir: path.resolve(projectDir),\n envFile,\n providedExplicitly,\n };\n}\n\nexport function deriveProjectName(input: string | undefined, webhookUrl: string): string {\n const trimmed = input?.trim();\n if (trimmed) {\n return trimmed;\n }\n return webhookUrl;\n}\n"],"mappings":"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","names":["import_node_path","path","setCookieParser","minimist","path","fs","os","open","spinner","delay","credentials","mnemonic","generateBip39Mnemonic","clipboard"]}
|
package/dist/index.d.cts
ADDED
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
#!/usr/bin/env -S node --
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { createORPCClient } from "@orpc/client";
|
|
5
|
+
import { RPCLink } from "@orpc/client/fetch";
|
|
6
|
+
import * as p from "@clack/prompts";
|
|
7
|
+
import minimist from "minimist";
|
|
8
|
+
import path2 from "path";
|
|
9
|
+
import fs from "fs";
|
|
10
|
+
import os from "os";
|
|
11
|
+
import open from "open";
|
|
12
|
+
import clipboard from "clipboardy";
|
|
13
|
+
import setCookieParser from "set-cookie-parser";
|
|
14
|
+
import { generateMnemonic as generateBip39Mnemonic } from "bip39";
|
|
15
|
+
import { setTimeout as delay } from "timers/promises";
|
|
16
|
+
|
|
17
|
+
// src/utils/env-target.ts
|
|
18
|
+
import path from "path";
|
|
19
|
+
function resolveEnvTarget(options) {
|
|
20
|
+
const { explicitTarget, overrideTarget, cwd, defaultFilename } = options;
|
|
21
|
+
const rawTarget = explicitTarget ?? overrideTarget ?? defaultFilename;
|
|
22
|
+
const hasPathSeparator = rawTarget.includes("/") || rawTarget.includes("\\");
|
|
23
|
+
let projectDir = cwd;
|
|
24
|
+
let envFile = path.basename(rawTarget);
|
|
25
|
+
let providedExplicitly = Boolean(explicitTarget);
|
|
26
|
+
if (path.isAbsolute(rawTarget)) {
|
|
27
|
+
projectDir = path.dirname(rawTarget);
|
|
28
|
+
envFile = path.basename(rawTarget);
|
|
29
|
+
providedExplicitly = true;
|
|
30
|
+
} else if (hasPathSeparator) {
|
|
31
|
+
const relativeDir = path.dirname(rawTarget);
|
|
32
|
+
if (relativeDir && relativeDir !== "." && relativeDir !== "") {
|
|
33
|
+
projectDir = path.resolve(cwd, relativeDir);
|
|
34
|
+
envFile = path.basename(rawTarget);
|
|
35
|
+
providedExplicitly = true;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
projectDir: path.resolve(projectDir),
|
|
40
|
+
envFile,
|
|
41
|
+
providedExplicitly
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function deriveProjectName(input, webhookUrl) {
|
|
45
|
+
const trimmed = input?.trim();
|
|
46
|
+
if (trimmed) {
|
|
47
|
+
return trimmed;
|
|
48
|
+
}
|
|
49
|
+
return webhookUrl;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/index.ts
|
|
53
|
+
var DEFAULT_BASE_URL = "https://moneydevkit.com";
|
|
54
|
+
var DEFAULT_ENV_FILE = ".env.local";
|
|
55
|
+
var CookieJar = class {
|
|
56
|
+
store = /* @__PURE__ */ new Map();
|
|
57
|
+
constructor(initial) {
|
|
58
|
+
if (initial) {
|
|
59
|
+
this.add(initial);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
add(input) {
|
|
63
|
+
const cookies = Array.isArray(input) ? input : [input];
|
|
64
|
+
for (const line of cookies) {
|
|
65
|
+
const trimmed = line.trim();
|
|
66
|
+
if (!trimmed) continue;
|
|
67
|
+
const parsed = setCookieParser.parse(trimmed);
|
|
68
|
+
const handle = (cookie) => {
|
|
69
|
+
if (cookie?.name && cookie.value !== void 0) {
|
|
70
|
+
this.store.set(cookie.name, cookie.value);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
if (Array.isArray(parsed)) {
|
|
74
|
+
for (const cookie of parsed) {
|
|
75
|
+
handle(cookie);
|
|
76
|
+
}
|
|
77
|
+
} else if (parsed && typeof parsed === "object") {
|
|
78
|
+
handle(parsed);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
header() {
|
|
83
|
+
if (this.store.size === 0) return void 0;
|
|
84
|
+
return Array.from(this.store.entries()).map(([name, value]) => `${name}=${value}`).join("; ");
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
function parseFlags(argv) {
|
|
88
|
+
const result = minimist(argv, {
|
|
89
|
+
boolean: ["json", "no-clipboard", "no-open", "force-new-webhook", "yes"],
|
|
90
|
+
string: [
|
|
91
|
+
"base-url",
|
|
92
|
+
"env-target",
|
|
93
|
+
"project-name",
|
|
94
|
+
"manual-login",
|
|
95
|
+
"webhook-url"
|
|
96
|
+
],
|
|
97
|
+
alias: {
|
|
98
|
+
json: "j"
|
|
99
|
+
},
|
|
100
|
+
default: {
|
|
101
|
+
"no-clipboard": false,
|
|
102
|
+
"no-open": false,
|
|
103
|
+
json: false,
|
|
104
|
+
"force-new-webhook": false,
|
|
105
|
+
yes: false
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
return {
|
|
109
|
+
json: Boolean(result.json),
|
|
110
|
+
noClipboard: Boolean(result["no-clipboard"]),
|
|
111
|
+
noOpen: Boolean(result["no-open"]),
|
|
112
|
+
yes: Boolean(result.yes),
|
|
113
|
+
baseUrl: result["base-url"],
|
|
114
|
+
envFile: result["env-target"],
|
|
115
|
+
projectName: typeof result["project-name"] === "string" ? result["project-name"] : void 0,
|
|
116
|
+
manualLogin: typeof result["manual-login"] === "string" ? result["manual-login"] : void 0,
|
|
117
|
+
forceNewWebhook: Boolean(result["force-new-webhook"]),
|
|
118
|
+
webhookUrl: typeof result["webhook-url"] === "string" ? result["webhook-url"] : void 0
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function normalizeDirectory(dir) {
|
|
122
|
+
if (path2.isAbsolute(dir)) return dir;
|
|
123
|
+
return path2.resolve(process.cwd(), dir);
|
|
124
|
+
}
|
|
125
|
+
function ensureDirectoryExists(dir) {
|
|
126
|
+
if (!fs.existsSync(dir)) {
|
|
127
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function readEnvFile(filePath) {
|
|
131
|
+
const env = /* @__PURE__ */ new Map();
|
|
132
|
+
if (!fs.existsSync(filePath)) {
|
|
133
|
+
return env;
|
|
134
|
+
}
|
|
135
|
+
const contents = fs.readFileSync(filePath, "utf8");
|
|
136
|
+
for (const line of contents.split(/\r?\n/)) {
|
|
137
|
+
if (!line || line.startsWith("#")) continue;
|
|
138
|
+
const [key, ...rest] = line.split("=");
|
|
139
|
+
if (!key) continue;
|
|
140
|
+
env.set(key.trim(), rest.join("=").trim());
|
|
141
|
+
}
|
|
142
|
+
return env;
|
|
143
|
+
}
|
|
144
|
+
function renderEnvPreview(_original, updates) {
|
|
145
|
+
const lines = ["Writing the following values:", ""];
|
|
146
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
147
|
+
lines.push(` ${key}=${value}`);
|
|
148
|
+
}
|
|
149
|
+
return lines.join("\n");
|
|
150
|
+
}
|
|
151
|
+
function writeEnvFile(filePath, existing, updates) {
|
|
152
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
153
|
+
existing.set(key, value);
|
|
154
|
+
}
|
|
155
|
+
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");
|
|
157
|
+
}
|
|
158
|
+
function ensureEnvFileExists(filePath) {
|
|
159
|
+
const dir = path2.dirname(filePath);
|
|
160
|
+
ensureDirectoryExists(dir);
|
|
161
|
+
if (!fs.existsSync(filePath)) {
|
|
162
|
+
fs.writeFileSync(filePath, "", "utf8");
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function isValidHttpUrl(value) {
|
|
166
|
+
if (!value) return false;
|
|
167
|
+
try {
|
|
168
|
+
const parsed = new URL(value);
|
|
169
|
+
return parsed.protocol === "https:" || parsed.protocol === "http:";
|
|
170
|
+
} catch {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function createRpcClient(baseUrl, jar) {
|
|
175
|
+
const link = new RPCLink({
|
|
176
|
+
url: `${baseUrl.replace(/\/$/, "")}/rpc`,
|
|
177
|
+
headers: () => {
|
|
178
|
+
const cookieHeader = jar.header();
|
|
179
|
+
return cookieHeader ? { Cookie: cookieHeader } : {};
|
|
180
|
+
},
|
|
181
|
+
fetch: async (input, init) => {
|
|
182
|
+
const response = await fetch(input, init);
|
|
183
|
+
const setCookie = response.headers.getSetCookie?.() ?? [];
|
|
184
|
+
if (setCookie.length > 0) {
|
|
185
|
+
jar.add(setCookie);
|
|
186
|
+
}
|
|
187
|
+
return response;
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
return createORPCClient(link);
|
|
191
|
+
}
|
|
192
|
+
async function runDeviceFlow(options) {
|
|
193
|
+
const client = createRpcClient(options.baseUrl, options.cookies);
|
|
194
|
+
const manualSessionCookie = options.flags.manualLogin;
|
|
195
|
+
const webhookUrl = options.webhookUrl;
|
|
196
|
+
const device = await client.onboarding.startDeviceAuth({
|
|
197
|
+
clientDisplayName: options.projectName,
|
|
198
|
+
webhookUrl,
|
|
199
|
+
forceNewWebhook: options.flags.forceNewWebhook
|
|
200
|
+
});
|
|
201
|
+
if (manualSessionCookie) {
|
|
202
|
+
const response = await fetch(
|
|
203
|
+
`${options.baseUrl.replace(/\/$/, "")}/api/cli/device/authorize`,
|
|
204
|
+
{
|
|
205
|
+
method: "POST",
|
|
206
|
+
headers: {
|
|
207
|
+
"Content-Type": "application/json",
|
|
208
|
+
Cookie: manualSessionCookie
|
|
209
|
+
},
|
|
210
|
+
body: JSON.stringify({
|
|
211
|
+
code: device.userCode,
|
|
212
|
+
forceNewWebhook: options.flags.forceNewWebhook ?? false
|
|
213
|
+
})
|
|
214
|
+
}
|
|
215
|
+
);
|
|
216
|
+
if (!response.ok) {
|
|
217
|
+
const body = await response.json().catch(() => ({}));
|
|
218
|
+
throw new Error(
|
|
219
|
+
body.error ?? `Manual authorize failed with status ${response.status}`
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
} else {
|
|
223
|
+
if (!options.flags.json) {
|
|
224
|
+
p.note(
|
|
225
|
+
[
|
|
226
|
+
`Device code: ${device.userCode}`,
|
|
227
|
+
`Webhook URL: ${webhookUrl}`,
|
|
228
|
+
"Open the authorization page, click Authorize, then return to this terminal."
|
|
229
|
+
].join("\n"),
|
|
230
|
+
"Authorize this device"
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
if (!options.flags.noOpen && !options.flags.json) {
|
|
234
|
+
try {
|
|
235
|
+
await open(device.verificationUri, { wait: false });
|
|
236
|
+
} catch (error) {
|
|
237
|
+
console.warn(
|
|
238
|
+
`Unable to open browser automatically (${error.message}).`
|
|
239
|
+
);
|
|
240
|
+
console.warn(`Open this URL manually: ${device.verificationUri}`);
|
|
241
|
+
}
|
|
242
|
+
} else if (!options.flags.json) {
|
|
243
|
+
console.log(`Open this URL in your browser: ${device.verificationUri}`);
|
|
244
|
+
}
|
|
245
|
+
const spinner2 = options.flags.json ? null : p.spinner();
|
|
246
|
+
spinner2?.start("Waiting for authorization...");
|
|
247
|
+
const deadline = Date.now() + device.expiresIn * 1e3;
|
|
248
|
+
let bootstrapToken;
|
|
249
|
+
while (Date.now() < deadline) {
|
|
250
|
+
const poll = await client.onboarding.pollDeviceAuth({
|
|
251
|
+
deviceCode: device.deviceCode
|
|
252
|
+
});
|
|
253
|
+
if (poll.status === "authorized") {
|
|
254
|
+
bootstrapToken = poll.bootstrapToken;
|
|
255
|
+
spinner2?.stop("Device authorized.");
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
258
|
+
if (poll.status === "expired") {
|
|
259
|
+
spinner2?.stop("Device code expired.");
|
|
260
|
+
throw new Error("Device code expired before authorization.");
|
|
261
|
+
}
|
|
262
|
+
if (poll.status === "denied") {
|
|
263
|
+
spinner2?.stop("Authorization denied.");
|
|
264
|
+
throw new Error("Authorization was denied in the dashboard.");
|
|
265
|
+
}
|
|
266
|
+
const secondsLeft = Math.max(
|
|
267
|
+
0,
|
|
268
|
+
Math.floor((deadline - Date.now()) / 1e3)
|
|
269
|
+
);
|
|
270
|
+
spinner2?.message(
|
|
271
|
+
`Waiting for authorization (${secondsLeft}s remaining)`
|
|
272
|
+
);
|
|
273
|
+
await delay(device.interval * 1e3);
|
|
274
|
+
}
|
|
275
|
+
if (!bootstrapToken) {
|
|
276
|
+
throw new Error("Timed out waiting for authorization.");
|
|
277
|
+
}
|
|
278
|
+
const credentials2 = await client.onboarding.bootstrap({
|
|
279
|
+
bootstrapToken,
|
|
280
|
+
projectName: options.projectName,
|
|
281
|
+
webhookUrl,
|
|
282
|
+
forceNewWebhook: options.flags.forceNewWebhook
|
|
283
|
+
});
|
|
284
|
+
const mnemonic2 = generateBip39Mnemonic(128);
|
|
285
|
+
return {
|
|
286
|
+
device,
|
|
287
|
+
bootstrapToken,
|
|
288
|
+
credentials: credentials2,
|
|
289
|
+
mnemonic: mnemonic2
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
const pollResult = await client.onboarding.pollDeviceAuth({
|
|
293
|
+
deviceCode: device.deviceCode
|
|
294
|
+
});
|
|
295
|
+
if (pollResult.status !== "authorized") {
|
|
296
|
+
throw new Error(
|
|
297
|
+
`Unable to obtain bootstrap token (status: ${pollResult.status}).`
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
const credentials = await client.onboarding.bootstrap({
|
|
301
|
+
bootstrapToken: pollResult.bootstrapToken,
|
|
302
|
+
projectName: options.projectName,
|
|
303
|
+
webhookUrl,
|
|
304
|
+
forceNewWebhook: options.flags.forceNewWebhook
|
|
305
|
+
});
|
|
306
|
+
const mnemonic = generateBip39Mnemonic(128);
|
|
307
|
+
return {
|
|
308
|
+
device,
|
|
309
|
+
bootstrapToken: pollResult.bootstrapToken,
|
|
310
|
+
credentials,
|
|
311
|
+
mnemonic
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
async function main() {
|
|
315
|
+
const flags = parseFlags(process.argv.slice(2));
|
|
316
|
+
const jsonMode = flags.json;
|
|
317
|
+
if (!jsonMode) {
|
|
318
|
+
p.intro("Money Dev Kit \u2013 @moneydevkit/create");
|
|
319
|
+
}
|
|
320
|
+
const baseUrl = flags.baseUrl ?? DEFAULT_BASE_URL;
|
|
321
|
+
const cookies = new CookieJar(flags.manualLogin);
|
|
322
|
+
const envFileOverride = process.env.MDK_ENV_FILE;
|
|
323
|
+
const envResolution = resolveEnvTarget({
|
|
324
|
+
explicitTarget: flags.envFile,
|
|
325
|
+
overrideTarget: envFileOverride,
|
|
326
|
+
cwd: process.cwd(),
|
|
327
|
+
defaultFilename: DEFAULT_ENV_FILE
|
|
328
|
+
});
|
|
329
|
+
const { providedExplicitly } = envResolution;
|
|
330
|
+
let projectDir = envResolution.projectDir;
|
|
331
|
+
let envFile = envResolution.envFile;
|
|
332
|
+
if (!providedExplicitly && !jsonMode && !flags.envFile) {
|
|
333
|
+
const dirPrompt = await p.text({
|
|
334
|
+
message: "Where should we store your MDK credentials?",
|
|
335
|
+
initialValue: projectDir
|
|
336
|
+
});
|
|
337
|
+
if (p.isCancel(dirPrompt)) {
|
|
338
|
+
p.cancel("Aborted.");
|
|
339
|
+
process.exit(1);
|
|
340
|
+
}
|
|
341
|
+
projectDir = dirPrompt;
|
|
342
|
+
}
|
|
343
|
+
projectDir = normalizeDirectory(projectDir);
|
|
344
|
+
ensureDirectoryExists(projectDir);
|
|
345
|
+
if (!flags.envFile && !envFileOverride && !jsonMode) {
|
|
346
|
+
const envPrompt = await p.text({
|
|
347
|
+
message: "Env file to update",
|
|
348
|
+
initialValue: envFile
|
|
349
|
+
});
|
|
350
|
+
if (p.isCancel(envPrompt)) {
|
|
351
|
+
p.cancel("Aborted.");
|
|
352
|
+
process.exit(1);
|
|
353
|
+
}
|
|
354
|
+
envFile = envPrompt.trim() || DEFAULT_ENV_FILE;
|
|
355
|
+
}
|
|
356
|
+
const envPath = path2.join(projectDir, envFile);
|
|
357
|
+
const existingEnvValues = readEnvFile(envPath);
|
|
358
|
+
const mnemonicAlreadySet = existingEnvValues.get("MDK_MNEMONIC")?.trim();
|
|
359
|
+
if (mnemonicAlreadySet) {
|
|
360
|
+
const warningMessage = "We found MDK_MNEMONIC already set in your project. Your mnemonic is the key to your wallet. If you've already deployed and taken payments with this mnemonic and change it, you will lose access to your funds. If you want to generate a new mnemonic, delete MDK_MNEMONIC from your .env and try again.";
|
|
361
|
+
if (jsonMode) {
|
|
362
|
+
console.error(
|
|
363
|
+
JSON.stringify(
|
|
364
|
+
{
|
|
365
|
+
status: "error",
|
|
366
|
+
error: { message: warningMessage }
|
|
367
|
+
},
|
|
368
|
+
null,
|
|
369
|
+
2
|
|
370
|
+
)
|
|
371
|
+
);
|
|
372
|
+
} else {
|
|
373
|
+
p.cancel(warningMessage);
|
|
374
|
+
}
|
|
375
|
+
process.exit(1);
|
|
376
|
+
}
|
|
377
|
+
let webhookUrl = flags.webhookUrl?.trim();
|
|
378
|
+
if ((!webhookUrl || !isValidHttpUrl(webhookUrl)) && jsonMode) {
|
|
379
|
+
throw new Error("Provide a valid --webhook-url when running in --json mode.");
|
|
380
|
+
}
|
|
381
|
+
while (!webhookUrl) {
|
|
382
|
+
const webhookInput = await p.text({
|
|
383
|
+
message: "Webhook URL for your application",
|
|
384
|
+
initialValue: "https://",
|
|
385
|
+
placeholder: "https://yourapp.com",
|
|
386
|
+
validate: (value) => isValidHttpUrl(value?.trim()) ? void 0 : "Enter a valid http(s) URL (e.g. https://yourapp.com)"
|
|
387
|
+
});
|
|
388
|
+
if (p.isCancel(webhookInput)) {
|
|
389
|
+
p.cancel("Aborted.");
|
|
390
|
+
process.exit(1);
|
|
391
|
+
}
|
|
392
|
+
webhookUrl = webhookInput.trim();
|
|
393
|
+
}
|
|
394
|
+
let projectName = flags.projectName?.trim();
|
|
395
|
+
if (!projectName && !jsonMode) {
|
|
396
|
+
const namePrompt = await p.text({
|
|
397
|
+
message: "Project name (used for the generated API key)",
|
|
398
|
+
placeholder: "Optional: e.g. My Next.js Store"
|
|
399
|
+
});
|
|
400
|
+
if (p.isCancel(namePrompt)) {
|
|
401
|
+
p.cancel("Aborted.");
|
|
402
|
+
process.exit(1);
|
|
403
|
+
}
|
|
404
|
+
projectName = namePrompt.trim() || void 0;
|
|
405
|
+
}
|
|
406
|
+
projectName = deriveProjectName(projectName, webhookUrl);
|
|
407
|
+
try {
|
|
408
|
+
const result = await runDeviceFlow({
|
|
409
|
+
flags,
|
|
410
|
+
baseUrl,
|
|
411
|
+
cookies,
|
|
412
|
+
projectName,
|
|
413
|
+
webhookUrl
|
|
414
|
+
});
|
|
415
|
+
const updates = {
|
|
416
|
+
MDK_ACCESS_TOKEN: result.credentials.apiKey,
|
|
417
|
+
MDK_WEBHOOK_SECRET: result.credentials.webhookSecret,
|
|
418
|
+
MDK_MNEMONIC: result.mnemonic
|
|
419
|
+
};
|
|
420
|
+
ensureEnvFileExists(envPath);
|
|
421
|
+
const existingEnv = readEnvFile(envPath);
|
|
422
|
+
const preview = renderEnvPreview(existingEnv, updates);
|
|
423
|
+
writeEnvFile(envPath, existingEnv, updates);
|
|
424
|
+
if (!jsonMode) {
|
|
425
|
+
p.note(preview, "Env file updated");
|
|
426
|
+
}
|
|
427
|
+
if (!flags.noClipboard) {
|
|
428
|
+
await clipboard.write(
|
|
429
|
+
[`MDK_ACCESS_TOKEN=${updates.MDK_ACCESS_TOKEN}`, `MDK_WEBHOOK_SECRET=${updates.MDK_WEBHOOK_SECRET}`, `MDK_MNEMONIC=${updates.MDK_MNEMONIC}`].join(
|
|
430
|
+
"\n"
|
|
431
|
+
)
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
const summary = {
|
|
435
|
+
projectDir,
|
|
436
|
+
envFile: envPath,
|
|
437
|
+
apiKeyPreview: result.credentials.apiKeyPreview,
|
|
438
|
+
webhookId: result.credentials.webhookId,
|
|
439
|
+
organizationId: result.credentials.organizationId,
|
|
440
|
+
webhookUrl: result.credentials.webhookUrl,
|
|
441
|
+
mnemonic: updates.MDK_MNEMONIC
|
|
442
|
+
};
|
|
443
|
+
if (jsonMode) {
|
|
444
|
+
console.log(
|
|
445
|
+
JSON.stringify(
|
|
446
|
+
{
|
|
447
|
+
status: "success",
|
|
448
|
+
data: {
|
|
449
|
+
envFile: envPath,
|
|
450
|
+
apiKeyId: result.credentials.apiKeyId,
|
|
451
|
+
apiKeyPreview: result.credentials.apiKeyPreview,
|
|
452
|
+
webhookId: result.credentials.webhookId,
|
|
453
|
+
webhookSecret: result.credentials.webhookSecret,
|
|
454
|
+
webhookUrl: result.credentials.webhookUrl,
|
|
455
|
+
organizationId: result.credentials.organizationId,
|
|
456
|
+
mnemonic: updates.MDK_MNEMONIC
|
|
457
|
+
}
|
|
458
|
+
},
|
|
459
|
+
null,
|
|
460
|
+
2
|
|
461
|
+
)
|
|
462
|
+
);
|
|
463
|
+
} else {
|
|
464
|
+
p.outro(
|
|
465
|
+
[
|
|
466
|
+
"Authorized successfully!",
|
|
467
|
+
`\u2022 Credentials written to ${envPath}`,
|
|
468
|
+
`\u2022 Webhook ID: ${result.credentials.webhookId}`,
|
|
469
|
+
`\u2022 Organization: ${result.credentials.organizationId}`,
|
|
470
|
+
flags.noClipboard ? "Clipboard copy skipped (--no-clipboard)." : "Secrets copied to clipboard.",
|
|
471
|
+
"Return to your project and continue development."
|
|
472
|
+
].join("\n")
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
return summary;
|
|
476
|
+
} catch (error) {
|
|
477
|
+
if (jsonMode) {
|
|
478
|
+
console.error(
|
|
479
|
+
JSON.stringify(
|
|
480
|
+
{
|
|
481
|
+
status: "error",
|
|
482
|
+
error: {
|
|
483
|
+
message: error instanceof Error ? error.message : String(error)
|
|
484
|
+
}
|
|
485
|
+
},
|
|
486
|
+
null,
|
|
487
|
+
2
|
|
488
|
+
)
|
|
489
|
+
);
|
|
490
|
+
} else {
|
|
491
|
+
p.cancel(
|
|
492
|
+
error instanceof Error ? error.message : `Unexpected error: ${error}`
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
process.exit(1);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
void main();
|
|
499
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/utils/env-target.ts"],"sourcesContent":["import { createORPCClient } from \"@orpc/client\";\nimport { RPCLink } from \"@orpc/client/fetch\";\nimport * as p from \"@clack/prompts\";\nimport minimist from \"minimist\";\nimport path from \"node:path\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport open from \"open\";\nimport clipboard from \"clipboardy\";\nimport setCookieParser, { Cookie } from \"set-cookie-parser\";\nimport { generateMnemonic as generateBip39Mnemonic } from \"bip39\";\nimport { contract } from \"@moneydevkit/api-contract\";\nimport type { ContractRouterClient } from \"@orpc/contract\";\nimport type {\n\tBootstrapOnboardingResponse,\n\tStartDeviceAuthResponse,\n} from \"@moneydevkit/api-contract\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport { deriveProjectName, resolveEnvTarget } from \"./utils/env-target.js\";\n\ntype Flags = {\n\tjson: boolean;\n\tnoClipboard: boolean;\n\tnoOpen: boolean;\n\tyes: boolean;\n\tbaseUrl?: string;\n\tenvFile?: string;\n\tprojectName?: string;\n\tmanualLogin?: string;\n\tforceNewWebhook?: boolean;\n\twebhookUrl?: string;\n};\n\nconst DEFAULT_BASE_URL = \"https://moneydevkit.com\";\nconst DEFAULT_ENV_FILE = \".env.local\";\n\nclass CookieJar {\n\tprivate store = new Map<string, string>();\n\n\tconstructor(initial?: string) {\n\t\tif (initial) {\n\t\t\tthis.add(initial);\n\t\t}\n\t}\n\n\tadd(input: string | string[]) {\n\t\tconst cookies = Array.isArray(input) ? input : [input];\n\t\tfor (const line of cookies) {\n\t\t\tconst trimmed = line.trim();\n\t\t\tif (!trimmed) continue;\n\t\t\tconst parsed = setCookieParser.parse(trimmed);\n\t\t\tconst handle = (cookie: Cookie) => {\n\t\t\t\tif (cookie?.name && cookie.value !== undefined) {\n\t\t\t\t\tthis.store.set(cookie.name, cookie.value);\n\t\t\t\t}\n\t\t\t};\n\t\t\tif (Array.isArray(parsed)) {\n\t\t\t\tfor (const cookie of parsed) {\n\t\t\t\t\thandle(cookie);\n\t\t\t\t}\n\t\t\t} else if (parsed && typeof parsed === \"object\") {\n\t\t\t\thandle(parsed);\n\t\t\t}\n\t\t}\n\t}\n\n\theader(): string | undefined {\n\t\tif (this.store.size === 0) return undefined;\n\t\treturn Array.from(this.store.entries())\n\t\t\t.map(([name, value]) => `${name}=${value}`)\n\t\t\t.join(\"; \");\n\t}\n}\n\nfunction parseFlags(argv: string[]): Flags {\n\tconst result = minimist(argv, {\n\t\tboolean: [\"json\", \"no-clipboard\", \"no-open\", \"force-new-webhook\", \"yes\"],\n\t\tstring: [\n\t\t\t\"base-url\",\n\t\t\t\"env-target\",\n\t\t\t\"project-name\",\n\t\t\t\"manual-login\",\n\t\t\t\"webhook-url\",\n\t\t],\n\t\talias: {\n\t\t\tjson: \"j\",\n\t\t},\n\t\tdefault: {\n\t\t\t\"no-clipboard\": false,\n\t\t\t\"no-open\": false,\n\t\t\tjson: false,\n\t\t\t\"force-new-webhook\": false,\n\t\t\tyes: false,\n\t\t},\n\t});\n\nreturn {\n\tjson: Boolean(result.json),\n\tnoClipboard: Boolean(result[\"no-clipboard\"]),\n\tnoOpen: Boolean(result[\"no-open\"]),\n\tyes: Boolean(result.yes),\n\tbaseUrl: result[\"base-url\"],\n\tenvFile: result[\"env-target\"],\n\t\tprojectName:\n\t\t\ttypeof result[\"project-name\"] === \"string\"\n\t\t\t\t? result[\"project-name\"]\n\t\t\t\t: undefined,\n\t\tmanualLogin:\n\t\t\ttypeof result[\"manual-login\"] === \"string\"\n\t\t\t\t? result[\"manual-login\"]\n\t\t\t\t: undefined,\n\t\tforceNewWebhook: Boolean(result[\"force-new-webhook\"]),\n\t\twebhookUrl:\n\t\t\ttypeof result[\"webhook-url\"] === \"string\"\n\t\t\t\t? result[\"webhook-url\"]\n\t\t\t\t: undefined,\n\t};\n}\n\nfunction normalizeDirectory(dir: string): string {\n\tif (path.isAbsolute(dir)) return dir;\n\treturn path.resolve(process.cwd(), dir);\n}\n\nfunction ensureDirectoryExists(dir: string) {\n\tif (!fs.existsSync(dir)) {\n\t\tfs.mkdirSync(dir, { recursive: true });\n\t}\n}\n\nfunction readEnvFile(filePath: string): Map<string, string> {\n\tconst env = new Map<string, string>();\n\tif (!fs.existsSync(filePath)) {\n\t\treturn env;\n\t}\n\tconst contents = fs.readFileSync(filePath, \"utf8\");\n\tfor (const line of contents.split(/\\r?\\n/)) {\n\t\tif (!line || line.startsWith(\"#\")) continue;\n\t\tconst [key, ...rest] = line.split(\"=\");\n\t\tif (!key) continue;\n\t\tenv.set(key.trim(), rest.join(\"=\").trim());\n\t}\n\treturn env;\n}\n\nfunction renderEnvPreview(\n\t_original: Map<string, string>,\n\tupdates: Record<string, string>,\n): string {\n\tconst lines: string[] = [\"Writing the following values:\", \"\"];\n\tfor (const [key, value] of Object.entries(updates)) {\n\t\tlines.push(` ${key}=${value}`);\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nfunction writeEnvFile(\n\tfilePath: string,\n\texisting: Map<string, string>,\n\tupdates: Record<string, string>,\n) {\n\tfor (const [key, value] of Object.entries(updates)) {\n\t\texisting.set(key, value);\n\t}\n\tconst content =\n\t\tArray.from(existing.entries())\n\t\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t\t.map(([key, value]) => `${key}=${value}`)\n\t\t\t.join(os.EOL) + os.EOL;\n\tfs.writeFileSync(filePath, content, \"utf8\");\n}\n\nfunction ensureEnvFileExists(filePath: string) {\n\tconst dir = path.dirname(filePath);\n\tensureDirectoryExists(dir);\n\tif (!fs.existsSync(filePath)) {\n\t\tfs.writeFileSync(filePath, \"\", \"utf8\");\n\t}\n}\n\nfunction isValidHttpUrl(value?: string): boolean {\n\tif (!value) return false;\n\ttry {\n\t\tconst parsed = new URL(value);\n\t\treturn parsed.protocol === \"https:\" || parsed.protocol === \"http:\";\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction createRpcClient(\n\tbaseUrl: string,\n\tjar: CookieJar,\n): ContractRouterClient<typeof contract> {\n\tconst link = new RPCLink({\n\t\turl: `${baseUrl.replace(/\\/$/, \"\")}/rpc`,\n\t\theaders: () => {\n\t\t\tconst cookieHeader = jar.header();\n\t\t\treturn cookieHeader ? { Cookie: cookieHeader } : {};\n\t\t},\n\t\tfetch: async (input, init) => {\n\t\t\tconst response = await fetch(input, init);\n\t\t\tconst setCookie = response.headers.getSetCookie?.() ?? [];\n\t\t\tif (setCookie.length > 0) {\n\t\t\t\tjar.add(setCookie);\n\t\t\t}\n\t\t\treturn response;\n\t\t},\n\t});\n\n\treturn createORPCClient(link) as ContractRouterClient<typeof contract>;\n}\n\nasync function runDeviceFlow(options: {\n\tflags: Flags;\n\tbaseUrl: string;\n\tcookies: CookieJar;\n\tprojectName?: string;\n\twebhookUrl: string;\n}): Promise<{\n\tdevice: StartDeviceAuthResponse;\n\tbootstrapToken: string;\n\tcredentials: BootstrapOnboardingResponse;\n\tmnemonic: string;\n}> {\n\tconst client = createRpcClient(options.baseUrl, options.cookies);\nconst manualSessionCookie = options.flags.manualLogin;\nconst webhookUrl = options.webhookUrl;\n\nconst device = await client.onboarding.startDeviceAuth({\n clientDisplayName: options.projectName,\n webhookUrl,\n forceNewWebhook: options.flags.forceNewWebhook,\n});\n\n\tif (manualSessionCookie) {\n\t\tconst response = await fetch(\n\t\t\t`${options.baseUrl.replace(/\\/$/, \"\")}/api/cli/device/authorize`,\n\t\t\t{\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\tCookie: manualSessionCookie,\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tcode: device.userCode,\n\t\t\t\t\tforceNewWebhook: options.flags.forceNewWebhook ?? false,\n\t\t\t\t}),\n\t\t\t},\n\t\t);\n\n\t\tif (!response.ok) {\n\t\t\tconst body = (await response.json().catch(() => ({}))) as {\n\t\t\t\terror?: string;\n\t\t\t};\n\t\t\tthrow new Error(\n\t\t\t\tbody.error ??\n\t\t\t\t\t`Manual authorize failed with status ${response.status}`,\n\t\t\t);\n\t\t}\n\t} else {\n if (!options.flags.json) {\n p.note(\n [\n `Device code: ${device.userCode}`,\n `Webhook URL: ${webhookUrl}`,\n \"Open the authorization page, click Authorize, then return to this terminal.\",\n ].join(\"\\n\"),\n \"Authorize this device\",\n );\n }\n\n\t\tif (!options.flags.noOpen && !options.flags.json) {\n\t\t\ttry {\n\t\t\t\tawait open(device.verificationUri, { wait: false });\n\t\t\t} catch (error) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`Unable to open browser automatically (${(error as Error).message}).`,\n\t\t\t\t);\n\t\t\t\tconsole.warn(`Open this URL manually: ${device.verificationUri}`);\n\t\t\t}\n\t\t} else if (!options.flags.json) {\n\t\t\tconsole.log(`Open this URL in your browser: ${device.verificationUri}`);\n\t\t}\n\n\t\tconst spinner = options.flags.json ? null : p.spinner();\n\t\tspinner?.start(\"Waiting for authorization...\");\n\n\t\tconst deadline = Date.now() + device.expiresIn * 1000;\n\t\tlet bootstrapToken: string | undefined;\n\n\t\twhile (Date.now() < deadline) {\n\t\t\tconst poll = await client.onboarding.pollDeviceAuth({\n\t\t\t\tdeviceCode: device.deviceCode,\n\t\t\t});\n\n\t\t\tif (poll.status === \"authorized\") {\n\t\t\t\tbootstrapToken = poll.bootstrapToken;\n\t\t\t\tspinner?.stop(\"Device authorized.\");\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (poll.status === \"expired\") {\n\t\t\t\tspinner?.stop(\"Device code expired.\");\n\t\t\t\tthrow new Error(\"Device code expired before authorization.\");\n\t\t\t}\n\n\t\t\tif (poll.status === \"denied\") {\n\t\t\t\tspinner?.stop(\"Authorization denied.\");\n\t\t\t\tthrow new Error(\"Authorization was denied in the dashboard.\");\n\t\t\t}\n\n const secondsLeft = Math.max(\n 0,\n Math.floor((deadline - Date.now()) / 1000),\n );\n spinner?.message(\n `Waiting for authorization (${secondsLeft}s remaining)`,\n\t\t\t);\n\t\t\tawait delay(device.interval * 1000);\n\t\t}\n\n\t\tif (!bootstrapToken) {\n\t\t\tthrow new Error(\"Timed out waiting for authorization.\");\n\t\t}\n\n const credentials = await client.onboarding.bootstrap({\n bootstrapToken,\n projectName: options.projectName,\n webhookUrl,\n forceNewWebhook: options.flags.forceNewWebhook,\n\t\t});\n\n\t\tconst mnemonic = generateBip39Mnemonic(128);\n\n\t\treturn {\n\t\t\tdevice,\n\t\t\tbootstrapToken,\n\t\t\tcredentials,\n\t\t\tmnemonic,\n\t\t};\n\t}\n\n\t// Manual path: poll once to get the bootstrap token.\n\tconst pollResult = await client.onboarding.pollDeviceAuth({\n\t\tdeviceCode: device.deviceCode,\n\t});\n\n\tif (pollResult.status !== \"authorized\") {\n\t\tthrow new Error(\n\t\t\t`Unable to obtain bootstrap token (status: ${pollResult.status}).`,\n\t\t);\n\t}\n\n\tconst credentials = await client.onboarding.bootstrap({\n\t\tbootstrapToken: pollResult.bootstrapToken,\n\t\tprojectName: options.projectName,\n\t\twebhookUrl,\n\t\tforceNewWebhook: options.flags.forceNewWebhook,\n\t});\n\n\tconst mnemonic = generateBip39Mnemonic(128);\n\n\treturn {\n\t\tdevice,\n\t\tbootstrapToken: pollResult.bootstrapToken,\n\t\tcredentials,\n\t\tmnemonic,\n\t};\n}\n\nasync function main() {\n\tconst flags = parseFlags(process.argv.slice(2));\n\tconst jsonMode = flags.json;\n\n\tif (!jsonMode) {\n\t\tp.intro(\"Money Dev Kit – @moneydevkit/create\");\n\t}\n\n\tconst baseUrl = flags.baseUrl ?? DEFAULT_BASE_URL;\n\tconst cookies = new CookieJar(flags.manualLogin);\n\n\tconst envFileOverride = process.env.MDK_ENV_FILE;\n\tconst envResolution = resolveEnvTarget({\n\t\texplicitTarget: flags.envFile,\n\t\toverrideTarget: envFileOverride,\n\t\tcwd: process.cwd(),\n\t\tdefaultFilename: DEFAULT_ENV_FILE,\n\t});\n\tconst { providedExplicitly } = envResolution;\n\tlet projectDir = envResolution.projectDir;\n\tlet envFile = envResolution.envFile;\n\n\tif (!providedExplicitly && !jsonMode && !flags.envFile) {\n\t\tconst dirPrompt = await p.text({\n\t\t\tmessage: \"Where should we store your MDK credentials?\",\n\t\t\tinitialValue: projectDir,\n\t\t});\n\n\t\tif (p.isCancel(dirPrompt)) {\n\t\t\tp.cancel(\"Aborted.\");\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tprojectDir = dirPrompt;\n\t}\n\n\tprojectDir = normalizeDirectory(projectDir);\n\tensureDirectoryExists(projectDir);\n\n\tif (!flags.envFile && !envFileOverride && !jsonMode) {\n\t\tconst envPrompt = await p.text({\n\t\t\tmessage: \"Env file to update\",\n\t\t\tinitialValue: envFile,\n\t\t});\n\n\t\tif (p.isCancel(envPrompt)) {\n\t\t\tp.cancel(\"Aborted.\");\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tenvFile = envPrompt.trim() || DEFAULT_ENV_FILE;\n\t}\n\n\tconst envPath = path.join(projectDir, envFile);\n\tconst existingEnvValues = readEnvFile(envPath);\n\tconst mnemonicAlreadySet = existingEnvValues.get(\"MDK_MNEMONIC\")?.trim();\n\n\tif (mnemonicAlreadySet) {\n\t\tconst warningMessage =\n\t\t\t\"We found MDK_MNEMONIC already set in your project. Your mnemonic is the key to your wallet. If you've already deployed and taken payments with this mnemonic and change it, you will lose access to your funds. If you want to generate a new mnemonic, delete MDK_MNEMONIC from your .env and try again.\";\n\n\t\tif (jsonMode) {\n\t\t\tconsole.error(\n\t\t\t\tJSON.stringify(\n\t\t\t\t\t{\n\t\t\t\t\t\tstatus: \"error\",\n\t\t\t\t\t\terror: { message: warningMessage },\n\t\t\t\t\t},\n\t\t\t\t\tnull,\n\t\t\t\t\t2,\n\t\t\t\t),\n\t\t\t);\n\t\t} else {\n\t\t\tp.cancel(warningMessage);\n\t\t}\n\n\t\tprocess.exit(1);\n\t}\n\n\tlet webhookUrl = flags.webhookUrl?.trim();\n\tif ((!webhookUrl || !isValidHttpUrl(webhookUrl)) && jsonMode) {\n\t\tthrow new Error(\"Provide a valid --webhook-url when running in --json mode.\");\n\t}\n\n\twhile (!webhookUrl) {\n\t\tconst webhookInput = await p.text({\n\t\t\tmessage: \"Webhook URL for your application\",\n\t\t\tinitialValue: \"https://\",\n\t\t\tplaceholder: \"https://yourapp.com\",\n\t\t\tvalidate: (value) =>\n\t\t\t\tisValidHttpUrl(value?.trim())\n\t\t\t\t\t? undefined\n\t\t\t\t\t: \"Enter a valid http(s) URL (e.g. https://yourapp.com)\",\n\t\t});\n\n\t\tif (p.isCancel(webhookInput)) {\n\t\t\tp.cancel(\"Aborted.\");\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\twebhookUrl = webhookInput.trim();\n\t}\n\n\tlet projectName = flags.projectName?.trim();\n\tif (!projectName && !jsonMode) {\n\t\tconst namePrompt = await p.text({\n\t\t\tmessage: \"Project name (used for the generated API key)\",\n\t\t\tplaceholder: \"Optional: e.g. My Next.js Store\",\n\t\t});\n\t\tif (p.isCancel(namePrompt)) {\n\t\t\tp.cancel(\"Aborted.\");\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tprojectName = namePrompt.trim() || undefined;\n\t}\n\n\tprojectName = deriveProjectName(projectName, webhookUrl);\n\n\ttry {\n\t\tconst result = await runDeviceFlow({\n\t\t\tflags,\n\t\t\tbaseUrl,\n\t\t\tcookies,\n\t\t\tprojectName,\n\t\t\twebhookUrl,\n\t\t});\n\n\t\tconst updates: Record<string, string> = {\n\t\t\tMDK_ACCESS_TOKEN: result.credentials.apiKey,\n\t\t\tMDK_WEBHOOK_SECRET: result.credentials.webhookSecret,\n\t\t\tMDK_MNEMONIC: result.mnemonic,\n\t\t};\n\n\t\tensureEnvFileExists(envPath);\n\t\tconst existingEnv = readEnvFile(envPath);\n\t\tconst preview = renderEnvPreview(existingEnv, updates);\n\n\t\twriteEnvFile(envPath, existingEnv, updates);\n\n\t\tif (!jsonMode) {\n\t\t\tp.note(preview, \"Env file updated\");\n\t\t}\n\n if (!flags.noClipboard) {\n await clipboard.write(\n\t\t\t\t[`MDK_ACCESS_TOKEN=${updates.MDK_ACCESS_TOKEN}`, `MDK_WEBHOOK_SECRET=${updates.MDK_WEBHOOK_SECRET}`, `MDK_MNEMONIC=${updates.MDK_MNEMONIC}`].join(\n\t\t\t\t\t\"\\n\",\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tconst summary = {\n\t\t\tprojectDir,\n\t\t\tenvFile: envPath,\n\t\t\tapiKeyPreview: result.credentials.apiKeyPreview,\n\t\t\twebhookId: result.credentials.webhookId,\n\t\t\torganizationId: result.credentials.organizationId,\n\t\t\twebhookUrl: result.credentials.webhookUrl,\n\t\t\tmnemonic: updates.MDK_MNEMONIC,\n\t\t};\n\n if (jsonMode) {\n console.log(\n JSON.stringify(\n {\n status: \"success\",\n data: {\n\t\t\t\t\t\t\tenvFile: envPath,\n\t\t\t\t\t\t\tapiKeyId: result.credentials.apiKeyId,\n\t\t\t\t\t\t\tapiKeyPreview: result.credentials.apiKeyPreview,\n\t\t\t\t\t\t\twebhookId: result.credentials.webhookId,\n\t\t\t\t\t\t\twebhookSecret: result.credentials.webhookSecret,\n\t\t\t\t\t\t\twebhookUrl: result.credentials.webhookUrl,\n\t\t\t\t\t\t\torganizationId: result.credentials.organizationId,\n\t\t\t\t\t\t\tmnemonic: updates.MDK_MNEMONIC,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tnull,\n\t\t\t\t\t2,\n ),\n );\n } else {\n p.outro(\n [\n \"Authorized successfully!\",\n `• Credentials written to ${envPath}`,\n `• Webhook ID: ${result.credentials.webhookId}`,\n `• Organization: ${result.credentials.organizationId}`,\n flags.noClipboard\n ? \"Clipboard copy skipped (--no-clipboard).\"\n : \"Secrets copied to clipboard.\",\n \"Return to your project and continue development.\",\n ].join(\"\\n\"),\n );\n }\n\n return summary;\n\t} catch (error) {\n\t\tif (jsonMode) {\n\t\t\tconsole.error(\n\t\t\t\tJSON.stringify(\n\t\t\t\t\t{\n\t\t\t\t\t\tstatus: \"error\",\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\terror instanceof Error ? error.message : String(error),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tnull,\n\t\t\t\t\t2,\n\t\t\t\t),\n\t\t\t);\n\t\t} else {\n\t\t\tp.cancel(\n\t\t\t\terror instanceof Error ? error.message : `Unexpected error: ${error}`,\n\t\t\t);\n\t\t}\n\t\tprocess.exit(1);\n\t}\n}\n\nvoid main();\n","import path from \"node:path\";\n\nexport type EnvTargetResolution = {\n projectDir: string;\n envFile: string;\n providedExplicitly: boolean;\n};\n\nexport function resolveEnvTarget(options: {\n explicitTarget?: string;\n overrideTarget?: string;\n cwd: string;\n defaultFilename: string;\n}): EnvTargetResolution {\n const { explicitTarget, overrideTarget, cwd, defaultFilename } = options;\n const rawTarget = explicitTarget ?? overrideTarget ?? defaultFilename;\n const hasPathSeparator = rawTarget.includes(\"/\") || rawTarget.includes(\"\\\\\");\n\n let projectDir = cwd;\n let envFile = path.basename(rawTarget);\n let providedExplicitly = Boolean(explicitTarget);\n\n if (path.isAbsolute(rawTarget)) {\n projectDir = path.dirname(rawTarget);\n envFile = path.basename(rawTarget);\n providedExplicitly = true;\n } else if (hasPathSeparator) {\n const relativeDir = path.dirname(rawTarget);\n if (relativeDir && relativeDir !== \".\" && relativeDir !== \"\") {\n projectDir = path.resolve(cwd, relativeDir);\n envFile = path.basename(rawTarget);\n providedExplicitly = true;\n }\n }\n\n return {\n projectDir: path.resolve(projectDir),\n envFile,\n providedExplicitly,\n };\n}\n\nexport function deriveProjectName(input: string | undefined, webhookUrl: string): string {\n const trimmed = input?.trim();\n if (trimmed) {\n return trimmed;\n }\n return webhookUrl;\n}\n"],"mappings":"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","names":["path","path","spinner","credentials","mnemonic"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@moneydevkit/create",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Interactive CLI for bootstrapping Money Dev Kit credentials.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsup src/index.ts --dts --format esm,cjs --clean",
|
|
14
|
+
"dev": "tsup src/index.ts --watch --format esm,cjs --dts",
|
|
15
|
+
"lint": "eslint \"src/**/*.{ts,tsx}\"",
|
|
16
|
+
"typecheck": "tsc --noEmit",
|
|
17
|
+
"run:local": "npm run build && node dist/index.js --base-url http://localhost:3900",
|
|
18
|
+
"prepublishOnly": "npm run build",
|
|
19
|
+
"test": "node --test --loader ts-node/esm src/**/*.test.ts"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@clack/prompts": "^0.10.0",
|
|
23
|
+
"@moneydevkit/api-contract": "^0.1.11",
|
|
24
|
+
"@moneydevkit/lightning-js": "^0.1.46",
|
|
25
|
+
"@orpc/client": "^1.3.0",
|
|
26
|
+
"@orpc/contract": "^1.3.0",
|
|
27
|
+
"bip39": "^3.1.0",
|
|
28
|
+
"clipboardy": "^4.0.0",
|
|
29
|
+
"minimist": "^1.2.8",
|
|
30
|
+
"open": "^10.1.0",
|
|
31
|
+
"set-cookie-parser": "^2.6.0",
|
|
32
|
+
"undici": "^7.16.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@eslint/eslintrc": "^3.1.0",
|
|
36
|
+
"@eslint/js": "^9.15.0",
|
|
37
|
+
"@types/minimist": "^1.2.5",
|
|
38
|
+
"@types/node": "^22.9.0",
|
|
39
|
+
"@types/set-cookie-parser": "^2.4.10",
|
|
40
|
+
"@typescript-eslint/eslint-plugin": "^8.12.2",
|
|
41
|
+
"@typescript-eslint/parser": "^8.12.2",
|
|
42
|
+
"eslint": "^9.15.0",
|
|
43
|
+
"ts-node": "^10.9.2",
|
|
44
|
+
"tsup": "^8.4.0",
|
|
45
|
+
"typescript": "^5.6.3"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=18"
|
|
49
|
+
},
|
|
50
|
+
"license": "Apache-2.0",
|
|
51
|
+
"repository": {
|
|
52
|
+
"type": "git",
|
|
53
|
+
"url": "git+https://github.com/moneydevkit/nextjs.git",
|
|
54
|
+
"directory": "packages/create"
|
|
55
|
+
},
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public"
|
|
58
|
+
},
|
|
59
|
+
"keywords": [
|
|
60
|
+
"moneydevkit",
|
|
61
|
+
"lightning",
|
|
62
|
+
"cli"
|
|
63
|
+
]
|
|
64
|
+
}
|