# Obfuscated code क्या वैसा ही रखता है (semantic contract)

AfterPack का output आपके program के व्यवहार में से क्या बनाए रखता है, हर engine release को असली code पर कैसे जाँचा जाता है, और जान-बूझकर रखे गए अंतरों की छोटी सूची।

Source: https://www.afterpack.dev/hi/docs/semantic-contract

AfterPack यह बदलता है कि आपका code कैसा पढ़ा जाता है, और यह बनाए रखता है कि वह क्या करता है। एक obfuscated build वही values लौटाती है, उसी प्रकार के errors throw करती है, वही output लिखती है और page में वही बदलाव करती है जो आपकी दी हुई build करती थी। यह page engine 0.2.3 और उसके बाद के लिए यह contract बताता है: क्या वैसा ही रहता है, हर release को कैसे जाँचा जाता है, और वे कुछ जगहें जहाँ output जान-बूझकर अलग है।

## क्या वैसा ही रहता है

हर [preset](https://www.afterpack.dev/hi/docs/presets) पर और हर [seed](https://www.afterpack.dev/hi/docs/config#seed) के साथ, obfuscated build ये बनाए रखती है:

- **नतीजे और errors।** Functions वही values लौटाते हैं। जो code error throw करता था, वह अब भी उसी प्रकार का error throw करता है।
- **Effects और उनका क्रम।** Console output, DOM बदलाव, network requests और storage writes उसी क्रम में, उन्हीं values के साथ होते हैं।
- **Async क्रम।** `async` functions, promises और timers उसी क्रम में settle होते हैं।
- **Global surface।** एक classic script पहले जैसे ही globals परिभाषित करती है, इसलिए page की दूसरी scripts अब भी उसके functions call कर सकती हैं और उसके variables पढ़ सकती हैं। एक ES module `window` में कुछ नहीं जोड़ता और किसी global को overwrite नहीं करता। `import` या `export` वाली फ़ाइल module के रूप में पढ़ी जाती है; जिस फ़ाइल में ये नहीं हैं, उसके लिए framework plugin, CLI या [`sourceType`](https://www.afterpack.dev/hi/docs/config#sourceType) engine को बताता है।
- **Language के वे नियम जिन पर आपका code निर्भर है।** Strict mode के errors, `this` और call receivers, getters और setters, class fields, `BigInt` arithmetic, और `eval` व `with` के scopes वैसा ही व्यवहार करते हैं जैसा लिखा गया है।
- **वे names जिन्हें आपका code पढ़ता है।** जो फ़ाइल `this.constructor.name` या `new.target.name` पढ़ती है, जैसा कोई custom error class करती है, उसमें classes और constructors वही names रखते हैं जो आपने लिखे थे, [जान-बूझकर रखे गए अंतरों](#deliberate-differences) में दिए अपवादों को छोड़कर।

अलग-अलग seeds वाली दो builds का आकार अलग होता है, व्यवहार कभी नहीं।

## Design के तहत क्या बदलता है

- **Code का text।** `fn.toString()` जो लौटाता है, line और column numbers, और stack trace के names बदल जाते हैं। Production stack traces पढ़ने के लिए [source map](https://www.afterpack.dev/hi/docs/config#sourceMap-enabled) को private रखें।
- **Size और speed।** Output बड़ा होता है, और `medium` व उससे ऊपर हर operation पर ज़्यादा काम करता है। मापे गए आँकड़े [Performance](https://www.afterpack.dev/hi/docs/performance) पर हैं।
- **ख़ुद को inspect करने वाला code।** जब engine ऐसा code पाता है जो runtime पर अपनी ही संरचना पढ़ता है, जैसे `fn.toString()`, तो वह build रोक देता है और pattern का नाम बताता है। Pattern को [`reflection.allow`](https://www.afterpack.dev/hi/docs/config#reflection-allow) से acknowledge करें, या [`paths.exclude`](https://www.afterpack.dev/hi/docs/config#paths-exclude) से फ़ाइल को बिना बदले ship करें।

## हर release को कैसे जाँचा जाता है

Engine 0.2.3 से, हर engine release ship होने से पहले एक semantic gate पास करता है। यह gate हर program को दो बार चलाता है, एक बार जैसा लिखा गया है और एक बार obfuscated, और तुलना करता है कि हर run क्या करता है: लौटाई गई values, throw किए गए errors, console output, और asynchronous काम का क्रम। कोई भी अंतर release को fail कर देता है, जब तक वह नीचे दिए [जान-बूझकर रखे गए अंतरों](#deliberate-differences) में से एक न हो।

यह gate चलाता है:

- **छोटे, लक्षित programs**, हर एक language के किसी ऐसे नियम पर केंद्रित जिसे code transformer ग़लत कर सकता है: classes और private fields, closures और scopes, generators, `async` क्रम, template literals, `BigInt`, `eval` और `with`, strict mode, labels और `switch`। हर preset, कई seeds, और native engine व WebAssembly engine दोनों।
- **असली libraries**, pinned versions पर, हर एक को एक छोटी script चलाती है: dates के लिए dayjs, Moment.js और Luxon, `BigInt`-heavy cryptography के लिए viem, ethers और @noble/curves, और Comlink, lodash का `_.template` और get-intrinsic।
- **Chromium में pages**, जो कई classic scripts को क्रम से load करते हैं, imports वाले और बिना imports वाले ES modules, inline event handlers और custom elements, और एक single-chunk Vue app। हर page को वैसा ही व्यवहार करना होता है और `window` को ठीक वैसा ही छोड़ना होता है जैसा original छोड़ता है: न कोई नया global, न कोई overwrite किया गया global।

## जान-बूझकर रखे गए अंतर

Gate केवल इन्हीं अंतरों की, और table के बाद दिए class names के अंतर की, अनुमति देता है। Table की हर row ऐसे code से जुड़ी है जो built-ins को बदलता है, instances को `Proxy` में लपेटता है, किसी class को `new` के बिना call करता है या JavaScript engine के error messages पढ़ता है, इसलिए ज़्यादातर applications का इनसे कभी सामना नहीं होता। ये उन classes के अंदर लागू होते हैं जिन्हें engine फिर से लिखता है, `light` और उससे ऊपर; `minify` classes को वैसा ही छोड़ता है जैसा लिखा गया है।

| आपका code | Native व्यवहार | Obfuscated output |
|---|---|---|
| ऐसे instance पर public class fields परिभाषित करता है जो ख़ुद एक `Proxy` है (base constructor से लौटाया गया) या जिसकी prototype chain में एक `Proxy` है | केवल proxy का `defineProperty` trap चलता है | हर field के लिए `has` trap भी चलता है, और जो field object में नहीं है उसके लिए `set` trap और वह सब जहाँ वह आगे भेजता है |
| किसी class constructor को `new` के बिना call करता है | किसी भी parameter default या destructuring के चलने से पहले `TypeError` throw करता है | Parameter defaults और destructuring चलाता है, फिर वही `TypeError` throw करता है |
| `Function.prototype.call` को बदलने के बाद, या अपनी `call` property वाले method पर, private method या `super.method()` call करता है | Method को सीधे call करता है | बदले गए `call` से होकर जाता है |
| Private-field check, private field के दूसरे initialization या `new` के बिना call की गई class से आए `TypeError` का message पढ़ता है | JavaScript engine का अपना message | AfterPack का अपना message, उसी error type के साथ |
| फ़ाइल load होने से पहले `TypeError`, `Object`, `Object.defineProperty`, `Reflect.construct`, `Reflect.ownKeys`, `WeakMap` या `WeakSet` को बदलता है | Classes अब भी original built-ins इस्तेमाल करती हैं | फिर से लिखी गई classes बदला हुआ version इस्तेमाल करती हैं |

Class और constructor names कुछ मामलों में अलग होते हैं, हर preset पर। जो फ़ाइल इन्हें केवल दूसरे तरीक़ों से पढ़ती है, जैसे `err.constructor.name` या `const { name } = new.target`, उसे बदले हुए names मिलते हैं। जो फ़ाइल `this.constructor.name` या `new.target.name` पढ़ती है, उसमें भी इन मामलों में बदला हुआ name दिखता है: `new (class X {})()` के रूप में construct की गई class, किसी default parameter से name पाने वाली anonymous class, ऐसा function जिसे किसी `switch` case में उस case से पहले construct किया जाता है जो उसे declare करता है, और ऐसा function जिसे केवल किसी दूसरे reference से construct किया जाता है, जैसे `new ns.F()`, कोई alias या `Reflect.construct`।

## क्या वैसा ही रहता है जैसा आपने लिखा

ये constructs वहाँ वैसे ही छोड़े जाते हैं जैसे लिखे गए हैं, जहाँ उन्हें सटीकता से फिर से लिखना सस्ता नहीं है। इनके आसपास का code फिर भी rename और encode होता है, `with` और direct `eval` के आसपास को छोड़कर।

- `async` functions और `await`।
- `delete`, और किसी अकेले name पर लगाया गया `typeof`।
- ऐसा function जिसका `catch (e)` block `var e` declare करता है।
- किसी `switch` case में सीधे declare किया गया `let` या `const`।
- ऐसा optional call या tag जिसका callee parentheses में है या `super` member है: `(o?.m)?.()`, `` (o?.m)`x` ``, `super.m?.()`।
- ऐसी class जो अपने ही name को assign करती है, किसी `super` member को optional call, tag या parenthesized callee के रूप में call करती है, या जिसके derived constructor में top level पर ठीक एक `super()` call नहीं है।
- Loops, `minify` और `light` पर।
- किसी `with` statement या direct `eval` के आसपास के scopes। उसे घेरने वाले हर scope में, फ़ाइल के top level तक, names अपनी मूल spelling रखते हैं, और `with` body के अंदर globals वैसे ही छोड़े जाते हैं जैसे लिखे गए हैं। Build इसे [`DIAG_DYNAMIC_SCOPE_NATIVE`](https://www.afterpack.dev/hi/docs/diagnostics#complete-reference) से report करती है। अगर evaluate होने वाले code को local variables की ज़रूरत नहीं है, तो `eval` को indirectly call करें, `(0, eval)(code)`, या जिस code को `eval` या `with` चाहिए उसे एक अलग फ़ाइल में ले जाएँ।

## Engine 0.2.3 से पहले

Engine 0.2.2 और उससे पहले के versions कुछ ऐसे मामलों में इस contract को पूरा नहीं करते थे जिन्हें gate अब cover करता है: दूसरी scripts के साथ साझा की गई classic scripts के top-level names, बिना imports वाले ES modules, template literals के अंदर dates जैसे objects, constructors के रूप में इस्तेमाल किए गए functions, inherited accessors के ऊपर class fields, ख़ुद को refer करने वाले functions, `medium` और उससे ऊपर `BigInt` arithmetic, `eval` और `with`, ऐसा `catch` block जो अपने variable को `var` से फिर से declare करता है, `async` क्रम, parentheses में optional calls, constant `**` expressions, और runtime पर पढ़े गए class names। Engine 0.2.3 या उसके बाद के version से फिर से build करें; [चेंजलॉग](https://www.afterpack.dev/hi/changelog) हर fix की सूची देता है।

## किसी अंतर की report करें

इस page पर न दिया गया कोई भी अंतर एक bug है। [github.com/afterpack-dev/afterpack/issues](https://github.com/afterpack-dev/afterpack/issues) पर एक छोटे reproduction के साथ issue खोलें। जब तक वह fix नहीं होता, [`paths.exclude`](https://www.afterpack.dev/hi/docs/config#paths-exclude) प्रभावित फ़ाइल को बिना बदले ship करता है।

## आगे

- [Diagnostics](https://www.afterpack.dev/hi/docs/diagnostics): हर code जो build report कर सकती है, और उसके बारे में क्या करना है।
- [AfterPack कैसे काम करता है](https://www.afterpack.dev/hi/docs/concepts): transformations आपके code के साथ क्या करते हैं।
- [Presets](https://www.afterpack.dev/hi/docs/presets): हर स्तर क्या लागू करता है।
- [कॉन्फ़िगरेशन](https://www.afterpack.dev/hi/docs/config): [`reflection.allow`](https://www.afterpack.dev/hi/docs/config#reflection-allow), [`paths.exclude`](https://www.afterpack.dev/hi/docs/config#paths-exclude) और वे दूसरी keys जिनसे यह page link करता है।
