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
86 changes: 86 additions & 0 deletions .changeset/stack-themes-carrier-retired.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
---
"@objectstack/spec": minor
---

feat(spec): retire the `themes` carrier key and `ThemeSchema` — the authoring surface nothing ever applied (#10485, ADR-0049)

**BREAKING** accept-set narrowing, landing after the v17.0.0 cut (the lockstep
launch-window convention ships it as `minor`; the migration prescription is
registered under protocol major 18, where `os migrate meta` users will look).
Maintainer ruling 2026-08-21, recorded verbatim on #10485: 「B:退役授权面 —
收掉 `themes` 载体键与 schema,`app.branding` 留作唯一颜色面;objectui 引擎代码
与单测保留。」

`defineStack({ themes })` was a real authoring surface — parsed strictly at the
authoring gate, ingested and stored by artifact ingest
(`ARTIFACT_FIELD_TO_TYPE`) — with ZERO consumers past that point, measured:
no non-test read of `.themes` or of stored `theme` items anywhere in
core/runtime/rest/services/plugins; `theme` never in `MetadataTypeSchema`,
`DEFAULT_METADATA_TYPE_REGISTRY` or `BUILTIN_METADATA_TYPE_SCHEMAS`; the only
mounted `ThemeProvider` is the app-shell chrome light/dark toggle (unrelated to
`ThemeSchema`); and no stack- or app-level key ever selected an active theme.
An author who wrote a theme shipped it through every green gate and the console
looked exactly the same.

**What is refused:** the top-level `themes:` key. `ObjectStackDefinitionSchema`
is a `strictObject`, so the key is deleted from the shape and the unknown-key
rejection carries the retirement prescription via the schema's `guidance` entry
(removal citation, why it was inert, and the `app.branding` replacement).
`ThemeSchema`, `ColorPaletteSchema`, `TypographySchema`, `BorderRadiusSchema`,
`ShadowSchema`, `ThemeModeSchema`, `defineTheme` and the `Theme` /
`ThemeParsed` / `ColorPalette` / `Typography` / `BorderRadius` / `Shadow` /
`ThemeMode` types are removed from `@objectstack/spec` / `@objectstack/spec/ui`
(orphaned value schemas leave with their one consumer, #3950). `PUT
/api/v1/meta/theme/:name` now gets the #8421 unrecognised-type refusal — the
`themes: 'theme'` fold left `PLURAL_TO_SINGULAR` and with it the generated
URL-spelling contract — instead of the pre-#10194 store-anything branch.

**What stays:** `app.branding.primaryColor` / `accentColor` — the one live
colour surface (objectui's `AppShell` reads it and derives `--primary`,
`--accent` and friends) — plus objectui's `ThemeEngine` / `ThemeContext` engine
code and their unit tests, explicitly retained by the ruling. Legacy stored
`theme` rows are untouched: reads still answer, DELETE still works, and
`applyConversionsToStoredItem` passes them through unchanged.

The retirement kit:

- strict deletion + `guidance` prescription at the stack schema
(`packages/spec/src/stack.zod.ts`); `packages/spec/src/ui/theme.zod.ts`
deleted whole
- ADR-0087 registration: retired-def entries `ui/Theme`, `ui/ThemeMode`,
`ui/ColorPalette`, `ui/Typography`, `ui/BorderRadius`, `ui/Shadow` and the
D3 **semantic** entry `stack-themes-carrier-retired` (protocol 18). Semantic
rather than a D2 conversion on the lossless-only scope guard: a stack may
declare N themes and M apps, so which palette entry becomes which app's
`branding.primaryColor` is a judgment the transform cannot make — the entry
prescribes the hand move instead of auto-deleting authored content
- ingest mapping removed (`packages/metadata/src/plugin.ts`), CLI stats row
removed, showcase example re-based on app branding
- pin tests: `stack-top-level-strict.test.ts` (refusal carries `#10485` +
`app.branding` + no rename suggestion; replacement parses green; no theme
export survives on `./ui`) and `protocol.unrecognised-meta-type.test.ts`
(`/meta/theme` refused with the ADR-0112 envelope, nothing stored)
- generated baselines/docs follow the schema (`authorable-surface/`,
`json-schema.manifest/`, api-surface, export-origins, meta-url-spelling,
spec-changes, upgrade guide, reference docs, skill references)

## FROM → TO

```ts
// before — parsed green, stored by artifact ingest, applied by NOTHING:
defineStack({
themes: [{ name: 'corporate', label: 'Corporate', mode: 'light',
colors: { primary: '#7C3AED' } }],
});

// after — delete the key; colour the console where something reads it:
defineApp({
name: 'my_app',
label: 'My App',
branding: { primaryColor: '#7C3AED', accentColor: '#06B6D4' },
});
// a custom CSS variable your own stylesheet consumed has no spec slot any
// more — move it into your own CSS.
```

<!-- adr-0087: registered stack-themes-carrier-retired -->
2 changes: 1 addition & 1 deletion content/docs/getting-started/examples.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -277,7 +277,7 @@ os compile # Build to dist/objectstack.json
A kitchen-sink workspace built for demonstration and debugging. It exercises
nearly every metadata type, view type, and chart type in a single app — objects,
views, apps, pages, dashboards, reports, datasets, flows, jobs, agents, security
profiles, translations, themes, webhooks, and more. Use it as a living reference
profiles, translations, webhooks, and more. Use it as a living reference
when you want to see how a particular metadata type is authored.

```bash
Expand Down
5 changes: 2 additions & 3 deletions content/docs/getting-started/quick-reference.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -46,9 +46,9 @@ Core business logic and data modeling schemas.
| **[Postgres Driver](/docs/references/data/driver-postgres)** | `driver/postgres.zod.ts` | PostgresConfig | PostgreSQL configuration |
| **[Mongo Driver](/docs/references/data/driver-mongo)** | `driver/mongo.zod.ts` | MongoConfig | MongoDB configuration |

## UI Protocol (11 of 17 schemas)
## UI Protocol (10 of 16 schemas)

Presentation layer - views, forms, dashboards, and themes.
Presentation layer - views, forms, dashboards, and app branding.

| Protocol | Source File | Key Schemas | Purpose |
|:---------|:-----------|:------------|:--------|
Expand All@@ -61,7 +61,6 @@ Presentation layer - views, forms, dashboards, and themes.
| **[Action](/docs/references/ui/action)** | `action.zod.ts` | Action, ActionType | UI button actions |
| **[Component](/docs/references/ui/component)** | `component.zod.ts` | PageComponent variants | Reusable UI components |
| **[Chart](/docs/references/ui/chart)** | `chart.zod.ts` | Chart, ChartType | Chart definitions |
| **[Theme](/docs/references/ui/theme)** | `theme.zod.ts` | Theme, ColorPalette | Theming and branding |
| **[Widget Contract](/docs/protocol/objectui/widget-contract)** ↗ | `widget.zod.ts` | FieldWidgetProps | Props a custom field widget receives — the contract is documented with ObjectUI, outside `references/ui/` |

## Kernel Protocol (17 of 31 schemas)
Expand Down
3 changes: 1 addition & 2 deletions content/docs/getting-started/quick-start.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -160,7 +160,7 @@ app-showcase/
├── objectstack.config.ts
├── src/
│ ├── data/ # objects, extensions, hooks, mappings, analytics, seed
│ ├── ui/ # views, pages, apps, actions, dashboards, reports, datasets, themes
│ ├── ui/ # views, pages, apps, actions, dashboards, reports, datasets
│ ├── automation/ # flows, jobs, webhooks
│ ├── security/ # permission sets, positions, sharing rules, capabilities
│ ├── system/ # apis, books, connectors, datasources, emails, server, translations
Expand DownExpand Up@@ -203,7 +203,6 @@ is the full authorable set, ordered data → interface → automation → integr
| `dashboards` | Chart and metric boards | [Dashboards](/docs/ui/dashboards) |
| `reports` | Saved analytical queries with grouping and totals | [Reference](/docs/references/ui/report) |
| `actions` | Buttons and bulk operations, with CEL visibility | [Actions](/docs/ui/actions) |
| `themes` | Color tokens and branding | [Reference](/docs/references/ui/theme) |
| `translations` | i18n bundles for labels and messages | [Translations](/docs/ui/translations) |
| `docs` | In-app Markdown documentation items | [Doc Pages](/docs/ui/doc-pages) |
| `books` | Ordered navigation spines over those doc items | [Reference](/docs/references/system/book) |
Expand Down
67 changes: 21 additions & 46 deletions content/docs/protocol/objectui/widget-contract.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -269,54 +269,29 @@ parse-clean no-op. Large datasets page via the view's `pagination` block.

## Theme

ObjectUI theming is defined by `ThemeSchema` in `packages/spec/src/ui/theme.zod.ts`, and it declares **ten** authorable keys — that list is the whole vocabulary. Five of them are identity and inheritance: `name` (a snake_case identifier) and `label` are required, `description` is optional, `mode` is one of `light`, `dark`, or `auto` (default `light`), and `extends` names another theme to inherit from. The other five are the token surface:

| Key | Required | Shape | What it puts on the document |
|-------|-------|-------|-------|
| `colors` | ✅ | `ColorPalette`; only `primary` is mandatory inside it | The shadcn palette variables — **renamed on the way out**: `surface` emits `--card`, `text` emits `--foreground`, `textSecondary` emits `--muted-foreground`, `disabled` emits `--muted`, `error` emits `--destructive`. |
| `borderRadius` | — | A scale object (`none`/`sm`/`base`/`md`/`lg`/`xl`/`2xl`/`full`), not a single token | `--radius-sm`, `--radius-md`, ... — and `base` emits the bare `--radius`. |
| `shadows` | — | The same stops plus `inner` | `--shadow-sm`, `--shadow-md`, ... — and `base` emits the bare `--shadow`. |
| `typography` | — | One live key since #5021: `fontFamily.base` | `--font-sans`. |
| `customVars` | — | A flat string map | Every entry verbatim, `--` prefixed if you omit it: `z-modal: '1050'` emits `--z-modal: 1050`. This is the declared door for any other custom property. |

```yaml
name: corporate
label: Corporate
mode: light
colors:
primary: '#2563eb'
surface: '#ffffff'
text: '#111827'
borderRadius:
base: 0.25rem
md: 0.375rem
shadows:
base: '0 1px 3px rgb(0 0 0 / 0.1)'
typography:
fontFamily:
base: 'Inter, system-ui, sans-serif'
customVars:
space-4: 1rem
The `themes` authoring surface was **retired** in `@objectstack/spec` 17.1
(#10485, ADR-0049 enforce-or-remove). Authored themes were parsed and stored,
but no framework package ever read them back and nothing selected an active
theme, so a declared theme never changed anything on screen. A stack that still
declares `themes:` is now refused at parse with a prescription pointing here.

**`app.branding` is the one colour surface.** Set
`branding.primaryColor` / `branding.accentColor` on the app
(`packages/spec/src/ui/app.zod.ts`): objectui's `AppShell` converts them to
HSL and writes `--primary`, `--primary-foreground`, `--ring`,
`--sidebar-primary`, `--sidebar-ring`, `--accent` and `--accent-foreground`,
re-deriving them on the light/dark flip.

```ts
export const MyApp = defineApp({
name: 'my_app',
label: 'My App',
branding: { primaryColor: '#2563eb', accentColor: '#06b6d4' },
});
```

`ThemeSchema` is `.strict()` (#4001), so a key outside that list is a **parse failure** at `defineStack({ themes })` / `defineTheme()`, carrying its own prescription — not a value silently dropped while the theme still reports valid.

<Callout type="warn">
**Older theme samples no longer parse** — check yours before copying it forward.
**#3494** removed `spacing`, `breakpoints`, `logo`, `density`, `wcagContrast`,
`rtl`, `touchTarget` and `keyboardNavigation`: the theme engine never emitted a
variable for any of them, so authoring one was a silent no-op. **#5021**
(`@objectstack/spec` 17.0.0, ADR-0049) removed `animation`, `zIndex`, the
`typography.fontSize` / `fontWeight` / `lineHeight` / `letterSpacing` scales and
`typography.fontFamily.heading` / `mono`: those *were* emitted, faithfully and
for years, but no first-party component or stylesheet has ever read one.
The prescription in both waves is `customVars`, and it is a byte-for-byte
replacement — `customVars` carrying `font-size-lg: 1.125rem` puts exactly the
same `--font-size-lg` on the document the retired scale did. Run
`os migrate meta --from 16` to rewrite stored metadata automatically.
</Callout>

Widgets inherit the active theme automatically; they do not each carry their own copy of the palette or the font stack.
Widgets read the resulting CSS variables (`hsl(var(--primary))`, …); they do
not each carry their own copy of the palette.

## What's Next?

Expand Down
9 changes: 4 additions & 5 deletions content/docs/references/index.mdx
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
---
title: Protocol Reference
description: Every schema published by @objectstack/spec — 1589 schemas across 14 protocol modules
description: Every schema published by @objectstack/spec — 1583 schemas across 14 protocol modules
---

{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */}
Expand DownExpand Up@@ -32,8 +32,8 @@ counts are sums of the rows they head. Regenerate with
| [Shared Protocol](/docs/references/shared) | 8 | 31 | Primitives used across every protocol — identifiers, HTTP, expressions, error maps, enums. |
| [Studio Protocol](/docs/references/studio) | 3 | 35 | Studio designer metadata — the authoring surfaces for the protocols above. |
| [System Protocol](/docs/references/system) | 36 | 287 | The runtime environment — logging, jobs, cache, metrics, notifications, i18n and compliance. |
| [UI Protocol](/docs/references/ui) | 17 | 162 | Apps, pages, views, dashboards, reports, actions and themes — the ObjectUI layer. |
| **Total** | **199** | **1589** | 14 protocol modules |
| [UI Protocol](/docs/references/ui) | 16 | 156 | Apps, pages, views, dashboards, reports, actions and themes — the ObjectUI layer. |
| **Total** | **198** | **1583** | 14 protocol modules |

---

Expand DownExpand Up@@ -364,7 +364,7 @@ The runtime environment — logging, jobs, cache, metrics, notifications, i18n a

## UI Protocol

**Source:** `packages/spec/src/ui/` · **Import:** `@objectstack/spec/ui` · **17 pages, 162 schemas**
**Source:** `packages/spec/src/ui/` · **Import:** `@objectstack/spec/ui` · **16 pages, 156 schemas**

Apps, pages, views, dashboards, reports, actions and themes — the ObjectUI layer.

Expand All@@ -385,7 +385,6 @@ Apps, pages, views, dashboards, reports, actions and themes — the ObjectUI lay
| [`report.zod.ts`](/docs/references/ui/report) | `JoinedReportBlock`, `Report`, `ReportChart`, `ReportSort`, `ReportType` |
| [`responsive.zod.ts`](/docs/references/ui/responsive) | `BreakpointColumnMap`, `BreakpointName`, `BreakpointOrderMap`, `ResponsiveConfig`, `ResponsiveStyles`, `StyleMap` |
| [`sharing.zod.ts`](/docs/references/ui/sharing) | `SharingConfig` |
| [`theme.zod.ts`](/docs/references/ui/theme) | `BorderRadius`, `ColorPalette`, `Shadow`, `Theme`, `ThemeMode`, `Typography` |
| [`view.zod.ts`](/docs/references/ui/view) | `AddRecordConfig`, `AppearanceConfig`, `CalendarConfig`, `ColumnPrefix`, `ColumnSummary`, `ColumnSummaryConfig`, `FormButtonConfig`, `FormField`, `FormFieldPublicPicker`, `FormSection`, `FormView`, `GalleryConfig`, `GanttConfig`, `GanttQuickFilter`, `GroupingConfig`, `GroupingField`, `HttpMethodSubset`, `HttpRequest`, `KanbanConfig`, `ListChartConfig`, `ListColumn`, `ListMapConfig`, `ListView`, `NavigationConfig`, `NavigationMode`, `ObjectListView`, `ObjectUserFilters`, `PaginationConfig`, `RowColorConfig`, `RowHeight`, `SelectionConfig`, `TimelineConfig`, `TreeConfig`, `UserActionsConfig`, `UserFilterField`, `UserFilters`, `View`, `ViewData`, `ViewFilterRule`, `ViewItem`, `ViewItemName`, `ViewItemWire`, `ViewKind`, `ViewScope`, `ViewSharing`, `ViewTab`, `VisualizationType` |

---
Expand Down
1 change: 0 additions & 1 deletion content/docs/references/ui/index.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,6 +21,5 @@ This section contains all protocol schemas for the ui layer of ObjectStack.
<Card href="/docs/references/ui/report" title="Report" description="Source: packages/spec/src/ui/report.zod.ts" />
<Card href="/docs/references/ui/responsive" title="Responsive" description="Source: packages/spec/src/ui/responsive.zod.ts" />
<Card href="/docs/references/ui/sharing" title="Sharing" description="Source: packages/spec/src/ui/sharing.zod.ts" />
<Card href="/docs/references/ui/theme" title="Theme" description="Source: packages/spec/src/ui/theme.zod.ts" />
<Card href="/docs/references/ui/view" title="View" description="Source: packages/spec/src/ui/view.zod.ts" />
</Cards>
1 change: 0 additions & 1 deletion content/docs/references/ui/meta.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,7 +16,6 @@
"report",
"---Interaction & Layout---",
"responsive",
"theme",
"---Platform---",
"i18n",
"notification",
Expand Down
Loading
Loading