AfterPack CLI संदर्भ

npx afterpack@latest को चलाना: एक वैकल्पिक path, हर config key एक flag के रूप में, verify, restore और audit subcommands, और पूरा exit-code contract।

npx afterpack@latest एक build directory को obfuscate करता है। इसका उपयोग तब करें जब आपके bundler के लिए कोई plugin न हो, या CI में। यदि आपके framework के लिए plugin मौजूद है, तो इसके बजाय @afterpack/<fw> install करें: तब आपका सामान्य build बिना किसी अलग चरण के obfuscated output देता है। देखें Frameworks।

यह पेज argument, उदाहरण, एक run क्या करता है, verify, restore, audit, machine-readable output और exit codes को कवर करता है। हर option एक ही बार, कॉन्फ़िगरेशन पर परिभाषित है।

उपयोग

afterpack [path] [--<key>=<value> ...] [-h | --help] [-v | --version]
afterpack verify [dir]
afterpack restore [dir]
afterpack audit <url>
$ npx afterpack@latest

path इनमें से कोई एक हो सकता है:

  • एक directory, जिसे हर .js, .mjs और .cjs के लिए recursively चला जाता है, या
  • एक अकेली .js, .mjs या .cjs फ़ाइल, जिसे अपने आप में obfuscate किया जाता है।

बिना path के चलाएँ, तो afterpack आपका build output खुद पहचान लेता है: वह directory जिसमें आपके package.json में नामित bundler परंपरागत रूप से लिखता है (Next.js → .next/, Nuxt → .output/, SvelteKit → build/, Electron → out/, बाकी हर supported bundler → dist/), यदि वह directory मौजूद है, अन्यथा dist/, build/, out/, .output/ और .next/ में से सबसे नई। यह आपके bundler की अपनी config फ़ाइल कभी नहीं पढ़ता, इसलिए custom output directory का पता नहीं चलता; ऐसी directory हो तो path स्वयं दें। यह बताता है कि उसे क्या मिला और वह क्या करेगा, फिर चलता है; CI में यह कभी prompt नहीं करता। कुछ न मिले तो यह quickstart help छापकर 1 के साथ exit करता है। यह command आपके bundler को package.json से भी पढ़ता है और run के अंत में मिलते-जुलते plugin की ओर एक पंक्ति का संकेत छापता है।

इसे अपने bundler के output पर चलाएँ, अपने source पर नहीं। ज़्यादातर bundlers (Vite, Rollup, esbuild, webpack, Astro, Parcel) dist/ में लिखते हैं। Next.js .next/ में लिखता है, Nuxt .output/ में।

उदाहरण

npx afterpack@latest                                        # detects the build output, light default
npx afterpack@latest dist/                                  # a directory you choose
npx afterpack@latest dist/ --preset=hard                    # heavier posture
npx afterpack@latest .next/ --seed=git                      # reproducible output, pinned to the commit
npx afterpack@latest build/widget.js                        # one file
npx afterpack@latest dist/ --diagnostics.level=all          # every diagnostic, not the rolled-up summary
AFTERPACK_complexity=40 npx afterpack@latest dist/           # any flag also works as an env var

