Пакет 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-версия используется через import:
import { jwtVerify, SignJWT } from 'jose'
или через более узкие пути:
import { jwtVerify } from 'jose/jwt'
ESM-структура предпочтительна, так как она позволяет:
requireДля проектов, использующих 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 отвечает за создание и проверку токенов:
SignJWT)jwtVerify)Путь:
jose/jwt
Этот модуль зависит от JWS, так как JWT использует JWS для подписи.
Модуль цифровых подписей:
signverifycompact сериализацияПуть:
jose/jws
Является базовым уровнем доверия для JWT.
Модуль шифрования:
encryptdecryptПуть:
jose/jwe
JWE является наиболее тяжёлым по зависимости модулем, так как включает криптографические алгоритмы обмена ключами и симметричного шифрования.
Модуль работы с ключами:
Используется всеми остальными модулями как фундамент.
Надстройка над JWK для работы с наборами ключей:
kidПуть:
jose/jwks
Внутри пакета выделен слой runtime, который отвечает за
адаптацию к среде выполнения.
Он определяет:
crypto.subtle)cryptoЭто позволяет одной и той же библиотеке работать в:
Каталог dist содержит финальные артефакты сборки.
dist/node/
Особенности:
crypto модуля Node.jsdist/browser/
Особенности:
Разделение на две платформы позволяет избежать универсальных “универсальных бандлов”, которые обычно содержат лишний код.
Пакет поддерживает три уровня импортов:
import * as jose from 'jose'
Используется редко, так как подтягивает больше кода.
import { jwtVerify } from 'jose/jwt'
Оптимальный баланс между удобством и размером.
import { decodeProtectedHeader } from 'jose/jws/compact/decode'
Формально доступен, но не считается стабильным API. Может меняться между версиями.
Архитектура экспорта напрямую влияет на возможность tree-shaking.
Ключевые принципы:
Это позволяет бандлерам (Vite, Webpack, Rollup) исключать неиспользуемые алгоритмы, например:
Логическая структура зависимостей выглядит следующим образом:
JWK (ключи)
↑
JWS (подписи)
↑
JWT (токены)
JWE (шифрование) → использует JWK напрямую
JWKS (наборы ключей) → использует JWK
Такая иерархия исключает циклические зависимости и делает поток криптографических операций линейным и предсказуемым.
Внутри src/runtime и src/util располагаются
вспомогательные компоненты:
Эти части не экспортируются напрямую, но используются всеми доменными модулями.
Структура пакета считается частью публичного API:
dist не влияют на пользователей
при сохранении exportsЭто делает библиотеку стабильной с точки зрения интеграции в долгоживущие системы аутентификации.