एक Pro key configure होते ही @afterpack/core और हर framework plugin यह protocol पहले से बोलते हैं: auth, multipart streaming, retries, सब कुछ। इसे तब पढ़ें जब आप कोई custom CI integration जोड़ रहे हों, official packages के बाहर कोई client लिख रहे हों, या किसी ऐसे response को debug कर रहे हों जिसकी आपके tooling को उम्मीद नहीं थी।
Base URL और versioning
Base URL: https://api.afterpack.dev/v1/
API का version URL में होता है, और v1 ही एकमात्र version है। इसके भीतर response fields जोड़े जाते हैं, कभी हटाए या दूसरे अर्थ में इस्तेमाल नहीं किए जाते; कोई breaking change v2 के रूप में इसके साथ-साथ ship होगा। GET /v1/version deployed version और environment लौटाता है, और GET / बिना authentication वाला liveness check है।
Client compatibility
दो वैकल्पिक request headers, जो न होने या malformed होने पर दोनों ignore किए जाते हैं, कभी 400 नहीं देते — curl script हो या इन headers से पुराना client, किसी पर भी कोई असर नहीं पड़ता:
| Header | क्या ले जाता है |
|---|---|
X-AfterPack-Client-Version | Installed @afterpack/core का npm version, उस पर बने client के लिए। |
X-AfterPack-Client | Call करने वाला package और उसका version, जैसे afterpack/0.1.0 या @afterpack/vite/0.1.0। |
तुलना केवल server-side होती है, MAJOR.MINOR.PATCH पर, किसी भी prerelease suffix को नज़रअंदाज़ करते हुए (0.1.0-rc.3 को 0.1.0 पढ़ा जाता है); ऐसा version जिसे यह server parse नहीं कर सकता, या header का पूरी तरह न होना, हमेशा स्वीकार किया जाता है। जब तक कोई minimum configured है, हर response में X-AfterPack-Min-Client-Version होता है, ताकि script बिना इनकार झेले अपनी स्थिति जाँच सके। यह जाँच key auth के ठीक बाद, request body पढ़े जाने से पहले होती है:
- Configured minimum से नीचे:
426 DIAG_CLIENT_UPGRADE_REQUIRED,details.minVersionके साथ। - Sunset window के दौरान:
410 DIAG_API_SUNSET।
डिफ़ॉल्ट रूप से इनमें से कोई configured नहीं है। Workspace इन्हें तभी देखता है जब AfterPack इस API के लिए कोई minimum version या sunset date सेट करता है।
Response में एक top-level notices array भी हो सकता है: सफल batch-summary पर, किसी भी error body पर, और Free-tier telemetry के 202 पर — {severity, code, message, url?}, अधिकतम 5, हर message 500 characters तक सीमित। अज्ञात severity को warning माना जाता है; इसे दिखाने के अलावा कुछ करने की ज़रूरत नहीं है।
Authentication
दो credentials, और वे एक-दूसरे की जगह इस्तेमाल नहीं हो सकते।
| Credential | Header | यह कहाँ तक पहुँचता है |
|---|---|---|
| एक Pro API key | Authorization: Bearer ap_v1_<...> | POST /v1/obfuscate/batch और GET /v1/usage। Key अपना workspace खुद निकाल लेती है, इसलिए कोई workspace id नहीं भेजा जाता। |
| एक dashboard session | वह session जो sign in करने के बाद आपके browser में रहता है | वह सब कुछ जो किसी account को manage करता है: keys बनाना, सूचीबद्ध करना और revoke करना, plans, billing, members, projects। एक स्पष्ट workspaceId और एक workspace role लेता है। |
Key एक build credential है। यह obfuscate करती है और अपना usage रिपोर्ट करती है, और यह न दूसरी key बना सकती है, न billing पढ़ सकती है, न workspace बदल सकती है। यही सीमा इसका उद्देश्य है: CI में रखी key आपका allowance खर्च कर सकती है, और कुछ नहीं।
Keys ap_v1_ के बाद 40 base62 characters होती हैं। Key ठीक एक बार दिखाई जाती है, बनाते समय। Server-side केवल एक salted HMAC-SHA256 hash रखा जाता है, इसलिए raw key बाद में कभी वापस नहीं मिल सकती, केवल revoke की जा सकती है। इसे dashboard में बनाएँ।
Endpoints
POST /v1/obfuscate/batch
एकमात्र obfuscation endpoint। एक call एक build है। हर फ़ाइल पूरी होते ही उसका result stream होकर वापस आता है।
Request: multipart/form-data।
| Part | ज़रूरी | विवरण |
|---|---|---|
batch | हाँ | Batch manifest, एक JSON string part के रूप में। |
| हर फ़ाइल का एक part | हाँ | JS source, उस partName के तहत जो उसकी manifest entry घोषित करती है। |
| हर source map का एक part | वैकल्पिक | एक upstream source map, उस entry के sourceMapPartName के तहत। |
Manifest यह है:
{
"version": "1",
"files": [
{
"filePath": "assets/app-a1b2c3.js", // echoed back on the result part
"partName": "file0", // names the form part carrying the source
"sourceMapPartName": "map0", // optional
"config": { "regions": [ /* ... */ ] } // optional, per-file
}
],
"config": { "preset": "hard", "seed": 42 }, // batch-level EngineConfig
"git": { "commitSha": "…", "ref": "…" } // optional build attribution
}Batch-level config एक engine config object है: Configuration पर दी गई हर key, जिसमें preset, seed और regions शामिल हैं। filePath और git manifest-level fields हैं; ऊपर manifest की बनावट देखें।
filePath में quote या CR/LF character नहीं हो सकता। इसे result part के Content-Disposition में ज्यों का त्यों echo किया जाता है, और malformed path अस्वीकार कर दिया जाता है।
curl https://api.afterpack.dev/v1/obfuscate/batch \
-H "Authorization: Bearer ap_v1_xxx" \
-F 'batch={"version":"1","files":[{"filePath":"dist/app.js","partName":"file0"}],"config":{"preset":"hard"}}' \
-F file0=@dist/app.jsResponse: 200, streaming multipart/mixed body के साथ। Parts फ़ाइलें पूरी होते ही आते हैं, इसलिए पूरे batch को buffer करने के बजाय हर part आते ही उसे disk पर लिखें:
- हर फ़ाइल का एक
obfuscation-resultpart:{ version, filePath, status, output, outputMap, processingManifest }। विफलता परoutputऔरoutputMapnullहोते हैं औरprocessingManifest.diagnosticsकारण बताता है। - एक अंतिम
batch-summarypart:{ version, totalFiles, successCount, failureCount, engineVersion, results, totalDurationMs, totalInputBytes, totalOutputBytes }।
किसी एक फ़ाइल की विफलता batch को नहीं रोकती। बाकी हर फ़ाइल सामान्य रूप से stream होती रहती है, और summary बताती है कि कितनी सफल और कितनी विफल रहीं।
GET /v1/usage
Workspace का usage और allowance। यह management जैसा एकमात्र read है जो key कर सकती है, ताकि कोई CI job अपना बचा हुआ allowance खुद जाँच सके। यह या तो एक Pro API key (जो अपना workspace खुद निकाल लेती है) या एक dashboard session के साथ ?workspaceId= स्वीकार करता है।
{
"tier": "indie",
"workspace": { "id": "…", "name": "…" },
"allowance": { "remainingMb": 412.5, "totalMb": 500, "resetAt": "…" },
"credits": { "balanceMb": 20 },
"subscription": { "status": "active", "plan": "indie_monthly", "renewsAt": "…", "graceUntil": null, "lapsed": false },
"recentBuilds": [
{
"buildId": "…", "builtAt": "…", "fileCount": 61,
"totalBytes": 3145728, "outputBytes": 9437184,
"meteredMb": 3.0, "allowanceMb": 3.0, "creditMb": 0, "overageMb": 0,
"projectId": "…", "cloudMs": 39120
}
]
}अज्ञात होने पर outputBytes और cloudMs null होते हैं, उनकी जगह कभी 0 नहीं। allowanceMb / creditMb / overageMb तीन pools में meteredMb का बँटवारा हैं।
Limits
| Limit | मान |
|---|---|
| प्रति फ़ाइल | 50 MB |
| प्रति batch फ़ाइलें | 200 |
| Batch के कुल bytes | 500 MB |
इनमें से किसी को भी पार करने पर request पूरी की पूरी 413 और DIAG_FILE_TOO_LARGE या DIAG_BATCH_TOO_LARGE के साथ अस्वीकार हो जाती है, कुछ भी meter होने से पहले। Dashboard की ओर से यही संख्याएँ API keys में हैं।
Rate limits
एक rolling 60-second window पर, प्रति key और प्रति client IP गिने जाते हैं:
| Scope | Limit |
|---|---|
| प्रति key, free workspace | 10 requests / min |
| प्रति key, paid workspace | 100 requests / min |
| प्रति client IP | 100 requests / min |
किसी भी scope को पार करने पर 429 लौटता है, DIAG_RATE_LIMITED और एक Retry-After header के साथ, जो उस समय पर सेट होता है जब तक trigger करने वाली window वास्तव में खाली न हो जाए। यदि rate-limit check खुद नहीं चल पाता, तो request 503 DIAG_RATE_CHECK_UNAVAILABLE और Retry-After: 5 के साथ fail closed होती है।
Build का time budget
पूरा bundle एक ही invocation के भीतर, 120-second CPU limit के तहत obfuscate होता है। दो wall-clock budgets build को उस limit के भीतर रखते हैं।
| बीता समय | क्या होता है |
|---|---|
| 45 s | Protection Map capture रुक जाता है। Obfuscation पूरा होने तक चलता है; stored map को deadline skip reason के साथ partial चिह्नित किया जाता है। |
| 90 s | कोई नई फ़ाइल शुरू नहीं की जाती। बाकी हर फ़ाइल DIAG_BUILD_DEADLINE के साथ एक स्पष्ट failure stream करती है, जो बताती है कि N में से कितनी पूरी हुईं, और stream सामान्य रूप से बंद होती है। |
अगर आप दूसरे budget तक पहुँचते हैं, तो batch को बाँट दें।
Diagnostic codes
Errors HTTP status के साथ एक स्थिर code लेकर आते हैं, उसी DIAG_* namespace में जिसमें engine के अपने diagnostics हैं। जिन्हें client को संभालना होता है:
| Code | Status | अर्थ |
|---|---|---|
DIAG_INVALID_KEY | 401 | Key मौजूद नहीं या पहचानी नहीं गई। |
DIAG_KEY_REVOKED | 401 | Key revoke कर दी गई थी। |
DIAG_KEY_EXPIRED | 401 | Key अपने expiresAt से आगे निकल चुकी है। |
DIAG_KEY_OUT_OF_SCOPE | 403 | Key मान्य है, पर उसकी allowedIPs सूची के बाहर के IP से इस्तेमाल हुई। |
DIAG_CLIENT_UPGRADE_REQUIRED | 426 | Client configured minimum version से नीचे है। details.minVersion साथ आता है। देखें Client compatibility। |
DIAG_API_SUNSET | 410 | इस API version का sunset हो चुका है। देखें Client compatibility। |
DIAG_ENTITLEMENT_LAPSED | 402 | Subscription का भुगतान बकाया है। graceUntil और upgradeUrl साथ आते हैं। |
DIAG_QUOTA_EXHAUSTED | 402 | Allowance + credits (+ overage cap, अगर चालू है) इस build को कवर नहीं कर सकते। remainingMb, requestedMb और एक reason साथ आते हैं, जो "quota ख़त्म" को "overage cap तक पहुँचे" से अलग करता है। |
DIAG_RATE_LIMITED | 429 | ऊपर rate limits देखें। retryAfterSeconds साथ आता है। |
DIAG_RATE_CHECK_UNAVAILABLE | 503 | Rate-limit check विफल हुआ; fail closed। Retry करें। |
DIAG_INVALID_MANIFEST | 400 | Malformed multipart body, batch part मौजूद नहीं, या ऐसा manifest जो validation में fail होता है। |
DIAG_FILE_TOO_LARGE | 413 | कोई एक फ़ाइल 50 MB से बड़ी। |
DIAG_BATCH_TOO_LARGE | 413 | 200 से ज़्यादा फ़ाइलें या कुल 500 MB से ज़्यादा। |
DIAG_BUILD_DEADLINE | n/a | प्रति फ़ाइल, एक 200 stream के भीतर। इस फ़ाइल के शुरू होने से पहले build का time budget ख़त्म हो गया। |
DIAG_ENGINE_FAILURE | n/a | प्रति फ़ाइल, एक 200 stream के भीतर। इस फ़ाइल पर engine ने error throw किया। |
आख़िरी दो HTTP statuses नहीं हैं। वे एक सफल response के भीतर किसी obfuscation-result part पर status: "failure" के रूप में आते हैं। जो client केवल HTTP status देखता है, वह आंशिक रूप से विफल build को साफ़ build समझ बैठेगा।
Retries और backoff
| Status | Retry योग्य | व्यवहार |
|---|---|---|
400, 401, 402, 403, 413 | नहीं | Request ठीक करें। |
429 | एक बार | Retry-After का ठीक-ठीक पालन करें, 120 s तक सीमित; दूसरा 429 fail closed होता है। |
500 | नहीं | Engine bug; इसे रिपोर्ट करें। |
503, 504 | हाँ | 1 s, 4 s, 16 s (तीन retries, कुल चार प्रयास), फिर fail closed। |
Official client 120-second का whole-request timeout भी लागू करता है, और DNS, TLS तथा connection-reset failures को अनिश्चित काल तक retry करने के बजाय unreachable-cloud मानता है।
Key lifecycle, client की नज़र से
Keys बनाना, उनका scope तय करना और उन्हें revoke करना dashboard operations हैं। इस API को call करने वाले code के लिए दो व्यवहार मायने रखते हैं:
- Build के बीच revocation। Batch stream होते समय revoke की गई key केवल अगली request पर
401लौटाती है; जो कुछ पहले से चल रहा है, वह सामान्य रूप से पूरा होता है। - IP सूची तक सीमित key कहीं और से इस्तेमाल होने पर
403 DIAG_KEY_OUT_OF_SCOPEलौटाती है, जो अमान्य या revoke की गई key को मिलने वाले401से अलग है, ताकि client "गलत key" और "सही key, गलत जगह" में फ़र्क कर सके।
जो batch workspace के pools में नहीं समाता, वह किसी भी फ़ाइल के dispatch होने से पहले पूरा का पूरा अस्वीकार हो जाता है, और pools अछूते रहते हैं: कभी आंशिक रूप से process नहीं, कभी आंशिक रूप से bill नहीं। यह fail-closed नियम का batch-level रूप है।
Source code का प्रबंधन
Obfuscation के लिए भेजा गया source केवल memory में, उसी एक request की अवधि तक process होता है, और कभी disk, logs या search index में नहीं लिखा जाता। Logs में request ids, फ़ाइलों की गिनती, bytes का योग और diagnostic codes होते हैं, कभी फ़ाइल contents, identifier names या constant values नहीं।
एक artifact request के बाद भी बना रहता है: dashboard के लिए हर build के साथ stored Protection Map। इसमें आपका मूल source होता है, जो इस आधार पर रंगा होता है कि हर token पर कितना transformation हुआ। यह हर project के लिए डिफ़ॉल्ट रूप से चालू है, केवल मालिक workspace के members ही इसे पढ़ सकते हैं, इसे एक साल और प्रति project आख़िरी 500 builds तक रखा जाता है (जो पहले ख़त्म हो), और इसे project settings में बंद किया जा सकता है। पूरा विवरण Privacy और data handling में है।
आगे
- Deployment modes: local Free build की तुलना में यह protocol कहाँ फिट होता है।
- Pro: Pro local engine के ऊपर क्या जोड़ता है।
- Privacy और data handling: क्या stored होता है, कितने समय तक, और उसे कौन पढ़ सकता है।
- Tiers: MB allowances, overage, और हर plan इस API पर क्या अनलॉक करता है।
- API keys: उस credential को बनाना, उसका scope तय करना, rotate और revoke करना जिसे यह API authenticate करता है।
- CLI reference: official client जो इन नियमों को लागू करता है।
- Configuration: वह engine config जो
configfield ले जाता है।