Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .changeset/6126-fields-unresolvable-imports.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
---
---

Docs only, publishes nothing: two `content/docs/fields` snippets referenced
identifiers the snippet program cannot resolve, so both pages were held out of
objectui#5867's batch 3 (objectui#6126). Neither is fixed by making the compiler
happy — each was narrowed to what ObjectUI actually owns.

`auto-number`'s Sequence Management block called `db.transaction` on a `db`
declared nowhere in the workspace and exported by nothing (TS2304, plus TS7006
on the `tx` that fell out of it). Declaring an ambient `db` would have had the
renderer's documentation mint a backend contract it does not own, so the block
is now the metadata the backend actually reads — a literal annotated with the
exported `AutoNumberFieldMetadata`, carrying `format` and `starting_number` —
and the transactional sketch is prose: one counter per object-and-field pair,
incremented in the same transaction that inserts the record. The page now also
says the thing it never said, which is that ObjectUI never allocates a value at
all and renders a placeholder until the saved record comes back.

`object`'s Backend Validation block opened `import Ajv from 'ajv'`, and `ajv` is
declared by no `package.json` in this repository and resolves from nowhere
(TS2307). Adding it as a dependency to satisfy a checker was refused, so the
block keeps the ObjectUI half — an `ObjectFieldMetadata` literal whose `schema`
is the JSON Schema a server validates against — and the Ajv call sequence, which
was Ajv's documentation rather than ObjectUI's, is a prose sentence naming it as
one option among any JSON Schema validator. The section now states the fact a
reader most needs: `ObjectField` checks JSON syntax only and never enforces
`schema`, so structural validation is the server's.

Both pages join the compile population with the batch's own classifier: the four
`plaintext`-fenced blocks whose first line starts with `import` or `interface`
are now `ts`. The gate's blocks-to-compile count rises from 206 to 210 — exactly
those four — with diagnostics at 0, no new `FRAGMENT_MARKER` declarations, and
the covered/ungated and declared-fragment sets unmoved.
45 changes: 26 additions & 19 deletions content/docs/fields/auto-number.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,7 +19,7 @@ The AutoNumber Field component displays auto-generated sequence numbers. This is

## Field Schema

```plaintext
```ts
interface AutoNumberFieldSchema {
type: 'auto_number';
name: string; // Field name/ID
Expand DownExpand Up@@ -104,27 +104,34 @@ generateAutoNumber('ORD-{YYYY}-{0000}', 42);

## Sequence Management

The backend maintains sequence counters:

```plaintext
interface SequenceCounter {
object: string; // Object name
field: string; // Field name
current_value: number; // Current sequence number
prefix?: string; // Optional prefix for partitioning
}

// Increment sequence atomically
const getNextSequence = async (object: string, field: string) => {
return await db.transaction(async (tx) => {
const counter = await tx.findOne('sequences', { object, field });
const nextValue = (counter?.current_value || 0) + 1;
await tx.upsert('sequences', { object, field }, { current_value: nextValue });
return nextValue;
});
Allocating the next number is the backend's job, not the renderer's. ObjectUI
never generates a value: `AutoNumberField` displays whatever the saved record
already carries, and renders a muted placeholder dash while the field is still
empty. What ObjectUI owns is the metadata the backend reads — where the
sequence starts, and how each value is formatted:

```ts
import type { AutoNumberFieldMetadata } from '@object-ui/types';

const orderNumber: AutoNumberFieldMetadata = {
type: 'auto_number',
name: 'order_number',
label: 'Order Number',
format: 'ORD-{YYYY}-{0000}',
starting_number: 1,
};
```

On the backend, keep one counter per object-and-field pair and increment it in
the same transaction that inserts the record, so two concurrent inserts cannot
read the same current value. Partition the counter (per year, per prefix) only
if the format resets — `'ORD-{YYYY}-{0000}'` needs one counter per year if the
sequence is meant to restart each January.

Because the number is assigned at insert time, it does not exist while the
record is still being drafted: a create form shows the field empty, and the
value appears once the saved record comes back.

## Use Cases

- **Order Management**: Order numbers, PO numbers
Expand Down
51 changes: 27 additions & 24 deletions content/docs/fields/object.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,7 +23,7 @@ The Object Field component provides a JSON editor for storing and editing struct

## Field Schema

```plaintext
```ts
interface ObjectFieldSchema {
type: 'object';
name: string; // Field name/ID
Expand DownExpand Up@@ -199,33 +199,36 @@ For typed object fields, you can define a schema in two formats:

## Backend Validation

Example backend validation:

```plaintext
import Ajv from 'ajv';
ObjectUI does not enforce `schema`. `ObjectField` checks JSON **syntax** only —
it accepts any value `JSON.parse` accepts, and simply declines to propagate a
draft it cannot parse — so nothing on the client rejects a well-formed object
whose shape is wrong. Structural validation belongs on the server.

const ajv = new Ajv();
The `schema` you author is carried on the field metadata untouched, and in the
JSON Schema Format above it is an ordinary JSON Schema document. That is the
whole integration point: the server validates the incoming value against the
very same object, using whichever JSON Schema validator it already has (Ajv,
for instance — ObjectUI ships none and names none).

const validateObjectField = (value: any, schema: any) => {
if (!schema) return { valid: true };

const validate = ajv.compile(schema);
const valid = validate(value);

return {
valid,
errors: validate.errors
};
};
```ts
import type { ObjectFieldMetadata } from '@object-ui/types';

// Example schema
const configSchema = {
const apiConfig: ObjectFieldMetadata = {
type: 'object',
properties: {
api_key: { type: 'string', minLength: 1 },
timeout: { type: 'number', minimum: 0 },
enabled: { type: 'boolean' }
name: 'api_config',
label: 'API Configuration',
schema: {
type: 'object',
properties: {
api_key: { type: 'string', minLength: 1 },
timeout: { type: 'number', minimum: 0 },
enabled: { type: 'boolean' },
},
required: ['api_key'],
},
required: ['api_key']
};
```

One caveat when you do: the Simplified Format above is
documentation for a reader, not a validator input — only the JSON Schema Format
can be handed to a JSON Schema validator as-is.