@hafley66/json-rx
v0.1.2
Published
JSON Schema-defined RxJS automation documents and generated React editor
Downloads
107
Readme
@hafley66/json-rx
JSON Schema-defined RxJS automation documents, a typed runtime compiler, a TypeSpec authoring path, and a generated React form editor.
The current document contract is automation.v1. Flows may use ordered pipes
or nested expressions. Ordered pipes are the default authoring form.
Install
From the hafley-rxjs workspace:
pnpm installFrom another local pnpm workspace:
{
"dependencies": {
"@hafley66/json-rx": "link:../hafley-rxjs/packages/json-rx"
}
}The package expects React 19 and RxJS 7.8 as peer dependencies.
JSON editor support
Add $schema to an automation document:
{
"$schema": "./node_modules/@hafley66/json-rx/automation.schema.json",
"version": "automation.v1",
"profile": "rxjs-7.8"
}The schema is exported as:
@hafley66/json-rx/automation.schema.jsonDocument shape
An automation binds host event sources, declares a circuit, and connects flows to outputs:
{
"$schema": "./node_modules/@hafley66/json-rx/automation.schema.json",
"version": "automation.v1",
"profile": "rxjs-7.8",
"id": "example.usage",
"enabled": true,
"bindings": {
"sources": {
"usage.responses": {
"kind": "http.event",
"page": { "host": "example.com" },
"request": { "methods": ["GET"], "url": "/api/usage" }
}
}
},
"circuit": {
"sources": {
"usage.responses": {}
},
"reducers": {},
"flows": {
"usage": {
"pipe": [
{
"node": "usage.source",
"source": { "$ref": "usage.responses" }
},
{
"node": "usage.map",
"map": {
"from": "$.body",
"language": "jsonata",
"fields": { "utilization": "utilization" }
}
},
{
"node": "usage.share",
"shareReplay": { "bufferSize": 1, "refCount": true }
}
]
}
}
},
"outputs": [
{
"kind": "host.emit",
"flow": "usage",
"stream": "example.usage",
"schema": { "type": "object", "additionalProperties": true }
}
]
}Source and reducer edges use { "$ref": "address" }. Output flow fields
refer to keys in circuit.flows.
Validate a document
import { AutomationSchema, type Automation } from '@hafley66/json-rx'
const automation: Automation = AutomationSchema.parse(input)AutomationSchema validates document fields, unique node IDs, source and
reducer references, host bindings, pipe ordering, and output flow references.
Compile a runtime
Supply an RxJS observable for every source address:
import { compileAutomation } from '@hafley66/json-rx'
import { of } from 'rxjs'
const runtime = compileAutomation(document, {
'usage.responses': of({
method: 'GET',
pageUrl: 'https://example.com/usage',
requestUrl: 'https://example.com/api/usage',
status: 200,
ts: Date.now(),
body: { utilization: 42 },
}),
})
const subscription = runtime.roots['example.usage'].subscribe((emission) => {
console.log(emission)
})
subscription.unsubscribe()Each output stream appears in runtime.roots under its configured stream
name. Runtime compilation parses the document before constructing its RxJS
graph.
React form editor
import { JsonRxForm } from '@hafley66/json-rx'
import { useState } from 'react'
export function AutomationEditor({ initialValue }: { initialValue: unknown }) {
const [value, setValue] = useState(initialValue)
return (
<JsonRxForm
value={value}
onChange={setValue}
onSubmit={(automation) => console.log(automation)}
/>
)
}The form is generated from the automation JSON Schema through RJSF and Material
UI. Operator variants and document references are presented as selections.
Saving is enabled after the controlled value passes AutomationSchema.
TypeSpec authoring
The initial TypeSpec vocabulary supplies @automation, @source, @flow, and
@output decorators:
import "../../4_typespec/4_decorators.tsp";
using JsonRx;
namespace Automations.Example;
@automation("example.usage", "example.com")
interface Usage {
@source("usage.responses", "/api/usage", #["GET"])
op responses(): unknown;
@flow("usage", "usage.responses", "$.body", #{
utilization: "utilization",
})
op usage(): unknown;
@output("usage", "example.usage")
op dashboard(): unknown;
}The current compiler slice is
src/5_automations/0_claude_usage/0_input.tsp.
Generation produces:
1_document.auto.ts
2_document.snapshot.jsonGenerated TypeScript files carry the .auto.ts suffix and a generated header.
Edit the TypeSpec input and run generation instead of editing those files.
Commands
From the repository root:
pnpm generate
pnpm generate:check
pnpm check:json-rxFrom packages/json-rx:
pnpm typespec:check # compile the TypeSpec vocabulary
pnpm generate # regenerate schema, document module, and JSON snapshot
pnpm generate:check # detect stale artifacts and missing generated headers
pnpm typecheck # check TypeScript
pnpm test # run Node and Chromium browser tests
pnpm build # build JavaScript, declarations, and JSON Schema
pnpm check # run every package gateSource layout
spec/ TypeSpec vocabulary
src/0_types.ts runtime event and output types
src/1_schema.ts Zod contract and JSON Schema generation
src/2_runtime.ts RxJS compiler
src/3_editor/ generated-schema React editor
src/4_typespec/ decorators, semantic graph, and emitter
src/5_automations/ authored slices and generated artifacts
scripts/ generation and generated-file checks
plans/ implementation plans