@jshookmcp/jshook 0.2.8 → 0.3.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 (162) hide show
  1. package/README.md +36 -5
  2. package/README.zh.md +36 -5
  3. package/dist/{AntiCheatDetector-S8VRj-dD.mjs → AntiCheatDetector-CqGDXmfc.mjs} +160 -54
  4. package/dist/{CodeInjector-4Z3ngPoX.mjs → CodeInjector-BdjRfNx7.mjs} +5 -5
  5. package/dist/ConsoleMonitor-DykL3IAw.mjs +2269 -0
  6. package/dist/{DarwinAPI-B8hg_yhz.mjs → DarwinAPI-ETyy0xyo.mjs} +1 -1
  7. package/dist/DetailedDataManager-HT49OrvF.mjs +217 -0
  8. package/dist/EventBus-DFKvADm3.mjs +141 -0
  9. package/dist/EvidenceGraphBridge-318Oi0Lf.mjs +153 -0
  10. package/dist/{ExtensionManager-D5-bO9D8.mjs → ExtensionManager-BDMsY2Dz.mjs} +27 -13
  11. package/dist/{FingerprintManager-BVxFJL2-.mjs → FingerprintManager-BN4UQWnX.mjs} +1 -1
  12. package/dist/{HardwareBreakpoint-DK1yjWkV.mjs → HardwareBreakpoint-Cc2AFq1Y.mjs} +3 -3
  13. package/dist/{HeapAnalyzer-CEbo10xU.mjs → HeapAnalyzer-DruMgsgj.mjs} +21 -21
  14. package/dist/HookGeneratorBuilders.core.generators.storage-CTbB4Lcx.mjs +566 -0
  15. package/dist/InstrumentationSession-DLH0vd-z.mjs +244 -0
  16. package/dist/{MemoryController-DdtnBdD4.mjs → MemoryController-CMtviNW_.mjs} +3 -3
  17. package/dist/{MemoryScanSession-RMixN3bX.mjs → MemoryScanSession-ITgb_NMi.mjs} +81 -78
  18. package/dist/{MemoryScanner-QjK4ld0B.mjs → MemoryScanner-CiL7Z3ey.mjs} +50 -21
  19. package/dist/{NativeMemoryManager.impl-CB6gJ0NM.mjs → NativeMemoryManager.impl-D9Lkovvn.mjs} +20 -56
  20. package/dist/{NativeMemoryManager.utils-BML4q1ry.mjs → NativeMemoryManager.utils-BBlAixF5.mjs} +1 -1
  21. package/dist/{PEAnalyzer-CK0xe0Fs.mjs → PEAnalyzer-DMQ44gen.mjs} +16 -16
  22. package/dist/PageController-BPJNqqBN.mjs +431 -0
  23. package/dist/{PointerChainEngine-Cd73qu5b.mjs → PointerChainEngine-K7wN8Z-w.mjs} +10 -7
  24. package/dist/PrerequisiteError-TuyZIs6n.mjs +20 -0
  25. package/dist/ProcessRegistry-zGg12QbE.mjs +74 -0
  26. package/dist/ResponseBuilder-CJXWmWNw.mjs +143 -0
  27. package/dist/ReverseEvidenceGraph-C02-gXOh.mjs +269 -0
  28. package/dist/ScriptManager-ZuWD-0Jg.mjs +3003 -0
  29. package/dist/{Speedhack-CeF0XmEz.mjs → Speedhack-D-z0umeT.mjs} +2 -2
  30. package/dist/{StructureAnalyzer-D4GkMduU.mjs → StructureAnalyzer-Cav5AVSL.mjs} +9 -6
  31. package/dist/ToolCatalog-5OJdMiF0.mjs +582 -0
  32. package/dist/ToolError-jh9whhMd.mjs +15 -0
  33. package/dist/ToolProbe-DbCFGyrg.mjs +45 -0
  34. package/dist/ToolRegistry-B9krbTtI.mjs +180 -0
  35. package/dist/ToolRouter.policy-BGDAGyeH.mjs +344 -0
  36. package/dist/TraceRecorder-B41Z5XBj.mjs +1286 -0
  37. package/dist/{Win32API-Bc0QnQsN.mjs → Win32API-C2kjj0ze.mjs} +19 -13
  38. package/dist/{Win32Debug-DUHt9XUn.mjs → Win32Debug-CKrGOTpo.mjs} +3 -3
  39. package/dist/WorkflowEngine-DJ6M4opp.mjs +569 -0
  40. package/dist/analysis-BHeJW2Nb.mjs +1234 -0
  41. package/dist/antidebug-BRKeyt27.mjs +1081 -0
  42. package/dist/artifactRetention-CPXkUJXp.mjs +598 -0
  43. package/dist/artifacts-DkfosXH3.mjs +59 -0
  44. package/dist/authorization-schema-DRqyJMSk.mjs +31 -0
  45. package/dist/betterSqlite3-DLSBZodi.mjs +74 -0
  46. package/dist/binary-instrument--V3MAhJ4.mjs +971 -0
  47. package/dist/bind-helpers-ClV34xdn.mjs +42 -0
  48. package/dist/boringssl-inspector-Bo_LOLaS.mjs +180 -0
  49. package/dist/browser-Dx3_S2cG.mjs +4369 -0
  50. package/dist/capabilities-CcHlvWgK.mjs +33 -0
  51. package/dist/concurrency-Drev_Vz9.mjs +41 -0
  52. package/dist/{constants-CCvsN80K.mjs → constants-CDZLOoVv.mjs} +105 -48
  53. package/dist/coordination-DgItD9DL.mjs +259 -0
  54. package/dist/debugger-RS3RSAqs.mjs +1288 -0
  55. package/dist/definitions-BEoYofW5.mjs +47 -0
  56. package/dist/definitions-BRaefg3u.mjs +365 -0
  57. package/dist/definitions-BbkvZkiv.mjs +96 -0
  58. package/dist/definitions-BtWSHJ3o.mjs +17 -0
  59. package/dist/definitions-C1gCHO0i.mjs +43 -0
  60. package/dist/definitions-CDOg_b-l.mjs +138 -0
  61. package/dist/definitions-CVPD9hzZ.mjs +54 -0
  62. package/dist/definitions-Cea8Lgl7.mjs +94 -0
  63. package/dist/definitions-DAgIyjxM.mjs +10 -0
  64. package/dist/definitions-DJA27nsL.mjs +66 -0
  65. package/dist/definitions-DKPFU3LW.mjs +25 -0
  66. package/dist/definitions-DPRpZQ96.mjs +47 -0
  67. package/dist/definitions-DUE5gmdn.mjs +18 -0
  68. package/dist/definitions-DYVjOtxa.mjs +26 -0
  69. package/dist/definitions-DcYLVLCo.mjs +37 -0
  70. package/dist/definitions-Pp5LI2H4.mjs +27 -0
  71. package/dist/definitions-j9KdHVNR.mjs +14 -0
  72. package/dist/definitions-uzkjBwa7.mjs +258 -0
  73. package/dist/definitions-va-AnLuQ.mjs +28 -0
  74. package/dist/encoding-DJeqHmpd.mjs +1079 -0
  75. package/dist/evidence-graph-bridge-DcYizFk2.mjs +136 -0
  76. package/dist/{factory-CibqTNC8.mjs → factory-C90tBff6.mjs} +41 -56
  77. package/dist/flat-target-session-Dgax2Cy3.mjs +29 -0
  78. package/dist/graphql-CoHrhweh.mjs +1197 -0
  79. package/dist/handlers-4jmR0nMs.mjs +898 -0
  80. package/dist/handlers-BAHPxcch.mjs +789 -0
  81. package/dist/handlers-BOs9b907.mjs +2600 -0
  82. package/dist/handlers-BWXEy6ef.mjs +917 -0
  83. package/dist/handlers-Bndn6QvE.mjs +111 -0
  84. package/dist/handlers-BqC4bD4s.mjs +681 -0
  85. package/dist/handlers-BtYq60bM2.mjs +276 -0
  86. package/dist/handlers-BzgcB4iv.mjs +799 -0
  87. package/dist/handlers-CRyRWj2b.mjs +859 -0
  88. package/dist/handlers-CVv2H1uq.mjs +592 -0
  89. package/dist/handlers-Dl5a7JS4.mjs +572 -0
  90. package/dist/handlers-Dx2d7jt7.mjs +2537 -0
  91. package/dist/handlers-Dz9PYsCa.mjs +2805 -0
  92. package/dist/handlers-HujRKC3b.mjs +661 -0
  93. package/dist/handlers.impl-XWXkQfyi.mjs +807 -0
  94. package/dist/hooks-B1B8NRHL.mjs +898 -0
  95. package/dist/index.mjs +491 -259
  96. package/dist/{logger-BmWzC2lM.mjs → logger-Dh_xb7_2.mjs} +14 -6
  97. package/dist/maintenance-PRMkLVRW.mjs +835 -0
  98. package/dist/manifest-67Bok-Si.mjs +58 -0
  99. package/dist/manifest-6lNTMZAB2.mjs +87 -0
  100. package/dist/manifest-B2duEHiH.mjs +90 -0
  101. package/dist/manifest-B6EY9Vm8.mjs +57 -0
  102. package/dist/manifest-B6nKSbyY.mjs +95 -0
  103. package/dist/manifest-BL8AQNPF.mjs +106 -0
  104. package/dist/manifest-BSZvJJmV.mjs +47 -0
  105. package/dist/manifest-BU7qzUyX.mjs +418 -0
  106. package/dist/manifest-Bl62e8WK.mjs +49 -0
  107. package/dist/manifest-Bo5cXjdt.mjs +82 -0
  108. package/dist/manifest-BpS4gtUK.mjs +1347 -0
  109. package/dist/manifest-Bv65_e2W.mjs +101 -0
  110. package/dist/manifest-BytNIF4Z.mjs +117 -0
  111. package/dist/manifest-C-xtsjS3.mjs +81 -0
  112. package/dist/manifest-CDYl7OhA.mjs +66 -0
  113. package/dist/manifest-CRZ3xmkD.mjs +61 -0
  114. package/dist/manifest-CoW6u4Tp.mjs +132 -0
  115. package/dist/manifest-Cq5zN_8A.mjs +50 -0
  116. package/dist/manifest-D7YZM_2e.mjs +194 -0
  117. package/dist/manifest-DE_VrAeQ.mjs +314 -0
  118. package/dist/manifest-DGsXSCpT.mjs +39 -0
  119. package/dist/manifest-DJ2vfEuW.mjs +156 -0
  120. package/dist/manifest-DPXDYhEu.mjs +80 -0
  121. package/dist/manifest-Dd4fQb0a.mjs +322 -0
  122. package/dist/manifest-Deq6opGg.mjs +223 -0
  123. package/dist/manifest-DfJTafJK.mjs +37 -0
  124. package/dist/manifest-DgOdgN_j.mjs +50 -0
  125. package/dist/manifest-DlbMW4v4.mjs +47 -0
  126. package/dist/manifest-DmVfbH0w.mjs +374 -0
  127. package/dist/manifest-Dog6Ddjr.mjs +109 -0
  128. package/dist/manifest-DvgU5FWb.mjs +58 -0
  129. package/dist/manifest-HsfDBs7j.mjs +50 -0
  130. package/dist/manifest-I8oQHvCG.mjs +186 -0
  131. package/dist/manifest-NvH_a-av.mjs +786 -0
  132. package/dist/manifest-cEJU1v0Z.mjs +129 -0
  133. package/dist/manifest-wOl5XLB12.mjs +112 -0
  134. package/dist/modules-tZozf0LQ.mjs +10635 -0
  135. package/dist/mojo-ipc-DXNEXEqb.mjs +640 -0
  136. package/dist/network-CPVvwvFg.mjs +3852 -0
  137. package/dist/{artifacts-BbdOMET5.mjs → outputPaths-um7lCRY3.mjs} +219 -216
  138. package/dist/parse-args-B4cY5Vx5.mjs +39 -0
  139. package/dist/platform-CYeFoTWp.mjs +2161 -0
  140. package/dist/process-BTbgcVc6.mjs +1306 -0
  141. package/dist/proxy-r8YN6nP1.mjs +192 -0
  142. package/dist/registry-Bl8ZQW61.mjs +34 -0
  143. package/dist/response-CWhh2aLo.mjs +34 -0
  144. package/dist/server/plugin-api.mjs +2 -2
  145. package/dist/shared-state-board-BoZnSoj-.mjs +586 -0
  146. package/dist/sourcemap-BIDHUVXy.mjs +934 -0
  147. package/dist/ssrf-policy-Dsqd-DTX.mjs +166 -0
  148. package/dist/streaming-Dal6utPp.mjs +725 -0
  149. package/dist/tool-builder-BHJp32mV.mjs +186 -0
  150. package/dist/transform-DRVgGG90.mjs +1011 -0
  151. package/dist/types-Bx92KJfT.mjs +4 -0
  152. package/dist/wasm-BYx5UOeG.mjs +1044 -0
  153. package/dist/webcrack-Be0_FccV.mjs +747 -0
  154. package/dist/workflow-BpuKEtvn.mjs +725 -0
  155. package/package.json +82 -49
  156. package/dist/ExtensionManager-CPTJhHFg.mjs +0 -2
  157. package/dist/ToolCatalog-Bq4V2sbJ.mjs +0 -67201
  158. package/dist/{CacheAdapters-CzFNpD9a.mjs → CacheAdapters-jJFy20G-.mjs} +0 -0
  159. package/dist/{StealthVerifier-BzBCFiwx.mjs → StealthVerifier-BWmPgQsv.mjs} +0 -0
  160. package/dist/{VersionDetector-CNXcvD46.mjs → VersionDetector-K3V4vGsw.mjs} +0 -0
  161. package/dist/{formatAddress-ChCSIRWT.mjs → formatAddress-nnMvEohD.mjs} +0 -0
  162. package/dist/{types-BBjOqye-.mjs → types-DDBWs9UP.mjs} +1 -1
