Skip to content

eclipse-basyx/basyx-typescript-sdk

Repository files navigation

GitHub Actions Workflow Status NPM Downloads NPM Version GitHub License

basyx-typescript-sdk

BaSyx TypeScript SDK for developing applications and components for the Asset Administration Shell (AAS)

Features

High-level orchestration services:

  • AasService: Unified API for AAS operations across registry and repository
    • Create, read, update, delete AAS with automatic registry synchronization
    • Fetch AAS with their submodels in a single call
    • Automatic endpoint resolution and fallback handling
  • SubmodelService: Unified API for Submodel operations across registry and repository
    • Create, read, update, delete Submodels with automatic registry synchronization
    • Flexible endpoint-based retrieval
    • Automatic fallback to repository when registry unavailable

Clients for the AAS API components:

  • AAS Repository
  • Submodel Repository
  • Concept Description Repository
  • AAS Registry
  • Submodel Registry
  • AAS Discovery Service
  • AASX File Service

Utility functions for working with AAS data:

  • Utils for Descriptors
  • Utils for KeyTypes
  • Utils for MultiLanguageProperties
  • Utils for Referables
  • Utils for References
  • Utils for SemanticIds

Installation

npm install basyx-typescript-sdk
# or
pnpm add basyx-typescript-sdk

See https://www.npmjs.com/package/basyx-typescript-sdk


[!IMPORTANT] Make sure to also install @aas-core-works/aas-core3.1-typescript in your project:

npm install @aas-core-works/aas-core3.1-typescript
# or
pnpm add @aas-core-works/aas-core3.1-typescript

Development

pnpm install
pnpm format:check
pnpm lint:check
pnpm type-check
pnpm build
pnpm bundle
pnpm test
pnpm verify:compat

Use .nvmrc to align local Node.js with CI:

nvm use

Import Styles

The SDK supports multiple import styles for flexibility:

Direct Imports (Recommended for most use cases)

// Import clients directly
import { AasRepositoryClient, AasRegistryClient, Configuration } from 'basyx-typescript-sdk';

// Import services directly
import { AasService } from 'basyx-typescript-sdk';

// Import utility functions directly
import { extractEndpointHref, getSubmodelElementByIdShort } from 'basyx-typescript-sdk';

// Import library functions directly
import { base64Encode, base64Decode } from 'basyx-typescript-sdk';

Namespaced Imports (For organized code)

// Import utilities as namespace
import { Utils, Lib } from 'basyx-typescript-sdk';

// Use with namespace
const endpoint = Utils.extractEndpointHref(descriptor, 'AAS-3.0');
const encoded = Lib.base64Encode('my-id');

Mixed Style

// Combine direct and namespaced imports
import { AasService, Configuration, Utils, base64Encode } from 'basyx-typescript-sdk';

// Use directly imported functions
const id = base64Encode('my-id');

// Use namespaced utilities
const element = Utils.getSubmodelElementByIdShort(submodel, 'myElement');

Usage Examples

Basic Client Usage

import { AasRepositoryClient, Configuration } from 'basyx-typescript-sdk';

async function getAllShells() {
  const client = new AasRepositoryClient();
  const configuration = new Configuration({
    basePath: 'http://localhost:8081',
  });

  const response = await client.getAllAssetAdministrationShells({ configuration });

  if (response.success) {
    console.log('Shells:', response.data.result);
  } else {
    console.error('Error:', response.error);
  }
}

Using the AasService (High-level API)

import { AasService, Configuration } from 'basyx-typescript-sdk';
import { AssetAdministrationShell, AssetInformation, AssetKind } from '@aas-core-works/aas-core3.1-typescript/types';

// Initialize service with both registry and repository
const service = new AasService({
  registryConfig: new Configuration({ basePath: 'http://localhost:8084' }),
  repositoryConfig: new Configuration({ basePath: 'http://localhost:8081' }),
  // Optional: Separate configs for submodel services (used when includeSubmodels is enabled)
  // If not provided, falls back to using registryConfig/repositoryConfig for submodels
  // In typical BaSyx deployments, submodel services run on different ports:
  submodelRegistryConfig: new Configuration({ basePath: 'http://localhost:8083' }),
  submodelRepositoryConfig: new Configuration({ basePath: 'http://localhost:8081' }),
  // Optional: Discovery service config (used for asset ID lookups)
  discoveryConfig: new Configuration({ basePath: 'http://localhost:8086' }),
});

