A comprehensive TypeScript types package for Open Badges 2.0 and 3.0 specifications.
- Overview
- Installation
- Usage
- API Documentation
- Type Guards and Validation
- Development
- Version Compatibility
- Migration Guide
- Consuming Applications
- License
This package provides TypeScript type definitions for both Open Badges 2.0 and Open Badges 3.0 specifications. It can be used in badge servers, component libraries, and applications that work with Open Badges.
Open Badges are digital credentials that represent achievements, skills, or competencies. They are designed to be verifiable, portable, and stackable, allowing individuals to showcase their accomplishments across different platforms and contexts.
Open Badges 2.0 is the established standard developed by the IMS Global Learning Consortium. It defines a structured format for digital badges, including information about the issuer, recipient, criteria, and evidence.
Open Badges 3.0 represents a significant evolution, adopting the W3C Verifiable Credentials Data Model. This alignment with broader digital credential standards enhances interoperability and security while maintaining the core concepts of Open Badges.
This package supports both versions to ensure backward compatibility while enabling adoption of the newer standard. It provides type-safe interfaces for working with badges in either format, as well as utilities for converting between versions.
npm install openbadges-typesor
yarn add openbadges-typesimport { OB2 } from 'openbadges-types';
// Create a BadgeClass
const badgeClass: OB2.BadgeClass = {
'@context': 'https://w3id.org/openbadges/v2',
id: 'https://example.org/badges/5',
type: 'BadgeClass',
name: '3-D Printmaster',
description: 'This badge is awarded for passing the 3-D printing knowledge and safety test.',
image: 'https://example.org/badges/5/image',
criteria: {
narrative:
'Students are tested on knowledge and safety, both through a paper test and a supervised performance evaluation on key skills.',
},
issuer: {
id: 'https://example.org/issuer',
type: 'Profile',
name: 'Example Maker Society',
url: 'https://example.org',
email: '[email protected]',
verification: {
type: 'hosted',
allowedOrigins: 'example.org',
},
},
};
// Create an Assertion
const assertion: OB2.Assertion = {
'@context': 'https://w3id.org/openbadges/v2',
id: 'https://example.org/assertions/123',
type: 'Assertion',
recipient: {
type: 'email',
identity: '[email protected]',
},
issuedOn: '2016-12-31T23:59:59+00:00',
verification: {
type: 'hosted',
},
badge: badgeClass,
};import { OB3 } from 'openbadges-types';
// Create an Achievement
const achievement: OB3.Achievement = {
type: ['Achievement'],
name: '3-D Printmaster',
description: 'This badge is awarded for passing the 3-D printing knowledge and safety test.',
criteria: {
narrative:
'Students are tested on knowledge and safety, both through a paper test and a supervised performance evaluation on key skills.',
},
alignments: [
{
targetName: 'ISTE Standard 3',
targetUrl: 'https://example.org/standards/iste3',
},
],
};
// Create a Verifiable Credential
const credential: OB3.VerifiableCredential = {
'@context': [
'https://www.w3.org/2018/credentials/v1',
'https://purl.imsglobal.org/spec/ob/v3p0/context.json',
],
id: 'https://example.org/credentials/3732',
type: ['VerifiableCredential'],
issuer: {
id: 'https://example.org/issuers/123',
type: ['Profile'],
name: 'Example Maker Society',
url: 'https://example.org',
email: '[email protected]',
},
issuanceDate: '2023-06-15T12:00:00Z',
credentialSubject: {
id: 'did:example:ebfeb1f712ebc6f1c276e12ec21',
achievement: achievement,
},
proof: {
type: 'Ed25519Signature2020',
created: '2023-06-15T12:05:00Z',
verificationMethod: 'https://example.org/issuers/123#keys-1',
proofPurpose: 'assertionMethod',
proofValue: 'z58DAdFfa9SkqZMVPxAQpic6FPCsJWa6SpsfDqwmUbHEVnWxeh',
},
};import { Shared } from 'openbadges-types';
// Use shared types
const dateTime: Shared.DateTime = '2023-06-15T12:00:00Z';
const iri: Shared.IRI = 'https://example.org/badges/5';import { OpenBadgesVersion, VersionedBadge } from 'openbadges-types';
// Function that works with either version
function processBadge<T extends OpenBadgesVersion>(badge: VersionedBadge<T>, version: T): string {
if (version === OpenBadgesVersion.V2) {
// badge is typed as OB2.Assertion
return (badge as OB2.Assertion).badge.name;
} else {
// badge is typed as OB3.VerifiableCredential
const vc = badge as OB3.VerifiableCredential;
const achievement = vc.credentialSubject.achievement;
return Array.isArray(achievement)
? achievement[0].name.toString()
: achievement.name.toString();
}
}You can import the official JSON-LD context objects for Open Badges 2.0 and 3.0 for use in validation or tooling:
import { OB2_CONTEXT, OB3_CONTEXT } from 'openbadges-types';
// OB2_CONTEXT and OB3_CONTEXT are the official JSON-LD context objects
console.log(OB2_CONTEXT['@context']);
console.log(OB3_CONTEXT['@context']);-
Assertion: Represents an awarded badge to a specific recipientinterface Assertion extends JsonLdObject { '@context': string | string[] | Record<string, any>; id: IRI; type: 'Assertion' | string; recipient: IdentityObject; badge: BadgeClass | IRI; issuedOn: DateTime; expires?: DateTime; image?: string | ImageObject; evidence?: Evidence | Evidence[]; narrative?: MarkdownText; verification: VerificationObject; [key: string]: any; }
-
BadgeClass: Represents the type of achievement being awardedinterface BadgeClass extends JsonLdObject { '@context': string | string[] | Record<string, any>; id: IRI; type: 'BadgeClass' | string; name: string; description: string; image: string | ImageObject; criteria: string | Criteria; issuer: Profile | IRI; alignment?: AlignmentObject[]; tags?: string[]; [key: string]: any; }
-
Profile: Represents an issuer of badgesinterface Profile extends JsonLdObject { '@context': string | string[] | Record<string, any>; id: IRI; type: 'Profile' | 'Issuer' | string; name: string; url?: string; email?: string; description?: string; image?: string | ImageObject; verification?: VerificationObject; [key: string]: any; }
IdentityObject: Represents the identity of a badge recipientVerificationObject: Contains instructions for third parties to verify an assertionEvidence: Describes the work that the recipient did to earn the achievementAlignmentObject: Describes an alignment to an educational standardImage: Represents an image associated with a badgeCriteria: Describes the criteria for earning the badgeRevocationList: Contains a list of revoked assertionsCryptographicKey: Represents a cryptographic key used for verificationExtension: Represents an extension to the Open Badges specification
-
VerifiableCredential: Based on the W3C Verifiable Credentials Data Modelinterface VerifiableCredential extends JsonLdObject { '@context': string | string[] | Record<string, any>; id: IRI; type: 'VerifiableCredential' | string | string[]; issuer: IRI | Issuer; issuanceDate: DateTime; expirationDate?: DateTime; credentialSubject: CredentialSubject; proof?: Proof; credentialStatus?: CredentialStatus; refreshService?: RefreshService; termsOfUse?: TermsOfUse | TermsOfUse[]; evidence?: Evidence | Evidence[]; [key: string]: any; }
-
Achievement: Represents the achievement being recognizedinterface Achievement extends JsonLdObject { type: 'Achievement' | string | string[]; id?: IRI; name: string | MultiLanguageString; description?: string | MultiLanguageString; criteria?: Criteria; image?: string | ImageObject; creator?: IRI | Issuer; alignments?: Alignment[]; resultDescriptions?: ResultDescription[]; [key: string]: any; }
-
CredentialSubject: Represents the entity receiving the credentialinterface CredentialSubject extends JsonLdObject { id?: IRI; achievement: Achievement | Achievement[]; results?: Results; [key: string]: any; }
Issuer: Represents the entity issuing the credentialProof: Contains cryptographic proof informationEvidence: Describes the evidence for the achievementCriteria: Describes the criteria for earning the achievementAlignment: Describes an alignment to an educational standardResultDescription: Describes possible results for an achievementResults: Represents the results achieved by the recipientCredentialStatus: Represents the status of a credentialRefreshService: Provides a way to refresh the credentialTermsOfUse: Describes the terms of use for the credential
-
IRI: URI/URL type (branded string type for type safety)type IRI = string & { readonly __brand: unique symbol };
-
DateTime: ISO 8601 date format (branded string type for type safety)type DateTime = string & { readonly __brand: unique symbol };
-
JsonLdContext: JSON-LD context typetype JsonLdContext = string | string[] | Record<string, any>;
-
MultiLanguageString: Internationalization supportinterface MultiLanguageString { [language: string]: string; }
-
LanguageMap: Record mapping language codes to stringstype LanguageMap = Record<string, string>;
-
MarkdownText: String that may contain Markdowntype MarkdownText = string;
-
ImageObject: Common image propertiesinterface ImageObject { id?: IRI; type?: string; caption?: string | MultiLanguageString; author?: string; }
-
JsonLdObject: Base interface for JSON-LD objectsinterface JsonLdObject { '@context'?: string | string[] | Record<string, any>; type?: string | string[]; id?: string; [key: string]: any; }
-
JsonLdArray: Helper type for JSON-LD arraystype JsonLdArray<T> = T | T[];
For detailed development instructions, see DEVELOPMENT.md.
This package is built to support both CommonJS and ESM environments, with proper TypeScript type definitions for each format:
{
"exports": {
".": {
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
},
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"default": "./dist/index.js"
}
}
}This structure ensures:
- CommonJS consumers get the correct
.cjsfile with.d.ctstype definitions - ESM consumers get the correct
.jsfile with.d.tstype definitions - TypeScript can properly resolve types in both module formats
The package is validated using:
publint- Validates package.json exports and entry points@arethetypeswrong/cli- Checks for TypeScript type resolution issues
This package uses Jest for testing. The tests verify that the type definitions correctly match the OpenBadges 2.0 and 3.0 specifications.
To run the tests:
npm testTo run the tests with coverage:
npm run test:coverageTo build the package:
npm run buildThis package uses ESLint for linting and Prettier for code formatting.
To lint the code:
npm run lintTo format the code:
npm run formatTo validate the codebase (lint, format check, and test):
npm run validateThis package includes type guards and runtime validation for both Open Badges 2.0 and 3.0 objects:
- OB2 (Open Badges 2.0):
- Uses custom, spec-aligned validation logic (see
src/validation.ts). - Covers all required fields, types, and edge cases for Assertion, BadgeClass, Profile, and supporting types.
- Comprehensive positive and negative test cases in
test/validation.test.tsandtest/ob2-guards.test.ts.
- Uses custom, spec-aligned validation logic (see
- OB3 (Open Badges 3.0):
- Uses AJV for JSON Schema-based validation (see
src/validateWithSchema.ts). - Validates VerifiableCredential and all nested types against the official OB3 JSON-LD context.
- Comprehensive positive and negative test cases in
test/ob3-schema-validation.test.tsandtest/ob3-guards.test.ts.
- Uses AJV for JSON Schema-based validation (see
Example:
import { validateBadge } from 'openbadges-types';
const result = validateBadge(badgeObject);
if (result.isValid) {
// Badge is valid OB2 or OB3
console.log('Version:', result.version);
} else {
console.error('Validation errors:', result.errors);
}The package provides composite type guards that work with both OB2 and OB3 badges:
import { CompositeGuards } from 'openbadges-types';
// Check if an object is a valid badge (either OB2 or OB3)
if (CompositeGuards.isBadge(badge)) {
// Get badge properties regardless of version
const name = CompositeGuards.getBadgeName(badge);
const description = CompositeGuards.getBadgeDescription(badge);
const issuerName = CompositeGuards.getBadgeIssuerName(badge);
const issuanceDate = CompositeGuards.getBadgeIssuanceDate(badge);
console.log(`Badge: ${name} issued by ${issuerName} on ${issuanceDate}`);
console.log(`Description: ${description}`);
}For applications that need to work with both OB2 and OB3 badges, the package provides utilities to normalize badges to a common format:
import { BadgeNormalizer } from 'openbadges-types';
// Normalize a badge to a common format
const normalizedBadge = BadgeNormalizer.normalizeBadge(badgeObject);
// Now you can access common properties regardless of badge version
console.log(`Badge: ${normalizedBadge.name}`);
console.log(`Issued by: ${normalizedBadge.issuerName}`);
console.log(`Issued on: ${normalizedBadge.issuanceDate}`);
// You can also filter, sort, and group badges
const badges = BadgeNormalizer.normalizeBadges(badgeArray);
const filteredBadges = BadgeNormalizer.filterBadgesBySearchTerm(badges, 'search term');
const sortedBadges = BadgeNormalizer.sortBadges(badges, 'name', 'asc');
const groupedBadges = BadgeNormalizer.groupBadges(badges, 'issuerName');See the test files and Consuming Applications documentation for more usage examples and edge case coverage.
Note: OB3 validation currently uses the official JSON-LD context (not a strict JSON Schema) and a combination of AJV and manual checks. This means:
- Some edge cases or nuanced spec requirements may not be fully enforced.
- The validation logic is as strict as possible given the available context, but is not a full substitute for a formal JSON Schema.
- If/when an official OB3 JSON Schema is published, it is recommended to update the validation logic to use it for maximum conformance.
This package supports:
- Open Badges 2.0: The IMS Global Final Release specification
- Open Badges 3.0: Based on the W3C Verifiable Credentials Data Model
For detailed information about migrating from Open Badges 2.0 to 3.0, see our Migration Guide.
For detailed examples of how to use this package in your applications, see our Consuming Applications Guide. This guide includes:
- Examples for using type guards in Vue components
- Examples for using badge normalization in services
- Patterns for filtering, sorting, and grouping badges
- Best practices for working with both OB2 and OB3 badges
MIT