Declaraciones públicas de zig/src/envelope.zig (spire-zig (SDK consumido)).
apps/docs/generated/zig/spire.jsonPágina generada desde
spire@spire-0.2.0-XvnrRek1BgCX4Bh8miuITCQgkn0FqeQrYYE3goFfDcQd (zig/src/root.zig). No se edita a mano:bun run docs:genla regenera ybun run docs:checkfalla si difiere.
MessageEnvelope v2 — el sobre firmado de spire (dec-0119 §5), en su
codificación binaria canónica. Especificación normativa:
spec/ENVELOPE_V2.md; TS (@spire/bus) y Zig deben dar el mismo veredicto
y el mismo valor decodificado sobre cualquier entrada (vectores en
vectors/envelope-v2.json, fuzz diferencial en packages/bus/test).
Cuerpo (big endian). La cabecera es la región firmada:
off len campo
0 1 version = 2
1 1 kind 1 cmd · 2 qry · 3 evt · 4 reply
2 1 status 0 salvo en reply (ver Status)
3 1 flags b0 actor · b1 causation · b2 traceparent · b3 deadline
4 16 id UUIDv7
20 16 correlation_id
36 8 ts_ms reloj de pared del emisor
44 16 nonce aleatorio, 128 bits
60 2 contract_version >= 1
62 8 kid SHA-256(clave pública del emisor)[0..8]
70 32 payload_sha256
102 4 payload_len
106 1+n subject n en 1..128
1+n source n en 1..64
[16] causation_id si b1
[8] deadline_ms si b3
[55] traceparent si b2 (W3C, minúsculas)
[2+n] actor si b0; n en 1..8192, ASCII visible (JWT)
─── fin de la cabecera ───
64 firma Ed25519 sobre "spire/env/v2\0" ‖ cabecera
n payload n = payload_len
La decodificación sigue el orden de los campos y el primer fallo decide el error (orden normativo, lo comparte TS). Nada reserva memoria: los campos variables son préstamos del cuerpo recibido.
envelope.VERSIONconst · línea 42
pub const VERSION: u8 = 2Sin ///.
envelope.SIGNING_DOMAINconst · línea 43
pub const SIGNING_DOMAIN = "spire/env/v2\x00"Sin ///.
envelope.SIGNATURE_LENconst · línea 44
pub const SIGNATURE_LEN: usize = Ed25519.Signature.encoded_lengthSin ///.
envelope.FIXED_HEADER_LENconst · línea 45
pub const FIXED_HEADER_LEN: usize = 106Sin ///.
envelope.MAX_SUBJECT_LENconst · línea 46
pub const MAX_SUBJECT_LEN: usize = 128Sin ///.
envelope.MAX_SOURCE_LENconst · línea 47
pub const MAX_SOURCE_LEN: usize = 64Sin ///.
envelope.MAX_ACTOR_LENconst · línea 48
pub const MAX_ACTOR_LEN: usize = 8192Sin ///.
envelope.TRACEPARENT_LENconst · línea 49
pub const TRACEPARENT_LEN: usize = 55Sin ///.
envelope.MAX_HEADER_LENconst · línea 51
pub const MAX_HEADER_LEN: usize = FIXED_HEADER_LEN + 1 + MAX_SUBJECT_LEN + 1 + MAX_SOURCE_LEN + 16 + 8 + TRACEPARENT_LEN + 2 + MAX_ACTOR_LENCabecera más larga posible (todos los opcionales al máximo).
envelope.HARD_MAX_PAYLOADconst · línea 54
pub const HARD_MAX_PAYLOAD: u32 = 1 << 20Techo absoluto del payload (dec-0119 §7). El límite efectivo lo pone el
llamador (Limits.max_payload), normalmente el del contrato.
envelope.Idconst · línea 56
pub const Id = [16]u8Sin ///.
envelope.Nonceconst · línea 57
pub const Nonce = [16]u8Sin ///.
envelope.Kidconst · línea 58
pub const Kid = [8]u8Sin ///.
envelope.Digestconst · línea 59
pub const Digest = [32]u8Sin ///.
envelope.Kindtype · línea 61
pub const Kind = enumSin ///.
envelope.Kind.fromBytefn · línea 67
pub fn fromByte(b: u8) ?KindSin ///.
envelope.Statustype · línea 74
pub const Status = enumResultado de una petición, sólo en reply. Los nombres son el código de
error que ve el cliente (TS los expone igual).
envelope.Status.fromBytefn · línea 86
pub fn fromByte(b: u8) ?StatusSin ///.
envelope.Flagstype · línea 91
pub const Flags = structSin ///.
envelope.Flags.actorconst · línea 92
pub const actor: u8 = 1 << 0Sin ///.
envelope.Flags.causationconst · línea 93
pub const causation: u8 = 1 << 1Sin ///.
envelope.Flags.traceparentconst · línea 94
pub const traceparent: u8 = 1 << 2Sin ///.
envelope.Flags.deadlineconst · línea 95
pub const deadline: u8 = 1 << 3Sin ///.
envelope.Flags.reservedconst · línea 96
pub const reserved: u8 = 0xf0Sin ///.
envelope.Headertype · línea 100
pub const Header = structCampos del sobre (sin firma ni payload). Las rebanadas son préstamos.
envelope.Header.encodedLenfn · línea 127
pub fn encodedLen(h: *const Header) usizeSin ///.
envelope.Decodedtype · línea 137
pub const Decoded = structSin ///.
envelope.DecodeErrorconst · línea 147
pub const DecodeError = error{ Truncated, UnsupportedVersion, BadKind, BadStatus, BadFlags, BadId, BadContractVersion, PayloadTooLarge, BadSubject, BadSource, BadTraceparent, BadActor, TrailingBytes, } …Errores de estructura. El nombre es el código de conformidad (TS usa el mismo string).
envelope.VerifyErrorconst · línea 163
pub const VerifyError = error{ BadSignature, PayloadDigestMismatch }Sin ///.
envelope.Limitstype · línea 165
pub const Limits = structSin ///.
envelope.validSubjectfn · línea 173
pub fn validSubject(s: []const u8) boolSubject: tokens [A-Za-z0-9_-]+ separados por ., sin comodines NATS
(*, >), sin vacíos ni espacios.
envelope.validSourcefn · línea 190
pub fn validSource(s: []const u8) boolIdentidad de servicio: [a-z][a-z0-9-]*, 1..64.
envelope.validTraceparentfn · línea 210
pub fn validTraceparent(s: []const u8) boolW3C traceparent versión 00: 00-<32 hex>-<16 hex>-<2 hex>, trace/span no nulos.
envelope.validActorfn · línea 220
pub fn validActor(s: []const u8) boolActor: token compacto (JWT) en ASCII visible.
envelope.validUuidV7fn · línea 227
pub fn validUuidV7(id: *const Id) boolUUIDv7: nibble de versión 7 y variante RFC 9562 (10).
envelope.decodefn · línea 243
pub fn decode(body: []const u8, limits: Limits) DecodeError!DecodedDecodifica un cuerpo de frame envelope. Sólo estructura: la firma y el
digest los comprueba verify, y el reloj/replay/policy el router.
envelope.verifyfn · línea 309
pub fn verify(d: *const Decoded, public_key: Ed25519.PublicKey) VerifyError!voidFirma estricta de la cabecera y, después, el digest del payload.
envelope.EncodeErrorconst · línea 322
pub const EncodeError = error{ NoSpaceLeft, InvalidField, PayloadTooLarge }Sin ///.
envelope.Signertype · línea 325
pub const Signer = structFirmante: par de claves Ed25519 + su kid derivado.
envelope.Signer.initfn · línea 329
pub fn init(key_pair: Ed25519.KeyPair) SignerSin ///.
envelope.Signer.SeedErrorconst · línea 333
pub const SeedError = error{ InvalidSeedEncoding, WeakKey }Sin ///.
envelope.Signer.fromSeedBase64fn · línea 338
pub fn fromSeedBase64(text: []const u8) SeedError!SignerFirmante desde la semilla Ed25519 de 32 bytes en base64url sin relleno
(43 caracteres, forma canónica): el mismo formato que la clave pública
del keyring y que signerFromSeed de @spire/bus.
envelope.kidOffn · línea 351
pub fn kidOf(public_key: [32]u8) KidSin ///.
envelope.sealedLenfn · línea 358
pub fn sealedLen(h: *const Header, payload_len: usize) usizeLongitud total del cuerpo para una cabecera y un payload dados.
envelope.sealfn · línea 366
pub fn seal(out: []u8, h_in: Header, payload: []const u8, signer: *const Signer) EncodeError![]u8Codifica y firma. Rellena en h el kid, el digest y la longitud del
payload (lo que haya puesto el llamador se ignora). Valida cada campo con
las mismas gramáticas que decode: spire nunca emite un sobre que él
mismo rechazaría.
envelope.newIdfn · línea 432
pub fn newId(ts_ms: u64) IdUUIDv7 (RFC 9562): 48 bits de milisegundos + 74 bits aleatorios.
envelope.newNoncefn · línea 446
pub fn newNonce() NonceSin ///.
envelope.nowMsfn · línea 452
pub fn nowMs() u64Sin ///.
envelope.testingtype · línea 461
pub const testing = structSin ///.
envelope.testing.signerfn · línea 462
pub fn signer(seed_byte: u8) SignerSin ///.
envelope.testing.headerfn · línea 468
pub fn header(subject: []const u8, source: []const u8) HeaderSin ///.
trace.TRACEPARENT_LENconst · línea 49
pub const TRACEPARENT_LEN: usize = 55Sin ///.