Release v0.0.71
Overviewβ
This release makes vNext event-driven and query-friendly. Event-driven workflows let an external pub/sub message start a new instance (workflow-level event) or advance an existing one through a triggerType: 3 transition, correlated by an IEventMapping script (#86). A fluent instance query language (InstanceQuery) replaces hand-written GraphQL filter JSON in script mappings β one builder powers event selectors, GetInstancesTask filter specs, and raw list-endpoint query strings. A new GetInstance task (TaskType = 19) returns a full single-instance projection (#806), and function result caching serves a repeat function call from a Dapr state store with a single cache read. Instance start/transition and function endpoints now accept application/x-www-form-urlencoded bodies (#825); output scripts can set the content-type response header and async operations return 202 Accepted (#819). The State function response gains a master schema HREF backed by a new master schema function (#821) and an always-present interaction directive object for long-poll clients. The component schema also ships a new data-vocab vocabulary (x-context-source / x-context-target) for schema-driven client context binding. This release runs on component schema 0.0.50.
Featuresβ
Event-driven workflows (#86)β
A workflow can now react to external pub/sub events in two independent ways:
| Action | What it does | Where the event is declared | Delivered with |
|---|---|---|---|
start | Creates a new instance | On the workflow (attributes.event) | ?action=start |
transition | Advances an active instance | On a transition (transition.event, requires "triggerType": 3) | ?action=transition&transitionKey=<key> |
{
"key": "abort-order",
"target": "aborted",
"triggerType": 3,
"event": {
"mapping": { "location": "./src/AbortEventMapping.csx", "code": "<base64>" }
}
}
The mapping script implements the new IEventMapping interface and returns an EventMappingResult: an InstanceKey + Body, or β when the payload carries no key β a Selector built with the fluent InstanceQuery and terminated with First()/Last(), which the runtime resolves against instance columns and instance-data JSON.
Behavior details:
- Event transitions are supported on state transitions and shared transitions only (
triggerType: 3requires aneventdefinition); start/cancel/exit/updateData transitions stay manual. - Delivery infrastructure is domain-owned: one generic runtime endpoint (
POST .../instances/events?action=...) receives everything; topics, Dapr Subscription YAMLs, and pub/sub components live with the domain β shipping a new event needs no runtime redeploy. - CloudEvent envelopes are unwrapped before the mapping runs; selectors are automatically scoped to the target workflow's flow; a non-matching event returns 200 by design so it is not redelivered forever.
- The vnext helm chart gains
global.pubsubComponentsandglobal.subscriptionComponentsvalues that render DaprComponent/Subscriptionresources scoped to the orchestrator sidecar.
Reference: issue #86, helm PR vnext-helm-charts #25 β see also the new Event-Driven Workflows guide and Interfaces β IEventMapping.
Fluent instance query helpers (InstanceQuery)β
Script mappings no longer need to hand-concatenate GraphQL filter JSON. The new fluent builder in BBT.Workflow.Filtering (part of the script engine's default imports) describes every instance query in the platform:
var query = InstanceQuery.Create()
.Where("currentState", f => f.Eq("active"))
.Where("attributes.amount", f => f.Ge(1000).Lt(5000))
.OrGroup(
q => q.Where("attributes.city", f => f.Eq("London")),
q => q.Where("attributes.city", f => f.Eq("Paris")))
.OrderByDescending("createdAt");
How you end the chain decides what you get:
| Terminal | Produces | Used for |
|---|---|---|
.First() / .Last() | A single-instance resolver | Event correlation (EventMappingResult.Selector) |
.Build() | An InstanceQuerySpec list/report query | GetInstancesTask.SetFilterSpec(...), or wire strings for DaprServiceTask |
- Full operator set (
Eq,Ne,Gt/Ge/Lt/Le,Like,StartsWith/EndsWith,In/NotIn,Between,IsNull,Includes) emitting the existing GraphQL wire JSON. GroupBy+Count/Sum/Avg/Min/Maxaggregations for report queries.- Build-time guardrails: whitelisted column names, no unfiltered single-resolve, list-only features rejected on
First()/Last(). GetInstancesTask.SetFilterSpec(spec)is the recommended path β same-domain queries run in-process with no HTTP/Dapr hop;spec.ToFilterJson()/ToSortJson()/ToQueryString()serve rawDaprServiceTaskintegrations.
Reference: see Instance Filtering β Fluent InstanceQuery Builder and GetInstances Task.
GetInstance task β full single-instance projection (#806)β
A new trigger-family task type, GetInstance (TaskType = 19), is the task-level equivalent of GET /api/v1/{domain}/workflows/{workflow}/instances/{instance}. It returns the full instance projection β metadata and data β complementing GetInstances (list, type 15) and GetInstanceData (data only, type 13).
{
"attributes": {
"type": "19",
"config": {
"domain": "sales",
"flow": "order-workflow",
"key": "ORDER-001",
"extensions": []
}
}
}
Same-domain execution runs in-process through the instance query gateway; cross-domain execution calls the same REST endpoint over HTTP or Dapr. Both paths surface an identical output shape to the script context, so one mapping works regardless of where the instance lives.
Reference: issue #806 β see also the new GetInstance Task component page.
Function result cachingβ
A custom function can now declare an optional cache block that caches its entire response in a Dapr state store. On a hit the response is served with a single cache read β tasks are skipped entirely (a real-world config-evaluation function dropped from ~230ms to ~93ms). Opt-in per function, and intended only for side-effect-free (read) functions.
{
"attributes": {
"scope": "I",
"task": { /* ... */ },
"cache": {
"keyExpression": { "location": "dynamicExpresso", "code": "\"config:\" + Instance.Key + \":\" + Instance.Version" },
"ttlInSeconds": 300,
"consistency": "Eventual",
"bypassOnCacheError": true
}
}
}
- The cache key comes from a Dynamic Expresso
keyExpression(evaluated against the script context) or a statickey;storeNamedefaults to the runtime'sDAPR_STATE_STORE_NAME. bypassOnCacheError: true(default) falls back to executing the function when the cache is unavailable.- Generation-namespace invalidation:
generationKey/generationKeyExpressionfolds a generation stamp (held in the state store) into the cache key, so bumping the stamp invalidates a whole family of entries without deletes.Instance.Versionis available in key expressions so a new config version self-invalidates.
Reference: see Custom Functions β Cache.
Form-urlencoded request bodies (#825)β
The public Orchestration endpoints for workflow start, transition execution, and function invocation now accept application/x-www-form-urlencoded bodies alongside JSON. Form keys use bracket paths and are normalized into the same JSON tree before the existing payload-mode pipeline runs:
| Form input | JSON result |
|---|---|
attributes[customer][name]=Ali | nested objects |
tags[]=a&tags[]=b (or repeated tags=a&tags=b) | scalar array |
items[0][name]=A&items[1][name]=B | array of objects |
- Scalar values use JSON-literal semantics in payload data (
30,true,nullbecome typed values;"00123"stays a string); the standard envelope fieldskey,stage, andtagsalways remain strings. - Ambiguous shapes (
items[][name]=A, sparse/negative indices, scalar/container collisions) are rejected with HTTP 400 β no partially normalized payload is passed downstream. - Payload mode resolution is unchanged:
x-vnext-payload-modeheader overrides auto-detection.
Reference: issue #825 β see also REST API β Instance Endpoints.
User-controlled Content-Type and 202 Accepted (#819)β
Two response-mapping changes for instance and function endpoints:
content-typeunblocked: function and instance output scripts can now set thecontent-typeresponse header for integration scenarios (previously stripped). The default remainsapplication/jsonwhen the script does not set one.- 202 Accepted for async operations: instance start and transition now return 202 Accepted instead of 200 for
sync=falsesuccess, reflecting that the work is queued for durable background processing.sync=true, error results, and the custom output-response path are unchanged.
Reference: issue #819 β see also Async / Sync.
Master schema function and State response HREF (#821)β
A new master system function resolves the flow-level master schema an instance is bound to (Workflow.Schema), forwarding to the active subflow instance when one is present. The State function response now carries a master HREF alongside the existing data/view/schema links, so clients can fetch the instance's master schema without knowing the workflow definition.
- Query-role denial returns 403; a flow without a master schema returns 404.
Reference: issue #821 β see also Built-in Functions.
State interaction directives for long-poll clientsβ
The State function response's interaction object is now emitted whenever the state declares interaction.longPoll (subject to role grants) β regardless of the terminate value:
{
"interaction": {
"terminateLongPoll": false,
"fallbackTimeoutSeconds": 600
}
}
terminateLongPollreflects the state'sinteraction.longPoll.terminatevalue. Whentrue, the client terminates its long-poll, renders the entered state, and acknowledges via the includedackHREF (fallback resumes the pipeline automatically if not acknowledged withinfallbackTimeoutSeconds).- When
false, the client restarts the long-poll request if it has stopped β independent of the instance status β and keeps retrying within thefallbackTimeoutSecondswindow. ackis present only whenterminateLongPollistrue.
Reference: see Workflow component β State Interaction and Async / Sync.
Data Context Vocabulary β data-vocabβ
The component schema package ships a new vocabulary, data-vocab.json, defining two backwards-compatible JSON Schema annotations for schema-driven client context binding:
x-context-source(on a transition-input schema property): marks the property as client-resolved β from a literal (const), a context-store slot (context), or the client identity (identity: subject|user) β instead of a rendered form field.x-context-target(on a workflow master schema): maps instance-data field paths to context-store slots, applied on every instance read so reusable outputs (tokens, device ids, certificates) propagate to the client context-store automatically.
Slot keys support {instance} / {subject} templating; standard validators ignore the annotations, so unannotated schemas behave exactly as before.
Reference: see Schema component β Data Context Vocabulary.
Configuration Updatesβ
Configuration for v0.0.71:
{
"runtimeVersion": "0.0.71",
"schemaVersion": "0.0.50"
}
Note: Schema version advances to 0.0.50 (from
0.0.49). The bump adds the CacheAside task type"18"and GetInstance task type"19"(#806), the functionattributes.cacheblock, the workflow/transitioneventdefinition (#86), and the newdata-vocab.jsonvocabulary. Update@burgan-tech/vnext-schemain your domain project before validating against this runtime.
Container images: published at tag 0.0.71 under ghcr.io/burgan-tech/vnext/*, Cosign-signed (keyless OIDC) with SBOM + provenance. Immutable digests are listed in the GitHub release.
Issues Referencedβ
- vnext #86 β Event-driven workflow start and transitions with
IEventMappingcorrelation. - vnext #806 β GetInstance task type for full single-instance projection.
- vnext #825 β
application/x-www-form-urlencodedsupport on start/transition/function endpoints. - vnext #819 β User-controlled
content-typeresponse header and 202 Accepted for async instance operations. - vnext #821 β Master schema function and
masterHREF in the State function response. - vnext-helm-charts #25 β Dapr resiliency policies + values-driven pub/sub and subscription components.
Summaryβ
- Event-driven workflows:
attributes.eventstarts instances,triggerType: 3transitions advance them;IEventMappingcorrelates byInstanceKeyor a fluentSelector; delivery stays domain-owned via Dapr Subscriptions (helm support included). - InstanceQuery: one fluent builder for event selectors (
First()/Last()),GetInstancesTaskfilter specs (Build()+SetFilterSpec), and raw list-endpoint wire strings β with GroupBy/aggregations and build-time guardrails. - GetInstance task (Type 19) returns the full instance projection (metadata + data), in-process for same-domain calls.
- Function result caching: opt-in
cacheblock with Dynamic Expresso keys, TTL, and generation-namespace invalidation. - Form-urlencoded bodies are accepted on start/transition/function endpoints with strict bracket-path β JSON normalization.
- Response shaping: output scripts may set
content-type; async start/transition return 202 Accepted. - State response: new
masterschema HREF and an always-presentinteractionlong-poll directive (terminateLongPoll,fallbackTimeoutSeconds). - data-vocab:
x-context-source/x-context-targetannotations for schema-driven client context binding. - Schema is 0.0.50.
vNext Runtime Platform Team Released July 21, 2026
