Cloudflare Worker के अंदर JavaScript को obfuscate करें

@afterpack/wasm के साथ AfterPack को अपने Cloudflare Worker में चलाएँ, अपनी Pro key pass करके AfterPack के cloud में build करें, और हर result को rotation window के हिसाब से cache करें।

AfterPack Cloudflare Worker से दो तरीकों से चलता है, एक ही package और एक ही call से। Key के बिना, Free engine आपके Worker के अंदर चलता है, एक WebAssembly module के रूप में जिसे आप npm से install करते हैं। अपनी Pro key के साथ, build AfterPack के cloud में Pro engine पर चलती है।

यह पेज दोनों को कवर करता है, फिर बताता है कि result को कैसे cache करें ताकि हर asset हर rotation window में एक ही बार build हो।

AfterPack, आपके अपने Worker के अंदर

@afterpack/wasm WebAssembly में compile किया गया AfterPack है। यह वही Rust engine है जिसे CLI और framework plugins चलाते हैं, बस आपकी मशीन की architecture के बजाय wasm32 के लिए build किया गया।

npm install @afterpack/wasm
import { obfuscate } from "@afterpack/wasm";

export default {
  async fetch(request) {
    const source = await request.text();
    const result = await obfuscate({ path: "app.js", source }, { preset: "hard" });
    return new Response(result.bytes, {
      headers: { "content-type": "application/javascript" },
    });
  },
};

यही पूरा integration है। कोई init call नहीं, कोई nodejs_compat flag नहीं, .wasm फ़ाइल के लिए कोई wrangler rule नहीं। Module का कोई WebAssembly import नहीं है, इसलिए पहली बार obfuscate call करने पर वह synchronously instantiate हो जाता है, और package का exports map आपके bundler को अपने आप Worker के अनुरूप entry दे देता है। वही import Node में भी काम करता है, जहाँ एक अलग entry binary को disk से पढ़ती है।

Surface @afterpack/core जैसी ही है — obfuscate, obfuscateAll, version, सभी async, और सभी ऐसी build पर throw करते हैं जो ship नहीं हो सकती। Configuration वही object है जो Configuration पर documented है, preset और seed समेत।

जब तक मजबूरी न हो, `@afterpack/core` इस्तेमाल करें

@afterpack/core एक native binary ship करता है और तेज़ है। @afterpack/wasm तब चुनें जब host native binary load नहीं कर सकता: एक Worker, एक sandboxed CI image, एक edge function।

इसकी लागत क्या है

Engine binary package के अंदर, पहले से compiled, ship होती है।

BytesSize
Raw .wasm4,573,3214.36 MiB
Gzipped1,307,7721.25 MiB

Cloudflare की Worker size सीमा free plan पर 3 MB compressed और paid पर 10 MB है, इसलिए engine दोनों में फ़िट हो जाता है। Free plan में जो फ़िट नहीं होता वह काम है: वह CPU को हर invocation पर 10 ms तक सीमित करता है, और laptop के एक core पर 185 KB bundle को obfuscate करने में डिफ़ॉल्ट light preset पर 0.3 सेकंड से कम और medium पर लगभग 1 सेकंड लगते हैं। Demo से आगे की किसी भी चीज़ के लिए Workers Paid चाहिए।

जो Worker हर request पर वही asset obfuscate करता है, वह हर बार वह CPU खर्च करता है। जहाँ हर request पर नया आकार आपका लक्ष्य नहीं है, वहाँ result को एक rotation window के लिए cache करना, या यह काम अपनी build में करके output serve करना, bill कम रखता है।

आपके host किए package की क्षमताएँ और सीमाएँ

आपका install किया .wasm Free protection करता है। Pro transforms केवल AfterPack के infrastructure पर चलते हैं, इसलिए package में unlock करने लायक कुछ नहीं है: bypass करने के लिए कोई key check नहीं, कोई switch नहीं जो host की गई copy को Pro build में बदल दे। एक key काम को cloud की ओर भेजती है; यह local पर कुछ भी चालू नहीं करती।

Published package एक npm provenance record रखता है — package version, उसे build करने वाला workflow, और artifact digest — ताकि आप अपने install किए bytes को उन्हें बनाने वाली build से जोड़ सकें।

Pro, आपके अपने Worker से

उसी obfuscate() call की config में अपनी key pass करें, उदाहरण के लिए Worker secret से, और build AfterPack के cloud में Pro engine पर चलती है:

import { obfuscate } from "@afterpack/wasm";

export default {
  async fetch(request, env) {
    const source = await request.text();
    const result = await obfuscate(
      { path: "app.js", source },
      { preset: "hard", key: env.AFTERPACK_KEY },
    );
    return new Response(result.bytes, {
      headers: { "content-type": "application/javascript" },
    });
  },
};

