Full Spanish -> English translation of sium/README.md (862 lines; faithful).
Code blocks, schema examples, issue codes and `#?sium.errors.*` idlangrefs kept
verbatim. Also fixed a stale ref: `/test/sium` -> `/active/docs/sium`. Carries
the A1 additions (cssLength/cssValue in Included Refines).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sium es la capa de contratos, validacion e introspeccion de Active.
Sium is Active's contract, validation and introspection layer.
Su objetivo no es competir con Zod, Valibot o ArkType como libreria generalista. Sium existe para que Active tenga un contrato nativo entre datos, validacion, errores traducibles, tipos de dominio y UI auto-generada.
Its goal is not to compete with Zod, Valibot or ArkType as a general-purpose library. Sium exists so Active has a native contract between data, validation, translatable errors, domain types and auto-generated UI.
Este archivo es la unica documentacion Markdown del modulo. Si cambia el comportamiento de Sium, actualiza este README en lugar de crear documentos paralelos.
This file is the module's only Markdown documentation. If Sium's behavior changes, update this README instead of creating parallel documents.
## Sium no forma parte de active-app core
## Sium is not part of active-app core
`createActiveApp(...)` deliberadamente no construye Sium. La validacion es
**page-scoped**: solo las paginas con formularios la necesitan. Cargar todo
el core de schemas/types/issues en paginas sin formularios serìa coste
innecesario.
`createActiveApp(...)` deliberately does not build Sium. Validation is
**page-scoped**: only pages with forms need it. Loading the whole
schemas/types/issues core on pages without forms would be unnecessary cost.
El patron estandar es una linea al inicio del modulo de la pagina:
The standard pattern is a single line at the top of the page module:
Asi cada formulario obtiene un engine afinado a sus necesidades (logger
category, contexto de validacion, etc.) y comparte la traduccion de issues +
el bus de logs con la app.
This way each form gets an engine tuned to its needs (logger category,
validation context, etc.) and shares the issue translation + the log bus with
the app.
## Estado
## Status
Core, tipos de dominio, lenguajes, Standard Schema e introspeccion estan activos.
Core, domain types, languages, Standard Schema and introspection are active.
Sium no tiene adapter Svelte propio, por diseno: la integracion con UI es agnostica al validador. Los formularios (`createForm` / `Form.Provider`) consumen cualquier schema via `~standard`, `Form.AutoFields` auto-renderiza via la introspeccion `~sium`, y langs/logger se inyectan por `createEngineSium({ langs, logger })`. El core sigue siendo TypeScript puro.
Sium has no Svelte adapter of its own, by design: the UI integration is validator-agnostic. Forms (`createForm` / `Form.Provider`) consume any schema via `~standard`, `Form.AutoFields` auto-renders via the `~sium` introspection, and langs/logger are injected through `createEngineSium({ langs, logger })`. The core stays pure TypeScript.
## Novedades 2.0
## What's New in 2.0
Ampliacion alineada a lo que el ecosistema Active necesita (formularios, storage, http). NO busca paridad con Zod/Valibot.
An extension aligned with what the Active ecosystem needs (forms, storage, http). It does NOT aim for parity with Zod/Valibot.
- **Refines de formato (string):** `uuid()`, `slug()`, `datetime()` (ISO 8601), `ipv4()`.
- **Coercion:**`coerceNumber()`, `coerceBoolean()`, `coerceString()` — hermanos generales de `coerceDate()` para entradas sueltas (inputs HTML, query strings).
- **Standard Schema sincrono:** `schema['~standard'].validate(x)` resuelve de forma SINCRONA cuando el schema no tiene pasos async (devuelve el `Result` directo en vez de `Promise`). SS v1 permite `Result | Promise<Result>`; esto elimina el branch async + el workaround `untrack` en los consumidores (`form-core`, `storage`) para schemas sincronos.
- **Transforms de string:** `trim()`, `toLowerCase()`, `toUpperCase()` para normalizar formularios.
- **Combinadores `tuple()` y `record()`:** tupla heterogenea de longitud fija + diccionario de claves arbitrarias. Amplian el vocabulario `SchemaKind` (`'tuple'`/`'record'`); `Form.AutoFields` los degrada con un aviso "not supported yet".
- **Utilidades de object:** `pick` / `omit` / `partial` / `extend` / `merge` — derivan un `object()` reusando los campos del original, con tipos precisos via `Pick`/`Omit`/`Partial`.
- **API depurada:** `dateValue()` / `timeValue()` ya no aceptan `opts` (eran ignorados). Para validar granularidad/calendario, compon un `refine` sobre el valor.
- **Coercion:**`coerceNumber()`, `coerceBoolean()`, `coerceString()` — general siblings of `coerceDate()` for loose inputs (HTML inputs, query strings).
- **Synchronous Standard Schema:** `schema['~standard'].validate(x)` resolves SYNCHRONOUSLY when the schema has no async steps (it returns the `Result` directly instead of a `Promise`). SS v1 allows `Result | Promise<Result>`; this removes the async branch + the `untrack` workaround in consumers (`form-core`, `storage`) for synchronous schemas.
- **String transforms:** `trim()`, `toLowerCase()`, `toUpperCase()` to normalize forms.
- **`tuple()` and `record()` combinators:** a fixed-length heterogeneous tuple + a dictionary of arbitrary keys. They extend the `SchemaKind` vocabulary (`'tuple'`/`'record'`); `Form.AutoFields` degrades them with a "not supported yet" notice.
- **Object utilities:** `pick` / `omit` / `partial` / `extend` / `merge` — derive an `object()` reusing the original's fields, with precise types via `Pick`/`Omit`/`Partial`.
- **Cleaned-up API:** `dateValue()` / `timeValue()` no longer accept `opts` (they were ignored). To validate granularity/calendar, compose a `refine` over the value.
- 8 new issue codes (`uuid`, `slug`, `datetime`, `ipv4`, `finite`, `positive`, `nonnegative`, `multiple_of`) with es/en translation.
## Importaciones
Sium expone una fachada publica y barrels tematicos.
Sium exposes a public facade and thematic barrels.
```ts
import { createEngineSium } from '$sium';
@ -55,7 +54,7 @@ import { createEngineSium } from '$sium';
const sium = createEngineSium();
```
Si quieres traducciones activas, inyecta el engine de traducciones:
If you want active translations, inject the translation engine:
```ts
import { createEngineSium, siumLangs } from '$sium';
`decode` valida y transforma. Si falla, lanza`SiumValidationError`.
`decode` validates and transforms. If it fails, it throws`SiumValidationError`.
`validate`envuelve `decode` y devuelve `{ ok: true, value }` o`{ ok: false, issues }`.
`validate`wraps `decode` and returns `{ ok: true, value }` or`{ ok: false, issues }`.
`createEngineSium({ logger }).validate(schema, input)`hace lo mismo y, si falla, emite un diagnóstico `SIUM_DIAGNOSTIC_EVENTS.VALIDATION_FAILED` a nivel `debug` (categoría `SIUM_MODULE`), con `issueCount` e`issues`.
`createEngineSium({ logger }).validate(schema, input)`does the same and, on failure, emits a `SIUM_DIAGNOSTIC_EVENTS.VALIDATION_FAILED` diagnostic at `debug` level (category `SIUM_MODULE`), with `issueCount` and`issues`.
`encode` invierte la salida hacia la forma de entrada. En transforms de una sola direccion actua como identidad para esa parte; usa `codec()` cuando necesites reversibilidad real.
`encode` inverts the output back toward the input shape. In one-way transforms it acts as identity for that part; use `codec()` when you need real reversibility.
`~standard`permite usar schemas Sium en cualquier consumidor de Standard Schema v1. Los schemas sincronos resuelven de forma sincrona (`validate` devuelve el `Result` directo); solo los que tienen pasos async devuelven`Promise`.
`~standard`lets you use Sium schemas in any Standard Schema v1 consumer. Synchronous schemas resolve synchronously (`validate` returns the `Result` directly); only those with async steps return a`Promise`.
`~sium` contiene metadata para UI, debug, docs y herramientas.
`~sium` contains metadata for UI, debug, docs and tooling.
## Por Que Existe
## Why It Exists
Sium cubre cuatro huecos que las librerias externas no resuelven de forma nativa dentro de Active.
Sium covers four gaps that external libraries do not solve natively within Active.
- Tipos de dominio: `ColorValue`, `DateValue`, `TimeValue` y sus segmentos ya existen en Active.
- UI metadata: `meta.widget`, `meta.channel`, labels y opciones viajan dentro del schema.
- `langs/` defines the `siumLangs` catalog and a minimal interpolation fallback.
- `engine-sium.ts` composes the public facade.
## Guia Rapida
## Quick Guide
### Usar La Fachada
### Using the Facade
```ts
import { createEngineSium } from '$sium';
@ -166,7 +165,7 @@ const result = await User.validate({
});
```
Con integracion:
With integration:
```ts
const s = createEngineSium({ langs, logger });
@ -179,18 +178,18 @@ s.resolveIssue({
});
```
Si `langs` existe, `resolveIssue()` delega en `EngineLangs`. Si no existe, usa el fallback local de `$sium/langs.resolve`.
If `langs` exists, `resolveIssue()` delegates to `EngineLangs`. If not, it uses the local `$sium/langs.resolve` fallback.
En desarrollo tambien puedes validar a traves del engine para obtener logs `debug` cuando hay issues:
In development you can also validate through the engine to get `debug` logs when there are issues:
```ts
const result = await s.validate(User, input);
const syncResult = s.validateSync(User, input);
```
Estos wrappers no cambian el resultado de `schema.validate()`. Solo emiten un log `debug` en la categoria exportada `LOGGER_CATEGORY` cuando la validacion falla y has inyectado`logger`.
These wrappers do not change the result of `schema.validate()`. They only emit a `debug` log in the exported `LOGGER_CATEGORY` category when validation fails and you have injected`logger`.
`tuple(...)` valida posicionalmente y exige la longitud exacta (issue `tuple_length`). `record(schema)` valida un objeto plano de claves arbitrarias cuyos valores comparten`schema`.
`tuple(...)` validates positionally and requires the exact length (issue `tuple_length`). `record(schema)` validates a flat object of arbitrary keys whose values share`schema`.
### Utilidades de object
### Object utilities
Derivan un nuevo `object()` a partir de otro, reusando sus campos:
They derive a new `object()` from another, reusing its fields:
merge(Base, Overrides); // combines two objects (the second wins)
```
Los tipos resultantes se derivan con `Pick` / `Omit` / `Partial` sobre el schema fuente, asi que siguen siendo precisos. Pasar un schema que no sea `object()` lanza`SiumObjectUtilError`.
The resulting types are derived with `Pick` / `Omit` / `Partial` over the source schema, so they stay precise. Passing a schema that is not an `object()` throws`SiumObjectUtilError`.
cssValue(); // richer CSS value — sibling of cssLength, code 'css_value'
// numericos
finite(); // rechaza Infinity / -Infinity / NaN
// numeric
finite(); // rejects Infinity / -Infinity / NaN
positive(); // > 0
nonnegative(); // >= 0
multipleOf(0.5);
```
`min`y `max` funcionan con numeros, strings y arrays. Emiten codigos distintos para valor numerico y longitud.
`min`and `max` work with numbers, strings and arrays. They emit distinct codes for numeric value and length.
`finite()` cubre el hueco de `number()`, que acepta `Infinity` por diseno. `positive()` no implica `finite()`: compon ambos para rechazar tambien`Infinity`.
`finite()` covers the gap in `number()`, which accepts `Infinity` by design. `positive()` does not imply `finite()`: compose both to also reject`Infinity`.
### Coercion
Para entradas sueltas (inputs HTML, query strings, FormData) que llegan como string y necesitan convertirse a un primitivo:
For loose inputs (HTML inputs, query strings, FormData) that arrive as a string and need converting to a primitive:
```ts
coerceNumber(); // string | number -> number (rechaza '' y NaN; Infinity pasa, compon con finite())
coerceNumber(); // string | number -> number (rejects '' and NaN; Infinity passes, compose with finite())
coerceBoolean(); // string | number | boolean -> boolean ('true/1/yes/on' vs 'false/0/no/off')
coerceString(); // string | number | boolean -> string
```
Son los hermanos generales de `coerceDate()`. Cada uno reporta el `kind` de SALIDA (`coerceNumber()` -> `number`), asi que `Form.AutoFields` renderiza el widget correcto.
They are the general siblings of `coerceDate()`. Each reports the OUTPUT `kind` (`coerceNumber()` -> `number`), so `Form.AutoFields` renders the right widget.
### Transforms De String
### String Transforms
Normalizadores que cambian el valor en decode (son `transform`, sin `encode`). Aplica despues de`string()`:
Normalizers that change the value on decode (they are `transform`, with no `encode`). Apply them after`string()`:
Sium no tiene adapter Svelte propio: la integracion es agnostica al validador y vive en la capa de formularios, no en sium.
Sium has no Svelte adapter of its own: the integration is validator-agnostic and lives in the forms layer, not in sium.
- El core es TypeScript puro y se usa sin Svelte.
- Los schemas exponen `~standard` (Standard Schema v1), asi que `createForm` / `Form.Provider` los validan reactivamente igual que a Zod/Valibot/ArkType. Los schemas sincronos resuelven de forma sincrona.
- `Form.AutoFields` auto-renderiza los campos leyendo la introspeccion `~sium` (`kind`, `wrappers`, `meta.widget`, …).
- Los issues idlangref (`#?sium.errors.*`) los traduce el servicio `langs` compartido, reactivo al locale activo.
- langs/logger se inyectan en sium por `createEngineSium({ langs, logger })`. sium es page-scoped: lo declara la app, no el runtime UIX.
- The core is pure TypeScript and is used without Svelte.
- Schemas expose `~standard` (Standard Schema v1), so `createForm` / `Form.Provider` validate them reactively just like Zod/Valibot/ArkType. Synchronous schemas resolve synchronously.
- `Form.AutoFields` auto-renders the fields by reading the `~sium` introspection (`kind`, `wrappers`, `meta.widget`, …).
- The idlangref issues (`#?sium.errors.*`) are translated by the shared `langs` service, reactive to the active locale.
- langs/logger are injected into sium via `createEngineSium({ langs, logger })`. sium is page-scoped: the app declares it, not the UIX runtime.