@voxgig-sdk/voxgig-solardemo
v0.1.0
Published
Unofficial generated TypeScript SDK for the Solar System public API. Not affiliated with or endorsed by the upstream API provider.
Downloads
120
Readme
Solardemo TypeScript SDK
The TypeScript SDK for the Solardemo API — a type-safe, entity-oriented client with full async/await support.
The API is exposed as capitalised, semantic Entities — e.g.
client.Moon() — each with a small set of operations (list, load, create, update, remove)
instead of raw URL paths and query parameters. This keeps the surface
predictable and low-friction for both humans and AI agents.
Other languages, the CLI, and MCP server live alongside this one — see the top-level README.
Install
npm install @voxgig-sdk/voxgig-solardemoTutorial: your first API call
This tutorial walks through creating a client, listing entities, and loading a specific record.
1. Create a client
import { SolardemoSDK } from '@voxgig-sdk/voxgig-solardemo'
const client = new SolardemoSDK()2. List moon records
list() resolves to an array of Moon ENTITIES — every operation
resolves to entities, not raw records. Iterate them directly, and call
.data() on one for the record it holds:
const moons = await client.Moon().list({ planet_id: "example" })
for (const moon of moons) {
console.log(moon)
}3. Load a moon
Moon is nested under planet, so provide the planet_id.
load() returns the entity directly and throws on failure:
try {
const moon = await client.Moon().load({
planet_id: 'example_planet_id',
id: 'example_id',
})
console.log(moon)
} catch (err) {
console.error('load failed:', err)
}4. Create, update, and remove
// Create — returns the created Moon ENTITY (.data() for the record)
const created = await client.Moon().create({
planet_id: 'example_planet_id',
diameter: 1,
id: 'example_id',
kind: 'example_kind',
name: 'example_name',
})
// Update — the id comes off the returned entity's data()
const updated = await client.Moon().update({
id: created.data().id!,
planet_id: 'example_planet_id',
diameter: 1,
})
// Remove
await client.Moon().remove({
id: created.data().id!,
planet_id: 'example_planet_id',
})Error handling
Entity operations reject on failure, so wrap them in try / catch:
try {
const moons = await client.Moon().list()
console.log(moons)
} catch (err) {
console.error('list failed:', err)
}The low-level direct() method does not throw — it returns the
value or an Error, so check the result before using it:
const result = await client.direct({
path: '/api/resource/{id}',
method: 'GET',
params: { id: 'example_id' },
})
if (result instanceof Error) {
throw result
}How-to guides
Make a direct HTTP request
For endpoints not covered by entity methods:
const result = await client.direct({
path: '/api/resource/{id}',
method: 'GET',
params: { id: 'example' },
})
if (result instanceof Error) {
throw result
}
if (result.ok) {
console.log(result.status) // 200
console.log(result.data) // response body
}Prepare a request without sending it
const fetchdef = await client.prepare({
path: '/api/resource/{id}',
method: 'DELETE',
params: { id: 'example' },
})
// Inspect before sending
console.log(fetchdef.url)
console.log(fetchdef.method)
console.log(fetchdef.headers)Use test mode
Create a mock client for unit testing — no server required:
const client = SolardemoSDK.test()
const moon = await client.Moon().list()
// moon is the entity, populated with mock response data
// — call moon.data() for the record itself
console.log(moon)You can also use the instance method:
const client = new SolardemoSDK()
const testClient = client.tester()Retain entity state across calls
Entity instances remember their last match and data:
const entity = client.Moon()
// First call runs the operation and stores its result
await entity.list()
// Subsequent calls reuse the stored state
const data = entity.data()
console.log(data.id)Add custom middleware
Pass features via the extend option:
const logger = {
hooks: {
PreRequest: (ctx: any) => {
console.log('Requesting:', ctx.spec.method, ctx.spec.path)
},
PreResponse: (ctx: any) => {
console.log('Status:', ctx.out.request?.status)
},
},
}
const client = new SolardemoSDK({
extend: [logger],
})Run live tests
Create a .env.local file at the project root:
SOLARDEMO_TEST_LIVE=TRUEThen run:
cd ts && npm testReference
SolardemoSDK
Constructor
new SolardemoSDK(options?: {
base?: string
prefix?: string
suffix?: string
feature?: Record<string, { active: boolean }>
extend?: Feature[]
})| Option | Type | Description |
| --- | --- | --- |
| base | string | Base URL of the API server. |
| prefix | string | URL path prefix prepended to all requests. |
| suffix | string | URL path suffix appended to all requests. |
| feature | object | Feature activation flags (e.g. { test: { active: true } }). |
| extend | Feature[] | Additional feature instances to load. |
Methods
| Method | Returns | Description |
| --- | --- | --- |
| options() | object | Deep copy of current SDK options. |
| utility() | Utility | Deep copy of the SDK utility object. |
| prepare(fetchargs?) | Promise<FetchDef> | Build an HTTP request definition without sending it. |
| direct(fetchargs?) | Promise<DirectResult> | Build and send an HTTP request. |
| Moon(data?) | MoonEntity | Create a Moon entity instance. |
| Planet(data?) | PlanetEntity | Create a Planet entity instance. |
| tester(testopts?, sdkopts?) | SolardemoSDK | Create a test-mode client instance. |
Static methods
| Method | Returns | Description |
| --- | --- | --- |
| SolardemoSDK.test(testopts?, sdkopts?) | SolardemoSDK | Create a test-mode client. |
Entity interface
All entities share the same interface.
Methods
| Method | Signature | Description |
| --- | --- | --- |
| load | load(reqmatch?, ctrl?): Promise<Entity> | Load a single entity by match criteria. |
| list | list(reqmatch?, ctrl?): Promise<Entity[]> | List entities matching the criteria. |
| create | create(reqdata?, ctrl?): Promise<Entity> | Create a new entity. |
| update | update(reqdata?, ctrl?): Promise<Entity> | Update an existing entity. |
| remove | remove(reqmatch?, ctrl?): Promise<void> | Remove an entity. |
| data | data(data?: Partial<Entity>): Entity | Get or set entity data. |
| match | match(match?: Partial<Entity>): Partial<Entity> | Get or set entity match criteria. |
| make | make(): Entity | Create a new instance with the same options. |
| client | client(): SolardemoSDK | Return the parent SDK client. |
| entopts | entopts(): object | Return a copy of the entity options. |
Return values
Entity operations resolve to the entity data directly — there is no result envelope:
load,createandupdateresolve to a single entity object.listresolves to an array of entity objects (iterate it directly; there is no.dataand no.ok).removeresolves tovoid.
On a failed request these methods throw, so wrap calls in
try/catch to handle errors. Only direct() returns the result
envelope described below.
DirectResult shape
The direct() method returns:
{
ok: boolean
status: number
headers: object
data: any
}On error, ok is false and an err property contains the error.
FetchDef shape
The prepare() method returns:
{
url: string
method: string
headers: Record<string, string>
body?: any
}Entities
Moon
| Field | Description |
| --- | --- |
| diameter | |
| id | |
| kind | |
| name | |
| planet_id | |
Operations: create, list, load, remove, update.
API path: /api/planet/{planet_id}/moon
Planet
| Field | Description |
| --- | --- |
| diameter | |
| forbid | |
| id | |
| kind | |
| name | |
| ok | |
| start | |
| state | |
| stop | |
| why | |
Operations: create, list, load, remove, update.
API path: /api/planet/{planet_id}/forbid
Entities
Moon
Create an instance: const moon = client.Moon()
Operations
| Method | Description |
| --- | --- |
| create(data) | Create a new entity with the given data. |
| list(match) | List entities matching the criteria. |
| load(match) | Load a single entity by match criteria. |
| remove(match) | Remove the matching entity. |
| update(data) | Update an existing entity. |
Fields
| Field | Type | Description |
| --- | --- | --- |
| diameter | number | |
| id | string | |
| kind | string | |
| name | string | |
| planet_id | string | |
Example: Load
const moon = await client.Moon().load({ id: 'moon_id', planet_id: 'planet_id' })Example: List
const moons = await client.Moon().list({ planet_id: "example" })Example: Create
const moon = await client.Moon().create({
planet_id: 'example_planet_id',
diameter: 1,
id: 'example_id',
kind: 'example_kind',
name: 'example_name',
})Planet
Create an instance: const planet = client.Planet()
Operations
| Method | Description |
| --- | --- |
| create(data) | Create a new entity with the given data. |
| list(match) | List entities matching the criteria. |
| load(match) | Load a single entity by match criteria. |
| remove(match) | Remove the matching entity. |
| update(data) | Update an existing entity. |
Fields
| Field | Type | Description |
| --- | --- | --- |
| diameter | number | |
| forbid | boolean | |
| id | string | |
| kind | string | |
| name | string | |
| ok | boolean | |
| start | boolean | |
| state | string | |
| stop | boolean | |
| why | string | |
Example: Load
const planet = await client.Planet().load({ id: 'planet_id' })Example: List
const planets = await client.Planet().list()Example: Create
const planet = await client.Planet().create({
diameter: 1,
id: 'example_id',
kind: 'example_kind',
name: 'example_name',
})Advanced
The sections above cover everyday use. The material below explains the SDK's internals — useful when extending it with custom features, but not needed for normal use.
The operation pipeline
Every entity operation follows a six-stage pipeline. Each stage fires a feature hook before executing:
PrePoint → PreSpec → PreRequest → PreResponse → PreResult → PreDone- PrePoint: Resolves which API endpoint to call based on the operation name and entity configuration.
- PreSpec: Builds the HTTP spec — URL, method, headers, body — from the resolved point and the caller's parameters.
- PreRequest: Sends the HTTP request. Features can intercept here to replace the transport (as TestFeature does with mocks).
- PreResponse: Parses the raw HTTP response.
- PreResult: Extracts the business data from the parsed response.
- PreDone: Final stage before returning to the caller. Entity state (match, data) is updated here.
If any stage errors, the pipeline short-circuits and the error surfaces to the caller — see Error handling for how that looks in this language.
Features and hooks
Features are the extension mechanism. A feature is an object with a
hooks map. Each hook key is a pipeline stage name, and the value is
a function that receives the context.
The SDK ships with built-in features:
- TestFeature: In-memory mock transport for testing without a live server
Features are initialized in order. Hooks fire in the order features were added, so later features can override earlier ones.
Module structure
solardemo/
├── src/
│ ├── SolardemoSDK.ts # Main SDK class
│ ├── entity/ # Entity implementations
│ ├── feature/ # Built-in features (Base, Test, Log)
│ └── utility/ # Utility functions
├── test/ # Test suites
└── dist/ # Compiled outputImport the SDK from the package root:
import { SolardemoSDK } from '@voxgig-sdk/voxgig-solardemo'Entity state
Entity instances are stateful. After a successful list, the entity
stores the returned data and match criteria internally. Subsequent
calls on the same instance can rely on this state.
const moon = client.Moon()
await moon.list()
// moon.data() now returns the moon data from the last `list`
// moon.match() returns the last match criteriaCall make() to create a fresh instance with the same configuration
but no stored state.
Direct vs entity access
The entity interface handles URL construction, parameter placement, and response parsing automatically. Use it for standard CRUD operations.
The direct method gives full control over the HTTP request. Use it
for non-standard endpoints, bulk operations, or any path not modelled
as an entity. The prepare method is useful for debugging — it
shows exactly what direct would send.
Full Reference
See REFERENCE.md for complete API reference documentation including all method signatures, entity field schemas, and detailed usage examples.
