aios-dashboard 0.2.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/LICENSE +25 -0
- package/README.md +91 -0
- package/bin/aios-dashboard.mjs +17 -0
- package/lib/connect.mjs +559 -0
- package/lib/env.mjs +111 -0
- package/lib/installer.mjs +698 -0
- package/lib/lifecycle.mjs +500 -0
- package/lib/pairing.mjs +107 -0
- package/lib/paths.mjs +104 -0
- package/lib/prerequisites.mjs +183 -0
- package/lib/service.mjs +141 -0
- package/lib/source.mjs +245 -0
- package/lib/tunnel.mjs +250 -0
- package/lib/zip.mjs +277 -0
- package/package.json +36 -0
package/lib/env.mjs
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
const KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
2
|
+
|
|
3
|
+
export function parseEnv(text) {
|
|
4
|
+
const values = {};
|
|
5
|
+
for (const line of String(text || "").split(/\r?\n/)) {
|
|
6
|
+
const match = line.match(
|
|
7
|
+
/^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)\s*$/,
|
|
8
|
+
);
|
|
9
|
+
if (!match) continue;
|
|
10
|
+
let value = match[2];
|
|
11
|
+
if (
|
|
12
|
+
value.length >= 2 &&
|
|
13
|
+
((value.startsWith('"') && value.endsWith('"')) ||
|
|
14
|
+
(value.startsWith("'") && value.endsWith("'")))
|
|
15
|
+
) {
|
|
16
|
+
const quote = value[0];
|
|
17
|
+
value = value.slice(1, -1);
|
|
18
|
+
if (quote === '"') {
|
|
19
|
+
value = value
|
|
20
|
+
.replace(/\\n/g, "\n")
|
|
21
|
+
.replace(/\\r/g, "\r")
|
|
22
|
+
.replace(/\\"/g, '"')
|
|
23
|
+
.replace(/\\\\/g, "\\");
|
|
24
|
+
}
|
|
25
|
+
} else {
|
|
26
|
+
value = value.replace(/\s+#.*$/, "").trim();
|
|
27
|
+
}
|
|
28
|
+
values[match[1]] = value;
|
|
29
|
+
}
|
|
30
|
+
return values;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function envKeys(text) {
|
|
34
|
+
const keys = new Set();
|
|
35
|
+
for (const line of String(text || "").split(/\r?\n/)) {
|
|
36
|
+
const match = line.match(/^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/);
|
|
37
|
+
if (match) keys.add(match[1]);
|
|
38
|
+
}
|
|
39
|
+
return keys;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function formatEnvValue(value) {
|
|
43
|
+
const text = String(value ?? "");
|
|
44
|
+
if (/^[A-Za-z0-9_./:@%+?&=,\\-]*$/.test(text)) return text;
|
|
45
|
+
return JSON.stringify(text);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function replaceLastAssignment(text, key, value) {
|
|
49
|
+
const parts = String(text).split(/(\r?\n)/);
|
|
50
|
+
const pattern = new RegExp(`^(\\s*(?:export\\s+)?${key}\\s*=\\s*).*$`);
|
|
51
|
+
let lastIndex = -1;
|
|
52
|
+
let prefix = "";
|
|
53
|
+
for (let index = 0; index < parts.length; index += 2) {
|
|
54
|
+
const match = parts[index].match(pattern);
|
|
55
|
+
if (match) {
|
|
56
|
+
lastIndex = index;
|
|
57
|
+
prefix = match[1];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (lastIndex >= 0) parts[lastIndex] = `${prefix}${formatEnvValue(value)}`;
|
|
61
|
+
return parts.join("");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function mergeEnv(existing, additions, { replaceBlankKeys = [] } = {}) {
|
|
65
|
+
const present = envKeys(existing);
|
|
66
|
+
const parsed = parseEnv(existing);
|
|
67
|
+
const replaceBlank = new Set(replaceBlankKeys);
|
|
68
|
+
let baseText = String(existing || "");
|
|
69
|
+
const lines = [];
|
|
70
|
+
for (const [key, value] of Object.entries(additions)) {
|
|
71
|
+
if (!KEY_PATTERN.test(key))
|
|
72
|
+
throw new Error(`Invalid environment key: ${key}`);
|
|
73
|
+
if (value === undefined || value === null) continue;
|
|
74
|
+
if (present.has(key)) {
|
|
75
|
+
if (
|
|
76
|
+
replaceBlank.has(key) &&
|
|
77
|
+
parsed[key] === "" &&
|
|
78
|
+
String(value).trim() !== ""
|
|
79
|
+
) {
|
|
80
|
+
baseText = replaceLastAssignment(baseText, key, value);
|
|
81
|
+
}
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
lines.push(`${key}=${formatEnvValue(value)}`);
|
|
85
|
+
}
|
|
86
|
+
if (lines.length === 0) return baseText;
|
|
87
|
+
const base = baseText.replace(/\s*$/, "");
|
|
88
|
+
return `${base ? `${base}\n\n` : ""}# Added by aios-dashboard init\n${lines.join("\n")}\n`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function installerEnv({ workspace, databaseUrl }) {
|
|
92
|
+
return {
|
|
93
|
+
AIOS_ROOT: workspace,
|
|
94
|
+
AIOS_MODE: "local",
|
|
95
|
+
...(databaseUrl ? { AIOS_DASHBOARD_DB_URL: databaseUrl } : {}),
|
|
96
|
+
AUTH_DISABLED: "true",
|
|
97
|
+
PORT: "8080",
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function redactDatabaseUrl(value) {
|
|
102
|
+
if (!value) return "not set";
|
|
103
|
+
try {
|
|
104
|
+
const parsed = new URL(value);
|
|
105
|
+
// Install plans need only identify the server/database. Userinfo, query
|
|
106
|
+
// parameters, and fragments can all carry credentials or TLS key material.
|
|
107
|
+
return `${parsed.protocol}//${parsed.host}${parsed.pathname}`;
|
|
108
|
+
} catch {
|
|
109
|
+
return "configured (value hidden)";
|
|
110
|
+
}
|
|
111
|
+
}
|