# @xyo-network/sdk-protocol-core

> Foundation SDK barrel for XYO Protocol 2.0 (protocol, core payload plugins, manifest, sdk-utils)

Latest version **8.0.3** (published 2026-10-09) · LGPL-3.0-only license · 0 weekly downloads

## Install

```sh
npm install @xyo-network/sdk-protocol-core
pnpm add @xyo-network/sdk-protocol-core
yarn add @xyo-network/sdk-protocol-core
bun add @xyo-network/sdk-protocol-core
```

## Health

**Score 60/100 (C)** — status: active.

Positive: esm support; no vulnerabilities; recently updated; high maintenance score.

Warnings: low downloads; no types.

## Facts

| | |
|---|---|
| Version | 8.0.3 |
| Published | 2026-10-09 |
| First published | 2026-07-10 |
| Weekly downloads | 0 |
| License | LGPL-3.0-only |
| TypeScript types | none |
| Module format | ESM |
| Node | ^26 |
| Dependencies | 11 |
| Unpacked size | 2.5 MB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | XYO Development Team |
| Maintainers | atrouw, joelbcarter, rphansen91, jordantrouw, jonesmac |

## Links

- npm: https://www.npmjs.com/package/@xyo-network/sdk-protocol-core
- Repository: https://github.com/XYOracleNetwork/sdk-protocol-js
- Homepage: https://xyo.network
- Issues: git+https://github.com/XYOracleNetwork/sdk-protocol-js/issues
- npm.io page: https://npm.io/package/@xyo-network/sdk-protocol-core

## Dependencies (11)