एक run क्या करता है

  1. <path> पर मौजूद JavaScript को इकट्ठा करता है। path directory हो तो यह recursively चलता है, अपनी ही .backup.<hash> copies को छोड़ देता है, और node_modules/ को भी छोड़ देता है जब तक आप उसे --paths.include='**/node_modules/**' से शामिल न करें। कुछ भी इकट्ठा न हो तो build fail हो जाता है।
  2. .afterpack/ के अंदर एक .gitignore रखकर उसे git से बाहर रखता है, जो पहली बार ज़रूरत पड़ने पर लिखी जाती है। आपकी अपनी .gitignore में कभी बदलाव नहीं किया जाता।
  3. इकट्ठा की गई हर फ़ाइल को उसी जगह obfuscate करता है, माँगे गए preset पर, या --complexity पर जब आप उसे स्पष्ट रूप से सेट करते हैं। Next.js, Angular, Vite या webpack build पर यह हर content-hashed फ़ाइल का नाम भी उसके obfuscated bytes के अनुसार बदल देता है और उसके हर reference को फिर से लिखता है; बाकी output पर नाम वैसे ही रहते हैं जैसे आपके bundler ने लिखे थे। देखें Content-hashed फ़ाइल नाम।
  4. वे artifacts लिखता है जिनकी flags अनुमति देती हैं, और हमेशा protection receipt। संयुक्त Protection Map हमेशा .afterpack/protectionMap.html में जाता है, जो gitignored है और कभी serve नहीं होता, क्योंकि उसमें आपका मूल source embedded होता है। source map या backup में आपका पूरा source होता है। इनमें से किसी को कभी deploy न करें। यदि इनमें से कोई serve किए जाने वाले path segment के नीचे पहुँच जाए, तो CLI एक बार चेतावनी देता है।
  5. diagnostics छापता है, फिर bundler का संकेत, यदि उसे कोई मिला हो।
Runs idempotent नहीं होते

यह command आपके build output को उसी जगह overwrite करता है और दोबारा obfuscate करने के लिए कोई copy नहीं रखता। पहले build करें, फिर इसे एक बार चलाएँ। CI में यह क्रम स्वतः बना रहता है।

इसे एक ही output पर दो बार न चलाएँ

AfterPack ऐसी फ़ाइल को obfuscate करने से इनकार करता है जिसमें पहले से किसी पिछले run का उसका अपना obfuscated output मौजूद है: यह इकट्ठा की गई फ़ाइलों को content hash से protection receipt के साथ मिलाता है और पहले से obfuscated कोड को फिर से obfuscate करने के बजाय DIAG_ALREADY_OBFUSCATED के साथ build को fail कर देता है, चाहे आप इसे किसी भी directory से चलाएँ। किसी framework द्वारा protected output की बनाई गई copy, जैसे SvelteKit का build/, भी इसी तरह अस्वीकार की जाती है। पहले source से फिर से build करें: output directory हटाएँ या अपने bundler का clean step चलाएँ।

Content-hashed फ़ाइल नाम

Bundlers किसी chunk का नाम उसकी सामग्री के hash पर रखते हैं, जैसे index-4f9a2c1e.js, ताकि server उसे Cache-Control: immutable के साथ एक साल तक cache कर सके। Obfuscation bytes बदल देता है, इसलिए नीचे दिए builds पर run हर content-hashed फ़ाइल के नाम में नया hash डालता है और HTML, manifests और दूसरे chunks में उसके हर reference को फिर से लिखता है। एक नाम कभी अलग bytes की ओर इशारा नहीं करता, इसलिए कोई browser, CDN या service worker दोबारा इस्तेमाल हुए नाम के नीचे कभी पुरानी copy नहीं देता। नया hash मूल hash के साथ seed, engine version और आपकी settings से बनता है, ठीक वैसे ही जैसे कोई plugin अपनी फ़ाइलों के नाम रखता है; seed का आपके cache पर क्या असर होता है, यह फ़ाइल नाम और caching में है।

BuildCLI को किस पर चलाएँRun किसका नाम बदलता है
Next.js, webpack या Turbopack पर.next/, .next/static/ या .next/static/chunks/; static export के लिए out/static/chunks/ के नीचे के chunks
Angular application builderdist/<app>/browser/ या dist/<app>/हर hashed फ़ाइल। Run integrity attributes और service worker की ngsw.json hash table भी फिर से गणना करता है
Viteऐसी directory जिसमें index.html या .vite/manifest.json होassets/ में, या manifest में बताए गए folders में, name-<hash> scripts और stylesheets
webpackऐसी directory जिसके chunks webpack runtime load करता हैवे फ़ाइलें जिनके नाम में hex content hash है

