API - Hono на Cloudflare Workers¶
Общее описание¶
API-шлюз платформы AACSearch, реализованный на фреймворке Hono и развёрнутый как Cloudflare Worker (hono-saas). Выступает единой точкой входа для всех клиентских запросов, обеспечивая аутентификацию, авторизацию, биллинг, rate limiting и проксирование запросов к Typesense.
Расположение: /root/api
Структура проекта¶
/root/api/
├── wrangler.jsonc # Конфигурация CF Workers + Secrets Store
├── package.json # Зависимости и скрипты
├── tsconfig.json # Конфигурация TypeScript
├── .dev.vars # Локальные секреты для wrangler dev
├── src/
│ ├── index.ts # Точка входа, middleware chain, exports
│ ├── env.ts # Типы биндингов, SecretBinding, resolveSecrets()
│ ├── middleware/
│ │ ├── auth.ts # Auth.js + Zitadel OIDC
│ │ ├── apiAuth.ts # 4-факторная аутентификация
│ │ ├── bearer.ts # JWT верификация с кешированием JWKS
│ │ ├── tenant.ts # Определение тенанта по поддомену
│ │ ├── billingGate.ts # Проверка наличия подписки (Lago)
│ │ ├── rateLimit.ts # Ограничение частоты запросов (KV)
│ │ └── featureGate.ts # Проверка доступных фич (Lago entitlements)
│ ├── modules/
│ │ ├── search/
│ │ │ ├── routes.ts # POST /api/v1/search
│ │ │ ├── apiKeysRoutes.ts # Управление scoped API keys
│ │ │ ├── typesense.ts # Клиент Typesense
│ │ │ └── scopedKey.ts # Верификация scoped search key
│ │ ├── documents/
│ │ │ └── routes.ts # CRUD документов
│ │ ├── billing/
│ │ │ ├── routes.ts # Эндпоинты биллинга (1168 строк)
│ │ │ ├── lagoClient.ts # Фабрика Lago SDK
│ │ │ ├── usageTracking.ts # Учёт использования
│ │ │ ├── lagoWebhooks.ts # Обработка вебхуков Lago
│ │ │ └── dashboardRoutes.ts # Дашборд биллинга
│ │ ├── typesense/
│ │ │ └── routes.ts # Прокси-шлюз к Typesense API (800+ строк)
│ │ ├── auth/
│ │ │ └── routes.ts # Zitadel V2 API proxy (login/register/reset)
│ │ ├── data-sources/
│ │ │ ├── routes.ts # CRUD источников данных
│ │ │ ├── queue.ts # Обработка очереди задач (crawl, reindex)
│ │ │ ├── crawl.ts # Web-краулинг
│ │ │ ├── parsers.ts # Парсеры (Feed/HTML)
│ │ │ ├── db.ts # D1 запросы
│ │ │ └── schema.sql # Схема D1
│ │ ├── reindex/
│ │ │ ├── routes.ts # API переиндексации
│ │ │ └── executor.ts # Исполнитель задач
│ │ └── ai/
│ │ ├── routes.ts # RAG/AI эндпоинты
│ │ └── presets.ts # AI-пресеты
│ ├── cron/
│ │ └── index.ts # Планировщик (daily + 15-min)
│ └── gen/
│ ├── typesense/ # Сгенерированные типы Typesense OpenAPI
│ └── search-client/ # Сгенерированные типы публичного Search API
├── scripts/ # Вспомогательные скрипты
└── specs/
└── typesense/openapi.yml # Спецификация Typesense API
Конфигурация Cloudflare Worker (wrangler.jsonc)¶
Основные параметры¶
| Параметр | Значение |
|---|---|
| Имя воркера | hono-saas |
| Compatibility Date | 2026-02-08 |
| KV Namespace (CACHE) | 26582ff95322434cb3a395bef5c0acc0 |
| D1 Database (DB) | aacsearch-data-sources |
| Queue (CRAWL_QUEUE) | jobs-queue |
| Secrets Store | 26a0f16b21cb435c8c842e2a18787e56 |
| Cron | 0 2 * * * (ежедневно в 2:00 UTC), */15 * * * * (каждые 15 мин) |
Маршруты¶
| Паттерн | Зона |
|---|---|
api.aacsearch.com/* |
cf8a427718fe4e801feaf840620e0bd3 |
docs.aacsearch.com/* |
та же зона |
Переменные окружения¶
ZITADEL_ISSUER=https://auth.aacsearch.com
ZITADEL_CLIENT_ID=359289240758059011
ZITADEL_JWKS_URI=https://auth.aacsearch.com/oauth/v2/keys
LAGO_API_URL=https://billing-api.aacsearch.com/api/v1
TYPESENSE_URL=http://aacsearch.com:13000
TYPESENSE_COLLECTION=documents
TENANT_ROOT_DOMAIN=aacsearch.com
Секреты (Cloudflare Secrets Store)¶
Все секреты хранятся в Secrets Store (ID: 26a0f16b21cb435c8c842e2a18787e56) и персистентны между деплоями. Не требуют переустановки после wrangler deploy.
| Секрет | Назначение |
|---|---|
AUTH_SECRET |
Подпись сессии Auth.js |
ZITADEL_CLIENT_SECRET |
OIDC client secret |
ZITADEL_SERVICE_ACCOUNT_TOKEN |
PAT сервисного аккаунта |
ZITADEL_AUDIENCE |
OIDC audience |
LAGO_API_KEY |
Ключ Lago API |
LAGO_WEBHOOK_HMAC_KEY |
HMAC-ключ для вебхуков Lago |
TYPESENSE_PARENT_SEARCH_KEY |
Родительский ключ поиска |
TYPESENSE_API_KEY |
Серверный ключ Typesense (aac) |
OPENAI_API_KEY |
Ключ OpenAI (для AI-модулей) |
Тип SecretBinding¶
В production Secrets Store возвращает { get(): Promise<string> }, в dev (.dev.vars) — обычную строку. Тип:
type SecretBinding = string | { get(): Promise<string> };
Секреты разрешаются один раз за запрос через resolveSecrets(env) и сохраняются в контексте Hono (c.get("secrets")) или передаются параметром в cron/queue обработчики.
Цепочка Middleware¶
Запросы проходят через последовательную цепочку middleware, каждый из которых добавляет контекст или отклоняет запрос:
Запрос
│
▼
0. resolveSecrets() — Разрешение SecretBinding → строки
│ Результат: secrets в контексте Hono
▼
1. CORS — Разрешённые origins:
│ app/platform/billing/docs.aacsearch.com
▼
2. authConfig() — Инициализация Auth.js
▼
3. Auth V2 Routes — /api/auth/v2/* (login, register, reset)
│ Публичные маршруты, без Bearer
▼
4. Auth.js Routes — /api/auth/* (OIDC sign-in, callback, sign-out)
▼
5. tenantResolver() — Извлечение slug из поддомена
│ acme.aacsearch.com → slug = "acme"
▼
6. apiAuth() — 4-факторная аутентификация:
│ 1) X-AACSEARCH-API-KEY (scoped key, клиентский JS)
│ 2) Bearer JWT (SDK, server-to-server)
│ 3) aac_session cookie (V2 Session, Panel SPA)
│ 4) Auth.js session cookie (legacy)
│ Результат: tenantId в контексте
▼
7. billingGate() — Проверка активной подписки
│ KV кеш → webhook маркер → Lago API (fallback)
│ 402 если нет подписки, 502 если Lago недоступен
▼
8. rateLimit() — Ограничение частоты запросов
│ KV счётчик: ratelimit:{tenantId}:{minute}
│ 429 если лимит превышен
▼
9. featureGate() — Проверка доступности фич
│ Lago entitlements → KV кеш
│ 403 если фича недоступна
▼
Обработчик маршрута
Аутентификация¶
Auth.js + Zitadel OIDC (файл: src/middleware/auth.ts)¶
Используется @hono/auth-js с провайдером Zitadel:
- Client ID: 359289240758059011
- Issuer: https://auth.aacsearch.com
- basePath: /api/auth
Поток JWT Callback¶
- Из профиля пользователя извлекается
urn:zitadel:iam:user:resourceowner:id→ сохраняется какtoken.org_id - Из JWT claim извлекается
plan_code(инжектируется Zitadel Action) → сохраняется в токене - Сессия содержит
org_idиplan_code
Bearer JWT верификация (файл: src/middleware/bearer.ts)¶
- Извлечение токена из заголовка
Authorization: Bearer <jwt> - Проверка подписи через JWKS:
- Сначала KV кеш
zitadel:jwks(TTL 1 час) - Затем удалённый запрос к
ZITADEL_JWKS_URI - Валидация issuer и audience
- Извлечение
tenantIdиз claim: urn:zitadel:iam:user:resourceowner:id(основной)org_id(запасной)resource_owner(запасной)- Извлечение
plan_code(если есть)
apiAuth Middleware (файл: src/middleware/apiAuth.ts)¶
4-факторная аутентификация в порядке приоритета:
| Приоритет | Метод | Назначение |
|---|---|---|
| 1 | X-AACSEARCH-API-KEY header |
Scoped search key для клиентского JS |
| 2 | Authorization: Bearer <jwt> |
SDK / server-to-server (Zitadel JWT) |
| 3 | aac_session cookie |
V2 Session API (Panel SPA) |
| 4 | Auth.js session cookie | Legacy браузерный flow |
V2 Session верифицируется через Zitadel GET /v2/sessions/{sessionId}, результат кешируется в KV на 5 минут. Все методы устанавливают tenantId в контексте.
Rate Limiting (файл: src/middleware/rateLimit.ts)¶
Лимиты по планам¶
| План | Запросов/мин |
|---|---|
starter_v1 |
100 |
professional_v1 |
500 |
enterprise_v1 |
0 (без ограничений) |
payg_v1 |
1000 |
Механизм¶
- Получение
planCodeиз контекста (Bearer JWT, billingGate или featureGate) - Если
planCodeотсутствует — проверка KV:billing:{tenantId}:entitlementилиbilling:{tenantId}:subscription_active - Вычисление минутного окна:
Math.floor(Date.now() / 60000) - KV ключ:
ratelimit:{tenantId}:{minute}(TTL 1 мин) - Инкремент счётчика
- HTTP 429 если лимит превышен
Заголовки ответа¶
X-RateLimit-Limit— Максимум запросовX-RateLimit-Remaining— Осталось запросовX-RateLimit-Reset— Время сброса счётчика
Feature Gates (файл: src/middleware/featureGate.ts)¶
Доступные фичи¶
synonyms, curations, stopwords, presets, vector_search, rag,
multi_search, analytics_advanced, bulk_import, export, stemming,
nl_search, geo_search, faceting, grouping, semantic_search,
image_search, voice_search, joins, scoped_api_keys, conversations
Привязка маршрутов к фичам¶
| Маршрут | Фича |
|---|---|
/api/v1/engine/conversations/* |
rag |
/api/v1/engine/synonym_sets/* |
synonyms |
/api/v1/engine/curation_sets/* |
curations |
/api/v1/engine/stopwords/* |
stopwords |
/api/v1/engine/presets/* |
presets |
/api/v1/engine/stemming/* |
stemming |
/api/v1/engine/nl_search_models/* |
nl_search |
/api/v1/engine/multi_search |
multi_search |
Механизм¶
- Получение
subscription external_idиз KV или Lago API - Запрос entitlements:
lago.subscriptions.findAllSubscriptionEntitlements() - Кеширование в KV:
entitlements:{tenantId}(TTL 5 мин) - Вебхуки инвалидируют кеш при изменении подписки
- HTTP 403 если фича недоступна, 402 если нет подписки
Модули¶
Search (файл: src/modules/search/routes.ts)¶
Эндпоинт: POST /api/v1/search
Запрос¶
{
"q": "поисковый запрос",
"limit": 20,
"page": 1,
"filters": { "status": "active", "category": "news" }
}
Ответ¶
{
"total": 150,
"hits": [
{
"id": "doc-123",
"title": "Заголовок документа",
"snippet": "...фрагмент с <mark>подсветкой</mark>...",
"score": 0.95
}
]
}
Поток обработки¶
- Валидация запроса (Zod)
- Вызов
searchTypesense()с изоляцией тенанта - Построение
filter_by:tenant_id:={tenantId} && ...safe_filters - Безопасные фильтры:
status,type,category,lang(whitelist) - Генерация scoped search key (HMAC, TTL 10 мин)
- Асинхронная отправка usage event
- Маппинг ответа: Typesense
text_match→score, highlights →snippet
Scoped Search Key (файл: src/modules/search/scopedKey.ts)¶
Алгоритм генерации ключа с ограниченными правами:
- Создание JSON параметров:
{filter_by: "...", expires_at: <unix_timestamp + 600>} - HMAC:
HMAC-SHA256(parentSearchKey, paramsJSON)→ base64 - Извлечение префикса: первые 4 символа
parentSearchKey - Комбинирование:
digest + prefix + paramsJSON→ base64
Documents (файл: src/modules/documents/routes.ts)¶
| Эндпоинт | Метод | Описание |
|---|---|---|
/api/v1/documents |
POST | Индексация одного документа |
/api/v1/documents/bulk |
POST | Массовая индексация (до 1000) |
/api/v1/documents/{id} |
DELETE | Удаление документа |
Схема документа¶
{
"id": "doc-1",
"title": "Заголовок",
"content": "Содержимое документа",
"type": "document",
"category": "news",
"status": "active",
"lang": "en",
"metadata": {}
}
Автоматически добавляемые поля:
- tenant_id — ID тенанта (изоляция)
- created_at — Unix timestamp
- Значения по умолчанию: type = "document", status = "active", lang = "en"
Typesense Gateway (файл: src/modules/typesense/routes.ts)¶
Прокси-шлюз к Typesense API с изоляцией тенантов через префиксирование коллекций.
Стратегия изоляции¶
Все коллекции имеют формат: t_{tenantId}__{collectionName}
| Внешнее имя | Внутреннее имя |
|---|---|
products |
t_12345__products |
articles |
t_12345__articles |
Разрешённые эндпоинты¶
/collections, /multi_search, /aliases, /analytics,
/presets, /stopwords, /curation_sets, /synonym_sets
Заблокированные эндпоинты¶
/keys, /debug, /stats.json, /metrics.json,
/operations, /analytics/flush
Перезапись запросов¶
| Операция | Перезапись |
|---|---|
POST /collections |
body.name → t_{tenantId}__name |
POST /multi_search |
searches[].collection → с префиксом |
PUT /aliases/{id} |
body.collection_name → с префиксом |
POST /analytics/rules |
Имя правила + source_collections → с префиксом |
POST /analytics/events |
body.name → с префиксом |
Перезапись ответов¶
Из ответов удаляется префикс тенанта: - Списки коллекций, алиасов, правил курирования, синонимов, стоп-слов, пресетов — фильтруются по тенанту и депрефиксируются
Определение и отслеживание фич¶
Из URL, query string и тела запроса определяются используемые фичи:
| Признак | Фича |
|---|---|
_geoloc, geo(...) |
geo_search |
vector_query |
semantic_search |
image_query, image_embedding |
image_search |
voice_query |
voice_search |
join, join_as |
joins |
group_by |
grouping |
/multi_search |
multi_search |
Auth V2 Proxy (файл: src/modules/auth/routes.ts)¶
Прокси к Zitadel V2 API для клиентской панели. Все эндпоинты публичные (без Bearer), PAT сервисного аккаунта хранится на сервере.
| Эндпоинт | Метод | Описание |
|---|---|---|
/api/auth/v2/login |
POST | Создание сессии (проверка пароля) |
/api/auth/v2/register |
POST | Регистрация + авто-логин |
/api/auth/v2/password-reset |
POST | Запрос письма для сброса пароля |
/api/auth/v2/password-set |
POST | Установка нового пароля по коду |
/api/auth/v2/session |
GET | Проверка текущей сессии |
/api/auth/v2/logout |
POST | Удаление сессии |
Data Sources (файл: src/modules/data-sources/)¶
Модуль управления источниками данных (RSS/Atom фиды, веб-страницы) с автоматическим краулингом.
| Эндпоинт | Метод | Описание |
|---|---|---|
/api/v1/data-sources |
GET | Список источников |
/api/v1/data-sources |
POST | Создание источника |
/api/v1/data-sources/:id |
PUT | Обновление |
/api/v1/data-sources/:id |
DELETE | Удаление |
Хранение: D1 (SQLite), асинхронная обработка: Queue (Cloudflare Queues).
Reindex (файл: src/modules/reindex/)¶
Управление задачами полной переиндексации коллекций.
AI (файл: src/modules/ai/)¶
RAG/AI эндпоинты и пресеты для AI-поиска.
API Keys (файл: src/modules/search/apiKeysRoutes.ts)¶
Генерация и управление scoped API-ключами для клиентского поиска.
Биллинг¶
Lago Client (файл: src/modules/billing/lagoClient.ts)¶
export function createLagoClient(env: LagoEnv) {
return Client(env.LAGO_API_KEY, { baseUrl: env.LAGO_API_URL });
}
КРИТИЧНО:
LAGO_API_URLдолжен заканчиваться на/api/v1— SDK конкатенирует пути напрямую.
Маршруты биллинга (файл: src/modules/billing/routes.ts)¶
| Эндпоинт | Метод | Описание |
|---|---|---|
/api/v1/billing/customers |
GET | Получение данных о клиенте тенанта |
/api/v1/billing/customers |
POST | Создание/обновление клиента |
/api/v1/billing/subscriptions |
GET | Список подписок |
/api/v1/billing/subscriptions |
POST | Создание подписки |
/api/v1/billing/wallets |
GET | Список кошельков |
/api/v1/billing/wallets |
POST | Создание кошелька |
/api/v1/billing/wallet/topup |
POST | Пополнение кошелька |
/api/v1/billing/invoices |
GET | Список инвойсов |
/api/v1/billing/events |
POST | Отправка события использования |
Дашборд биллинга (файл: src/modules/billing/dashboardRoutes.ts)¶
| Эндпоинт | Описание |
|---|---|
/api/v1/billing/dashboard/usage |
Статистика использования за текущий период |
/api/v1/billing/dashboard/invoices |
История инвойсов |
/api/v1/billing/dashboard/subscription |
Детали текущей подписки |
Отслеживаемые метрики: search_request, vector_search, rag_query, documents_stored, geo_query, multi_search_query, semantic_query, image_query, voice_query, join_query
Учёт использования (файл: src/modules/billing/usageTracking.ts)¶
Биллинговые события¶
search_request, vector_search, rag_query, documents_indexed,
documents_stored, api_call, synonym_set_created, curation_rule_created,
geo_query, multi_search_query, semantic_query, image_query,
voice_query, join_query
Структура события¶
{
"transaction_id": "uuid-v4",
"external_subscription_id": "sub-123",
"code": "search_request",
"timestamp": 1707523200,
"properties": {
"tenant_id": "org-456",
"query": "поисковый запрос"
}
}
Отправка неблокирующая через executionCtx.waitUntil().
Вебхуки Lago (файл: src/modules/billing/lagoWebhooks.ts)¶
Эндпоинт: POST /webhooks/lago (без аутентификации)
Верификация подписи¶
- Заголовок:
X-Lago-Signature - Алгоритм:
X-Lago-Signature-Algorithm(hmacилиjwt, по умолчаниюhmac) - HMAC:
base64(HMAC-SHA256(key, body))— base64, НЕ hex!
Дедупликация¶
KV ключ: wh:{uniqueKey} (TTL 7 дней). UniqueKey из заголовка X-Lago-Unique-Key или SHA-256 хеш тела.
Обработка событий¶
| Событие | Действие |
|---|---|
subscription.started |
Кеш subscription_active + plan_code + очистка entitlements + синхронизация plan_code в Zitadel |
subscription.terminated |
Удаление всех биллинг-кешей + удаление plan_code из Zitadel |
subscription.updated |
Очистка кешей, обновление plan_code, синхронизация в Zitadel |
invoice.paid_credit_added |
Кеш последнего кредитного события |
invoice.finalized |
Кеш деталей инвойса |
wallet.depleted |
Кеш события истощения кошелька |
Синхронизация с Zitadel¶
При наличии ZITADEL_SERVICE_ACCOUNT_TOKEN:
- POST {issuer}/management/v1/metadata/plan_code с plan_code (base64)
- DELETE {issuer}/management/v1/metadata/plan_code при отмене подписки
- Выполняется неблокирующе через waitUntil
Billing Gate (файл: src/middleware/billingGate.ts)¶
Каскад проверок наличия активной подписки:
1. KV кеш: billing:{tenantId}:entitlement (TTL 5 мин)
├─ Найдено → результат
└─ Не найдено ↓
2. KV маркер: billing:{tenantId}:subscription_active (TTL 30 дней)
├─ Найдено → результат
└─ Не найдено ↓
3. Lago API (таймаут 5 сек):
lago.customers.findAllCustomerSubscriptions(tenantId)
├─ Активная подписка → кеширование + OK
├─ Нет подписки → HTTP 402
└─ Lago недоступен → HTTP 502
Кеширование отрицательных результатов: - Неоплаченные тенанты: 60 сек - Оплаченные тенанты: 300 сек
Планировщик задач (Cron)¶
Расписания¶
| Расписание | Задача |
|---|---|
0 2 * * * (ежедневно в 2:00 UTC) |
reportDocumentStorage() — подсчёт документов |
*/15 * * * * (каждые 15 мин) |
dispatchScheduledCrawls() — запуск краулинга |
Все cron-обработчики получают секреты через resolveSecrets(env) в index.ts, затем передают как параметр secrets: ResolvedSecrets.
reportDocumentStorage()¶
- Запрос к Typesense
/collections - Агрегация количества документов по тенантам (коллекции
t_{tenantId}__*) - Отправка события
documents_storedв Lago для каждого тенанта - Агрегация MAX (Lago хранит только максимальное значение за период)
dispatchScheduledCrawls()¶
- Проверка D1 на источники данных с наступившим расписанием
- Постановка задач краулинга в Queue (
CRAWL_QUEUE)
Очередь задач (Queue)¶
Queue: jobs-queue (Cloudflare Queues)
Обработчик handleJobQueue() принимает batch сообщений:
| Тип | Описание |
|---|---|
crawl |
Краулинг источника данных (URL, парсинг, индексация) |
reindex |
Полная переиндексация коллекции |
reindex_chunk |
Обработка чанка переиндексации |
Постоянные ошибки (400, 404) → подтверждение + пометка failed. Временные ошибки → retry.
KV Cache — Использование¶
| Ключ | TTL | Назначение |
|---|---|---|
zitadel:jwks |
1 час | Кеш JWKS для верификации JWT |
billing:{tenantId}:entitlement |
5 мин / 1 мин (negative) | Кеш entitlement с источником |
billing:{tenantId}:subscription_active |
30 дней | Маркер вебхука с plan_code |
billing:{tenantId}:plan_code |
5 мин | Кешированный plan code |
billing:{tenantId}:last_paid_credit |
1 день | Последнее кредитное событие |
billing:{tenantId}:last_invoice |
1 день | Последний инвойс |
billing:{tenantId}:wallet_depleted |
1 час | Событие истощения кошелька |
ratelimit:{tenantId}:{minute} |
1 мин | Счётчик запросов |
wh:{uniqueKey} |
7 дней | Дедупликация вебхуков |
entitlements:{tenantId} |
5 мин | Entitlements фич |
lago:webhook:public_key |
1 день | Публичный ключ вебхука Lago |
OpenAPI документация¶
| Эндпоинт | Описание |
|---|---|
GET /doc |
OpenAPI спецификация (JSON, английский) |
GET /doc/en |
OpenAPI спецификация (английский) |
GET /doc/ru |
OpenAPI спецификация (русский) |
GET /docs |
Scalar API Reference UI (двуязычный) |
Обработка ошибок¶
Глобальный обработчик¶
app.onError((err, c) => {
if (err instanceof HTTPException) {
return c.json({ error: err.message }, err.status);
}
console.error(err);
return c.json({ error: "Internal error", debug: String(err) }, 500);
});
HTTP-коды ответа¶
| Код | Значение |
|---|---|
| 401 | Отсутствует или невалидная аутентификация |
| 402 | Нет активной подписки / фича недоступна |
| 403 | Доступ запрещён / фича не включена в план |
| 404 | Ресурс не найден |
| 429 | Превышен лимит запросов |
| 502 | Провайдер биллинга / бэкенд поиска недоступен |
Зависимости¶
| Библиотека | Версия | Назначение |
|---|---|---|
hono |
4.9.0 | Веб-фреймворк для Workers |
@hono/zod-openapi |
1.2.1 | OpenAPI из Zod-схем |
@hono/auth-js |
1.1.0 | Интеграция Auth.js |
@scalar/hono-api-reference |
0.9.40 | UI документации API |
@auth/core |
0.37.0 | Auth.js core |
jose |
6.1.3 | JWT операции, JWKS |
lago-javascript-client |
1.0.0 | Lago SDK |
openapi-fetch |
0.13.0 | Сгенерированный OpenAPI клиент |
zod |
4.0.0 | Валидация схем |
wrangler |
4.12.0 | CLI Cloudflare Workers |
Деплой¶
Секреты хранятся в Cloudflare Secrets Store и персистентны между деплоями. Пост-деплой шаги не требуются.
cd /root/api
npx wrangler deploy
# Готово! Секреты сохраняются автоматически.
Обновление секрета¶
npx wrangler secrets-store secret update 26a0f16b21cb435c8c842e2a18787e56 \
--name SECRET_NAME --remote
Экспорт обработчиков¶
Worker экспортирует три обработчика:
export default {
fetch: app.fetch, // HTTP-запросы
async scheduled(event, env, ctx) { // Cron-триггеры
const secrets = await resolveSecrets(env);
await handleScheduled(event, env, ctx, secrets);
},
async queue(batch, env, ctx) { // Queue-сообщения
const secrets = await resolveSecrets(env);
await handleJobQueue(batch, env, ctx, secrets);
},
};