@@ -0,0 +1,1011 @@
1
+ import { Fr as WORKER_POOL_MIN_WORKERS, Mr as WORKER_POOL_IDLE_TIMEOUT_MS, Nr as WORKER_POOL_JOB_TIMEOUT_MS, Pr as WORKER_POOL_MAX_WORKERS, _r as TRANSFORM_CRYPTO_POOL_MAX_OLD_GEN_MB, br as TRANSFORM_WORKER_TIMEOUT_MS, gr as TRANSFORM_CRYPTO_POOL_IDLE_TIMEOUT_MS, vr as TRANSFORM_CRYPTO_POOL_MAX_WORKERS, yr as TRANSFORM_CRYPTO_POOL_MAX_YOUNG_GEN_MB } from "./constants-CDZLOoVv.mjs";
2
+ import { t as ProcessRegistry } from "./ProcessRegistry-zGg12QbE.mjs";
3
+ import "./modules-tZozf0LQ.mjs";
4
+ import { t as ScriptManager } from "./ScriptManager-ZuWD-0Jg.mjs";
5
+ import { s as evaluateWithTimeout } from "./PageController-BPJNqqBN.mjs";
6
+ import "./definitions-va-AnLuQ.mjs";
7
+ import { Worker } from "node:worker_threads";
8
+ //#region src/utils/WorkerPool.ts
9
+ const DEFAULT_MIN_WORKERS = WORKER_POOL_MIN_WORKERS;
10
+ const DEFAULT_MAX_WORKERS = WORKER_POOL_MAX_WORKERS;
11
+ const DEFAULT_IDLE_TIMEOUT_MS = WORKER_POOL_IDLE_TIMEOUT_MS;
12
+ const DEFAULT_JOB_TIMEOUT_MS = WORKER_POOL_JOB_TIMEOUT_MS;
13
+ /**
14
+ * Generic worker pool with O(1) dispatch, idle eviction, and graceful shutdown.
15
+ */
16
+ var WorkerPool = class {
17
+ name;
18
+ workerScript;
19
+ minWorkers;
20
+ maxWorkers;
21
+ idleTimeoutMs;
22
+ resourceLimits;
23
+ workers = /* @__PURE__ */ new Map();
24
+ queuedJobs = [];
25
+ activeJobs = /* @__PURE__ */ new Map();
26
+ nextWorkerId = 1;
27
+ nextJobId = 1;
28
+ closed = false;
29
+ constructor(options) {
30
+ this.name = options.name ?? "worker-pool";
31
+ this.workerScript = options.workerScript;
32
+ this.minWorkers = options.minWorkers ?? DEFAULT_MIN_WORKERS;
33
+ this.maxWorkers = options.maxWorkers ?? DEFAULT_MAX_WORKERS;
34
+ this.idleTimeoutMs = options.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS;
35
+ this.resourceLimits = options.resourceLimits;
36
+ if (!this.workerScript || this.workerScript.trim().length === 0) throw this.toError("workerScript must be a non-empty string");
37
+ if (!Number.isInteger(this.minWorkers) || this.minWorkers < 0) throw this.toError("minWorkers must be an integer >= 0");
38
+ if (!Number.isInteger(this.maxWorkers) || this.maxWorkers < 1) throw this.toError("maxWorkers must be an integer >= 1");
39
+ if (this.minWorkers > this.maxWorkers) throw this.toError("minWorkers cannot be greater than maxWorkers");
40
+ this.ensureMinWorkers();
41
+ }
42
+ submit(payload, timeoutMs = DEFAULT_JOB_TIMEOUT_MS) {
43
+ if (this.closed) return Promise.reject(this.toError("pool is closed"));
44
+ return new Promise((resolve, reject) => {
45
+ const job = {
46
+ id: this.nextJobId++,
47
+ payload,
48
+ timeoutMs,
49
+ resolve,
50
+ reject
51
+ };
52
+ this.queuedJobs.push(job);
53
+ this.pumpQueue();
54
+ });
55
+ }
56
+ async warmup(count = 1) {
57
+ if (this.closed) return;
58
+ const toSpawn = Math.min(count, this.maxWorkers - this.workers.size);
59
+ for (let i = 0; i < toSpawn; i++) {
60
+ const worker = this.spawnWorker();
61
+ this.armIdleTimer(worker);
62
+ }
63
+ }
64
+ async close() {
65
+ if (this.closed) return;
66
+ this.closed = true;
67
+ const closeError = this.toError("pool is closed");
68
+ while (this.queuedJobs.length > 0) this.queuedJobs.shift()?.reject(closeError);
69
+ for (const activeJob of this.activeJobs.values()) {
70
+ if (activeJob.timeoutHandle) clearTimeout(activeJob.timeoutHandle);
71
+ activeJob.reject(closeError);
72
+ }
73
+ this.activeJobs.clear();
74
+ const workerIds = Array.from(this.workers.keys());
75
+ await Promise.all(workerIds.map((workerId) => this.terminateWorker(workerId)));
76
+ }
77
+ /**
78
+ * Terminate all idle workers beyond minWorkers, freeing memory immediately
79
+ * instead of waiting for the idle timeout.
80
+ */
81
+ async drainIdle() {
82
+ if (this.closed) return;
83
+ const toTerminate = [];
84
+ for (const [id, worker] of this.workers) if (!worker.busy && this.workers.size - toTerminate.length > this.minWorkers) toTerminate.push(id);
85
+ await Promise.all(toTerminate.map((id) => this.terminateWorker(id)));
86
+ }
87
+ ensureMinWorkers() {
88
+ /* v8 ignore next */
89
+ if (this.closed) return;
90
+ while (this.workers.size < this.minWorkers) this.spawnWorker();
91
+ }
92
+ pumpQueue() {
93
+ /* v8 ignore next */
94
+ if (this.closed) return;
95
+ while (this.queuedJobs.length > 0) {
96
+ let worker = this.findIdleWorker();
97
+ if (!worker) if (this.workers.size < this.maxWorkers) worker = this.spawnWorker();
98
+ else return;
99
+ const job = this.queuedJobs.shift();
100
+ /* v8 ignore next */
101
+ if (!job) return;
102
+ this.dispatchJob(worker, job);
103
+ }
104
+ }
105
+ findIdleWorker() {
106
+ for (const worker of this.workers.values()) if (!worker.busy) return worker;
107
+ }
108
+ spawnWorker() {
109
+ const id = this.nextWorkerId++;
110
+ const worker = new Worker(this.workerScript, {
111
+ eval: true,
112
+ resourceLimits: this.resourceLimits
113
+ });
114
+ if (typeof worker.unref === "function") worker.unref();
115
+ ProcessRegistry.register(worker);
116
+ const pooled = {
117
+ id,
118
+ worker,
119
+ busy: false,
120
+ activeJobId: null,
121
+ idleTimer: null
122
+ };
123
+ worker.on("message", (message) => this.handleWorkerMessage(id, message));
124
+ worker.on("error", (error) => this.handleWorkerFailure(id, error));
125
+ worker.on("exit", (code) => this.handleWorkerExit(id, code));
126
+ this.workers.set(id, pooled);
127
+ return pooled;
128
+ }
129
+ dispatchJob(worker, job) {
130
+ worker.busy = true;
131
+ worker.activeJobId = job.id;
132
+ if (worker.idleTimer) {
133
+ clearTimeout(worker.idleTimer);
134
+ worker.idleTimer = null;
135
+ }
136
+ const timeoutHandle = setTimeout(() => {
137
+ this.handleJobTimeout(job.id, job.timeoutMs);
138
+ }, job.timeoutMs);
139
+ this.activeJobs.set(job.id, {
140
+ ...job,
141
+ workerId: worker.id,
142
+ timeoutHandle
143
+ });
144
+ try {
145
+ worker.worker.postMessage({
146
+ jobId: job.id,
147
+ payload: job.payload
148
+ });
149
+ } catch (error) {
150
+ const activeJob = this.activeJobs.get(job.id);
151
+ if (activeJob?.timeoutHandle) clearTimeout(activeJob.timeoutHandle);
152
+ this.activeJobs.delete(job.id);
153
+ worker.busy = false;
154
+ worker.activeJobId = null;
155
+ job.reject(this.toError(error instanceof Error ? error.message : String(error)));
156
+ this.terminateWorker(worker.id).then(() => {
157
+ this.ensureMinWorkers();
158
+ this.pumpQueue();
159
+ });
160
+ }
161
+ }
162
+ handleWorkerMessage(workerId, message) {
163
+ const envelope = message;
164
+ if (!envelope || typeof envelope !== "object" || typeof envelope.jobId !== "number") return;
165
+ const activeJob = this.activeJobs.get(envelope.jobId);
166
+ if (!activeJob) return;
167
+ if (activeJob.timeoutHandle) clearTimeout(activeJob.timeoutHandle);
168
+ this.activeJobs.delete(envelope.jobId);
169
+ const worker = this.workers.get(workerId);
170
+ if (worker) {
171
+ worker.busy = false;
172
+ worker.activeJobId = null;
173
+ this.armIdleTimer(worker);
174
+ }
175
+ if (!envelope.ok) activeJob.reject(this.toError(envelope.error ?? "worker task failed"));
176
+ else if (typeof envelope.result === "undefined") activeJob.reject(this.toError("worker returned empty result"));
177
+ else activeJob.resolve(envelope.result);
178
+ this.pumpQueue();
179
+ }
180
+ handleWorkerFailure(workerId, error) {
181
+ const worker = this.workers.get(workerId);
182
+ /* v8 ignore next */
183
+ if (!worker) return;
184
+ const activeJobId = worker.activeJobId;
185
+ if (activeJobId !== null) {
186
+ const activeJob = this.activeJobs.get(activeJobId);
187
+ if (activeJob) {
188
+ if (activeJob.timeoutHandle) clearTimeout(activeJob.timeoutHandle);
189
+ this.activeJobs.delete(activeJobId);
190
+ activeJob.reject(this.toError(error.message));
191
+ }
192
+ }
193
+ this.terminateWorker(workerId).then(() => {
194
+ this.ensureMinWorkers();
195
+ this.pumpQueue();
196
+ });
197
+ }
198
+ handleWorkerExit(workerId, code) {
199
+ const worker = this.workers.get(workerId);
200
+ /* v8 ignore next */
201
+ if (!worker) return;
202
+ const activeJobId = worker.activeJobId;
203
+ this.workers.delete(workerId);
204
+ if (worker.idleTimer) clearTimeout(worker.idleTimer);
205
+ if (activeJobId !== null) {
206
+ const activeJob = this.activeJobs.get(activeJobId);
207
+ if (activeJob) {
208
+ if (activeJob.timeoutHandle) clearTimeout(activeJob.timeoutHandle);
209
+ this.activeJobs.delete(activeJobId);
210
+ activeJob.reject(this.toError(`worker exited unexpectedly with code ${code}`));
211
+ }
212
+ }
213
+ this.ensureMinWorkers();
214
+ this.pumpQueue();
215
+ }
216
+ handleJobTimeout(jobId, timeoutMs) {
217
+ const activeJob = this.activeJobs.get(jobId);
218
+ /* v8 ignore next */
219
+ if (!activeJob) return;
220
+ this.activeJobs.delete(jobId);
221
+ activeJob.reject(this.toError(`worker task timed out after ${timeoutMs}ms`));
222
+ this.terminateWorker(activeJob.workerId).then(() => {
223
+ this.ensureMinWorkers();
224
+ this.pumpQueue();
225
+ });
226
+ }
227
+ armIdleTimer(worker) {
228
+ if (this.idleTimeoutMs <= 0 || this.workers.size <= this.minWorkers) return;
229
+ if (worker.idleTimer) clearTimeout(worker.idleTimer);
230
+ worker.idleTimer = setTimeout(() => {
231
+ const current = this.workers.get(worker.id);
232
+ /* v8 ignore next */
233
+ if (!current || current.busy || this.workers.size <= this.minWorkers) return;
234
+ this.terminateWorker(worker.id);
235
+ }, this.idleTimeoutMs);
236
+ }
237
+ async terminateWorker(workerId) {
238
+ const worker = this.workers.get(workerId);
239
+ /* v8 ignore next */
240
+ if (!worker) return;
241
+ this.workers.delete(workerId);
242
+ if (worker.idleTimer) clearTimeout(worker.idleTimer);
243
+ worker.idleTimer = null;
244
+ worker.worker.removeAllListeners("message");
245
+ worker.worker.removeAllListeners("error");
246
+ worker.worker.removeAllListeners("exit");
247
+ try {
248
+ await worker.worker.terminate();
249
+ } catch {}
250
+ }
251
+ toError(message) {
252
+ return /* @__PURE__ */ new Error(`[${this.name}] ${message}`);
253
+ }
254
+ };
255
+ const SUPPORTED_TRANSFORM_SET = new Set([
256
+ "constant_fold",
257
+ "string_decrypt",
258
+ "dead_code_remove",
259
+ "control_flow_flatten",
260
+ "rename_vars"
261
+ ]);
262
+ const NUMERIC_BINARY_EXPR = /\b(-?\d+(?:\.\d+)?)\s*([+\-*/%])\s*(-?\d+(?:\.\d+)?)\b/g;
263
+ const STRING_CONCAT_EXPR = /(['"])((?:\\.|(?!\1)[^\\])*)\1\s*\+\s*(['"])((?:\\.|(?!\3)[^\\])*)\3/g;
264
+ const STRING_LITERAL_EXPR = /(['"])((?:\\.|(?!\1)[^\\])*)\1/g;
265
+ const DEAD_CODE_IF_FALSE_WITH_ELSE = /if\s*\(\s*(?:false|0|!0\s*===\s*!1)\s*\)\s*\{([\s\S]*?)\}\s*else\s*\{([\s\S]*?)\}/g;
266
+ const DEAD_CODE_IF_FALSE = /if\s*\(\s*(?:false|0|!0\s*===\s*!1)\s*\)\s*\{[\s\S]*?\}/g;
267
+ const WORKER_TIMEOUT_MS = TRANSFORM_WORKER_TIMEOUT_MS;
268
+ const CRYPTO_KEYWORDS = [
269
+ "cryptojs",
270
+ "md5",
271
+ "sha",
272
+ "hmac",
273
+ "sign",
274
+ "signature",
275
+ "encrypt",
276
+ "decrypt",
277
+ "aes",
278
+ "rsa"
279
+ ];
280
+ const CRYPTO_TEST_WORKER_SCRIPT = `
281
+ const __bootstrap = async () => {
282
+ const [workerThreads, vm, perfHooks] = await Promise.all([
283
+ import('node:worker_threads'), import('node:vm'), import('node:perf_hooks'),
284
+ ]);
285
+ const parentPort = workerThreads.parentPort;
286
+ const performance = perfHooks.performance;
287
+ if (!parentPort) throw new Error('worker parentPort is unavailable');
288
+ function normalizeOutput(value) {
289
+ if (value === undefined) return '__undefined__';
290
+ if (value === null) return 'null';
291
+ if (typeof value === 'string') return value;
292
+ if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') return String(value);
293
+ try { return JSON.stringify(value); } catch { return String(value); }
294
+ }
295
+ parentPort.on('message', async (msg) => {
296
+ const { jobId, payload } = msg;
297
+ try {
298
+ const { code, functionName, testInputs } = payload;
299
+ const sandbox = Object.create(null);
300
+ sandbox.console = Object.freeze({ log() {}, warn() {}, error() {} });
301
+ sandbox.Buffer = { from: (...args) => Buffer.from(...args), alloc: (size) => Buffer.alloc(Math.min(size, 1048576)), concat: (...args) => Buffer.concat(...args) };
302
+ Object.freeze(sandbox.Buffer);
303
+ sandbox.TextEncoder = TextEncoder; sandbox.TextDecoder = TextDecoder;
304
+ sandbox.atob = (v) => Buffer.from(String(v), 'base64').toString('binary');
305
+ sandbox.btoa = (v) => Buffer.from(String(v), 'binary').toString('base64');
306
+ sandbox.globalThis = sandbox; Object.freeze(sandbox);
307
+ const context = vm.createContext(sandbox);
308
+ const isValidIdentifier = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(functionName);
309
+ const targetExpression = isValidIdentifier
310
+ ? "(typeof " + functionName + " !== 'undefined' ? " + functionName + " : globalThis[" + JSON.stringify(functionName) + "])"
311
+ : "globalThis[" + JSON.stringify(functionName) + "]";
312
+ const script = new vm.Script(
313
+ "(() => {\\n" + code + "\\n;return " + targetExpression + ";\\n})()",
314
+ { timeout: 5000 },
315
+ );
316
+ const targetFn = script.runInContext(context, { timeout: 5000 });
317
+ if (typeof targetFn !== 'function') throw new Error("Function not found or not callable: " + functionName);
318
+ const rows = [];
319
+ for (const input of testInputs) {
320
+ const started = performance.now();
321
+ try {
322
+ const raw = targetFn(input);
323
+ const resolved = raw && typeof raw.then === 'function' ? await raw : raw;
324
+ rows.push({ input, output: normalizeOutput(resolved), duration: Number((performance.now() - started).toFixed(3)) });
325
+ } catch (err) {
326
+ rows.push({ input, output: '', error: err && err.message ? err.message : String(err), duration: Number((performance.now() - started).toFixed(3)) });
327
+ }
328
+ }
329
+ parentPort.postMessage({ jobId, ok: true, result: { ok: true, results: rows } });
330
+ } catch (error) {
331
+ parentPort.postMessage({ jobId, ok: true, result: { ok: false, error: error && error.message ? error.message : String(error), results: [] } });
332
+ }
333
+ });
334
+ };
335
+ __bootstrap().catch((error) => { if (typeof console !== 'undefined' && typeof console.error === 'function') console.error('crypto harness worker bootstrap failed:', error && error.message ? error.message : String(error)); });
336
+ `;
337
+ function createTransformSharedState(collector) {
338
+ return {
339
+ collector,
340
+ chains: /* @__PURE__ */ new Map(),
341
+ cryptoHarnessPool: new WorkerPool({
342
+ name: "crypto-harness",
343
+ workerScript: CRYPTO_TEST_WORKER_SCRIPT,
344
+ minWorkers: 0,
345
+ maxWorkers: TRANSFORM_CRYPTO_POOL_MAX_WORKERS,
346
+ idleTimeoutMs: TRANSFORM_CRYPTO_POOL_IDLE_TIMEOUT_MS,
347
+ resourceLimits: {
348
+ maxOldGenerationSizeMb: TRANSFORM_CRYPTO_POOL_MAX_OLD_GEN_MB,
349
+ maxYoungGenerationSizeMb: TRANSFORM_CRYPTO_POOL_MAX_YOUNG_GEN_MB,
350
+ stackSizeMb: 8
351
+ }
352
+ })
353
+ };
354
+ }
355
+ function toTextResponse(payload) {
356
+ return { content: [{
357
+ type: "text",
358
+ text: JSON.stringify(payload, null, 2)
359
+ }] };
360
+ }
361
+ function fail(tool, error) {
362
+ return toTextResponse({
363
+ tool,
364
+ error: error instanceof Error ? error.message : String(error)
365
+ });
366
+ }
367
+ function parseTransforms(raw) {
368
+ const values = Array.isArray(raw) ? raw.map((item) => String(item).trim()).filter((item) => item.length > 0) : typeof raw === "string" ? raw.split(",").map((item) => item.trim()).filter((item) => item.length > 0) : [];
369
+ if (values.length === 0) throw new Error("transforms must contain at least one transform");
370
+ const unique = [];
371
+ const seen = /* @__PURE__ */ new Set();
372
+ for (const value of values) {
373
+ if (!SUPPORTED_TRANSFORM_SET.has(value)) throw new Error(`Unsupported transform: ${value}`);
374
+ if (!seen.has(value)) {
375
+ seen.add(value);
376
+ unique.push(value);
377
+ }
378
+ }
379
+ return unique;
380
+ }
381
+ function parseTestInputs(raw) {
382
+ if (!Array.isArray(raw)) throw new Error("testInputs must be an array of strings");
383
+ const normalized = raw.map((item) => String(item));
384
+ if (normalized.length === 0) throw new Error("testInputs cannot be empty");
385
+ return normalized;
386
+ }
387
+ function parseBoolean(raw, defaultValue) {
388
+ if (typeof raw === "boolean") return raw;
389
+ if (typeof raw === "string") {
390
+ const n = raw.trim().toLowerCase();
391
+ if ([
392
+ "true",
393
+ "1",
394
+ "yes",
395
+ "on"
396
+ ].includes(n)) return true;
397
+ if ([
398
+ "false",
399
+ "0",
400
+ "no",
401
+ "off"
402
+ ].includes(n)) return false;
403
+ }
404
+ if (typeof raw === "number") {
405
+ if (raw === 1) return true;
406
+ if (raw === 0) return false;
407
+ }
408
+ return defaultValue;
409
+ }
410
+ function requireString(raw, field) {
411
+ if (typeof raw !== "string" || raw.length === 0) throw new Error(`${field} must be a non-empty string`);
412
+ return raw;
413
+ }
414
+ function escapeStringContent(value, quote) {
415
+ const escapedControls = value.replace(/\\/g, "\\\\").replace(/\r/g, "\\r").replace(/\n/g, "\\n").replace(/\t/g, "\\t");
416
+ return quote === "\"" ? escapedControls.replace(/"/g, "\\\"") : escapedControls.replace(/'/g, "\\'");
417
+ }
418
+ function decodeEscapedString(value) {
419
+ return value.replace(/\\x([0-9a-fA-F]{2})/g, (_f, hex) => String.fromCharCode(parseInt(hex, 16))).replace(/\\u\{([0-9a-fA-F]{1,6})\}/g, (_f, hex) => String.fromCodePoint(parseInt(hex, 16))).replace(/\\u([0-9a-fA-F]{4})/g, (_f, hex) => String.fromCharCode(parseInt(hex, 16))).replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ").replace(/\\v/g, "\v").replace(/\\f/g, "\f").replace(/\\0/g, "\0").replace(/\\"/g, "\"").replace(/\\'/g, "'").replace(/\\\\/g, "\\");
420
+ }
421
+ async function resolveScriptSource(collector, scriptId) {
422
+ let manager = null;
423
+ try {
424
+ manager = new ScriptManager(collector);
425
+ const script = await manager.getScriptSource(scriptId);
426
+ if (script?.source && script.source.length > 0) return script.source;
427
+ } catch {} finally {
428
+ if (manager) try {
429
+ await manager.close();
430
+ } catch {}
431
+ }
432
+ const fromCache = collector.getFileByUrl(scriptId);
433
+ if (fromCache?.content && fromCache.content.length > 0) return fromCache.content;
434
+ const pageSource = await (await collector.getActivePage()).evaluate(async (id) => {
435
+ const scripts = Array.from(document.scripts);
436
+ const byNumericIndex = Number(id);
437
+ if (Number.isInteger(byNumericIndex) && byNumericIndex >= 0 && byNumericIndex < scripts.length) {
438
+ const script = scripts[byNumericIndex];
439
+ if (script.textContent && script.textContent.trim().length > 0) return script.textContent;
440
+ if (script.src) try {
441
+ const r = await fetch(script.src);
442
+ if (r.ok) return await r.text();
443
+ } catch {}
444
+ }
445
+ for (const script of scripts) {
446
+ if (script.id === id || script.dataset?.scriptId === id) {
447
+ if (script.textContent && script.textContent.trim().length > 0) return script.textContent;
448
+ if (script.src) try {
449
+ const r = await fetch(script.src);
450
+ if (r.ok) return await r.text();
451
+ } catch {}
452
+ }
453
+ if (script.src && script.src.includes(id)) try {
454
+ const r = await fetch(script.src);
455
+ if (r.ok) return await r.text();
456
+ } catch {}
457
+ }
458
+ return "";
459
+ }, scriptId);
460
+ if (typeof pageSource === "string" && pageSource.length > 0) return pageSource;
461
+ throw new Error(`Unable to resolve source from scriptId: ${scriptId}`);
462
+ }
463
+ function extractLastSegment(value) {
464
+ const parts = (value.startsWith("window.") ? value.slice(7) : value).split(".").filter(Boolean);
465
+ return parts.length > 0 ? parts[parts.length - 1] : "";
466
+ }
467
+ function resolveFunctionName(targetFunction, targetPath, source) {
468
+ const c1 = extractLastSegment(targetFunction);
469
+ if (isValidIdentifier(c1)) return c1;
470
+ const c2 = extractLastSegment(targetPath);
471
+ if (isValidIdentifier(c2)) return c2;
472
+ const match = source.match(/function\s+([A-Za-z_$][A-Za-z0-9_$]*)\s*\(/);
473
+ if (match?.[1] && isValidIdentifier(match[1])) return match[1];
474
+ return "extractedCryptoFn";
475
+ }
476
+ function isValidIdentifier(value) {
477
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(value);
478
+ }
479
+ async function ensureCryptoPoolWarmed(pool) {
480
+ await pool.warmup(1);
481
+ }
482
+ function buildCryptoPolyfills() {
483
+ return `
484
+ const __textEncoder = typeof TextEncoder !== 'undefined' ? new TextEncoder() : null;
485
+ const __textDecoder = typeof TextDecoder !== 'undefined' ? new TextDecoder() : null;
486
+ if (typeof globalThis.atob === 'undefined') { globalThis.atob = (value) => Buffer.from(String(value), 'base64').toString('binary'); }
487
+ if (typeof globalThis.btoa === 'undefined') { globalThis.btoa = (value) => Buffer.from(String(value), 'binary').toString('base64'); }
488
+ `.trim();
489
+ }
490
+ async function runCryptoHarness(pool, code, functionName, testInputs) {
491
+ try {
492
+ const msg = await pool.submit({
493
+ code,
494
+ functionName,
495
+ testInputs
496
+ }, WORKER_TIMEOUT_MS);
497
+ if (!msg.ok) return {
498
+ results: testInputs.map((input) => ({
499
+ input,
500
+ output: "",
501
+ duration: 0,
502
+ error: msg.error ?? "Worker execution failed"
503
+ })),
504
+ allPassed: false
505
+ };
506
+ const rows = Array.isArray(msg.results) ? msg.results : [];
507
+ return {
508
+ results: rows,
509
+ allPassed: rows.every((row) => !row.error)
510
+ };
511
+ } catch (error) {
512
+ return {
513
+ results: testInputs.map((input) => ({
514
+ input,
515
+ output: "",
516
+ duration: 0,
517
+ error: error instanceof Error ? error.message : String(error)
518
+ })),
519
+ allPassed: false
520
+ };
521
+ }
522
+ }
523
+ //#endregion
524
+ //#region src/server/domains/transform/handlers/transform-operations.ts
525
+ function resolveTransformsForApply(chains, chainName, transformsRaw) {
526
+ if (chainName.length > 0) {
527
+ const chain = chains.get(chainName);
528
+ if (!chain) throw new Error(`Transform chain not found: ${chainName}`);
529
+ return [...chain.transforms];
530
+ }
531
+ return parseTransforms(transformsRaw);
532
+ }
533
+ function applyTransforms(code, transforms) {
534
+ let transformed = code;
535
+ const appliedTransforms = [];
536
+ for (const transform of transforms) {
537
+ const before = transformed;
538
+ transformed = applySingleTransform(transformed, transform);
539
+ if (transformed !== before) appliedTransforms.push(transform);
540
+ }
541
+ return {
542
+ transformed,
543
+ appliedTransforms
544
+ };
545
+ }
546
+ function applySingleTransform(code, transform) {
547
+ switch (transform) {
548
+ case "constant_fold": return transformConstantFold(code);
549
+ case "string_decrypt": return transformStringDecrypt(code);
550
+ case "dead_code_remove": return transformDeadCodeRemove(code);
551
+ case "control_flow_flatten": return transformControlFlowFlatten(code);
552
+ case "rename_vars": return transformRenameVars(code);
553
+ default: return code;
554
+ }
555
+ }
556
+ function transformConstantFold(code) {
557
+ let current = code;
558
+ for (let round = 0; round < 4; round++) {
559
+ const stringFolded = current.replace(NUMERIC_BINARY_EXPR, (_full, leftRaw, operator, rightRaw) => {
560
+ const left = Number(leftRaw);
561
+ const right = Number(rightRaw);
562
+ if (!Number.isFinite(left) || !Number.isFinite(right)) return `${leftRaw}${operator}${rightRaw}`;
563
+ let value = null;
564
+ switch (operator) {
565
+ case "+":
566
+ value = left + right;
567
+ break;
568
+ case "-":
569
+ value = left - right;
570
+ break;
571
+ case "*":
572
+ value = left * right;
573
+ break;
574
+ case "/":
575
+ if (right !== 0) value = left / right;
576
+ break;
577
+ case "%":
578
+ if (right !== 0) value = left % right;
579
+ break;
580
+ default: value = null;
581
+ }
582
+ if (value === null || !Number.isFinite(value)) return `${leftRaw}${operator}${rightRaw}`;
583
+ return Number.isInteger(value) ? String(value) : String(Number(value.toFixed(12)));
584
+ }).replace(STRING_CONCAT_EXPR, (_full, q1, left, q2, right) => {
585
+ const quote = q1 === q2 ? q1 : "'";
586
+ return `${quote}${escapeStringContent(`${left}${right}`, quote)}${quote}`;
587
+ });
588
+ if (stringFolded === current) break;
589
+ current = stringFolded;
590
+ }
591
+ return current;
592
+ }
593
+ function transformStringDecrypt(code) {
594
+ return code.replace(STRING_LITERAL_EXPR, (_full, quote, inner) => {
595
+ const decoded = decodeEscapedString(inner);
596
+ if (decoded === inner) return `${quote}${inner}${quote}`;
597
+ return `${quote}${escapeStringContent(decoded, quote)}${quote}`;
598
+ });
599
+ }
600
+ function transformDeadCodeRemove(code) {
601
+ return code.replace(DEAD_CODE_IF_FALSE_WITH_ELSE, (_full, _ifBody, elseBody) => elseBody).replace(DEAD_CODE_IF_FALSE, "");
602
+ }
603
+ function transformControlFlowFlatten(code) {
604
+ return code.replace(/var\s+([A-Za-z_$][A-Za-z0-9_$]*)\s*=\s*['"]([^'"]+)['"]\.split\(\s*['"]\|['"]\s*\)\s*;\s*var\s+([A-Za-z_$][A-Za-z0-9_$]*)\s*=\s*0\s*;\s*while\s*\(\s*!!\[\]\s*\)\s*\{\s*switch\s*\(\s*\1\[\s*\3\+\+\s*\]\s*\)\s*\{([\s\S]*?)\}\s*break;\s*\}/g, (_full, _dispatcher, orderRaw, _cursor, switchBody) => {
605
+ const caseRegex = /case\s*['"]([^'"]+)['"]\s*:\s*([\s\S]*?)(?=case\s*['"]|default\s*:|$)/g;
606
+ const caseMap = /* @__PURE__ */ new Map();
607
+ let match;
608
+ while ((match = caseRegex.exec(switchBody)) !== null) {
609
+ const caseKey = match[1];
610
+ const cleaned = (match[2] ?? "").replace(/\bcontinue\s*;?/g, "").replace(/\bbreak\s*;?/g, "").trim();
611
+ if (caseKey && cleaned.length > 0) caseMap.set(caseKey, cleaned);
612
+ }
613
+ const rebuilt = orderRaw.split("|").map((item) => item.trim()).map((token) => caseMap.get(token)).filter((part) => typeof part === "string" && part.length > 0).join("\n");
614
+ return rebuilt.length > 0 ? rebuilt : _full;
615
+ });
616
+ }
617
+ function transformRenameVars(code) {
618
+ const declaredSingleLetterVars = /* @__PURE__ */ new Set();
619
+ const declarationRegex = /\b(?:var|let|const)\s+([A-Za-z])\b/g;
620
+ let match;
621
+ while ((match = declarationRegex.exec(code)) !== null) {
622
+ const name = match[1];
623
+ if (name) declaredSingleLetterVars.add(name);
624
+ }
625
+ if (declaredSingleLetterVars.size === 0) return code;
626
+ const renameMap = /* @__PURE__ */ new Map();
627
+ let counter = 1;
628
+ for (const name of declaredSingleLetterVars) {
629
+ renameMap.set(name, `var_${counter}`);
630
+ counter += 1;
631
+ }
632
+ return code.replace(/\b([A-Za-z])\b/g, (token, identifier, offset, full) => {
633
+ const replacement = renameMap.get(identifier);
634
+ if (!replacement) return token;
635
+ const prev = offset > 0 ? full[offset - 1] : "";
636
+ if (prev === "." || prev === "'" || prev === "\"" || prev === "`" || prev === "$") return token;
637
+ return replacement;
638
+ });
639
+ }
640
+ function buildDiff(original, transformed) {
641
+ if (original === transformed) return "";
642
+ const oldLines = original.split("\n");
643
+ const newLines = transformed.split("\n");
644
+ if (oldLines.length * newLines.length > 25e4) return buildFallbackDiff(oldLines, newLines);
645
+ const m = oldLines.length;
646
+ const n = newLines.length;
647
+ const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
648
+ for (let i = m - 1; i >= 0; i--) for (let j = n - 1; j >= 0; j--) dp[i][j] = oldLines[i] === newLines[j] ? dp[i + 1][j + 1] + 1 : Math.max(dp[i + 1][j], dp[i][j + 1]);
649
+ const diffLines = [];
650
+ let i = 0;
651
+ let j = 0;
652
+ while (i < m && j < n) {
653
+ if (oldLines[i] === newLines[j]) {
654
+ diffLines.push(` ${oldLines[i]}`);
655
+ i += 1;
656
+ j += 1;
657
+ continue;
658
+ }
659
+ if (dp[i + 1][j] >= dp[i][j + 1]) {
660
+ diffLines.push(`-${oldLines[i]}`);
661
+ i += 1;
662
+ } else {
663
+ diffLines.push(`+${newLines[j]}`);
664
+ j += 1;
665
+ }
666
+ }
667
+ while (i < m) {
668
+ diffLines.push(`-${oldLines[i]}`);
669
+ i += 1;
670
+ }
671
+ while (j < n) {
672
+ diffLines.push(`+${newLines[j]}`);
673
+ j += 1;
674
+ }
675
+ return diffLines.join("\n");
676
+ }
677
+ function buildFallbackDiff(oldLines, newLines) {
678
+ let start = 0;
679
+ while (start < oldLines.length && start < newLines.length && oldLines[start] === newLines[start]) start += 1;
680
+ let oldEnd = oldLines.length - 1;
681
+ let newEnd = newLines.length - 1;
682
+ while (oldEnd >= start && newEnd >= start && oldLines[oldEnd] === newLines[newEnd]) {
683
+ oldEnd -= 1;
684
+ newEnd -= 1;
685
+ }
686
+ const removed = oldLines.slice(start, oldEnd + 1).map((line) => `-${line}`);
687
+ const added = newLines.slice(start, newEnd + 1).map((line) => `+${line}`);
688
+ return [...removed, ...added].join("\n");
689
+ }
690
+ //#endregion
691
+ //#region src/server/domains/transform/handlers/ast-handlers.ts
692
+ var AstHandlers = class {
693
+ state;
694
+ constructor(state) {
695
+ this.state = state;
696
+ }
697
+ async handleAstTransformPreview(args) {
698
+ try {
699
+ const code = requireString(args.code, "code");
700
+ const transforms = parseTransforms(args.transforms);
701
+ const preview = parseBoolean(args.preview, true);
702
+ const result = applyTransforms(code, transforms);
703
+ const diff = preview ? buildDiff(code, result.transformed) : "";
704
+ return toTextResponse({
705
+ original: code,
706
+ transformed: result.transformed,
707
+ diff,
708
+ appliedTransforms: result.appliedTransforms
709
+ });
710
+ } catch (error) {
711
+ return fail("ast_transform_preview", error);
712
+ }
713
+ }
714
+ async handleAstTransformChain(args) {
715
+ try {
716
+ const name = requireString(args.name, "name").trim();
717
+ const description = typeof args.description === "string" && args.description.trim().length > 0 ? args.description.trim() : void 0;
718
+ const transforms = parseTransforms(args.transforms);
719
+ if (name.length === 0) throw new Error("name cannot be empty");
720
+ this.state.chains.set(name, {
721
+ name,
722
+ transforms,
723
+ description,
724
+ createdAt: Date.now()
725
+ });
726
+ return toTextResponse({
727
+ name,
728
+ transforms,
729
+ created: true
730
+ });
731
+ } catch (error) {
732
+ return fail("ast_transform_chain", error);
733
+ }
734
+ }
735
+ async handleAstTransformApply(args) {
736
+ try {
737
+ const chainName = typeof args.chainName === "string" ? args.chainName.trim() : "";
738
+ const inlineCode = typeof args.code === "string" ? args.code : "";
739
+ const scriptId = typeof args.scriptId === "string" ? args.scriptId.trim() : "";
740
+ const sourceCode = inlineCode.length > 0 ? inlineCode : scriptId.length > 0 ? await resolveScriptSource(this.state.collector, scriptId) : "";
741
+ if (sourceCode.length === 0) throw new Error("Either code or scriptId must be provided");
742
+ const result = applyTransforms(sourceCode, resolveTransformsForApply(this.state.chains, chainName, args.transforms));
743
+ return toTextResponse({
744
+ transformed: result.transformed,
745
+ stats: {
746
+ originalSize: sourceCode.length,
747
+ transformedSize: result.transformed.length,
748
+ transformsApplied: result.appliedTransforms
749
+ }
750
+ });
751
+ } catch (error) {
752
+ return fail("ast_transform_apply", error);
753
+ }
754
+ }
755
+ };
756
+ //#endregion
757
+ //#region src/server/domains/transform/handlers/crypto-handlers.ts
758
+ var CryptoHandlers = class {
759
+ state;
760
+ constructor(state) {
761
+ this.state = state;
762
+ }
763
+ async runCryptoHarnessProxy(code, functionName, testInputs) {
764
+ return runCryptoHarness(this.state.cryptoHarnessPool, code, functionName, testInputs);
765
+ }
766
+ async handleCryptoExtractStandalone(args) {
767
+ try {
768
+ const targetFunction = requireString(args.targetFunction, "targetFunction").trim();
769
+ const includePolyfills = parseBoolean(args.includePolyfills, true);
770
+ const extracted = await evaluateWithTimeout(await this.state.collector.getActivePage(), (target, keywords) => {
771
+ const lowerKeywords = (Array.isArray(keywords) ? keywords : []).map((item) => String(item).toLowerCase());
772
+ const globalObj = window;
773
+ const scoreFunction = (path, source) => {
774
+ const text = (path + "\n" + source).toLowerCase();
775
+ let score = 0;
776
+ for (const keyword of lowerKeywords) if (text.includes(keyword)) score += 1;
777
+ return score;
778
+ };
779
+ const candidates = [];
780
+ const pushCandidate = (path, value, boost = 0) => {
781
+ if (typeof value !== "function") return;
782
+ const source = Function.prototype.toString.call(value);
783
+ if (source.includes("[native code]")) return;
784
+ const score = scoreFunction(path, source) + boost;
785
+ if (score <= 0 && boost <= 0) return;
786
+ candidates.push({
787
+ path,
788
+ source,
789
+ score
790
+ });
791
+ };
792
+ if (target.length > 0) pushCandidate(target, (() => {
793
+ const parts = (target.startsWith("window.") ? target.slice(7) : target).split(".").filter(Boolean);
794
+ let cursor = window;
795
+ for (const part of parts) {
796
+ if (cursor === null || cursor === void 0 || typeof cursor !== "object" && typeof cursor !== "function") return;
797
+ const carrier = cursor;
798
+ if (!(part in carrier)) return void 0;
799
+ cursor = carrier[part];
800
+ }
801
+ return cursor;
802
+ })(), 100);
803
+ const globalKeys = Object.getOwnPropertyNames(globalObj).slice(0, 800);
804
+ for (const key of globalKeys) {
805
+ const topValue = globalObj[key];
806
+ pushCandidate("window." + key, topValue);
807
+ if (topValue && typeof topValue === "object") {
808
+ const nestedObj = topValue;
809
+ const nestedKeys = Object.keys(nestedObj).slice(0, 40);
810
+ for (const nestedKey of nestedKeys) pushCandidate("window." + key + "." + nestedKey, nestedObj[nestedKey]);
811
+ }
812
+ }
813
+ candidates.sort((a, b) => b.score - a.score);
814
+ const selected = candidates[0];
815
+ if (!selected) return {
816
+ targetPath: null,
817
+ targetSource: "",
818
+ candidates: [],
819
+ dependencies: [],
820
+ dependencySnippets: []
821
+ };
822
+ const identifierRegex = /\b[A-Za-z_$][A-Za-z0-9_$]{1,}\b/g;
823
+ const reserved = new Set([
824
+ "function",
825
+ "return",
826
+ "const",
827
+ "let",
828
+ "var",
829
+ "if",
830
+ "else",
831
+ "for",
832
+ "while",
833
+ "switch",
834
+ "case",
835
+ "break",
836
+ "continue",
837
+ "new",
838
+ "this",
839
+ "window",
840
+ "globalThis",
841
+ "Math",
842
+ "JSON",
843
+ "Date",
844
+ "Array",
845
+ "Object",
846
+ "String",
847
+ "Number",
848
+ "Boolean",
849
+ "Promise",
850
+ "RegExp",
851
+ "Error",
852
+ "null",
853
+ "undefined",
854
+ "true",
855
+ "false",
856
+ "async",
857
+ "await"
858
+ ]);
859
+ const dependencyNames = Array.from(new Set((selected.source.match(identifierRegex) ?? []).filter((name) => !reserved.has(name)))).slice(0, 30);
860
+ const dependencySnippets = [];
861
+ for (const depName of dependencyNames) {
862
+ if (!(depName in globalObj)) continue;
863
+ const depValue = globalObj[depName];
864
+ if (typeof depValue === "function") {
865
+ const depSource = Function.prototype.toString.call(depValue);
866
+ if (!depSource.includes("[native code]") && depSource.length < 5e4) dependencySnippets.push("const " + depName + " = " + depSource + ";");
867
+ continue;
868
+ }
869
+ if (depValue === null || typeof depValue === "string" || typeof depValue === "number" || typeof depValue === "boolean") {
870
+ dependencySnippets.push("const " + depName + " = " + JSON.stringify(depValue) + ";");
871
+ continue;
872
+ }
873
+ if (typeof depValue === "object") try {
874
+ const serialized = JSON.stringify(depValue);
875
+ if (serialized && serialized.length < 4e3) dependencySnippets.push("const " + depName + " = " + serialized + ";");
876
+ } catch {}
877
+ }
878
+ return {
879
+ targetPath: selected.path,
880
+ targetSource: selected.source,
881
+ candidates: candidates.slice(0, 20),
882
+ dependencies: dependencyNames,
883
+ dependencySnippets
884
+ };
885
+ }, targetFunction, CRYPTO_KEYWORDS);
886
+ if (!extracted || extracted.targetSource.trim().length === 0) throw new Error("No crypto/signature-like function found on current page");
887
+ const functionName = resolveFunctionName(targetFunction, extracted.targetPath ?? "", extracted.targetSource);
888
+ const dependencySnippets = extracted.dependencySnippets.filter((snippet) => !snippet.startsWith(`const ${functionName} = `));
889
+ const dependencies = extracted.dependencies.filter((name) => name !== functionName);
890
+ const sections = [`'use strict';`];
891
+ if (includePolyfills) sections.push(buildCryptoPolyfills());
892
+ if (dependencySnippets.length > 0) sections.push(dependencySnippets.join("\n"));
893
+ sections.push(`const ${functionName} = ${extracted.targetSource.trim()};`);
894
+ sections.push(`if (typeof globalThis !== 'undefined') { globalThis.${functionName} = ${functionName}; }`);
895
+ const extractedCode = sections.filter((part) => part.trim().length > 0).join("\n\n");
896
+ return toTextResponse({
897
+ extractedCode,
898
+ dependencies,
899
+ size: extractedCode.length
900
+ });
901
+ } catch (error) {
902
+ return fail("crypto_extract_standalone", error);
903
+ }
904
+ }
905
+ async handleCryptoTestHarness(args) {
906
+ try {
907
+ const code = requireString(args.code, "code");
908
+ const functionName = requireString(args.functionName, "functionName");
909
+ const testInputs = parseTestInputs(args.testInputs);
910
+ await ensureCryptoPoolWarmed(this.state.cryptoHarnessPool);
911
+ try {
912
+ const harness = await runCryptoHarness(this.state.cryptoHarnessPool, code, functionName, testInputs);
913
+ return toTextResponse({
914
+ results: harness.results.map((row) => ({
915
+ input: row.input,
916
+ output: row.output,
917
+ duration: row.duration,
918
+ ...row.error ? { error: row.error } : {}
919
+ })),
920
+ allPassed: harness.allPassed
921
+ });
922
+ } finally {
923
+ this.state.cryptoHarnessPool.drainIdle?.();
924
+ }
925
+ } catch (error) {
926
+ return fail("crypto_test_harness", error);
927
+ }
928
+ }
929
+ async handleCryptoCompare(args) {
930
+ try {
931
+ const code1 = requireString(args.code1, "code1");
932
+ const code2 = requireString(args.code2, "code2");
933
+ const functionName = requireString(args.functionName, "functionName");
934
+ const testInputs = parseTestInputs(args.testInputs);
935
+ await ensureCryptoPoolWarmed(this.state.cryptoHarnessPool);
936
+ try {
937
+ const [run1, run2] = await Promise.all([runCryptoHarness(this.state.cryptoHarnessPool, code1, functionName, testInputs), runCryptoHarness(this.state.cryptoHarnessPool, code2, functionName, testInputs)]);
938
+ const rows = testInputs.map((input, index) => {
939
+ const left = run1.results[index] ?? {
940
+ input,
941
+ output: "",
942
+ duration: 0,
943
+ error: "missing result from implementation #1"
944
+ };
945
+ const right = run2.results[index] ?? {
946
+ input,
947
+ output: "",
948
+ duration: 0,
949
+ error: "missing result from implementation #2"
950
+ };
951
+ const sameOutput = left.output === right.output;
952
+ const noError = !left.error && !right.error;
953
+ return {
954
+ input,
955
+ output1: left.output,
956
+ output2: right.output,
957
+ duration1: left.duration,
958
+ duration2: right.duration,
959
+ match: sameOutput && noError,
960
+ ...left.error ? { error1: left.error } : {},
961
+ ...right.error ? { error2: right.error } : {}
962
+ };
963
+ });
964
+ const matches = rows.filter((row) => row.match).length;
965
+ return toTextResponse({
966
+ matches,
967
+ mismatches: rows.length - matches,
968
+ results: rows
969
+ });
970
+ } finally {
971
+ this.state.cryptoHarnessPool.drainIdle?.();
972
+ }
973
+ } catch (error) {
974
+ return fail("crypto_compare", error);
975
+ }
976
+ }
977
+ };
978
+ //#endregion
979
+ //#region src/server/domains/transform/handlers.impl.core.ts
980
+ var TransformToolHandlers = class {
981
+ collector;
982
+ state;
983
+ ast;
984
+ crypto;
985
+ constructor(collector) {
986
+ this.collector = collector;
987
+ this.state = createTransformSharedState(collector);
988
+ this.ast = new AstHandlers(this.state);
989
+ this.crypto = new CryptoHandlers(this.state);
990
+ }
991
+ async close() {
992
+ await this.state.cryptoHarnessPool.close();
993
+ }
994
+ get chains() {
995
+ return this.state.chains;
996
+ }
997
+ get cryptoHarnessPool() {
998
+ return this.state.cryptoHarnessPool;
999
+ }
1000
+ async runCryptoHarness(code, functionName, testInputs) {
1001
+ return this.crypto.runCryptoHarnessProxy(code, functionName, testInputs);
1002
+ }
1003
+ handleAstTransformPreview = (args) => this.ast.handleAstTransformPreview(args);
1004
+ handleAstTransformChain = (args) => this.ast.handleAstTransformChain(args);
1005
+ handleAstTransformApply = (args) => this.ast.handleAstTransformApply(args);
1006
+ handleCryptoExtractStandalone = (args) => this.crypto.handleCryptoExtractStandalone(args);
1007
+ handleCryptoTestHarness = (args) => this.crypto.handleCryptoTestHarness(args);
1008
+ handleCryptoCompare = (args) => this.crypto.handleCryptoCompare(args);
1009
+ };
1010
+ //#endregion
1011
+ export { TransformToolHandlers };