@aas-studio/sdk

Official TypeScript SDK for the AAS Studio public REST API.

Install
npm install @aas-studio/sdk
Setup
import { AasStudioClient } from '@aas-studio/sdk'

const aas = new AasStudioClient({
  apiKey: process.env.AAS_STUDIO_KEY!,
  // Optional: self-hosted deployments
  // baseUrl: 'https://aas.yourcompany.com/api/v1',
})

Methods

extract

extract(opts: ExtractOptions): Promise<ExtractEnvelope>

Extract an AAS submodel from a PDF datasheet. Counts as 1 extraction toward the monthly quota.

import { readFileSync } from 'node:fs'

const pdf = readFileSync('./datasheets/ur10e.pdf')
const { result, provider, warnings } = await aas.extract({
  file: pdf,
  fileName: 'ur10e.pdf',
  idPrefix: 'urn:acme:aas',
})

console.log(result.assetIdShort)              // 'UR10e'
console.log(result.submodels.length)          // 4 (Nameplate, TechnicalData, …)
console.log(provider)                          // 'gemini'
  • PDF must be ≤ 20 MB. Multi-page text PDFs work; scanned PDFs return UnprocessableError until OCR ships in Phase 3.
  • For LLM-cost-sensitive workloads, pass `apiKey` (your own Gemini/OpenAI/Anthropic key) — bypasses our server's key entirely.
  • Server caches extraction text up to 80,000 chars. Longer PDFs get a `truncated` warning in the response.

listExtractions

listExtractions(opts?: ListExtractionsOptions): Promise<ListExtractionsEnvelope>

List the caller's saved extractions, cursor-paginated.

let cursor: string | null = null
do {
  const { extractions, nextCursor } = await aas.listExtractions({ limit: 50, cursor: cursor ?? undefined })
  for (const e of extractions) {
    console.log(`${e.id}  ${e.name}  (${e.mode}, ${e.sourceCount} sources)`)
  }
  cursor = nextCursor
} while (cursor)
  • Filters out manually-imported AAS files (extractionMeta = null). For the full /api/models surface, use the internal route.
  • Sorted by `updatedAt DESC` — newest first.

getExtraction

getExtraction(id: string): Promise<ExtractionDetailEnvelope>

Fetch a saved extraction's full audit-replay payload.

const { extraction } = await aas.getExtraction('cmoyalmj3000004jxefn8cicd')
console.log(extraction.aas)    // the AAS itself
console.log(extraction.meta)   // merged result + traces + cert + sourceHash
  • Returns 404 for IDs not owned by the bearer's userId/orgId — strict tenant isolation.
  • `meta` contains the full extractionMeta — use it to reconstruct the wizard's Review pane in your own UI, or drive downstream tooling.

validate

validate(opts: ValidateOptions): Promise<ValidateEnvelope>

Validate an AASX/XML file against the AAS schema.

import { readFileSync } from 'node:fs'

const aasx = readFileSync('./output.aasx')
const { valid, errors } = await aas.validate({ file: aasx })

if (!valid) {
  for (const e of errors) console.error(`Line ${e.line}: ${e.message}`)
}

fix

fix(opts: FixOptions): Promise<FixEnvelope>

Best-effort repair of a malformed AAS XML file.

const { xml, changed, warnings } = await aas.fix({ file: brokenAasxBuffer })
if (changed) {
  await fs.writeFile('./fixed.xml', xml)
}
for (const w of warnings) console.warn(w)

health

health(): Promise<HealthEnvelope>

Service liveness probe. No auth required.

const { status, version } = await aas.health()
console.log(status)  // 'ok'

merge

merge(opts: MergeOptions): Promise<MergeEnvelope>

Multi-source consensus voting — merge N ExtractionResults via the proprietary weighted per-field algorithm. Pure compute, no LLM cost (~€0.05/call).

const { merged } = await aas.merge({
  sources: [
    { sourceId: 'mfg',  authority: 'manufacturer', result: mfgResult },
    { sourceId: 'dist', authority: 'distributor',  result: distResult },
    { sourceId: '3p',   authority: 'third-party',  result: thirdPartyResult },
  ],
  weights: { distributor: 1.5 }, // optional override; defaults to 2.0/1.0/0.5
})

for (const sm of merged.submodels) {
  for (const el of sm.elements) {
    if (el.consensus && el.consensus.alternatives.length) {
      console.warn(`${el.idShort}: ${el.consensus.voters.length} agree, ${el.consensus.alternatives.length} disagree`)
    }
  }
}
  • Each `result` is a normal ExtractionResult (the same shape extract() returns). Tolerant of missing optional arrays — if the source omits warnings/variants, they're normalised at the boundary.
  • 1-20 sources per call. Body cap 5 MB. The merger's output is fully deterministic — same input + weights produces byte-identical output.

searchDatasheets

searchDatasheets(opts: SearchDatasheetsOptions): Promise<SearchDatasheetsEnvelope>

Tavily-backed search across the public web for product datasheets. Returns up to 8 hits scored by domain authority (manufacturer 100 → third-party 35), pre-validated as PDFs.

const { hits, images } = await aas.searchDatasheets({
  query: 'Universal Robots UR10e',
  maxHits: 5,           // optional, 1-8, default 5
  // skipProbe: true    // skip pingPdf pre-validation; faster but caller handles dead URLs
})

const top = hits[0]
console.log(top.title, top.url, top.authority, top.isPdf)

// Then pipe a confirmed-PDF hit straight into extract():
const pdfRes = await fetch(top.url)
const buf = new Uint8Array(await pdfRes.arrayBuffer())
const { result } = await aas.extract({ file: buf, fileName: top.title + '.pdf' })
  • Costs ~€0.10/call (paid Tavily backend). Cache results client-side if the same query repeats.
  • Images array contains product photo URLs (when Tavily returns them). Useful for thumbnails.
  • If skipProbe is false (default), every returned hit's `isPdf` is verified via a server-side GET + magic-byte check.
Source on GitHub · Raw API docs · OpenAPI schema

Command palette

Navigate + run actions