zerochat 7.3.0__py3-none-any.whl
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.
- zerochat-7.3.0.dist-info/METADATA +70 -0
- zerochat-7.3.0.dist-info/RECORD +130 -0
- zerochat-7.3.0.dist-info/WHEEL +5 -0
- zerochat-7.3.0.dist-info/entry_points.txt +2 -0
- zerochat-7.3.0.dist-info/licenses/LICENSE +34 -0
- zerochat-7.3.0.dist-info/top_level.txt +2 -0
- zerochat.py +2004 -0
- zerochat_runtime/__init__.py +1 -0
- zerochat_runtime/assets/css/base.css +199 -0
- zerochat_runtime/assets/css/components/composer.css +1258 -0
- zerochat_runtime/assets/css/components/debug.css +777 -0
- zerochat_runtime/assets/css/components/header.css +97 -0
- zerochat_runtime/assets/css/components/icons.css +39 -0
- zerochat_runtime/assets/css/components/markdown.css +685 -0
- zerochat_runtime/assets/css/components/messages.css +473 -0
- zerochat_runtime/assets/css/components/modals.css +1319 -0
- zerochat_runtime/assets/css/components/sidebar.css +622 -0
- zerochat_runtime/assets/css/components/tools.css +1223 -0
- zerochat_runtime/assets/css/layout.css +171 -0
- zerochat_runtime/assets/css/print.css +120 -0
- zerochat_runtime/assets/css/styles.css +18 -0
- zerochat_runtime/assets/css/theme-overrides.css +555 -0
- zerochat_runtime/assets/css/tokens.css +165 -0
- zerochat_runtime/assets/help/architecture.html +247 -0
- zerochat_runtime/assets/help/composer.html +134 -0
- zerochat_runtime/assets/help/conversations.html +105 -0
- zerochat_runtime/assets/help/debug.html +108 -0
- zerochat_runtime/assets/help/en/architecture.html +247 -0
- zerochat_runtime/assets/help/en/composer.html +134 -0
- zerochat_runtime/assets/help/en/conversations.html +104 -0
- zerochat_runtime/assets/help/en/debug.html +105 -0
- zerochat_runtime/assets/help/en/gemini-free.html +39 -0
- zerochat_runtime/assets/help/en/index.html +191 -0
- zerochat_runtime/assets/help/en/learning.html +71 -0
- zerochat_runtime/assets/help/en/mcp.html +143 -0
- zerochat_runtime/assets/help/en/openrouter-free.html +39 -0
- zerochat_runtime/assets/help/en/profiles.html +173 -0
- zerochat_runtime/assets/help/en/rag.html +130 -0
- zerochat_runtime/assets/help/en/reasoning-telemetry.html +108 -0
- zerochat_runtime/assets/help/en/tools-agent.html +133 -0
- zerochat_runtime/assets/help/en/webllm.html +355 -0
- zerochat_runtime/assets/help/gemini-free.html +39 -0
- zerochat_runtime/assets/help/help.css +604 -0
- zerochat_runtime/assets/help/help.js +51 -0
- zerochat_runtime/assets/help/index.html +194 -0
- zerochat_runtime/assets/help/learning.html +71 -0
- zerochat_runtime/assets/help/mcp.html +143 -0
- zerochat_runtime/assets/help/openrouter-free.html +39 -0
- zerochat_runtime/assets/help/profiles.html +174 -0
- zerochat_runtime/assets/help/rag.html +130 -0
- zerochat_runtime/assets/help/reasoning-telemetry.html +111 -0
- zerochat_runtime/assets/help/tools-agent.html +133 -0
- zerochat_runtime/assets/help/webllm.html +359 -0
- zerochat_runtime/assets/js/agent-core.js +1553 -0
- zerochat_runtime/assets/js/api.js +844 -0
- zerochat_runtime/assets/js/app.js +2558 -0
- zerochat_runtime/assets/js/attachments.js +220 -0
- zerochat_runtime/assets/js/charts.js +338 -0
- zerochat_runtime/assets/js/chat-engine.js +566 -0
- zerochat_runtime/assets/js/config-store.js +207 -0
- zerochat_runtime/assets/js/context-manager.js +584 -0
- zerochat_runtime/assets/js/conversation-service.js +484 -0
- zerochat_runtime/assets/js/cookies.js +688 -0
- zerochat_runtime/assets/js/data-reset-service.js +136 -0
- zerochat_runtime/assets/js/debug.js +508 -0
- zerochat_runtime/assets/js/defaults.js +16 -0
- zerochat_runtime/assets/js/export.js +179 -0
- zerochat_runtime/assets/js/file-parser.js +2088 -0
- zerochat_runtime/assets/js/generation-controller.js +417 -0
- zerochat_runtime/assets/js/i18n.js +1483 -0
- zerochat_runtime/assets/js/icons.js +156 -0
- zerochat_runtime/assets/js/ingestionEngine.js +436 -0
- zerochat_runtime/assets/js/markdown.js +588 -0
- zerochat_runtime/assets/js/mcp.js +1271 -0
- zerochat_runtime/assets/js/message-turns.js +62 -0
- zerochat_runtime/assets/js/profile-backup.js +118 -0
- zerochat_runtime/assets/js/profile-export-bundle.js +481 -0
- zerochat_runtime/assets/js/profile-repository.js +213 -0
- zerochat_runtime/assets/js/providers-webllm.js +486 -0
- zerochat_runtime/assets/js/providers.js +1560 -0
- zerochat_runtime/assets/js/rag-index.js +295 -0
- zerochat_runtime/assets/js/rag-service.js +530 -0
- zerochat_runtime/assets/js/rag-ui.js +997 -0
- zerochat_runtime/assets/js/ragStorage.js +676 -0
- zerochat_runtime/assets/js/sandbox.js +449 -0
- zerochat_runtime/assets/js/state.js +704 -0
- zerochat_runtime/assets/js/storage-db.js +144 -0
- zerochat_runtime/assets/js/tool-cards.js +330 -0
- zerochat_runtime/assets/js/tool-security.js +653 -0
- zerochat_runtime/assets/js/tools/README.md +50 -0
- zerochat_runtime/assets/js/tools/builtin/agent-checkpoint.tool.js +212 -0
- zerochat_runtime/assets/js/tools/builtin/download-pdf.tool.js +111 -0
- zerochat_runtime/assets/js/tools/builtin/execute-javascript.tool.js +219 -0
- zerochat_runtime/assets/js/tools/builtin/fetch-web-page.tool.js +112 -0
- zerochat_runtime/assets/js/tools/builtin/list-documents.tool.js +117 -0
- zerochat_runtime/assets/js/tools/builtin/read-knowledge-chunk.tool.js +129 -0
- zerochat_runtime/assets/js/tools/builtin/read-knowledge-image.tool.js +95 -0
- zerochat_runtime/assets/js/tools/builtin/render-chart.tool.js +90 -0
- zerochat_runtime/assets/js/tools/builtin/search-knowledge-base.tool.js +124 -0
- zerochat_runtime/assets/js/tools/builtin/search-web.tool.js +125 -0
- zerochat_runtime/assets/js/tools/tool-manifest.js +53 -0
- zerochat_runtime/assets/js/tools/tool-runtime.js +77 -0
- zerochat_runtime/assets/js/ui-composer.js +319 -0
- zerochat_runtime/assets/js/ui-conversation.js +655 -0
- zerochat_runtime/assets/js/ui-dialogs.js +132 -0
- zerochat_runtime/assets/js/ui-generation-status.js +119 -0
- zerochat_runtime/assets/js/ui-inspector.js +804 -0
- zerochat_runtime/assets/js/ui-mcp.js +604 -0
- zerochat_runtime/assets/js/ui-profiles.js +824 -0
- zerochat_runtime/assets/js/ui-reasoning.js +146 -0
- zerochat_runtime/assets/js/ui-settings.js +825 -0
- zerochat_runtime/assets/js/ui-shell.js +215 -0
- zerochat_runtime/assets/js/ui-sidebar.js +429 -0
- zerochat_runtime/assets/js/ui-telemetry.js +404 -0
- zerochat_runtime/assets/js/ui-transfer.js +262 -0
- zerochat_runtime/assets/js/utils.js +216 -0
- zerochat_runtime/assets/js/vendor/orama.browser.js +11 -0
- zerochat_runtime/assets/js/web-browser.js +569 -0
- zerochat_runtime/assets/js/web-search.js +519 -0
- zerochat_runtime/assets/manifest.webmanifest +20 -0
- zerochat_runtime/assets/services/dummy_mcp/dummy_mcp_server.py +47 -0
- zerochat_runtime/assets/services/dummy_mcp/service.json +22 -0
- zerochat_runtime/assets/services/lsp/installer.json +9 -0
- zerochat_runtime/assets/services/lsp/service.json +22 -0
- zerochat_runtime/assets/services/memory/installer.json +9 -0
- zerochat_runtime/assets/services/memory/service.json +24 -0
- zerochat_runtime/assets/services/playwright/installer.json +10 -0
- zerochat_runtime/assets/services/playwright/service.json +39 -0
- zerochat_runtime/assets/sw.js +164 -0
- zerochat_runtime/assets/zerochat.html +671 -0
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Módulo de ejecución de JavaScript local (ChatSandbox).
|
|
3
|
+
*
|
|
4
|
+
* - Ejecución desacoplada mediante Web Worker en hilo independiente cuando está disponible (evita bloqueos del hilo principal).
|
|
5
|
+
* - Control de tiempo de ejecución (Timeout) con terminación forzada del Worker (worker.terminate()).
|
|
6
|
+
* - Límites de salida y protección de flujo (truncamiento de texto y límite de logs de consola).
|
|
7
|
+
* - Mitigación en el Worker de APIs no deseadas para cálculos (red y sub-workers).
|
|
8
|
+
* - Fallback controlado para entornos sin soporte nativo de Web Worker.
|
|
9
|
+
*
|
|
10
|
+
* NOTA DE SEGURIDAD Y VIGILANCIA TÉCNICA:
|
|
11
|
+
* Este módulo es una herramienta de apoyo para facilitar cálculos matemáticos, manipulación de
|
|
12
|
+
* datos y algoritmos del modelo. No debe considerarse un sandbox de seguridad a nivel de sistema
|
|
13
|
+
* operativo ni un entorno de ejecución hostil aislado. Su uso está pensado bajo el conocimiento,
|
|
14
|
+
* supervisión y vigilancia consciente de un usuario técnico.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
(function (root, factory) {
|
|
18
|
+
if (typeof exports === 'object' && typeof module !== 'undefined') {
|
|
19
|
+
module.exports = factory();
|
|
20
|
+
} else {
|
|
21
|
+
root.ChatSandbox = factory();
|
|
22
|
+
}
|
|
23
|
+
})(typeof self !== 'undefined' ? self : this, function () {
|
|
24
|
+
'use strict';
|
|
25
|
+
|
|
26
|
+
const DEFAULT_TIMEOUT_MS = 2500;
|
|
27
|
+
const MAX_OUTPUT_LENGTH = 30000;
|
|
28
|
+
const MAX_LOG_ENTRIES = 200;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Código fuente del Worker aislado empaquetado como texto estático.
|
|
32
|
+
*/
|
|
33
|
+
const WORKER_CODE = `
|
|
34
|
+
self.onmessage = function(e) {
|
|
35
|
+
const notifyParent = typeof self.postMessage === 'function' ? self.postMessage.bind(self) : null;
|
|
36
|
+
const { id, code, maxOutputLength, maxLogEntries } = e.data;
|
|
37
|
+
const logs = [];
|
|
38
|
+
|
|
39
|
+
function formatValue(v) {
|
|
40
|
+
if (v === null) return 'null';
|
|
41
|
+
if (v === undefined) return 'undefined';
|
|
42
|
+
if (typeof v === 'bigint') return v.toString();
|
|
43
|
+
if (typeof v === 'object') {
|
|
44
|
+
try {
|
|
45
|
+
return JSON.stringify(v, function(key, value) {
|
|
46
|
+
return typeof value === 'bigint' ? value.toString() : value;
|
|
47
|
+
}, 2);
|
|
48
|
+
} catch (err) {
|
|
49
|
+
return String(v);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return String(v);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function addLog(prefix, args) {
|
|
56
|
+
if (logs.length >= maxLogEntries) return;
|
|
57
|
+
let text = args.map(formatValue).join(' ');
|
|
58
|
+
if (prefix) text = '[' + prefix + '] ' + text;
|
|
59
|
+
if (text.length > maxOutputLength) {
|
|
60
|
+
text = text.substring(0, maxOutputLength) + '... [Salida truncada]';
|
|
61
|
+
}
|
|
62
|
+
logs.push(text);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const customConsole = {
|
|
66
|
+
log: (...args) => addLog('', args),
|
|
67
|
+
info: (...args) => addLog('INFO', args),
|
|
68
|
+
warn: (...args) => addLog('WARN', args),
|
|
69
|
+
error: (...args) => addLog('ERROR', args)
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const blockedGlobals = [
|
|
74
|
+
'fetch', 'XMLHttpRequest', 'WebSocket', 'EventSource',
|
|
75
|
+
'importScripts', 'indexedDB', 'Worker', 'SharedWorker', 'ServiceWorker',
|
|
76
|
+
'postMessage', 'addEventListener', 'removeEventListener'
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
// 1. Neutralizar recursivamente en la cadena de prototipos del Worker (WorkerGlobalScope, etc.)
|
|
80
|
+
const rootObj = typeof self !== 'undefined' ? self : (typeof globalThis !== 'undefined' ? globalThis : null);
|
|
81
|
+
if (rootObj) {
|
|
82
|
+
let currentProto = rootObj;
|
|
83
|
+
while (currentProto && currentProto !== Object.prototype) {
|
|
84
|
+
blockedGlobals.forEach(function(name) {
|
|
85
|
+
try {
|
|
86
|
+
Object.defineProperty(currentProto, name, {
|
|
87
|
+
value: undefined,
|
|
88
|
+
writable: false,
|
|
89
|
+
configurable: false
|
|
90
|
+
});
|
|
91
|
+
} catch (err) {
|
|
92
|
+
try { currentProto[name] = undefined; } catch (_) {}
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
currentProto = Object.getPrototypeOf(currentProto);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// 2. Eliminar explícitamente importScripts de self y prototipos
|
|
100
|
+
try {
|
|
101
|
+
if (typeof self !== 'undefined') delete self.importScripts;
|
|
102
|
+
if (typeof WorkerGlobalScope !== 'undefined') {
|
|
103
|
+
delete WorkerGlobalScope.prototype.importScripts;
|
|
104
|
+
}
|
|
105
|
+
} catch (_) {}
|
|
106
|
+
|
|
107
|
+
const paramNames = ['console', ...blockedGlobals];
|
|
108
|
+
const paramValues = [customConsole, ...blockedGlobals.map(() => undefined)];
|
|
109
|
+
|
|
110
|
+
const trimmed = (code || '').trim();
|
|
111
|
+
let wrappedBody;
|
|
112
|
+
if (!trimmed.includes('return') && !trimmed.includes(';') && !trimmed.includes('\\n')) {
|
|
113
|
+
wrappedBody = '"use strict"; return (' + trimmed + ');';
|
|
114
|
+
} else {
|
|
115
|
+
wrappedBody = '"use strict";\\n' + trimmed;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const runner = new Function(...paramNames, wrappedBody);
|
|
119
|
+
|
|
120
|
+
// 3. Desactivar invocación de Function.prototype.constructor durante la ejecución
|
|
121
|
+
// para neutralizar vectores de escape vía prototipos como ({}).constructor.constructor('return this')()
|
|
122
|
+
const origFunctionConstructor = Function.prototype.constructor;
|
|
123
|
+
let rawResult;
|
|
124
|
+
try {
|
|
125
|
+
Function.prototype.constructor = function() {
|
|
126
|
+
throw new Error('La creación dinámica de funciones está restringida en el sandbox.');
|
|
127
|
+
};
|
|
128
|
+
rawResult = runner.apply(null, paramValues);
|
|
129
|
+
} finally {
|
|
130
|
+
try { Function.prototype.constructor = origFunctionConstructor; } catch (_) {}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
Promise.resolve(rawResult).then(function(resolvedResult) {
|
|
134
|
+
let formattedResult = resolvedResult !== undefined ? formatValue(resolvedResult) : (logs.length > 0 ? logs.join('\\n') : 'undefined');
|
|
135
|
+
if (formattedResult && formattedResult.length > maxOutputLength) {
|
|
136
|
+
formattedResult = formattedResult.substring(0, maxOutputLength) + '... [Salida truncada por límite de tamaño]';
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const msg = {
|
|
140
|
+
id: id,
|
|
141
|
+
success: true,
|
|
142
|
+
result: formattedResult,
|
|
143
|
+
logs: logs
|
|
144
|
+
};
|
|
145
|
+
if (notifyParent) notifyParent(msg);
|
|
146
|
+
else self.postMessage(msg);
|
|
147
|
+
}).catch(function(asyncErr) {
|
|
148
|
+
const msg = {
|
|
149
|
+
id: id,
|
|
150
|
+
success: false,
|
|
151
|
+
result: '',
|
|
152
|
+
logs: logs,
|
|
153
|
+
error: (asyncErr && (asyncErr.message || asyncErr.toString())) || 'Error en ejecución asíncrona'
|
|
154
|
+
};
|
|
155
|
+
if (notifyParent) notifyParent(msg);
|
|
156
|
+
else self.postMessage(msg);
|
|
157
|
+
});
|
|
158
|
+
} catch (err) {
|
|
159
|
+
const msg = {
|
|
160
|
+
id: id,
|
|
161
|
+
success: false,
|
|
162
|
+
result: '',
|
|
163
|
+
logs: logs,
|
|
164
|
+
error: err.toString()
|
|
165
|
+
};
|
|
166
|
+
if (notifyParent) notifyParent(msg);
|
|
167
|
+
else self.postMessage(msg);
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
`;
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Ejecuta código JavaScript utilizando un Web Worker en un hilo independiente.
|
|
174
|
+
*/
|
|
175
|
+
function executeWithWorker(code, timeoutMs) {
|
|
176
|
+
return new Promise((resolve) => {
|
|
177
|
+
let workerUrl = null;
|
|
178
|
+
let worker = null;
|
|
179
|
+
let isResolved = false;
|
|
180
|
+
const startTime = performance.now();
|
|
181
|
+
|
|
182
|
+
function cleanup() {
|
|
183
|
+
if (worker) {
|
|
184
|
+
try {
|
|
185
|
+
worker.terminate();
|
|
186
|
+
} catch (e) {}
|
|
187
|
+
worker = null;
|
|
188
|
+
}
|
|
189
|
+
if (workerUrl && typeof URL !== 'undefined' && URL.revokeObjectURL) {
|
|
190
|
+
try {
|
|
191
|
+
URL.revokeObjectURL(workerUrl);
|
|
192
|
+
} catch (e) {}
|
|
193
|
+
workerUrl = null;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const timer = setTimeout(() => {
|
|
198
|
+
if (!isResolved) {
|
|
199
|
+
isResolved = true;
|
|
200
|
+
cleanup();
|
|
201
|
+
const elapsed = (performance.now() - startTime).toFixed(2);
|
|
202
|
+
resolve({
|
|
203
|
+
success: false,
|
|
204
|
+
result: '',
|
|
205
|
+
logs: [],
|
|
206
|
+
executionTimeMs: parseFloat(elapsed),
|
|
207
|
+
error: `Tiempo de ejecución excedido (Timeout de ${timeoutMs}ms). El Worker fue terminado forzosamente.`
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}, timeoutMs);
|
|
211
|
+
|
|
212
|
+
try {
|
|
213
|
+
const blob = new Blob([WORKER_CODE], { type: 'application/javascript' });
|
|
214
|
+
workerUrl = URL.createObjectURL(blob);
|
|
215
|
+
worker = new Worker(workerUrl);
|
|
216
|
+
|
|
217
|
+
worker.onmessage = function (e) {
|
|
218
|
+
if (!isResolved) {
|
|
219
|
+
isResolved = true;
|
|
220
|
+
clearTimeout(timer);
|
|
221
|
+
const data = e.data || {};
|
|
222
|
+
cleanup();
|
|
223
|
+
const elapsed = (performance.now() - startTime).toFixed(2);
|
|
224
|
+
resolve({
|
|
225
|
+
success: Boolean(data.success),
|
|
226
|
+
result: data.result || '',
|
|
227
|
+
logs: data.logs || [],
|
|
228
|
+
executionTimeMs: parseFloat(elapsed),
|
|
229
|
+
error: data.error
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
worker.onerror = function (err) {
|
|
235
|
+
if (!isResolved) {
|
|
236
|
+
isResolved = true;
|
|
237
|
+
clearTimeout(timer);
|
|
238
|
+
cleanup();
|
|
239
|
+
const elapsed = (performance.now() - startTime).toFixed(2);
|
|
240
|
+
resolve({
|
|
241
|
+
success: false,
|
|
242
|
+
result: '',
|
|
243
|
+
logs: [],
|
|
244
|
+
executionTimeMs: parseFloat(elapsed),
|
|
245
|
+
error: (err && err.message) || String(err)
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
worker.postMessage({
|
|
251
|
+
id: Date.now(),
|
|
252
|
+
code: code,
|
|
253
|
+
maxOutputLength: MAX_OUTPUT_LENGTH,
|
|
254
|
+
maxLogEntries: MAX_LOG_ENTRIES
|
|
255
|
+
});
|
|
256
|
+
} catch (err) {
|
|
257
|
+
if (!isResolved) {
|
|
258
|
+
isResolved = true;
|
|
259
|
+
clearTimeout(timer);
|
|
260
|
+
cleanup();
|
|
261
|
+
const elapsed = (performance.now() - startTime).toFixed(2);
|
|
262
|
+
resolve({
|
|
263
|
+
success: false,
|
|
264
|
+
result: '',
|
|
265
|
+
logs: [],
|
|
266
|
+
executionTimeMs: parseFloat(elapsed),
|
|
267
|
+
error: err.toString()
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Fallback de ejecución controlada para entornos donde Web Worker no esté disponible.
|
|
276
|
+
*/
|
|
277
|
+
function executeWithFallback(code, timeoutMs) {
|
|
278
|
+
return new Promise((resolve) => {
|
|
279
|
+
const logs = [];
|
|
280
|
+
const startTime = performance.now();
|
|
281
|
+
let isResolved = false;
|
|
282
|
+
|
|
283
|
+
function formatValue(v) {
|
|
284
|
+
if (v === null) return 'null';
|
|
285
|
+
if (v === undefined) return 'undefined';
|
|
286
|
+
if (typeof v === 'bigint') return v.toString();
|
|
287
|
+
if (typeof v === 'object') {
|
|
288
|
+
try {
|
|
289
|
+
return JSON.stringify(v, function(key, value) {
|
|
290
|
+
return typeof value === 'bigint' ? value.toString() : value;
|
|
291
|
+
}, 2);
|
|
292
|
+
} catch (e) {
|
|
293
|
+
return String(v);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return String(v);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function addLog(prefix, args) {
|
|
300
|
+
if (logs.length >= MAX_LOG_ENTRIES) return;
|
|
301
|
+
let text = args.map(formatValue).join(' ');
|
|
302
|
+
if (prefix) text = '[' + prefix + '] ' + text;
|
|
303
|
+
if (text.length > MAX_OUTPUT_LENGTH) {
|
|
304
|
+
text = text.substring(0, MAX_OUTPUT_LENGTH) + '... [Salida truncada]';
|
|
305
|
+
}
|
|
306
|
+
logs.push(text);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const customConsole = {
|
|
310
|
+
log: (...args) => addLog('', args),
|
|
311
|
+
info: (...args) => addLog('INFO', args),
|
|
312
|
+
warn: (...args) => addLog('WARN', args),
|
|
313
|
+
error: (...args) => addLog('ERROR', args)
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
const timer = setTimeout(() => {
|
|
317
|
+
if (!isResolved) {
|
|
318
|
+
isResolved = true;
|
|
319
|
+
const elapsed = (performance.now() - startTime).toFixed(2);
|
|
320
|
+
resolve({
|
|
321
|
+
success: false,
|
|
322
|
+
result: '',
|
|
323
|
+
logs: logs,
|
|
324
|
+
executionTimeMs: parseFloat(elapsed),
|
|
325
|
+
error: `Tiempo de ejecución excedido (Timeout de ${timeoutMs}ms).`
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
}, timeoutMs);
|
|
329
|
+
|
|
330
|
+
try {
|
|
331
|
+
const blockedGlobals = [
|
|
332
|
+
'window', 'document', 'fetch', 'XMLHttpRequest', 'WebSocket', 'EventSource',
|
|
333
|
+
'localStorage', 'sessionStorage', 'indexedDB', 'cookie', 'location', 'navigator',
|
|
334
|
+
'parent', 'top', 'frames', 'opener', 'Worker', 'SharedWorker', 'ServiceWorker',
|
|
335
|
+
'FileReader', 'DecompressionStream', 'CompressionStream', 'alert', 'confirm', 'prompt',
|
|
336
|
+
'open', 'close', 'postMessage', 'importScripts'
|
|
337
|
+
];
|
|
338
|
+
|
|
339
|
+
const paramNames = ['console', ...blockedGlobals];
|
|
340
|
+
const paramValues = [customConsole, ...blockedGlobals.map(() => undefined)];
|
|
341
|
+
|
|
342
|
+
const trimmedCode = (code || '').trim();
|
|
343
|
+
let wrappedBody;
|
|
344
|
+
if (!trimmedCode.includes('return') && !trimmedCode.includes(';') && !trimmedCode.includes('\n')) {
|
|
345
|
+
wrappedBody = `"use strict"; return (${trimmedCode});`;
|
|
346
|
+
} else {
|
|
347
|
+
wrappedBody = `"use strict";\n${trimmedCode}`;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const runner = new Function(...paramNames, wrappedBody);
|
|
351
|
+
const rawResult = runner.apply(null, paramValues);
|
|
352
|
+
|
|
353
|
+
Promise.resolve(rawResult).then(function(resolvedResult) {
|
|
354
|
+
clearTimeout(timer);
|
|
355
|
+
if (!isResolved) {
|
|
356
|
+
isResolved = true;
|
|
357
|
+
const elapsed = (performance.now() - startTime).toFixed(2);
|
|
358
|
+
let formattedResult = resolvedResult !== undefined ? formatValue(resolvedResult) : (logs.length > 0 ? logs.join('\n') : 'undefined');
|
|
359
|
+
if (formattedResult && formattedResult.length > MAX_OUTPUT_LENGTH) {
|
|
360
|
+
formattedResult = formattedResult.substring(0, MAX_OUTPUT_LENGTH) + '... [Salida truncada por límite de tamaño]';
|
|
361
|
+
}
|
|
362
|
+
resolve({
|
|
363
|
+
success: true,
|
|
364
|
+
result: formattedResult,
|
|
365
|
+
logs: logs,
|
|
366
|
+
executionTimeMs: parseFloat(elapsed)
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
}).catch(function(asyncErr) {
|
|
370
|
+
clearTimeout(timer);
|
|
371
|
+
if (!isResolved) {
|
|
372
|
+
isResolved = true;
|
|
373
|
+
const elapsed = (performance.now() - startTime).toFixed(2);
|
|
374
|
+
resolve({
|
|
375
|
+
success: false,
|
|
376
|
+
result: '',
|
|
377
|
+
logs: logs,
|
|
378
|
+
executionTimeMs: parseFloat(elapsed),
|
|
379
|
+
error: (asyncErr && (asyncErr.message || asyncErr.toString())) || 'Error en ejecución asíncrona'
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
} catch (err) {
|
|
384
|
+
clearTimeout(timer);
|
|
385
|
+
if (!isResolved) {
|
|
386
|
+
isResolved = true;
|
|
387
|
+
const elapsed = (performance.now() - startTime).toFixed(2);
|
|
388
|
+
resolve({
|
|
389
|
+
success: false,
|
|
390
|
+
result: '',
|
|
391
|
+
logs: logs,
|
|
392
|
+
executionTimeMs: parseFloat(elapsed),
|
|
393
|
+
error: err.toString()
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Ejecuta código JavaScript de forma aislada.
|
|
402
|
+
* Utiliza Web Worker cuando está disponible; en caso contrario, recurre al fallback controlado.
|
|
403
|
+
*
|
|
404
|
+
* @param {string} code - Código JS a ejecutar
|
|
405
|
+
* @param {number} timeoutMs - Límite de tiempo máximo en ms
|
|
406
|
+
* @returns {Promise<{ success: boolean, result: string, logs: string[], executionTimeMs: number, error?: string }>}
|
|
407
|
+
*/
|
|
408
|
+
async function execute(code, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
409
|
+
let effectiveTimeout = DEFAULT_TIMEOUT_MS;
|
|
410
|
+
if (typeof timeoutMs === 'number' && !isNaN(timeoutMs) && timeoutMs > 0) {
|
|
411
|
+
effectiveTimeout = timeoutMs;
|
|
412
|
+
} else if (typeof timeoutMs === 'object' && timeoutMs !== null) {
|
|
413
|
+
const parsed = timeoutMs.timeoutMs || timeoutMs.timeout;
|
|
414
|
+
if (typeof parsed === 'number' && !isNaN(parsed) && parsed > 0) {
|
|
415
|
+
effectiveTimeout = parsed;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
if (!code || typeof code !== 'string') {
|
|
420
|
+
return {
|
|
421
|
+
success: false,
|
|
422
|
+
result: '',
|
|
423
|
+
logs: [],
|
|
424
|
+
executionTimeMs: 0,
|
|
425
|
+
error: 'No se proporcionó código JavaScript para ejecutar.'
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const isWorkerSupported = typeof Worker !== 'undefined' &&
|
|
430
|
+
typeof Blob !== 'undefined' &&
|
|
431
|
+
typeof URL !== 'undefined' &&
|
|
432
|
+
typeof URL.createObjectURL === 'function';
|
|
433
|
+
|
|
434
|
+
if (isWorkerSupported) {
|
|
435
|
+
return executeWithWorker(code, effectiveTimeout);
|
|
436
|
+
} else {
|
|
437
|
+
return executeWithFallback(code, effectiveTimeout);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
return {
|
|
442
|
+
execute,
|
|
443
|
+
executeWithWorker,
|
|
444
|
+
executeWithFallback,
|
|
445
|
+
MAX_OUTPUT_LENGTH,
|
|
446
|
+
MAX_LOG_ENTRIES
|
|
447
|
+
};
|
|
448
|
+
});
|
|
449
|
+
|