Skip to content

Form conversion and workflow

import { castValuesBySchema } from '@alneas/data-engine/schema/cast';
const values = castValuesBySchema({ quantity: '12', optional: '' }, {
type: 'object', properties: {
quantity: { type: 'integer' }, optional: { type: ['number', 'null'] },
},
}, { numericMode: 'strict' }); // { quantity: 12, optional: null }

Conversion is separate from JSON Schema validation. Validate the result with AJV before storing it. Neither mode enforces required, minimum/maximum, enum, formats, additionalProperties or other schema constraints. It does not resolve $ref, choose anyOf/oneOf/allOf branches, insert defaults, convert boolean strings, or parse dates. Only own declared object properties, array prefixItems and remaining items are walked. Unknown properties and mismatched object/array inputs survive for validation. Inputs are not mutated. Existing null/undefined values remain unchanged.

The default numericMode: 'legacy' preserves existing form behavior: parseInt for integer (including integer/number unions), parseFloat for number. Thus 12suffix becomes 12, integer 1.9 becomes 1, integer 1e3 becomes 1, and number Infinity becomes Infinity. This mode is input convenience, not a numeric safety boundary. Prefer explicit strict mode for new consumers: it accepts an entire finite JSON number, supports exponents, rejects hexadecimal/leading zeros/trailing characters, and retains values failing Number.isInteger for integer inputs as strings. Results use JavaScript Number (IEEE 754); large integers and decimals can lose precision, including before the integer check. Keep exact financial/large-integer values as strings and use a separate decimal representation. In either mode whitespace-only numeric strings become null when the numeric type includes null, otherwise undefined. Unconvertible strings remain unchanged. Object/array/string unions follow the same object/array-first traversal, not branch validation. Depth over 64 or more than 10,000 visited values throws, including cyclic input/schema combinations.

import { WorkflowEngine, WorkflowPolicyEngine } from '@alneas/data-engine/workflow';
const flow = new WorkflowEngine({ id: 'review', label: 'Review',
statusOrder: ['draft', 'done'], transitions: [{ from: 'draft', to: 'done' }],
statusInfo: {}, defaultStatusInfo: { title: 'Unknown' } });
flow.getTransitions('draft');
flow.getProgress('draft'); // 50: position-based, first known status is 1/N
const policy = new WorkflowPolicyEngine<{ authorized: boolean }>({
validateTransition: context => ({ allowed: context.authorized }),
requiresApproval: context => !context.authorized,
getRequiredFields: () => [],
});

WorkflowEngine filters configured transitions/actions and reads labels/status info. Unknown status progress is 0; absent or falsy status information uses defaultStatusInfo, including prototype-named keys. Configuration and returned entries retain their references. It does not write state, persist transitions, enforce approvals/required fields, or authenticate/authorize users. Applications enforce these on the server. Generic transition/action types contain no ReactNode, icons, colours or components; consumers can add presentation metadata through the generic types.

WorkflowPolicyEngine requires all three callbacks explicitly. No purchase document, 10,000 threshold or PAID/RECEIVED/INVOICED convention is built in. Before first public release, react-tools changes its former static policy API to this configured instance API. Private UI retains the former static purchase policy in private app-core. Public and private WorkflowEngine use the same constructor specialized with UI types.

@alneas/data-engine/async provides withTimeout(promise, milliseconds = 30000, errorFactory?). Timers are cleared on success, failure and timeout. Milliseconds must be finite and between 0 and 2147483647. A deadline does not cancel underlying work; supply AbortSignal handling to that work separately. Private error/display handling remains in the React consumer.

@alneas/data-engine/google-calendar/watch provides setupWatchChannel. It POSTs calendarId/webhookUrl to the application’s functionUrl with the supplied bearer token and returns channelId/resourceId/expiration. The application owns endpoint validation, authorization, watch renewal, webhook verification and deployment. Neither helper needs React or another ALNEAS peer.

Granular compatibility subpaths now expose existing canonical schema, Excel, Calendar, notification and graph integration modules. Graph DB/HTTP and agent entries still require their documented optional peers. /server/contained-path is Node-only (its declarations are self-contained); use it only with a trusted, application-owned filesystem root. It does not make arbitrary file access safe.