<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Orbital Changelog</title>
        <link>https://orbitalhq.com/changelog</link>
        <description>What changed in each Orbital release.</description>
        <lastBuildDate>Fri, 18 Sep 2026 11:19:44 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>Orbital Changelog</title>
            <url>https://orbitalhq.com/brand/orbital-mark.png</url>
            <link>https://orbitalhq.com/changelog</link>
        </image>
        <copyright>All rights reserved 2026, Notional Technology Ltd</copyright>
        <atom:link href="https://orbitalhq.com/feeds/changelog.xml" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[0.39.1-M1 - Workspaces, Copilot, secrets and validation]]></title>
            <link>https://orbitalhq.com/changelog/2026-08-24-release-announcement-0.39.0</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2026-08-24-release-announcement-0.39.0</guid>
            <pubDate>Mon, 24 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[The first milestone of 0.39, the biggest change Orbital has had. Multiple workspaces per instance, organisations, a secrets manager with five backends, a data validation framework, an MCP server, and a new multi-file code editor.]]></description>
            <content:encoded><![CDATA[<a href="https://hub.docker.com/r/orbitalhq/orbital/tags?name=0.39.1-M1" target="_blank" rel="noreferrer">Available since <!-- -->0.39.1-M1</a>
<p>0.39.1-M1 is the first milestone of 0.39 — the largest change Orbital has had. It has been in development since
April, and it changes the shape of the product in a few significant ways.</p>
<p>The headline is <strong>workspaces</strong>: a single Orbital instance can now run many independent schemas, each with its
own projects, its own compiled schema, its own connections and its own query context. Everything downstream of
that — auth, secrets, search, history, caching, the language server — was reworked to be workspace-aware.</p>
<p>Alongside that: a <strong>secrets manager</strong> with five backends, a <strong>data validation framework</strong>, <strong>Copilot</strong>
(chat-driven querying and schema building), an <strong>MCP server</strong> so external agents can query your data mesh, and
a <strong>new code editor</strong> that edits whole projects rather than single queries.</p>
<p>Two features we announced over the summer also ship here for the first time: <strong>collection options</strong>
(<code>limit</code>, <code>offset</code>, <code>orderBy</code>, <code>uniqueBy</code> on any query, pushed down to the source where it can take them), and
<strong><code>@DeleteOperation</code> / <code>@SqlQuery</code></strong> for the database connectors.</p>
<p>As a milestone, 0.39.1-M1 is for early adopters and teams who want to test ahead of the full 0.39 release.
Expect rough edges, and tell us about them.</p>
<aside role="note"><p><span>Read the breaking changes first</span></p><p>This milestone requires a license, renames a feature toggle, migrates the query history schema, and removes
the legacy Jet pipeline server. Start with <a href="#breaking-changes">Breaking changes</a> before you upgrade.</p></aside>
<div><span></span><span></span></div>
<h2 id="breaking-changes"><a href="#breaking-changes">​<span></span></a>Breaking changes</h2>
<h3 id="orbital-now-requires-a-license"><a href="#orbital-now-requires-a-license">​<span></span></a>Orbital now requires a license<span><span>Breaking change</span></span></h3>
<p>Orbital checks for a <code>license.json</code> on startup. When you first sign in, Orbital contacts the license server at
<code>https://account.orbitalhq.app</code>, downloads a <strong>free</strong> license and installs it. In most environments this needs
no setup.</p>
<p>If no license is found, Orbital issues a short-lived fallback license so the server still starts — but that
fallback only lasts <strong>30 minutes</strong>, after which the UI shows a blocking overlay.</p>
<p>Orbital searches these paths in order, and the first valid license wins:</p>
<ol role="list">
<li><code>--vyne.license.path</code> (if set)</li>
<li><code>${vyne.app.data.path}/license.json</code> — by default <code>./orbital_data/license.json</code></li>
<li><code>~/.orbital/license.json</code></li>
<li><code>/opt/var/orbital/license/license.json</code></li>
</ol>
<p>For air-gapped deployments that can’t reach the license server, Orbital supports an air-gapped mode that
disables usage reporting. <a href="mailto:hello@orbitalhq.com">Get in touch</a> if you need it.</p>
<p>See <a href="https://orbitalhq.com/docs/deploying/configuring-your-license">configuring your license</a> for the full detail.</p>
<p>One improvement worth calling out: an expired license no longer terminates the JVM. The old <code>LicenseMonitor</code>
called <code>exitProcess(0)</code> on expiry. That’s gone — expiry now surfaces in the UI and is governed by the license
policy instead of killing the process.</p>
<h3 id="the-workspaces-enabled-toggle-is-replaced-by-workspace-mode"><a href="#the-workspaces-enabled-toggle-is-replaced-by-workspace-mode">​<span></span></a>The workspaces-enabled toggle is replaced by workspace-mode<span><span>Breaking change</span></span></h3>
<p>The boolean toggle is gone, replaced by a three-state enum:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>vyne</span><span>:</span></span><span><span>  </span><span>toggles</span><span>:</span></span><span><span>    </span><span>workspace-mode</span><span>:</span><span> None    </span><span># None | Workspace | OrgAndWorkspace</span></span></code></pre></div></div>
<div><table><thead><tr><th>Mode</th><th>Behaviour</th></tr></thead><tbody><tr><td><code>None</code> (default)</td><td>Single workspace. No workspace prefix in UI routes, no selector. Behaves as Orbital always has.</td></tr><tr><td><code>Workspace</code></td><td>Workspace routing. UI routes are prefixed <code>/{workspaceId}/...</code></td></tr><tr><td><code>OrgAndWorkspace</code></td><td>Org and workspace routing: <code>/{orgId}/{workspaceId}/...</code></td></tr></tbody></table></div>
<p>If you were setting <code>workspacesEnabled: true</code>, that key is now ignored and you will silently fall back to
<code>None</code>. Set <code>workspace-mode</code> instead.</p>
<aside role="note"><p><span>Use the kebab-case spelling</span></p><p>Some of the code reads this property through a <code>@Value</code> placeholder, which does not get Spring’s relaxed
binding. Always spell it <code>vyne.toggles.workspace-mode</code>, not <code>workspaceMode</code>.</p></aside>
<h3 id="query-history-tables-gain-non-null-orgid-and-workspace_slug-columns"><a href="#query-history-tables-gain-non-null-orgid-and-workspace_slug-columns">​<span></span></a>Query history tables gain non-null orgId and workspace_slug columns<span><span>Breaking change</span></span></h3>
<p>A Flyway migration adds a <code>workspace_slug</code> column across eight history tables, adds <code>orgId</code> to
<code>query_error_event</code> and <code>trace_event</code>, backfills both with <code>default</code>, and enforces <code>NOT NULL</code>. Indexes on
<code>(orgId, workspace_slug)</code> are created alongside.</p>
<p>The migration runs automatically. On instances with a large query history, the <code>SET NOT NULL</code> statements take
a table lock, so budget for some downtime on the first boot after upgrading.</p>
<p>The same migration drops the Postgres row-level-security policies on those tables. RLS was keyed on
<code>current_user</code>, which never worked with a shared connection pool. Org and workspace isolation is now enforced
in the application layer via org-membership checks and explicit <code>orgId</code> / <code>workspace_slug</code> filters on every
query.</p>
<p>Rows written before this milestone cannot be attributed to a workspace — they were never stamped — so they stay
as <code>default</code>/<code>default</code>.</p>
<h3 id="the-legacy-jet-pipeline-server-has-been-removed"><a href="#the-legacy-jet-pipeline-server-has-been-removed">​<span></span></a>The legacy Jet pipeline server has been removed<span><span>Breaking change</span><span>Removed</span></span></h3>
<p><code>pipelines/pipeline-jet</code> is gone from the build, along with the pipeline transports that only it used (S3,
SQS, Cask, file-watcher, HTTP listener, JDBC, Kafka, Redshift, logging sink, polling query input) and the
transform stage.</p>
<p>This is the standalone pipeline runner, which has been unmaintained and undocumented for a long time.
<strong>Streaming queries are unaffected</strong> — <code>stream { }</code> queries run through <code>pipelines/stream-engine</code>, which stays.</p>
<h3 id="h2-is-no-longer-a-shipped-jdbc-driver"><a href="#h2-is-no-longer-a-shipped-jdbc-driver">​<span></span></a>H2 is no longer a shipped JDBC driver<span><span>Breaking change</span><span>Removed</span></span></h3>
<p><code>H2DatabaseSupport</code> has moved to test sources. The drivers shipped to end users are now Postgres, MSSQL,
Oracle, Redshift, Snowflake and Databricks. If you had an H2 connection defined in <code>connections.conf</code>, it will
fail to resolve.</p>
<h3 id="spring-boot-4-and-jackson-3"><a href="#spring-boot-4-and-jackson-3">​<span></span></a>Spring Boot 4 and Jackson 3<span><span>Breaking change</span></span></h3>
<p>Orbital is built on Spring Boot 4.0 and Jackson 3. If you write custom Orbital extensions — custom taxi
functions, custom connectors, anything compiled against Orbital’s jars — you will need to migrate. The main
things that bite:</p>
<ul role="list">
<li>Jackson 2 → 3: the mapper and builder are immutable, and several APIs were renamed. The annotation package
is still <code>com.fasterxml</code>.</li>
<li>Spring 7 / Security 7 JSpecify nullability, and <code>: Any</code> generic bounds in Kotlin.</li>
<li>The Spring Boot 4 modular auto-config split (<code>spring-boot-health</code>, <code>-jdbc</code>, <code>-hibernate</code>, <code>-mongodb</code>, and the
matching test slices).</li>
<li>Testcontainers 1.x → 2.x, if your tests use it.</li>
</ul>
<h3 id="numeric-comparison-is-now-type--and-scale-insensitive"><a href="#numeric-comparison-is-now-type--and-scale-insensitive">​<span></span></a>Numeric comparison is now type- and scale-insensitive<span><span>Breaking change</span><span>Fixed</span></span></h3>
<p>Comparisons between numbers of different JVM types now coerce both sides to <code>BigDecimal</code> and compare with
<code>compareTo</code>. Two consequences:</p>
<ul role="list">
<li>Cross-type numeric comparisons work. Previously only a narrow set of pairings (such as <code>Int</code> vs
<code>BigDecimal</code>) compared correctly; others silently failed.</li>
<li><code>Equal</code> and <code>NotEqual</code> are now scale-insensitive. <code>2.50 == 2.5</code> is now <code>true</code> where it was previously
<code>false</code>, because <code>BigDecimal.equals</code> treats different scales as different values.</li>
</ul>
<p>Taxi’s <code>Long</code> is backed by <code>BigInteger</code>, which previously had no branch in the arithmetic calculator at all
and errored with <em>“Unsupported number type”</em>. <code>Long</code> arithmetic now works, and division on <code>Long</code> truncates —
the same semantics as <code>Int</code>.</p>
<h3 id="the-right-function-now-reads-from-the-right"><a href="#the-right-function-now-reads-from-the-right">​<span></span></a>The right() function now reads from the right<span><span>Breaking change</span><span>Fixed</span></span></h3>
<p><code>right(input, n)</code> was returning characters counted from the <em>left</em> of the string. It now returns the last <code>n</code>
characters, as the name and documentation always said. If you worked around the old behaviour, remove the
workaround.</p>
<h3 id="operation-parameters-are-no-longer-matched-to-raw-primitives-by-type"><a href="#operation-parameters-are-no-longer-matched-to-raw-primitives-by-type">​<span></span></a>Operation parameters are no longer matched to raw primitives by type<span><span>Breaking change</span><span>Fixed</span></span></h3>
<p>Given <code>operation confirm(OrderId, note : String)</code> and an <code>OrderId</code> in context, the old code would bind the
<code>OrderId</code>’s value to <code>note</code> — because everything is assignable to <code>String</code>, so a raw primitive parameter
matched whatever value happened to be nearby.</p>
<p>Parameters typed as raw primitives (<code>String</code>, <code>Int</code>, …) or <code>Any</code> are now populated only from an <strong>exact</strong>
type match already in context — never an inherited match, never a graph query. Otherwise they resolve to null
and normal nullability handling applies.</p>
<p><strong>A default declared in the signature is unaffected</strong>, because it names the parameter it belongs to rather
than being matched to it. That remains the supported way to populate a raw primitive.</p>
<p>If a schema was relying on the old behaviour, the operation will now be invoked with a null (or not invoked at
all, if the parameter is required). Give the parameter a semantic type, or a default.</p>
<h3 id="query-responses-honour-the-accept-header"><a href="#query-responses-honour-the-accept-header">​<span></span></a>Query responses honour the Accept header<span><span>Breaking change</span><span>Fixed</span></span></h3>
<p>HTTP query responses now follow standard content negotiation, in this order:</p>
<ol role="list">
<li>An explicit, specific <code>Accept</code> header wins.</li>
<li>Otherwise the response type’s declared format (<code>@Xml</code>, <code>@Csv</code>) is used.</li>
<li>Otherwise JSON.</li>
</ol>
<p>Previously the model’s declared format always won, so a model annotated <code>@Xml</code> requested with
<code>Accept: application/json</code> still came back as XML. If you have a client relying on that — sending an <code>Accept</code>
header it didn’t mean and getting the model’s format regardless — it will now get what it asked for.</p>
<p>An absent <code>Accept</code> header is treated as “no preference” rather than being forced to JSON, so it defers to the
model’s declared format. This applies uniformly to the <code>/api/taxiql</code> endpoints and to routed saved queries.
Streaming responses (SSE and WebSocket) negotiate separately and are unchanged.</p>
<h3 id="api-routes-are-workspace-prefixed-when-workspace-mode-is-enabled"><a href="#api-routes-are-workspace-prefixed-when-workspace-mode-is-enabled">​<span></span></a>API routes are workspace-prefixed when workspace mode is enabled<span><span>Breaking change</span></span></h3>
<p>In <code>Workspace</code> or <code>OrgAndWorkspace</code> mode, all workspace-scoped APIs move under <code>/api/{orgId}/{workspaceId}/...</code>,
and published query endpoints move to <code>/api/{orgId}/{workspaceId}/q/...</code>.</p>
<p>In <code>None</code> mode — the default — legacy routes such as <code>/api/schema/types</code> and <code>/api/q/myQuery</code> continue to work
exactly as before. This includes the anonymous-access security matcher, which now picks the pattern matching
the active mode.</p>
<h3 id="smaller-breaks"><a href="#smaller-breaks">​<span></span></a>Smaller breaks<span><span>Breaking change</span></span></h3>
<ul role="list">
<li><strong>The auth-token listing API changed shape.</strong> <code>GET /tokens</code> returned a flattened
<code>Map&lt;ServiceName, List&lt;AuthScheme&gt;&gt;</code>. It now returns a row-shaped listing that preserves the package each
entry came from, plus a sibling field carrying per-package parse errors.</li>
<li><strong>Git credentials in <code>workspace.conf</code> are now secret references.</strong> Inline <code>GitCredentials</code> / <code>GitSshAuth</code>
are replaced by a <code>GitAuthentication</code> reference that points at a secret name resolved through the workspace’s
secrets manager at fetch time.</li>
<li><strong>SOAP responses are parsed by JAXB element names.</strong> Responses are read using <code>@XmlElement</code> metadata and
field access rather than by introspecting CXF’s generated Java getters. This fixes acronym and casing
mangling (<code>getSISOCode</code> was becoming <code>SISOCode</code> rather than <code>sISOCode</code>), but if you had types hand-shaped to
match the old mangled names, they now need to match the WSDL names.</li>
<li><strong>UI routes renamed</strong>, with redirects in place: <code>/stubs</code> → <code>/local-environment</code>, <code>/catalog/diagram</code> →
<code>/mesh</code>, <code>/workspace</code> → <code>/workspaces</code>. The old query editor at <code>/query/editor</code> is replaced by
<code>/code-editor</code>.</li>
<li><strong>New privileges.</strong> <code>LIST_SECRETS</code> and <code>EDIT_SECRETS</code> were added and are granted to the admin and platform
manager roles in the bundled default role definitions. Deployments that already have a <code>roles.conf</code> on disk
will not pick these up automatically — Orbital only writes the defaults when the file is absent. Add them by
hand if you want the secrets UI available to existing roles.</li>
</ul>
<div><span></span><span></span></div>
<h2 id="workspaces-and-organisations"><a href="#workspaces-and-organisations">​<span></span></a>Workspaces and organisations<span><span>New</span></span></h2>
<p>A workspace is a named context that compiles to a schema. Everything schema-driven in Orbital — queries,
streams, published endpoints, the catalog, the search index — operates within one.</p>
<p>Typical uses:</p>
<ul role="list">
<li><strong>Team isolation</strong> — each team owns a workspace with its own services and types.</li>
<li><strong>Environment separation</strong> — production, staging and development in one cluster.</li>
<li><strong>Safe experimentation</strong> — test a new version of a service in a workspace without touching the others.</li>
</ul>
<p>An <strong>organisation</strong> is the tenant above that. A cluster serves one or more organisations; on-prem deployments
typically have one, and a default org is created on first boot if none exists.</p>
<h3 id="turning-it-on"><a href="#turning-it-on">​<span></span></a>Turning it on</h3>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>vyne</span><span>:</span></span><span><span>  </span><span>toggles</span><span>:</span></span><span><span>    </span><span>workspace-mode</span><span>:</span><span> OrgAndWorkspace</span></span></code></pre></div></div>
<p>When enabled, a combined org-and-workspace selector appears in the header. Collapsed, it shows the active
workspace above the active organisation; expanded, it lists the workspaces in the org, with a nested
<em>Switch organisation</em> submenu and management actions. In <code>Workspace</code> mode the org half is hidden.</p>
<p>Every page — catalog, code editor, projects, activity — is scoped to the active workspace, and the URL
reflects it.</p>
<h3 id="where-workspace-config-lives"><a href="#where-workspace-config-lives">​<span></span></a>Where workspace config lives</h3>
<p>Two things need storing: which orgs and workspaces exist, and what projects make up each workspace. Both are
configured under <code>vyne.orgs</code>:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>vyne</span><span>:</span></span><span><span>  </span><span>orgs</span><span>:</span></span><span><span>    </span><span>store</span><span>:</span><span> FILE                 </span><span># FILE | IN_MEMORY | DATABASE</span></span><span><span>    </span><span>config-path</span><span>:</span><span> ./orbital_data</span></span></code></pre></div></div>
<div><table><thead><tr><th>Backend</th><th>Best for</th><th>Writable from the UI?</th></tr></thead><tbody><tr><td><code>FILE</code> (default)</td><td>Local dev, single-node on-prem</td><td>Yes</td></tr><tr><td><code>IN_MEMORY</code></td><td>Ephemeral environments, tests</td><td>Yes, until restart</td></tr><tr><td><code>DATABASE</code></td><td>Multi-node and cloud deployments</td><td>Yes</td></tr></tbody></table></div>
<p>The file backend reads an <code>organisations.conf</code> from <code>config-path</code>, with one <code>workspace.conf</code> per workspace
underneath:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>orbital_data/</span></span><span><span>  organisations.conf</span></span><span><span>  workspaces/</span></span><span><span>    acme-bank/</span></span><span><span>      production/workspace.conf</span></span><span><span>      analytics/workspace.conf</span></span></code></pre></div></div>
<p>The database backend stores the same HOCON content as text blobs in <code>org_config</code>, <code>workspace_config_entry</code> and
<code>workspace_config</code>, using Spring Data repositories over Orbital’s existing datasource. Because the stored
content is byte-identical to the file format, you can move between backends without transforming anything.</p>
<p>Workspace config also materialises back to disk on boot, so a cloud deployment with a populated database and a
fresh disk rehydrates correctly. The file backend leaves hand-edited content alone.</p>
<aside role="note"><p><span>Git-backed org config</span></p><p>A <code>GIT</code> store type is declared in the enum but is not implemented in this milestone. Use <code>FILE</code> or <code>DATABASE</code>.</p></aside>
<h3 id="what-became-workspace-aware"><a href="#what-became-workspace-aware">​<span></span></a>What became workspace-aware</h3>
<p>The bulk of the work in 0.39 was making everything downstream of the schema respect workspace boundaries. Things
that used to be global singletons and are now per-workspace:</p>
<ul role="list">
<li><strong>Connections and invokers.</strong> Every connection-based invoker (JDBC, Kafka, MongoDB, AWS, Azure, Hazelcast,
SOAP, HTTP) is built per workspace through an <code>InvokerFactory</code>, from that workspace’s own connection registry.</li>
<li><strong><code>services.conf</code> and <code>auth.conf</code>.</strong> Service discovery and outbound auth resolve through per-workspace
registries, so HOCON substitution sees that workspace’s own environment variables. Previously a single global
registry meant <code>auth.conf</code> files discovered through a workspace’s project <code>additionalSources</code> were silently
ignored, and outbound HTTP calls went out unauthenticated.</li>
<li><strong>Hazelcast state.</strong> Operation caches, state stores and stream topics are all namespaced by workspace, so
results can’t leak across boundaries.</li>
<li><strong>The search index.</strong> Lucene indices are per workspace, stored under <code>{basePath}/{orgId}/{workspaceId}/</code>,
rebuilt only for the workspace whose schema changed.</li>
<li><strong>Query history.</strong> Every history table is stamped and filtered by org and workspace.</li>
<li><strong>The language server.</strong> LSP sessions resolve the workspace’s live schema, and schema edits are delivered to
the sessions bound to that workspace.</li>
<li><strong>WebSocket streams.</strong> Schema notifications, query status, stream results and stub updates all reconnect when
you switch workspace, and are filtered to the workspace you’re connected to.</li>
<li><strong>Query routes, scheduled queries and persistent streams.</strong> These maintain cross-workspace indices and now
subscribe to schema changes from every workspace, including ones created at runtime.</li>
</ul>
<p>Workspaces created through the API or by dropping a directory on disk are registered live — no restart needed
for schema compilation, search indexing or route registration.</p>
<h3 id="org-scoped-authorization"><a href="#org-scoped-authorization">​<span></span></a>Org-scoped authorization<span><span>New</span><span>Security</span></span></h3>
<p><code>@RequiresOrgPrivilege</code> replaces <code>@PreAuthorize(&quot;hasAuthority(...)&quot;)</code> across roughly 150 production endpoints.
It resolves the request’s <code>{orgId}</code> path variable and delegates the decision to an <code>OrgAuthorityService</code>, which
has two implementations:</p>
<ul role="list">
<li>The default is org-blind and checks the flat authority set, preserving behaviour for single-org and
non-PropelAuth deployments.</li>
<li>When <code>vyne.security.open-idp.roles.format=propelauth</code>, per-org roles are read from the JWT’s
<code>org_id_to_org_member_info</code> claim.</li>
</ul>
<p>This unblocks users who belong to multiple organisations, who previously hit
<em>“You are a member of multiple organisations”</em>.</p>
<p>Org membership is now enforced on the workspace endpoints themselves. Previously any authenticated user could
list or create workspaces in any tenant by putting that tenant’s slug in the URL. Organisations are also
auto-provisioned from JWT claims on first sign-in, so workspace creation works on a fresh deployment.</p>
<div><span></span><span></span></div>
<h2 id="copilot"><a href="#copilot">​<span></span></a>Copilot<span><span>New</span></span></h2>
<p>Copilot is a chat interface to your data mesh. It runs in two modes:</p>
<ul role="list">
<li><strong>Ask</strong> — natural-language questions answered by generating and running a TaxiQL query against the current
workspace. <em>“What’s Jim Patterson’s account balance?”</em>, or <em>“write me a query that joins orders to
customers”</em>.</li>
<li><strong>Build</strong> — an agent with file-editing tools that works on your Taxi projects, streaming its edits directly
into the code editor beside the conversation.</li>
</ul>
<p>The mode is chosen before you send the first message, and pinned for the life of the conversation — reopening
a conversation restores the mode it was started with.</p>
<p>Conversations are persisted with their history, can be renamed, and are listed in a sidebar. File uploads are
supported and scoped to the workspace. In Build mode, edits stream into Monaco models as they arrive, so you
watch the agent write.</p>
<h3 id="configuring-it"><a href="#configuring-it">​<span></span></a>Configuring it</h3>
<p>Copilot is a separate service. Point Orbital at it and turn on the toggle:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>vyne</span><span>:</span></span><span><span>  </span><span>toggles</span><span>:</span></span><span><span>    </span><span>copilot-enabled</span><span>:</span><span> </span><span>true</span></span><span><span>  </span><span>copilot</span><span>:</span></span><span><span>    </span><span>endpoint-url</span><span>:</span><span> http</span><span>:</span><span>//localhost</span><span>:</span><span>9028</span></span><span><span>    </span><span>upload-store</span><span>:</span><span> local</span></span><span><span>    </span><span>local-store-path</span><span>:</span><span> ./orbital_data/copilot/uploads</span></span></code></pre></div></div>
<p>Requests to the Copilot service carry the caller’s JWT, and all calls are scoped to the current org and
workspace.</p>
<h3 id="mcp-server"><a href="#mcp-server">​<span></span></a>MCP server<span><span>New</span></span></h3>
<p>Orbital exposes a <a href="https://modelcontextprotocol.io" target="_blank" rel="noreferrer">Model Context Protocol</a> server, so Claude, Cursor, IDE
agents and your own tooling can ask the same questions a Copilot user can.</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>vyne</span><span>:</span></span><span><span>  </span><span>toggles</span><span>:</span></span><span><span>    </span><span>mcp-server-enabled</span><span>:</span><span> </span><span>true</span></span></code></pre></div></div>
<p>One endpoint is mounted per workspace:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>/api/{orgId}/{workspaceId}/mcp</span></span></code></pre></div></div>
<p>Mounting it under the workspace path means it inherits the existing org-membership gate from the security
filter chain. No tool takes <code>orgId</code> or <code>workspaceId</code> as an argument — the URL is the only source, so an MCP
client can’t reach across into another tenant’s data by changing a parameter.</p>
<p>The server exposes a single <code>ask</code> tool:</p>
<div><table><thead><tr><th>Field</th><th>Description</th></tr></thead><tbody><tr><td><code>question</code></td><td>The question, in natural language</td></tr><tr><td><code>execute</code></td><td>Run the generated query and return rows, or just show the query that would run</td></tr></tbody></table></div>
<p>It answers with the natural-language <code>answer</code>, the generated <code>query</code>, a <code>queryHistoryId</code> you can use to
inspect the run in Orbital’s history, the result <code>rows</code>, and any <code>queryError</code> or <code>diagnostics</code>.</p>
<p>The tool description and the server’s MCP <code>instructions</code> are generated from the workspace’s own schema, so
clients know what data they’re pointed at.</p>
<p>Authentication accepts a PropelAuth API key presented the standard way — <code>Authorization: Bearer &lt;token&gt;</code> —
which is what MCP clients send. Orbital now discriminates structurally: a bearer credential shaped like a JWT
is validated as one, anything else is validated as an opaque API key. Previously an API key had to be sent
<em>without</em> the <code>Bearer</code> prefix, which MCP clients can’t do.</p>
<div><span></span><span></span></div>
<h2 id="the-new-code-editor"><a href="#the-new-code-editor">​<span></span></a>The new code editor<span><span>New</span></span></h2>
<p>The old single-query editor is replaced by a multi-file editor at <code>/code-editor</code>.</p>
<ul role="list">
<li><strong>A real file tree.</strong> It walks the project on disk, so <code>taxi.conf</code>, READMEs, <code>connections.conf</code>, nebula
scripts and everything else is visible — not just <code>.taxi</code> files. Content is fetched lazily when you click.
Per-file error counts show in the tree.</li>
<li><strong>Split panels.</strong> Editors, query results and query history live in dockable panels you can arrange, and the
layout persists across refreshes — keyed by workspace, so switching org or workspace doesn’t restore the
wrong location’s panels.</li>
<li><strong>File lifecycle.</strong> Right-click to rename or delete. Both flow through the same compile-after-change pipeline
as content edits, with atomic moves for renames.</li>
<li><strong>Save anything.</strong> Saving no longer runs every source in the package through the Taxi compiler and rejects
the write on any error. Non-Taxi files are excluded from compilation entirely, and Taxi files with
compilation errors save anyway, with the errors surfaced in the UI. The editor’s job is to write what you
typed.</li>
<li><strong>Language support</strong> is auto-detected from the file extension. Markdown renders. Unmapped types open as
plain text instead of failing.</li>
</ul>
<p>Two long-standing editor bugs are fixed. Editing or saving a file used to produce
<code>Symbol X is already declared</code> errors for every symbol in the file, caused by the same file being registered
under two different URIs — once through the language server and once through the schema editor’s in-memory
edit application. And edits to files outside <code>src/</code> were being nested under <code>src/</code>, while edits already
addressed with a <code>src/</code> prefix were double-nested at <code>src/src/...</code>.</p>
<div><span></span><span></span></div>
<h2 id="secrets-management"><a href="#secrets-management">​<span></span></a>Secrets management<span><span>New</span></span></h2>
<p>Secrets are now first-class. Reference one anywhere in your config the same way you’d reference an environment
variable:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>connections.jdbc.warehouse </span><span>{</span></span><span><span>   </span><span>url</span><span>:</span><span>      </span><span>&quot;jdbc:postgresql://warehouse.example.com:5432/prod&quot;</span></span><span><span>   </span><span>password</span><span>:</span><span> $</span><span>{</span><span>secrets.DB_PASSWORD</span><span>}</span></span><span><span>}</span></span></code></pre></div></div>
<p>Real values never enter the merged HOCON config. The placeholder resolves to an opaque token that the consumer
resolves at the point of use — at connection time, at outbound-request time, at git-fetch time — so a secret
lives in a call frame and never in long-lived state. Rotating a secret takes effect without a restart.</p>
<h3 id="backends"><a href="#backends">​<span></span></a>Backends</h3>
<p>Pick one with <code>vyne.secrets.backend</code>:</p>
<div><table><thead><tr><th>Value</th><th>Backend</th></tr></thead><tbody><tr><td><code>InMemory</code> (default)</td><td>In-process. Tests and demos only.</td></tr><tr><td><code>File</code></td><td>Local file, age-encrypted (X25519 + ChaCha20-Poly1305). Dev only — the key sits next to the data.</td></tr><tr><td><code>Infisical</code></td><td><a href="https://infisical.com" target="_blank" rel="noreferrer">Infisical</a>, cloud or self-hosted, via universal auth</td></tr><tr><td><code>Aws</code></td><td><a href="https://aws.amazon.com/secrets-manager/" target="_blank" rel="noreferrer">AWS Secrets Manager</a></td></tr><tr><td><code>Vault</code></td><td><a href="https://www.vaultproject.io/" target="_blank" rel="noreferrer">HashiCorp Vault</a> KV v2</td></tr><tr><td><code>Gcp</code></td><td><a href="https://cloud.google.com/secret-manager" target="_blank" rel="noreferrer">Google Cloud Secret Manager</a></td></tr></tbody></table></div>
<p>Each backend maps Orbital’s scope hierarchy onto its own naming rules — paths in Vault and Infisical, flat
prefixed names in AWS, <code>__</code>-separated segments in GCP, whose names can’t contain slashes.</p>
<h3 id="scopes"><a href="#scopes">​<span></span></a>Scopes</h3>
<div><table><thead><tr><th>Scope</th><th>Visible to</th></tr></thead><tbody><tr><td><code>Server</code></td><td>every workspace on this server</td></tr><tr><td><code>Organisation</code></td><td>every workspace in that organisation</td></tr><tr><td><code>Workspace</code></td><td>only that workspace</td></tr></tbody></table></div>
<p>Reads cascade — workspace, then organisation, then server — and the narrower scope wins on a name collision.
There is no global namespace that bypasses scoping.</p>
<h3 id="managing-them"><a href="#managing-them">​<span></span></a>Managing them</h3>
<p>Secrets are managed in the UI under <strong>Secrets</strong>, and over REST:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>GET    /api/{orgId}/{workspaceId}/secrets</span></span><span><span>GET    /api/{orgId}/{workspaceId}/secrets/{scope}</span></span><span><span>POST   /api/{orgId}/{workspaceId}/secrets/{scope}</span></span><span><span>PUT    /api/{orgId}/{workspaceId}/secrets/{scope}/{name}</span></span><span><span>DELETE /api/{orgId}/{workspaceId}/secrets/{scope}/{name}</span></span><span><span>POST   /api/{orgId}/{workspaceId}/secrets/refresh</span></span></code></pre></div></div>
<p>Reads need <code>LIST_SECRETS</code>, writes need <code>EDIT_SECRETS</code>. <strong>No endpoint ever returns a secret value</strong> — responses
carry name, scope, description, last-updated and version only. Server-scoped secrets are listable but
operator-managed: writes to that scope are rejected with a 403.</p>
<p>A caller at <code>/api/acme/prod/...</code> can only touch <code>Workspace(acme/prod)</code> and <code>Organisation(acme)</code> — not another
org’s or another workspace’s secrets.</p>
<p>Every backend is wrapped in a caching decorator with a 15-minute TTL (configurable via
<code>vyne.secrets.cache.ttl</code> and <code>.max-size</code>), write-through invalidation, and the <code>refresh</code> endpoint above for
forcing a reload after rotating a secret out of band.</p>
<h3 id="git-authentication"><a href="#git-authentication">​<span></span></a>Git authentication<span><span>New</span></span></h3>
<p>Adding a git project now captures credentials — none, username/password, token, or SSH key — as references to
secrets rather than as credentials embedded in <code>workspace.conf</code> and travelling through git. The UI rejects
plaintext entries at submit, since they would defeat the point.</p>
<p>Credentials resolve inside JGit’s <code>configure(transport)</code> call. SSH keys load as bytes, so no key is ever
written to a temp file.</p>
<p>See <a href="https://orbitalhq.com/docs/deploying/managing-secrets">managing secrets</a> for the full setup.</p>
<div><span></span><span></span></div>
<h2 id="data-validation"><a href="#data-validation">​<span></span></a>Data validation<span><span>New</span></span></h2>
<p>You can now declare validation rules against your types, and control what happens when data breaks them.
Because rules are declared against <strong>types</strong>, you define them once and they’re enforced everywhere that type
appears, whichever service the data came from.</p>
<p>Three parts: <strong>declare</strong> rules with annotations, <strong>activate</strong> them with <code>@Valid</code>, <strong>decide</strong> what happens with
<code>@OnValidationFailure</code>.</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>import</span><span> com</span><span>.</span><span>orbitalhq</span><span>.</span><span>validation</span><span>.</span><span>NotEmpty</span></span><span><span>import</span><span> com</span><span>.</span><span>orbitalhq</span><span>.</span><span>validation</span><span>.</span><span>Valid</span></span><span>
</span><span><span>@</span><span>NotEmpty</span></span><span><span>type</span><span> </span><span>Name</span><span> </span><span>inherits</span><span> </span><span>String</span></span><span>
</span><span><span>@</span><span>Valid</span></span><span><span>model</span><span> </span><span>Person</span><span> </span><span>{</span></span><span><span>   name</span><span> </span><span>:</span><span> Name</span></span><span><span>}</span></span></code></pre></div></div>
<p>A <code>Person</code> arriving as <code>{ &quot;name&quot;: &quot;&quot; }</code> produces one violation — rule <code>com.orbitalhq.validation.NotEmpty</code>, at
path <code>name</code>, severity <code>Error</code> — and by default rejects the query with an HTTP 400. Remove the <code>@Valid</code> and the
same data flows through untouched. Rules do nothing until something activates them.</p>
<h3 id="the-built-in-rules"><a href="#the-built-in-rules">​<span></span></a>The built-in rules</h3>
<p><code>@NotEmpty</code>, <code>@MinLength</code>, <code>@MaxLength</code>, <code>@Pattern</code>, <code>@Min</code>, <code>@Max</code>, <code>@MultipleOf</code>, <code>@MinItems</code>, <code>@MaxItems</code>,
<code>@UniqueItems</code>, <code>@Email</code>, <code>@Uuid</code>. That’s feature parity with OpenAPI’s schema validations. Every rule takes an
optional <code>message</code> and <code>severity</code> (<code>Info</code>, <code>Warning</code> or <code>Error</code>).</p>
<p>Rules can go on a type, a field, or a query parameter, and they’re inherited — a rule on <code>Name</code> applies to
every type inheriting from it.</p>
<p>Two rule ids are produced by the engine rather than declared: <code>NotNull</code>, when a non-nullable field inside a
<code>@Valid</code> scope holds a null, and <code>ParseFailure</code>, when a value can’t be parsed into its declared type.</p>
<aside role="note"><p><span>@Valid also turns on nullability enforcement</span></p><p>Type-system nullability has historically been declared but not enforced. Inside a <code>@Valid</code> scope it is. This
is opt-in — nothing changes for schemas that don’t use <code>@Valid</code> — but expect to find violations the first
time you switch it on for an existing model.</p></aside>
<h3 id="deciding-what-happens"><a href="#deciding-what-happens">​<span></span></a>Deciding what happens</h3>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>@</span><span>OnValidationFailure</span><span>(</span><span>action </span><span>=</span><span> ValidationAction</span><span>.</span><span>Warn</span><span>,</span><span> threshold </span><span>=</span><span> Severity</span><span>.</span><span>Error</span><span>)</span></span><span><span>query</span><span> </span><span>GetOrder</span><span> </span><span>{</span></span><span><span>   </span><span>find</span><span> </span><span>{</span><span> Order</span><span> </span><span>}</span></span><span><span>}</span></span></code></pre></div></div>
<div><table><thead><tr><th>Action</th><th>Behaviour</th></tr></thead><tbody><tr><td><code>Reject</code></td><td>Fails the request with an HTTP 400 and a structured violation report</td></tr><tr><td><code>Warn</code></td><td>Data passes through. Violations are still logged and reported</td></tr><tr><td><code>Drop</code></td><td>Skips the offending record and keeps going. Never silent — every drop is reported</td></tr></tbody></table></div>
<p><code>threshold</code> sets the minimum severity that triggers the action. <strong>All violations are reported regardless of
threshold</strong> — the threshold only decides which are severe enough to act on. That pairs well with per-rule
severity: mark rules you’re not yet confident about as <code>Warning</code>, watch them in your logs, promote them to
<code>Error</code> once you trust them.</p>
<p>Defaults are per query kind: <code>find</code> rejects at <code>Error</code>, <code>stream</code> drops at <code>Error</code>. Query arguments always
reject — dropping a record makes no sense when the record is the caller’s own input.</p>
<p>Violation paths are precise: <code>cast.actors[1].actor.name</code>, not just “somewhere in the response”.</p>
<p>Validation runs on query arguments, on data returned by services, and on streaming pipeline inputs.</p>
<p>See <a href="https://orbitalhq.com/docs/data-validation/data-validation">validating data</a> and the
<a href="https://orbitalhq.com/docs/data-validation/validation-rules">rule reference</a>.</p>
<div><span></span><span></span></div>
<h2 id="data-sources"><a href="#data-sources">​<span></span></a>Data sources</h2>
<h3 id="oracle"><a href="#oracle">​<span></span></a>Oracle<span><span>New</span></span></h3>
<p>Orbital now ships an Oracle driver, with full write support: <code>Insert</code> and generated-primary-key <code>Upsert</code> use
<code>INSERT ... RETURNING</code>, <code>Update</code> runs per-row batches, and a user-supplied-PK <code>Upsert</code> uses <code>MERGE</code>. Oracle’s
<code>MERGE</code> can’t return rows, so the invoker echoes the input back, matching how the Postgres upsert behaves.</p>
<p>Table generation accounts for Oracle lacking <code>CREATE INDEX IF NOT EXISTS</code> and needing explicit lengths on
indexed <code>VARCHAR2</code> / <code>CLOB</code> columns. jOOQ’s dialect is resolved by probing the live connection rather than
assuming a version, so Orbital doesn’t emit <code>CREATE TABLE IF NOT EXISTS</code> (23ai and later only) against an
older database. The probe is cached per connection.</p>
<p>Metadata reads are scoped to the connecting user’s schema. Oracle has no schema concept separate from the
user, so without that scoping Orbital crawled <code>SYS</code>, <code>SYSTEM</code> and every other user’s schema.</p>
<h3 id="database-metadata-is-read-directly-and-scoped"><a href="#database-metadata-is-read-directly-and-scoped">​<span></span></a>Database metadata is read directly, and scoped<span><span>Improved</span><span>Fixed</span></span></h3>
<p>Table introspection — the connection UI’s table list, and the schema generator behind <em>import from database</em> —
was built on SchemaCrawler, which required a full catalog crawl. On a warehouse that’s slow to the point of
unusable, and it had no plugin support for Snowflake or Databricks.</p>
<p>It’s been replaced with targeted <code>DatabaseMetaData</code> calls. What that changes for you:</p>
<ul role="list">
<li><strong>The reactive server no longer stalls.</strong> <code>listConnectionTables</code> and <code>getTableMetadata</code> ran their blocking
JDBC calls on the Netty event loop, which starved the whole server until it was restarted. They now run on
a bounded elastic scheduler.</li>
<li><strong>Listing tables returns names only.</strong> Column, primary-key and index metadata were an extra round-trip per
table, on a screen that only needs names. They’re opt-in now, via <code>includeColumns</code> / <code>includeIndexes</code> query
parameters on the tables endpoint.</li>
<li><strong>Generating Taxi for one table is independent of database size.</strong> It reads the tables you asked for plus
the ones their foreign keys reference, one level deep, rather than crawling the whole schema.</li>
<li><strong>Better type coverage.</strong> <code>CLOB</code> maps to <code>String</code> instead of failing generation outright, and Postgres
domain types map to <code>Any</code> rather than erroring.</li>
</ul>
<h3 id="databricks-and-snowflake"><a href="#databricks-and-snowflake">​<span></span></a>Databricks and Snowflake<span><span>New</span></span></h3>
<p><strong>Databricks</strong> is new. Hostname, port, HTTP path and token are the user-facing parameters; <code>AuthMech=3</code> and
<code>UID=token</code> are baked into the URL template so you don’t see them.</p>
<p><strong>Snowflake</strong> existed as a twelve-line shell that had never been used in anger, with its JDBC driver commented
out of the build because the fat jar broke shading. It’s been rebuilt: region is now an optional URL parameter,
and the thin driver replaces the fat one — no shading problems, no broken native build.</p>
<p>Neither platform supports the <code>ON CONFLICT</code> syntax the other drivers use for upserts, so both build a
<code>MERGE INTO</code> statement instead. That needs something to match existing rows on, so when a primary key column
isn’t among the written fields — a <code>@GeneratedId</code> key, for instance — the write falls back to a plain
<code>INSERT</code> and logs a warning. It’s a warning rather than a silent fallback because rows can duplicate under an
<code>@UpsertOperation</code> when it happens.</p>
<p>Driver-specific column unwrapping moved off the base JDBC invoker onto the driver itself, so Postgres owns its
<code>PGobject</code> / <code>PgArray</code> handling and any driver returning its own wrapper types can be supported cleanly.</p>
<h3 id="mongodb"><a href="#mongodb">​<span></span></a>MongoDB<span><span>New</span></span></h3>
<p>MongoDB connections can now be created and tested from the UI. The driver was already listed in the connections
editor, but test and create posted nowhere — the UI had no URL mapping for NoSQL connectors and the backend had
no endpoint. Both now exist, and MongoDB has a health-check provider like the other connectors.</p>
<h3 id="connection-failures-surface-properly"><a href="#connection-failures-surface-properly">​<span></span></a>Connection failures surface properly<span><span>Fixed</span></span></h3>
<p>A database-backed saved query invoked through a routed HTTP endpoint used to return <code>200 OK</code> with an empty body
when its connection was undefined or unreachable — indistinguishable from a query that legitimately matched
nothing.</p>
<p>Connectors now raise typed exceptions whose HTTP status comes from the exception itself:</p>
<div><table><thead><tr><th>Condition</th><th>Status</th></tr></thead><tbody><tr><td>Schema references an undefined connection</td><td>500</td></tr><tr><td>Connection defined but upstream unreachable</td><td>502</td></tr></tbody></table></div>
<p>JDBC connection failures are also reported as trace events, so they show up in the query profile rather than
vanishing.</p>
<h3 id="deletes-and-native-sql"><a href="#deletes-and-native-sql">​<span></span></a>Deletes and native SQL<span><span>New</span></span></h3>
<p><code>@DeleteOperation</code> gives you type-safe deletes through TaxiQL. A single <code>@Id</code> renders <code>WHERE pk IN (...)</code>,
composite keys use row-value <code>IN</code>, and statements are chunked at 500 rows to stay under Oracle’s IN-list cap.
Values are always bound, never inlined. The operation returns a <code>deletedCount</code>.</p>
<p><code>@SqlQuery</code> lets you write the SQL yourself — joins, aggregations, dialect-specific statements — for the cases
where the generated query isn’t what you want. One annotation covers reads and native DML, split by taxi’s
<code>write</code> keyword. Reads map joined and aggregated rows onto plain models by column name or alias, with no
<code>@Table</code> needed; writes return the affected-row count.</p>
<p><code>:param</code> placeholders bind as real prepared-statement parameters, validated against the operation’s parameters
before execution. Values never touch the SQL text.</p>
<p>Both were <a href="https://orbitalhq.com/changelog/2026-07-16-jdbc-deletes-and-native-sql">announced in July</a>, and this is the first build
they ship in.</p>
<h3 id="also"><a href="#also">​<span></span></a>Also</h3>
<ul role="list">
<li>Overriding a service in <code>services.conf</code> can now downgrade from <code>https</code> to <code>http</code>, which it previously
refused to do.</li>
</ul>
<div><span></span><span></span></div>
<h2 id="query-engine"><a href="#query-engine">​<span></span></a>Query engine</h2>
<h3 id="collection-options-limit-sort-paginate-and-dedupe"><a href="#collection-options-limit-sort-paginate-and-dedupe">​<span></span></a>Collection options: limit, sort, paginate and dedupe<span><span>New</span></span></h3>
<p>You can shape the results of a query directly in TaxiQL — limiting how many rows come back, paginating through
them, sorting them, and removing duplicates:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>find</span><span> </span><span>{</span><span> Person</span><span>[</span><span>]</span><span>(</span><span> CountryCode </span><span>==</span><span> </span><span>&quot;GB&quot;</span><span>,</span><span> orderBy</span><span>:</span><span> DateOfBirth</span><span> desc</span><span>,</span><span> offset</span><span>:</span><span> </span><span>20</span><span>,</span><span> limit</span><span>:</span><span> </span><span>10</span><span> </span><span>)</span><span> </span><span>}</span></span></code></pre></div></div>
<p><code>limit</code>, <code>offset</code>, <code>orderBy</code> and <code>uniqueBy</code> are the standard database-style controls, and they work on <strong>any</strong>
query, against any source — not just databases.</p>
<p>Sort by more than one field, and paginate:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>find</span><span> </span><span>{</span><span> Person</span><span>[</span><span>]</span><span>(</span><span> orderBy</span><span>:</span><span> </span><span>[</span><span>CountryCode asc</span><span>,</span><span> DateOfBirth desc</span><span>]</span><span>,</span><span> offset</span><span>:</span><span> </span><span>40</span><span>,</span><span> limit</span><span>:</span><span> </span><span>20</span><span> </span><span>)</span><span> </span><span>}</span></span></code></pre></div></div>
<p>They work on projections too, including nested collections, which is handy for trimming child records per
parent:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>find</span><span> </span><span>{</span><span> Customer</span><span>[</span><span>]</span><span> </span><span>}</span><span> </span><span>as</span><span> </span><span>{</span></span><span><span>  name</span><span> </span><span>:</span><span> CustomerName</span></span><span><span>  </span><span>// Only the 20 most recent transactions per customer</span></span><span><span>  transactions</span><span> </span><span>:</span><span> Transaction</span><span>[</span><span>]</span><span>(</span><span> limit</span><span>:</span><span> </span><span>20</span><span>,</span><span> orderBy</span><span>:</span><span> TransactionDate</span><span> desc </span><span>)</span></span><span><span>}</span><span>[</span><span>]</span></span></code></pre></div></div>
<p>Values can be literals or query parameters, so <code>limit: maxRows</code> works when <code>maxRows</code> is a query argument.</p>
<p><strong>Pushdown is decided per option, per data source.</strong> When a source can apply an option itself, Orbital pushes
the work down to it; when it can’t, Orbital does it after fetching. Either way you get the same answer, and
pushdown only happens when it can’t change the result — if a source can’t sort, Orbital won’t push a <code>limit</code>
below the missing sort, because limiting before sorting returns the wrong rows.</p>
<div><table><thead><tr><th>Source</th><th>Pushed down</th></tr></thead><tbody><tr><td>SQL databases (Postgres, MySQL, MSSQL, Oracle, Redshift, Snowflake, Databricks)</td><td><code>limit</code>, <code>offset</code>, and <code>orderBy</code> when every sort term resolves to a single column — rendered in your driver’s dialect</td></tr><tr><td>MongoDB</td><td><code>limit</code>, <code>offset</code> and <code>orderBy</code>, as <code>sort</code> / <code>skip</code> / <code>limit</code></td></tr><tr><td>Hazelcast</td><td><code>limit</code>, as a key-ordered page</td></tr><tr><td>REST APIs, Kafka, everything else</td><td>Nothing — Orbital applies all of it after fetching</td></tr></tbody></table></div>
<p><code>uniqueBy</code> is never pushed down; it’s always applied by Orbital. Operations annotated with <code>@SqlQuery</code> opt out
of pushdown entirely, since options can’t be spliced into SQL you wrote by hand — they’re applied after the
fetch instead.</p>
<p>On streaming queries, <code>limit</code> is supported and completes the stream once it has emitted N items. <code>orderBy</code>,
<code>offset</code> and <code>uniqueBy</code> are rejected on streams, as is cursor pagination (<code>after</code> / <code>before</code>), which parses but
is not yet implemented.</p>
<p>This was <a href="https://orbitalhq.com/changelog/2026-07-04-collection-options">announced in July</a> — 0.39.1-M1 is the first build it ships in.
Full detail is in the <a href="https://orbitalhq.com/docs/querying/collection-options">collection options docs</a>.</p>
<h3 id="operation-parameters-are-gathered-consistently"><a href="#operation-parameters-are-gathered-consistently">​<span></span></a>Operation parameters are gathered consistently<span><span>Fixed</span></span></h3>
<p>Parameters were being gathered in four separate places that disagreed with each other: the mutation path, the
graph-search path, the direct-invocation path, and again inside the invoker. The same call could bind a value
to the wrong parameter on one path, send <code>null</code> on another, and ignore a declared default entirely on a third.
An operation could also be invoked with fewer arguments than it declares, because the graph path caught any
discovery failure and quietly dropped that parameter.</p>
<p>There is now one shared implementation returning an explicit map of parameter to value. Callers differ in what
they do when it can’t be satisfied — direct invocation tries another candidate, graph search fails the edge,
mutation returns a null — but they all gather the same way.</p>
<p>The operation-result cache is keyed off that map, too. Keyed off a set, as it was,
<code>getEligibility(orderId=A, lineId=B)</code> and <code>getEligibility(orderId=B, lineId=A)</code> shared a cache entry.</p>
<p>Nullable parameters that can be constructed from context now are. Previously <code>discover</code> short-circuited to null
the moment it saw a nullable parameter, so a nullable request body whose fields were all present in context was
sent as <code>null</code>.</p>
<h3 id="circular-type-references-no-longer-blow-the-stack"><a href="#circular-type-references-no-longer-blow-the-stack">​<span></span></a>Circular type references no longer blow the stack<span><span>Fixed</span></span></h3>
<p>A model whose definition leads back to itself — <code>total : Total = (Total * 1.2)</code>, or a pair of types whose
expressions reference each other — recursed until the JVM threw <code>StackOverflowError</code>.</p>
<p>A closed loop now yields a null carrying the cycle path — <code>Order.total -&gt; Order.total</code>, or <code>A -&gt; B -&gt; A</code> —
rather than throwing. Circular definitions are now <em>legible</em>, not valid; they remain unsatisfiable.</p>
<p>This matters more than it looks. <code>StackOverflowError</code> isn’t recoverable the way an exception is: if it lands
while a class is initialising, that class stays unusable for the life of the JVM and every later touch throws
<code>NoClassDefFoundError</code>. We hit exactly that during a benchmark run — it broke coroutine cancellation
process-wide, with no error naming the cause.</p>
<h3 id="collecting-arrays-across-collection-boundaries"><a href="#collecting-arrays-across-collection-boundaries">​<span></span></a>Collecting arrays across collection boundaries<span><span>Fixed</span></span></h3>
<p>A query like <code>find { GivenName[] }</code>, against a response whose <code>givenNames</code> sit two collection layers deep
inside the returned object, failed with <em>“no data sources can return GivenName[]”</em>. The query graph only had
scalar attribute edges, so there was no path.</p>
<p>There’s now an edge from each provided instance to every <code>T[]</code> reachable via a path crossing at least one
collection field. Its cost sits between cheap attribute navigation and remote operation invocation, so a direct
attribute path still wins when one exists, but the planner always prefers in-memory extraction over calling a
service again.</p>
<p>A service returning no matching instances yields an empty <code>T[]</code> rather than failing the query.</p>
<h3 id="query-errors-reach-the-error-view"><a href="#query-errors-reach-the-error-view">​<span></span></a>Query errors reach the error view<span><span>Fixed</span></span></h3>
<p>Several places in the engine caught exceptions and returned a null or an empty result without telling anyone,
so genuine failures never reached the query error view. Failures that are actually meaningful — a nullable
operation parameter that couldn’t be constructed, unexpected exceptions while searching for a type — now
publish to the error stream that feeds the errors websocket and query history.</p>
<p>Routine search backtracking is deliberately left silent. It’s normal control flow, it fires per row during
projection, and surfacing it would flood the view with alarming noise.</p>
<p>Separately, fast-failing queries used to tear down their error stream before the UI could connect to it, so the
same query would only intermittently show its errors. The error publisher keeps a 30-second replay buffer for
exactly this reason; eviction is now deferred past the replay window so a late-connecting websocket can still
drain it.</p>
<h3 id="also-in-the-engine"><a href="#also-in-the-engine">​<span></span></a>Also in the engine<span><span>Fixed</span></span></h3>
<ul role="list">
<li>A TaxiQL statement that fails to compile returns <strong>400 Bad Request</strong> rather than 500.</li>
<li>Failed searches capture where and why they failed, with a readable display of the failure point.</li>
<li>Graph search error reporting is more informative, and the error message now hints when a <code>find</code> with a
contract would be better expressed as a <code>given {}</code>.</li>
<li>Fact-bag lookups had lost their combine, dedupe and absent semantics when they moved to an <code>Either</code>-based
API: deep searches silently dropped all secondary-bag matches whenever the primary bag had any match, merged
collections skipped deduplication, and “absent everywhere” was reported as an empty collection rather than a
null — which stopped the object builder falling through to discovery. All three are restored.</li>
<li>Data policies are no longer applied to primitive types.</li>
<li>Projections no longer attempt to construct scalar types, and fields carrying expressions are deferred to
expression evaluation rather than being built directly.</li>
<li>Object construction no longer throws when the type is nullable, matching field construction.</li>
</ul>
<h3 id="performance"><a href="#performance">​<span></span></a>Performance<span><span>Improved</span></span></h3>
<p>This milestone adds a benchmark suite and CI guards rather than a broad optimisation pass. <code>query-engine-benchmarks</code>
carries seeded synthetic schema and data generators, 13 workloads, 7 JMH micro-benchmarks, and a guard suite
that gates merge requests on deterministic metrics — operation invocation counts, allocation budgets,
complexity-class scaling ratios and heap-slope leak checks — while tracking wall-clock time as a nightly trend
rather than a flaky gate.</p>
<p>One fix landed alongside it: fact-bag search caching now validates lazily on read against a generation stamp,
so adding a fact is O(1) rather than doing predicate work proportional to every cached search. Measured 86–93%
off <code>addFact</code>, with lookup cost flat.</p>
<p>A full review of the engine’s performance characteristics is written up internally. The remaining findings are
the fix programme for subsequent releases, and each has a matching benchmark guard waiting to be switched on.</p>
<div><span></span><span></span></div>
<h2 id="ui"><a href="#ui">​<span></span></a>UI<span><span>Improved</span></span></h2>
<p>The navigation has been reorganised:</p>
<div><table><thead><tr><th>Was</th><th>Now</th></tr></thead><tbody><tr><td>Query editor</td><td><strong>Code editor</strong> — the new multi-file editor</td></tr><tr><td>Query history</td><td><strong>Activity</strong> — running queries and history in one paginated view</td></tr><tr><td>Authentication</td><td><strong>Secrets</strong></td></tr><tr><td>Stub Servers</td><td><strong>Local environments</strong></td></tr><tr><td>Catalog → Diagram tab</td><td><strong>Mesh</strong> — promoted to a top-level item</td></tr><tr><td>—</td><td><strong>Copilot</strong></td></tr></tbody></table></div>
<h3 id="endpoints"><a href="#endpoints">​<span></span></a>Endpoints<span><span>New</span></span></h3>
<p>The endpoint page is now tabbed, matching the catalog layout:</p>
<ul role="list">
<li><strong>Overview</strong> — query plan diagram and metrics</li>
<li><strong>Schema</strong> — the model attribute tree for the query’s return type</li>
<li><strong>OpenAPI</strong> — a generated OpenAPI spec, for non-streaming queries</li>
<li><strong>Source</strong> — the query source</li>
</ul>
<p>A new endpoint, <code>GET /api/schemas/queries/{queryName}/openapi</code>, generates the spec for any saved query by name.
The existing <code>/api/q/meta/{queryName}/oas</code> only covered HTTP-routable queries.</p>
<p>Published query URLs shown in the UI now match where the endpoint is actually served — previously the raw
declared URL was shown, which didn’t match the workspace-prefixed route.</p>
<h3 id="local-environments"><a href="#local-environments">​<span></span></a>Local environments<span><span>Fixed</span></span></h3>
<p>Three unhappy paths on the Local Environments page used to fail silently or mislead:</p>
<ul role="list">
<li><strong>Compilation errors.</strong> A nebula script that failed to compile produced no feedback at all — the Nebula
server killed the websocket handler. Per-stack compilation errors are now accumulated and listed against
their stack, clearing when a corrected version compiles.</li>
<li><strong>Disconnected empty state.</strong> With nebula files defined but the server unreachable, the page claimed no
environments were defined. It now shows <em>“Waiting to connect…”</em> with the names of the stacks it knows
about from the schema.</li>
<li><strong>Component start failures.</strong> An invalid DDL or similar now shows its message in the tree tooltip, as a
banner on the component detail panel, and as a red Failed state in the status bar — which previously showed
<em>“Starting…”</em> forever.</li>
</ul>
<p>Two connection bugs are fixed too. A dropped session (a network blip, or a non-text control frame) used to kill
the consumer coroutine permanently: the socket kept reconnecting and logging that it had connected, but nothing
consumed the new sessions, so schemas were never resubmitted. And rapid status transitions were being dropped —
the in-process HTTP component fires <em>Starting</em> and <em>Running</em> microseconds apart, and the sink was configured to
drop an update for every subscriber if any one of them was momentarily at zero demand, leaving consumers stuck
on “starting” forever.</p>
<p>Projects that reference <code>NEBULA_*</code> environment variables no longer flash a red config-errors banner at startup
while the local stack is still coming up. Orbital distinguishes “Nebula starting” from a real config failure
and shows a quiet <em>“Starting local environment…”</em> instead, escalating to a proper error if the connection drops.</p>
<h3 id="query-graph-debugger"><a href="#query-graph-debugger">​<span></span></a>Query graph debugger<span><span>New</span></span></h3>
<p>The old Angular <code>graph-vis</code> tool is replaced by a React Flow rewrite under <code>tools/graph-debugger</code>. Paste the
graph the engine logs while planning a query and explore it interactively to work out why a query isn’t
resolving.</p>
<p>Large graphs used to lock the canvas, so it now starts empty: add a single type, expand outward from any node
via its off-canvas-neighbour badge, or drop the whole graph on at once for small ones. Auto-layout is
left-to-right hierarchical, matching the engine’s traversal direction, and dragging a node pins it.</p>
<h3 id="smaller-ui-fixes"><a href="#smaller-ui-fixes">​<span></span></a>Smaller UI fixes<span><span>Fixed</span></span></h3>
<ul role="list">
<li>Picking a result in the search bar navigated twice — once to the item you chose, and again to the first item
in the list.</li>
<li>The schema diagram’s markdown round-trip now serialises member keys as qualified names, so saved layouts
resolve on re-render.</li>
<li>Clicking a model node header in the schema diagram navigated to the literal path rather than the type’s
qualified name.</li>
<li>Operation parameter type names link through to the catalog, matching the return type’s behaviour.</li>
<li>Query plans containing a Hazelcast node no longer throw.</li>
<li>Loading buttons inside pop-ups are no longer obscured by incorrect styling.</li>
<li>Alert action links (project errors, config errors, compilation errors) navigate to the correct workspace.</li>
<li>A 404 for a type that doesn’t exist no longer bounces you out to the workspace selector — only a genuine
workspace-not-found does.</li>
</ul>
<div><span></span><span></span></div>
<h2 id="other-fixes"><a href="#other-fixes">​<span></span></a>Other fixes<span><span>Fixed</span></span></h2>
<ul role="list">
<li><strong>HTTP header parameters were matched by position, not name.</strong> <code>buildHttpHeaders</code> resolved each
<code>@HttpHeader</code> parameter by its index in the supplied list, assuming that list matched the operation’s
declared parameter order. It doesn’t — directly-provided parameters are appended after searched ones — so
header values could silently be attached to the wrong header.</li>
<li><strong>A JDBC driver returning null threw an NPE</strong> rather than producing a null value.</li>
<li><strong>Config loading could throw <code>ConcurrentModificationException</code></strong> because custom types were being registered
on every load rather than once at class initialisation.</li>
<li><strong>An invalid PropelAuth API key returned 500.</strong> It now maps to 401 for a rejected token, 403 for a permitted
token without access, and 503 when PropelAuth itself is unreachable.</li>
<li><strong>A file watcher missed the contents of newly created directories.</strong> <code>java.nio.WatchService</code> doesn’t replay
events from before a key is registered, so writing <code>orbital/config/services.conf</code> in one go meant the watcher
saw only the <code>orbital/</code> directory and never the files inside it. Creating a directory now registers the watch
and walks its existing contents.</li>
<li><strong>Sankey lineage rows weren’t stamped with the query’s workspace</strong>, so the lineage view in the query profile
was empty for every workspace-scoped query.</li>
<li><strong>History results for <code>PROVIDED</code> lineage nodes weren’t showing.</strong></li>
<li><strong>Trace events from published-query routes</strong> were stamped with the default workspace rather than the one
that ran the query.</li>
</ul>
<div><span></span><span></span></div>
<h2 id="in-case-you-missed-it"><a href="#in-case-you-missed-it">​<span></span></a>In case you missed it</h2>
<p>Writing these notes turned up a gap in our own record-keeping. <strong>0.36.0</strong> (October 2025) and <strong>0.38.0-M1</strong>
(June 2026) both shipped without a release announcement, and a handful of point releases went out quietly too.
A fair amount of work reached you without us ever saying so.</p>
<p>None of this is new in 0.39 — it’s all been in your hands for a while. It’s here because you may not know
you have it.</p>
<h3 id="custom-kotlin-functions"><a href="#custom-kotlin-functions">​<span></span></a>Custom Kotlin functions<span><span>New</span></span></h3>
<a href="https://hub.docker.com/r/orbitalhq/orbital/tags?name=0.36.0" target="_blank" rel="noreferrer">Available since <!-- -->0.36.0</a>
<p>You can extend Taxi’s standard library with your own functions, written in Kotlin and loaded at runtime. Declare
the function in Taxi, implement it in Kotlin, and it’s available in expressions, projections and queries like
any built-in.</p>
<p>This is the extension point to reach for when a transformation can’t be expressed in Taxi itself — a
proprietary check-digit algorithm, a domain-specific parse, an internal encoding scheme.</p>
<p>It’s documented at <a href="https://orbitalhq.com/docs/extending/custom-functions">custom functions</a>; it has simply never appeared in a
changelog, because 0.36.0 never got one.</p>
<p>It’s also the mechanism the <a href="#data-validation">validation framework</a> will use when user-written validation
rules land — the loader is already proven.</p>
<h3 id="everything-else"><a href="#everything-else">​<span></span></a>Everything else</h3>
<div><table><thead><tr><th>Feature</th><th>Shipped in</th><th>Documented</th></tr></thead><tbody><tr><td><a href="https://orbitalhq.com/docs/querying/scheduled-queries">Scheduled queries</a> — run a query on a cron schedule</td><td>0.36.0</td><td>Yes</td></tr><tr><td><code>in</code> / <code>not in</code> operators, pushed down to SQL and MongoDB</td><td>0.36.0</td><td>Yes</td></tr><tr><td>MongoDB native aggregations via <code>@MongoAggregate</code></td><td>0.36.0</td><td>No</td></tr><tr><td><code>map { }</code> iterates a collection rather than operating on it whole</td><td>0.36.0</td><td>No</td></tr><tr><td>Negate (<code>!</code>) and modulo operators</td><td>0.36.0</td><td>No</td></tr><tr><td><code>env.conf</code> resolves environment variables inside annotations</td><td>0.36.0</td><td>Partly</td></tr><tr><td>Query-level Kafka offset override, by annotation</td><td>0.36.0</td><td>Yes</td></tr><tr><td>Custom error responses thrown from a <code>given { }</code> clause</td><td>0.36.0</td><td>No</td></tr><tr><td>Query error events persisted to the database</td><td>0.36.0</td><td>No</td></tr><tr><td>Roughly twenty stdlib functions — <code>append</code>, <code>average</code>, <code>joinToString</code>, <code>ifEmpty</code>, <code>orEmpty</code>, <code>size</code>, <code>isNullOrEmpty</code>, <code>indexOfItem</code>, <code>containsAll</code>, <code>containsAny</code>, <code>all</code>, <code>some</code>, <code>none</code>, <code>emptyInstance</code>, <code>startsWith</code>, <code>endsWith</code>, <code>matches</code>, <code>containsPattern</code>, <code>padStart</code>, <code>padEnd</code>, <code>applyFormat</code></td><td>0.36.0</td><td>No</td></tr><tr><td>Logbook HTTP request/response capture</td><td>0.36.0</td><td>No</td></tr><tr><td>File-system monitors filter irrelevant files, stopping continuous polling loops</td><td>0.36.7</td><td>n/a</td></tr><tr><td>WebSocket transport for schema publication</td><td>0.37.0-M4</td><td>Partly</td></tr><tr><td><a href="https://orbitalhq.com/docs/sdks/java-and-kotlin/spring-boot-schema-publisher">Schema-publisher Spring Boot starter</a></td><td>0.37.0-M4</td><td>Yes</td></tr><tr><td>SOAP as a loadable language via <code>additionalSources</code></td><td>0.38.0-M1</td><td>Yes</td></tr><tr><td><a href="https://orbitalhq.com/docs/guides/working-with-xml">XSD as a source format</a></td><td>0.38.0-M1</td><td>Yes</td></tr><tr><td><a href="https://orbitalhq.com/docs/describing-data-sources/databases#batching-writes">JDBC batching</a> — <code>batchSize</code> / <code>batchDuration</code> on database writes</td><td>0.38.0-M1</td><td>Yes</td></tr><tr><td>Operations usable as callable expressions</td><td>0.38.0-M1</td><td>No</td></tr><tr><td><a href="https://orbitalhq.com/docs/describing-data-sources/authentication-to-services">Multiple authentication tokens per service</a></td><td>0.38.0-M1</td><td>Yes</td></tr><tr><td>Environment-specific config files (<code>auth.conf</code> overridden per environment)</td><td>0.38.0-M1</td><td>Partly</td></tr><tr><td>New query-plan diagram</td><td>0.38.0-M1</td><td>No</td></tr><tr><td>Tabbed catalog layout, and README as the first tab in the project explorer</td><td>0.38.0-M1</td><td>n/a</td></tr><tr><td>Endpoint for submitting parameterized query objects</td><td>0.38.0-M1</td><td>No</td></tr><tr><td>JSON message body accepted on the SSE streaming endpoint</td><td>0.38.0-M1</td><td>No</td></tr><tr><td>Git configuration changes clean up stale clones</td><td>0.38.0-M1</td><td>n/a</td></tr><tr><td><code>schema-management</code> relicensed to Apache 2.0</td><td>0.38.0-M1</td><td>n/a</td></tr></tbody></table></div>
<p>The undocumented rows are on our list. If one of them is something you’ve wanted, tell us and we’ll bump it.</p>
<div><span></span><span></span></div>
<h2 id="upgrading"><a href="#upgrading">​<span></span></a>Upgrading</h2>
<p>This is a milestone build. Try it somewhere that isn’t production first.</p>
<ol role="list">
<li>Read <a href="#breaking-changes">Breaking changes</a> — particularly the license requirement and the
<code>workspace-mode</code> toggle rename.</li>
<li>Back up your query history database. The Flyway migration takes table locks to enforce the new non-null
columns.</li>
<li>If you use H2 as a data source, migrate off it before upgrading.</li>
<li>If you rely on the standalone Jet pipeline server, stay on 0.38.x. Streaming queries are unaffected.</li>
<li>Start Orbital and sign in. Your free license downloads automatically.</li>
</ol>
<p>Workspaces are opt-in. Leave <code>workspace-mode</code> at <code>None</code> and Orbital behaves as it always has, with a single
workspace and legacy routes intact — you can adopt workspaces when you’re ready.</p><p><em>(The post <a href="https://orbitalhq.com/changelog/2026-08-24-release-announcement-0.39.0">0.39.1-M1 - Workspaces, Copilot, secrets and validation</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/changelog-cards/2026-08-24-release-announcement-0.39.0.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Database connectors: delete support and native SQL queries]]></title>
            <link>https://orbitalhq.com/changelog/2026-07-16-jdbc-deletes-and-native-sql</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2026-07-16-jdbc-deletes-and-native-sql</guid>
            <pubDate>Thu, 16 Jul 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Delete rows through TaxiQL with @DeleteOperation, and run hand-written SQL - joins, aggregations, dialect-specific statements - with @SqlQuery.]]></description>
            <content:encoded><![CDATA[<a href="https://hub.docker.com/r/orbitalhq/orbital/tags?name=0.38.0-M2" target="_blank" rel="noreferrer">Available since <!-- -->0.38.0-M2</a>
<p>Two additions to our database connectors in this release: deleting rows through TaxiQL, and running SQL
you’ve written yourself.</p>
<h2 id="deleting-rows"><a href="#deleting-rows">​<span></span></a>Deleting rows</h2>
<p>Databases connected to Orbital have long supported reads, inserts, updates and upserts. Deletes now join
the family - annotate a <code>write operation</code> with <code>@DeleteOperation</code>:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>@</span><span>DatabaseService</span><span>(</span><span>connection </span><span>=</span><span> </span><span>&quot;customers-database&quot;</span><span>)</span></span><span><span>service</span><span> </span><span>CustomerService</span><span> </span><span>{</span></span><span><span>   </span><span>@</span><span>DeleteOperation</span></span><span><span>   </span><span>write</span><span> </span><span>operation</span><span> </span><span>deleteCustomer</span><span>(</span><span>Customer</span><span>)</span><span>:</span><span>DeleteResult</span></span><span>
</span><span><span>   </span><span>@</span><span>DeleteOperation</span></span><span><span>   </span><span>write</span><span> </span><span>operation</span><span> </span><span>deleteCustomers</span><span>(</span><span>Customer</span><span>[</span><span>]</span><span>)</span><span>:</span><span>DeleteResult</span></span><span><span>}</span></span></code></pre></div></div>
<p>Rows are matched on the model’s <code>@Id</code> fields (composite keys work too - rows match on the combination),
and you can pass a single instance or a whole array. Invoking it looks like any other mutation:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>given</span><span> </span><span>{</span></span><span><span>   customers</span><span> </span><span>:</span><span> Customer</span><span>[</span><span>]</span><span> </span><span>=</span><span> </span><span>[</span></span><span><span>      </span><span>{</span><span> id </span><span>:</span><span> </span><span>123</span><span> </span><span>}</span><span>,</span></span><span><span>      </span><span>{</span><span> id </span><span>:</span><span> </span><span>456</span><span> </span><span>}</span></span><span><span>   </span><span>]</span></span><span><span>}</span></span><span><span>call CustomerService</span><span>:</span><span>:</span><span>deleteCustomers</span></span></code></pre></div></div>
<p>You get back a <code>deletedCount</code> telling you how many rows went away. Deletes run in a single transaction,
so a failure partway through rolls the whole thing back rather than leaving you half-deleted.</p>
<h2 id="native-sql-queries"><a href="#native-sql-queries">​<span></span></a>Native SQL queries</h2>
<p>Orbital’s <code>table</code> operations cover most day-to-day querying, and keep your queries portable across
databases. But sometimes you just want to write the SQL yourself - a join, an aggregation, or something
dialect-specific. The new <code>@SqlQuery</code> annotation is that escape hatch:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>@</span><span>DatabaseService</span><span>(</span><span>connection </span><span>=</span><span> </span><span>&quot;films-database&quot;</span><span>)</span></span><span><span>service</span><span> </span><span>FilmStats</span><span> </span><span>{</span></span><span><span>   </span><span>@</span><span>SqlQuery</span><span>(</span><span>sql </span><span>=</span><span> </span><span>&quot;&quot;</span><span>&quot;</span></span><span><span>      SELECT d</span><span>.</span><span>name AS director</span><span>,</span><span> </span><span>COUNT</span><span>(</span><span>f</span><span>.</span><span>id</span><span>)</span><span> AS filmCount</span></span><span><span>      FROM film f</span></span><span><span>      JOIN director d ON f</span><span>.</span><span>director_id </span><span>=</span><span> d</span><span>.</span><span>id</span></span><span><span>      GROUP BY d</span><span>.</span><span>name</span></span><span><span>   </span><span>&quot;&quot;</span><span>&quot;</span><span>)</span></span><span><span>   </span><span>operation</span><span> </span><span>filmsPerDirector</span><span>(</span><span>)</span><span> </span><span>:</span><span> DirectorFilmSummary</span><span>[</span><span>]</span></span><span><span>}</span></span></code></pre></div></div>
<p>The SQL is passed to your database exactly as written, and result columns map back to your Taxi model’s
fields by name or alias. One annotation covers both directions: a plain <code>operation</code> runs the SQL as a
query, while a <code>write operation</code> runs it as a statement (<code>UPDATE</code>, <code>DELETE</code>, <code>INSERT</code>) and returns the
number of rows affected.</p>
<p>Operation parameters bind into the SQL with the <code>:parameterName</code> syntax:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>@</span><span>SqlQuery</span><span>(</span><span>sql </span><span>=</span><span> </span><span>&quot;SELECT title, release_year AS releaseYear FROM film WHERE release_year &gt; :year&quot;</span><span>)</span></span><span><span>operation</span><span> </span><span>recentFilms</span><span>(</span><span>year</span><span> </span><span>:</span><span> ReleaseYear</span><span>)</span><span> </span><span>:</span><span> Film</span><span>[</span><span>]</span></span></code></pre></div></div>
<p>Values are always bound as prepared-statement parameters - never spliced into the SQL text - so
user-supplied values can’t alter your query.</p>
<p>Both features work across all of Orbital’s SQL database connectors. Full details are in the
<a href="https://orbitalhq.com/docs/describing-data-sources/databases#deleting-data-from-a-database">database docs</a>, including
<a href="https://orbitalhq.com/docs/describing-data-sources/databases#running-native-sql-queries">native query behaviour notes</a>.</p><p><em>(The post <a href="https://orbitalhq.com/changelog/2026-07-16-jdbc-deletes-and-native-sql">Database connectors: delete support and native SQL queries</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/changelog-cards/2026-07-16-jdbc-deletes-and-native-sql.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Collection options: limit, sort and paginate any query]]></title>
            <link>https://orbitalhq.com/changelog/2026-07-04-collection-options</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2026-07-04-collection-options</guid>
            <pubDate>Sat, 04 Jul 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[TaxiQL now supports collection options - limit, offset, orderBy and uniqueBy - pushed down to your data sources where they can be, and applied by Orbital everywhere else.]]></description>
            <content:encoded><![CDATA[<a href="https://hub.docker.com/r/orbitalhq/orbital/tags?name=0.38.0-M2" target="_blank" rel="noreferrer">Available since <!-- -->0.38.0-M2</a>
<p>You can now shape the results of a query directly in TaxiQL - limiting how many rows come back, paginating through them,
sorting them, and removing duplicates. We’re calling these <strong>collection options</strong>, and they look like this:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>find</span><span> </span><span>{</span><span> Person</span><span>[</span><span>]</span><span>(</span><span> CountryCode </span><span>==</span><span> </span><span>&quot;GB&quot;</span><span>,</span><span> orderBy</span><span>:</span><span> DateOfBirth</span><span> desc</span><span>,</span><span> offset</span><span>:</span><span> </span><span>20</span><span>,</span><span> limit</span><span>:</span><span> </span><span>10</span><span> </span><span>)</span><span> </span><span>}</span></span></code></pre></div></div>
<p>These are the standard database-style controls we all already know and love - <code>limit</code>, <code>offset</code>, <code>orderBy</code> and
<code>uniqueBy</code> - but they work on <strong>any</strong> query, against any source.</p>
<p>When the source can apply an option itself, Orbital pushes the work down to it. When it can’t, Orbital does the work after fetching. Either way you get the same result.</p>
<h2 id="a-few-examples"><a href="#a-few-examples">​<span></span></a>A few examples</h2>
<p>Sort and take the top N:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>find</span><span> </span><span>{</span><span> Film</span><span>[</span><span>]</span><span>(</span><span> orderBy</span><span>:</span><span> RottenTomatoesScore</span><span> desc</span><span>,</span><span> limit</span><span>:</span><span> </span><span>10</span><span> </span><span>)</span><span> </span><span>}</span></span></code></pre></div></div>
<p>Sort by more than one field, and paginate:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>find</span><span> </span><span>{</span><span> Person</span><span>[</span><span>]</span><span>(</span><span> orderBy</span><span>:</span><span> </span><span>[</span><span>CountryCode asc</span><span>,</span><span> DateOfBirth desc</span><span>]</span><span>,</span><span> offset</span><span>:</span><span> </span><span>40</span><span>,</span><span> limit</span><span>:</span><span> </span><span>20</span><span> </span><span>)</span><span> </span><span>}</span></span></code></pre></div></div>
<p>Options work on projections too, including nested collections - handy for trimming child records per parent:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>find</span><span> </span><span>{</span><span> Customer</span><span>[</span><span>]</span><span> </span><span>}</span><span> </span><span>as</span><span> </span><span>{</span></span><span><span>  name</span><span> </span><span>:</span><span> CustomerName</span></span><span><span>  </span><span>// Only the 20 most recent transactions per customer</span></span><span><span>  transactions</span><span> </span><span>:</span><span> Transaction</span><span>[</span><span>]</span><span>(</span><span> limit</span><span>:</span><span> </span><span>20</span><span>,</span><span> orderBy</span><span>:</span><span> TransactionDate</span><span> desc </span><span>)</span></span><span><span>}</span><span>[</span><span>]</span></span></code></pre></div></div>
<p>Values can be literals or query parameters, so <code>limit: maxRows</code> works just as well when <code>maxRows</code> is a query argument.</p>
<h2 id="how-pushdown-works"><a href="#how-pushdown-works">​<span></span></a>How pushdown works</h2>
<p>For each option, Orbital’s query planner decides - per data source - whether to push it down or to apply it itself.</p>
<p>Pushing down tot he source system is only permitted if it doesn’t change the answer: if a source can’t sort, Orbital won’t push a
<code>limit</code> below the (missing) sort either, because limiting before sorting would hand back the wrong rows.</p>
<p>Here’s what’s supported in this release:</p>
<ul role="list">
<li><strong>SQL databases</strong> (Postgres, MySQL, MSSQL, Oracle, Redshift, Snowflake) push <code>limit</code>, <code>offset</code> and <code>orderBy</code> straight
into the generated SQL, in the right dialect for your driver.</li>
<li><strong>MongoDB</strong> pushes <code>limit</code>, <code>offset</code> and <code>orderBy</code> into the Mongo query as <code>sort</code> / <code>skip</code> / <code>limit</code>.</li>
<li><strong>Hazelcast</strong> pushes <code>limit</code> down as a key-ordered page; everything else is applied by Orbital.</li>
<li><strong>Everything else</strong> - REST APIs, Kafka, and any other source - is applied by Orbital after fetching. No source-side
support required.</li>
</ul>
<p><code>limit</code> also works on streaming queries, completing the stream once it has emitted N items.</p>
<h2 id="coming-next"><a href="#coming-next">​<span></span></a>Coming next</h2>
<p><code>after</code> / <code>before</code> cursors are reserved for cursor-based pagination and will land in a future release - for now they
parse but are rejected at runtime.</p>
<p>Full details are in the <a href="https://orbitalhq.com/docs/querying/collection-options">collection options docs</a>, and the syntax reference lives in
the <a href="https://taxilang.org/docs/taxiql/querying#collection-options" target="_blank" rel="noreferrer">Taxi language docs</a>.</p><p><em>(The post <a href="https://orbitalhq.com/changelog/2026-07-04-collection-options">Collection options: limit, sort and paginate any query</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/changelog-cards/2026-07-04-collection-options.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[0.38.0 - Anonymous access for published queries]]></title>
            <link>https://orbitalhq.com/changelog/2026-05-08-release-announcement-0.38.0</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2026-05-08-release-announcement-0.38.0</guid>
            <pubDate>Fri, 08 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Orbital 0.38.0 - Per-query opt-out from authentication for published HTTP query endpoints]]></description>
            <content:encoded><![CDATA[<h2 id="new-features"><a href="#new-features">​<span></span></a>New Features</h2>
<h3 id="anonymous-access-for-published-queries"><a href="#anonymous-access-for-published-queries">​<span></span></a>Anonymous access for published queries</h3>
<a href="https://hub.docker.com/r/orbitalhq/orbital/tags?name=0.38.0" target="_blank" rel="noreferrer">Available since <!-- -->0.38.0</a>
<p>Queries <a href="https://orbitalhq.com/docs/querying/queries-as-endpoints">published as HTTP endpoints</a> can now opt out of authentication on a per-query basis using the new <code>@com.orbitalhq.authentication.AllowAnonymous</code> annotation.</p>
<p>When Orbital is deployed with an authentication provider configured, all published query endpoints require a valid token by default. <code>@AllowAnonymous</code> relaxes that requirement for a single query — useful for health checks, public catalogues, or any endpoint intended to be reachable without a token. Other queries in the same workspace are unaffected.</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>import</span><span> taxi</span><span>.</span><span>http</span><span>.</span><span>HttpOperation</span></span><span><span>import</span><span> com</span><span>.</span><span>orbitalhq</span><span>.</span><span>authentication</span><span>.</span><span>AllowAnonymous</span></span><span>
</span><span><span>@</span><span>HttpOperation</span><span>(</span><span>url </span><span>=</span><span> </span><span>&#x27;/api/q/healthcheck&#x27;</span><span>,</span><span> method </span><span>=</span><span> </span><span>&#x27;GET&#x27;</span><span>)</span></span><span><span>@</span><span>AllowAnonymous</span></span><span><span>query</span><span> </span><span>Healthcheck</span><span> </span><span>{</span></span><span><span>  </span><span>find</span><span> </span><span>{</span><span> status</span><span>:</span><span> String</span><span> </span><span>=</span><span> </span><span>&quot;ok&quot;</span><span> </span><span>}</span></span><span><span>}</span></span></code></pre></div></div>
<p>The annotation only affects the authentication check. Data policies and authorization rules still run.</p>
<p>See the <a href="https://orbitalhq.com/docs/querying/queries-as-endpoints#allowing-anonymous-access">docs on allowing anonymous access</a> for more detail.</p><p><em>(The post <a href="https://orbitalhq.com/changelog/2026-05-08-release-announcement-0.38.0">0.38.0 - Anonymous access for published queries</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/changelog-cards/2026-05-08-release-announcement-0.38.0.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Breaking change: /api/taxiql content-type and removal of /api/vyneql]]></title>
            <link>https://orbitalhq.com/changelog/2026-03-24-query-api-content-type-breaking-change</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2026-03-24-query-api-content-type-breaking-change</guid>
            <pubDate>Tue, 24 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[The /api/taxiql endpoint no longer accepts application/json. The legacy /api/vyneql endpoint has been removed.]]></description>
            <content:encoded><![CDATA[<a href="https://hub.docker.com/r/orbitalhq/orbital/tags?name=0.38.x" target="_blank" rel="noreferrer">Available since <!-- -->0.38.x</a>
<p>As part of upcoming feature work for improved SDK tooling for JVM and TS/JS ecosystems, there are two
breaking changes to the query API are shipping in 0.38.x (and nightly builds of <code>next</code>). Neither affects 0.37.x.</p>
<h2 id="breaking-apitaxiql-no-longer-accepts-applicationjson"><a href="#breaking-apitaxiql-no-longer-accepts-applicationjson">​<span></span></a>Breaking: <code>/api/taxiql</code> no longer accepts <code>application/json</code></h2>
<p>The <code>/api/taxiql</code> streaming query endpoint previously accepted requests with <code>Content-Type: application/json</code>.
This is no longer supported.</p>
<p>Use either of the following content types instead:</p>
<ul role="list">
<li><code>application/taxiql</code> (Preferred, but less standard)</li>
<li><code>text/plain</code> (Standard, but less accurate)</li>
</ul>
<p>Either are fine to use, and both content types are already supported in all versions of Orbital today, so you can make this change now, without waiting.</p>
<p>If you’re sending queries via <code>curl</code> or an HTTP client, update accordingly:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span># Before (no longer works)</span></span><span><span>curl</span><span> </span><span>-X</span><span> POST /api/taxiql </span><span>\</span></span><span><span>  </span><span>-H</span><span> </span><span>&quot;Content-Type: application/json&quot;</span><span> </span><span>\</span></span><span><span>  </span><span>-d</span><span> </span><span>&#x27;{ &quot;query&quot;: &quot;find { ... }&quot; }&#x27;</span></span><span>
</span><span><span># After</span></span><span><span>curl</span><span> </span><span>-X</span><span> POST /api/taxiql </span><span>\</span></span><span><span>  </span><span>-H</span><span> </span><span>&quot;Content-Type: application/taxiql&quot;</span><span> </span><span>\</span></span><span><span>  --data-raw </span><span>&#x27;find { ... }&#x27;</span></span></code></pre></div></div>
<h2 id="removal-of-apivyneql"><a href="#removal-of-apivyneql">​<span></span></a>Removal of <code>/api/vyneql</code></h2>
<p>The legacy <code>/api/vyneql</code> endpoint has been removed. It was a holdover from the previous product name and has been
superseded by <code>/api/taxiql</code> for some time. If you were still referencing <code>/api/vyneql</code>, update your calls to use <code>/api/taxiql</code>.</p><p><em>(The post <a href="https://orbitalhq.com/changelog/2026-03-24-query-api-content-type-breaking-change">Breaking change: /api/taxiql content-type and removal of /api/vyneql</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/changelog-cards/2026-03-24-query-api-content-type-breaking-change.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[0.37.0-M3 - Preflight exports, parseJson, and observability improvements]]></title>
            <link>https://orbitalhq.com/changelog/2026-03-23-release-announcement-0.37.0-M3</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2026-03-23-release-announcement-0.37.0-M3</guid>
            <pubDate>Mon, 23 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Orbital 0.37.0-M3 - Preflight test spec exports, parseJson stdlib function, improved query observability, and performance improvements]]></description>
            <content:encoded><![CDATA[<p>Orbital 0.37.0-M3 is the third milestone release of 0.37.
We haven’t published release notes on <code>0.37.0-M1</code> or <code>-M2</code>, we’ll cover off those releases too.</p>
<p>The headline features are a new <code>parseJson()</code> standard library function, the ability to export query history
as <a href="https://preflight.orbitalhq.com" target="_blank" rel="noreferrer">Preflight</a> test specs, and a significant improvement to observability — with request
parameters now captured on every remote call across all connectors.</p>
<p>There’s also a crop of reliability improvements: better git sync resilience, a fix for a stack overflow in
the query engine, and an internal overhaul that removes a class of thread-pool starvation under concurrent load.</p>
<p>As a milestone release, 0.37.0-M3 is intended for early adopters and teams that want to test ahead of the
GA release. Feedback welcome.</p>
<h2 id="new-features"><a href="#new-features">​<span></span></a>New Features</h2>
<h3 id="parsejson-stdlib-function"><a href="#parsejson-stdlib-function">​<span></span></a><code>parseJson()</code> stdlib function</h3>
<a href="https://hub.docker.com/r/orbitalhq/orbital/tags?name=0.37.0-M3" target="_blank" rel="noreferrer">Available since <!-- -->0.37.0-M3</a>
<p>You can now use <code>parseJson()</code> in your queries and projections to parse a JSON string into a typed value.</p>
<p>This is useful when JSON arrives embedded in a field as a string — a common pattern in event-driven systems where a
message envelope wraps a serialized payload.</p>
<section><h3>Using parseJson()</h3><div><div><span>Show schema</span><div><a href="https://playground.taxilang.org" target="_blank" rel="noreferrer"><span>Edit this on Taxi Playground</span></a><span>Run this query</span></div></div><div><div><textarea id="_R_16qqj5_-query" rows="10" wrap="off" spellCheck="false">given {
   customer: Customer = {
      name: &#x27;Alice&#x27;,
      addressJson: &#x27;{ &quot;city&quot;: &quot;London&quot;, &quot;country&quot;: &quot;UK&quot; }&#x27;
   }
}
find {
   name: Name
   address: Address = parseJson(customer.addressJson, Address)
}</textarea></div></div></div></section>
<h3 id="preflight-test-spec-export"><a href="#preflight-test-spec-export">​<span></span></a>Preflight test spec export</h3>
<a href="https://hub.docker.com/r/orbitalhq/orbital/tags?name=0.37.0-M2" target="_blank" rel="noreferrer">Available since <!-- -->0.37.0-M2</a>
<p>Query history can now be exported as a <a href="https://preflight.orbitalhq.com" target="_blank" rel="noreferrer">Preflight</a> test spec, in addition to the
existing ZIP regression pack format.</p>
<p>When downloading a regression pack from query history, you can now choose between <code>Zip</code> (the original format)
and <code>Preflight</code> spec files.</p>
<p><a href="https://preflight.orbitalhq.com/spec-files" target="_blank" rel="noreferrer">Preflight Spec Files</a> are markdown files that describe a test scenario,
along with all the information to stub out query services:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>---</span></span><span><span>spec-version: 0.1</span></span><span><span>---</span></span><span><span> </span></span><span><span># Test name</span></span><span><span> </span></span><span><span>Optional description paragraph.</span></span><span><span> </span></span><span><span>## Query</span></span><span><span> </span></span><span><span>```taxiql</span></span><span><span>find { Customer( CustomerId == &quot;C-100&quot; ) } as CustomerProfile</span></span><span><span>```</span></span><span><span> </span></span><span><span>## Data Sources</span></span><span><span> </span></span><span><span>### Customer API</span></span><span><span>&lt;!-- operation: getCustomer --&gt;</span></span><span><span> </span></span><span><span>Response:</span></span><span><span>```json</span></span><span><span>{ &quot;id&quot;: &quot;C-100&quot;, &quot;name&quot;: &quot;Alice Smith&quot;, &quot;age&quot;: 30 }</span></span><span><span>```</span></span><span><span> </span></span><span><span>## Expected Result</span></span><span><span> </span></span><span><span>```json</span></span><span><span>{ &quot;id&quot;: &quot;C-100&quot;, &quot;name&quot;: &quot;Alice Smith&quot;, &quot;age&quot;: 30, &quot;isAdult&quot;: true }</span></span><span><span>```</span></span></code></pre></div></div>
<p>By capturing these using the data from your queries, you can very quickly build test suites for
your taxi projects.</p>
<p>Preflight tests are runnable using <a href="https://preflight.orbitalhq.com/" target="_blank" rel="noreferrer">Gradle</a>, so works great with established build tooling and CI/CD.</p>
<h2 id="observability"><a href="#observability">​<span></span></a>Observability</h2>
<h3 id="request-parameters-captured-on-trace-events"><a href="#request-parameters-captured-on-trace-events">​<span></span></a>Request parameters captured on trace events</h3>
<p>The capture of input parameters for events shown in the Trace View has been extended, capturing inputs across all connectors.</p>
<h3 id="jfr-flight-recorder"><a href="#jfr-flight-recorder">​<span></span></a>JFR flight recorder</h3>
<a href="https://hub.docker.com/r/orbitalhq/orbital/tags?name=0.37.0-M1" target="_blank" rel="noreferrer">Available since <!-- -->0.37.0-M1</a>
<p>Orbital now supports capturing Java Flight Recorder traces for capturing diagnostic data.
This feature is disabled by default, but can be enabled <a href="https://orbitalhq.com/docs/deploying/capturing-diagnostics#enabling-flight-recorder">through configuration</a></p>
<p><code>0.37.0-M3</code> extends this to further capture exception data.</p>
<h2 id="reliability--performance"><a href="#reliability--performance">​<span></span></a>Reliability &amp; Performance</h2>
<h3 id="query-engine-fix-for-circular-operation-types-orb-1081"><a href="#query-engine-fix-for-circular-operation-types-orb-1081">​<span></span></a>Query engine: fix for circular operation types (ORB-1081)</h3>
<a href="https://hub.docker.com/r/orbitalhq/orbital/tags?name=0.37.0-M2" target="_blank" rel="noreferrer">Available since <!-- -->0.37.0-M2</a>
<p>Fixed a bug where an operation whose return type also appeared as an input parameter type would trigger
recursive parameter construction, ultimately causing a stack overflow. Type-level cycle detection is now
applied during object building, so these circular type graphs are handled cleanly.</p>
<h3 id="git-sync-failures-are-no-longer-fatal"><a href="#git-sync-failures-are-no-longer-fatal">​<span></span></a>Git sync failures are no longer fatal</h3>
<a href="https://hub.docker.com/r/orbitalhq/orbital/tags?name=0.37.0-M3" target="_blank" rel="noreferrer">Available since <!-- -->0.37.0-M3</a>
<p>A git repository sync failure at startup is now treated as a warning rather than an error. If a
locally-cached copy of the schema is available, Orbital will use it and continue running — reporting a
<code>WARNING</code> state in the UI rather than refusing to start.</p>
<p>The UI also now distinguishes between <code>ERROR</code> (schema could not be loaded at all) and <code>WARNING</code> (schema
loaded from local cache), with separate alerts and colour-coded severity badges, so it’s clearer what’s
actually happening.</p>
<p>A rate limiter (via resilience4j) has also been introduced on git repository polling, to prevent remote
git servers from denying requests when Orbital is polling frequently.</p>
<h3 id="eliminated-blocking-calls-from-the-query-engine"><a href="#eliminated-blocking-calls-from-the-query-engine">​<span></span></a>Eliminated blocking calls from the query engine</h3>
<a href="https://hub.docker.com/r/orbitalhq/orbital/tags?name=0.37.0-M1" target="_blank" rel="noreferrer">Available since <!-- -->0.37.0-M1</a>
<p>The internal TaxiQL query engine has been refactored to remove blocking calls. Under specific conditions, it was
previously possible for the query engine to get into thread starvation, waiting for I/O calls to complete.</p>
<p>By migrating the core query engine away from blocking, this removes the risk</p><p><em>(The post <a href="https://orbitalhq.com/changelog/2026-03-23-release-announcement-0.37.0-M3">0.37.0-M3 - Preflight exports, parseJson, and observability improvements</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/changelog-cards/2026-03-23-release-announcement-0.37.0-M3.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[0.36.6 released]]></title>
            <link>https://orbitalhq.com/changelog/2026-02-16-release-announcement-0.36.6</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2026-02-16-release-announcement-0.36.6</guid>
            <pubDate>Mon, 16 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Orbital 0.36.6 introduces enhanced authentication capabilities for complex service integration scenarios.]]></description>
            <content:encoded><![CDATA[<p>Orbital 0.36.6 introduces enhanced authentication capabilities for complex service integration scenarios.</p>
<h2 id="new-features"><a href="#new-features">​<span></span></a>New Features</h2>
<ul role="list">
<li>Added support for multiple authentication tokens per service (<a href="https://linear.app/orbital/issue/ORB-1065" target="_blank" rel="noreferrer">ORB-1065</a>)<!-- -->
<ul role="list">
<li>Services can now use multiple authentication mechanisms simultaneously (e.g., API key header + query param)</li>
<li>Define an array of auth schemes instead of a single object in <code>auth.conf</code></li>
<li>Fully backwards compatible with existing single-scheme configurations</li>
</ul>
</li>
</ul>
<h3 id="example"><a href="#example">​<span></span></a>Example</h3>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>authenticationTokens {</span></span><span><span>  &quot;com.foo.service.*&quot; [</span></span><span><span>    { type: HttpHeader, value: ${API_KEY}, headerName: X-API-KEY },</span></span><span><span>    { type: QueryParam, parameterName: apiKey, value: ${API_SECRET} }</span></span><span><span>  ]</span></span><span><span>}</span></span></code></pre></div></div>
<p>There are no other functional changes in this release.</p><p><em>(The post <a href="https://orbitalhq.com/changelog/2026-02-16-release-announcement-0.36.6">0.36.6 released</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/changelog-cards/2026-02-16-release-announcement-0.36.6.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[0.36.5 released]]></title>
            <link>https://orbitalhq.com/changelog/2026-02-13-release-announcement-0.36.5</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2026-02-13-release-announcement-0.36.5</guid>
            <pubDate>Fri, 13 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Orbital 0.36.5 is a patch release that updates the Taxi compiler dependency to fix enum-related compilation errors.]]></description>
            <content:encoded><![CDATA[<p>Orbital 0.36.5 is a patch release that updates the Taxi compiler dependency to fix enum-related compilation errors.</p>
<h2 id="bug-fixes"><a href="#bug-fixes">​<span></span></a>Bug Fixes</h2>
<ul role="list">
<li>Updated Taxi version to 1.69.1 to fix incorrect “Enum does not contain a member of” compilation errors (<a href="https://linear.app/orbital/issue/ORB-1064" target="_blank" rel="noreferrer">ORB-1064</a>)<!-- -->
<ul role="list">
<li>Fixed poor state management and hashcode handling when enum synonyms (extensions) are used</li>
<li>This resolves false positive errors that could occur when working with enum types that have synonyms defined</li>
</ul>
</li>
</ul>
<p>There are no other functional changes in this release.</p><p><em>(The post <a href="https://orbitalhq.com/changelog/2026-02-13-release-announcement-0.36.5">0.36.5 released</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/changelog-cards/2026-02-13-release-announcement-0.36.5.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[0.36.4 released]]></title>
            <link>https://orbitalhq.com/changelog/2026-01-08-release-announcement-0.36.4</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2026-01-08-release-announcement-0.36.4</guid>
            <pubDate>Thu, 08 Jan 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Orbital 0.36.4 introduces a new debugging feature for advanced troubleshooting.]]></description>
            <content:encoded><![CDATA[<p>Orbital 0.36.4 introduces a new debugging feature for advanced troubleshooting.</p>
<h2 id="new-features"><a href="#new-features">​<span></span></a>New Features</h2>
<ul role="list">
<li>Added a flight recorder endpoint for debugging purposes (disabled by default)<!-- -->
<ul role="list">
<li>Provides JVM Flight Recorder data for performance analysis and troubleshooting</li>
<li>Can be enabled via configuration when needed for debugging</li>
</ul>
</li>
</ul>
<p>There are no other functional changes in this release.</p><p><em>(The post <a href="https://orbitalhq.com/changelog/2026-01-08-release-announcement-0.36.4">0.36.4 released</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/changelog-cards/2026-01-08-release-announcement-0.36.4.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[0.36.3 released]]></title>
            <link>https://orbitalhq.com/changelog/2025-12-22-release-announcement-0.36.3</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2025-12-22-release-announcement-0.36.3</guid>
            <pubDate>Mon, 22 Dec 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Orbital 0.36.3 is a patch release that addresses issues with very large lineage records.]]></description>
            <content:encoded><![CDATA[<p>Orbital 0.36.3 is a patch release that addresses issues with very large lineage records.</p>
<h2 id="bug-fixes"><a href="#bug-fixes">​<span></span></a>Bug Fixes</h2>
<ul role="list">
<li>Fixed buffer overflow when writing very large lineage records (<a href="https://linear.app/orbital/issue/ORB-1054" target="_blank" rel="noreferrer">ORB-1054</a>)</li>
<li>Increased maximum message size from 16MB to 64MB</li>
<li>Added warning logging when messages are too large</li>
</ul>
<p>There are no other functional changes in this release.</p><p><em>(The post <a href="https://orbitalhq.com/changelog/2025-12-22-release-announcement-0.36.3">0.36.3 released</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/changelog-cards/2025-12-22-release-announcement-0.36.3.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[New start script, and changes to default config]]></title>
            <link>https://orbitalhq.com/changelog/2025-12-05-changes-to-start-and-default-config</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2025-12-05-changes-to-start-and-default-config</guid>
            <pubDate>Fri, 05 Dec 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[We’ve made some small changes on how to get Orbital running. We’ve also added a new config variable to centralize where Orbital stores all it’s internal files. You should add this config variable to your own deployments before 0.37 is released.]]></description>
            <content:encoded><![CDATA[<p>We’ve made some small changes on how to get Orbital running. We’ve also added a <a href="#what-do-i-need-to-do">new config variable</a> to centralize
where Orbital stores all it’s internal files. <em>You should add this config variable to your own deployments before 0.37 is released</em>.</p>
<h2 id="new-way-to-start-orbital---startsh"><a href="#new-way-to-start-orbital---startsh">​<span></span></a>New way to start Orbital - start.sh</h2>
<p>We’ve updated the way people get started on Orbital - replacing our docker-compose.yml with a bash script.</p>
<p>If you head over to <a href="https://orbitalhq.com" target="_blank" rel="noreferrer">orbitalhq.com</a>, you’ll notice that we’re now asking people to start
by curling:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>curl</span><span> </span><span>-sSL</span><span> https://start.orbitalhq.com/start.sh </span><span>|</span><span> </span><span>bash</span></span></code></pre></div></div>
<p>You can <a href="https://start.orbitalhq.com/start.sh" target="_blank" rel="noreferrer">view the bash script</a> - it’s still running the same <a href="https://start.orbitalhq.com/docker-compose.yml" target="_blank" rel="noreferrer">docker-compose.yml</a>,
but we’ve just added some scripting to make the experience a bit better.</p>
<h2 id="what-do-i-need-to-do"><a href="#what-do-i-need-to-do">​<span></span></a>What do I need to do?</h2>
<p>There’s very little that’s changed.</p>
<p>You should add <code>--vyne.app.data.path=/a/path/for/your/config</code> to your config. It’s safe to do this now, before 0.37.0 is released.</p>
<p>It’s also safe not to do this at all, and Orbital will work with reasonable defaults. But, our new preferred config includes setting this property.</p>
<h2 id="what-we-changed"><a href="#what-we-changed">​<span></span></a>What we changed:</h2>
<ul role="list">
<li>By default, the app now launches with user permissions, rather than root</li>
<li>All app data (license files, temporary write queues, lucene search indices) are now written to the same, configurable directory (<code>--vyne.app.data.path</code>)</li>
<li>Docker Volume directories are created before docker starts</li>
</ul>
<h2 id="why-we-did-this---the-pains-of-docker-compose"><a href="#why-we-did-this---the-pains-of-docker-compose">​<span></span></a>Why we did this - the pains of Docker Compose</h2>
<p>We still ❤️ Docker Compose - it’s our preferred way for people to start the stack. But, we hit issues that made the experience unpleasant for developers…</p>
<h3 id="file-permissions"><a href="#file-permissions">​<span></span></a>File permissions</h3>
<p>When you’re working with Orbital, we expect you’ll do some stuff inside the browser, and other stuff inside your IDE.</p>
<p>However, if Docker creates the directories you’re using - <strong>even if your docker container is running with a non-root user</strong>, then you can end up
with file permissions errors. You - the user - lack the permissions to edit the files that get created.</p>
<p>The <code>start.sh</code> fixes this by simply creating the directories before docker launches,</p>
<h3 id="user-permissions"><a href="#user-permissions">​<span></span></a>User permissions</h3>
<p>Telling Docker Compose to launch in a non-root user is slightly trickier than you’d expect. It’s not <em>hard</em>, but you can’t
say “run with my account”, you have to say “run with <em>this</em> account”.</p>
<p>The idiomatic way to address this is:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>services</span><span>:</span></span><span><span>    </span></span><span><span>   </span><span>orbital</span><span>:</span></span><span><span>      </span><span>image</span><span>:</span><span> orbitalhq/orbital</span><span>:</span><span>$</span><span>{</span><span>ORBITAL_VERSION</span><span>:</span><span>-</span><span>next</span><span>}</span></span><span><span>      </span><span>user</span><span>:</span><span> </span><span>&quot;${UID}:${GID}&quot;</span></span></code></pre></div></div>
<p>And then have a <code>.env</code> file that defines those variables:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>UID=1000</span></span><span><span>GID=1000</span></span></code></pre></div></div>
<p>This isn’t difficult, but it’s awkward for a user to just get started. So, the script handles this for you.</p>
<h3 id="networking"><a href="#networking">​<span></span></a>Networking</h3>
<p>Orbital is an integration platform, so when we ship demos or test stacks, we need things to integrate.</p>
<p>We solved that by building <a href="https://nebula.orbitalhq.com" target="_blank" rel="noreferrer">Nebula</a> to deploy local environments. However,
Nebula deploys other docker containers - and docker-launching-docker varies between OS’s. That meant our docker-compose.yml
is OS-specific. We built tools to detect and try to serve the correct docker-compose.yml, but it’s clumsy if you’re running from the command line.</p>
<p>Our script detects which OS you’re running on, and downloads the correct docker-compose file for you.</p>
<h2 id="summary"><a href="#summary">​<span></span></a>Summary</h2>
<p>That it! The new launcher script is live now, and config variables are shipping now in <code>next</code> and will be part of the <code>0.37</code> release.</p>
<p>Happy integrating.</p><p><em>(The post <a href="https://orbitalhq.com/changelog/2025-12-05-changes-to-start-and-default-config">New start script, and changes to default config</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/changelog-cards/2025-12-05-changes-to-start-and-default-config.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[0.36.2 released]]></title>
            <link>https://orbitalhq.com/changelog/2025-12-02-release-announcement-0.36.2</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2025-12-02-release-announcement-0.36.2</guid>
            <pubDate>Tue, 02 Dec 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Orbital 0.36.2 is a patch release that fixes a critical issue with lineage persistence.]]></description>
            <content:encoded><![CDATA[<p>Orbital 0.36.2 is a patch release that fixes a critical issue with lineage persistence.</p>
<h2 id="bug-fixes"><a href="#bug-fixes">​<span></span></a>Bug Fixes</h2>
<ul role="list">
<li>Fixed broken persistence in lineage, caused by attempting to write taxi definitions (<a href="https://linear.app/orbital/issue/ORB-1052" target="_blank" rel="noreferrer">ORB-1052</a>)</li>
</ul>
<p>There are no other functional changes in this release.</p><p><em>(The post <a href="https://orbitalhq.com/changelog/2025-12-02-release-announcement-0.36.2">0.36.2 released</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/changelog-cards/2025-12-02-release-announcement-0.36.2.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[0.36.1 released]]></title>
            <link>https://orbitalhq.com/changelog/2025-11-11-release-announcement-0.36.1</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2025-11-11-release-announcement-0.36.1</guid>
            <pubDate>Tue, 11 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Orbital 0.36.1 is a patch release that addresses memory leaks.]]></description>
            <content:encoded><![CDATA[<p>Orbital 0.36.1 is a patch release that addresses memory leaks.</p>
<p>There are no other functional changes in this release.</p><p><em>(The post <a href="https://orbitalhq.com/changelog/2025-11-11-release-announcement-0.36.1">0.36.1 released</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/changelog-cards/2025-11-11-release-announcement-0.36.1.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Breaking change - improved type checking with arrays in 0.36]]></title>
            <link>https://orbitalhq.com/changelog/2025-08-04-improved-array-type-checking</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2025-08-04-improved-array-type-checking</guid>
            <pubDate>Mon, 04 Aug 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Orbital 0.36 introduces a fix to type checking with array arguments.]]></description>
            <content:encoded><![CDATA[<p>Orbital 0.36 introduces a fix to type checking with array arguments.</p>
<p>Previously, arrays were not being correctly type checked, such that this was possible:</p>
<section><div><div><span>Show schema</span><div><a href="https://playground.taxilang.org" target="_blank" rel="noreferrer"><span>Edit this on Taxi Playground</span></a><span>Run this query</span></div></div><div><div><textarea id="_R_aqqj5_-query" rows="4" wrap="off" spellCheck="false">import Actor
find { 
   films: Film[] = Film[] as Actor[]
}</textarea></div></div></div></section>
<p>The same type checking would also fail with arguments to functions or expression types:</p>
<section><div><div><span>Show schema</span><div><a href="https://playground.taxilang.org" target="_blank" rel="noreferrer"><span>Edit this on Taxi Playground</span></a><span>Run this query</span></div></div><div><div><textarea id="_R_iqqj5_-query" rows="5" wrap="off" spellCheck="false">import Actor
given { actors: Actor[] = [{name: &quot;Jim&quot;}]}
find { 
   films: Film = onlyOneFilm(actors)
}</textarea></div></div></div></section>
<p>These now correctly return compilation errors.</p>
<p>This is a breaking change, as these statements did not used to return compilation errors (but would not behave as expected).</p>
<p>This change will be released in 0.36, and is available from 0.36.0-M9</p><p><em>(The post <a href="https://orbitalhq.com/changelog/2025-08-04-improved-array-type-checking">Breaking change - improved type checking with arrays in 0.36</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/changelog-cards/2025-08-04-improved-array-type-checking.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Orbital 0.35 - Partial models, mixed-source projects, parallel streaming, improved caching]]></title>
            <link>https://orbitalhq.com/changelog/2025-05-07-release-announcement-0-35-0</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2025-05-07-release-announcement-0-35-0</guid>
            <pubDate>Wed, 07 May 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Orbital 0.35 - Partial models, mixed-source projects, parallel streaming, improved caching]]></description>
            <content:encoded><![CDATA[<figure><img src="https://orbitalhq.com/assets/title-card-DCtABlAo.jpg" alt=""/><span></span></figure><p>Orbital 0.35.0 brings significant enhancements to core capabilities, with major improvements to streaming,
caching, and model handling.</p>
<p>This release focuses on stability and performance, particularly for high-volume data processing scenarios.</p>
<h2 id="partial-models"><a href="#partial-models">​<span></span></a>Partial models</h2>
<p>Partial models create variations of existing models where all fields are optional. This pattern is especially useful for API operations that support partial updates (PATCH), allowing clients to send only the fields they want to change.</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>model</span><span> </span><span>Customer</span><span> </span><span>{</span></span><span><span>   id</span><span>:</span><span> CustomerId</span><span> </span><span>inherits</span><span> </span><span>String</span></span><span><span>   name</span><span>:</span><span> CustomerName</span><span> </span><span>inherits</span><span> </span><span>String</span></span><span><span>}</span></span><span><span>   </span></span><span><span>// Creates a new model where all fields are optional</span></span><span><span>partial </span><span>model</span><span> </span><span>CustomerUpdate</span><span> from Customer</span></span></code></pre></div></div>
<p>When you create a partial model, all fields become optional (nullable), including:</p>
<ul role="list">
<li>Nested objects: Automatically converted to partial versions</li>
<li>Collections: Arrays become arrays of partial versions</li>
<li>Self-references: Updated to reference the partial version</li>
<li>Annotations from the source model are merged with annotations on the partial model</li>
<li>Modifiers are inherited with one exception: partial models cannot be <code>closed</code></li>
</ul>
<p>This all combines well with the @OmitNulls annotation to ensure null fields are excluded from serialized payloads:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>// Original model with required fields</span></span><span><span>model</span><span> </span><span>Product</span><span> </span><span>{</span></span><span><span>   id</span><span>:</span><span> ProductId</span><span> </span><span>inherits</span><span> </span><span>String</span></span><span><span>   name</span><span>:</span><span> ProductName</span><span> </span><span>inherits</span><span> </span><span>String</span></span><span><span>   price</span><span>:</span><span> Price</span><span> </span><span>inherits</span><span> </span><span>Decimal</span></span><span><span>   category</span><span>:</span><span> Category</span></span><span><span>   tags</span><span>:</span><span> Tag</span><span>[</span><span>]</span></span><span><span>}</span></span><span>
</span><span><span>// Create a partial version where everything is optional</span></span><span><span>@</span><span>OmitNulls</span></span><span><span>partial </span><span>model</span><span> </span><span>ProductUpdate</span><span> from Product</span></span><span>
</span><span><span>service</span><span> </span><span>ProductCatalog</span><span> </span><span>{</span></span><span><span>   </span><span>// Full replacement (PUT)</span></span><span><span>   </span><span>write</span><span> </span><span>operation</span><span> </span><span>replaceProduct</span><span>(</span><span>Product</span><span>)</span><span>:</span><span> Product</span></span><span><span>   </span></span><span><span>   </span><span>// Partial update (PATCH)</span></span><span><span>   </span><span>write</span><span> </span><span>operation</span><span> </span><span>updateProduct</span><span>(</span><span>ProductUpdate</span><span>)</span><span>:</span><span> Product</span></span><span><span>}</span></span></code></pre></div></div>
<h2 id="openapi-avro-and-protobuf-in-a-taxi-project"><a href="#openapi-avro-and-protobuf-in-a-taxi-project">​<span></span></a>OpenAPI, Avro and Protobuf in a taxi project</h2>
<p>We now support including OpenAPI, Avro and Protobuf files directly within a taxi project.</p>
<p>Add entries in the <code>additionalSources</code> block of your <code>taxi.conf</code>, as shown below:</p>
<div><div><div><span>taxi.conf</span></div><div><span></span><span>Copy</span></div></div><div><pre><code><span><span>name</span><span>:</span><span> taxi/mixed</span><span>-</span><span>sources</span></span><span><span>version</span><span>:</span><span> 0.3.0</span></span><span><span>sourceRoot</span><span>:</span><span> src/</span></span><span><span>additionalSources</span><span>:</span><span> </span><span>{</span></span><span><span>   &quot;@orbital/avro&quot; = &quot;avro/src/</span><span>*.avsc&quot;</span></span><span><span>   &quot;@orbital/openapi&quot; = &quot;openapi/</span><span>*.yaml&quot;</span></span><span><span>   &quot;@orbital/protobuf&quot; = &quot;proto/src/</span><span>**/*.proto&quot;</span></span><span><span>}</span></span></code></pre></div></div>
<p>These sources are automatically read, along with their taxi annotations, and imported into your taxi project.</p>
<p>This simplifies setups (and startup times) for teams where each spec was  previously imported as standalone projects.</p>
<h2 id="parallel-streaming"><a href="#parallel-streaming">​<span></span></a>Parallel streaming</h2>
<p>When running Orbital in a cluster, background stream jobs can now be configured to run in parallel,
which controls the number of nodes in the cluster that will execute the stream.</p>
<p>using the <code>@Parallel</code> annotation.</p>
<p>For example, assuming Orbital is deployed in a 6-node cluster, consuming events from Kafka.</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>import</span><span> com</span><span>.</span><span>orbitalhq</span><span>.</span><span>streams</span><span>.</span><span>Parallel</span></span><span><span>   </span></span><span><span>@</span><span>Parallel</span><span>(</span><span>count </span><span>=</span><span> </span><span>4</span><span>)</span></span><span><span>query</span><span> </span><span>MyStream</span><span> </span><span>{</span></span><span><span>   </span><span>stream</span><span> </span><span>{</span><span> CustomerLoggedInEvent</span><span> </span><span>}</span></span><span><span>   call MyMongoDb</span><span>:</span><span>:</span><span>upsertCustomerMetrics</span></span><span><span>}</span></span></code></pre></div></div>
<p>In this configuration, 4 of the nodes will subscribe to Kafka, and consume the events.</p>
<p>Orbital correctly rebalances as nodes enter and leave the cluster.</p>
<p>Learn more in the <a href="https://orbitalhq.com/docs/querying/streaming-data#controlling-parallelism">streaming data docs</a></p>
<h2 id="improved-caching-controls"><a href="#improved-caching-controls">​<span></span></a>Improved caching controls</h2>
<p>The <code>@com.orbitalhq.caching.Cache</code> annotation offers control over caching behavior at both operation and model
levels.</p>
<p>You can disable caching for specific operations or data types, or adjust cache expiration
with configurable time-to-live settings.</p>
<p>This helps balance performance needs when working with both static reference data and
changing values in long-running stream processors.</p>
<p>Read more about configuring caching in the <a href="https://orbitalhq.com/docs/querying/caching">caching docs</a></p>
<h2 id="azure-service-bus"><a href="#azure-service-bus">​<span></span></a>Azure service bus</h2>
<p>We added support for Azure Service Bus, enabling integration with Azure messaging infrastructure
through a full-featured connector.</p>
<p>Read more in the <a href="https://orbitalhq.com/docs/describing-data-sources/azure-service-bus">Azure Service Bus docs</a></p>
<h2 id="other-updates"><a href="#other-updates">​<span></span></a>Other updates</h2>
<h3 id="enhanced-model--query-capabilities"><a href="#enhanced-model--query-capabilities">​<span></span></a>Enhanced Model &amp; Query Capabilities</h3>
<ul role="list">
<li><strong>Nested Projections with Multiple Scopes</strong>: Fixed support for nested projections with multiple scope variables, eliminating the “How to handle multiple scoped facts here?” error.</li>
<li><strong>Operation Input Improvements</strong>: Operations can now accept inputs populated by supertypes, enabling more flexible service invocation.</li>
<li>Added ability to use expressions and constraints on the left-hand side of type references. [ORB-932]</li>
<li>Object build type searches now correctly consider constraints. [ORB-895]</li>
<li>Improved support for constraints on nested chained projections. [ORB-897]</li>
<li><strong>Spread Operator Improvements</strong>: Fixed spread operator to properly consider inherited types. [ORB-891]</li>
</ul>
<h3 id="streaming-enhancements"><a href="#streaming-enhancements">​<span></span></a>Streaming Enhancements</h3>
<ul role="list">
<li>Added low-cardinality error reporting for streams, providing better visibility into failures during stream processing.</li>
<li>Fixed error reporting in streams so stream failures are accurately reported in the UI. [ORB-868]</li>
<li>Streaming queries with a mutation operation now continue even if the mutation operation fails. [ORB-934]</li>
</ul>
<h3 id="http-improvements"><a href="#http-improvements">​<span></span></a>HTTP Improvements</h3>
<ul role="list">
<li><strong>HTTP Retry Reporting</strong>: Fixed reporting of retried HTTP service calls in the profile window, improving visibility of retry attempts for operations with the <code>@HttpRetry</code> annotation. [ORB-931]</li>
</ul>
<h3 id="operational-improvements"><a href="#operational-improvements">​<span></span></a>Operational Improvements</h3>
<ul role="list">
<li><strong>Improved Error Reporting</strong>: Enhanced error reporting when variables are missing in queries, providing more meaningful feedback to developers.</li>
<li><strong>Metrics &amp; Monitoring</strong>: Multiple improvements to stream observability, including better error reporting, status monitoring, and metrics collection.</li>
</ul>
<h3 id="file-monitoring"><a href="#file-monitoring">​<span></span></a>File Monitoring</h3>
<ul role="list">
<li><strong>Git Project File Watching</strong>: Added support for polling file watchers with Git projects, providing more reliable file change detection in certain environments. [ORB-865]</li>
<li><strong>Empty Workspace Configuration</strong>: Added ability to configure file monitoring settings for automatically created empty workspaces.</li>
<li><strong>Authentication Improvements</strong>: Fixed issue where updates in auth.conf were not reflected in Orbital Query Execution. [ORB-943]</li>
</ul><p><em>(The post <a href="https://orbitalhq.com/changelog/2025-05-07-release-announcement-0-35-0">Orbital 0.35 - Partial models, mixed-source projects, parallel streaming, improved caching</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/assets/title-card-DCtABlAo.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Orbital 0.33 - Landing page insights, improved query editor, and simpler deployments.]]></title>
            <link>https://orbitalhq.com/changelog/2024-07-24-release-announcement-0-33-0</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2024-07-24-release-announcement-0-33-0</guid>
            <pubDate>Wed, 24 Jul 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Orbital 0.33 - Landing page insights, improved query editor, and simpler deployments.]]></description>
            <content:encoded><![CDATA[<figure><img src="https://orbitalhq.com/assets/0-33-title-card-Gjg5NP06.jpg" alt=""/><span></span></figure><h2 id="orbital-0330---growing-pains-edition"><a href="#orbital-0330---growing-pains-edition">​<span></span></a>Orbital 0.33.0 - “Growing Pains” Edition</h2>
<p>Orbital 0.33 is out - with lots (and lots) of small, incremental improvements to the features you already know and love.</p>
<p>Sure, we skipped 0.32 - but who hasn’t had an episode in early 30’s they forgot?</p>
<p>Because this release is all about beloved features growing, and squashing bug fixes, and because we made a
bold choice shortly after Dry January finished to name each of this year’s releases after an 80’s sitcom,
we’re proud to present Orbital 0.33 - The Growing Pains edition.</p>
<h2 id="highlights"><a href="#highlights">​<span></span></a>Highlights</h2>
<ul role="list">
<li>Improved UX: <a href="#a-new-landing-experience">landing page</a> and <a href="#improved-query-editor-experience">query editor improvements</a></li>
<li>Orbital is simpler to deploy, as we’ve <a href="#stream-server-is-now-folded-into-orbital">merged the Stream Server into Orbital</a></li>
<li><a href="#improved-s3-connector">Improved S3 connector</a></li>
<li><a href="#streaming-queries-are-observable-via-http-endpoints">Streaming queries observable over Http endpoints</a></li>
<li><a href="#avro-format">Avro support</a></li>
<li>Lots of <a href="#bug-fixes">bug fixes</a></li>
</ul>
<h3 id="a-new-landing-experience"><a href="#a-new-landing-experience">​<span></span></a>A new landing experience</h3>
<p>We’ve completely redesigned the landing page and now surface insights into the health of your project’s connections,
an at a glance overview of schema changes, as well as metrics on currently running services.</p>
<p>We’ll be adding more content in this area as well, to help get new users up to speed,
and provide more experienced users with documentation and tutorials to improve their Orbital productivity. Watch this space!</p>
<h3 id="improved-query-editor-experience"><a href="#improved-query-editor-experience">​<span></span></a>Improved Query Editor experience</h3>
<p>You asked for it, and we listened - tabs are now part of the query editor experience!</p>
<figure><img src="https://orbitalhq.com/assets/query-editor-BwUgCj7Y.png" alt="Tabs FTW!"/><span></span><figcaption><span>Tabs FTW!</span></figcaption></figure>
<p>Create as many queries as you like, safe in the knowledge that you can tweak and edit them in isolation,
and run the query when you’re satisfied things are looking good.</p>
<p>Results are retained for each tab, allowing some serious multitasking.</p>
<p>We’ve also overhauled the query editor’s toolbar, allowing you to <a href="#streaming-queries-are-observable-via-http-endpoints">publish queries to endpoints</a>, and remove them
if they’ve already been published. Alongside that, you’re now able to see which queries have endpoints associated with them, launch the endpoint,
or copy the endpoint URL or code for a cURL command.</p>
<p>We’re confident these UI additions further improve the developer experience, let us know what other improvements in this space you’d like to see.</p>
<h3 id="stream-server-is-now-folded-into-orbital"><a href="#stream-server-is-now-folded-into-orbital">​<span></span></a>Stream server is now folded into Orbital</h3>
<p>The Stream Server historically was a standalone service that was responsible for executing long-running streaming queries.</p>
<p>It’s now folded directly into Orbital, simplifying the deployment significantly.</p>
<h3 id="improved-s3-connector"><a href="#improved-s3-connector">​<span></span></a>Improved S3 connector</h3>
<p>Our S3 connector received a much-needed makeover.</p>
<p>When reading, we now support reading from either a single file, an entire bucket, or any type of wildcard glob pattern. Files on S3 are also now supported as a standard write target.</p>
<p>We also support reading and writing to S3 in any of Orbital’s <a href="https://orbitalhq.com/docs/data-formats/overview" target="_blank" rel="noreferrer">supported formats</a>.</p>
<p>This means you can now do things like query a database, enrich it against a series of APIs, and write the results to a csv file on an S3 bucket. Alternatively, you can read a CSV file from S3, split it, enrich each record and write the values to Kafka.</p>
<p>For example:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>// Given a model of data stored on S3:</span></span><span><span>@</span><span>Csv</span></span><span><span>model</span><span> </span><span>TradeSummary</span><span> </span><span>{</span></span><span><span>   symbol</span><span> </span><span>:</span><span> Symbol</span><span> </span><span>inherits</span><span> </span><span>String</span></span><span><span>   open</span><span> </span><span>:</span><span> OpenPrice</span><span> </span><span>inherits</span><span> </span><span>Decimal</span></span><span><span>   high</span><span> </span><span>:</span><span> HighPrice</span><span> </span><span>inherits</span><span> </span><span>Decimal</span></span><span><span>   close</span><span> </span><span>:</span><span> ClosePrice</span><span> </span><span>inherits</span><span> </span><span>Decimal</span></span><span><span>}</span></span><span>
</span><span><span>// Expose the S3 bucket:</span></span><span><span>@</span><span>S3Service</span><span>(</span><span>connectionName </span><span>=</span><span> </span><span>&quot;MyAwsConnection&quot;</span><span>)</span></span><span><span>service</span><span> </span><span>AwsBucketService</span><span> </span><span>{</span></span><span><span>    </span><span>@</span><span>S3Operation</span><span>(</span><span>bucket </span><span>=</span><span> </span><span>&quot;MyTrades&quot;</span><span>)</span></span><span><span>    </span><span>operation</span><span> </span><span>readBucket</span><span>(</span><span>filename</span><span>:</span><span>FilenamePattern</span><span> </span><span>=</span><span> </span><span>&quot;trades.csv&quot;</span><span>)</span><span>:</span><span>TradeSummary</span><span>[</span><span>]</span></span><span><span>}</span></span><span>
</span><span><span>// Expose some enrichment services:</span></span><span><span>service</span><span> </span><span>TradeVolumeApi</span><span> </span><span>{</span></span><span><span>   </span><span>@</span><span>HttpOperation</span><span>(</span><span>url</span><span>=</span><span>&quot;https://myTradeService/volumes/{symbol}&quot;</span><span>,</span><span> method </span><span>=</span><span> </span><span>&quot;GET&quot;</span><span>)</span></span><span><span>   </span><span>operation</span><span> </span><span>getTradeVolumes</span><span>(</span><span>@</span><span>PathVariable</span><span>(</span><span>&quot;symbol&quot;</span><span>)</span><span> symbol</span><span> </span><span>:</span><span> Symbol</span><span>)</span><span>:</span><span> TradeVolumes</span></span><span><span>}</span></span><span>
</span><span><span>// Expose our enriched data model:</span></span><span><span>model</span><span> </span><span>TradesWithVolumes</span><span> </span><span>{</span></span><span><span>  symbol</span><span> </span><span>:</span><span> Symbol</span></span><span><span>  prices </span><span>:</span><span>  </span><span>{</span></span><span><span>     open</span><span> </span><span>:</span><span> OpenPrice</span></span><span><span>     close</span><span> </span><span>:</span><span> ClosePrice</span></span><span><span>  </span><span>}</span></span><span><span>  volumes </span><span>:</span><span> </span><span>{</span></span><span><span>    volumes</span><span> </span><span>:</span><span> TradeVolumes</span></span><span><span>  </span><span>}</span></span><span><span>}</span></span><span>
</span><span><span>// And a Kafka topic to write to:</span></span><span><span>service</span><span> </span><span>MyKafkaBroker</span><span> </span><span>{</span></span><span><span>   </span><span>@</span><span>KafkaOperation</span><span>(</span><span>topic </span><span>=</span><span> </span><span>&quot;tradesWithVolumes&quot;</span><span>)</span></span><span><span>   </span><span>write</span><span> </span><span>operation</span><span> </span><span>publishTrades</span><span>(</span><span>TradesWithVolumes</span><span>)</span><span>:</span><span>TradesWithVolumes</span></span><span><span>}</span></span><span>
</span><span><span>// Given the above, we can fetch from S3, transform against our</span></span><span><span>// enrichment API, and write the results to Kafka using the following</span></span><span><span>// query:</span></span><span><span>find</span><span> </span><span>{</span><span> TradeSummary</span><span>[</span><span>]</span><span> </span><span>)</span></span><span><span>call MyKafkaBroker</span><span>:</span><span>:</span><span>publishTrades</span></span></code></pre></div></div>
<p>See more examples in the docs for the <a href="https://orbitalhq.com/docs/describing-data-sources/aws-services#s3">S3 connector</a>.</p>
<h3 id="kafka-headers-and-message-key-are-now-available"><a href="#kafka-headers-and-message-key-are-now-available">​<span></span></a>Kafka headers and message key are now available</h3>
<p>You can now access the message key for a Kafka message directly in your model:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>import</span><span> com</span><span>.</span><span>orbitalhq</span><span>.</span><span>kafka</span><span>.</span><span>KafkaMessageKey</span></span><span>
</span><span><span>model</span><span> </span><span>Movie</span><span> </span><span>{</span></span><span><span>  </span><span>// The key from Kafka will be read into the id property</span></span><span><span>  </span><span>@</span><span>KafkaMessageKey</span></span><span><span>  id</span><span> </span><span>:</span><span> MovieId</span><span> </span><span>inherits</span><span> </span><span>String</span></span><span><span>  title</span><span> </span><span>:</span><span> Title</span><span> </span><span>inherits</span><span> </span><span>String</span></span><span><span>}</span></span></code></pre></div></div>
<p>Similarly, Kafka message headers can now be provided using the @KafkaMessageMetadata annotation</p>
<p>More details are available in the updated <a href="https://orbitalhq.com/docs/describing-data-sources/kafka#keys-headers-and-metadata">Kafka documentation</a></p>
<h3 id="streaming-queries-are-observable-via-http-endpoints"><a href="#streaming-queries-are-observable-via-http-endpoints">​<span></span></a>Streaming queries are observable via Http endpoints</h3>
<p>Orbital has supported saved streaming queries for some time. These run in the background doing things like consuming from
a Kafka topic (amongst others), transforming, enriching and writing data.</p>
<p>Now, these same queries can be observed via HTTP endpoints - using either Server Sent Events or Websockets. Simply add an annotation to your query definition:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>@</span><span>HttpOperation</span><span>(</span><span>url </span><span>=</span><span> </span><span>&#x27;/api/q/newReleases&#x27;</span><span>,</span><span> method </span><span>=</span><span> </span><span>&#x27;GET&#x27;</span><span>)</span></span><span><span>query</span><span> </span><span>getNewReleaseAnnouncements</span><span> </span><span>{</span></span><span><span>  </span><span>stream</span><span> </span><span>{</span><span> NewReleaseAnnouncement</span><span> </span><span>}</span><span> </span><span>as</span><span> </span><span>{</span></span><span><span>    title</span><span> </span><span>:</span><span> MovieTitle</span></span><span><span>    reviewScore</span><span> </span><span>:</span><span> ReviewScore</span></span><span><span>  </span><span>}</span><span>[</span><span>]</span></span><span><span>}</span></span></code></pre></div></div>
<p>These annotations can also be added by using the new publish endpoint feature detailed in the <a href="#improved-query-editor-experience">query editor improvements</a></p>
<p>This query would be available over Curl using</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>curl</span><span> </span><span>-X</span><span> GET </span><span>&#x27;http://localhost:9022/api/q/newReleases&#x27;</span><span> </span><span>\</span></span><span><span>  </span><span>-H</span><span> </span><span>&#x27;Accept: text/event-stream;charset-UTF-8&#x27;</span></span></code></pre></div></div>
<p>More details are available in the documentation for <a href="https://orbitalhq.com/docs/querying/queries-as-endpoints#saved-streams">saved streaming queries</a>.</p>
<h3 id="avro-format"><a href="#avro-format">​<span></span></a>Avro format</h3>
<p>We’ve added support for Avro as a format - both reading and writing.</p>
<p>Additionally, we also support Confluent’s own, special, <a href="https://docs.confluent.io/platform/current/schema-registry/fundamentals/serdes-develop/serdes-avro.html" target="_blank" rel="noreferrer">magical version of Avro</a>, which injects a few additional bytes at
the start … “magic bytes” — their words, not ours. Anyway, we support reading this, without a dependency on the Confluent schema server.</p>
<p>Find out more about Avro support in the <a href="https://orbitalhq.com/docs/data-formats/avro">Avro documentation</a></p>
<h3 id="batched-writes-for-mongo"><a href="#batched-writes-for-mongo">​<span></span></a>Batched writes for Mongo</h3>
<p>Orbital can now batch upserts target to a Mongo Collections. See the <a href="https://orbitalhq.com/docs/describing-data-sources/mongodb#batching-upsert-operations">documentation for details.</a></p>
<h3 id="batching-mutations"><a href="#batching-mutations">​<span></span></a>Batching mutations</h3>
<p>Previously, mutations were run incrementally in parallel.</p>
<p>You can now optionally indicate that a mutation should be performed at the end of the query,
after all projections have been completed. This is useful for targets like S3, where incremental writing isn’t supported.</p>
<p>More information and examples are available in our updated docs on <a href="https://orbitalhq.com/docs/querying/mutations#writing-single-item-vs-batch">mutations</a>.</p>
<h3 id="other-features"><a href="#other-features">​<span></span></a>Other features:</h3>
<ul role="list">
<li><a href="https://orbitalhq.com/docs/describing-data-sources/kafka#additional-kafka-connection-properties">Configurable groupId for a Kafka connection</a></li>
<li><a href="https://orbitalhq.com/docs/describing-data-sources/hazelcast#advanced-configuration">Better configuration options for Hazelcast connections</a></li>
</ul>
<h2 id="bug-fixes"><a href="#bug-fixes">​<span></span></a>Bug Fixes</h2>
<h3 id="performance"><a href="#performance">​<span></span></a>Performance</h3>
<p>There’s been a number of performance improvements across the stack:</p>
<ul role="list">
<li>Fixed bottleneck when queries don’t use a projection in a mutation</li>
<li>Fixed performance writing to Hazelcast maps</li>
<li>Fixed performance issues with @Cache annotated queries</li>
<li>A number of minor tweaks to the core query engine to improve performance</li>
<li>We’ve fixed issues making it very slow to parse database metadata (when importing a database table)</li>
</ul>
<h3 id="relative-paths-in-workspaceconf"><a href="#relative-paths-in-workspaceconf">​<span></span></a>Relative paths in workspace.conf</h3>
<p>Some customers like to manually deploy their taxi projects onto the same box that Orbital is running on, and refer to the taxi projects using file paths (rather than pulling from a git repository).</p>
<p>In cases like this, it’s often convenient to declare your projects in workspace.conf with relative paths (relative to the workspace.conf file), rather than absolute paths. We’ve fixed a number of bugs that previously made this very hit-and-miss. Now, it’s all hits.</p>
<h3 id="pagination-in-query-history"><a href="#pagination-in-query-history">​<span></span></a>Pagination in query history</h3>
<p>Previously, we only showed the first 100 results in query history. We now paginate these, so the full result set is available.</p>
<h3 id="websockets-timing-out"><a href="#websockets-timing-out">​<span></span></a>Websockets timing out</h3>
<p>We fixed a number of issues with websockets timing out - this was particularly noticeable if Orbital was deployed in AWS behind an ALB, where the ALB would terminate websocket connections after a period of inactivity. We’ve added ping/pong on the websockets to prevent this.</p>
<h3 id="ability-to-remove-projects-pushed-to-orbital"><a href="#ability-to-remove-projects-pushed-to-orbital">​<span></span></a>Ability to remove projects pushed to Orbital</h3>
<p>Often, a microservice will publish it’s project directly to Orbital. Previously, these weren’t removable using the UI. Now they are. That’s progress.</p>
<h3 id="fixed-cast-expressions-on-a-field"><a href="#fixed-cast-expressions-on-a-field">​<span></span></a>Fixed cast expressions on a field</h3>
<p>This used to throw an error. Now it doesn’t.</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>find</span><span> </span><span>{</span></span><span><span>    long</span><span>:</span><span> Long</span><span> </span><span>by</span><span> </span><span>(</span><span>Long</span><span>)</span><span> Foo</span></span><span><span>}</span></span></code></pre></div></div>
<h3 id="projecting-a-scoped-variable-to-a-predefined-array-type"><a href="#projecting-a-scoped-variable-to-a-predefined-array-type">​<span></span></a>Projecting a scoped variable to a predefined array type</h3>
<p>This also used to throw an error. We fixed that too.</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>find</span><span> </span><span>{</span><span> FilmCatalog</span><span> </span><span>}</span><span> </span><span>as</span><span> </span><span>(</span><span>films</span><span>:</span><span>Film</span><span>[</span><span>]</span><span>)</span><span> </span><span>-</span><span>&gt;</span><span> Movie</span><span>[</span><span>]</span></span></code></pre></div></div>
<h3 id="lots-of-bug-fixes-with-git-based-projects"><a href="#lots-of-bug-fixes-with-git-based-projects">​<span></span></a>Lots of bug fixes with Git based projects</h3>
<p>We squashed lots of bugs related to workspaces that were pulled from git, and projects within workspaces that were pulled from git.
This now behaves much much better.</p>
<h3 id="sqs-subscriber-fixes"><a href="#sqs-subscriber-fixes">​<span></span></a>SQS Subscriber fixes</h3>
<p>We have fixed an SQS subscription that might result in corresponding poll operations interrupted after the first successful poll.
Additional configuration parameters to fine tune AWS SQS poll operations were also added, see the <a href="https://orbitalhq.com/docs/describing-data-sources/aws-services#consuming-events" target="_blank" rel="noreferrer">docs for the details.</a></p>
<h3 id="changes-to-workspaceconf-are-now-live-reloaded"><a href="#changes-to-workspaceconf-are-now-live-reloaded">​<span></span></a>Changes to workspace.conf are now live reloaded</h3>
<p>This bug manifested in lots of little, but rather annoying changes.</p>
<p>We now automatically update the UI after changes are made to the workspace.conf file (such as adding and removing projects).</p>
<h3 id="other-bug-fixes"><a href="#other-bug-fixes">​<span></span></a>Other bug fixes:</h3>
<ul role="list">
<li>We’ve addressed issues with Logout not working as expected on Cognito</li>
<li>Importing a Protobuf spec from the UI now works</li>
<li>Saving a query no longer breaks the formatting</li>
<li>Language server now reconnects automatically after disconnect</li>
<li>Cancelling a streaming query from the query history view works again</li>
<li>Fixed a bug where JSON results viewer would show type hints over and over and over</li>
<li>Download query results as CSV works again</li>
<li>Browser would crash when running queries returning large volumes of results</li>
<li>A misconfigured workspace.conf file could prevent the server from starting</li>
</ul><p><em>(The post <a href="https://orbitalhq.com/changelog/2024-07-24-release-announcement-0-33-0">Orbital 0.33 - Landing page insights, improved query editor, and simpler deployments.</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/assets/0-33-title-card-Gjg5NP06.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[0.31 released - Hazelcast, MongoDb and a new onboarding experience]]></title>
            <link>https://orbitalhq.com/changelog/2024-04-05-release-announcement-0-31-0</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2024-04-05-release-announcement-0-31-0</guid>
            <pubDate>Fri, 05 Apr 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Orbital 0.31.0 - "Alf" - MongoDB support, Hazelcast datasources and onboarding]]></description>
            <content:encoded><![CDATA[<figure><img src="https://orbitalhq.com/assets/0-31-title-card-BI6HYHTz.jpg" alt=""/><span></span></figure><h2 id="orbital-0310---alf-edition"><a href="#orbital-0310---alf-edition">​<span></span></a>Orbital 0.31.0 - “Alf” Edition</h2>
<p>We’re excited
to announce the release of Orbital <a href="https://hub.docker.com/layers/orbitalhq/orbital/0.31.0/images/sha256-62c195eed42025fec0d22debcdbc6c0d9e250425eeb37b34a92e825ffae4f416?context=explore" target="_blank" rel="noreferrer">0.31.0</a> -
with a large focus on helping new users feel comfortable — which reminded us of a certain ’80s friend.
So, we present Orbital 0.31.0 - The “Alf” edition. 👽🛸🏡</p>
<h2 id="highlights"><a href="#highlights">​<span></span></a>Highlights</h2>
<ul role="list">
<li>New connectors: <a href="#mongodb-support">MongoDB</a> and <a href="#hazelcast-support">Hazelcast</a></li>
<li><a href="#new-onboarding-experience">New onboarding flow</a>, and <a href="#improved-ux-for-managing-projects-and-data-sources">improved UX for projects and data sources</a></li>
<li><a href="#filtering-a-stream">Filtering streams of data</a></li>
<li><a href="#controlling-services-used-in-a-query-preview">Controlling the services called in a query</a></li>
</ul>
<h3 id="mongodb-support-preview"><a href="#mongodb-support-preview">​<span></span></a>MongoDB support (Preview)</h3>
<p>We now support <a href="https://orbitalhq.com/docs/describing-data-sources/mongodb">MongoDB</a> as a datasource, including support for both
<a href="https://orbitalhq.com/docs/describing-data-sources/mongodb#querying-collections">querying</a> and <a href="https://orbitalhq.com/docs/describing-data-sources/mongodb#writing-data-to-a-collection">writing</a></p>
<h3 id="hazelcast-support-preview"><a href="#hazelcast-support-preview">​<span></span></a>Hazelcast support (Preview)</h3>
<p>Building on top of our support for <a href="https://hazelcast.com" target="_blank" rel="noreferrer">Hazelcast</a> as a <a href="https://orbitalhq.com/docs/querying/caching">cache</a>,
Hazelcast is now available as a data source, supporting reads, writes and streams.</p>
<p>Use a Hazelcast Map as a <a href="https://orbitalhq.com/docs/describing-data-sources/hazelcast#writing-data-to-hazelcast">high speed data store</a>,
or use a Map as the basis for a <a href="https://orbitalhq.com/docs/describing-data-sources/hazelcast#streaming-data-from-hazelcast">Stream of data</a>,
giving you the best of both worlds.</p>
<h3 id="new-onboarding-experience"><a href="#new-onboarding-experience">​<span></span></a>New onboarding experience</h3>
<p>For those wanting to dip their toes into the world of Taxi and Orbital, we’ve built an onboarding flow which should help
get you up to speed in no time! And remember, just like Alf trying to fit in with the Tanners, you might feel a bit out
of place at first, but with our guidance, you’ll be navigating through like a pro in no time!</p>
<p>You’ll see this screen automatically when you don’t have any data sources declared, but you can also view it manually by
going to /onboarding.</p>
<figure><img src="https://orbitalhq.com/assets/onboarding-BYhHAFME.png" alt="The new onboarding flow"/><span></span><figcaption><span>The new onboarding flow</span></figcaption></figure>
<p>We welcome feedback in this area of the app, so please take it for a spin and let us know what you think.</p>
<h3 id="improved-ux-for-managing-projects-and-data-sources"><a href="#improved-ux-for-managing-projects-and-data-sources">​<span></span></a>Improved UX for managing projects and data sources</h3>
<p>Now that you’re familiar with adding projects and data sources after completing the onboarding steps, you’ll be happy to
hear that those same project import and data source creation steps are available to you outside the onboarding flow.
Consistency FTW!</p>
<p>We’ve completely reworked the Connections page, allowing a more streamlined view of all connections, and their related
data sources.</p>
<figure><img src="https://orbitalhq.com/assets/data-source-tree-CDMdKcSQ.jpg" alt="Viewing connections and data sources all from one screen"/><span></span><figcaption><span>Viewing connections and data sources all from one screen</span></figcaption></figure>
<p>If you want to add a new data source, then the same flow that was created for the onboarding flow is now used here as
well. It’s like having Alf in charge of the kitchen - he sticks to his recipes with that good ‘ol fashioned consistency
that we’re all about here at the house of Orbital.</p>
<figure><img src="https://orbitalhq.com/assets/add-data-source-y6jRubvj.jpg" alt="Adding a new data source"/><span></span><figcaption><span>Adding a new data source</span></figcaption></figure>
<h3 id="sliding-sidebars"><a href="#sliding-sidebars">​<span></span></a>Sliding Sidebars</h3>
<p>Ever needed a few more cm’s of screen space and thought, gee that sidebar is taking up a bunch of space? Well, now you
can collapse it with a click of the mouse, and regain all that space you’ve been desperately hankering for. We’ll
remember your preference as well, and restore things how you left them.</p>
<figure><img src="https://orbitalhq.com/assets/sidebar-collapse-DRpusLhj.png" alt="Optimise your screen real estate, all with one click!"/><span></span><figcaption><span>Optimise your screen real estate, all with one click!</span></figcaption></figure>
<h3 id="controlling-services-used-in-a-query-preview"><a href="#controlling-services-used-in-a-query-preview">​<span></span></a>Controlling services used in a query (preview)</h3>
<p>By popular demand, one of our most requested features is the ability to control which services are called in a query.
After all - if Alf taught us anything - given a universe of possibilities, a little navigation can save you landing in a whole world of trouble.</p>
<p>While designing this feature, we wanted to ensure that Taxi remains declarative - and find a balance between giving
users control over which services are called, while remaining resilient and self-adapting as services evolve.</p>
<p>You can now limit a query to <strong>only call specified services</strong>, with the <code>using</code> keyword:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>find</span><span> </span><span>{</span><span> Film</span><span>[</span><span>]</span><span> </span><span>}</span><span> </span><span>as</span><span> </span><span>{</span></span><span><span>  filmId</span><span> </span><span>:</span><span> FilmId</span></span><span><span>  reviews</span><span> </span><span>:</span><span> ReviewScore</span></span><span><span>}</span></span><span><span>using </span><span>{</span><span> FilmsDb</span><span>,</span><span> NetflixApi</span><span>:</span><span>:</span><span>getReviews </span><span>}</span></span></code></pre></div></div>
<p>The list of allowed endpoints can be a mixture of services (<code>FilmsDb</code>), or even specific operations on services
(<code>NetflixApi::getReviews</code>).</p>
<p>Similarly, you can allow Orbital to call any services <em>except</em> some, using the <code>excluding</code> keyword:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>find</span><span> </span><span>{</span><span> Film</span><span>[</span><span>]</span><span> </span><span>}</span><span> </span><span>as</span><span> </span><span>{</span></span><span><span>  filmId</span><span> </span><span>:</span><span> FilmId</span></span><span><span>  reviews</span><span> </span><span>:</span><span> ReviewScore</span></span><span><span>}</span></span><span><span>excluding </span><span>{</span><span> ImdbApi</span><span>,</span><span> RottenTomatoes</span><span>:</span><span>:</span><span>getReviews </span><span>}</span></span></code></pre></div></div>
<p>This too allows combining services and specific operations to exclude.</p>
<p>This feature is considered in preview, and the syntax may change, so we’re actively seeking feedback.</p>
<p>Please <a href="https://join.slack.com/t/orbitalapi/shared_invite/zt-697laanr-DHGXXak5slqsY9DqwrkzHg" target="_blank" rel="noreferrer">reach out</a> to share your thoughts.</p>
<h3 id="filtering-a-stream"><a href="#filtering-a-stream">​<span></span></a>Filtering a stream</h3>
<p>We’ve added new support for <a href="https://orbitalhq.com/docs/querying/streaming-data#filtering-streams">filtering streams of data</a> server-side (ie., on Orbital).</p>
<p>Imagine you have a Kafka stream of stock quotes, and you only want
quotes for a specific symbol - this is now possible using <code>.filterEach()</code>.</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>stream</span><span> </span><span>{</span><span> StockQuotes</span><span>.</span><span>filterEach</span><span>(</span><span> Symbol </span><span>-</span><span>&gt;</span><span> Symbol </span><span>==</span><span> </span><span>&#x27;AAPL&#x27;</span><span> </span><span>)</span><span> </span><span>}</span></span></code></pre></div></div>
<h3 id="http-headers-now-visible"><a href="#http-headers-now-visible">​<span></span></a>Http headers now visible</h3>
<p>We now display HTTP headers in the Profiler view of queries</p>
<figure><img src="https://orbitalhq.com/assets/http-headers-display-oVdy6yEf.png" alt="Http headers now visible"/><span></span><figcaption><span>Http headers now visible</span></figcaption></figure>
<h3 id="updates-to-stream-ux"><a href="#updates-to-stream-ux">​<span></span></a>Updates to Stream UX</h3>
<p>The Endpoints page now shows the current status of individual streams.</p>
<p>The Stream Page allows enabling &amp; disabling of individual streams.</p>
<figure><img src="https://orbitalhq.com/assets/stream-server-overview-DI-hnKF7.png" alt="Stream status now shown"/><span></span><figcaption><span>Stream status now shown</span></figcaption></figure>
<h3 id="streams-now-disabled-by-default"><a href="#streams-now-disabled-by-default">​<span></span></a>Streams now disabled by default</h3>
<p>When a stream appears for the first time in the schema, it’s now disabled by default, and required
manually enabling — for the first time only.</p>
<p>This is to prevent streams - which can be mutating - starting accidentally, because as Alf would say, ‘Hey, no one wants
accidental mutations on their hands… or their planet!</p>
<h3 id="streams-now-automatically-updated"><a href="#streams-now-automatically-updated">​<span></span></a>Streams now automatically updated</h3>
<p>Whenever changes are found in a running streaming query, the stream
is now automatically updated. Previously, this was buggy…Suboptimal.</p>
<h3 id="cve-updates"><a href="#cve-updates">​<span></span></a>CVE Updates</h3>
<p>This build bumps our internal dependencies, addressing the following CVE’s:</p>
<ul role="list">
<li><a href="https://nvd.nist.gov/vuln/detail/CVE-2024-22257" target="_blank" rel="noreferrer">CVE-2024-22257</a> Possible Broken Access Control in Spring Security With Direct Use of AuthenticatedVoter</li>
<li><a href="https://nvd.nist.gov/vuln/detail/CVE-2024-22234" target="_blank" rel="noreferrer">CVE-2024-22234</a> Broken Access Control in Spring Security With Direct Use of isFullyAuthenticated</li>
<li><a href="https://nvd.nist.gov/vuln/detail/CVE-2024-22259" target="_blank" rel="noreferrer">CVE-2024-22259</a> Spring Framework URL Parsing with Host Validation (2nd report)</li>
<li><a href="https://nvd.nist.gov/vuln/detail/CVE-2024-22243" target="_blank" rel="noreferrer">CVE-2024-22243</a> Spring Framework URL Parsing with Host Validation</li>
<li><a href="https://nvd.nist.gov/vuln/detail/CVE-2023-52425" target="_blank" rel="noreferrer">CVE-2023-52425</a> libexpat through 2.5.0 allows a denial of service</li>
</ul>
<aside role="note"><p><span>Info</span></p><p>We upgrade our dependencies regularly to address published CVE’s. Based on our independent research, Orbital
was not affected by these vulnerabilities.</p></aside><p><em>(The post <a href="https://orbitalhq.com/changelog/2024-04-05-release-announcement-0-31-0">0.31 released - Hazelcast, MongoDb and a new onboarding experience</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/assets/0-31-title-card-BI6HYHTz.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[0.30 is Out - SQL Server, new authentication methods, and JSON inside XML inside a... duck?]]></title>
            <link>https://orbitalhq.com/changelog/2024-03-08-release-announcement-0-30-0</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2024-03-08-release-announcement-0-30-0</guid>
            <pubDate>Fri, 08 Mar 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Orbital 0.30.0 - "Full House" - MSSQL, SAML, mTLS and Mixed Messages]]></description>
            <content:encoded><![CDATA[<figure><img src="https://orbitalhq.com/assets/0-30-title-card-BWp82QFu.jpg" alt=""/><span></span></figure><h2 id="orbital-0300---full-house-edition"><a href="#orbital-0300---full-house-edition">​<span></span></a>Orbital 0.30.0 - Full House Edition</h2>
<p>We’re excited to announce the release of Orbital <a href="https://hub.docker.com/layers/orbitalhq/orbital/0.30.0/images/sha256-ecffa5ece8d7e5dc6bbde2f1a47232ce393b34929415196c13ffae92d4fd6b69?context=explore" target="_blank" rel="noreferrer">0.30.0</a> - our “Full House” edition, because we got so distracted by Valentine’s Day last month that we didn’t manage to ship a release, making this one double-packed.</p>
<p>If you’re not familiar with Orbital, it’s a platform for automating integration between APIs, Databases, Message Brokers, Serverless Functions, and more.
We have great stuff like API-spec driven data sources, self-repairing integration, automated lineage and more.</p>
<p>So, let’s take a look at what we’ve been working on for the past two months.
It’s a full house jam packed with features and squashed bugs.</p>
<h2 id="highlights"><a href="#highlights">​<span></span></a>Highlights</h2>
<h3 id="ms-sql-server-support"><a href="#ms-sql-server-support">​<span></span></a>MS SQL Server support</h3>
<p>We’ve extended our family of supported databases to include MS SQL Server for comprehensive read and write operations.</p>
<p>So, it’s “DATABASES!
DATABASES!
DATABASES!”, sweaty armpits, and happy Microsoft shops.</p>
<p>Our docs explain all the details on <a href="https://orbitalhq.com/docs/describing-data-sources/configuring-connections#mssql-server">how to connect to MSSQL</a>, to get your Northwind blowing.
(Get it? That’s a MSSQL sample database joke. If you know, you know.)</p>
<figure><img src="https://media1.tenor.com/m/eIJUpOJlykUAAAAC/steve-ballmer-yes.gif" alt="Steve Balmer"/><span></span><figcaption><span>Steve Balmer</span></figcaption></figure>
<h3 id="saml-authentication-support"><a href="#saml-authentication-support">​<span></span></a>SAML authentication support</h3>
<p>Someone paid us a lot of money to build SAML. We didn’t wanna do it. But we did, and now it’s awesome. Learn more about how to configure <a href="https://orbitalhq.com/docs/deploying/authentication#saml-authentication">SAML authentication in Orbital</a>.</p>
<h3 id="mtls-support"><a href="#mtls-support">​<span></span></a>mTLS Support</h3>
<p>Mutual trust is a big theme in the Tanner household, and it’s something we can really get behind.</p>
<p>mTLS is now supported when calling HTTP(s) APIs. Read more about <a href="https://orbitalhq.com/docs/describing-data-sources/authentication-to-services#mutual-authentication-mtls">how to set up mTLS</a></p>
<h3 id="mixed-messages"><a href="#mixed-messages">​<span></span></a>Mixed messages</h3>
<p>Orbital will now read an XML message with a JSON message in the middle, or JSON with XML in it, or a CSV file with a JSON blog in that, or really anything inside of another thing, which is inside yet another thing.
It’s the integration version of a <a href="https://www.seriouseats.com/the-ultimate-turducken-recipe" target="_blank" rel="noreferrer">Turducken</a>.</p>
<p>For example, here’s some XML inside a JSON message:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>{</span></span><span><span>    </span><span>&quot;messageId&quot;</span><span> </span><span>:</span><span> </span><span>&quot;123&quot;</span><span>,</span></span><span><span>    </span><span>&quot;xmlRecord&quot;</span><span> </span><span>:</span><span> </span><span>&quot;&lt;person&gt;&lt;name&gt;Jimmy&lt;/name&gt;&lt;/person&gt;&quot;</span></span><span><span>}</span></span></code></pre></div></div>
<p>Here’s the associated definition:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>import</span><span> com</span><span>.</span><span>orbitalhq</span><span>.</span><span>formats</span><span>.</span><span>Xml</span></span><span><span>model</span><span> </span><span>MyMessage</span><span> </span><span>{</span></span><span><span>    messageId</span><span> </span><span>:</span><span> MessageId</span><span> </span><span>inherits</span><span> </span><span>String</span></span><span><span>    xmlRecord</span><span> </span><span>:</span><span> Person</span></span><span><span>}</span></span><span>
</span><span><span>@</span><span>Xml</span></span><span><span>model</span><span> </span><span>Person</span><span> </span><span>{</span></span><span><span>    name</span><span> </span><span>:</span><span> PersonName</span><span> </span><span>inherits</span><span> </span><span>String</span></span><span><span>}</span></span></code></pre></div></div>
<h3 id="using-jwt-claims-within-a-query"><a href="#using-jwt-claims-within-a-query">​<span></span></a>Using Jwt claims within a query</h3>
<p>You can now pass the claims from a JWT token into Orbital so the claims can be used during query execution,
and passed to upstream services.</p>
<p>Let’s look at a simple example where your JWT token has a key piece of information - the customers <code>accountId</code>.
If you want to use these to connect with external REST services to run specific Orbital queries, the first thing to do is create a model that
builds on Orbital’s basic <code>JwtClaim</code> model:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>// Custom JwtClaim model with contactId and accountId</span></span><span><span>model</span><span> </span><span>CompanyXJwtClaim</span><span> </span><span>inherits</span><span> </span><span>JwtClaim</span><span> </span><span>{</span></span><span><span>  accountId</span><span>:</span><span> AccountId</span><span> </span><span>// a claim present with the key accountId</span></span><span><span>  </span><span>// other claims omitted</span></span><span><span>}</span></span></code></pre></div></div>
<p>Adding this model to your system makes sure that <code>accountId</code> is available for Orbital when it runs queries.</p>
<p>For example, a service may require the users <code>accountId</code> from the JWT be passed in the URL:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>// A service needs to use the current users accountId in the URL: </span></span><span><span>service</span><span> </span><span>AccountService</span><span> </span><span>{</span></span><span><span>   </span><span>@</span><span>HttpOperation</span><span>(</span><span>method </span><span>=</span><span> </span><span>&quot;GET&quot;</span><span>,</span><span>url </span><span>=</span><span> </span><span>&quot;/account/{accountId}&quot;</span><span>)</span></span><span><span>   </span><span>operation</span><span> </span><span>getByAccountId</span><span>(</span><span>@</span><span>PathVariable</span><span>(</span><span>&quot;accountId&quot;</span><span>)</span><span> accountId</span><span>:</span><span> AccountId</span><span>)</span><span>:</span><span> Account</span></span><span><span>}</span></span></code></pre></div></div>
<p>To make the users <code>accountId</code> available, we simply expose the JWT to the query:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>query</span><span> </span><span>MyQuery</span><span> </span><span>(</span><span> jwt</span><span>:</span><span>CompanyXJwtClaim</span><span> </span><span>)</span><span> </span><span>{</span></span><span><span>   </span><span>given</span><span> </span><span>{</span><span> jwt </span><span>}</span></span><span><span>   </span><span>find</span><span> </span><span>{</span><span> Account</span><span> </span><span>}</span></span><span><span>}</span></span></code></pre></div></div>
<p>That’s it! The presented JWT is read and the <code>accountId</code> is used to invoice the <code>getByAccountId</code> operation.</p>
<h3 id="errors-on-streaming-messages"><a href="#errors-on-streaming-messages">​<span></span></a>Errors on streaming messages</h3>
<p>Previously, it was hard to see when things went wrong inside streaming queries, requiring tailing logs to debug issues.</p>
<p>Now, errors in streams are shown in a dedicated UI.</p>
<figure><img src="https://orbitalhq.com/assets/query-problems-panel-B4zmnzDG.gif" alt="Errors in streaming queries are now shown off for the beautiful learning opportunities they are."/><span></span><figcaption><span>Errors in streaming queries are now shown off for the beautiful learning opportunities they are.</span></figcaption></figure>
<h2 id="usability"><a href="#usability">​<span></span></a>Usability</h2>
<h3 id="filtering-in-the-results-table"><a href="#filtering-in-the-results-table">​<span></span></a>Filtering in the results table</h3>
<p>Results returned from the server can be filtered client side in the query view:</p>
<figure><img src="https://orbitalhq.com/assets/filters-BDk6t8Vl.gif" alt="Filtering tables in query results"/><span></span><figcaption><span>Filtering tables in query results</span></figcaption></figure>
<h2 id="language-features"><a href="#language-features">​<span></span></a>Language features</h2>
<h3 id="type-checker"><a href="#type-checker">​<span></span></a>Type checker</h3>
<p>We’ve enabled Taxi’s type checker by default, to help surface errors in queries earlier.</p>
<p>For example, everyone in our office has made this mistake before:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>find</span><span> </span><span>{</span><span> Film</span><span>[</span><span>]</span><span> </span><span>}</span><span> </span><span>as</span><span> </span><span>{</span></span><span><span>   cast</span><span>:</span><span> </span><span>(</span><span>Actor</span><span>[</span><span>]</span><span>)</span><span> </span><span>-</span><span>&gt;</span><span> </span><span>{</span><span> </span><span>// because this is projecting an array...</span></span><span><span>     name</span><span> </span><span>:</span><span> ActorName</span></span><span><span>   </span><span>}</span><span> </span><span>// &lt;--- ...this should be an array</span></span><span><span>}</span><span> </span><span>// &lt;-- so should this</span></span></code></pre></div></div>
<p>Now, the compiler tells us what a mistake it was, so we can take a good long look at ourselves.</p>
<h3 id="scoped-variables"><a href="#scoped-variables">​<span></span></a>Scoped Variables</h3>
<p>When projecting, you sometimes need to hoist multiple variables into the scope. This is to make them available at the top level of a projection, without declaring them directly in the output.</p>
<p>For example, in the below example, we want to operate on a single item from an array of values, as well as the parent object.</p>
<p>However, we need both the objects in scope:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>find</span><span> </span><span>{</span><span> Film</span><span> </span><span>}</span><span> </span><span>as</span><span> </span><span>(</span><span>Film</span><span>,</span><span> </span><span>first</span><span>(</span><span>Actor</span><span>[</span><span>]</span><span>)</span><span>)</span><span> </span><span>-</span><span>&gt;</span><span> </span><span>{</span><span>  </span><span>// two values declared in scope</span></span><span><span>    title</span><span> </span><span>:</span><span> Title</span><span> </span><span>// title comes from Film</span></span><span><span>    starring</span><span> </span><span>:</span><span> ActorName</span><span> </span><span>// ActorName comes from Actor</span></span><span><span>}</span></span></code></pre></div></div>
<p>Our query syntax now supports adding these additional variables into the query scope</p>
<h3 id="compiler-warnings-when-something-should-be-declared-closed"><a href="#compiler-warnings-when-something-should-be-declared-closed">​<span></span></a>Compiler warnings when something should be declared <code>closed</code></h3>
<p>Marking a model as <code>closed</code> in TaxiQL indicates that the query engine should not attempt to build an instance if you ask for it.</p>
<p>Generally, this is the expected behaviour for things that a server returns.</p>
<p>For example:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>// I want the Film object as returned from the server, not constructed</span></span><span><span>model</span><span> </span><span>Film</span><span> </span><span>{</span></span><span><span>   title</span><span> </span><span>:</span><span> Title</span><span> </span><span>inherits</span><span> </span><span>String</span></span><span><span>}</span></span><span>
</span><span><span>service</span><span> </span><span>Films</span><span> </span><span>{</span></span><span><span>   </span><span>operation</span><span> </span><span>findAllFilms</span><span>(</span><span>)</span><span>:</span><span>Film</span><span>[</span><span>]</span></span><span><span>}</span></span></code></pre></div></div>
<p>If writing a query like:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>find</span><span> </span><span>{</span><span> Film</span><span>[</span><span>]</span><span> </span><span>}</span></span></code></pre></div></div>
<p>In the above example, you don’t want Orbital to try to construct a Film instance, you want one returned.</p>
<p>If you forget to mark <code>Film</code> as <code>closed</code> then the compiler will now warn you.</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>// That&#x27;s better:</span></span><span><span>closed</span><span> </span><span>model</span><span> </span><span>Film</span><span> </span><span>{</span></span><span><span>   title</span><span> </span><span>:</span><span> Title</span><span> </span><span>inherits</span><span> </span><span>String</span></span><span><span>}</span></span></code></pre></div></div>
<h2 id="fixes"><a href="#fixes">​<span></span></a>Fixes</h2>
<p>Here’s a big long list of things that we showed to people who asked why we hadn’t been to the pub this month.</p>
<p>To play us out, while you read through our bug list, here’s the Full House theme song.</p>
<iframe src="https://www.youtube.com/embed/2EL65KLdEHE?si=_o36iLeKjkh63BUS" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowFullScreen=""></iframe>
<ul role="list">
<li><code>given</code> clause with cast statement referencing parameter throws exception</li>
<li>Server sends all responses as arrays</li>
<li>Server sends arrays when response isn’t an array</li>
<li>Response arrays of single item are incorrectly unwrapped</li>
<li>Compiler not erroring when projecting array to non-array</li>
<li>Can’t use params in call to table operation</li>
<li>Live query view in history is broken</li>
<li>Removing a project results in an orphaned view for a project that no longer exists</li>
<li>Can’t onboard Kafka connections via UI</li>
<li>Viewing Operations in Services view is borked</li>
<li>Incorrect responsive layout in TypeViewer component</li>
<li>Fix streaming results progress bar and record count</li>
<li>Query History should not list active queries in the history panel, only in the “active” panel</li>
<li>Copy as Curl breaks with single / double quote issues</li>
<li>“undefined” entries showing in catalog</li>
<li>Error not thrown when inner-projection mismatch on array properties</li>
<li>Schema view shows all types in uppercase</li>
<li>Duplicates listed in the intellisense</li>
<li>Active queries in history is missing icons</li>
<li>Docs missing from catalog page</li>
<li>Tables in connection details need a minimum width</li>
<li>Make checkboxes in app-model-attribute-tree-list readonly</li>
<li>Disable project selector when adding connection</li>
<li>Inlay type hints not shown in raw results</li>
<li>Can’t authenticate to Confluent Cloud Kafka</li>
<li>Format JSON responses in Response not working</li>
<li>Ensure UI is in correct state when query is run</li>
<li>Query History takes too long to load</li>
<li>Projections with fields that are subtypes assign incorrectly</li>
<li>Fields on anonymous types are not considered for population of graph queries</li>
<li>Projection of a scoped top-level array fails</li>
<li>Lineage for cached items can’t trace further back than the cache query</li>
<li>Query Plan diagram is broken when cache is invoeld</li>
<li>Services diagram renders shared attributes incorrectly</li>
<li>StateStore is applied without the annotation</li>
<li>Streaming queries are rewritten to join streams incorrectly</li>
<li>Better UX when nothing is registered</li>
<li>Starting a query with Apple+Enter / Ctrl+Enter shows incorrect time in ticker</li>
<li>Http 204 responses are not persisted</li>
<li>Language Server incorrectly reports some types as not defined</li>
<li>connections.conf not resolving env variables from env.conf</li>
<li>After saving a query with a streaming union type, can’t rerun another adhoc query with the same streaming union type</li>
<li>SQL queries fail if the table name is different from the model name</li>
<li>Profiler view doesn’t show all interactions</li>
</ul><p><em>(The post <a href="https://orbitalhq.com/changelog/2024-03-08-release-announcement-0-30-0">0.30 is Out - SQL Server, new authentication methods, and JSON inside XML inside a... duck?</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/assets/0-30-title-card-BWp82QFu.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[0.27 is Out - Retry, Cache Eviction and UX improvements]]></title>
            <link>https://orbitalhq.com/changelog/2024-01-27-release-announcement-0-27-0</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2024-01-27-release-announcement-0-27-0</guid>
            <pubDate>Sat, 27 Jan 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Orbital 0.27.0 - The "Cheers" Edition - Release Notes]]></description>
            <content:encoded><![CDATA[<figure><img src="https://orbitalhq.com/assets/title-card-i06M7AW0.jpg" alt=""/><span></span></figure><h2 id="orbital-0270---the-cheers-edition-"><a href="#orbital-0270---the-cheers-edition-">​<span></span></a>Orbital 0.27.0 - The “Cheers” Edition 🍻</h2>
<p>As the Orbital office farewells Dry January, we welcome back Friday drinks with a fresh release - <a href="https://hub.docker.com/layers/orbitalhq/orbital/0.27.0/images/sha256-80b561bf9e936a044ee26b6f8758af41e39d4eb7dc073b6eb7a8c78eabd7162d?context=explore" target="_blank" rel="noreferrer">0.27.0</a>.</p>
<p>Pull up a stool, grab your favorite beverage, and let’s toast to the new features, usability improvements, and fixes that are making Orbital 0.27.0 as cozy and welcoming as your favorite Boston bar.</p>
<h2 id="features"><a href="#features">​<span></span></a>Features</h2>
<h3 id="retry-operations"><a href="#retry-operations">​<span></span></a>Retry Operations</h3>
<p>Like Sam Malone behind the bar - or a Fraser reboot - we know the importance of second and third chances.</p>
<p>That’s why we’ve introduced <code>@Retry</code> annotations, ensuring that if at first you don’t succeed, requests can try, try again to connect and get your data flowing just right.
Read more about it in the release announcement <a href="https://orbitalhq.com/changelog/2024-01-26-retry-operations">here</a>, and the docs are available <a href="https://orbitalhq.com/docs/describing-data-sources/http#retry-policies">here</a></p>
<h3 id="cache-eviction"><a href="#cache-eviction">​<span></span></a>Cache Eviction</h3>
<p>There’s nothing worse than overstaying your welcome when it’s time to leave.</p>
<p>Orbital’s caches now support Cache headers, evicting data when it’s stale.
Read more about it <a href="https://orbitalhq.com/changelog/2024-01-26-cache-eviction">here</a>, with the docs available <a href="https://orbitalhq.com/docs/querying/caching">here</a></p>
<h3 id="better-connections-for-kafka"><a href="#better-connections-for-kafka">​<span></span></a>Better Connections for Kafka</h3>
<p>Our Kafka connections now have more options than Frasier had patients - with full support for secure Kafka connections.
Expect a seamless experience that keeps the data pouring in.  More detail available in our <a href="https://orbitalhq.com/docs/describing-data-sources/configuring-connections#additional-kafka-connection-properties">docs</a></p>
<h2 id="usability-stuff"><a href="#usability-stuff">​<span></span></a>Usability Stuff</h2>
<h3 id="better-handling-of-query-compilation-errors"><a href="#better-handling-of-query-compilation-errors">​<span></span></a>Better handling of query compilation errors</h3>
<p>Pobody’s Nerfect, right?</p>
<p>Orbital now displays compilation errors in a slightly less antagonistic way. Read more <a href="./2024-01-25-better-query-compilation-errors">here</a>.</p>
<h3 id="query-history-refreshes"><a href="#query-history-refreshes">​<span></span></a>Query history refreshes</h3>
<p>Running a new query now refreshes the history view automatically, much like Norm Peterson’s beer mug. You’ll always have the latest information at your fingertips, no manual refresh needed.</p>
<h3 id="loading-bars"><a href="#loading-bars">​<span></span></a>Loading bars</h3>
<p>Our loading bars have received a makeover, becoming more informative and visually appealing. It’s the little details that make all the difference, ensuring you’re not left hanging while waiting for your data to appear.</p>
<h2 id="fixes"><a href="#fixes">​<span></span></a>Fixes</h2>
<ul role="list">
<li>
<p><strong>Projections of Nested Arrays</strong>: We’ve fixed the projection of nested arrays, ensuring that your data structures are handled with the care and precision of Cliff Clavin’s factoids—accurate, detailed, and meticulously organized.</p>
</li>
<li>
<p><strong>Nested Values in Discovery:</strong> Nested values are now correctly used as inputs to discovery, making your data exploration as smooth and effective as Woody Boyd’s charm. No more confusion or missteps.</p>
</li>
<li>
<p><strong>Cancelled Queries:</strong> Cancelled queries now appropriately show as “cancelled,” clearing up any confusion and ensuring you’re not left wondering what went wrong. It’s straightforward communication, just how Coach would have wanted it.</p>
</li>
<li>
<p><strong>Improved Performance of Loading Query History:</strong> We’ve supercharged the performance of loading your query history, making it faster than ever. It’s like getting your data served up by Sam himself—quick, efficient, and with a smile.</p>
</li>
<li>
<p><strong>Fix duplicates on child properties with same names:</strong> An unfortunate little gremlin meant in certain conditions child properties with the same name as a parent would get incorrect values.</p>
</li>
</ul>
<p>So, here’s to Orbital 0.27.0 — Cheers to faster data, better performance, and a community where everyone is connected! 🍻</p><p><em>(The post <a href="https://orbitalhq.com/changelog/2024-01-27-release-announcement-0-27-0">0.27 is Out - Retry, Cache Eviction and UX improvements</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/assets/title-card-i06M7AW0.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Cache Eviction support]]></title>
            <link>https://orbitalhq.com/changelog/2024-01-26-cache-eviction</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2024-01-26-cache-eviction</guid>
            <pubDate>Fri, 26 Jan 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Orbital's caching layer now supports HTTP Cache headers]]></description>
            <content:encoded><![CDATA[<figure><img src="https://orbitalhq.com/assets/cover-image-CjJkw9qI.png" alt=""/><span></span></figure><h2 id="expiry-for-cached-queries"><a href="#expiry-for-cached-queries">​<span></span></a>Expiry for Cached Queries</h2>
<p>Orbital now honours HTTP cache headers on HTTP responses, when a cache is enabled for a query.</p>
<p>As described in <a href="https://orbitalhq.com/docs/querying/caching">Caching</a> Orbital provides ability to cache query results with <code>@Cache</code> annotation:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>@</span><span>Cache</span><span>(</span><span>connection </span><span>=</span><span> </span><span>&quot;mycache&quot;</span><span>)</span></span><span><span>find</span><span> </span><span>{</span><span> Film</span><span>[</span><span>]</span><span> </span><span>}</span></span></code></pre></div></div>
<p>Let assume that you have a rest end point returning list of films:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>service</span><span> </span><span>FilmServices</span><span> </span><span>{</span></span><span><span>  </span><span>@</span><span>HttpOperation</span><span>(</span><span>method </span><span>=</span><span> </span><span>&quot;GET&quot;</span><span>,</span><span> url </span><span>=</span><span> </span><span>&quot;...&quot;</span><span>)</span></span><span><span>  </span><span>operation</span><span> </span><span>listFilms</span><span>(</span><span>)</span><span>:</span><span>Film</span><span>[</span><span>]</span></span><span><span>}</span></span></code></pre></div></div>
<p>If your Rest operation returns <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control" target="_blank" rel="noreferrer">Cache-Control</a> header in its response,
Orbital will take the <code>max-age</code> directive into account and expire the cached query result accordingly.</p>
<p>Here as an example response with Cache-Control header:</p>
<figure><img src="https://orbitalhq.com/assets/http-response-cache-control-wDWMvd05.png" alt=""/><span></span></figure>
<p><code>max-age=144004</code> will get Orbital to cache the Film list for 4 hours. After 4 hours, the items in the query cache will expire automatically.</p>
<h2 id="grab-the-docs"><a href="#grab-the-docs">​<span></span></a>Grab the docs</h2>
<p>Read more about caching in our <a href="https://orbitalhq.com/docs/querying/caching">docs</a></p><p><em>(The post <a href="https://orbitalhq.com/changelog/2024-01-26-cache-eviction">Cache Eviction support</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/assets/cover-image-CjJkw9qI.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Http Retry Support]]></title>
            <link>https://orbitalhq.com/changelog/2024-01-26-retry-operations</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2024-01-26-retry-operations</guid>
            <pubDate>Fri, 26 Jan 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[If at first you don't succeed]]></description>
            <content:encoded><![CDATA[<figure><img src="https://orbitalhq.com/assets/cover-image-xte7Vc4K.jpg" alt=""/><span></span></figure><h2 id="retry-option-for-http-operations"><a href="#retry-option-for-http-operations">​<span></span></a>Retry Option for Http operations:</h2>
<p>Let’s say you need to stitch Film data with reviews coming from an unreliable third party Rest Api:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>service</span><span> </span><span>ReviewsApi</span><span> </span><span>{</span></span><span><span>    </span><span>@</span><span>HttpOperation</span><span>(</span><span>method </span><span>=</span><span> </span><span>&quot;GET&quot;</span><span>,</span><span> url </span><span>=</span><span> </span><span>&quot;https://reviews/{id}&quot;</span><span>)</span></span><span><span>    </span><span>operation</span><span> </span><span>getReviews</span><span>(</span><span>id</span><span>:</span><span> FilmId</span><span>)</span><span>:</span><span> FilmReview</span><span>[</span><span>]</span></span><span><span>}</span></span></code></pre></div></div>
<p>The third party REST API gives you intermittent HTTP 500s as it can’t cope with user requests at particular times during day.</p>
<p>To address such outages, you can now define a <code>HttpRetry</code> settings in Taxi for the operation.</p>
<p>Orbital Supports two <code>HttpRetry</code> policies:</p>
<h3 id="retry-policy-with-fixed-delay"><a href="#retry-policy-with-fixed-delay">​<span></span></a>Retry Policy with Fixed Delay</h3>
<p>Let say you want to Orbital to retry ‘getReviews’ operation when it responds with Http 500. You want Orbital to try the operation at most 10 times and wait 5 seconds between each retry.
Here is how you can modify the taxi definition:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>service</span><span> </span><span>ReviewsApi</span><span> </span><span>{</span></span><span><span>    </span><span>@</span><span>HttpOperation</span><span>(</span><span>method </span><span>=</span><span> </span><span>&quot;GET&quot;</span><span>,</span><span> url </span><span>=</span><span> </span><span>&quot;https://reviews/{id}&quot;</span><span>)</span></span><span><span>    </span><span>@</span><span>HttpRetry</span><span>(</span><span>responseCode </span><span>=</span><span> </span><span>[</span><span>500</span><span>]</span><span>,</span><span> fixedRetryPolicy </span><span>=</span><span> </span><span>@</span><span>HttpFixedRetryPolicy</span><span>(</span><span>maxRetries </span><span>=</span><span> </span><span>10</span><span>,</span><span> retryDelay </span><span>=</span><span> </span><span>5</span><span>)</span><span>)</span></span><span><span>    </span><span>operation</span><span> </span><span>getReviews</span><span>(</span><span>id</span><span>:</span><span> FilmId</span><span>)</span><span>:</span><span> FilmReview</span><span>[</span><span>]</span></span><span><span>}</span></span></code></pre></div></div>
<p>You can trigger the retry mechanism for multiple response codes as well, here is how you can modify previous Taxi definition to trigger the Retry mechanism when the  remote service returns either Http 500 or Http 502</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>service</span><span> </span><span>ReviewsApi</span><span> </span><span>{</span></span><span><span>    </span><span>@</span><span>HttpOperation</span><span>(</span><span>method </span><span>=</span><span> </span><span>&quot;GET&quot;</span><span>,</span><span> url </span><span>=</span><span> </span><span>&quot;https://reviews/{id}&quot;</span><span>)</span></span><span><span>    </span><span>@</span><span>HttpRetry</span><span>(</span><span>responseCode </span><span>=</span><span> </span><span>[</span><span>500</span><span>,</span><span> </span><span>502</span><span>]</span><span>,</span><span> </span></span><span><span>      fixedRetryPolicy </span><span>=</span><span> </span><span>@</span><span>HttpFixedRetryPolicy</span><span>(</span></span><span><span>        maxRetries </span><span>=</span><span> </span><span>10</span><span>,</span><span> </span></span><span><span>        retryDelay </span><span>=</span><span> </span><span>5</span></span><span><span>    </span><span>)</span><span>)</span></span><span><span>    </span><span>operation</span><span> </span><span>getReviews</span><span>(</span><span>id</span><span>:</span><span> FilmId</span><span>)</span><span>:</span><span> FilmReview</span><span>[</span><span>]</span></span><span><span>}</span></span></code></pre></div></div>
<h3 id="retry-policy-with-exponential-delay"><a href="#retry-policy-with-exponential-delay">​<span></span></a>Retry Policy with Exponential Delay</h3>
<p>With exponential delay retry policy, Orbital will wait progressively longer intervals between consecutive retries:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>service</span><span> </span><span>ReviewsApi</span><span> </span><span>{</span></span><span><span>    </span><span>@</span><span>HttpOperation</span><span>(</span><span>method </span><span>=</span><span> </span><span>&quot;GET&quot;</span><span>,</span><span> url </span><span>=</span><span> </span><span>&quot;https://reviews/{id}&quot;</span><span>)</span></span><span><span>     </span><span>@</span><span>HttpRetry</span><span>(</span><span>responseCode </span><span>=</span><span> </span><span>[</span><span>500</span><span>,</span><span> </span><span>502</span><span>]</span><span>,</span><span> fixedRetryPolicy </span><span>=</span><span> </span><span>@</span><span>HttpExponentialRetryPolicy</span><span>(</span><span>maxRetries </span><span>=</span><span> </span><span>10</span><span>,</span><span> retryDelay </span><span>=</span><span> </span><span>5</span><span>,</span><span> jitter </span><span>=</span><span> </span><span>0.5</span><span>)</span><span>)</span></span><span><span>    </span><span>operation</span><span> </span><span>getReviews</span><span>(</span><span>id</span><span>:</span><span> FilmId</span><span>)</span><span>:</span><span> FilmReview</span><span>[</span><span>]</span></span><span><span>}</span></span></code></pre></div></div>
<p>With the above definition, Orbital will try invoking the Rest at most 10 times in case of Http 500 or Http 502 errors.</p>
<p>However, the delay between retries will increase exponentially.</p>
<p>With a <code>jitter</code> value between 0 and 1, you add some randomness to the delay time by introducing a random delay, or “jitter”, to the next retry delay time.
This ensures that the retries are not synchronous and reduces the likelihood of a retry storm.</p>
<p>Here’s how the table would look with exponential backoff with Jitter:</p>
<p>| Retry Attempt | Delay Time (seconds)  | 	Jitter Range (seconds) | Actual Delay Time (seconds) |
| ------------- | ---- -----------------|------------------------- |-----------------------------|
| 1             | 1.0                   | 0.5                      | 1-0 - 1.5                   |
| 2             | 2.0                   | 0.5                      | 1-5 - 2.5                   |
| 3             | 4.0                   | 0.5                      | 3.5 – 4.5                   |
| 4             | 8.0                   | 0.5                      | 7.5 – 8.5                   |
| 5             | 16.0                  | 0.5                      | 15.5 – 16.5                 |</p>
<h2 id="summary"><a href="#summary">​<span></span></a>Summary</h2>
<p>Http retries is out in 0.27. Read more about it over in our <a href="https://orbitalhq.com/docs/describing-data-sources/http#retry-policies">docs</a></p><p><em>(The post <a href="https://orbitalhq.com/changelog/2024-01-26-retry-operations">Http Retry Support</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/assets/cover-image-xte7Vc4K.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Better query compilation errors]]></title>
            <link>https://orbitalhq.com/changelog/2024-01-25-better-query-compilation-errors</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2024-01-25-better-query-compilation-errors</guid>
            <pubDate>Thu, 25 Jan 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[description goes here]]></description>
            <content:encoded><![CDATA[<figure><img src="https://orbitalhq.com/assets/query-compilation-error-CQhcC4Tl.gif" alt=""/><span></span></figure><p>Some UI/UX love for Orbital now, with a fine tuning of how compilation errors are being displayed on screen.</p>
<p>We’ll continue to improve the surfacing of messages like this throughout Orbital, allowing a more streamlined experience for users.</p><p><em>(The post <a href="https://orbitalhq.com/changelog/2024-01-25-better-query-compilation-errors">Better query compilation errors</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/assets/query-compilation-error-CQhcC4Tl.gif" length="0" type="image/gif"/>
        </item>
        <item>
            <title><![CDATA[Apple Silicon Friendly docker images available]]></title>
            <link>https://orbitalhq.com/changelog/2024-01-15-m2-images</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2024-01-15-m2-images</guid>
            <pubDate>Mon, 15 Jan 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[New docker images for M2 Macbooks]]></description>
            <content:encoded><![CDATA[<figure><img src="https://orbitalhq.com/assets/cover-image-C7euE211.png" alt=""/><span></span></figure><p>Some users have been experiencing errors when running our docker images on
Apple Silicon Macbook Pro’s (M1-3 et al).</p>
<p>The issue appears to be related to the base image we use for our Docker images - <code>eclipse-temurin:alpine</code>.</p>
<p>To address this, we’ve started producing extra images, based on Ubuntu Jammy.</p>
<p>Grab the images with the <code>-jammy</code> suffix, eg:</p>
<ul role="list">
<li><code>0.27.0-jammy</code></li>
<li><code>next-jammy</code></li>
</ul>
<p>These images aren’t suitable for production usage, as the <code>Ubuntu Jammy</code> base image contains
significantly more security CVE’s than the <code>-alpine</code> images.</p>
<p>However, for local developer environments, they’re great - mainly because they don’t crash. Brilliant.</p><p><em>(The post <a href="https://orbitalhq.com/changelog/2024-01-15-m2-images">Apple Silicon Friendly docker images available</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/assets/cover-image-C7euE211.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Http Headers and Date Math]]></title>
            <link>https://orbitalhq.com/changelog/2024-01-05-http-headers-date-math</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2024-01-05-http-headers-date-math</guid>
            <pubDate>Fri, 05 Jan 2024 01:00:00 GMT</pubDate>
            <description><![CDATA[describption goes here]]></description>
            <content:encoded><![CDATA[<h2 id="http-headers"><a href="#http-headers">​<span></span></a>Http Headers</h2>
<p>The <code>@HttpHeader</code> annotation now is now supported, for setting headers on HTTP requests.</p>
<p>For example:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>service</span><span> </span><span>MyService</span><span> </span><span>{</span></span><span><span>  </span><span>@</span><span>HttpOperation</span><span>(</span><span>method </span><span>=</span><span> </span><span>&quot;GET&quot;</span><span>,</span><span> url </span><span>=</span><span> </span><span>&quot;...&quot;</span><span>)</span></span><span><span> </span></span><span><span>  </span><span>// A fixed, static header</span></span><span><span>  </span><span>@</span><span>HttpHeader</span><span>(</span><span>name </span><span>=</span><span> </span><span>&quot;Consumes&quot;</span><span>,</span><span> value </span><span>=</span><span> </span><span>&quot;application/json&quot;</span><span>)</span></span><span><span>  </span><span>operation</span><span> </span><span>findPeople</span><span>(</span><span>)</span><span>:</span><span>Person</span><span>[</span><span>]</span></span><span>
</span><span><span>  </span><span>// A header that&#x27;s calculated</span></span><span><span>  </span><span>operation</span><span> </span><span>findPeople</span><span>(</span></span><span><span>     </span><span>@</span><span>HttpHeader</span><span>(</span><span>name </span><span>=</span><span> </span><span>&quot;If-Modified-Since&quot;</span><span>)</span><span> ifModifiedSince</span><span> </span><span>:</span><span> Instant</span><span> </span><span>=</span><span> </span><span>addDays</span><span>(</span><span>now</span><span>(</span><span>)</span><span>,</span><span>-</span><span>7</span><span>)</span></span><span><span>  </span><span>)</span><span>:</span><span>Person</span><span>[</span><span>]</span></span><span><span>}</span></span></code></pre></div></div>
<p>You can also pass header values in using the <code>given {}</code> clause in a query:</p>
<div><div><span></span><span>Copy</span></div><div><pre><code><span><span>service</span><span> </span><span>MyService</span><span> </span><span>{</span></span><span><span>  </span><span>operation</span><span> </span><span>findPeople</span><span>(</span></span><span><span>     </span><span>@</span><span>HttpHeader</span><span>(</span><span>name </span><span>=</span><span> </span><span>&quot;Cache-Control&quot;</span><span>,</span><span> prefix </span><span>=</span><span> </span><span>&quot;max-age=&quot;</span><span>)</span><span> cacheMaxAge</span><span> </span><span>:</span><span> CacheMaxAge</span></span><span><span>  </span><span>)</span><span>:</span><span>Person</span><span>[</span><span>]</span></span><span><span>}</span></span><span>
</span><span><span>// which is then invoked as:</span></span><span><span>given</span><span> </span><span>{</span><span> maxAge</span><span> </span><span>:</span><span> CacheMaxAge</span><span> </span><span>=</span><span> </span><span>64000</span><span> </span><span>}</span><span> </span></span><span><span>find</span><span> </span><span>{</span><span> Person</span><span>[</span><span>]</span><span> </span><span>}</span></span></code></pre></div></div>
<p>Read more about it in our <a href="https://orbitalhq.com/docs/describing-data-sources/http#http-headers">docs</a></p>
<h2 id="date-math"><a href="#date-math">​<span></span></a>Date math</h2>
<p>The stdlib in Taxi has been expanded to add date math functions to the stdlib:</p>
<ul role="list">
<li><code>addMinutes</code></li>
<li><code>addDays</code></li>
<li><code>addSeconds</code></li>
<li><code>now</code></li>
<li><code>parseDate</code></li>
</ul>
<p>Read more about these in the <a href="https://taxilang.org/language-reference/stdlib/#dates" target="_blank" rel="noreferrer">Taxi docs</a></p><p><em>(The post <a href="https://orbitalhq.com/changelog/2024-01-05-http-headers-date-math">Http Headers and Date Math</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/changelog-cards/2024-01-05-http-headers-date-math.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Auth with AWS and Azure]]></title>
            <link>https://orbitalhq.com/changelog/2024-01-05-auth-with-cognito-azure</link>
            <guid isPermaLink="false">https://orbitalhq.com/changelog/2024-01-05-auth-with-cognito-azure</guid>
            <pubDate>Fri, 05 Jan 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[describption goes here]]></description>
            <content:encoded><![CDATA[<figure><img src="https://orbitalhq.com/assets/changelog-cognito-auth-BtruFZU7.png" alt=""/><span></span></figure><p>Orbital now supports authentication and authorization with <a href="https://orbitalhq.com/docs/deploying/authentication#azure">Azure AD (Entra)</a> and <a href="https://orbitalhq.com/docs/deploying/authentication#aws-cognito">AWS Cognito</a></p>
<p>This expands our OpenId Connect auth implementation (we already support <a href="https://orbitalhq.com/docs/deploying/authentication#keycloak">Keycloak</a>).</p>
<p>Full documentation with vendor-specific tutorials is now available in our sections on <a href="https://orbitalhq.com/docs/deploying/authentication">Authentication</a> and <a href="https://orbitalhq.com/docs/deploying/authorization">Authorization</a>.</p><p><em>(The post <a href="https://orbitalhq.com/changelog/2024-01-05-auth-with-cognito-azure">Auth with AWS and Azure</a> appeared first on <a href="https://orbitalhq.com/changelog">Orbital Changelog</a>.)</em></p>]]></content:encoded>
            <enclosure url="https://orbitalhq.com/assets/changelog-cognito-auth-BtruFZU7.png" length="0" type="image/png"/>
        </item>
    </channel>
</rss>