Skip to content

Protocol reference

The protocol defines the serialized table response. Use the Laravel builders for application code; use these schemas and the decoder when building validation or integration tooling.

The development protocol is draft 0.3.0 with checksum d44c495114d1c4a3add438136683eca7c994662e8dc472cecd6dd8dc60081a39.

Number presentation and table-local problems require a matching contract in the Laravel producer and frontend consumers. Repository development artifacts do not establish feature support in already-published package versions.

Declare @inertiax/table-protocol as a direct dependency if your source imports it. It owns the Table contract. @inertiax/protocol supplies common JSON types and validation primitives; it has no Table decoder or Table schema exports.

The installed @inertiax/table-protocol package exposes the maintained contract without repository access:

Package subpath Purpose
@inertiax/table-protocol/schemas/envelope.schema.json Envelope entry schema
@inertiax/table-protocol/schemas/table.schema.json Complete Table component schema
@inertiax/table-protocol/schemas/common.schema.json Table definitions and references to common identifiers
@inertiax/table-protocol/schemas/foundation.schema.json Pinned common JSON definitions included in this Table artifact
@inertiax/table-protocol/contract.json Table contract identity and common-schema provenance
@inertiax/table-protocol/fixtures/manifest.json Accepted and rejected fixture inventory
@inertiax/table-protocol/fixtures/valid/minimal.json Smallest complete valid Table example
@inertiax/table-protocol/fixtures/valid/custom-type.json Namespaced custom leaf example
@inertiax/table-protocol/VERSION and @inertiax/table-protocol/CHECKSUM Installed artifact identity

Use these package subpaths in validators, tests, or tooling. Application code normally needs only the root package exports.

Every payload contains a protocol version and a component:

{
"protocolVersion": "0.3.0",
"component": {
"type": "table",
"id": "users"
}
}

The abbreviated component above is explanatory, not a valid complete Table. Use the shipped fixtures/valid/minimal.json subpath for executable minimal input and the shipped schemas for the complete contract.

A successful Table component carries:

  • a stable type: "table" and instance id;
  • Column and Filter definitions;
  • capabilities for pagination, sorting, selection, filter mode, and refresh;
  • server state for pagination, ordered sorting, recursive filters, and search;
  • result totals and last-page information;
  • a rowKey and row-oriented data.rows.

Columns contain definitions only. Each row cell is a payload with value plus optional icon, variant, and meta. Capabilities constrain which state transitions are valid.

Selection and column visibility are local state, not server query state.

data.rowKey must name a declared Column even when rows is empty. Each row must contain that cell, and its value must be a string or JavaScript-safe integer. Laravel transports larger integer identities as exact decimal strings so JavaScript does not silently change them.

A filter is a field. Its clauses are the comparisons offered for it, and each clause’s input describes the value it takes, so a renderer draws and checks a value from the clause alone.

Filter field Required Meaning
key Yes The filter’s ID in state, URLs, and links
label No Shown in the field picker and chips; renderers fall back to key
clauses Yes, at least one The clauses offered for the field, in order, with unique keys
defaultClause Yes The key of one of clauses, picked when the field is added
pinned No, default false Shown as a pinned control unless the page gives its own list
meta No Application data
Clause field Required Meaning
key Yes A built-in clause key or a vendor/name identifier
label No Shown for the comparison
input No The value the clause takes; absent when it takes none
meta No Application data
Input field Required Meaning
valueType Yes text, number, boolean, select, date, datetime, time, or vendor/name
mode Yes single, multiple, or range
options Yes for select; not allowed otherwise { value, label } entries whose scalar values are unique
optionsTruncated No; select only true when the producer stopped listing options at its limit

Every value type allows single. Only select allows multiple, and range is allowed for number, date, datetime, time, and custom value types.

{
"key": "created_at",
"label": "Created",
"defaultClause": "between",
"pinned": false,
"clauses": [
{ "key": "between", "label": "Between", "input": { "valueType": "date", "mode": "range" } },
{ "key": "acme/last-days", "label": "In the last … days", "input": { "valueType": "number", "mode": "single" } },
{ "key": "is-not-set", "label": "Is empty" }
]
}

Each condition { key, clause, value } in the filter state carries a value that matches its clause’s input:

  • no input: null;
  • single: one value of the value type;
  • multiple: a non-empty list of values of the value type;
  • range: [from, to], both of the value type.

text, date, datetime, and time values are strings, number values finite numbers, boolean values Booleans, and select values strings, numbers, or Booleans. A custom value type accepts any JSON value except null. null is never a value.

TableEnvelope is the union of successful Envelope and ProblemEnvelope. A problem component contains only type, id, and problem:

{
"type": "table",
"id": "orders",
"problem": {
"issues": [{ "field": "page", "code": "page-unavailable" }],
"resettable": true
}
}

Each issue names one unique field: page, pageSize, sorting, filters, or search. Codes are invalid-url-state or page-unavailable (page only). resettable records whether the producer permits a reset; the integration must also support it. Problem components have no rows, result metadata, or successful state. Use isProblemEnvelope() to narrow a decoded envelope before accessing result fields. The shipped fixtures/valid/table-problem.json is a complete example.

Consumers decode unknown input before creating a runtime session. Producers validate the complete envelope before returning it. A malformed known field reports schema-path context; an unsupported protocol version fails before a transformation or render.

Use decodeTableEnvelope when an application or integration receives unknown protocol data directly:

import { decodeTableEnvelope } from '@inertiax/table-protocol';
export function decodeInput(input: unknown) {
return decodeTableEnvelope(input);
}

decodeTableEnvelope returns a deeply immutable clone. It throws ProtocolDecodeError with:

  • INERTIAX_PROTOCOL_VERSION_UNSUPPORTED when the received protocol version is not supported;
  • INERTIAX_PROTOCOL_DECODE_FAILED for invalid JSON-domain values, malformed known fields, or invalid Table semantics.

The error includes path, structured diagnostics, the supported version, and available received version/component context. Catch it only when the application can add useful context or recovery; do not continue with the rejected input.

  • Protocol versions are independent from npm and Composer package versions. A decoder-only patch can preserve the same wire contract and Laravel snapshot.
  • Unsupported versions fail before transformation or rendering.
  • Known malformed fields fail with schema-path diagnostics.
  • Custom column types, value types, and clause keys must be namespaced as vendor/name.
  • Unknown custom leaf identifiers remain valid protocol data, but the React renderer needs a matching registration or uses its configured diagnosed fallback.

A package patch or minor release does not imply a protocol change. Conversely, protocol evolution may require coordinated compatible package releases while their version numbers remain different.

Use the exported TypeScript declarations and runtime decoder; do not copy protocol types into application code. Validate unknown input before creating a session. See Direct envelope for custom integrations and their ownership contracts.

View Markdown