@enactprotocol/shared 1.2.11 → 2.0.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 +44 -0
- package/package.json +16 -58
- package/src/config.ts +476 -0
- package/src/constants.ts +36 -0
- package/src/execution/command.ts +314 -0
- package/src/execution/index.ts +73 -0
- package/src/execution/runtime.ts +308 -0
- package/src/execution/types.ts +379 -0
- package/src/execution/validation.ts +508 -0
- package/src/index.ts +237 -30
- package/src/manifest/index.ts +36 -0
- package/src/manifest/loader.ts +187 -0
- package/src/manifest/parser.ts +173 -0
- package/src/manifest/validator.ts +309 -0
- package/src/paths.ts +108 -0
- package/src/registry.ts +219 -0
- package/src/resolver.ts +345 -0
- package/src/types/index.ts +30 -0
- package/src/types/manifest.ts +255 -0
- package/src/types.ts +5 -188
- package/src/utils/fs.ts +281 -0
- package/src/utils/logger.ts +270 -59
- package/src/utils/version.ts +304 -36
- package/tests/config.test.ts +515 -0
- package/tests/execution/command.test.ts +317 -0
- package/tests/execution/validation.test.ts +384 -0
- package/tests/fixtures/invalid-tool.yaml +4 -0
- package/tests/fixtures/valid-tool.md +62 -0
- package/tests/fixtures/valid-tool.yaml +40 -0
- package/tests/index.test.ts +8 -0
- package/tests/manifest/loader.test.ts +291 -0
- package/tests/manifest/parser.test.ts +345 -0
- package/tests/manifest/validator.test.ts +394 -0
- package/tests/manifest-types.test.ts +358 -0
- package/tests/paths.test.ts +153 -0
- package/tests/registry.test.ts +231 -0
- package/tests/resolver.test.ts +272 -0
- package/tests/utils/fs.test.ts +388 -0
- package/tests/utils/logger.test.ts +480 -0
- package/tests/utils/version.test.ts +390 -0
- package/tsconfig.json +12 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/dist/LocalToolResolver.d.ts +0 -84
- package/dist/LocalToolResolver.js +0 -353
- package/dist/api/enact-api.d.ts +0 -130
- package/dist/api/enact-api.js +0 -428
- package/dist/api/index.d.ts +0 -2
- package/dist/api/index.js +0 -2
- package/dist/api/types.d.ts +0 -103
- package/dist/api/types.js +0 -1
- package/dist/constants.d.ts +0 -7
- package/dist/constants.js +0 -10
- package/dist/core/DaggerExecutionProvider.d.ts +0 -169
- package/dist/core/DaggerExecutionProvider.js +0 -1029
- package/dist/core/DirectExecutionProvider.d.ts +0 -23
- package/dist/core/DirectExecutionProvider.js +0 -406
- package/dist/core/EnactCore.d.ts +0 -162
- package/dist/core/EnactCore.js +0 -597
- package/dist/core/NativeExecutionProvider.d.ts +0 -9
- package/dist/core/NativeExecutionProvider.js +0 -16
- package/dist/core/index.d.ts +0 -3
- package/dist/core/index.js +0 -3
- package/dist/exec/index.d.ts +0 -3
- package/dist/exec/index.js +0 -3
- package/dist/exec/logger.d.ts +0 -11
- package/dist/exec/logger.js +0 -57
- package/dist/exec/validate.d.ts +0 -5
- package/dist/exec/validate.js +0 -167
- package/dist/index.d.ts +0 -21
- package/dist/index.js +0 -25
- package/dist/lib/enact-direct.d.ts +0 -150
- package/dist/lib/enact-direct.js +0 -159
- package/dist/lib/index.d.ts +0 -1
- package/dist/lib/index.js +0 -1
- package/dist/security/index.d.ts +0 -3
- package/dist/security/index.js +0 -3
- package/dist/security/security.d.ts +0 -23
- package/dist/security/security.js +0 -137
- package/dist/security/sign.d.ts +0 -103
- package/dist/security/sign.js +0 -666
- package/dist/security/verification-enforcer.d.ts +0 -53
- package/dist/security/verification-enforcer.js +0 -204
- package/dist/services/McpCoreService.d.ts +0 -98
- package/dist/services/McpCoreService.js +0 -124
- package/dist/services/index.d.ts +0 -1
- package/dist/services/index.js +0 -1
- package/dist/types.d.ts +0 -132
- package/dist/types.js +0 -3
- package/dist/utils/config.d.ts +0 -111
- package/dist/utils/config.js +0 -342
- package/dist/utils/env-loader.d.ts +0 -54
- package/dist/utils/env-loader.js +0 -270
- package/dist/utils/help.d.ts +0 -36
- package/dist/utils/help.js +0 -248
- package/dist/utils/index.d.ts +0 -7
- package/dist/utils/index.js +0 -7
- package/dist/utils/logger.d.ts +0 -35
- package/dist/utils/logger.js +0 -75
- package/dist/utils/silent-monitor.d.ts +0 -67
- package/dist/utils/silent-monitor.js +0 -242
- package/dist/utils/timeout.d.ts +0 -5
- package/dist/utils/timeout.js +0 -23
- package/dist/utils/version.d.ts +0 -4
- package/dist/utils/version.js +0 -35
- package/dist/web/env-manager-server.d.ts +0 -29
- package/dist/web/env-manager-server.js +0 -367
- package/dist/web/index.d.ts +0 -1
- package/dist/web/index.js +0 -1
- package/src/LocalToolResolver.ts +0 -424
- package/src/api/enact-api.ts +0 -604
- package/src/api/index.ts +0 -2
- package/src/api/types.ts +0 -114
- package/src/core/DaggerExecutionProvider.ts +0 -1357
- package/src/core/DirectExecutionProvider.ts +0 -484
- package/src/core/EnactCore.ts +0 -847
- package/src/core/index.ts +0 -3
- package/src/exec/index.ts +0 -3
- package/src/exec/logger.ts +0 -63
- package/src/exec/validate.ts +0 -238
- package/src/lib/enact-direct.ts +0 -254
- package/src/lib/index.ts +0 -1
- package/src/services/McpCoreService.ts +0 -201
- package/src/services/index.ts +0 -1
- package/src/utils/config.ts +0 -438
- package/src/utils/env-loader.ts +0 -370
- package/src/utils/help.ts +0 -257
- package/src/utils/index.ts +0 -7
- package/src/utils/silent-monitor.ts +0 -328
- package/src/utils/timeout.ts +0 -26
- package/src/web/env-manager-server.ts +0 -465
- package/src/web/index.ts +0 -1
- package/src/web/static/app.js +0 -663
- package/src/web/static/index.html +0 -117
- package/src/web/static/style.css +0 -291
package/src/web/static/app.js
DELETED
|
@@ -1,663 +0,0 @@
|
|
|
1
|
-
// Enact Environment Manager - Client-side JavaScript
|
|
2
|
-
let currentPackage = null;
|
|
3
|
-
let packages = [];
|
|
4
|
-
|
|
5
|
-
document.addEventListener("DOMContentLoaded", () => {
|
|
6
|
-
loadPackages();
|
|
7
|
-
|
|
8
|
-
// Check URL parameters for bulk variable requests
|
|
9
|
-
checkUrlForVars();
|
|
10
|
-
|
|
11
|
-
// Event listeners
|
|
12
|
-
document
|
|
13
|
-
.getElementById("env-var-form")
|
|
14
|
-
.addEventListener("submit", saveVariable);
|
|
15
|
-
document
|
|
16
|
-
.getElementById("clear-form-btn")
|
|
17
|
-
.addEventListener("click", clearForm);
|
|
18
|
-
document
|
|
19
|
-
.getElementById("create-package-btn")
|
|
20
|
-
.addEventListener("click", createPackage);
|
|
21
|
-
|
|
22
|
-
// Link generator event listeners
|
|
23
|
-
document
|
|
24
|
-
.getElementById("generate-link-btn")
|
|
25
|
-
.addEventListener("click", generateLink);
|
|
26
|
-
document.getElementById("copy-link-btn").addEventListener("click", copyLink);
|
|
27
|
-
|
|
28
|
-
// Modal event listeners
|
|
29
|
-
document
|
|
30
|
-
.getElementById("close-modal")
|
|
31
|
-
.addEventListener("click", closeBulkModal);
|
|
32
|
-
document
|
|
33
|
-
.getElementById("cancel-bulk")
|
|
34
|
-
.addEventListener("click", closeBulkModal);
|
|
35
|
-
document
|
|
36
|
-
.getElementById("bulk-form")
|
|
37
|
-
.addEventListener("submit", saveBulkVariables);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
// Check URL parameters for bulk variable requests
|
|
41
|
-
function checkUrlForVars() {
|
|
42
|
-
const urlParams = new URLSearchParams(window.location.search);
|
|
43
|
-
const varsParam = urlParams.get("vars");
|
|
44
|
-
const packageParam = urlParams.get("package");
|
|
45
|
-
|
|
46
|
-
if (varsParam) {
|
|
47
|
-
try {
|
|
48
|
-
let varsArray;
|
|
49
|
-
// Try to parse as JSON first
|
|
50
|
-
if (varsParam.startsWith("[") && varsParam.endsWith("]")) {
|
|
51
|
-
varsArray = JSON.parse(varsParam);
|
|
52
|
-
} else {
|
|
53
|
-
// Fallback to comma-separated string
|
|
54
|
-
varsArray = varsParam
|
|
55
|
-
.split(",")
|
|
56
|
-
.map((item) => item.trim())
|
|
57
|
-
.filter((item) => item);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (varsArray && varsArray.length > 0) {
|
|
61
|
-
// Set current package if specified
|
|
62
|
-
if (packageParam) {
|
|
63
|
-
currentPackage = packageParam;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Wait for packages to load before opening modal
|
|
67
|
-
setTimeout(() => {
|
|
68
|
-
openBulkModal(varsArray);
|
|
69
|
-
}, 100);
|
|
70
|
-
}
|
|
71
|
-
} catch (error) {
|
|
72
|
-
console.error("Error parsing URL variables:", error);
|
|
73
|
-
showNotification("Invalid variables format in URL", "error");
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Function to open bulk modal with variables
|
|
79
|
-
function openBulkModal(variables) {
|
|
80
|
-
const bulkVariablesContainer = document.getElementById(
|
|
81
|
-
"bulk-variables-container",
|
|
82
|
-
);
|
|
83
|
-
bulkVariablesContainer.innerHTML = "";
|
|
84
|
-
|
|
85
|
-
// Add package selection if no current package is selected
|
|
86
|
-
if (!currentPackage) {
|
|
87
|
-
const packageSelectContainer = document.createElement("div");
|
|
88
|
-
packageSelectContainer.className = "form-group";
|
|
89
|
-
|
|
90
|
-
const packageOptions = packages
|
|
91
|
-
.map(
|
|
92
|
-
(pkg) =>
|
|
93
|
-
`<option value="${escapeHtml(pkg.namespace)}">${escapeHtml(pkg.namespace)}</option>`,
|
|
94
|
-
)
|
|
95
|
-
.join("");
|
|
96
|
-
|
|
97
|
-
packageSelectContainer.innerHTML = `
|
|
98
|
-
<label for="bulk-package-select">Select Package Namespace</label>
|
|
99
|
-
<select id="bulk-package-select" required>
|
|
100
|
-
<option value="">-- Select a package --</option>
|
|
101
|
-
${packageOptions}
|
|
102
|
-
</select>
|
|
103
|
-
<small style="color: #666; font-size: 0.9em;">Or <a href="#" onclick="showCreatePackageForBulk(event)">create a new package</a></small>
|
|
104
|
-
`;
|
|
105
|
-
bulkVariablesContainer.appendChild(packageSelectContainer);
|
|
106
|
-
|
|
107
|
-
// Add event listener for package selection
|
|
108
|
-
document
|
|
109
|
-
.getElementById("bulk-package-select")
|
|
110
|
-
.addEventListener("change", function (e) {
|
|
111
|
-
currentPackage = e.target.value;
|
|
112
|
-
});
|
|
113
|
-
} else {
|
|
114
|
-
// Show current package
|
|
115
|
-
const packageInfoContainer = document.createElement("div");
|
|
116
|
-
packageInfoContainer.className = "form-group";
|
|
117
|
-
packageInfoContainer.innerHTML = `
|
|
118
|
-
<label>Package Namespace</label>
|
|
119
|
-
<div style="background-color: #f1f1f1; padding: 8px; border-radius: 4px; font-family: monospace;">${escapeHtml(currentPackage)}</div>
|
|
120
|
-
`;
|
|
121
|
-
bulkVariablesContainer.appendChild(packageInfoContainer);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
variables.forEach((key, index) => {
|
|
125
|
-
const fieldContainer = document.createElement("div");
|
|
126
|
-
fieldContainer.className = "form-group";
|
|
127
|
-
|
|
128
|
-
fieldContainer.innerHTML = `
|
|
129
|
-
<label for="bulk-value-${index}">${escapeHtml(key)}</label>
|
|
130
|
-
<input type="text" id="bulk-value-${index}" name="${escapeHtml(key)}" required>
|
|
131
|
-
`;
|
|
132
|
-
|
|
133
|
-
bulkVariablesContainer.appendChild(fieldContainer);
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
document.getElementById("bulk-modal").style.display = "block";
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Function to close bulk modal
|
|
140
|
-
function closeBulkModal() {
|
|
141
|
-
document.getElementById("bulk-modal").style.display = "none";
|
|
142
|
-
// Clear URL parameters after closing modal
|
|
143
|
-
const url = new URL(window.location);
|
|
144
|
-
url.searchParams.delete("vars");
|
|
145
|
-
url.searchParams.delete("package");
|
|
146
|
-
window.history.replaceState({}, "", url);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Function to show create package form in bulk modal
|
|
150
|
-
function showCreatePackageForBulk(event) {
|
|
151
|
-
event.preventDefault();
|
|
152
|
-
const bulkVariablesContainer = document.getElementById(
|
|
153
|
-
"bulk-variables-container",
|
|
154
|
-
);
|
|
155
|
-
const packageSelectContainer =
|
|
156
|
-
bulkVariablesContainer.querySelector(".form-group");
|
|
157
|
-
|
|
158
|
-
packageSelectContainer.innerHTML = `
|
|
159
|
-
<label for="bulk-new-package">Create New Package Namespace</label>
|
|
160
|
-
<input type="text" id="bulk-new-package" placeholder="e.g., org/package/subpackage" required>
|
|
161
|
-
<button type="button" onclick="createPackageForBulk(event)">Create Package</button>
|
|
162
|
-
<small style="color: #666; font-size: 0.9em;">Or <a href="#" onclick="showPackageSelectForBulk(event)">select existing package</a></small>
|
|
163
|
-
`;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Function to show package select in bulk modal
|
|
167
|
-
function showPackageSelectForBulk(event) {
|
|
168
|
-
event.preventDefault();
|
|
169
|
-
const bulkVariablesContainer = document.getElementById(
|
|
170
|
-
"bulk-variables-container",
|
|
171
|
-
);
|
|
172
|
-
const packageSelectContainer =
|
|
173
|
-
bulkVariablesContainer.querySelector(".form-group");
|
|
174
|
-
|
|
175
|
-
const packageOptions = packages
|
|
176
|
-
.map(
|
|
177
|
-
(pkg) =>
|
|
178
|
-
`<option value="${escapeHtml(pkg.namespace)}">${escapeHtml(pkg.namespace)}</option>`,
|
|
179
|
-
)
|
|
180
|
-
.join("");
|
|
181
|
-
|
|
182
|
-
packageSelectContainer.innerHTML = `
|
|
183
|
-
<label for="bulk-package-select">Select Package Namespace</label>
|
|
184
|
-
<select id="bulk-package-select" required>
|
|
185
|
-
<option value="">-- Select a package --</option>
|
|
186
|
-
${packageOptions}
|
|
187
|
-
</select>
|
|
188
|
-
<small style="color: #666; font-size: 0.9em;">Or <a href="#" onclick="showCreatePackageForBulk(event)">create a new package</a></small>
|
|
189
|
-
`;
|
|
190
|
-
|
|
191
|
-
// Add event listener for package selection
|
|
192
|
-
document
|
|
193
|
-
.getElementById("bulk-package-select")
|
|
194
|
-
.addEventListener("change", function (e) {
|
|
195
|
-
currentPackage = e.target.value;
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// Function to create package for bulk variables
|
|
200
|
-
async function createPackageForBulk(event) {
|
|
201
|
-
event.preventDefault();
|
|
202
|
-
const newPackageInput = document.getElementById("bulk-new-package");
|
|
203
|
-
const namespace = newPackageInput.value.trim();
|
|
204
|
-
|
|
205
|
-
if (!namespace) {
|
|
206
|
-
showNotification("Package namespace is required", "error");
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
if (!/^[a-zA-Z0-9_-]+([\/][a-zA-Z0-9_-]+)*$/.test(namespace)) {
|
|
211
|
-
showNotification(
|
|
212
|
-
'Invalid package namespace format. Use format like "org/package" or "org/package/subpackage"',
|
|
213
|
-
"error",
|
|
214
|
-
);
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
try {
|
|
219
|
-
const response = await fetch("/api/packages", {
|
|
220
|
-
method: "POST",
|
|
221
|
-
headers: {
|
|
222
|
-
"Content-Type": "application/json",
|
|
223
|
-
},
|
|
224
|
-
body: JSON.stringify({ namespace }),
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
if (!response.ok) {
|
|
228
|
-
const error = await response.json();
|
|
229
|
-
throw new Error(error.error || "Failed to create package");
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// Set as current package and update UI
|
|
233
|
-
currentPackage = namespace;
|
|
234
|
-
await loadPackages(); // Refresh package list
|
|
235
|
-
|
|
236
|
-
// Update the bulk modal to show the created package
|
|
237
|
-
const bulkVariablesContainer = document.getElementById(
|
|
238
|
-
"bulk-variables-container",
|
|
239
|
-
);
|
|
240
|
-
const packageSelectContainer =
|
|
241
|
-
bulkVariablesContainer.querySelector(".form-group");
|
|
242
|
-
packageSelectContainer.innerHTML = `
|
|
243
|
-
<label>Package Namespace</label>
|
|
244
|
-
<div style="background-color: #e8f5e8; padding: 8px; border-radius: 4px; font-family: monospace; border: 1px solid #4caf50;">${escapeHtml(namespace)} <small style="color: #4caf50;">(created)</small></div>
|
|
245
|
-
`;
|
|
246
|
-
|
|
247
|
-
showNotification(`Package "${namespace}" created successfully`, "success");
|
|
248
|
-
} catch (error) {
|
|
249
|
-
showNotification(error.message, "error");
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// Function to save bulk variables
|
|
254
|
-
async function saveBulkVariables(event) {
|
|
255
|
-
event.preventDefault();
|
|
256
|
-
|
|
257
|
-
// Check if package is selected from the dropdown if no current package
|
|
258
|
-
if (!currentPackage) {
|
|
259
|
-
const packageSelect = document.getElementById("bulk-package-select");
|
|
260
|
-
if (packageSelect && packageSelect.value) {
|
|
261
|
-
currentPackage = packageSelect.value;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
if (!currentPackage) {
|
|
266
|
-
showNotification("Please select or create a package first", "error");
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
const formData = new FormData(document.getElementById("bulk-form"));
|
|
271
|
-
const variables = {};
|
|
272
|
-
let successCount = 0;
|
|
273
|
-
|
|
274
|
-
// Collect all variables from the form (excluding package selection)
|
|
275
|
-
for (const [key, value] of formData.entries()) {
|
|
276
|
-
if (key !== "package-select" && value.trim()) {
|
|
277
|
-
variables[key] = value.trim();
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
if (Object.keys(variables).length === 0) {
|
|
282
|
-
showNotification("No variables to save", "error");
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// Save each variable via API
|
|
287
|
-
for (const [key, value] of Object.entries(variables)) {
|
|
288
|
-
try {
|
|
289
|
-
const response = await fetch(
|
|
290
|
-
`/api/packages/${encodeURIComponent(currentPackage)}/variables`,
|
|
291
|
-
{
|
|
292
|
-
method: "POST",
|
|
293
|
-
headers: {
|
|
294
|
-
"Content-Type": "application/json",
|
|
295
|
-
},
|
|
296
|
-
body: JSON.stringify({ key, value }),
|
|
297
|
-
},
|
|
298
|
-
);
|
|
299
|
-
|
|
300
|
-
if (response.ok) {
|
|
301
|
-
successCount++;
|
|
302
|
-
} else {
|
|
303
|
-
const error = await response.json();
|
|
304
|
-
console.error(`Error saving ${key}:`, error.error || "Unknown error");
|
|
305
|
-
}
|
|
306
|
-
} catch (error) {
|
|
307
|
-
console.error(`Error saving ${key}:`, error);
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
closeBulkModal();
|
|
312
|
-
showNotification(
|
|
313
|
-
`Successfully saved ${successCount} out of ${Object.keys(variables).length} variables to package "${currentPackage}"`,
|
|
314
|
-
"success",
|
|
315
|
-
);
|
|
316
|
-
|
|
317
|
-
// Reload data
|
|
318
|
-
await loadPackages();
|
|
319
|
-
if (currentPackage) {
|
|
320
|
-
// Find and select the package in the UI
|
|
321
|
-
setTimeout(() => {
|
|
322
|
-
const packageItems = document.querySelectorAll(".package-item");
|
|
323
|
-
for (const item of packageItems) {
|
|
324
|
-
if (item.textContent.includes(currentPackage)) {
|
|
325
|
-
item.click();
|
|
326
|
-
break;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}, 100);
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// Function to generate link with variables
|
|
334
|
-
function generateLink() {
|
|
335
|
-
const varsInput = document.getElementById("vars-input");
|
|
336
|
-
const packageInput = document.getElementById("package-input");
|
|
337
|
-
const linkOutput = document.getElementById("link-output");
|
|
338
|
-
const linkOutputContainer = document.getElementById("link-output-container");
|
|
339
|
-
|
|
340
|
-
const vars = varsInput.value
|
|
341
|
-
.split(/[\n,]/) // Split by newline or comma
|
|
342
|
-
.map((item) => item.trim())
|
|
343
|
-
.filter((item) => item); // Remove empty items
|
|
344
|
-
|
|
345
|
-
if (vars.length === 0) {
|
|
346
|
-
showNotification("Please enter at least one variable", "error");
|
|
347
|
-
return;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
const baseUrl = window.location.origin + window.location.pathname;
|
|
351
|
-
const varsParam = encodeURIComponent(JSON.stringify(vars));
|
|
352
|
-
let url = `${baseUrl}?vars=${varsParam}`;
|
|
353
|
-
|
|
354
|
-
// Add package parameter if specified
|
|
355
|
-
const packageName = packageInput.value.trim();
|
|
356
|
-
if (packageName) {
|
|
357
|
-
url += `&package=${encodeURIComponent(packageName)}`;
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
linkOutput.textContent = url;
|
|
361
|
-
linkOutputContainer.style.display = "block";
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
// Function to copy link to clipboard
|
|
365
|
-
function copyLink() {
|
|
366
|
-
const linkOutput = document.getElementById("link-output");
|
|
367
|
-
navigator.clipboard
|
|
368
|
-
.writeText(linkOutput.textContent)
|
|
369
|
-
.then(() => {
|
|
370
|
-
showNotification("Link copied to clipboard", "success");
|
|
371
|
-
})
|
|
372
|
-
.catch(() => {
|
|
373
|
-
showNotification("Failed to copy link", "error");
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
async function loadPackages() {
|
|
378
|
-
try {
|
|
379
|
-
const response = await fetch("/api/packages");
|
|
380
|
-
const data = await response.json();
|
|
381
|
-
packages = data.packages;
|
|
382
|
-
renderPackageList();
|
|
383
|
-
} catch (error) {
|
|
384
|
-
showNotification("Error loading packages: " + error.message, "error");
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
function renderPackageList() {
|
|
389
|
-
const container = document.getElementById("package-list-content");
|
|
390
|
-
|
|
391
|
-
if (packages.length === 0) {
|
|
392
|
-
container.innerHTML =
|
|
393
|
-
'<div class="empty-state"><p>No packages found</p><p>Create your first package using the form below</p></div>';
|
|
394
|
-
return;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
container.innerHTML = packages
|
|
398
|
-
.map(
|
|
399
|
-
(pkg) => `
|
|
400
|
-
<div class="package-item" onclick="selectPackage('${escapeForJs(pkg.namespace)}')">
|
|
401
|
-
<div class="package-name">${escapeHtml(pkg.namespace)}</div>
|
|
402
|
-
<div class="package-path">${escapeHtml(pkg.path)}</div>
|
|
403
|
-
<div class="package-var-count">${Object.keys(pkg.variables).length} variables</div>
|
|
404
|
-
</div>
|
|
405
|
-
`,
|
|
406
|
-
)
|
|
407
|
-
.join("");
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
async function selectPackage(namespace) {
|
|
411
|
-
currentPackage = namespace;
|
|
412
|
-
|
|
413
|
-
// Update UI
|
|
414
|
-
document
|
|
415
|
-
.querySelectorAll(".package-item")
|
|
416
|
-
.forEach((item) => item.classList.remove("active"));
|
|
417
|
-
// Find the clicked item and make it active
|
|
418
|
-
const packageItems = document.querySelectorAll(".package-item");
|
|
419
|
-
for (const item of packageItems) {
|
|
420
|
-
if (item.textContent.includes(namespace)) {
|
|
421
|
-
item.classList.add("active");
|
|
422
|
-
break;
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
document.getElementById("selected-package-title").textContent = namespace;
|
|
427
|
-
document.getElementById("add-var-form").style.display = "block";
|
|
428
|
-
|
|
429
|
-
// Load package details
|
|
430
|
-
try {
|
|
431
|
-
const response = await fetch(
|
|
432
|
-
`/api/packages/${encodeURIComponent(namespace)}`,
|
|
433
|
-
);
|
|
434
|
-
const data = await response.json();
|
|
435
|
-
renderPackageDetail(data.variables);
|
|
436
|
-
} catch (error) {
|
|
437
|
-
showNotification(
|
|
438
|
-
"Error loading package details: " + error.message,
|
|
439
|
-
"error",
|
|
440
|
-
);
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
function escapeHtml(unsafe) {
|
|
445
|
-
return unsafe
|
|
446
|
-
.toString()
|
|
447
|
-
.replace(/&/g, "&")
|
|
448
|
-
.replace(/</g, "<")
|
|
449
|
-
.replace(/>/g, ">")
|
|
450
|
-
.replace(/"/g, """)
|
|
451
|
-
.replace(/'/g, "'");
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
// For use in onclick attributes - only escape quotes that would break JS
|
|
455
|
-
function escapeForJs(unsafe) {
|
|
456
|
-
return unsafe
|
|
457
|
-
.toString()
|
|
458
|
-
.replace(/\\/g, "\\\\")
|
|
459
|
-
.replace(/'/g, "\\'")
|
|
460
|
-
.replace(/"/g, '\\"')
|
|
461
|
-
.replace(/\n/g, "\\n")
|
|
462
|
-
.replace(/\r/g, "\\r");
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
function renderPackageDetail(variables) {
|
|
466
|
-
const container = document.getElementById("package-detail-content");
|
|
467
|
-
|
|
468
|
-
if (Object.keys(variables).length === 0) {
|
|
469
|
-
container.innerHTML =
|
|
470
|
-
'<div class="empty-state"><p>No environment variables</p><p>Add your first variable using the form below</p></div>';
|
|
471
|
-
return;
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
let tableHtml = `
|
|
475
|
-
<table>
|
|
476
|
-
<thead>
|
|
477
|
-
<tr>
|
|
478
|
-
<th>Variable Name</th>
|
|
479
|
-
<th>Value</th>
|
|
480
|
-
<th>Actions</th>
|
|
481
|
-
</tr>
|
|
482
|
-
</thead>
|
|
483
|
-
<tbody>
|
|
484
|
-
`;
|
|
485
|
-
|
|
486
|
-
for (const [key, value] of Object.entries(variables)) {
|
|
487
|
-
const escapedKey = escapeForJs(key);
|
|
488
|
-
const escapedValue = escapeForJs(value);
|
|
489
|
-
tableHtml += `
|
|
490
|
-
<tr>
|
|
491
|
-
<td>${escapeHtml(key)}</td>
|
|
492
|
-
<td class="value-cell">
|
|
493
|
-
<span class="masked-value" data-key="${escapeHtml(key)}" data-value="${escapeHtml(value)}">••••••••</span>
|
|
494
|
-
</td>
|
|
495
|
-
<td>
|
|
496
|
-
<div class="actions">
|
|
497
|
-
<button class="view" onclick="toggleValue('${escapedKey}')">View</button>
|
|
498
|
-
<button onclick="editVariable('${escapedKey}', '${escapedValue}')">Edit</button>
|
|
499
|
-
<button class="delete" onclick="deleteVariable('${escapedKey}')">Delete</button>
|
|
500
|
-
</div>
|
|
501
|
-
</td>
|
|
502
|
-
</tr>
|
|
503
|
-
`;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
tableHtml += "</tbody></table>";
|
|
507
|
-
container.innerHTML = tableHtml;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
function toggleValue(key) {
|
|
511
|
-
const element = document.querySelector(`[data-key='${CSS.escape(key)}']`);
|
|
512
|
-
const button = event.target;
|
|
513
|
-
|
|
514
|
-
if (element.textContent === "••••••••") {
|
|
515
|
-
element.textContent = element.dataset.value;
|
|
516
|
-
button.textContent = "Hide";
|
|
517
|
-
button.classList.remove("view");
|
|
518
|
-
button.classList.add("hide");
|
|
519
|
-
} else {
|
|
520
|
-
element.textContent = "••••••••";
|
|
521
|
-
button.textContent = "View";
|
|
522
|
-
button.classList.remove("hide");
|
|
523
|
-
button.classList.add("view");
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
function editVariable(key, value) {
|
|
528
|
-
document.getElementById("var-key").value = key;
|
|
529
|
-
document.getElementById("var-value").value = value;
|
|
530
|
-
document.getElementById("var-key").setAttribute("readonly", true);
|
|
531
|
-
document.getElementById("var-key").style.backgroundColor = "#f1f1f1";
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
async function deleteVariable(key) {
|
|
535
|
-
if (!confirm(`Are you sure you want to delete variable "${key}"?`)) {
|
|
536
|
-
return;
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
try {
|
|
540
|
-
const response = await fetch(
|
|
541
|
-
`/api/packages/${encodeURIComponent(currentPackage)}/variables/${encodeURIComponent(key)}`,
|
|
542
|
-
{
|
|
543
|
-
method: "DELETE",
|
|
544
|
-
},
|
|
545
|
-
);
|
|
546
|
-
|
|
547
|
-
if (!response.ok) {
|
|
548
|
-
const error = await response.json();
|
|
549
|
-
throw new Error(error.error || "Failed to delete variable");
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
showNotification(`Variable "${key}" deleted successfully`, "success");
|
|
553
|
-
selectPackage(currentPackage); // Reload package details
|
|
554
|
-
loadPackages(); // Reload package list to update counts
|
|
555
|
-
} catch (error) {
|
|
556
|
-
showNotification(error.message, "error");
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
async function saveVariable(event) {
|
|
561
|
-
event.preventDefault();
|
|
562
|
-
|
|
563
|
-
if (!currentPackage) {
|
|
564
|
-
showNotification("Please select a package first", "error");
|
|
565
|
-
return;
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
const formData = new FormData(event.target);
|
|
569
|
-
const key = formData.get("key").trim();
|
|
570
|
-
const value = formData.get("value").trim();
|
|
571
|
-
|
|
572
|
-
if (!key || !value) {
|
|
573
|
-
showNotification("Variable name and value are required", "error");
|
|
574
|
-
return;
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
try {
|
|
578
|
-
const response = await fetch(
|
|
579
|
-
`/api/packages/${encodeURIComponent(currentPackage)}/variables`,
|
|
580
|
-
{
|
|
581
|
-
method: "POST",
|
|
582
|
-
headers: {
|
|
583
|
-
"Content-Type": "application/json",
|
|
584
|
-
},
|
|
585
|
-
body: JSON.stringify({ key, value }),
|
|
586
|
-
},
|
|
587
|
-
);
|
|
588
|
-
|
|
589
|
-
if (!response.ok) {
|
|
590
|
-
const error = await response.json();
|
|
591
|
-
throw new Error(error.error || "Failed to save variable");
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
showNotification(`Variable "${key}" saved successfully`, "success");
|
|
595
|
-
clearForm();
|
|
596
|
-
selectPackage(currentPackage); // Reload package details
|
|
597
|
-
loadPackages(); // Reload package list to update counts
|
|
598
|
-
} catch (error) {
|
|
599
|
-
showNotification(error.message, "error");
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
async function createPackage() {
|
|
604
|
-
const namespace = document
|
|
605
|
-
.getElementById("new-package-namespace")
|
|
606
|
-
.value.trim();
|
|
607
|
-
|
|
608
|
-
if (!namespace) {
|
|
609
|
-
showNotification("Package namespace is required", "error");
|
|
610
|
-
return;
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
if (!/^[a-zA-Z0-9_-]+([\/][a-zA-Z0-9_-]+)*$/.test(namespace)) {
|
|
614
|
-
showNotification(
|
|
615
|
-
'Invalid package namespace format. Use format like "org/package" or "org/package/subpackage"',
|
|
616
|
-
"error",
|
|
617
|
-
);
|
|
618
|
-
return;
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
try {
|
|
622
|
-
const response = await fetch("/api/packages", {
|
|
623
|
-
method: "POST",
|
|
624
|
-
headers: {
|
|
625
|
-
"Content-Type": "application/json",
|
|
626
|
-
},
|
|
627
|
-
body: JSON.stringify({ namespace }),
|
|
628
|
-
});
|
|
629
|
-
|
|
630
|
-
if (!response.ok) {
|
|
631
|
-
const error = await response.json();
|
|
632
|
-
throw new Error(error.error || "Failed to create package");
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
showNotification(`Package "${namespace}" created successfully`, "success");
|
|
636
|
-
document.getElementById("new-package-namespace").value = "";
|
|
637
|
-
loadPackages();
|
|
638
|
-
} catch (error) {
|
|
639
|
-
showNotification(error.message, "error");
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
function clearForm() {
|
|
644
|
-
document.getElementById("var-key").value = "";
|
|
645
|
-
document.getElementById("var-value").value = "";
|
|
646
|
-
document.getElementById("var-key").removeAttribute("readonly");
|
|
647
|
-
document.getElementById("var-key").style.backgroundColor = "";
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
function showNotification(message, type) {
|
|
651
|
-
const notification = document.getElementById("notification");
|
|
652
|
-
notification.textContent = message;
|
|
653
|
-
notification.className = `notification ${type}`;
|
|
654
|
-
|
|
655
|
-
setTimeout(() => {
|
|
656
|
-
notification.style.opacity = "0";
|
|
657
|
-
}, 3000);
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
// Make functions globally accessible for onclick handlers
|
|
661
|
-
window.showCreatePackageForBulk = showCreatePackageForBulk;
|
|
662
|
-
window.showPackageSelectForBulk = showPackageSelectForBulk;
|
|
663
|
-
window.createPackageForBulk = createPackageForBulk;
|