// Create a new AAS (automatically registers in registry)
const shell = new AssetAdministrationShell(
  'https://example.com/ids/aas/my-aas',
  new AssetInformation(AssetKind.Instance)
);

const createResult = await service.createAas({ shell });
if (createResult.success) {
  console.log('Created AAS:', createResult.data.shell);
}

// Get AAS list from registry with automatic endpoint resolution
const listResult = await service.getAasList();
if (listResult.success) {
  console.log('All shells:', listResult.data.shells);
}

// Get AAS by ID (uses registry endpoint if available)
const getResult = await service.getAasById({
  aasIdentifier: 'https://example.com/ids/aas/my-aas',
});

// Get AAS with its submodels in a single call
const withSubmodels = await service.getAasById({
  aasIdentifier: 'https://example.com/ids/aas/my-aas',
  includeSubmodels: true,
});
if (withSubmodels.success) {
  console.log('Shell:', withSubmodels.data.shell);
  console.log('Submodels:', withSubmodels.data.submodels); // Array of submodels
}

// Get all AAS with their submodels
const allWithSubmodels = await service.getAasList({ includeSubmodels: true });
if (allWithSubmodels.success) {
  allWithSubmodels.data.shells.forEach((shell, index) => {
    console.log(`Shell ${index}:`, shell.id);
    console.log(`Submodels:`, allWithSubmodels.data.submodels?.[shell.id]);
  });
}

// Update AAS (updates both repository and registry)
shell.idShort = 'UpdatedName';
const updateResult = await service.updateAas({ shell });

// Get endpoint for an AAS
const endpointResult = await service.getAasEndpointById({
  aasIdentifier: 'https://example.com/ids/aas/my-aas',
});

// Get AAS directly by endpoint URL
const byEndpointResult = await service.getAasByEndpoint({
  endpoint: 'http://localhost:8081/shells/encoded-id',
});

// Delete AAS (removes from both registry and repository)
await service.deleteAas({
  aasIdentifier: 'https://example.com/ids/aas/my-aas',
});

// Find AAS by asset IDs using discovery service
const assetIds = [
  { name: 'serialNumber', value: '12345' },
  { name: 'deviceId', value: 'device-001' },
];

const byAssetIdResult = await service.getAasByAssetId({
  assetIds,
  includeSubmodels: true, // Optionally include submodels
});
if (byAssetIdResult.success) {
  console.log('Found AAS IDs:', byAssetIdResult.data.aasIds);
  console.log('Found shells:', byAssetIdResult.data.shells);
  // If multiple AAS match the asset IDs, all are returned
}

// Fetch AAS with submodels and their concept descriptions
const serviceWithCD = new AasService({
  registryConfig: new Configuration({ basePath: 'http://localhost:8084' }),
  repositoryConfig: new Configuration({ basePath: 'http://localhost:8081' }),
  submodelRegistryConfig: new Configuration({ basePath: 'http://localhost:8085' }),
  submodelRepositoryConfig: new Configuration({ basePath: 'http://localhost:8082' }),
  conceptDescriptionRepositoryConfig: new Configuration({ basePath: 'http://localhost:8083' }),
});

const withConceptDescriptions = await serviceWithCD.getAasById({
  aasIdentifier: 'https://example.com/ids/aas/my-aas',
  includeSubmodels: true,
  includeConceptDescriptions: true,
});
if (withConceptDescriptions.success) {
  console.log('Shell:', withConceptDescriptions.data.shell);
  console.log('Submodels with CDs:', withConceptDescriptions.data.submodels);
  // Concept descriptions are fetched for all semantic IDs in submodels and their elements
}

// Resolve a Reference to get endpoints for AAS, Submodel, or SubmodelElement
import { Reference, Key, KeyTypes, ReferenceTypes } from '@aas-core-works/aas-core3.1-typescript/types';

// Example 1: Reference to AAS and Submodel
const reference1 = new Reference(ReferenceTypes.ModelReference, [
  new Key(KeyTypes.AssetAdministrationShell, 'https://example.com/ids/aas/my-aas'),
  new Key(KeyTypes.Submodel, 'https://example.com/ids/sm/my-submodel'),
]);