- [idb](https://npm.io/package/idb.md) ~8.0.4
- [hash-wasm](https://npm.io/package/hash-wasm.md) ~4.12.0
- [@scure/base](https://npm.io/package/@scure/base.md) ~2.4.0
- [async-mutex](https://npm.io/package/async-mutex.md) ~0.5.0
- [@scure/bip39](https://npm.io/package/@scure/bip39.md) ~2.4.0
- [observable-fns](https://npm.io/package/observable-fns.md) ~0.6.1
- [@ariestools/sdk](https://npm.io/package/@ariestools/sdk.md) ~9.0.1
- [@bitauth/libauth](https://npm.io/package/@bitauth/libauth.md) ~3.0.0
- [@ariestools/threads](https://npm.io/package/@ariestools/threads.md) ~9.0.1
- [@metamask/providers](https://npm.io/package/@metamask/providers.md) ~22.1.1
- [@noble/post-quantum](https://npm.io/package/@noble/post-quantum.md) ~0.7.1

## Recent versions

- 8.0.3 (latest) — 2026-10-09
- 8.0.2 — 2026-10-08
- 8.0.1 — 2026-09-22
- 8.0.0 — 2026-09-17
- 7.4.2 — 2026-08-28
- 7.4.1 — 2026-08-27
- 7.4.0 — 2026-08-27
- 7.3.3 — 2026-08-25
- 7.3.2 — 2026-08-23
- 7.3.1 — 2026-08-23
- 7.3.0 — 2026-08-23
- 7.2.4 — 2026-08-13
- 7.2.3 — 2026-07-27
- 7.2.2 — 2026-07-20
- 7.2.1 — 2026-07-16
- … 3 more at https://npm.io/package/@xyo-network/sdk-protocol-core/versions

## README

[![logo][]](https://xyo.network)

# @xyo-network/sdk-protocol-core

[![npm][npm-badge]][npm-link]
[![license][license-badge]][license-link]

> Foundation SDK core monolith for XYO Protocol 2.0 — protocol, core payload plugins, manifest, and sdk-utils. The public `@xyo-network/sdk-protocol` package re-exports this package.

## Core implementation

This package owns the implementation modules. `@xyo-network/sdk-protocol` is the
public compatibility facade; consumers normally import from that facade or the
`@xyo-network/sdk` umbrella. The core compiles in toolchain monolith mode from
[`xy.config.ts`](xy.config.ts); the facade re-exports its public modules.

```ts
import { asSchema, PayloadBuilder } from '@xyo-network/sdk-protocol'
```

## Payload schema contracts

This section defines schema naming, payload structure revisions, and hash selection
for XYO and applications on XYO Layer 1. The SDK validates syntax and explicitly
supported revisions; the application still owns its field semantics, authorization,
compatibility policy, and historical replay rules. This documents the current
source contract; no package publication, deployed-network activation, or automatic
upgrade of older consumers is implied. Tightened validation needs a compatibility
review before rollout to an existing ingestion or replay path.

### Schema identifiers

`schema` is a stable type-family identifier, not a URL or a structure-version string.
Its exact grammar is:

```text
[a-z0-9]+(?:\.[a-z0-9]+)*
```

The entire string must match. Only ASCII lowercase `a`–`z`, digits `0`–`9`, and
single dots between nonempty segments are allowed. Reject uppercase, Unicode,
hyphens, underscores, whitespace, URL punctuation/escaping, empty segments, and
leading or trailing dots. Do not normalize an invalid identifier into another one.
Create constants with `asSchema(name, true)`; `makeSchema(name)` also validates the
literal before producing its schema.

| Valid identifiers | Invalid identifiers |
|---|---|
| `com.example.market.results` | `com.example.market.results-view` |
| `network.xyo.payload` | `network.xyo.Payload` |
| `com.example.sensor2.reading` | `com.example..reading`, `com.example.café` |

The base syntax does not require three segments or establish ownership.
`SchemaNameValidator`, and `PayloadValidator` with its default schema-name factory,
also retain their existing minimum of three segments: `asSchema('local', true)`
can pass while default payload validation rejects that name. This update does not
loosen that existing acceptance requirement.

Public application identifiers should use a controlled reverse-domain namespace;
`network.xyo.*` is reserved for XYO protocol authors, and `com.example.*` is for
examples. Domain-authority resolution additionally requires at least three
segments and verifies the exact reversed domain. A domain containing a hyphen
cannot simply be copied into this grammar: removing `-` changes the domain and may
name somebody else's authority. Use a valid namespace you actually control; do not
invent a domain-normalization mapping. See the
[Domain Schema Authority specification](src/modules/domain-payload-plugin/SPEC.md).

New identifiers MUST NOT encode a payload structure revision with suffixes such as
`.v1`, `.v01`, or `.1`; these are syntactically valid but are a design anti-pattern.
Use `$version` for structure revisions. A subject's API/product version is a
separate, explicitly named data field such as `apiVersion`. Existing published
identifiers remain historical contracts: do not rename them, reinterpret their
suffixes, or dual-read unrelated shapes without an explicit migration.

### Payload structure version

`$version` is reserved client metadata identifying the payload's structure
contract. It is optional. Absence in the **original payload** permanently means
`1.0.0`; malformed values are errors, not another spelling of absence.

```text
encoded = major * 1_000_000 + minor * 1_000 + patch
```

Each component is an integer from `0` through `999`; the encoded value is an integer
from `0` through `999_999_999`. `1.2.3` is `1_002_003`, and the absent default is
`1_000_000`. Strings, `null`, negative values, fractions, non-finite numbers, and
out-of-range values are invalid. This is a numeric three-component version; it
does not encode SemVer prerelease or build labels. Do not switch to radix 10,000.

```ts
import {
  asSchema, DefaultPayloadVersion, encodePayloadVersion,
  getPayloadVersion, PayloadBuilder,
} from '@xyo-network/sdk-protocol'

const schema = asSchema('com.example.sensor.reading', true)
const payload = new PayloadBuilder({ schema })
  .fields({ temperatureCelsius: 21 })
  .meta({ $version: encodePayloadVersion({ major: 1, minor: 2, patch: 3 }) })
  .build()

getPayloadVersion(payload) // 1_002_003; validates, does not mutate
getPayloadVersion({ schema }) === DefaultPayloadVersion // true; no field inserted
```

`PayloadVersionZod`, `isPayloadVersion`, `asPayloadVersion`, `toPayloadVersion`,
`encodePayloadVersion`, and `decodePayloadVersion` implement this numeric contract.
Reading or validating an omitted default MUST NOT inject `$version` into an
existing object: explicit and omitted `1.0.0` have the same effective revision but
different root hashes. Choose the emitted representation at creation time.

### Definitions, closure, and compatibility

Every published `(schema, effectiveVersion)` definition is **frozen**: its fields,
types, constraints, semantics, and unknown-field policy cannot silently change.
Freezing a contract is separate from closing its objects:

- **Closed object:** undeclared fields are rejected. Declare supported metadata
  deliberately; closure also needs an explicit rule for nested objects.
- **Open object:** extra fields may be accepted according to the definition's
  extension policy. Preserve them when forwarding/hashing. Acceptance does not
  authorize an old reader to execute semantics it does not understand.
- **Frozen definition:** immutable for that revision, whether open or closed. A
  sender cannot relax it by adding a self-declared `$frozen` or `$locked` flag.

JSON Schema expresses object closure through `additionalProperties`; in Zod choose
strict or loose objects deliberately. Default `z.object` parsing can strip unknown
fields; that is neither strict rejection nor faithful preservation of an open
payload. Verify hashes over the original representation before any projection.

An open definition can already permit additional, ignorable data without a new
revision. Changing the published definition or assigning new operational meaning
is a contract revision. Never change units, defaults, or effects behind an existing
field name: use explicit stable names such as `dollarCost` and `centsCost`.

Assess compatibility in both directions, including stored history:

| Change | New reader accepts old payloads? | Old reader accepts new payloads? |
|---|---|---|
| Add optional field | Usually; check formerly allowed unknown values | Only if its extension policy and semantics permit it |
| Add required field | No, when old data lacks it | Depends on old closure and semantics |
| Widen a field's accepted type | Yes, for that field | No for newly permitted values |
| Narrow a field's accepted type | No for removed values | Yes, for that field |
| Remove a field or change its meaning | Depends on requiredness/closure; meaning must stay explicit | Depends on requiredness/closure; may break behavior |

Use a major revision for a change that breaks a promised reader/writer contract;
use a minor revision for compatible additions; use patch revisions for compatible
clarifications/corrections. Optionality, open objects, or a type widening alone do
not prove compatibility. Retain exact historical definitions, and document which
revisions each receiver accepts. Never try older validators until one accepts
malformed or unsupported data.

### Typed validation and metadata

Validate **identifier, supported effective version, and shape** together:

```ts
import * as z from 'zod/mini'
import { zodIsFactory } from '@ariestools/sdk'
import {
  asSchema, encodePayloadVersion, PayloadZodLooseOfSchema,
} from '@xyo-network/sdk-protocol'

const ReadingSchema = asSchema('com.example.sensor.reading', true)
const ReadingVersion = encodePayloadVersion({ major: 1, minor: 2, patch: 3 })
const ReadingPayloadZod = z.extend(
  PayloadZodLooseOfSchema(ReadingSchema, ReadingVersion),
  { temperatureCelsius: z.number() },
)
const isReadingPayload = zodIsFactory(ReadingPayloadZod)
```

`PayloadZodOfSchema`, `PayloadZodStrictOfSchema`, and `PayloadZodLooseOfSchema` take
an optional second argument containing one supported version or an array; the
default is only `1.0.0`, not every version. A version list is appropriate only when
the same shape and semantics cover every listed revision. Otherwise dispatch
explicitly to separate definitions. Generic payload validation checks version
syntax, not a product's supported-version policy.

`isPayloadOfSchemaType` also checks the version policy but remains a tag/version
check, not a field-shape validator. Use a full typed guard at trust boundaries.
`PayloadVersionZodForVersions` and `isPayloadVersionSupported` support custom
validators without making an unknown version valid.

Do not call `omitMeta` or `omitClientMeta` before selecting/validating a version:
they remove `$version`. A metadata-stripped projection is not evidence that the
original payload omitted the field. Verify the original hash first, retain the
original revision, and remove only explicitly handled metadata when a closed
body parser requires it. Parser defaults or stripping must not alter the bytes
whose identity is being verified.

### Root hashes are the application default

**Use `PayloadBuilder.hash(payload)` for virtually all application identities,
references, commitments, cache keys, and deduplication.** It is the root hash
(`_hash`), includes client metadata such as `$version` and `$sources`, and excludes
storage metadata (`_*`). Use it for new `$sources` references and for commitments
that must bind a particular payload representation. Do not replace it with
`JSON.stringify` plus a native digest.

`PayloadBuilder.dataHash(payload)` (`_dataHash`) excludes **all** metadata, including
`$version`, `$sources`, and `$signatures`. It deliberately groups representations
with the same data. Use it only when a specific protocol requires that projection;
it does not bind a payload's version or provenance. Never assume `_hash` and
`_dataHash` are interchangeable just because they match on a metadata-free example.

A BoundWitness signs its own data hash, excluding its `$signatures` to avoid a
circular signature dependency. Normally attached child payloads are committed
through root hashes in `payload_hashes`, so the parent signature can authenticate
the child's `$version`. A reference containing only a data hash cannot do that.
A standalone BoundWitness's **own** `$version` is not authenticated by its own
signatures; only a verified outer root-hash commitment or trusted protocol context
can supply that authority. An unbound version label MUST NOT choose weaker
signature, authorization, closure, or consensus rules.

Cache definitions by `(schema, effectiveVersion)` and validation results by the
root hash plus the applicable validation/authorization policy. A data-hash-only
lookup may collect variants, but must not substitute one versioned representation
for another. Existing SDK/storage/protocol contracts that use data hashes are not
automatically migrated by this guidance.

### Schema-definition payloads and rollout scope

`network.xyo.schema` has an existing ordinary `version` field using the **same
radix-1,000 encoding**. It describes the contract identified by `definition.$id`.
Its outer `$version` instead describes the structure of the `network.xyo.schema`
envelope itself. These are different levels; do not rename, copy, or reinterpret
one as the other. Omitted described-contract versions use the same `1.0.0` baseline
when applying this policy; retain the original serialized definition.

`SchemaCache` validates the complete `network.xyo.schema` payload before compiling
an authoritative or legacy alias definition. This includes the supported outer
`$version` and numeric format of the described contract's ordinary `version`.
Validation preserves the original payload without inserting an implicit version.

The existing `SchemaCache` and domain publication map remain name-keyed; this
implementation does not make them select exact `(schema, version)` definitions.
They do not supply an immutable multi-version registry or consensus-wide
compatibility proof. Resolve/pin exact definitions and retain
historical revisions in application policy; version-aware authority discovery is
separate follow-up work. Likewise, publishing these helpers does not deploy them
to existing chains or make legacy Statement Graph, Event Kit, ordinal, or exchange
data-hash contracts root-hash contracts. Preserve shipped identifiers and hash
algorithms until an explicit coordinated migration is implemented and verified.

## Cloudflare workerd secp256k1

The `elliptic/workerd` subpath supplies the SDK's secp256k1 operations from a
statically imported `WebAssembly.Module`, as required by Cloudflare Workers:

```ts
import { initializeEllipticWorkerd } from '@xyo-network/sdk-protocol-core/elliptic/workerd'

const cryptoReady = initializeEllipticWorkerd()
```

Await `cryptoReady` before using `Account` signing or verification APIs. The
backend is installed once into the shared `Elliptic` singleton and cannot be
replaced after initialization. The packaged libauth Wasm artifact is SHA-256
pinned and includes its upstream MIT license.

## Install

Using npm:

```sh
npm install @xyo-network/sdk-protocol
```

Using yarn:

```sh
yarn add @xyo-network/sdk-protocol
```

Using pnpm:

```sh
pnpm add @xyo-network/sdk-protocol
```

Using bun:

```sh
bun add @xyo-network/sdk-protocol
```


## License

See the [LICENSE](LICENSE) file for license rights and limitations (LGPL-3.0-only).

## Credits

[Made with 🔥 and ❄️ by XYO Foundation](https://xyo.network)

[npm-badge]: https://img.shields.io/npm/v/@xyo-network/sdk-protocol.svg
[npm-link]: https://www.npmjs.com/package/@xyo-network/sdk-protocol
[license-badge]: https://img.shields.io/npm/l/@xyo-network/sdk-protocol.svg
[license-link]: https://github.com/XYOracleNetwork/sdk-protocol-js/blob/main/LICENSE
[logo]: https://cdn.xy.company/img/brand/XYO_full_colored.png

---
_Source: https://npm.io/package/@xyo-network/sdk-protocol-core · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