Package आपके लिए POST /v1/obfuscate/batch पर request भेजता है, इसलिए Worker को API हाथ से code नहीं करनी पड़ती। Worker के लिए बहुत बड़ी फ़ाइलें अपने आप containers में चली जाती हैं। Pro engine कभी आपके Worker में ship नहीं होता: यह केवल AfterPack के infrastructure पर चलता है, और ऊपर बताई tier सीमा यही है।

हर call एक metered Pro build है (Pro की लागत), साथ में Cloudflare के network के अंदर एक तेज़ request। आप हर request पर build कर सकते हैं, लेकिन हर एक का bill बनता है, इसलिए इसके बजाय result को एक rotation window के लिए cache करें।

आपका source आपके Worker से बाहर जाता है और AfterPack के cloud में process होता है, memory में और persist किए बिना, जैसा Privacy & data handling में बताया गया है। अगर cloud तक नहीं पहुँचा जा सकता, तो call fail closed होती है: वह error throw करती है और कुछ भी बिना सुरक्षा के ship नहीं होता। Cloud API reference पूरा wire contract है, और Deployment modes बताता है कि engine की जगह बदलने पर क्या बदलता है।

Pro कभी ऐसे wasm के रूप में ship नहीं होगा जिसे आप host करें

जो package आपके अपने infrastructure पर Pro transforms चलाने का दावा करता है, वह हमारा नहीं है। इस नाम से कुछ भी install करने से पहले npm provenance record जाँचें।

Result को एक rotation window के लिए cache करें

seed को मौजूदा time window से निकालें और result को ऐसी key के तहत cache करें जिसमें window शामिल हो। तब हर location हर window में asset को एक बार build करती है और window ख़त्म होने तक उसे serve करती है, Free और Pro दोनों पर:

import { obfuscate } from "@afterpack/wasm";
import source from "./pricing.client.js";

const WINDOW_SECONDS = 600;

export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);
    if (url.pathname !== "/pricing.js") {
      return new Response("Not found", { status: 404 });
    }

    const now = Math.floor(Date.now() / 1000);
    const slot = Math.floor(now / WINDOW_SECONDS);
    const secondsLeft = (slot + 1) * WINDOW_SECONDS - now;
    const cacheKey = new Request(`${url.origin}/pricing.js?slot=${slot}`);

    let response = await caches.default.match(cacheKey);
    if (!response) {
      const result = await obfuscate(
        { path: "pricing.js", source },
        { preset: "hard", seed: `pricing.js:${slot}`, key: env.AFTERPACK_KEY },
      );
      response = new Response(result.bytes, {
        headers: {
          "content-type": "application/javascript",
          "cache-control": `public, max-age=${secondsLeft}`,
        },
      });
      ctx.waitUntil(caches.default.put(cacheKey, response.clone()));
    }

    response = new Response(response.body, response);
    response.headers.set("cache-control", `public, max-age=${secondsLeft}`);
    return response;
  },
};

AFTERPACK_KEY secret के बिना key undefined रहती है और वही Worker आपके Worker के अंदर Free पर build करता है। Source फ़ाइल wrangler के Text rule के ज़रिए string के रूप में import होती है, जैसा पूरे walkthrough में है।

Window seed और cache key दोनों में है, इसलिए एक ही deployment चलाने वाली हर location एक window में वही bytes serve करती है, और नई window कभी पुरानी entry नहीं पढ़ती। बाहर जाने वाला cache-control window के अंत तक उल्टी गिनती करता है, इसलिए browser कभी उसके बाद copy नहीं रखता। Cache API entries को हर data center में अलग store करता है और dashboard editor में कोई असर नहीं करता, इसलिए इसे wrangler dev या किसी deployed route पर test करें।

चुनाव

आप चाहते हैंइस्तेमाल करें
Worker में obfuscation, आपके account से कुछ बाहर न जाए@afterpack/wasm, यही पेज
सामान्य Node build में obfuscation@afterpack/core या CLI
Pro hardening और region-स्तर के directives, Worker सेवही call एक key के साथ, जो AfterPack के cloud में build करती है
हर window में नई शक्ल, हर visitor के लिए build के बिनाRotation-window cache

आगे

  • Deployment modes: local बनाम cloud, और हर एक क्या store करता है।
  • Cloud API reference: वह contract जिसे Worker Pro builds के लिए call करता है।
  • Configuration: हर key जिसे दोनों packages स्वीकार करते हैं।
  • Tiers: Free में क्या शामिल है, और Pro क्या जोड़ता है।
  • Privacy & data handling: हर mode में आपकी मशीन से क्या बाहर जाता है।