const resolved1 = await service.resolveReference({ reference: reference1 });
if (resolved1.success) {
  console.log('AAS Endpoint:', resolved1.data.aasEndpoint);
  // e.g., 'http://localhost:8081/shells/encoded-aas-id'
  console.log('Submodel Endpoint:', resolved1.data.submodelEndpoint);
  // e.g., 'http://localhost:8082/submodels/encoded-sm-id'
}

// Example 2: Reference to a specific SubmodelElement
const reference2 = new Reference(ReferenceTypes.ModelReference, [
  new Key(KeyTypes.AssetAdministrationShell, 'https://example.com/ids/aas/my-aas'),
  new Key(KeyTypes.Submodel, 'https://example.com/ids/sm/my-submodel'),
  new Key(KeyTypes.Property, 'MyProperty'),
]);

const resolved2 = await service.resolveReference({ reference: reference2 });
if (resolved2.success) {
  console.log('SubmodelElement Path:', resolved2.data.submodelElementPath);
  // e.g., 'http://localhost:8082/submodels/encoded-sm-id/submodel-elements/MyProperty'
}

// Example 3: Reference to nested SubmodelElements
const reference3 = new Reference(ReferenceTypes.ModelReference, [
  new Key(KeyTypes.Submodel, 'https://example.com/ids/sm/my-submodel'),
  new Key(KeyTypes.SubmodelElementCollection, 'MyCollection'),
  new Key(KeyTypes.Property, 'NestedProperty'),
]);

const resolved3 = await service.resolveReference({ reference: reference3 });
if (resolved3.success) {
  console.log('SubmodelElement Path:', resolved3.data.submodelElementPath);
  // e.g., 'http://localhost:8082/submodels/encoded-sm-id/submodel-elements/MyCollection.NestedProperty'
}

// Fetch all AAS with submodels and concept descriptions
const allWithCD = await serviceWithCD.getAasList({
  includeSubmodels: true,
  includeConceptDescriptions: true,
});
if (allWithCD.success) {
  allWithCD.data.shells.forEach((shell) => {
    console.log('Shell:', shell.id);
    console.log('Submodels:', allWithCD.data.submodels?.[shell.id]);
    // Concept descriptions are available through the submodel service
  });
}

Using the SubmodelService (High-level API)

import { SubmodelService, Configuration } from 'basyx-typescript-sdk';
import { Submodel, ModellingKind } from '@aas-core-works/aas-core3.1-typescript/types';

// Initialize service with both registry and repository
const service = new SubmodelService({
  registryConfig: new Configuration({ basePath: 'http://localhost:8085' }),
  repositoryConfig: new Configuration({ basePath: 'http://localhost:8082' }),
});

// Create a new Submodel (automatically registers in registry)
const submodel = new Submodel(
  'https://example.com/ids/sm/my-submodel',
  null, // extensions
  null, // category
  'MySubmodel', // idShort
  null, // displayName
  null, // description
  null, // administration
  ModellingKind.Instance
);

const createResult = await service.createSubmodel({ submodel });
if (createResult.success) {
  console.log('Created Submodel:', createResult.data.submodel);
  console.log('Registry Descriptor:', createResult.data.descriptor);
}

// Get Submodel list from registry with automatic endpoint resolution
const listResult = await service.getSubmodelList({ preferRegistry: true });
if (listResult.success) {
  console.log('All submodels:', listResult.data.submodels);
  console.log('Fetched from:', listResult.data.source); // 'registry' or 'repository'
}

// Get Submodel by ID (uses registry endpoint if available)
const getResult = await service.getSubmodelById({
  submodelIdentifier: 'https://example.com/ids/sm/my-submodel',
  useRegistryEndpoint: true,
});
if (getResult.success) {
  console.log('Submodel:', getResult.data.submodel);
  console.log('Descriptor:', getResult.data.descriptor);
}

// Update Submodel (updates both repository and registry)
submodel.idShort = 'UpdatedSubmodel';
const updateResult = await service.updateSubmodel({ submodel });

// Get endpoint for a Submodel
const endpointResult = await service.getSubmodelEndpointById({
  submodelIdentifier: 'https://example.com/ids/sm/my-submodel',
});
if (endpointResult.success) {
  console.log('Endpoint:', endpointResult.data);
}

// Get Submodel directly by endpoint URL
const byEndpointResult = await service.getSubmodelByEndpoint({
  endpoint: 'http://localhost:8082/submodels/encoded-id',
});

