Pro API for JSVMP: call VEILVM's JS VM obfuscator from CI

2026-11-03来源 dev.to DevOpsEnglish

I built VEILVM as a browser workspace that compiles JavaScript into a custom VM (JSVMP) — high-performance or dynamic mode — so small critical fragments are harder to reverse than with classic string/control-flow obfuscators.

Pro plans can now hit the same engines over HTTP, which is what you want for CI, batch jobs, or a private build step. API runs share the monthly quota with the web UI.

Quick facts (from the live docs)

  • POST https://vm.ldvmp.com/api/v1/obfuscate
  • Header: Authorization: Bearer veil_live_… (key shown once; up to 3 active keys per account)
  • Body: { "code": "<js>", "mode": "performance" | "dynamic" }
  • Max 2 MB source per request (UTF-8)
  • Success 200: { ok, output, inputBytes, outputBytes, ms, engine, engineVersion } plus X-Quota-Limit / X-Quota-Remaining
  • Plans: Try free 3 times a day, no sign-up; 20 runs a month after free signup; Pro $9/month or $79/year → 1,000 runs/month + API

Full reference: API documentation.

curl

curl -X POST https://vm.ldvmp.com/api/v1/obfuscate \ -H "Authorization: Bearer $VEILVM_API_KEY" \ -H "Content-Type: application/json" \ -d '{"code":"console.log(\"hello\")","mode":"performance"}' 

Node.js 18+ with Retry-After on 503

Cold starts or engine timeouts return 503 with ENGINE_UNAVAILABLE or TIMEOUT. Those runs are not charged. Wait for the Retry-After header (seconds), then retry. 500 INTERNAL_ERROR is also refunded — retry later. 422 COMPILE_FAILED is refunded (bad source, not a transient fault).

// Node.js 18+ — keep the key in an env var, never in the repo import { readFile, writeFile } from "node:fs/promises"; async function obfuscate(code, mode = "performance", { maxAttempts = 4 } = {}) { let attempt = 0; while (true) { attempt += 1; const response = await fetch("https://vm.ldvmp.com/api/v1/obfuscate", { method: "POST", headers: { Authorization: `Bearer ${process.env.VEILVM_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ code, mode }), }); const data = await response.json(); if (response.ok && data.ok) return data; const retriable = response.status === 503 || response.status === 500 || data.error === "ENGINE_UNAVAILABLE" || data.error === "TIMEOUT" || data.error === "INTERNAL_ERROR" || data.error === "UNAVAILABLE" || data.error === "QUOTA_UNAVAILABLE"; if (!retriable || attempt >= maxAttempts) { throw new Error(`${response.status} ${data.error}: ${data.message}`); } const retryAfterHeader = response.headers.get("Retry-After"); const waitSec = Number(retryAfterHeader); const delayMs = Number.isFinite(waitSec) && waitSec > 0 ? waitSec * 1000 : Math.min(8000, 1000 * 2 ** (attempt - 1)); await new Promise((r) => setTimeout(r, delayMs)); } } const code = await readFile("input.js", "utf8"); const data = await obfuscate(code, "dynamic"); await writeFile("output.js", data.output); console.log( `${data.engine}: ${data.inputBytes} → ${data.outputBytes} bytes in ${data.ms} ms` ); 

Error cheat sheet

HTTP error Notes
401 INVALID_KEY Missing, malformed, revoked, or unknown
403 PLAN_REQUIRED Account is no longer Pro — keys die immediately on downgrade
422 COMPILE_FAILED Source would not compile — run refunded
429 QUOTA_EXCEEDED Body includes limit / used / remaining / resetAt
503 ENGINE_UNAVAILABLE / TIMEOUT Wait Retry-After seconds — run refunded
500 INTERNAL_ERROR Retry later — run refunded

Honest caveats

  • VM output is larger and slower; protect small high-value functions, not your whole bundle.
  • No client-side obfuscation is unbreakable.
  • Keep keys server-side; revoke from the Account page if one leaks.

If you try it, I’d love feedback on CI integration vs a future CLI. Links: workspace · pricing · docs.

原文:https://www.a8q9.cn/en/article/pro-api-for-jsvmp-call-veilvm-s-js-vm-obfuscator-from-ci-2e0ca8.html

相关文章