इन स्थितियों में content-hashed नाम वैसे ही रहते हैं जैसे आपके bundler ने लिखे थे, और run एक notice print करता है:

  • path एक अकेली फ़ाइल है, या output किसी और bundler का है;
  • Next.js build के पीछे का bundler पहचाना नहीं जा सकता;
  • Vite या webpack build पर, कोई hashed फ़ाइल build directory के अंदर से referenced नहीं है, दो hashes में फ़र्क नहीं किया जा सकता, या build directory के बगल का कोई folder, जैसे server bundle, .svelte-kit/ या .output/, hashed फ़ाइलों का नाम लेता है या जाँचने के लिए बहुत बड़ा है;
  • कोई precache manifest, जैसे Workbox का, फ़ाइलों को revision के साथ सूचीबद्ध करता है।

ऐसे build पर long-lived caching के लिए अपने framework का plugin इस्तेमाल करें, या एक स्थिर --seed pin करें।

जिस Angular server build की angular-app-manifest.mjs में asset hashes embedded हैं, उसे exit 1 के साथ अस्वीकार किया जाता है, और output वैसा ही रहता है जैसा builder ने लिखा था। SSR के बिना वाले build के browser output को obfuscate करें।

Flags

हर configuration key एक flag है: --<key>=<value>, उदाहरण के लिए --complexity=40 या किसी list के लिए --identifiers.reserved=Hls,Foo। boolean flag true के लिए बिना value के लिखी जाती है (--build.backup) और =false उसे बंद कर देता है (--protectionMap.enabled=false)। -h, --help और -v, --version output छापकर 0 के साथ exit करते हैं।

option reference की हर scalar या list key इसी तरह flag के रूप में काम करती है। structured values afterpack.json में रखी जाती हैं। environment variables वही नाम रखते हैं जिनमें dots की जगह underscores होते हैं, देखें कॉन्फ़िगरेशन, उदाहरण के लिए AFTERPACK_key, AFTERPACK_preset और AFTERPACK_telemetry_enabled।

फ़ाइलें

Pathभूमिका
afterpack.jsonconfig फ़ाइल। AfterPack working directory से ऊपर की ओर सबसे नज़दीकी मिलान तक जाता है। इसमें पूरा engine config होता है: build options, key, सब कुछ।
.afterpack/receipts/<build dir>.jsonकिसी एक build directory की protection receipt, उदाहरण के लिए .afterpack/receipts/dist.json या .afterpack/receipts/.next.json। लंबे या असामान्य path को hash के साथ एक छोटा नाम मिलता है। इसमें हर output फ़ाइल, लिखे गए bytes के hash के साथ, engine version और seed दर्ज होते हैं। afterpack verify इसके विरुद्ध फिर से hash करता है, और इसी के कारण उसी बिना rebuild किए output पर बाद का run अस्वीकार कर दिया जाता है।
.afterpack/protectionMap.htmlसंयुक्त Protection Map। स्वतः gitignored। इसमें आपका मूल source embedded होता है। इसे कभी commit या serve न करें।
.afterpack/backups/<build dir>/एक build directory की आपकी मूल फ़ाइलें, ज्यों की त्यों, उदाहरण के लिए .afterpack/backups/dist/, साथ में एक manifest जिसमें हर वह फ़ाइल दर्ज है जिसे run ने बनाया, बदला, rename किया या हटाया। हर build directory का अपना backup और अपना lock होता है, इसलिए एक repository में अलग-अलग apps के builds कभी एक backup साझा नहीं करते। हर run पर लिखा जाता है (--build.backup=false से बंद करें), और afterpack restore run को undo करने के लिए इसे पढ़ता है। Run खत्म होने पर इसका path print करता है। यह आपका source है। इसे कभी commit या deploy न करें।
<file>.js.mapउत्पन्न source map, जब sourceMap.enabled चालू हो। डिफ़ॉल्ट रूप से बंद: हर run production है जब तक वह ख़ुद को development न बताए, और production run आपके bundler के लिखे source maps भी हटा देता है, CSS maps समेत। ship किया गया source map output को सीधे आपके source तक वापस map कर देता है।

