npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@safe-shape/compat

v3.4.1

Published

Contract snapshots and compatibility analysis for SafeShape.

Readme

Совместимость контрактов

English | Русский

@safe-shape/compat создаёт детерминированные snapshots и консервативно сравнивает версии контрактов.

Snapshots v1 и v2

import { object, string } from "@safe-shape/core";
import { createContractSnapshot, createContractSnapshotV2 } from "@safe-shape/compat";
const user = object({ id: string() });
const tree = createContractSnapshot(user, { id: "user" });
const graph = createContractSnapshotV2(user, { id: "user" });

V1: формат safe-shape.contract/v1, стабильный id, каноническое JSON-safe дерево и fingerprint sha256:. Свойства и required сортируются; title/description сохраняются, examples исключаются, чтобы не сохранять образцы payload. V1 отклоняет lazy-ссылки и сохраняет прежние формат/fingerprint.

V2: safe-shape.contract/v2, графы input/output со своими fingerprint и общий fingerprint. Граф содержит root и сортированный definitions. Непрозрачные выходы остаются opaque. Хеш вычисляется по компактному каноническому JSON; ключи и required сортируются, значимый порядок tuple/union сохраняется. Id контракта и сохранённые fingerprint не входят в семантический хеш.

parseContractSnapshot и parseContractSnapshotV2 проверяют недоверенные данные, пересобирают замороженные контейнеры, отклоняют несовпадение fingerprint. V2 проверяет все три хеша, отсутствующие цели ссылок и недостижимые definitions. V1 и V2 не подменяют друг друга. При переходе создавайте отдельный согласованный baseline, не перезаписывайте рассмотренный файл автоматически.

Направления сравнения

compareContracts(previousSchema, nextSchema, options?) и compareContractSnapshots(previous, next, options?) работают с v1. compareContractsV2 и compareContractSnapshotsV2 — с графами; side по умолчанию input, допускается output. Режимы compatibility:

  • backward: previous ⊆ next;
  • forward: next ⊆ previous;
  • full: оба направления.
import { string } from "@safe-shape/core";
import { compareContracts } from "@safe-shape/compat";
const previous = string({ minLength: 3, maxLength: 40 });
const next = string({ minLength: 1, maxLength: 80 });
compareContracts(previous, next, { compatibility: "backward" }).status; // safe
compareContracts(previous, next, { compatibility: "forward" }).status; // breaking

Id версий одного контракта должны совпадать, иначе результат unknown. Рекурсивные пары проверяются коиндуктивно; lazy-id и топология повторного использования не являются runtime-семантикой. Пути findings семантические, не пути хранения definitions.

Отчёты и решения о миграции

Отчёт содержит compatible, status, compatibility, fingerprint обеих сторон и замороженные findings. Статусы: safe — доказано, breaking — известен класс контрпримеров, risky — достоверный, но недоказанный риск, unknown — доказательства нет, annotation-only — изменились только не-runtime аннотации. Finding содержит code, path, direction, предыдущий/следующий узел, message и suggestion.

createMigrationDiagnostics(report) даёт JSON-friendly решение, счётчики, summary и действия без изменения доказательства: safe/annotation-only → compatible, breaking → migration-required, risky/unknown → manual-review. migrationRequired истинен только для breaking; manualReviewRequired — для risky/unknown. Helper не генерирует миграции и не принимает новый baseline.

Правила

Нормативная матрица задаёт правила для всех видов схем. Нативные ограничения сравниваются как множества допустимых значений. Enum/literal проверяются точно, включая pattern, format и multipleOf цели. После проверки opaque-ограничений never содержится в любой цели, unknown содержит любой источник; сужение unknown — breaking.

Одинаковые discriminatedUnion/intersection поддерживаются; неподдержанные структурные отношения дают unknown. При чтении snapshot перепроверяются структура и уникальность дискриминатора. Шаблоны/форматы хранятся и проверяются; смена неподдающихся доказательству pattern/format даёт unknown. При их совпадении длина по-прежнему анализируется направленно.

Для multipleOf доказывается расширение десятичной решётки: удаление ограничения или шаг цели, делящий шаг источника. Другие случаи консервативны. Ограничения ключей record используют строковые правила на пути <key>, значения — на *.

Политики объектов сохраняются. При той же форме reject → permissive безопасен в направлении принятия, обратно — breaking. Strip ↔ passthrough меняет выход и считается breaking. Добавление universal identity unknown в passthrough может быть безопасно; более узкие поля дают breaking, opaque остаются unknown. Удаление identity-поля в passthrough безопасно; transforms требуют отдельного анализа.

Кортежи сравниваются позиционно и с массивами с учётом эффективной длины. Union-removal даёт breaking при конечном непокрытом значении или доказанно непересекающейся населённой ветви; возможное коллективное покрытие остаётся unknown. Коды включают tuple.array.changed, contract.target.empty; пустая цель даёт breaking только при конструктивном доказательстве непустоты источника.

Непрозрачное поведение

Callback нельзя восстановить из snapshot. Анонимные правила дают unknown. Равные стабильные id — утверждение автора о неизменной семантике, не сравнение кода функций. Меняйте id вместе с поведением; пустые id запрещены. Совпадающие стабильные opaque output id считаются неизменным поведением.

HTTP и контрпримеры

createHttpCompatibilityPresentation(report, { exchange: "request" | "response" }) сохраняет доказательство и добавляет роли: request — клиент производит, сервер потребляет; response — наоборот. Backward относится к consumer, forward — к producer, full — к обоим. Сохраняются status, fingerprint, side и исходные findings.

createContractCounterexamples добавляет конкретные свидетельства в ограниченном поддержанном домене; отсутствие значения не доказывает безопасность. См. контрпримеры.

Связи producer/consumer

С 3.2 checkContractConnection(producerSnapshotV2, consumerSnapshotV2) сравнивает output производителя с input потребителя. ContractConnectionReport содержит идентичности, comparison, migration и counterexample с реально производимым значением либо явной причиной отсутствия. См. связи.

В версии 3.3.0 checkSchemaConnection(producer, consumer, { producerId?, consumerId? }) анализирует живые схемы по верхней границе выхода. Значения id по умолчанию: producer, consumer. SchemaConnectionReport.evidence равен output-bound; producer fingerprint относится к границе. Только доказанное включение даёт compatible, недоказанное — unknown/manual-review, контрпример не строится. Callbacks не исполняются, lazy-getters могут разрешаться. Старые snapshot API не меняются. См. проверяемые выходы.