// Delete Submodel (removes from both registry and repository)
await service.deleteSubmodel({
  submodelIdentifier: 'https://example.com/ids/sm/my-submodel',
});

// Service works with only repository (no registry)
const repoOnlyService = new SubmodelService({
  repositoryConfig: new Configuration({ basePath: 'http://localhost:8082' }),
});

const repoList = await repoOnlyService.getSubmodelList();
// Automatically falls back to repository when registry unavailable

// Fetch submodels with concept descriptions
const serviceWithCD = new SubmodelService({
  registryConfig: new Configuration({ basePath: 'http://localhost:8085' }),
  repositoryConfig: new Configuration({ basePath: 'http://localhost:8082' }),
  conceptDescriptionRepositoryConfig: new Configuration({ basePath: 'http://localhost:8083' }),
});

// Get submodel with its concept descriptions
const withCD = await serviceWithCD.getSubmodelById({
  submodelIdentifier: 'https://example.com/ids/sm/my-submodel',
  includeConceptDescriptions: true,
});
if (withCD.success) {
  console.log('Submodel:', withCD.data.submodel);
  console.log('Concept Descriptions:', withCD.data.conceptDescriptions);
  // conceptDescriptions array contains all unique CDs referenced by:
  // - The submodel's semanticId
  // - All submodel elements' semanticId properties (recursively through collections, lists, entities)
}

// Get all submodels with concept descriptions
const listWithCD = await serviceWithCD.getSubmodelList({
  preferRegistry: false,
  includeConceptDescriptions: true,
});
if (listWithCD.success) {
  console.log('Submodels:', listWithCD.data.submodels);
  console.log('All Concept Descriptions:', listWithCD.data.conceptDescriptions);
  // Concept descriptions are deduplicated across all submodels
}

// Get submodel by endpoint with concept descriptions
const byEndpointWithCD = await serviceWithCD.getSubmodelByEndpoint({
  endpoint: 'http://localhost:8082/submodels/encoded-id',
  includeConceptDescriptions: true,
});

Using Utility Functions

import { getSubmodelElementByIdShort, extractEndpointHref, base64Encode } from 'basyx-typescript-sdk';
import { Submodel } from '@aas-core-works/aas-core3.1-typescript/types';

// Get a submodel element by its idShort
const element = getSubmodelElementByIdShort(submodel, 'MyProperty');

// Extract endpoint from descriptor
const endpoint = extractEndpointHref(descriptor, 'AAS-3.0');

// Encode/decode IDs from Identifiables
const encoded = base64Encode('https://example.com/ids/aas/my-aas');
// Use in URL: http://localhost:8081/shells/{encoded}

XML Serialization and Deserialization

import { serializeXml, deserializeXml } from 'basyx-typescript-sdk';
import { BaSyxEnvironment } from 'basyx-typescript-sdk';
import {
  AssetAdministrationShell,
  AssetInformation,
  AssetKind,
  Submodel,
  ModellingKind,
} from '@aas-core-works/aas-core3.1-typescript/types';

// Create an environment with AAS and Submodels
const environment = new BaSyxEnvironment(
  [new AssetAdministrationShell('https://example.com/ids/aas/my-aas', new AssetInformation(AssetKind.Instance))],
  [
    new Submodel(
      'https://example.com/ids/sm/my-submodel',
      null,
      null,
      'MySubmodel',
      null,
      null,
      null,
      ModellingKind.Instance
    ),
  ],
  [] // conceptDescriptions
);

// Serialize to XML string
const xmlString = serializeXml(environment);
console.log(xmlString);
// Output:
// <?xml version="1.0" encoding="UTF-8"?>
// <aas:environment xmlns:aas="https://admin-shell.io/aas/3/1"
//   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
//   xsi:schemaLocation="https://admin-shell.io/aas/3/1 AAS.xsd">
//   ...
// </aas:environment>

// Customize namespace prefix (default is 'aas')
const xmlWithCustomPrefix = serializeXml(environment, 'custom');

// Deserialize XML back to BaSyxEnvironment
const deserializedEnv = deserializeXml(xmlString);
console.log('AAS:', deserializedEnv.assetAdministrationShells);
console.log('Submodels:', deserializedEnv.submodels);

About

BaSyx TypeScript SDK for developing applications and components for the Asset Administration Shell (AAS)

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors