Довідник AfterPack Cloud API

Протокол взаємодії з api.afterpack.dev: автентифікація, ендпоінт пакетної обфускації, обмеження, ліміти запитів, часовий бюджет збірки та діагностичні коди, які має обробляти клієнт.

@afterpack/core і кожен плагін для фреймворку вже працюють за цим протоколом, щойно налаштовано ключ Pro: автентифікація, потокова передача multipart, повторні спроби, усе це. Читайте цю сторінку, коли підключаєте власну інтеграцію з CI, пишете клієнт поза офіційними пакетами або налагоджуєте відповідь, якої ваш інструментарій не очікував.

Базовий URL і версіонування

Базовий URL: https://api.afterpack.dev/v1/

API версіонується через URL, і v1 є єдиною версією. У її межах поля відповіді додаються, але ніколи не видаляються і не змінюють призначення; несумісна зміна вийшла б як v2 поруч із нею. GET /v1/version повертає розгорнуту версію та середовище, а GET / є перевіркою доступності без автентифікації.

Сумісність клієнтів

Два необов'язкові заголовки запиту; якщо їх немає або вони некоректні, вони ігноруються, а не спричиняють 400. Скрипт на curl або клієнт, старший за ці заголовки, це ніяк не зачіпає:

ЗаголовокЩо передає
X-AfterPack-Client-VersionВстановлену npm-версію @afterpack/core для клієнта, побудованого на ньому.
X-AfterPack-ClientПакет, що викликає API, і його версію, наприклад afterpack/0.1.0 або @afterpack/vite/0.1.0.

Порівняння відбувається лише на сервері, за MAJOR.MINOR.PATCH, без урахування суфікса пререлізу (0.1.0-rc.3 читається як 0.1.0); версію, яку сервер не може розібрати, або відсутність заголовка завжди приймають. Поки мінімальну версію налаштовано, кожна відповідь містить X-AfterPack-Min-Client-Version, тож скрипт може перевірити свій стан, не наражаючись на відмову. Перевірка відбувається одразу після автентифікації ключа, до читання тіла запиту:

  • Нижче налаштованого мінімуму: 426 DIAG_CLIENT_UPGRADE_REQUIRED із details.minVersion.
  • Під час періоду виведення з експлуатації: 410 DIAG_API_SUNSET.

За замовчуванням жодне з них не налаштовано. Робочий простір побачить їх лише тоді, коли AfterPack задасть мінімальну версію або дату виведення з експлуатації для цього API.

Відповідь також може містити масив notices верхнього рівня: в успішному batch-summary, у будь-якому тілі помилки та у відповіді 202 телеметрії тарифу Free. Формат {severity, code, message, url?}, не більше 5 елементів, кожне message обмежене 500 символами. Невідоме значення severity трактується як попередження; окрім показу, робити з ним нічого не потрібно.

Автентифікація

Два види облікових даних, і вони не взаємозамінні.

Облікові даніЗаголовокДо чого дають доступ
API-ключ ProAuthorization: Bearer ap_v1_<...>POST /v1/obfuscate/batch і GET /v1/usage. Ключ сам визначає свій робочий простір, тож ідентифікатор робочого простору не надсилається.
Сесія дашбордуСесія, яку тримає ваш браузер після входуУсе, що керує обліковим записом: створення, перегляд і відкликання ключів, плани, оплата, учасники, проєкти. Потребує явного workspaceId і ролі в робочому просторі.

Ключ є обліковими даними для збірки. Він обфускує та звітує про власне використання і не може створити інший ключ, прочитати дані про оплату чи змінити робочий простір. Саме в цьому обмеженні суть: ключ, що лежить у CI, може витрачати ваш ліміт, і нічого більше.

Ключі мають вигляд ap_v1_, за яким іде 40 символів base62. Ключ показується рівно один раз, під час створення. На сервері зберігається лише солений хеш HMAC-SHA256, тож сирий ключ пізніше неможливо відновити, лише відкликати. Створіть ключ у дашборді.

Pro cloud batch-obfuscation request flowYour buildplugin / CLIPOST /v1/obfuscate/batchAuthorization: Bearer ap_…AfterPack cloudobfuscates each fileobfuscation is in-memoryper-file resultsBatch summarycounts + timingYour build outputprotected & written backFiles stream back one by one; the source sent for obfuscation is processed in memory, not stored.

Ендпоінти

POST /v1/obfuscate/batch

Єдиний ендпоінт обфускації. Один виклик дорівнює одній збірці. Результати повертаються потоком у міру завершення кожного файлу.

Запит: multipart/form-data.

ЧастинаОбов'язковаОпис
batchТакМаніфест пакета як рядкова JSON-частина.
по одній частині на файлТакВихідний код JS під іменем partName, яке оголошує його запис у маніфесті.
по одній частині на source mapНеобов'язковаВхідний source map під іменем sourceMapPartName цього запису.

Маніфест має такий вигляд:

{
  "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
}

config рівня пакета є об'єктом конфігурації рушія: кожен ключ зі сторінки Конфігурація, зокрема preset, seed і regions. filePath і git є полями рівня маніфесту; див. структуру маніфесту вище.

filePath не може містити лапки або символи CR/LF. Його дослівно повертають у Content-Disposition частини з результатом, а некоректний шлях відхиляється.

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.js

Відповідь: 200 з потоковим тілом multipart/mixed. Частини надходять у міру завершення файлів, тож записуйте кожну на диск, щойно вона прийшла, а не буферизуйте весь пакет:

  1. По одній частині obfuscation-result на файл: { version, filePath, status, output, outputMap, processingManifest }. У разі помилки output і outputMap дорівнюють null, а processingManifest.diagnostics пояснює причину.
  2. Завершальна частина batch-summary: { version, totalFiles, successCount, failureCount, engineVersion, results, totalDurationMs, totalInputBytes, totalOutputBytes }.

Помилка в одному файлі не перериває пакет. Усі інші файли так само надходять потоком, а підсумок показує розподіл.

GET /v1/usage

Використання та ліміт робочого простору. Єдине читання з категорії керування, доступне ключу, щоб завдання CI могло перевірити свій залишок ліміту. Приймає або API-ключ Pro (який сам визначає свій робочий простір), або сесію дашборду разом із ?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 показують, як meteredMb розподілено між трьома пулами.

Обмеження

ОбмеженняЗначення
На файл50 MB
Файлів у пакеті200
Загальний обсяг пакета500 MB

Якщо перевищено будь-яке з них, запит відхиляється повністю з 413 і DIAG_FILE_TOO_LARGE або DIAG_BATCH_TOO_LARGE, ще до будь-якого обліку. Ті самі числа з боку дашборду наведено в розділі API-ключі.

Ліміти запитів

Рахуються в ковзному вікні 60 секунд, окремо для ключа та для IP-адреси клієнта:

ОбластьЛіміт
На ключ, безкоштовний робочий простір10 запитів / хв
На ключ, платний робочий простір100 запитів / хв
На IP-адресу клієнта100 запитів / хв

Перевищення будь-якої з областей повертає 429 з DIAG_RATE_LIMITED і заголовком Retry-After, що дорівнює часу, за який вікно, яке спрацювало, справді звільниться. Якщо саму перевірку ліміту неможливо виконати, запит зупиняється з помилкою (fail closed): 503 DIAG_RATE_CHECK_UNAVAILABLE і Retry-After: 5.

Часовий бюджет збірки

Увесь бандл обфускується в межах одного виклику з лімітом CPU у 120 секунд. Два бюджети реального часу утримують збірку в цьому ліміті.

МинулоЩо відбувається
45 sЗбирання даних для Protection Map припиняється. Обфускація триває до завершення; збережену мапу позначено як часткову з причиною пропуску deadline.
90 sЖоден новий файл більше не починається. Для кожного файлу, що залишився, потоком надходить явна помилка DIAG_BUILD_DEADLINE із зазначенням, скільки з N завершено, і потік закривається штатно.

Якщо ви досягли другого бюджету, розділіть пакет.

Діагностичні коди

Помилки містять стабільний code разом зі статусом HTTP, у тому самому просторі імен DIAG_*, що й власна діагностика рушія. Ті, які має обробляти клієнт:

