Высокопроизводительный HTTP- и WebSocket-сервер для Node.js поверх нативного транспорта swm-uws. Один экземпляр сервера может обслуживать оба протокола.
Выбирайте swm-core, если нужен готовый серверный слой: маршрутизация и before hooks, контексты запросов, лимиты body и времени, streaming, backpressure и корректное завершение работы.
Синхронный handler оставляйте синхронным: Promise-путь нужен только при реальном await.
http.onRequest и http.routes взаимоисключающие. Пустой http: {} возвращает предсказуемый 404.
HTTP и WebSocket можно включать независимо; хотя бы один из них должен быть настроен.
ws.onUpgrade обязателен: верните объект user data для принятия соединения или null для отказа. Тот же объект становится ctx.data без копирования; подпротокол выбирает отдельный selectProtocol.
Все размеры задаются в байтах. По умолчанию HTTP body ограничен 1 МиБ на запрос и общим бюджетом 256 МиБ.
В v5.1.2 ctx.bodyStream() даёт поток owned Buffer chunks с backpressure для крупных upload. Создайте его до первого await, не сочетайте с prefetch и другими readers; maxStreamBodySize ограничивает один поток, а тело не учитывается в maxBodyBudget.
02
Что предоставляет сервер
Нативный транспорт
HTTP и WebSocket проходят через @swarmmachina/swm-uws без промежуточного JS transport layer.
Маршрутизация и hooks
Универсальный onRequest или декларативные method/path routes с :param, wildcard /* и цепочками before.
Контроль ресурсов
Пулы HttpContext, конечный body budget, лимиты buffered и streaming body на route, 30-секундный async timeout и нативная transport policy для заголовков, body rate, соединений и trusted proxy.
Потоки и backpressure
ctx.bodyStream() для upload с backpressure, stream, startStreaming, tryEnd, onWritable и числовой статус отправки WebSocket.
Управление соединениями
Безопасный async upgrade: ctx.data сохраняет точную идентичность возвращённого объекта; доступны selectProtocol, pub/sub, адресация через connectionKey, graceful close и force terminate.
Ответы и lifecycle
prepareHeaders, CORS и static-file helpers; shutdown(timeout) ждёт активные запросы и соединения, close() завершает их немедленно.
03
Runtime и платформы
Среда
Статус
Примечание
Node.js 22 / 24
Поддерживается
Другие major-версии отклоняются engines constraint.
Linux x64 + glibc
Поддерживается
Для контейнеров используйте bookworm/slim.
Windows x64
Поддерживается
Готовая нативная сборка.
macOS arm64 / x64
Поддерживается
Apple Silicon и Intel.
Linux ARM64 / Windows ARM64
Нет сборки
Не входят в текущую матрицу prebuilds.
Alpine / musl
Не поддерживается
Используйте glibc-based image.
TLS / permessage-deflate
Отключено
Завершайте TLS перед приложением.
04
Карта API
Server
Жизненный цикл, pub/sub и адресуемые WebSocket-соединения.
Переиспользуемые заголовки, CORS и раздача статических файлов.
defineConfig()prepareHeaders()cors()serveStatic()
Полные сигнатуры, типы и примеры находятся в README и TypeScript declarations исходного репозитория.
05
Body lifetime, лимиты и backpressure
swm-core намеренно оставляет стоимость и время жизни данных видимыми. Эти правила важны для корректного production-кода.
Lazy body до первого await
В режиме по умолчанию вызовите ctx.body(), buffer(), text() или json() до первой асинхронной операции. Иначе uWS-события body могут прийти до регистрации reader.
Prefetch для async auth
Включите http.prefetch или route.prefetch, если сначала нужно дождаться БД/авторизации, а затем читать body. Байты собираются заранее, JSON всё равно парсится лениво.
Потоковый upload создавайте до await
Для большого request body вызовите ctx.bodyStream() синхронно до первого await в hook или handler и передайте поток в pipeline(). Не сочетайте его с prefetch, body(), buffer(), text() или json(). maxStreamBodySize и более узкий route/per-call лимит ограничивают размер одного upload; stream.destroy() нужен, если чтение прекращается раньше.
Ограничивайте память и время
Значения задаются в байтах: maxBodySize по умолчанию 1 МиБ (максимум 64 МиБ), maxBodyBudget — 256 МиБ. maxStreamBodySize по умолчанию равен maxBodySize и не учитывается в общем body budget. 0 означает нулевую ёмкость, null явно отключает общий учёт. Превышение запроса даёт 413, исчерпание бюджета — 503.
Учитывайте защитные дефолты v4.1
requestTimeoutMs по умолчанию завершает зависшую async-цепочку через 30 секунд с 408. WebSocket ограничен 1 МиБ на входящее сообщение и 64 КиБ backpressure на соединение; медленный сокет по умолчанию закрывается после drop.
Изолируйте доставку ошибок
В v5.1 http.onError получает неизменяемое body-free event, а не HttpContext. Укажите errorDelivery.headers, query и includeIp только для необходимой диагностики; queueLimit, concurrency и timeoutMs ограничивают удалённый sink. Смотрите httpErrorDeliveryStats, включая dropped и timedOut.
Сохраняйте только нужные заголовки
http, route и ws prefetchHeaders сохраняют выбранные поля в ctx.headers или meta.headers для работы после await. Используйте 'all' только когда нужен полный набор: selective prefetch дешевле и явнее.
Используйте явные request readers
В v5 используйте getIP(), getMethod(), getUrl(), getQuery(), getParameter(), getReqHeader(), getHeaders() и getContentLength(): короткие aliases удалены. getHeaders() возвращает изолированную копию полного набора и после await требует заранее сохранённых данных.
Ограничивайте нативный transport
transport задаёт maxHeaderSize/count, таймауты headers, keep-alive, body idle и response write, минимальную скорость body и trustedProxy. Значения валидируются до запуска сервера.
Проверяйте send status
WSContext.send() возвращает 1 при успехе, 0 при backpressure и 2, если сообщение отброшено из-за лимита.
Не удерживайте HttpContext
HttpContext переиспользуется между запросами. WSContext живёт всё соединение, но использовать его после onClose нельзя.
Задавайте границу доверия к proxy явно
transport.trustedProxy по умолчанию выключен. Включайте { header: 'x-real-ip' } или { header: 'x-forwarded-for', hops: N } только на listener за proxy, который перезаписывает выбранный заголовок; X-Forwarded-For считается справа. ctx.getIP() возвращает выбранный адрес, а без заголовка — адрес upstream peer. Не используйте сетевой адрес как аутентифицированную identity.
06
Частые вопросы
Короткие ответы на вопросы о выборе пакета, runtime-контрактах и production-ограничениях.
01
Что такое swm-core?
swm-core - экспериментальный HTTP- и WebSocket-сервер для Node.js 22 и 24 поверх нативного binding swm-uws. Он объединяет routing, request context, лимиты body, таймауты, backpressure и graceful shutdown в одном серверном API.
02
Когда выбирать swm-core, а когда swm-uws?
Для прикладного API, WebSocket gateway или обычного production-сервиса начинайте со swm-core. Берите swm-uws, если нужна совместимая низкоуровневая поверхность uWebSockets.js App() и команда готова сама владеть routing, lifetime request/response, лимитами и shutdown.
03
Как сохранить HTTP-заголовки после await в swm-core 5.1?
Укажите http.prefetchHeaders или route.prefetchHeaders со списком нужных полей. Для WebSocket upgrade используйте ws.prefetchHeaders. Выбранные заголовки доступны через ctx.headers или meta.headers после await; режим 'all' сохраняйте для случаев, где действительно нужен полный набор.
04
Как безопасно отправлять HTTP-ошибки во внешний сервис?
В v5.1 http.onError получает immutable HttpErrorEvent, а не переиспользуемый HttpContext. Настройте errorDelivery с конечными concurrency, queueLimit и timeoutMs; headers, query и includeIp включайте только явным allowlist. Состояние очереди и потери доступны через server.httpErrorDeliveryStats.
05
Как читать body после асинхронной авторизации?
Включите http.prefetch или route.prefetch: swm-core начнёт ограниченный сбор байтов до before/handler, а JSON распарсит только при вызове ctx.json(). В lazy-режиме вызовите ctx.body(), buffer(), text() или json() до первого await и сохраните Promise.
06
Как оптимизировать большие upload в swm-core 5.1.2?
Не материализуйте весь body: при выключенном prefetch создайте ctx.bodyStream() синхронно до первого await и передайте его в pipeline(). maxStreamBodySize ограничивает один поток, route/per-call лимит может только сузить его. Поток нельзя сочетать с body(), buffer(), text() или json(); если handler прекращает чтение раньше, вызовите stream.destroy(). Backpressure ограничивает очередь потока, но не заменяет лимит параллельных upload и бюджет downstream-хранилища.
07
Как ограничить медленные или некорректные HTTP-клиенты?
Передайте transport с явными maxHeaderSize, maxHeaderCount, headersTimeoutMs, keepAliveTimeoutMs, bodyIdleTimeoutMs, minBodyRateBytesPerSec и responseWriteTimeoutMs. Эти ограничения применяются нативным транспортом до или во время работы прикладного handler.
08
Как получить IP клиента за доверенным reverse proxy?
В swm-core 5.1.2 настройте transport.trustedProxy как { header: 'x-real-ip' } или { header: 'x-forwarded-for', hops: N }. Опция выключена по умолчанию: включайте её только на listener, доступном через proxy, который перезаписывает выбранный заголовок. X-Forwarded-For считается справа; если заголовка нет, ctx.getIP() возвращает адрес upstream peer.
09
Поддерживает ли swm-core TLS, Alpine и ARM64 Linux?
Нет. Текущая матрица поддерживает Node.js 22/24, Linux x64 с glibc, Windows x64 и macOS arm64/x64. TLS и permessage-deflate отключены, Alpine/musl и Linux/Windows ARM64 не имеют текущих prebuilds; TLS нужно завершать перед приложением.
07
Когда брать низкоуровневый binding
swm-core подходит большинству сервисов. Переходите к swm-uws, если нужна прямая совместимость с обычным App() API uWebSockets.js и вы готовы сами управлять lifetime request/response объектов.
JavaScripttransport-choice.js
// Высокоуровневый серверimport Server from'@swarmmachina/swm-core'// Низкоуровневый bindingimport uWS from'@swarmmachina/swm-uws'