@uru-intelligence/app
v1.0.0
Published
Runtime client for Uru Gems: capability calls, Datasets, jobs and secrets
Readme
@uru-intelligence/app
This package is the runtime client for Uru Gems. It is published so that Gem projects install and build outside the Uru hosted builder. It talks only to an Uru workspace runtime and does nothing on its own. The API tracks the Uru platform, and is versioned semantically against it. It is not a general-purpose library.
If you are not building a Uru Gem, this package will not do anything useful for you.
Why it exists
A Gem's generated project declares @uru-intelligence/app as a dependency. Before this
package was published, npm install on such a project failed with a 404, and
only Uru's own hosted builder could build a Gem — it vendored the package from
inside the platform image. Publishing removes that special case, so a Gem builds
the same way on a laptop, in an agent's sandbox, and in Uru's builder.
Install
npm install @uru-intelligence/app- ESM only. There is no CommonJS build.
- Zero runtime dependencies.
- Node.js
>= 22.12.0, and Cloudflare Workers. Both are measured against every release before it publishes: the packed tarball is installed and exercised on Node 22.12.0, 24 and 26 — 22.12.0 exactly, because that is the floor this package promises — and it is bundled into a Workers build through Uru's own Gem template. Anything else with a globalfetchwill very likely work, but is not something this package tests. - TypeScript consumers need
fetch,HeadersandResponsein theirlib— theDOMlib,@types/node, or@cloudflare/workers-types.
Usage
Inside a Uru server runtime, build a context from the injected environment:
import { createUruServerContext } from '@uru-intelligence/app';
const uru = createUruServerContext(process.env);
// Datasets: filter, sort, paginate and aggregate on the SERVER.
const page = await uru.datasets.queryRows('sales', {
limit: 25,
offset: 0,
includeTotal: true,
where: [{ field: 'region', op: 'eq', value: 'emea' }],
sort: [{ field: 'closed_at', direction: 'desc' }],
});
// Actions: run a declared capability and take its result, or throw.
const summary = await uru.actions.run<string>('summarize', { id: page.rows[0]?.id });
// Jobs: start long work and poll it, so the page can show real progress.
const job = await uru.jobs.start('rebuild-index');
const status = await uru.app.jobStatus(job.executionId ?? '');
// Secrets: the app's own declared bindings.
const key = uru.secrets.has('STRIPE_KEY') ? uru.secrets.get('STRIPE_KEY') : null;createUruServerContext requires URU_DEPLOYMENT_ID, URU_RUNTIME_API_BASE
and URU_RUNTIME_TOKEN. The Uru runtime injects all three. A missing binding
throws UruAppRuntimeError naming the binding, rather than failing later at a
request that could never have worked.
For a browser calling a public Gem page's runtime, build the client directly:
import { createUruAppRuntimeClient } from '@uru-intelligence/app';
const app = createUruAppRuntimeClient({
deploymentId,
publicPageSlug: 'quarterly-report',
});
const response = await app.query('summary', {}, { onStatus: event => render(event.state) });What it gives you
- Every capability kind a Gem can declare:
query,action,job,endpointandserverFunction, plusjobStatusandcancelJob. - Real states, not just success and failure. Every response carries a
normalized
state—queued,running,cached,stale,refreshing,rate_limited,budget_blocked,service_unavailable,canceledand more. Surface them. A Gem that hides expensive work behind a spinner is a Gem whose users cannot tell a slow query from a blocked budget. - Server-side Datasets. Read with
queryRows; write withinsertRows,upsertRows,deleteRows,restoreRowsandsqlWrite. Totals, counts and top-N summaries must come from the server, never from one fetched page. - Runaway dampers, on by default. An accidental render loop is the expensive
failure mode for a Gem, so the client defaults an idempotency key per
invocation, backs off on HTTP 429, and throttles
forceRefreshper capability. Override any of it throughdampers; seeUruRunawayDamperOptions.
Errors
Every failure throws UruAppRuntimeError, which carries status (the HTTP
status, or 0 for a local failure) and body (the parsed response, or null).
import { UruAppRuntimeError } from '@uru-intelligence/app';
try {
await uru.actions.run('summarize');
} catch (error) {
if (error instanceof UruAppRuntimeError && error.status === 429) {
// rate limited after the client's own retries were exhausted
}
throw error;
}Stability
Semantic versioning, from 1.0.0 onward. A breaking change to the public
surface takes a major version. This package starts at 1.0.0 rather than 0.x
because it is already load-bearing: every hosted Uru Gem runs against it, so
breaking it is expensive whatever the version number claims.
The API still follows the Uru platform rather than the other way round. When the platform's runtime contract moves, this package moves with it — additively where it can, and in a major version where it cannot. Pin an exact version if you need a build to be reproducible; Uru's own Gem templates do.
The public surface is createUruServerContext, createUruAppRuntimeClient,
UruAppRuntimeError, and the exported types. Nothing else is API, even if you
can reach it.
Documentation
Building Gems is documented at uruintelligence.com. Bugs and questions go to the issue tracker.
Licence
Proprietary. See LICENSE. You may use and redistribute this package as part of an application that runs on the Uru platform.