КодСтатусЗначення
DIAG_INVALID_KEY401Ключ відсутній або не розпізнаний.
DIAG_KEY_REVOKED401Ключ відкликано.
DIAG_KEY_EXPIRED401Термін дії ключа (expiresAt) минув.
DIAG_KEY_OUT_OF_SCOPE403Дійсний ключ використано з IP-адреси поза його списком allowedIPs.
DIAG_CLIENT_UPGRADE_REQUIRED426Версія клієнта нижча за налаштований мінімум. Містить details.minVersion. Див. Сумісність клієнтів.
DIAG_API_SUNSET410Цю версію API виведено з експлуатації. Див. Сумісність клієнтів.
DIAG_ENTITLEMENT_LAPSED402Платіж за підписку прострочено. Містить graceUntil і upgradeUrl.
DIAG_QUOTA_EXHAUSTED402Ліміт + кредити (+ ліміт перевищення, якщо увімкнено) не покривають цю збірку. Містить remainingMb, requestedMb і reason, що розрізняє «ліміт вичерпано» та «досягнуто ліміту перевищення».
DIAG_RATE_LIMITED429Див. ліміти запитів вище. Містить retryAfterSeconds.
DIAG_RATE_CHECK_UNAVAILABLE503Перевірка ліміту запитів не вдалася; зупинка з помилкою (fail closed). Повторіть спробу.
DIAG_INVALID_MANIFEST400Некоректне тіло multipart, відсутня частина batch або маніфест, що не пройшов валідацію.
DIAG_FILE_TOO_LARGE413Один файл понад 50 MB.
DIAG_BATCH_TOO_LARGE413Понад 200 файлів або понад 500 MB загалом.
DIAG_BUILD_DEADLINEн/дДля окремого файлу, усередині потоку 200. Часовий бюджет збірки вичерпався до того, як цей файл було розпочато.
DIAG_ENGINE_FAILUREн/дДля окремого файлу, усередині потоку 200. Рушій видав помилку на цьому файлі.

Останні два не є статусами HTTP. Вони надходять як status: "failure" у частині obfuscation-result усередині успішної відповіді. Клієнт, який перевіряє лише статус HTTP, сприйме частково невдалу збірку за чисту.

Повторні спроби та відступ

СтатусПовторюватиПоведінка
400, 401, 402, 403, 413НіВиправте запит.
429Один разДотримуйтеся Retry-After точно, не більше 120 s; другий 429 зупиняє з помилкою (fail closed).
500НіПомилка рушія; повідомте про неї.
503, 504Так1 s, 4 s, 16 s (три повтори, усього чотири спроби), потім зупинка з помилкою (fail closed).

Офіційний клієнт також застосовує 120-секундний тайм-аут на весь запит і трактує збої DNS, TLS і скидання з'єднання як недоступність хмари, а не повторює їх безкінечно.

Життєвий цикл ключа з боку клієнта

Створення, обмеження та відкликання ключів є операціями дашборду. Для коду, що викликає цей API, важливі дві особливості поведінки:

  • Відкликання посеред збірки. Ключ, відкликаний під час потокової передачі пакета, повертає 401 лише на наступний запит; усе, що вже виконується, завершується штатно.
  • Ключ, обмежений списком IP-адрес, повертає 403 DIAG_KEY_OUT_OF_SCOPE, коли його використовують звідкись іще. Це відрізняється від 401, який отримує недійсний або відкликаний ключ, тож клієнт може відрізнити «не той ключ» від «правильний ключ, не те місце».
Облік атомарний і виконується першим

Пакет, який не вміщається в пули робочого простору, відхиляється повністю до того, як буде відправлено будь-який файл, а пули залишаються незмінними: ніколи не обробляється частково і ніколи не оплачується частково. Це форма правила fail closed на рівні пакета.

Поводження з вихідним кодом

Вихідний код, надісланий на обфускацію, обробляється лише в пам'яті, протягом одного цього запиту, і ніколи не записується на диск, у журнали чи в пошуковий індекс. Журнали містять ідентифікатори запитів, кількість файлів, сумарні обсяги в байтах і діагностичні коди, але ніколи не вміст файлів, імена ідентифікаторів чи значення констант.

Один артефакт живе довше за запит: Protection Map, яка зберігається для кожної збірки для дашборду. Вона містить ваш оригінальний вихідний код, розфарбований за тим, скільки трансформацій зазнав кожен токен. Вона увімкнена за замовчуванням для кожного проєкту, доступна для читання лише учасникам робочого простору-власника, зберігається один рік і в межах останніх 500 збірок на проєкт (залежно від того, що настане раніше), і її можна вимкнути в налаштуваннях проєкту. Докладніше в розділі Конфіденційність і обробка даних.

Далі

  • Режими розгортання: яке місце цей протокол посідає порівняно з локальною збіркою Free.
  • Pro: що Pro додає понад локальний рушій.
  • Конфіденційність і обробка даних: що зберігається, як довго і хто може це читати.
  • Тарифи: ліміти в MB, перевищення і що кожен план відкриває в цьому API.
  • API-ключі: створення, обмеження, ротація та відкликання облікових даних, якими автентифікується цей API.
  • Довідник CLI: офіційний клієнт, який реалізує ці правила.
  • Конфігурація: конфігурація рушія, яку передає поле config.