@enactprotocol/shared 1.2.13 → 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.
Files changed (134) hide show
  1. package/README.md +44 -0
  2. package/package.json +16 -58
  3. package/src/config.ts +476 -0
  4. package/src/constants.ts +36 -0
  5. package/src/execution/command.ts +314 -0
  6. package/src/execution/index.ts +73 -0
  7. package/src/execution/runtime.ts +308 -0
  8. package/src/execution/types.ts +379 -0
  9. package/src/execution/validation.ts +508 -0
  10. package/src/index.ts +237 -30
  11. package/src/manifest/index.ts +36 -0
  12. package/src/manifest/loader.ts +187 -0
  13. package/src/manifest/parser.ts +173 -0
  14. package/src/manifest/validator.ts +309 -0
  15. package/src/paths.ts +108 -0
  16. package/src/registry.ts +219 -0
  17. package/src/resolver.ts +345 -0
  18. package/src/types/index.ts +30 -0
  19. package/src/types/manifest.ts +255 -0
  20. package/src/types.ts +5 -188
  21. package/src/utils/fs.ts +281 -0
  22. package/src/utils/logger.ts +270 -59
  23. package/src/utils/version.ts +304 -36
  24. package/tests/config.test.ts +515 -0
  25. package/tests/execution/command.test.ts +317 -0
  26. package/tests/execution/validation.test.ts +384 -0
  27. package/tests/fixtures/invalid-tool.yaml +4 -0
  28. package/tests/fixtures/valid-tool.md +62 -0
  29. package/tests/fixtures/valid-tool.yaml +40 -0
  30. package/tests/index.test.ts +8 -0
  31. package/tests/manifest/loader.test.ts +291 -0
  32. package/tests/manifest/parser.test.ts +345 -0
  33. package/tests/manifest/validator.test.ts +394 -0
  34. package/tests/manifest-types.test.ts +358 -0
  35. package/tests/paths.test.ts +153 -0
  36. package/tests/registry.test.ts +231 -0
  37. package/tests/resolver.test.ts +272 -0
  38. package/tests/utils/fs.test.ts +388 -0
  39. package/tests/utils/logger.test.ts +480 -0
  40. package/tests/utils/version.test.ts +390 -0
  41. package/tsconfig.json +12 -0
  42. package/tsconfig.tsbuildinfo +1 -0
  43. package/dist/LocalToolResolver.d.ts +0 -84
  44. package/dist/LocalToolResolver.js +0 -353
  45. package/dist/api/enact-api.d.ts +0 -130
  46. package/dist/api/enact-api.js +0 -428
  47. package/dist/api/index.d.ts +0 -2
  48. package/dist/api/index.js +0 -2
  49. package/dist/api/types.d.ts +0 -103
  50. package/dist/api/types.js +0 -1
  51. package/dist/constants.d.ts +0 -7
  52. package/dist/constants.js +0 -10
  53. package/dist/core/DaggerExecutionProvider.d.ts +0 -169
  54. package/dist/core/DaggerExecutionProvider.js +0 -1029
  55. package/dist/core/DirectExecutionProvider.d.ts +0 -23
  56. package/dist/core/DirectExecutionProvider.js +0 -406
  57. package/dist/core/EnactCore.d.ts +0 -162
  58. package/dist/core/EnactCore.js +0 -597
  59. package/dist/core/NativeExecutionProvider.d.ts +0 -9
  60. package/dist/core/NativeExecutionProvider.js +0 -16
  61. package/dist/core/index.d.ts +0 -3
  62. package/dist/core/index.js +0 -3
  63. package/dist/exec/index.d.ts +0 -3
  64. package/dist/exec/index.js +0 -3
  65. package/dist/exec/logger.d.ts +0 -11
  66. package/dist/exec/logger.js +0 -57
  67. package/dist/exec/validate.d.ts +0 -5
  68. package/dist/exec/validate.js +0 -167
  69. package/dist/index.d.ts +0 -21
  70. package/dist/index.js +0 -25
  71. package/dist/lib/enact-direct.d.ts +0 -150
  72. package/dist/lib/enact-direct.js +0 -159
  73. package/dist/lib/index.d.ts +0 -1
  74. package/dist/lib/index.js +0 -1
  75. package/dist/security/index.d.ts +0 -3
  76. package/dist/security/index.js +0 -3
  77. package/dist/security/security.d.ts +0 -23
  78. package/dist/security/security.js +0 -137
  79. package/dist/security/sign.d.ts +0 -103
  80. package/dist/security/sign.js +0 -666
  81. package/dist/security/verification-enforcer.d.ts +0 -53
  82. package/dist/security/verification-enforcer.js +0 -204
  83. package/dist/services/McpCoreService.d.ts +0 -98
  84. package/dist/services/McpCoreService.js +0 -124
  85. package/dist/services/index.d.ts +0 -1
  86. package/dist/services/index.js +0 -1
  87. package/dist/types.d.ts +0 -132
  88. package/dist/types.js +0 -3
  89. package/dist/utils/config.d.ts +0 -111
  90. package/dist/utils/config.js +0 -342
  91. package/dist/utils/env-loader.d.ts +0 -54
  92. package/dist/utils/env-loader.js +0 -270
  93. package/dist/utils/help.d.ts +0 -36
  94. package/dist/utils/help.js +0 -248
  95. package/dist/utils/index.d.ts +0 -7
  96. package/dist/utils/index.js +0 -7
  97. package/dist/utils/logger.d.ts +0 -35
  98. package/dist/utils/logger.js +0 -75
  99. package/dist/utils/silent-monitor.d.ts +0 -67
  100. package/dist/utils/silent-monitor.js +0 -242
  101. package/dist/utils/timeout.d.ts +0 -5
  102. package/dist/utils/timeout.js +0 -23
  103. package/dist/utils/version.d.ts +0 -4
  104. package/dist/utils/version.js +0 -35
  105. package/dist/web/env-manager-server.d.ts +0 -29
  106. package/dist/web/env-manager-server.js +0 -367
  107. package/dist/web/index.d.ts +0 -1
  108. package/dist/web/index.js +0 -1
  109. package/src/LocalToolResolver.ts +0 -424
  110. package/src/api/enact-api.ts +0 -604
  111. package/src/api/index.ts +0 -2
  112. package/src/api/types.ts +0 -114
  113. package/src/core/DaggerExecutionProvider.ts +0 -1357
  114. package/src/core/DirectExecutionProvider.ts +0 -484
  115. package/src/core/EnactCore.ts +0 -847
  116. package/src/core/index.ts +0 -3
  117. package/src/exec/index.ts +0 -3
  118. package/src/exec/logger.ts +0 -63
  119. package/src/exec/validate.ts +0 -238
  120. package/src/lib/enact-direct.ts +0 -254
  121. package/src/lib/index.ts +0 -1
  122. package/src/services/McpCoreService.ts +0 -201
  123. package/src/services/index.ts +0 -1
  124. package/src/utils/config.ts +0 -438
  125. package/src/utils/env-loader.ts +0 -370
  126. package/src/utils/help.ts +0 -257
  127. package/src/utils/index.ts +0 -7
  128. package/src/utils/silent-monitor.ts +0 -328
  129. package/src/utils/timeout.ts +0 -26
  130. package/src/web/env-manager-server.ts +0 -465
  131. package/src/web/index.ts +0 -1
  132. package/src/web/static/app.js +0 -663
  133. package/src/web/static/index.html +0 -117
  134. package/src/web/static/style.css +0 -291
@@ -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, "&amp;")
448
- .replace(/</g, "&lt;")
449
- .replace(/>/g, "&gt;")
450
- .replace(/"/g, "&quot;")
451
- .replace(/'/g, "&#039;");
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;