.afterpack/ में receipts, Protection Map और backups रहते हैं। AfterPack इसे build directory से खोजता है, चाहे आप किसी भी directory से चलाएँ। यह ऊपर की ओर उस सबसे नज़दीकी folder तक जाता है जिसमें कोई lockfile (package-lock.json, npm-shrinkwrap.json, pnpm-lock.yaml, yarn.lock, bun.lock या bun.lockb), afterpack.json या .git हो। ऐसा folder न मिले तो यह package.json वाला सबसे नज़दीकी folder लेता है, और वह भी न मिले तो इसे build directory के बगल में रखता है। इन पन्नों पर वही folder आपका project root है। .afterpack/ कभी build output के अंदर नहीं होता।

run fail हो जाता है, और कुछ भी फिर से नहीं लिखा जाता, जब उसे build output के अंदर कोई .afterpack/ folder मिलता है (DIAG_AFTERPACK_DIR_IN_OUTPUT: वह folder हटाएँ और फिर से build करें) या वह receipt नहीं लिख पाता (DIAG_RECEIPT_UNWRITABLE)। किसी पुराने version द्वारा output में छोड़ी गई .afterpack-protection.json अगले run पर हटा दी जाती है।

afterpack verify [dir]

deploy gate। हर protected build एक protection receipt .afterpack/receipts/ में लिखता है। verify [dir] की receipt उसी तरह खोजता है जैसे run ने खोजी थी, इसलिए यह किसी भी directory से काम करता है। यह receipt में नामित हर फ़ाइल को फिर से hash करता है और तब fail होता है जब कोई फ़ाइल अब मेल नहीं खाती, जब receipt मौजूद नहीं है, या जब वह किसी दूसरे build की है।

npx afterpack@latest verify .        # a project root: looks in ./ then ./.next/
npx afterpack@latest verify dist     # or the build output directory itself
npx afterpack@latest verify build    # SvelteKit's adapter copy; also .output/public, out/

कोई directory जिसे framework ने अपने build output से copy किया हो, जैसे SvelteKit का build/, Nuxt का .output/public/ या Next का out/, उस directory की receipt से जाँची जाती है जिससे वह copy की गई। verify फ़ाइलों के आधार पर copy को उस receipt से मिलाता है और हर hash जाँचता है, इसलिए बदली गई फ़ाइल fail होती है और उसका नाम बताया जाता है। इसे deploy root पर ही चलाएँ। तब text output में · copy of <source dir>/ जुड़ जाता है।

यह कोई engine configuration नहीं पढ़ता, केवल --diagnostics.format और --diagnostics.level। --diagnostics.format=json के साथ, summary का receipt field उस receipt का नाम बताता है जिसे उसने जाँचा, और copiedFrom उस directory का नाम बताता है जिससे copy बनाई गई। इसे deploy से पहले अंतिम चरण के रूप में चलाएँ; देखें Builds और CI।

यह तब भी fail होता है जब कोई रुका हुआ run या restore build directory में एक अस्थायी .afterpack-tmp फ़ाइल छोड़ गया हो। देखें बीच में रुका run।

afterpack restore [dir]

undo। कुछ भी लिखने से पहले कोई run आपकी मूल फ़ाइलों को .afterpack/backups/<build dir>/ में copy करता है और हर वह फ़ाइल दर्ज करता है जिसे वह बनाएगा, बदलेगा, rename करेगा या हटाएगा। restore हर फ़ाइल को उसके मूल नाम और मूल bytes के साथ वापस रखता है, renames और फिर से लिखे गए references को undo करता है, और backup तथा run की लिखी receipt को हटा देता है।

