SIAX Technology (sax3l)

@siax/event-client (0.1.0)

Published 2026-09-16 09:35:08 +00:00 by admin

Installation

@siax:registry=https://git.cloud.siax.io/api/packages/sax3l/npm/
npm install @siax/event-client@0.1.0
"@siax/event-client": "0.1.0"

About this package

@siax/event-client

P012 (Network/DB/Event/Idempotency/SLO Standards, new P000-P049 masterplan): createEventClient() — validates a candidate event against @siax/schemas' siax.event schema and, only if valid, POSTs it to AUD0 (POST /v1/aud0/events). Zero external dependencies — @siax/schemas is a workspace-internal link only. Node ESM (.mjs), Node ≥ 20 — same convention as @siax/schemas, @siax/secret-resolver and @siax/write-guard.

Why this package exists

P012 recon (2026-09) found schema/siax.event.schema.json in exactly the same state P002 found siax.secret-reference in: a real, well-formed, unit-tested JSON Schema with zero runtime consumers anywhere in the estate. grep -rl "@siax/schemas" across every local clone under ~/siax-platforms-work/ returned hits only inside siax-standard's own packages — no aud0, act0, h0st, cl0ud, n0d, inf0, st0re, 0pt, b00k, vehiq-infra, … import it.

It was worse than a plain stub, though: a real, ~20-producer wire contract already existed, just not captured by this schema. AUD0's own src/schemas/event.ts (zod, backing its real POST /v1/aud0/events Fastify route) defines the actual shape: event_type, tenant_id, project_id?, actor_id?, app_id, capability_id, resource_type, resource_id, risk_level, source?, payload?, created_at?, event_id?, plus the P0 context fields added later (sql/032_audit_event_context.sql): occurred_at, correlation_id, causation_id, trace_id, purpose, policy_decision, input_refs, output_refs, result, idempotency_key. act0, h0st, doc0, cal0, n0d, 0pt, id0, n0tify, c0nf0rm, inf0, siax-templates, and more each hand-roll a local copy of this shape in their own aud0-client.ts — ACT0's own comment says it best: "Kept as a separate copy here … there is no automated sync." Even AUD0's own JSON Schema mirror (src/schemas/event.schema.json) had drifted from its own zod source of truth, missing every one of the P0 context fields.

schema/siax.event.schema.json has been reconciled field-for-field to that real contract (snake_case wire shape) instead of the old P003 camelCase shape (id/type/tenantId/actor/occurredAt/riskLevel) nothing ever emitted. This package is the first thing in the estate that actually validates an event against that reconciled schema before sending it anywhere.

The one behavior change from a hand-rolled client

emit(event) validates BEFORE doing anything else. An invalid event throws EventValidationError and the network call never happens — fail-closed, the same discipline @siax/secret-resolver and @siax/write-guard already apply to their own side effects.

Reference consumer: @siax/write-guard

packages/write-guard/src/aud0-client.mjs used to BE a hand-rolled AUD0 client (deliberately reimplemented rather than imported, because siax.event was a stub at the time — see that file's git history). Now that the schema is real, write-guard's createAud0Client() delegates to this package — same public API (.ingest(event), same error class names, re-exported not reimplemented), but every event write-guard sends (including privileged-override.mjs's real, production-code-path audit events for P000-E's override flow) is now validated against siax.event first. This is the reference-service wiring an unconsumed schema does not get for free — see packages/write-guard/README.md and packages/write-guard/test/aud0-client.test.mjs's new Aud0EventValidationError test for the proof.

Core API

import { createEventClient, EventValidationError } from '@siax/event-client';

const client = createEventClient({
  projectId: undefined, // not applicable here — see baseUrl/token below
  token: process.env.EVENT_CLIENT_AUD0_TOKEN,
});

try {
  const stored = await client.emit({
    event_type: 'capability.invoked',
    tenant_id: 't_vehiq',
    app_id: 'my-service',
    capability_id: 'n0d.run_job',
    resource_type: 'job',
    resource_id: 'job-42',
    risk_level: 'L1',
  });
  console.log(stored.event_id); // AUD0-assigned, if omitted on input
} catch (err) {
  if (err instanceof EventValidationError) {
    // the event never left this process — err.errors names exactly what's wrong
  }
  throw err;
}

Configuration (env vars)

Env var Purpose
EVENT_CLIENT_AUD0_API_URL (falls back to WRITE_GUARD_AUD0_API_URL for write-guard compat) AUD0 base URL. Defaults to https://api.aud0.siax.io/v1/aud0.
EVENT_CLIENT_AUD0_TOKEN (falls back to WRITE_GUARD_AUD0_TOKEN) Bearer token for the AUD0 API.

Honest status — what is real vs. not yet verified

Same convention as packages/secret-resolver/README.md and the old aud0-client.mjs's "HONEST STATUS" note: whether https://api.aud0.siax.io/v1/aud0 is actually deployed and reachable was not verified from this repo/pass. Every test in test/*.test.mjs runs against an injected fake fetch — zero real network calls. A follow-up pass must run one real request against the actual deployed AUD0 instance before this is trusted in a real boot path.

What "reference service uses the library" means here, precisely

write-guard consuming this package (within siax-standard) is real, tested, end-to-end wiring — but it is not the same claim as "AUD0 or another estate repo imports @siax/event-client in production". No repo outside siax-standard does yet (confirmed: zero hits for @siax/event-client anywhere else under ~/siax-platforms-work/, same as @siax/secret-resolver's status after P002). Closing that estate-wide gap — migrating ACT0's or AUD0's own hand-rolled client to this package, or at minimum pointing their event.schema.json at this reconciled shape — is a clear, actionable follow-up this pass flags rather than silently claims done.

Dependencies

Dependencies

ID Version
@siax/schemas workspace:*
Details
npm
2026-09-16 09:35:08 +00:00
0
UNLICENSED
latest
5.8 KiB
Assets (1)
Versions (1) View all
0.1.0 2026-09-16