@subspacecomputing/sdk
ASTRIA — TypeScript SDK
TypeScript SDK for ASTRIA, the Subspace Computing Engine.
Installation
npm install @subspacecomputing/sdk
# or
yarn add @subspacecomputing/sdk
# or
pnpm add @subspacecomputing/sdk
Usage
Initialization
import { ASTRIA } from '@subspacecomputing/sdk';
// Initialize the client (defaults to production URL)
const client = new ASTRIA('your-api-key-here');
// For local testing or custom environments (optional)
// const client = new ASTRIA('your-api-key-here', 'http://localhost:8000');
Teams (X-Team-Id)
Optional third constructor argument sets the team UUID (header X-Team-Id). Use setTeamId to change or clear it. If the API needs a team context, you may get 400 with error.reason === 'team_context_required' — handle ValidationError and read err.errorReason.
const client = new ASTRIA('key', 'https://api.subspacecomputing.com', 'team-uuid');
client.setTeamId(undefined);
Simple Projection (1 scenario)
// Create a simple SP Model
const spec = {
scenarios: 1, // Must be 1 for project()
steps: 12,
variables: [
{
name: 'capital',
init: 1000.0,
formula: 'capital[t-1] * 1.05', // 5% growth per period
},
],
};
// Run the projection
const result = await client.project(spec);
// Display results
console.log(`Final capital: ${result.final_values.capital}`);
console.log(`Trajectory: ${result.trajectory.capital}`);
Monte Carlo Simulation (Multiple scenarios)
// SP Model with random variables
const spec = {
scenarios: 1000, // 1000 Monte Carlo scenarios
steps: 12,
variables: [
{
name: 'taux',
dist: 'uniform',
params: { min: 0.03, max: 0.07 },
per: 'scenario',
},
{
name: 'capital',
init: 1000.0,
formula: 'capital[t-1] * (1 + taux)',
},
],
};
// Run the simulation
const result = await client.simulate(spec);
// Analyze results
console.log(`Mean final capital: ${result.last_mean.capital}`);
console.log(`Median: ${result.statistics.capital.median}`);
console.log(`P5: ${result.statistics.capital.percentiles['5']}`);
console.log(`P95: ${result.statistics.capital.percentiles['95']}`);
Per-step statistics (fan charts)
When the API supports it, set include_per_step_statistics: true to receive full MC statistics at each time step (t = 0 through steps). The last entry matches statistics[var].
const spec = {
scenarios: 1000,
steps: 12,
include_per_step_statistics: true,
variables: [/* ... */],
};
const result = await client.simulate(spec);
if (result.per_step_statistics?.capital) {
const atHorizon = result.per_step_statistics.capital.at(-1);
console.log(`P10 at horizon: ${atHorizon?.p10 ?? atHorizon?.percentiles['10']}`);
}
Batch Mode (Multiple Entities)
// SP Model template
const template = {
scenarios: 1,
steps: '65 - batch_params.age', // Dynamic steps
variables: [
{
name: 'age_actuel',
init: 'batch_params.age',
},
{
name: 'salaire',
init: 'batch_params.salary',
formula: 'salaire[t-1] * 1.03', // 3% annual increase
},
{
name: 'capital_retraite',
init: 0.0,
formula: 'capital_retraite[t-1] * 1.05 + salaire[t] * 0.10',
},
],
};
// Entity data
const batchParams = [
{ entity_id: 'emp_001', age: 45, salary: 60000 },
{ entity_id: 'emp_002', age: 50, salary: 80000 },
{ entity_id: 'emp_003', age: 35, salary: 50000 },
];
// Global aggregations (optional)
const aggregations = [
{
name: 'capital_total',
formula: 'sum(capital_retraite[t_final])',
},
{
name: 'moyenne_capital',
formula: 'mean(capital_retraite[t_final])',
},
];
// Run batch
const result = await client.projectBatch(template, batchParams, aggregations);
// Analyze results
for (const entity of result.entities) {
console.log(`${entity._entity_id}: Capital = ${entity.final_values.capital_retraite}`);
}
console.log(`Total capital: ${result.aggregations?.capital_total}`);
console.log(`Average: ${result.aggregations?.moyenne_capital}`);
Runs: read, artifact, rerun, replay
Four distinct operations on persisted runs:
| Method | What it does |
|---|---|
getRun(runId) |
Read metadata, stored SP Model snapshot, and result_summary |
getRunArtifact(artifactId) |
Read heavy results already computed (final_values / URL) |
rerunRun(runId, specPatch?) |
Re-execute the run's snapshot in Astria; creates a new run |
replayRun(runId, scenarioId) |
Reproduce one Monte Carlo scenario when seeds were stored |
// Cross-language analysis: app computed → TypeScript/Python reads original results
const run = await client.getRun(runId);
console.log(run.result_summary);
if (run.artefact_id) {
const artifact = await client.getRunArtifact(run.artefact_id);
console.log(artifact.final_values);
}
// Re-execute the exact snapshot (validation) — new run, same projection
const baseline = await client.rerunRun(runId);
console.log(baseline.run_id, baseline.source_spec_hash, baseline.spec_changed);
// What-if: fork the snapshot with a JSON Merge Patch (source run unchanged)
const whatIf = await client.rerunRun(runId, {
meta: { seed: 42 },
});
console.log(whatIf.executed_spec_hash);
// Exact one-scenario MC replay (requires meta.store_seeds_for_replay on the source run)
const replay = await client.replayRun(runId, 0);
console.log(replay.final_values);
Notes
rerunRunuses the run's storedspec, not the projection's currentdsl_template.- Requires
persist_mode=full. replayRunneeds seeds persisted on the source run; it does not accept a body (path params only).- Live
table_refsmay resolve to newer data than at original execution time.
Validation
// Validate an SP Model before execution
const validation = await client.validate(spec);
if (validation.is_valid) {
console.log('✅ SP Model is valid');
if (validation.warnings) {
console.log(`⚠️ Warnings: ${validation.warnings}`);
}
} else {
console.log(`❌ Errors: ${validation.errors}`);
}
Utilities
// Get examples
const examples = await client.getExamples();
console.log(`Available examples: ${examples.examples.length}`);
// Check usage
const usage = await client.getUsage();
console.log(
`Simulations used: ${usage.quota.used}/${usage.quota.limit}`
);
// Get plans
const plans = await client.getPlans();
for (const plan of plans.plans) {
console.log(`${plan.name}: $${plan.price_monthly}/month`);
}
Error Handling
import {
ASTRIA,
SubspaceError,
QuotaExceededError,
RateLimitError,
AuthenticationError,
ValidationError,
} from '@subspacecomputing/sdk';
try {
const result = await client.simulate(spec);
} catch (error) {
if (error instanceof QuotaExceededError) {
console.error(`Monthly quota exceeded: ${error.message}`);
} else if (error instanceof RateLimitError) {
console.error(`Rate limit exceeded: ${error.message}`);
const retryAfter = error.response?.headers.get('Retry-After');
if (retryAfter) {
console.log(`Retry after: ${retryAfter} seconds`);
}
} else if (error instanceof AuthenticationError) {
console.error(`Invalid API key: ${error.message}`);
} else if (error instanceof ValidationError) {
console.error(`Validation error: ${error.detail}`);
} else if (error instanceof SubspaceError) {
console.error(`API error: ${error.message}`);
}
}
Rate Limit and Quota Information
After making a request, you can check your rate limit and quota status:
// Make a request
const result = await client.project(spec);
// Check rate limit info
const rateLimit = client.getRateLimitInfo();
if (rateLimit) {
console.log(
`Rate limit: ${rateLimit.remaining}/${rateLimit.limit} remaining`
);
}
// Check quota info
const quota = client.getQuotaInfo();
if (quota) {
console.log(
`Quota: ${quota.used}/${quota.limit} used, ${quota.remaining} remaining`
);
}
Documentation
Full documentation: https://www.subspacecomputing.com/developer
API Reference: https://www.subspacecomputing.com/docs
Support: contact@subspacecomputing.com
License
MIT License. See LICENSE for details.
Copyright
2026 Subspace Computing Inc. All Rights Reserved