npx afterpack@latest restore          # every backup under the project root
npx afterpack@latest restore dist     # only the run over dist/

किसी build directory पर चलाने पर यह सिर्फ़ उन runs को restore करता है जो उस directory पर, उसके अंदर की किसी directory पर, या उसे रखने वाले build पर चले थे। Project root पर चलाने पर यह वहाँ का हर backup restore करता है। जब कोई backup उस path को cover नहीं करता, तो यह fail होता है और उन directories की सूची देता है जिनका backup है। यह .afterpack/ को [dir] से उसी तरह खोजता है जैसे कोई run खोजता है, और किसी पुराने release का लिखा .afterpack/backup/ folder भी पढ़ता है।

यह fail closed है: कुछ भी लिखे जाने से पहले हर दर्ज फ़ाइल जाँची जाती है, इसलिए run के बाद आपके द्वारा संपादित या फिर से build की गई फ़ाइल restore को रोक देती है, कुछ भी restore नहीं होता, और command उस फ़ाइल का नाम बताकर 1 के साथ exit करता है। Backup न हो तो यह सीधे इनकार कर देता है। बीच में रुका restore अगले restore से पूरा होता है। --diagnostics.format के अलावा कोई engine configuration नहीं पढ़ता।

बीच में रुका run

किसी error पर fail होने वाला run exit करने से पहले अपने writes को rollback कर देता है। हर फ़ाइल पहले एक अस्थायी <file>.afterpack-tmp में लिखी जाती है और फिर rename होकर अपनी जगह आती है, इसलिए kill किया गया run कभी आधी लिखी फ़ाइल नहीं छोड़ता। Kill किए गए run का backup अधूरा marked रहता है, और उसी directory पर अगला afterpack run पहले output जाँचता है:

Build output में क्या हैअगला run
सिर्फ़ वह जो आपके bundler ने लिखा और वह जो रुके हुए run ने लिखाexit 1 के साथ fail होता है। Output को वैसा वापस लाने के लिए जैसा आपके bundler ने लिखा था, afterpack restore चलाएँ, या source से फिर से build करके दोबारा चलाएँ।
एक नया build, या ठीक वही जो आपके bundler ने लिखा, रुके हुए run का कुछ भी बाकी नहींपुराने backup को एक notice के साथ हटा देता है, फिर चलता है।
मिश्रण: कुछ फ़ाइलें फिर से build हुईं, बाकी में अब भी रुके हुए run का output हैexit 1 के साथ fail होता है और फिर से build हुई फ़ाइलों के नाम बताता है, और restore भी इनकार करता है। पूरे output को source से फिर से build करके दोबारा चलाएँ, या बाकी फ़ाइलों के मूल रूप message में बताए गए backup folder से वापस copy करें।

--build.backup=false के साथ कोई backup नहीं लिखा जाता, इसलिए kill किए गए run को undo नहीं किया जा सकता: source से फिर से build करें। AfterPack अपने writes को disk पर flush नहीं करता, इसलिए run या restore के दौरान बिजली जाने के बाद भी source से फिर से build करें।

Parallel runs और locks

एक run और एक restore, दोनों खत्म होने तक अपनी build directory का lock, .afterpack/backups/<build dir>/lock, रखते हैं। अलग-अलग build directories पर runs, जैसे एक repository के दो apps, parallel चलते हैं। उसी build पर दूसरा run, जिसमें उसके अंदर की कोई directory भी शामिल है जैसे .next/ के protect होते समय .next/static/chunks/, exit 1 के साथ fail होता है और lock रखने वाले run का नाम बताता है। जिस lock का process इस machine पर बंद हो चुका है, या जो दो घंटे से पुराना है, उसे एक notice के साथ ले लिया जाता है। अगर कोई run नहीं चल रहा और lock बना रहता है, तो message में बताई गई फ़ाइल हटा दें।

afterpack audit <url>

