v0.8.0
Minor Changes
b553c9f: The preview host moves to
@revenexx/studio-integrations1.4.1Three minors and a patch on from the 1.1.1 pin, and 1.3.0 is the release the devkit has been half of since 0.7.0:
showIfandstate-refshipped here as validator behaviour (PO-410, PO-374) against an editor that did not yet draw either. Both halves now exist, so what the preview shows and whatconfig:validaterefuses are the same rule rather than two guesses about it.What a node author sees that they did not before. A setting carrying a
showIfcondition is drawn only while the condition holds, and is not counted among the optional ones either — the mock skips that setting on validate for the same reason, so a hidden setting is never demanded. Astate-refsetting is a picker over the namespaces of itsstateRoleinstead of the raw JSON box a field type the editor did not know fell back to; typing"article"as a JSON string is no longer the way in. A setting declaredmultilinegets a text area with room for what it asked for. And a node exported in more than one version can be moved between them from inside the dialog, with what the move costs — what travels, what is dropped, what arrives needing an answer — listed before it happens.The node page owns the state namespaces, because there is no workflow to. The inspector stages a namespace declared inside the picker and, on Save, hands it up (
declare-state) for the editor to write into the workflow blob. Nothing here holds a blob, so without an owner the namespace an author had just declared would disappear from the picker the moment they saved it, and again on every reopen. The page keeps the list for the session: it starts empty, a declaration kept by Save joins it, a reload starts over. The mock still does not check a namespace against any declaration — that is the engine's half, and it has no local equivalent.GET /nodesnow answers newest version first per slug, with the slugs themselves left in the order the package exports them. This is the bump's one real bug rather than a nicety: from 1.3.0 the studio's catalogue reads "a newer version of this node exists" as position in the array rather than by parsing a semver, matching a registry that answers each slug's versions semver-descending. The mock answered in export order — the order a human writes versions in, oldest first — so a package exporting 1.0.0 before 2.0.0 would have had the inspector announce the older version as the upgrade and stay silent about the real one.GET /nodes/{slug}/versionshas always sorted; the listing the catalogue is actually built from now sorts the same way, andtests/server.test.tsholds the two together. The contract test cannot catch this class of drift at all — OpenAPI declares shapes, not order — which is now written intodocs/architecture.md.One order is now one rule, rather than sorted in the places someone remembered.
GET /nodes/{slug}/latestandDELETEon the same path resolvedlatestas the FIRST export of the slug whileconfig:resolve,config:validateandexecute:testwent through a helper that sorts — so for that same package the mock would describe 1.0.0 and execute 2.0.0 under one URL. Both now go through the orderingGET /nodesis built from. And a prerelease is ranked below its own release:2.0.0-beta.1used to parse its patch as0and compare equal to2.0.0, a tie the stable sort broke by export order, so a package exporting its beta first offered an author pinned to the stable an "upgrade" to the beta — the same wrong-direction prompt, from a different cause. Prerelease identifiers follow semver precedence (numeric below alphanumeric, shorter set below longer), and build metadata is ignored.1.4.0 rearranges the dialog the preview exists to show. Three of its changesets land on the node configuration surface and on nothing else the host mounts:
- The Parameters tab draws a node's settings in the order the node declares
them (PO-463), where it used to draw every required setting first and fold
every optional one away. Four or fewer are all shown; past the fourth a
setting stands when it is required and folds when it is not. For a node author
this moves the lever into their own manifest: a setting that is central to the
node belongs near the top of
config, whether or not the API would refuse it empty. Requiredness no longer stands in for importance. - A setting inside a repeating row is drawn as what it declares (PO-436) —
its options, its default, its description, its required marker, and its
showIfresolved against that row — instead of as an empty text box whatever the manifest said. A new row now carries each sub-setting's declared default and omits one that has none, where it used to seed an empty string under every key, which is a value rather than an absence. - An option declared with an empty value — "unchanged", "all kinds" — is selectable (PO-422). It used to be refused by the control underneath, which reserves the empty value for "nothing selected", and the refusal took the dialog's dismissal machinery with it.
Which opens one gap the other way, and this bump documents rather than closes it.
validateNodeConfigreads a node's settings one level deep: a field declaringitemsorpropertiesis checked for being an array or an object, plus theminLength/maxLengthon the field itself, and the sub-settings inside it are neither demanded when required nor type-checked, with no per-rowshowIf. That cost nothing while the form drew a nested setting as a text box; from 1.4.0 the dialog marks a nested setting required and the mock does not refuse it empty. The inversion is now stated in the fidelity caveats and indocs/testing.md, where theshowIfrule it mirrors is written down.The Save/Cancel arrangement on the node page is unchanged and still needed.
NodeInspectoremitsupdateonly when its draft differs fromselection, then always emitsclose, so the stampedALWAYS_DIRTYkey is still what tells a Save from a Cancel. 1.3.0 widensdirtyto count a staged state declaration as well, butcommit()gates theupdateemit on the draft compare alone in 1.4.1 exactly as in 1.3.0, so nothing about the workaround moves. The upstreamsaveevent that would retire it still does not exist.Nothing else in the host moves. 1.4.1 declares the same dependencies and the same peers as 1.1.1, so the
@revenexx/studio^0.2.2,@revenexx/studio-shared^0.3.0 and@solar-icons/nuxt^1.2.1 pins stand as they are, and the host's tree resolves with no peer conflict.NodeInspector's props and events are byte-identical between 1.3.0 and 1.4.1, sopreview-host/pages/nodes.vueneeds nothing new.The rest of the three releases lands outside what the preview shows: the tenant-wide Runs page paging and sorting on the platform (which needs
?sort=onGET /v1/runs, PO-371), build states that become true on their own, deleting a workflow from its editor, the loading announcements, template installation taking the same step from both routes into it (PO-244), the run replay losing its unreachablesinglemode (PO-350), and — the whole of 1.4.1 — a refused credential save stating each reason once (PO-477). The Workflows surface is hidden and…/runs/*is deliberately unmocked, so the mock is untouched there: the one route the three releases change is…/runs/{id}/steps?include_payloads=(PO-421), inside that unmocked prefix.Two traces do reach the mock, and both already hold. A test run from the editor now names the workflow it belongs to, so
POST …/execute:testmay carryworkflow_id; the preview has no workflow to name and never sends one, and the mock readsconfig,inputsandtimeout_msand ignores the rest. And PO-394 gives the studio one answer to whether a response carries adataenvelope, replacing nine expressions that each decided for themselves — the rule being that a collection is wrapped and a single record is bare. The sharedunwrapRecordstill accepts either shape and only fails on an absent record, and the mock's wrapped single records are what this repository's own contract snapshot declares (GET /credential-types/{slug}among them), so nothing here needs to change. If that leniency is ever tightened to match the table, the envelope is a shape — which means the contract test would catch it, unlike the ordering above.- The Parameters tab draws a node's settings in the order the node declares
them (PO-463), where it used to draw every required setting first and fold
every optional one away. Four or fewer are all shown; past the fourth a
setting stands when it is required and folds when it is not. For a node author
this moves the lever into their own manifest: a setting that is central to the
node belongs near the top of
Patch Changes
0da0d11: The OAuth redirect URI carries the port the dev server actually listens on
handle()parsed every request against the fixed basehttp://localhost, andreq.urlis only ever the path, sourl.originwashttp://localhost— port 80 — no matter where the server was bound. The authorize route did not even go through it: it passed a hard-codedhttp://localhost/api/v1/credentials/oauth/callback.The two agreed with each other, which is why nothing 400s at the provider, and also why the failure is confusing: consent succeeds, and then the browser is sent to port 80, where the devkit is not listening. On the default port the callback that completes the flow was unreachable, so a 3-legged credential could never reach
activein the preview.Both now derive from the
Hostheader of the incoming request, so with--port 3555the redirect URI ishttp://localhost:3555/api/v1/credentials/oauth/callback— the value to register with the provider, now written down indocs/architecture.md. Authorize and exchange still read from one place, so they cannot drift apart; a missing or malformedHostfalls back to the old base rather than throwing.Nothing else reads
url.origin, so no other route changes. Packages that worked around this by overridingbuildAuthorizeUrl/exchangeCodeto substitute their own redirect URI can drop the override — the value they receive is now the reachable one.