@ivcap/client
v0.1.0
Published
TypeScript/JavaScript client SDK for IVCAP – a platform for offering and ordering analytics services
Downloads
30
Maintainers
Readme
@ivcap/client
TypeScript / JavaScript client SDK for IVCAP – a platform for offering, discovering and ordering analytics services.
Table of Contents
- Features
- Installation
- Quick Start
- Key Concepts
- Configuration
- Resources
- Pagination
- Typical Workflow
- Error Handling
- Advanced Usage
- Contributing
- Development
- License
Features
- 🔐 Auth – bearer-token injection, env-variable fallback (
IVCAP_JWT) - 📦 Typed resources –
artifacts,services,jobs,aspects,queues,projects,secrets - ♾️ Async iteration – lazy cursor-based pagination with
for await...of - 🔄 Fire-and-forget jobs –
jobs.createAndWait()submits and polls until done - 🚦 Rich errors – typed error classes (
NotFoundError,UnauthorizedError, …) - 🌐 Universal – works in Node ≥ 18, modern browsers, edge runtimes (Axios-based)
- 📝 ESM + CJS – ships both module formats plus TypeScript declarations
Installation
npm install @ivcap/client
# or
yarn add @ivcap/client
# or
pnpm add @ivcap/clientQuick Start
import { IvcapClient } from "@ivcap/client";
const client = new IvcapClient({
baseUrl: "https://develop.ivcap.net",
token: process.env.IVCAP_JWT,
});
// ── Browse services ──────────────────────────────────────────────────────────
for await (const svc of client.services.list()) {
console.log(svc.id, svc.name);
}
// ── Inspect a service's parameter schema ─────────────────────────────────────
const detail = await client.services.get("urn:ivcap:service:my-analysis-service");
detail.parameters.forEach(p => console.log(" ", p.name, p.type));
// ── Upload an input artifact ─────────────────────────────────────────────────
const artifact = await client.artifacts.upload(
JSON.stringify({ temperature: [21.3, 22.1, 19.8] }),
{ name: "sensor-data.json", contentType: "application/json" }
);
console.log("Uploaded:", artifact.id);
// ── Submit a job and wait for results ────────────────────────────────────────
const job = await client.jobs.createAndWait(
"urn:ivcap:service:my-analysis-service",
{
parameters: [
{ name: "input", value: artifact.id },
{ name: "threshold", value: "0.05" },
],
name: "My analysis run",
},
{
pollInterval: 5_000, // check every 5 s
timeout: 300_000, // give up after 5 min
onUpdate: (j) => console.log("status:", j.status),
}
);
if (job.status === "succeeded") {
for (const product of job.products.items) {
console.log("Product:", product.id, product.mimeType);
const text = await client.artifacts.downloadText(product.id);
console.log(text);
}
}Key Concepts
| Entity | URN pattern | Description |
|--------|-------------|-------------|
| Service | urn:ivcap:service:<uuid> | A registered analytic capability with defined parameters |
| Job | urn:ivcap:job:<uuid> | A single execution of a service |
| Artifact | urn:ivcap:artifact:<uuid> | Any binary or structured data blob stored on the platform |
| Aspect | urn:ivcap:aspect:<uuid> | Typed, time-stamped metadata attached to any entity |
Note on terminology: Some parts of the IVCAP platform and the
ivcapCLI still use the term order for jobs. These mean the same thing. The canonical term is now job.
Configuration
| Option | Type | Default | Description |
|-----------|----------|---------|-------------|
| baseUrl | string | IVCAP_URL env var | Base URL of the IVCAP deployment |
| token | string | IVCAP_JWT env var | Bearer authentication token |
| timeout | number | 30000 | Request timeout in milliseconds |
| headers | Record<string,string> | – | Extra HTTP headers sent with every request |
export IVCAP_URL=https://develop.ivcap.net
export IVCAP_JWT=eyJhbGciOiJ...const client = new IvcapClient(); // picks up env vars automaticallyResources
client.artifacts
| Method | Description |
|--------|-------------|
| list(opts?) | Async iterator over all artifacts (lazy pagination) |
| listPage(opts?) | Fetch a single page |
| get(id) | Fetch full artifact metadata |
| upload(data, opts?) | Upload string / Buffer / Blob / ReadableStream |
| download(id) | Download as ArrayBuffer |
| downloadText(id) | Download as UTF-8 string |
| downloadJson<T>(id) | Download and JSON-parse |
client.services
| Method | Description |
|--------|-------------|
| list(opts?) | Async iterator over all available services |
| listPage(opts?) | Fetch a single page |
| get(id) | Fetch service details including parameter schema |
client.jobs
Jobs are always scoped to a service. All methods take a serviceId as their first argument.
API paths follow /1/services/{serviceId}/jobs/....
| Method | Description |
|--------|-------------|
| list(serviceId, opts?) | Async iterator over all jobs for a service |
| listPage(serviceId, opts?) | Fetch a single page |
| get(serviceId, jobId) | Fetch job status, parameters, and products |
| create(serviceId, req) | Submit a new job |
| createAndWait(serviceId, req, opts?) | Submit and poll until terminal state |
| waitUntilDone(serviceId, jobId, opts?) | Poll an existing job until done |
| getOutput(serviceId, jobId) | Retrieve the structured result payload |
| JobResource.buildParameters(obj) | Convert {key: val} → JobParameter[] |
Job status values: pending → scheduled → executing → succeeded / failed / error
client.aspects
Aspects are typed, time-stamped metadata records attached to any entity URN. They are the foundation of IVCAP's provenance model.
| Method | Description |
|--------|-------------|
| list(opts?) | Async iterator filtered by entity, schema, time, etc. |
| listPage(opts?) | Fetch a single page |
| get(id) | Fetch aspect detail |
| create(input) | Assert a new aspect on an entity |
| update(id, content) | Retract + re-assert with new content |
| retract(id) | Logically delete an aspect |
client.queues
| Method | Description |
|--------|-------------|
| list(opts?) | Async iterator over all queues |
| get(id) | Fetch queue details |
| create(req) | Create a queue |
| delete(id) | Delete a queue |
| enqueue(id, msg) | Publish a message |
| dequeue(id) | Consume the next message (null if empty) |
client.projects
| Method | Description |
|--------|-------------|
| list(opts?) | Async iterator over all projects |
| get(id) | Fetch project details |
| create(req) | Create a project |
client.secrets
| Method | Description |
|--------|-------------|
| list() | List secret names + expiry (values not returned) |
| get(name) | Retrieve a secret value |
| set(req) | Create or update a secret |
| delete(name) | Delete a secret |
Pagination
All list() methods return a PageIterator that lazily fetches pages as you consume items:
// Iterate item-by-item (lazy – only fetches pages as needed)
for await (const artifact of client.artifacts.list({ limit: 50 })) {
process(artifact);
}
// Collect everything at once
import { collectAll } from "@ivcap/client";
const all = await collectAll(client.services.list());
// Or use the helper on the iterator itself
const all = await client.artifacts.list().toArray();
// First page only
const firstPage = await client.artifacts.list().firstPage();
// Callback style
await client.jobs.list(serviceId).forEach(async (job) => {
console.log(job.id, job.status);
});Typical Workflow
1. List available services client.services.list()
2. Inspect a service client.services.get(serviceId)
3. Upload input data client.artifacts.upload(data, opts)
4. Submit a job client.jobs.create(serviceId, req)
5. Poll for completion client.jobs.waitUntilDone(serviceId, jobId)
(or combine 4+5) client.jobs.createAndWait(serviceId, req)
6. Download result artifacts client.artifacts.download(productId)Error Handling
import {
IvcapClient,
NotFoundError,
UnauthorizedError,
TimeoutError,
} from "@ivcap/client";
try {
const job = await client.jobs.get(serviceId, "urn:ivcap:job:unknown");
} catch (err) {
if (err instanceof NotFoundError) {
console.error("Job not found:", err.resourceId);
} else if (err instanceof UnauthorizedError) {
console.error("Check your IVCAP_JWT token");
} else if (err instanceof TimeoutError) {
console.error("Job polling timed out");
} else {
throw err;
}
}Available error classes:
| Class | HTTP status |
|-------|-------------|
| BadRequestError | 400 |
| UnauthorizedError | 401 |
| ForbiddenError | 403 |
| NotFoundError | 404 |
| ConflictError | 409 |
| InvalidParameterError | 422 |
| NotImplementedError | 501 |
| ServiceUnavailableError | 503 |
| AmbiguousResultError | (multiple matches) |
| TimeoutError | (polling timeout) |
| IvcapError | (base class) |
Advanced Usage
Using JobResource.buildParameters
import { JobResource } from "@ivcap/client";
const job = await client.jobs.create(serviceId, {
name: "fire-risk-analysis",
parameters: JobResource.buildParameters({
region: "Tasmania-North",
threshold: "0.05",
"input-data": artifactId,
}),
});Provenance queries via Aspects
// What jobs produced a given artifact?
for await (const aspect of client.aspects.list({
entity: artifactId,
schema: "urn:ivcap:schema:artifact-usedBy-order.1",
})) {
console.log(aspect.content);
}
// Historical query: what was known at a point in time?
const historical = await client.aspects.list({
entity: artifactId,
atTime: "2025-06-01T12:00:00Z",
}).toArray();Token rotation
const client = new IvcapClient({ baseUrl: "..." });
setInterval(async () => {
const newToken = await myTokenProvider.refresh();
client.setToken(newToken);
}, 60_000);Low-level HTTP access
const axiosInstance = client.getHttpClient().getAxios();
const raw = await axiosInstance.get("/1/some/custom/endpoint");Browser / Vite / Next.js
The package ships both ESM (dist/index.mjs) and CJS (dist/index.js) builds with TypeScript declarations. Axios handles the HTTP layer and works transparently in browser environments — no polyfills needed for modern browsers.
Contributing
Contributions are very welcome! The preferred way to contribute is to open a Pull Request on GitHub. If you've found a bug, have a feature idea, or spotted something wrong in the documentation but don't have time for a fix, please raise an issue instead — just include enough detail (steps to reproduce, expected vs. actual behaviour, SDK version, runtime) so we can act on it.
- 🔀 PR → fork, branch, fix, open a PR against
main - 🐛 Issue → github.com/ivcap-works/ivcap-client-sdk-js/issues
See CONTRIBUTING for the full guide (setup, code style, docs workflow).
Development
npm install # install dependencies
npm run typecheck # type-check without emitting
npm run build # CJS + ESM + .d.ts → dist/
npm test # run tests (Vitest)
npm run test:watch # watch mode
npm run test:coverage # coverage reportLicense
MIT © Commonwealth Scientific and Industrial Research Organisation (CSIRO) and contributors