किसी deployed साइट को leaked secrets, exposed source और unprotected JavaScript के लिए scan करता है, और scan चलते-चलते findings को stream करता है। यह कोई configuration नहीं पढ़ता और URL के सिवा कुछ नहीं भेजता। पूरे command reference के लिए देखें Audit।

npx afterpack@latest audit example.com

Machine-readable output

--diagnostics.format=json stdout पर ठीक एक JSON document रखता है और कुछ नहीं; हर human-readable पंक्ति stderr पर चली जाती है। यह flag से, AFTERPACK_diagnostics_format=json से, या afterpack.json में diagnostics.format से काम करता है, और verify तथा audit भी इसका पालन करते हैं। ऐसे run के लिए जो document के सिवा कुछ न छापे, इसे diagnostics.level=none के साथ जोड़ें। CI steps और AI agents को text output parse करने के बजाय यही रूप पढ़ना चाहिए; package में एक SKILL.md भी शामिल है जो CLI को सीधे चलाने वाले agent के लिए उसका दस्तावेज़ है।

npx afterpack@latest dist/ --diagnostics.format=json --diagnostics.level=none

Exit codes

Codeअर्थ
0सफलता। इकट्ठा की गई हर फ़ाइल obfuscate करके लिखी गई। --help और --version भी यही लौटाते हैं।
1विफलता। कुछ भी उपयोगी उत्पन्न नहीं हुआ: ऐसा path जो मौजूद नहीं है, उसके नीचे कोई JavaScript नहीं मिली, कोई engine error, fail हुआ verify, fail हुआ audit scan, या Pro key वाला build जिसकी cloud call fail हो गई।
2आंशिक। कोटा समाप्त हो चुके build के लिए आरक्षित; आज कोई build इसे नहीं लौटाता।
3Size cap। inflation.max के भीतर complexity target तक नहीं पहुँचा जा सका (DIAG_SIZE_CAP_REACHED)।
4Pro आवश्यक। कोई regions entry सुरक्षा को पूरे program की configuration से ऊपर बढ़ाती है और उसके लिए key चाहिए (DIAG_PRO_DIRECTIVE_REQUIRES_KEY)। CLI source के directives नहीं पढ़ता, इसलिए इस exit तक केवल regions से पहुँचा जा सकता है।
5Reflection। reflection.allow के बिना runtime reflection का पता चला (DIAG_REFLECTION_NOT_ACKNOWLEDGED)।
6Update ज़रूरी। AfterPack cloud को, या इस afterpack को, नया @afterpack/core चाहिए। कुछ भी नहीं लिखा गया।
64गलत उपयोग। कोई अज्ञात flag या command, गलत रूप की value, या दोहराया गया path argument।

ऐसी फ़ाइल को अलग रखने के लिए जो बिना बदले ship होनी चाहिए, paths.exclude का उपयोग करें।

resolved key वाला Pro build fail closed है। यदि cloud call fail हो जाए, तो build Free tier के output पर वापस जाने के बजाय रुक जाता है। 4 उस Free build का exit है जिसकी किसी regions entry को key चाहिए; 5 किसी भी build (Free या Pro) में बिना acknowledge किए reflection pattern का exit है; 2 भविष्य के कोटा-समाप्त build के लिए आरक्षित है और आज कोई build इसे नहीं लौटाता। पूरे contract के लिए देखें Exit codes।

आगे

  • कॉन्फ़िगरेशन: हर option, और उसे सेट करने के चार रूप।
  • Presets: पाँच पायदानों की सीढ़ी और हर पायदान की लागत।
  • Audit: पूरा afterpack audit संदर्भ।
  • Diagnostics: exit contract, fail-closed नियम, और हर DIAG_* code।
  • Frameworks: plugin का रास्ता, जो आपके stack के लिए plugin मौजूद होने पर बेहतर है।
  • Quickstart: install से Protection Map तक का सबसे छोटा रास्ता।