@remotedraw/cli 0.1.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.
@@ -0,0 +1,63 @@
1
+ export declare const DEFAULT_REMOTEDRAW_API_BASE_URL = "https://api.remotedraw.com";
2
+ export type CloudRuntime = {
3
+ env: Record<string, string | undefined>;
4
+ isInteractive?: boolean;
5
+ fetch?: typeof fetch;
6
+ exists: (filePath: string) => boolean | Promise<boolean>;
7
+ readFile: (filePath: string) => Promise<string>;
8
+ writeFile: (filePath: string, contents: string) => Promise<void>;
9
+ writePrivateFile?: (filePath: string, contents: string) => Promise<void>;
10
+ mkdir: (dirPath: string) => Promise<void>;
11
+ chmod?: (filePath: string, mode: number) => Promise<void>;
12
+ homeDir?: string;
13
+ openUrl?: (url: string) => void | Promise<void>;
14
+ sleep?: (milliseconds: number) => Promise<void>;
15
+ notify?: (message: string) => void;
16
+ };
17
+ type CliAccount = {
18
+ userId: string;
19
+ tenantId: string;
20
+ tenantSlug: string;
21
+ name?: string;
22
+ email?: string;
23
+ credentialName?: string;
24
+ expiresAt?: number;
25
+ };
26
+ export type ProvisionedProject = {
27
+ project: {
28
+ id: string;
29
+ name: string;
30
+ slug: string;
31
+ source: "cli";
32
+ dashboardUrl: string;
33
+ };
34
+ apiKey: {
35
+ id: string;
36
+ name: string;
37
+ value: string;
38
+ };
39
+ apiBaseUrl: string;
40
+ };
41
+ export declare function remoteDrawApiBaseUrl(env: Record<string, string | undefined>, requested?: string): string;
42
+ export declare function globalConfigPath(runtime: CloudRuntime): string;
43
+ export declare function currentCliAccount(runtime: CloudRuntime, apiBaseUrl: string): Promise<CliAccount | undefined>;
44
+ export declare function loginToRemoteDraw(runtime: CloudRuntime, apiBaseUrl: string, options?: {
45
+ openBrowser?: boolean;
46
+ force?: boolean;
47
+ deviceName?: string;
48
+ }): Promise<{
49
+ account: CliAccount;
50
+ alreadyLoggedIn: boolean;
51
+ }>;
52
+ export declare function logoutFromRemoteDraw(runtime: CloudRuntime, apiBaseUrl: string): Promise<{
53
+ hadCredential: boolean;
54
+ }>;
55
+ export declare function provisionRemoteDrawProject(runtime: CloudRuntime, apiBaseUrl: string, input: {
56
+ name: string;
57
+ keyName?: string;
58
+ }): Promise<ProvisionedProject>;
59
+ export declare function updateEnvContents(contents: string, values: Record<string, string>, force?: boolean): string;
60
+ export declare function assertEnvCanAcceptProvisioning(runtime: CloudRuntime, outputDir: string, apiBaseUrl: string, force: boolean): Promise<void>;
61
+ export declare function writeProvisionedProjectSetup(runtime: CloudRuntime, outputDir: string, provisioning: ProvisionedProject, force: boolean): Promise<void>;
62
+ export {};
63
+ //# sourceMappingURL=cloud.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud.d.ts","sourceRoot":"","sources":["../src/cloud.ts"],"names":[],"mappings":"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"}
package/dist/cloud.js ADDED
@@ -0,0 +1,302 @@
1
+ import { homedir } from "node:os";
2
+ import path from "node:path";
3
+ export const DEFAULT_REMOTEDRAW_API_BASE_URL = "https://api.remotedraw.com";
4
+ function normalizedOrigin(value) {
5
+ const url = new URL(value.trim());
6
+ if ((url.protocol !== "https:" && url.protocol !== "http:") ||
7
+ url.username ||
8
+ url.password ||
9
+ url.pathname !== "/" ||
10
+ url.search ||
11
+ url.hash) {
12
+ throw new Error(`Expected an HTTP API origin, received ${value}.`);
13
+ }
14
+ return url.origin;
15
+ }
16
+ export function remoteDrawApiBaseUrl(env, requested) {
17
+ const value = requested && !requested.includes("<deployment>")
18
+ ? requested
19
+ : env.REMOTEDRAW_API_BASE_URL || DEFAULT_REMOTEDRAW_API_BASE_URL;
20
+ return normalizedOrigin(value);
21
+ }
22
+ export function globalConfigPath(runtime) {
23
+ const explicit = runtime.env.REMOTEDRAW_CONFIG_DIR?.trim();
24
+ const configRoot = explicit ||
25
+ runtime.env.XDG_CONFIG_HOME?.trim() ||
26
+ path.join(runtime.homeDir || homedir(), ".config");
27
+ return path.join(configRoot, "remotedraw", "config.json");
28
+ }
29
+ function isRecord(value) {
30
+ return typeof value === "object" && value !== null && !Array.isArray(value);
31
+ }
32
+ async function readStoredConfig(runtime) {
33
+ const configPath = globalConfigPath(runtime);
34
+ if (!(await runtime.exists(configPath))) {
35
+ return { version: 1, activeApiBaseUrl: "", profiles: {} };
36
+ }
37
+ try {
38
+ const parsed = JSON.parse(await runtime.readFile(configPath));
39
+ if (!isRecord(parsed) || !isRecord(parsed.profiles))
40
+ throw new Error();
41
+ const profiles = {};
42
+ for (const [origin, value] of Object.entries(parsed.profiles)) {
43
+ if (!isRecord(value) || typeof value.cliToken !== "string")
44
+ continue;
45
+ profiles[origin] = {
46
+ apiBaseUrl: typeof value.apiBaseUrl === "string" ? value.apiBaseUrl : origin,
47
+ cliToken: value.cliToken,
48
+ ...(isRecord(value.account)
49
+ ? { account: value.account }
50
+ : {}),
51
+ ...(typeof value.expiresAt === "number"
52
+ ? { expiresAt: value.expiresAt }
53
+ : {}),
54
+ };
55
+ }
56
+ return {
57
+ version: 1,
58
+ activeApiBaseUrl: typeof parsed.activeApiBaseUrl === "string"
59
+ ? parsed.activeApiBaseUrl
60
+ : "",
61
+ profiles,
62
+ };
63
+ }
64
+ catch {
65
+ throw new Error(`Could not read RemoteDraw CLI credentials from ${configPath}. Remove or repair that file.`);
66
+ }
67
+ }
68
+ async function writeStoredConfig(runtime, config) {
69
+ const configPath = globalConfigPath(runtime);
70
+ await runtime.mkdir(path.dirname(configPath));
71
+ await runtime.chmod?.(path.dirname(configPath), 0o700);
72
+ await writePrivateFile(runtime, configPath, JSON.stringify(config, null, 2) + "\n");
73
+ }
74
+ async function writePrivateFile(runtime, filePath, contents) {
75
+ if (runtime.writePrivateFile) {
76
+ await runtime.writePrivateFile(filePath, contents);
77
+ }
78
+ else {
79
+ await runtime.writeFile(filePath, contents);
80
+ }
81
+ await runtime.chmod?.(filePath, 0o600);
82
+ }
83
+ async function storedToken(runtime, apiBaseUrl) {
84
+ const envToken = runtime.env.REMOTEDRAW_CLI_TOKEN?.trim();
85
+ if (envToken)
86
+ return envToken;
87
+ const config = await readStoredConfig(runtime);
88
+ return config.profiles[apiBaseUrl]?.cliToken;
89
+ }
90
+ async function fetchJson(runtime, apiBaseUrl, pathname, options = {}) {
91
+ if (!runtime.fetch)
92
+ throw new Error("This runtime cannot access RemoteDraw.");
93
+ let response;
94
+ try {
95
+ response = await runtime.fetch(`${apiBaseUrl}${pathname}`, {
96
+ method: "POST",
97
+ headers: {
98
+ "Content-Type": "application/json",
99
+ ...(options.token ? { Authorization: `Bearer ${options.token}` } : {}),
100
+ },
101
+ body: JSON.stringify(options.body ?? {}),
102
+ });
103
+ }
104
+ catch (error) {
105
+ throw new Error(`Could not reach ${apiBaseUrl}: ${error instanceof Error ? error.message : String(error)}`);
106
+ }
107
+ const raw = await response.text();
108
+ let payload;
109
+ try {
110
+ payload = raw ? JSON.parse(raw) : {};
111
+ }
112
+ catch {
113
+ if (response.status === 404) {
114
+ throw new Error(`RemoteDraw CLI endpoint ${pathname} was not found at ${apiBaseUrl}. Set REMOTEDRAW_API_BASE_URL to a deployment with the latest CLI auth functions.`);
115
+ }
116
+ throw new Error(`RemoteDraw returned an invalid response (${response.status}).`);
117
+ }
118
+ if (!response.ok) {
119
+ const message = isRecord(payload) &&
120
+ isRecord(payload.error) &&
121
+ typeof payload.error.message === "string"
122
+ ? payload.error.message
123
+ : `RemoteDraw request failed (${response.status}).`;
124
+ throw new Error(message);
125
+ }
126
+ return payload;
127
+ }
128
+ export async function currentCliAccount(runtime, apiBaseUrl) {
129
+ const token = await storedToken(runtime, apiBaseUrl);
130
+ if (!token)
131
+ return undefined;
132
+ return await fetchJson(runtime, apiBaseUrl, "/v1/cli/auth/current", { token });
133
+ }
134
+ export async function loginToRemoteDraw(runtime, apiBaseUrl, options = {}) {
135
+ const normalized = normalizedOrigin(apiBaseUrl);
136
+ if (!options.force) {
137
+ try {
138
+ const account = await currentCliAccount(runtime, normalized);
139
+ if (account)
140
+ return { account, alreadyLoggedIn: true };
141
+ }
142
+ catch {
143
+ // An expired or revoked stored token is replaced by the new login below.
144
+ }
145
+ }
146
+ const request = await fetchJson(runtime, normalized, "/v1/cli/auth/start", {
147
+ body: { deviceName: options.deviceName ?? "RemoteDraw CLI" },
148
+ });
149
+ runtime.notify?.(`Authorize this CLI at ${request.verificationUrl}\nConfirmation code: ${request.userCode}`);
150
+ if (options.openBrowser !== false && runtime.openUrl) {
151
+ try {
152
+ await runtime.openUrl(request.verificationUrl);
153
+ runtime.notify?.("Opened the browser. Waiting for authorization...");
154
+ }
155
+ catch {
156
+ runtime.notify?.("Could not open the browser automatically; use the URL above.");
157
+ }
158
+ }
159
+ const sleep = runtime.sleep ??
160
+ ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
161
+ while (Date.now() < request.expiresAt) {
162
+ await sleep(Math.max(500, request.intervalMs));
163
+ const result = await fetchJson(runtime, normalized, "/v1/cli/auth/token", {
164
+ body: { deviceCode: request.deviceCode },
165
+ });
166
+ if (result.status === "pending")
167
+ continue;
168
+ if (result.status !== "authorized") {
169
+ throw new Error(`CLI authorization ${result.status}. Run remotedraw login again.`);
170
+ }
171
+ const config = await readStoredConfig(runtime);
172
+ config.activeApiBaseUrl = normalized;
173
+ config.profiles[normalized] = {
174
+ apiBaseUrl: normalized,
175
+ cliToken: result.cliToken,
176
+ account: result.account,
177
+ expiresAt: result.expiresAt,
178
+ };
179
+ await writeStoredConfig(runtime, config);
180
+ return { account: result.account, alreadyLoggedIn: false };
181
+ }
182
+ throw new Error("CLI authorization expired. Run remotedraw login again.");
183
+ }
184
+ export async function logoutFromRemoteDraw(runtime, apiBaseUrl) {
185
+ const normalized = normalizedOrigin(apiBaseUrl);
186
+ const token = await storedToken(runtime, normalized);
187
+ if (token) {
188
+ try {
189
+ await fetchJson(runtime, normalized, "/v1/cli/auth/revoke", { token });
190
+ }
191
+ catch {
192
+ // Local logout still removes an expired or already-revoked credential.
193
+ }
194
+ }
195
+ if (!runtime.env.REMOTEDRAW_CLI_TOKEN) {
196
+ const config = await readStoredConfig(runtime);
197
+ delete config.profiles[normalized];
198
+ if (config.activeApiBaseUrl === normalized) {
199
+ config.activeApiBaseUrl = Object.keys(config.profiles)[0] ?? "";
200
+ }
201
+ await writeStoredConfig(runtime, config);
202
+ }
203
+ return { hadCredential: Boolean(token) };
204
+ }
205
+ export async function provisionRemoteDrawProject(runtime, apiBaseUrl, input) {
206
+ const normalized = normalizedOrigin(apiBaseUrl);
207
+ let token = await storedToken(runtime, normalized);
208
+ if (!token) {
209
+ if (!runtime.env.REMOTEDRAW_CLI_TOKEN &&
210
+ runtime.isInteractive &&
211
+ runtime.openUrl) {
212
+ await loginToRemoteDraw(runtime, normalized);
213
+ token = await storedToken(runtime, normalized);
214
+ }
215
+ }
216
+ if (!token) {
217
+ throw new Error("Not logged in. Run remotedraw login, or set REMOTEDRAW_CLI_TOKEN for non-interactive use.");
218
+ }
219
+ return await fetchJson(runtime, normalized, "/v1/cli/projects", { body: input, token });
220
+ }
221
+ function envAssignment(contents, name) {
222
+ const line = contents
223
+ .split(/\r?\n/)
224
+ .find((candidate) => new RegExp(`^\\s*(?:export\\s+)?${name}\\s*=`).test(candidate));
225
+ if (!line)
226
+ return undefined;
227
+ return line
228
+ .slice(line.indexOf("=") + 1)
229
+ .trim()
230
+ .replace(/^(['"])(.*)\1$/, "$2");
231
+ }
232
+ function isReplaceableEnvValue(name, value) {
233
+ if (!value)
234
+ return true;
235
+ if (value.includes("replace_me") || value.includes("<deployment>"))
236
+ return true;
237
+ if (name === "REMOTEDRAW_API_KEY" && value === "rd_sk_...")
238
+ return true;
239
+ return false;
240
+ }
241
+ export function updateEnvContents(contents, values, force = false) {
242
+ let next = contents;
243
+ for (const [name, value] of Object.entries(values)) {
244
+ const existing = envAssignment(next, name);
245
+ if (existing != null &&
246
+ existing !== value &&
247
+ !isReplaceableEnvValue(name, existing) &&
248
+ !force) {
249
+ throw new Error(`${name} is already set in .env.local. Pass --force to replace it or use --offline to keep setup local-only.`);
250
+ }
251
+ const pattern = new RegExp(`^\\s*(?:export\\s+)?${name}\\s*=.*$`, "m");
252
+ if (pattern.test(next)) {
253
+ next = next.replace(pattern, `${name}=${value}`);
254
+ }
255
+ else {
256
+ if (next && !next.endsWith("\n"))
257
+ next += "\n";
258
+ next += `${name}=${value}\n`;
259
+ }
260
+ }
261
+ return next;
262
+ }
263
+ export async function assertEnvCanAcceptProvisioning(runtime, outputDir, apiBaseUrl, force) {
264
+ const envPath = path.join(outputDir, ".env.local");
265
+ const contents = (await runtime.exists(envPath))
266
+ ? await runtime.readFile(envPath)
267
+ : "";
268
+ updateEnvContents(contents, {
269
+ REMOTEDRAW_API_BASE_URL: apiBaseUrl,
270
+ REMOTEDRAW_PROJECT_ID: "__pending__",
271
+ REMOTEDRAW_API_KEY: "rd_sk_replace_me",
272
+ }, force);
273
+ }
274
+ export async function writeProvisionedProjectSetup(runtime, outputDir, provisioning, force) {
275
+ const envPath = path.join(outputDir, ".env.local");
276
+ const envContents = (await runtime.exists(envPath))
277
+ ? await runtime.readFile(envPath)
278
+ : "# Generated by RemoteDraw CLI. Server-side secrets only.\n";
279
+ const nextEnv = updateEnvContents(envContents, {
280
+ REMOTEDRAW_API_BASE_URL: provisioning.apiBaseUrl,
281
+ REMOTEDRAW_PROJECT_ID: provisioning.project.id,
282
+ REMOTEDRAW_API_KEY: provisioning.apiKey.value,
283
+ }, force);
284
+ await writePrivateFile(runtime, envPath, nextEnv);
285
+ const configPath = path.join(outputDir, "remotedraw.config.json");
286
+ const config = JSON.parse(await runtime.readFile(configPath));
287
+ config.apiBaseUrl = provisioning.apiBaseUrl;
288
+ config.cloud = {
289
+ projectId: provisioning.project.id,
290
+ apiKeyId: provisioning.apiKey.id,
291
+ dashboardUrl: provisioning.project.dashboardUrl,
292
+ };
293
+ await runtime.writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
294
+ const gitignorePath = path.join(outputDir, ".gitignore");
295
+ const gitignore = (await runtime.exists(gitignorePath))
296
+ ? await runtime.readFile(gitignorePath)
297
+ : "";
298
+ if (!gitignore.split(/\r?\n/).includes(".env.local")) {
299
+ const prefix = gitignore && !gitignore.endsWith("\n") ? `${gitignore}\n` : gitignore;
300
+ await runtime.writeFile(gitignorePath, `${prefix}.env.local\n`);
301
+ }
302
+ }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import { pathToFileURL } from "node:url";
3
+ import { createNodeRuntime, runCli } from "./cli.js";
4
+ if (process.argv[1] &&
5
+ import.meta.url === pathToFileURL(process.argv[1]).href) {
6
+ const result = await runCli(process.argv.slice(2), createNodeRuntime());
7
+ if (result.stdout)
8
+ process.stdout.write(result.stdout);
9
+ if (result.stderr)
10
+ process.stderr.write(result.stderr);
11
+ process.exitCode = result.exitCode;
12
+ }
@@ -0,0 +1,122 @@
1
+ export type WizardFieldKey = "appName" | "target" | "sender" | "sdk" | "preset" | "packageManager" | "apiEndpoint";
2
+ export type WizardValues = Record<WizardFieldKey, string>;
3
+ export type WizardChoice = {
4
+ value: string;
5
+ label: string;
6
+ hint?: string;
7
+ details?: WizardChoiceDetails;
8
+ };
9
+ export type WizardChoiceDetails = {
10
+ summary: string;
11
+ explanation: string;
12
+ docsUrl: string;
13
+ docsLabel: string;
14
+ };
15
+ export type WizardField = {
16
+ key: WizardFieldKey;
17
+ label: string;
18
+ kind: "text" | "select";
19
+ choices?: (values: WizardValues) => readonly WizardChoice[];
20
+ validate?: (value: string) => string | undefined;
21
+ };
22
+ export type WizardDefinition = {
23
+ fields: readonly WizardField[];
24
+ defaults: WizardValues;
25
+ normalize: (values: WizardValues, changed: WizardFieldKey) => WizardValues;
26
+ review: (values: WizardValues) => readonly [string, string][];
27
+ };
28
+ export type WizardScreen = "field" | "review" | "confirm" | "executing" | "success" | "error" | "cancelled" | "interrupted";
29
+ export type WizardState = {
30
+ screen: WizardScreen;
31
+ fieldIndex: number;
32
+ values: WizardValues;
33
+ editedFields: WizardFieldKey[];
34
+ error?: string | undefined;
35
+ confirmCreate: boolean;
36
+ createdPath?: string | undefined;
37
+ nextCommand?: string | undefined;
38
+ };
39
+ export type WizardAction = {
40
+ type: "character";
41
+ value: string;
42
+ } | {
43
+ type: "backspace";
44
+ } | {
45
+ type: "previousChoice";
46
+ } | {
47
+ type: "nextChoice";
48
+ } | {
49
+ type: "forward";
50
+ } | {
51
+ type: "back";
52
+ } | {
53
+ type: "cancel";
54
+ } | {
55
+ type: "interrupt";
56
+ } | {
57
+ type: "executionSucceeded";
58
+ path: string;
59
+ nextCommand: string;
60
+ } | {
61
+ type: "executionFailed";
62
+ message: string;
63
+ };
64
+ export type WizardSemanticView = {
65
+ screen: WizardScreen;
66
+ title: string;
67
+ progress?: {
68
+ current: number;
69
+ total: number;
70
+ } | undefined;
71
+ activeLabel?: string | undefined;
72
+ value?: string | undefined;
73
+ valueIsDefault?: boolean | undefined;
74
+ choices?: readonly WizardChoice[] | undefined;
75
+ selectedChoice?: string | undefined;
76
+ selectedDetails?: WizardChoiceDetails | undefined;
77
+ validation?: string | undefined;
78
+ review?: readonly [string, string][] | undefined;
79
+ controls: readonly string[];
80
+ createdPath?: string | undefined;
81
+ nextCommand?: string | undefined;
82
+ error?: string | undefined;
83
+ };
84
+ export declare function initialWizardState(definition: WizardDefinition): WizardState;
85
+ export declare function transitionWizard(state: WizardState, action: WizardAction, definition: WizardDefinition): WizardState;
86
+ export declare function wizardSemanticView(state: WizardState, definition: WizardDefinition): WizardSemanticView;
87
+ export type WizardKey = {
88
+ name?: string;
89
+ sequence?: string;
90
+ ctrl?: boolean;
91
+ };
92
+ export type WizardTerminal = {
93
+ columns: number;
94
+ color: boolean;
95
+ hyperlinks?: boolean;
96
+ write: (value: string) => void;
97
+ readKey: () => Promise<WizardKey>;
98
+ openUrl?: (url: string) => void | Promise<void>;
99
+ enter: () => void | Promise<void>;
100
+ restore: () => void | Promise<void>;
101
+ };
102
+ export type WizardExecutionResult = {
103
+ path: string;
104
+ nextCommand: string;
105
+ };
106
+ export declare function runSetupWizard(options: {
107
+ definition: WizardDefinition;
108
+ terminal: WizardTerminal;
109
+ execute: (values: WizardValues) => Promise<WizardExecutionResult>;
110
+ }): Promise<{
111
+ exitCode: number;
112
+ state: WizardState;
113
+ }>;
114
+ export declare function actionForKey(key: WizardKey, state: WizardState): WizardAction;
115
+ export declare function renderWizard(state: WizardState, definition: WizardDefinition, terminal: Pick<WizardTerminal, "columns" | "color" | "hyperlinks">, bannerFrame?: number): string;
116
+ type KeypressInput = NodeJS.ReadStream & {
117
+ isRaw?: boolean;
118
+ setRawMode?: (mode: boolean) => KeypressInput;
119
+ };
120
+ export declare function createWizardTerminal(input: KeypressInput, output: NodeJS.WriteStream, env: Record<string, string | undefined>): WizardTerminal;
121
+ export {};
122
+ //# sourceMappingURL=setup-wizard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-wizard.d.ts","sourceRoot":"","sources":["../src/setup-wizard.ts"],"names":[],"mappings":"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"}