Структура пакета и точки входа

Пакет jose организован вокруг строгого разделения на модули, ориентированные на разные криптографические операции JSON Object Signing and Encryption (JOSE). Архитектура построена так, чтобы обеспечить максимально возможный tree-shaking, предсказуемые точки входа и поддержку как Node.js, так и современных браузерных окружений без дополнительных полифилов.

В основе структуры лежит поле exports в package.json, которое явно описывает доступные точки входа. Это позволяет ограничить использование внутренних файлов и гарантировать стабильный публичный API.

Типичная структура экспорта выглядит концептуально так:

{
  "exports": {
    ".": {
      "import": "./dist/browser/index.js",
      "require": "./dist/node/index.js"
    },
    "./jwt": {
      "import": "./dist/browser/jwt/index.js",
      "require": "./dist/node/jwt/index.js"
    },
    "./jws": {
      "import": "./dist/browser/jws/index.js",
      "require": "./dist/node/jws/index.js"
    },
    "./jwe": {
      "import": "./dist/browser/jwe/index.js",
      "require": "./dist/node/jwe/index.js"
    },
    "./jwks": {
      "import": "./dist/browser/jwks/index.js",
      "require": "./dist/node/jwks/index.js"
    }
  }
}

Такая схема делает пакет строго модульным: каждая функциональная область вынесена в отдельную точку входа, что уменьшает итоговый бандл при сборке приложения.

ESM и CommonJS точки входа

Библиотека поддерживает два режима загрузки:

  • ESM (ES Modules) — основной современный формат
  • CommonJS — для обратной совместимости с Node.js проектами старого типа

ESM-ветка

ESM-версия используется через import:

import { jwtVerify, SignJWT } from 'jose'

или через более узкие пути:

import { jwtVerify } from 'jose/jwt'

ESM-структура предпочтительна, так как она позволяет:

  • выполнять tree-shaking на уровне бандлера
  • избегать динамических require
  • использовать статический анализ зависимостей

CommonJS-ветка

Для проектов, использующих require, доступна отдельная сборка:

const { jwtVerify } = require('jose')

Внутренне она ссылается на CommonJS-сборку в dist/node.

Основные каталоги пакета

Физическая структура пакета (упрощённо) выглядит следующим образом:

jose/
 ├── dist/
 │    ├── node/
 │    │    ├── index.js
 │    │    ├── jwt/
 │    │    ├── jws/
 │    │    ├── jwe/
 │    │    └── jwks/
 │    ├── browser/
 │         ├── index.js
 │         ├── jwt/
 │         ├── jws/
 │         ├── jwe/
 │         └── jwks/
 ├── src/
 │    ├── jwt/
 │    ├── jws/
 │    ├── jwe/
 │    ├── jwk/
 │    └── runtime/
 ├── package.json

Ключевая идея: исходный код (src) разделён по криптографическим доменам, а dist содержит платформенные сборки.

Разделение на криптографические домены

Библиотека строго делит функциональность на несколько независимых модулей.

JWT (JSON Web Token)

Модуль JWT отвечает за создание и проверку токенов:

  • подпись (SignJWT)
  • верификация (jwtVerify)
  • декодирование без проверки

Путь:

jose/jwt

Этот модуль зависит от JWS, так как JWT использует JWS для подписи.

JWS (JSON Web Signature)

Модуль цифровых подписей:

  • sign
  • verify
  • compact сериализация

Путь:

jose/jws

Является базовым уровнем доверия для JWT.

JWE (JSON Web Encryption)

Модуль шифрования:

  • encrypt
  • decrypt
  • управление ключами для симметричного и асимметричного шифрования

Путь:

jose/jwe

JWE является наиболее тяжёлым по зависимости модулем, так как включает криптографические алгоритмы обмена ключами и симметричного шифрования.

JWK (JSON Web Key)

Модуль работы с ключами:

  • импорт ключей из PEM / JWK
  • экспорт ключей
  • нормализация форматов

Используется всеми остальными модулями как фундамент.

JWKS (JSON Web Key Set)

Надстройка над JWK для работы с наборами ключей:

  • загрузка из URL
  • кеширование ключей
  • автоматический выбор ключа по kid

Путь:

jose/jwks

Рuntime-слой и абстракция окружений

Внутри пакета выделен слой runtime, который отвечает за адаптацию к среде выполнения.

Он определяет:

  • доступность Web Crypto API (crypto.subtle)
  • fallback на Node.js crypto
  • различия в импорте ключей
  • поведение random generator

Это позволяет одной и той же библиотеке работать в:

  • Node.js (16+)
  • современных браузерах
  • edge runtime (Cloudflare Workers, Vercel Edge)

Сборка и dist-структура

Каталог dist содержит финальные артефакты сборки.

Node.js сборка

dist/node/

Особенности:

  • использование встроенного crypto модуля Node.js
  • CommonJS и ESM варианты
  • оптимизация под серверное выполнение

Browser сборка

dist/browser/

Особенности:

  • использование Web Crypto API
  • отсутствие Node.js зависимостей
  • минимизация и tree-shaking готовность

Разделение на две платформы позволяет избежать универсальных “универсальных бандлов”, которые обычно содержат лишний код.

Стратегия точек входа и глубокого импорта

Пакет поддерживает три уровня импортов:

1. Полный импорт

import * as jose from 'jose'

Используется редко, так как подтягивает больше кода.

2. Доменный импорт

import { jwtVerify } from 'jose/jwt'

Оптимальный баланс между удобством и размером.

3. Глубокий импорт (внутренний API)

import { decodeProtectedHeader } from 'jose/jws/compact/decode'

Формально доступен, но не считается стабильным API. Может меняться между версиями.

Tree-shaking и влияние структуры на размер бандла

Архитектура экспорта напрямую влияет на возможность tree-shaking.

Ключевые принципы:

  • каждый криптографический алгоритм вынесен в отдельный модуль
  • отсутствует централизованный “монолитный” index с побочными импортами
  • зависимости между модулями направлены строго вниз (JWT → JWS → JWK)

Это позволяет бандлерам (Vite, Webpack, Rollup) исключать неиспользуемые алгоритмы, например:

  • RSA при использовании только HMAC
  • JWE при работе только с JWT

Иерархия зависимостей внутри пакета

Логическая структура зависимостей выглядит следующим образом:

JWK (ключи)
 ↑
JWS (подписи)
 ↑
JWT (токены)
 
JWE (шифрование) → использует JWK напрямую
JWKS (наборы ключей) → использует JWK

Такая иерархия исключает циклические зависимости и делает поток криптографических операций линейным и предсказуемым.

Внутренние утилиты и вспомогательные слои

Внутри src/runtime и src/util располагаются вспомогательные компоненты:

  • нормализация Base64URL
  • сериализация JOSE header
  • проверка типов ключей
  • адаптеры криптографических API

Эти части не экспортируются напрямую, но используются всеми доменными модулями.

Особенности версионирования структуры

Структура пакета считается частью публичного API:

  • изменение путей экспорта считается breaking change
  • добавление новых точек входа — minor release
  • внутренние изменения dist не влияют на пользователей при сохранении exports

Это делает библиотеку стабильной с точки зрения интеграции в долгоживущие системы аутентификации.