Overview
v0.13.0 is an architecture hardening release (ADR 0021). The focus is on narrowing the public API surface, adding compiler-enforced phase ordering, and eliminating the last cross-package coupling points.
No new features. Just tighter contracts.
Breaking Changes
Core exports: 18 → 6
@openelement/core now exports only 6 public subpaths:
// Remaining (public)
import { ... } from '@openelement/core'; // runtime utilities
import { LessError } from '@openelement/core/errors';
import { createSsrContext } from '@openelement/core/context';
import { createLogger } from '@openelement/core/logger';
import { navigate } from '@openelement/core/navigation';
// ./constants kept for cross-package shared constants
Removed (internal implementation details, no longer exposed):
./render-dsd— internal, not user-facing./html-escape— internal./adapter-registry— internal./ssr-handler— deleted in v0.12, lingering export removed
Generated code resolves through CORE_SUBPATHS mapping in @openelement/adapter-vite.
ssr-handler.ts deleted
The pure re-export facade ssr-handler.ts is finally gone. Consumers import directly from @openelement/core.
Virtual module IDs moved
All Vite virtual module constants (VIRTUAL_NAV_ID, RESOLVED_BLOG_DATA_ID, etc.) moved from @openelement/core/constants to @openelement/adapter-vite/virtual-ids. Core no longer knows about Vite internals.
New (Internal)
Compile-time Phase ordering
Branded Type state machine ensures build phases execute in the correct order:
type Phase1Ready = { __phase: 'phase1' };
type Phase2Ready = { __phase: 'phase2' };
type Phase3Ready = { __phase: 'phase3' };
function buildPhase1(ctx): Phase1Ready & { ... }
function buildPhase2(state: Phase1Ready): Phase2Ready & { ... }
function buildPhase3(state: Phase2Ready): void
buildPhase2 only accepts Phase1Ready output. buildPhase3 only accepts Phase2Ready. The compiler catches out-of-order calls.
CI coverage
All test jobs now collect --coverage. Coverage reports generated on every CI run.
By-Product Cleanup
| Item | Change |
|---|---|
| Zero barrel files | content/src/nav/index.ts, sitemap/types.ts — inlined |
| islandEffect interval | 5000ms → 30000ms (reduced polling) |
| @openelement/app tests | 0 → 16 tests |
Package Versions
| Package | v0.12.x | v0.13.0 |
|---|---|---|
@openelement/core |
0.12.1 | 0.13.0 |
@openelement/adapter-vite |
0.2.0 | 0.3.0 |
@openelement/content |
0.3.2 | 0.3.3 |
@openelement/signals |
0.6.2 | 0.6.3 |
@openelement/app |
0.3.0 | 0.3.1 |
@openelement/i18n |
0.1.0 | 0.1.1 |
@openelement/create |
0.8.0 | 0.8.1 |
No changes to adapter-lit, ui, rpc.
Migration Guide
If you use @openelement/app (recommended)
No changes needed. lessjs() abstracts all internal restructuring.
If you import from @openelement/core subpaths
Remove imports from removed subpaths:
// Delete these:
import { ... } from '@openelement/core/render-dsd'; // ❌ removed
import { ... } from '@openelement/core/html-escape'; // ❌ removed
import { ... } from '@openelement/core/adapter-registry'; // ❌ removed
import { ... } from '@openelement/core/ssr-handler'; // ❌ removed in v0.12
All runtime exports are available from the main entry:
import { escapeHtml, registerAdapter, renderDSD } from '@openelement/core'; // ✅
Stats
- 86 files changed, +5,427 / −1,506 lines
- 268 tests passing (41 new)
- CI coverage: all jobs collect
--coverage - Zero globalThis bridges: verified deleted in codebase
- Zero barrel files: verified
Release date: 2026-05-12