runcloud 0.1.8 → 0.1.10
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 +31 -3
- package/dist/api.js +2 -1
- package/dist/commands/boxAccess.js +127 -89
- package/dist/commands/environment.js +1 -1
- package/dist/commands/login.js +149 -14
- package/dist/commands/run-cloud.js +2 -2
- package/dist/commands/sandbox.js +200 -68
- package/dist/config.js +6 -10
- package/dist/deviceLogin.js +48 -0
- package/dist/prompt.js +150 -0
- package/dist/run-cloud.js +2 -3
- package/dist/runCloudAuth.js +79 -0
- package/dist/{environmentShell.js → shellSession.js} +17 -3
- package/dist/version.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const SESSION_TOKEN_HEADER = 'set-auth-token';
|
|
2
|
+
export class AuthError extends Error {
|
|
3
|
+
status;
|
|
4
|
+
constructor(message, status) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.status = status;
|
|
7
|
+
this.name = 'AuthError';
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function apiBase(apiUrl) {
|
|
11
|
+
return apiUrl.replace(/\/+$/, '');
|
|
12
|
+
}
|
|
13
|
+
async function readError(response) {
|
|
14
|
+
const body = await response.text();
|
|
15
|
+
try {
|
|
16
|
+
const parsed = JSON.parse(body);
|
|
17
|
+
return parsed.error ?? parsed.message ?? body.slice(0, 200);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return body.slice(0, 200) || response.statusText;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
async function post(apiUrl, path, body, token) {
|
|
24
|
+
const response = await fetch(`${apiBase(apiUrl)}${path}`, {
|
|
25
|
+
method: 'POST',
|
|
26
|
+
headers: {
|
|
27
|
+
'content-type': 'application/json',
|
|
28
|
+
...(token ? { authorization: `Bearer ${token}` } : {}),
|
|
29
|
+
},
|
|
30
|
+
body: JSON.stringify(body),
|
|
31
|
+
});
|
|
32
|
+
if (!response.ok)
|
|
33
|
+
throw new AuthError(await readError(response), response.status);
|
|
34
|
+
const sessionToken = response.headers.get(SESSION_TOKEN_HEADER);
|
|
35
|
+
const text = await response.text();
|
|
36
|
+
const data = (text ? JSON.parse(text) : {});
|
|
37
|
+
return { data, sessionToken: sessionToken?.trim() || null };
|
|
38
|
+
}
|
|
39
|
+
export async function fetchProviders(apiUrl) {
|
|
40
|
+
const response = await fetch(`${apiBase(apiUrl)}/auth/web/providers`);
|
|
41
|
+
if (!response.ok)
|
|
42
|
+
throw new AuthError(await readError(response), response.status);
|
|
43
|
+
const payload = (await response.json());
|
|
44
|
+
return {
|
|
45
|
+
emailOtp: payload.emailOtp === true,
|
|
46
|
+
google: payload.google === true,
|
|
47
|
+
github: payload.github === true,
|
|
48
|
+
apple: payload.apple === true,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export async function sendEmailCode(apiUrl, email) {
|
|
52
|
+
await post(apiUrl, '/api/auth/email-otp/send-verification-otp', { email, type: 'sign-in' });
|
|
53
|
+
}
|
|
54
|
+
export async function verifyEmailCode(apiUrl, email, otp) {
|
|
55
|
+
const { data, sessionToken } = await post(apiUrl, '/api/auth/sign-in/email-otp', { email, otp, name: email.split('@')[0] || 'Run Cloud user' });
|
|
56
|
+
if (!sessionToken) {
|
|
57
|
+
throw new AuthError(`${apiUrl} accepted the code but did not return a session token.`, 502);
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
user: { id: data.user?.id ?? '', email: data.user?.email ?? email },
|
|
61
|
+
sessionToken,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export async function createApiKey(apiUrl, sessionToken, name) {
|
|
65
|
+
const { data } = await post(apiUrl, '/run-cloud/api-keys', { name }, sessionToken);
|
|
66
|
+
const key = data.apiKey?.key;
|
|
67
|
+
if (!key)
|
|
68
|
+
throw new AuthError(`${apiUrl} did not return an API key.`, 502);
|
|
69
|
+
return key;
|
|
70
|
+
}
|
|
71
|
+
export function isValidEmail(value) {
|
|
72
|
+
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value.trim());
|
|
73
|
+
}
|
|
74
|
+
export function normalizeOtp(value) {
|
|
75
|
+
return value.replace(/[\s-]/g, '');
|
|
76
|
+
}
|
|
77
|
+
export function isValidOtp(value) {
|
|
78
|
+
return /^\d{6}$/.test(normalizeOtp(value));
|
|
79
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import WebSocket from 'ws';
|
|
2
|
-
export async function
|
|
2
|
+
export async function runShellSession(input) {
|
|
3
3
|
const stdin = input.stdin ?? process.stdin;
|
|
4
4
|
const stdout = input.stdout ?? process.stdout;
|
|
5
5
|
const stderr = input.stderr ?? process.stderr;
|
|
6
|
-
const url = new URL(
|
|
6
|
+
const url = new URL(input.path, input.apiUrl);
|
|
7
7
|
url.protocol = url.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
8
8
|
const createWebSocket = input.createWebSocket ?? ((address, options) => new WebSocket(address, options));
|
|
9
9
|
const socket = createWebSocket(url.toString(), {
|
|
@@ -60,7 +60,7 @@ export async function runEnvironmentDatabaseShell(input) {
|
|
|
60
60
|
socket.once('close', (code, reason) => {
|
|
61
61
|
restore();
|
|
62
62
|
if (code >= 4400) {
|
|
63
|
-
reject(new Error(reason.toString() ||
|
|
63
|
+
reject(new Error(reason.toString() || `${input.label} rejected (${code})`));
|
|
64
64
|
}
|
|
65
65
|
else {
|
|
66
66
|
resolve(exitCode);
|
|
@@ -68,3 +68,17 @@ export async function runEnvironmentDatabaseShell(input) {
|
|
|
68
68
|
});
|
|
69
69
|
});
|
|
70
70
|
}
|
|
71
|
+
export function runEnvironmentDatabaseShell(input) {
|
|
72
|
+
return runShellSession({
|
|
73
|
+
...input,
|
|
74
|
+
path: `/environment-databases/${encodeURIComponent(input.databaseId)}/shell`,
|
|
75
|
+
label: 'Database shell',
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
export function runSandboxShell(input) {
|
|
79
|
+
return runShellSession({
|
|
80
|
+
...input,
|
|
81
|
+
path: `/run-cloud/sandboxes/${encodeURIComponent(input.sandboxId)}/exec/stream`,
|
|
82
|
+
label: 'Sandbox shell',
|
|
83
|
+
});
|
|
84
|
+
}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const CLI_VERSION = '0.1.10';
|