@codeenvision/ui-framework
v1.0.5
Published
Compile-time first UI framework with CE ecosystem integrations.
Maintainers
Readme
@clusterenvision/ui-framework
A compile-time focused UI framework that powers the CE ecosystem. It blends a component + hooks mental model with Angular-like templates, dependency injection, SSR, and hydration – all optimized through a tiny runtime built on signals.
Looking for a working example? The
web/ce-lmsstarter usesce-ui-scss, pre-registers CE web components, and is Vite-ready for dropping@clusterenvision/ui-frameworkcomponents into a realistic auth flow.
Highlights
- CEX single-file components compiled into optimal DOM instructions.
- Signals + hooks for state, side-effects, async resources, and context.
- Hierarchical DI + router + forms out of the box.
- Universal rendering: render the same component on the server and hydrate on the client.
- Tooling: Vite plugin, tsup build, CLI (
ceui) for compilation pipelines.
Styling + component alignment
This framework expects CE design tokens and web components to be present for a production experience:
- Tokens (scss 1.94.2): import
@clusterenvision/ui-scss/dist/ce-ui.cssinto your app shell or bundler entry, or use the CDNhttps://unpkg.com/@clusterenvision/[email protected]/dist/ce-ui.csswith SRI. Apply a theme class on<html>(e.g.,theme-default,theme-dark). - Web Components (1.1.0): register CE elements once at startup:
import { registerDefaultComponents } from '@clusterenvision/ui-webcomponents'; import '@clusterenvision/ui-scss/dist/ce-ui.css'; registerDefaultComponents(); // defines <ce-switch>, <ce-dialog>, etc. - CEX + CE WC interop: CEX templates can render CE web components directly (no wrapper). See
examples/webcomponents-bridgeand the integration test undertests/runtime/webcomponents-interop.spec.ts.
Production hardening: see docs/PRODUCTION.md for routing/data/error policies, security headers/CSP, perf budgets, and deployment playbooks. TL;DR for releases: run npm run lint && npm run test:ci && npm run typecheck && npm run build && npm run bench, apply CSP and boundary policies per route, and publish only from CI.
Stack roadmap
For the unified future work plan across ce-ui-framework, ce-ui-webcomponents, ce-ui-scss, ce-ui-kit, and ce-ui-platform, see docs/ce-ui-framework/STACK_ROADMAP.md.
Runtime Requirements
- Node.js 20.x LTS (or Node 22.x once the upstream worker leak in Node 25 is fixed). Running the Vitest suite or the CLI on Node 25 currently crashes with
ERR_WORKER_OUT_OF_MEMORY. Use a version manager such asnvm/fnmto pin Node 20 when contributing.
Getting Started
npm install
npm run build
npx ceui compile examples/basic-counterAuthor components with defineComponent:
import { defineComponent, signal } from '@clusterenvision/ui-framework';
export const Counter = defineComponent({
name: 'Counter',
template: `
<section class="counter">
<h1>Hello {{ props.name }}</h1>
<button on:click="increment">Clicks {{ count() }}</button>
<p ce:if="count() > 5">Milestone reached!</p>
</section>
`,
setup() {
const count = signal(0);
const increment = () => count.update(v => v + 1);
return { count, increment };
}
});Then render or hydrate:
import { render } from '@clusterenvision/ui-framework';
render(Counter, { name: 'CE' }, document.getElementById('app')!);Compiler & parser utilities
If you previously depended on node-html-parser to preprocess CE templates, you can now import the built-in parser directly from the compiler bundle:
import {
parse,
createElement,
createTextNode,
createCommentNode,
createFragment,
serialize,
walk,
isElementNode,
} from '@clusterenvision/ui-framework/compiler';
const ast = parse('<section ce:if="visible">Hello</section>', {
lowerCaseTagName: false,
lowerCaseAttributeName: false,
});
const fragment = createFragment([createElement('aside'), createTextNode('scoped docs')]);
fragment.firstChild?.appendChild(createCommentNode('inline note'));
const html = serialize([ast, fragment], { pretty: true });
walk(ast, (node) => {
if (isElementNode(node)) {
console.log('tag', node.tagName, node.attrs);
}
return undefined;
});This keeps template tooling in sync with the CE compiler and avoids CommonJS bundles when shipping to Angular, React, or Vite-based demos.
Parser capabilities
- Returns a real
DocumentFragmentso multiple root nodes are naturally supported. - Configurable tag + attribute casing (
lowerCaseTagName,lowerCaseAttributeName). - Optional HTML entity decoding (
decodeEntities) and comment preservation (preserveComments). - Overridable
voidElements/rawTextElementsfor custom syntaxes. - Helper factories (
createElement,createTextNode,createCommentNode,createFragment) pluscloneNode,serialize, andwalkfor AST transforms. - Type guards (
isElementNode,isTextNode,isCommentNode,isParentNode) ensure ergonomic authoring in toolchains.
Project Scripts
npm run build– bundle via tsup.npm run dev– watch mode for hack-and-learn.npm run test– Vitest suite for compiler/runtime primitives.npm run lint– ESLint (strict TS config).
CLI
The ceui compile command now supports incremental workflows:
ceui compile src/components/**/*.cex --out-dir dist --watch– recompile on file changes.--source-map– emit ESM modules with.mapfiles for debugger parity.- Scoped
<style>blocks automatically receive deterministicdata-ce-scopeattributes so emitted CSS stays encapsulated.
Workflow Orchestrator (Preview)
The runtime now exposes a hybrid workflow/state-machine engine that runs in both the browser and Node.js. Author definitions via the fluent builder API or load JSON specs, then execute them with pluggable stores, HTTP/database tasks, actor-aware approvals, and retry policies.
import {
WorkflowRuntime,
InMemoryWorkflowStore,
InMemoryDatabaseRegistry,
createWorkflow,
httpTask,
databaseTask,
createDefaultTaskMap,
createPostgresProvider,
DatabaseWorkflowStore
} from '@clusterenvision/ui-framework/workflow';
const definition = createWorkflow('order-fulfillment', builder => {
builder
.step('fetch-inventory', httpTask({ url: 'https://inventory.ce/api/items', parse: 'json', assignResponseTo: 'inventory' }))
.onSuccess('persist-order');
builder
.step('persist-order', databaseTask({
provider: 'postgres',
operation: { type: 'command', text: 'select create_order($1)', parameters: [{ $ref: 'inventory' }] },
assignResultTo: 'order'
}))
.withApproval({ id: 'finance', requiredRoles: ['finance-approver'] });
});
const databaseRegistry = new InMemoryDatabaseRegistry();
const postgresProvider = createPostgresProvider(pool, 'postgres');
databaseRegistry.register(postgresProvider);
const runtime = new WorkflowRuntime({
store: new DatabaseWorkflowStore({ provider: postgresProvider, dialect: 'postgres' }),
services: { databases: databaseRegistry },
tasks: createDefaultTaskMap()
});
await runtime.run(definition, { actor: { id: 'user-123', roles: ['finance-approver'] } });Highlights:
- Hybrid definitions (TypeScript DSL + JSON) with deterministic IDs and metadata.
- Built-in retry policies, approval gates, and execution history persistence.
- HTTP + database task adapters (MySQL, Postgres, SQLite, Mongo, or any custom provider).
- In-memory workflow store, logger, background runner, and time service ready for production swaps.
- Actor-aware approvals with
actorcontext injection and role/approver checks. - Delay/schedule helpers (
delayTask,scheduleTask) that leverage the time service, scheduler, and background runner.
Actor Context & Approval Gates
Pass an actor into runtime.run to capture the human/system identity that initiated a workflow. Steps can call .withApproval({ id: 'finance', requiredRoles: ['finance-approver'] }) to block until an approver with the appropriate role resolves the gate. Provide a custom ApprovalResolver to plug in ticketing/notification flows or multi-step approvals.
Scheduling & Background Tasks
The default services include a scheduler built on the background runner + time service. Use the provided tasks to pause or defer work:
builder.step('wait-for-window', delayTask({ seconds: 30 })).onSuccess('notify');
builder.step(
'notify',
scheduleTask({ taskName: 'webhook.dispatch', delayMs: 5_000, payload: { target: 'https://hooks.ce/api' } })
);You can also inject your own scheduler implementation to route deferrals to hosted cron/queue systems.
Persistence
DatabaseWorkflowStore serializes workflow state/history into a SQL table (workflow_instances by default) using upserts compatible with Postgres, MySQL, and SQLite. The expected schema is:
CREATE TABLE workflow_instances (
id TEXT PRIMARY KEY,
workflow_id TEXT NOT NULL,
version TEXT NOT NULL,
status TEXT NOT NULL,
current_step TEXT NULL,
state_json JSON NOT NULL,
actor_json JSON NULL,
metadata_json JSON NULL,
history_json JSON NOT NULL,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);Swap in a custom store if you need to target MongoDB or document databases directly.
Mongo Store
import { MongoWorkflowStore } from '@clusterenvision/ui-framework/workflow';
const mongoStore = new MongoWorkflowStore({ collection: db.collection('workflow_instances'), createIndexes: true });
const runtime = new WorkflowRuntime({
store: mongoStore,
services: { databases: databaseRegistry },
tasks: createDefaultTaskMap(),
});Documents stay shape-aligned with the SQL table (state/history serialized as JSON, indexes on workflowId, status, updatedAt).
Visual DSL Hooks
workflow/schema.ts exposes a VisualWorkflowSchema with node positions, annotations, and stable IDs so an editor (VS Code, diagram tool, BPMN canvas) can round-trip definitions.
import { workflowToVisualSchema, visualSchemaToWorkflow } from '@clusterenvision/ui-framework/workflow';
const schema = workflowToVisualSchema(definition);
schema.nodes[0].position = { x: 100, y: 240 };
const updatedDefinition = visualSchemaToWorkflow(schema);Database Adapters
Beyond the built-in SQL + Mongo helpers, you can now register:
createPrismaProvider– wraps Prisma clients via$queryRawUnsafe/$executeRawUnsafe.createDrizzleProvider– forwards to Drizzle’sexecuteAPI.createSupabaseProvider– targets Supabase/PostgREST tables or RPC endpoints.createRestDatabaseProvider– generic wrapper over any REST backend (e.g., Hasura, custom serverless DB).
Queue-Based Background Runners
QueueBackgroundRunner wires the workflow scheduler to queue systems (BullMQ/Redis, AWS SQS, Azure Storage Queues, or any custom driver). Each driver implements the minimal QueueDriver interface so you can plug in enterprise transports while emitting metrics.
import { QueueBackgroundRunner, createBullMqDriver, MetricsConsoleEmitter } from '@clusterenvision/ui-framework/workflow';
const queueRunner = new QueueBackgroundRunner({
driver: createBullMqDriver(queue),
metrics: new MetricsConsoleEmitter(),
});
const runtime = new WorkflowRuntime({
store: mongoStore,
services: { background: queueRunner, scheduler: queueRunner },
tasks: createDefaultTaskMap(),
});Auth & Policy Integrations
actorFromAuth0Claims,actorFromCognitoClaims,actorFromAzureAdClaims,actorFromOidcClaimsmap identity tokens intoActorContext.PolicyApprovalResolver+RuleBasedPolicyEngineenable custom policy-as-code enforcement before approvals.- Middleware helpers (
requireActorRoles,requireActorScopes,runAuthMiddleware) make it easy to guard workflow start or per-step execution. multiStepApprovalResolvercomposes multiple resolvers andManualOverrideApprovalResolverallows humans to unblock via manual overrides.
Status
Early alpha. The current codebase focuses on the core runtime, compiler skeleton, CLI, and reference examples. Contributions welcome!
