
Security News
Deno Goes the Way of the Dinosaur
Cloudflare is acquiring Deno’s team, which will provide another year of bug fixes and security updates before ending support for the runtime.
form0-core
Advanced tools
The schema-driven form engine behind form0, the open-source form ecosystem by paqu.io. Framework-agnostic: conditional visibility, validation and calculations from a JSON schema, in Node.js, browsers and React Native.
[!NOTE] form0 is in active development and is available to use today. Its schema format and core concepts are stable in practice, but releases before 1.0 may include breaking changes. Pin your versions and review the release notes when upgrading. A formally stable release is coming.
form0-core is the framework-agnostic, schema-driven engine behind the
form0 open-source ecosystem. It evaluates calculations, conditional
visibility, requirements, read-only rules, validation, and form events in Node.js, browsers, and
React Native.
Most users should begin with form0-cli rather than install
the engine directly. Follow the quickstart to
create a project, edit a schema, and preview a form.
Use form0-core directly when you are building a renderer, integration, developer tool, or other
custom form runtime.
npm install form0-core
import { createFormEngine } from 'form0-core';
const schema = {
form: {
name: 'Contact form',
status_field: null,
elements: [
{
type: 'TextField',
key: 'name',
data_name: 'name',
label: 'Name',
display: 'default',
description: null,
description_mode: null,
required: true,
required_conditions: null,
visible: true,
visible_conditions: null,
read_only: false,
read_only_conditions: null,
default_value: null,
pattern: null,
pattern_description: null,
supporting_image: false,
supporting_image_path: null,
supporting_image_display: null,
},
],
},
};
const engine = createFormEngine({
schema,
initialValues: { name: 'Ada' },
});
engine.eval();
console.log(engine.getState());
The engine API exposes eval() for calculations, conditions, and validation; trigger() for form
events; triggerDetailed() for managed events and custom validation; and getState() for current
values and evaluated field state.
Schema event callbacks retain their authored source, so ordinary functions and arrows defined in
form.events.code also work on Hermes. Each dispatch uses current scoped field values; initialization
runs once. Local initialization variables are not captured. Callbacks supplied by host helpers still
require executable toString() output; unavailable source produces an event warning.
Use synchronous engine.triggerDetailed(eventType, fieldDataName, metadata) to receive defensive
operations, validationIssues and execution issues. It does not evaluate, apply operations,
persist or close an editor. Inspect issues before applying a batch; execution failures return no
applicable operations. The existing trigger() operation-array interface retains its legacy behavior.
// In schema.form.events.code:
ON('validate-record', function (event) {
if ($amount < 4) INVALID('Amount must be at least four.');
});
// In the host, after evaluating the intended snapshot:
const result = engine.triggerDetailed('validate-record', undefined, {
isDraft: false,
isValid: true,
});
console.log(result.validationIssues);
INVALID() requires a nonempty string and is valid only during managed validation. Findings remain
separate from intrinsic field errors and calculation diagnostics. Validation handlers cannot return
value or UI operations; cancel/unload handlers are read-only notifications. Promise-returning schema
handlers are rejected, and late operations cannot enter a later dispatch.
Root scope defaults to []. Headless row engines must provide eventScope.instancePath at creation,
using complete repeatable keys and existing IDs (or explicit positional identity). Managed row
handlers can read current, ancestor and main fields supplied by the host, but SETVALUE() writes
only current-row fields. Dispatch metadata cannot replace engine scope or event identity.
See the maintained event contract
for routing, supported events, metadata,
failure behavior and the subsequent binding adoption. Core does not introduce automatic renderer
lifecycle or save preparation by itself. Applications retain persistence and closing ownership;
save-* events are pre-save, with no saved-* schema events.
Diagnostics are collected automatically, including when console reporting is disabled:
const engine = createFormEngine({ schema });
console.log(engine.getDiagnostics()); // [] before the first evaluation
engine.eval();
console.log(engine.getDiagnostics()); // latest evaluation, returned as a defensive copy
Configure reporting in application code:
const engine = createFormEngine({
schema,
diagnostics: { console: false },
onDiagnostics(snapshot) {
for (const diagnostic of snapshot) {
reportCalculationDiagnostic(diagnostic);
}
},
});
engine.eval();
// For a schema calculating quotient from divisor, correct the input and evaluate again:
engine.getState().values.divisor = 4;
engine.eval(); // replaces the snapshot; recovered failures disappear
onDiagnostics runs once after every completed evaluation, including identical snapshots and
[]. Observer exceptions cannot interrupt evaluation and are reported according to the console
policy. Each diagnostic has code, severity, message, fieldName, phase, suggestion, and
context. Context identifies the schema parent path, related/referenced fields, and expression
versus EVAL origin. The engine adds no expression source, field values, or stack traces.
Identical diagnostics are deduplicated within an evaluation. Distinct failures are retained,
including failures observed in intermediate stabilization passes even if a later pass succeeds.
The snapshot records that evaluation; it is not a history or just the final unresolved errors.
Legitimate null, undefined, NaN, and Infinity results do not produce errors by themselves.
Diagnostics stay separate from state.errors and do not change submission validity.
Omit diagnostics.console to preserve existing defaults and supplied WarningSystem settings.
false silences calculation-owned reporting, including EVAL() warnings and debug logs; true
prints diagnostic reporting in development and production. Event reporting retains its existing
behavior. WarningSystem remains compatible.
The append-only runtimeDiagnostics option is deprecated but remains supported for compatibility.
For new integrations, omit that option and use engine.getDiagnostics() for the latest evaluation,
or onDiagnostics(snapshot) to receive every completed evaluation, including recovery ([]).
This is not a drop-in replacement for the legacy array: snapshots use the structured diagnostic
contract above and replace prior results rather than accumulating them. If you need a history,
store snapshots in application code. No removal version is scheduled.
See calculation diagnostics for stable codes and the reporting contract. CLI and renderer diagnostics adoption is separate from this core API.
form0-core owns behavioral schema concerns such as fields, conditions, calculations, events, and
AI metadata. Applications may attach optional top-level metadata such as form identifiers,
publication state, schema version, organization scope, and media or location settings.
Operational counters should remain platform-owned and be injected at application or API
boundaries.
form0-core intentionally uses two choice-value shapes:
{ choice, other }{ choices, other }{ choice_value, other_value }{ choices_value, other_value }Record utilities follow this contract:
createStructuredRecord() produces canonical stored records.normalizeStructuredRecord() consumes and returns canonical stored records.buildFormRecordSnapshot() converts canonical records into renderer snapshot values.projectDatasetRowValues() consumes canonical stored rows.Record status remains top-level as @status; it is not stored inside form_values.
getFormAuthoringContext({ schema }) includes mutationOperationCatalog: the installed operation
formats, required parameters, and examples. mutationOperations remains the list of supported names.
Use these formats with applyFormMutationBatch; for example, a rename uses
{ op: 'updateForm', changes: { name: 'Renamed form' } }, not a patch parameter.
Malformed operations, unknown operation parameters, and empty change objects are rejected atomically
with diagnostics, rather than silently ignored. Clearing a title/status field, calculation, or event
code requires its explicit parameter (for example, field: null), not an omitted value. Valid
idempotent batches remain valid in core; consumers should check actual changes before offering to save.
[!CAUTION] Schema expressions and event scripts execute JavaScript. Only evaluate schemas from authors you trust.
SAFEandCUSTOMmodes provide validation controls; they are not security sandboxes.
Read the security policy before evaluating schemas outside a fully trusted authoring workflow.
See SUPPORT.md for help and CONTRIBUTING.md to contribute.
FAQs
The schema-driven form engine behind form0, the open-source form ecosystem by paqu.io. Framework-agnostic: conditional visibility, validation and calculations from a JSON schema, in Node.js, browsers and React Native.
The npm package form0-core receives a total of 0 weekly downloads. As such, form0-core popularity was classified as not popular.
We found that form0-core demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
Cloudflare is acquiring Deno’s team, which will provide another year of bug fixes and security updates before ending support for the runtime.

Security News
Anthropic’s free OSS Scanner uses Mythos and other Claude models to find open source vulnerabilities and send maintainers reports with proposed fixes.

Security News
On Front Lines’ Early Adopters: CISO podcast, Andrew Becherer shares lessons from Datadog, weighs the long-term costs of AI-built tools, and explains how founders can actually gain a CISO’s trust.