@project-sunbird/client-services
Table of Contents
Development setup
Prerequisites
NodeJS 22.15
Local Development
git clone https://github.com/your-username/sunbird-client-service.git
cd sunbird-client-service
npm i
npm run build
Continuous Integration
This project uses GitHub Actions for automated testing, building, and publishing. Below are details of the CI processes:
Pull Request Workflow
When a pull request is opened or updated, the following automated checks are performed:
- Code checkout: The repository code is checked out
- Environment setup: Node.js 22.15 is installed and configured
- Test execution: All tests are run with coverage reporting
- Code linting: ESLint is run to check code style and quality
- Static code analysis: SonarQube scan is performed to evaluate code quality
- Build verification: The project is built using webpack to ensure it compiles correctly. Ensure
SONAR_TOKEN is configured in your repository.
This ensures that all changes in pull requests meet quality standards before merging.
Release Workflow
When a new tag is pushed to the repository, the following automated steps are executed:
- Code checkout: The tagged version of code is checked out
- Environment setup: Node.js 22.15 is installed and configured with NPM registry access
- Dependency installation: Project dependencies are installed via
npm i
- Build process: The project is built for production
- Package creation: The build output is packaged for distribution
- NPM publication: The package is published to the NPM registry after setting
NPM_TOKEN
This allows for simple, reliable releases by simply pushing a new tag.
Manual Release Process
To manually trigger a new release:
- Update the version in
package.json
- Commit the change:
git commit -m "Increase version to x.y.z"
- Create and push a tag:
git tag v{x.y.z} && git push origin v{x.y.z}
The GitHub Actions workflow will automatically build and publish the new version.
Overview
The library is grouped into Modules and SubModules as shown below -
@project-sunbird/client-services
βββ blocs
βΒ Β βββ group-addable
βββ core
βΒ Β βββ http-service
βββ models
βΒ Β βββ certificate
βΒ Β βββ channel
βΒ Β βββ content
βΒ Β βββ course
βΒ Β βββ device
βΒ Β βββ faq
βΒ Β βββ form
βΒ Β βββ group
βΒ Β βββ location
βΒ Β βββ notification
βΒ Β βββ organisation
βΒ Β βββ page
βΒ Β βββ user
βββ services
βΒ Β βββ certificate
βΒ Β βββ content
βΒ Β βββ course
βΒ Β βββ discussion
βΒ Β βββ form
βΒ Β βββ framework
βΒ Β βββ group
βΒ Β βββ location
βΒ Β βββ notification
βΒ Β βββ system-settings
βΒ Β βββ user
βββ telemetry
βΒ Β βββ errors
βΒ Β βββ implementation
βΒ Β βββ interface
βββ utilities
βββ aggregator
βββ certificate
The public facing API is prefixed with 'Cs' namespace, as in -
- CsModule
- CsConfig
- CsGroupService
- ...
For instance,
- CsModule is part of the root module
- CsContentsGroupGenerator is a utlility within content service
Their respective imports would be -
import {CsModule} from "@project-sunbird/client-services";
import {CsContentsGroupGenerator} from "@project-sunbird/client-services/services/content/utilities/content-group-generator";
Installation
To install the package
npm i @project-sunbird/client-services@3.x.x
The package requires the consumer to have rxjs@6.x.x installed as the only peerDependency
Getting Started
To use the library CsModule, it needs to be initialised with basic configuration.
CsModule is a singleton and it would be best to check if it has already been initialised before attempting to initialise -
if (!CsModule.instance.isInitialised) { // Singleton initialised or not
await CsModule.instance.init({
core: {
httpAdapter: 'HttpClientBrowserAdapter', // optional - HttpClientBrowserAdapter or HttpClientCordovaAdapter, default - HttpClientBrowserAdapter
global: {
channelId: 'some_channel_id', // required
producerId: 'some_producer_id', // required
deviceId: 'some_random_device_id' // required
},
api: {
host: 'https://staging.ntp.net.in', // default host
authentication: {
// userToken: string; // optional
// bearerToken: string; // optional
}
}
},
services: {
// groupServiceConfig: CsGroupServiceConfig // optional
}
);
}
Adapters
If the client for the library is a cordova project, use the 'HttpClientCordovaAdapter' adapter
or use 'HttpClientBrowserAdapter'. 'HttpClientBrowserAdapter' is the default if not specified.
Update Configuration
The configuration can be dynamically reset after initialisation
const newConfig = {...CsModule.instance.config}; // copy existing config
newConfig.core.api.authentication = {
bearerToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV.eyJpc3MiOiJzdGFnaW5nLmRpa3NoYS5hcHAtYTMzM2YzZjExZDM0YzlkNWYwZTE2MjUyYWMwZDVhYTZmMTBjYSIsImlhdCI6MTU4ODkxNDc1NX0.dEmjK6LStoenL_pRX1KwEtU4-opuUOUGI05ecex',
};
CsModule.instance.updateConfig(CsModule.instance.config);
// after login
newConfig.core.api.authentication = {
userToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV.eyJpc3MiOiJzdGFnaW5nLmRpa3NoYS5hcHAtYTMzM2YzZjExZDM0YzlkNWYwZTE2MjUyYWMwZDVhYTZmMTBjYSIsImlhdCI6MTU4ODkxNDc1NX0.dEmjK6LStoenL_pRX1KwEtU4-opuUOUGI05ecex',
};
CsModule.instance.updateConfig(CsModule.instance.config);
Accessing a service
The CsModule being a singleton, every service within would also be a singleton, To access any service -
const httpService = CsModule.instance.httpService; // handles API calls, interceptors (tokens, logging)
const groupService = CsModule.instance.groupService; // internally uses httpService
Services
Every service by default will utilise the optional configuration declared during init() or updateConfig()
CsModule.instance.init({
...
services: {
groupServiceConfig: { // optional
apiPath: '/api/v1/group'
}
}
);
Additionally, methods of the service may have an optional argument that can override the global configuration explicitly
just for that method call
const group = await groupService.getById(
group1.identifier,
{ apiPath: '/api/v2/group' } // optional
).toPromise();
CsGroupService
This service deals with user group management and has the following interface -
CsModule.instance.init({
...
services: {
groupServiceConfig: { // optional
apiPath: '/api/v1/group'
}
}
);
interface CsGroupService {
create(
name: string,
board: string,
medium: string | string[],
gradeLevel: string | string[],
subject: string | string[],
config?: CsGroupServiceConfig
): Observable<Group>;
deleteById(id: string, config?: CsGroupServiceConfig): Observable<void>;
getAll(config?: CsGroupServiceConfig): Observable<Group[]>;
getById(id: string, config?: CsGroupServiceConfig): Observable<Group>;
addMemberById(memberId: string, groupId: string, config?: CsGroupServiceConfig): Observable<Group>;
removeMemberById(memberId: string, groupId: string, config?: CsGroupServiceConfig): Observable<void>;
}
CsFrameworkService
CsModule.instance.init({
...
services: {
frameworkServiceConfig: { // optional
apiPath: '<path>'
}
}
);
export interface CsFrameworkService {
getFramework(id: string, options?: GetFrameworkOptions, config?: CsFrameworkServiceConfig): Observable<Framework>;
}
CsLocationService
CsModule.instance.init({
...
services: {
locationServiceConfig: { // optional
apiPath: '<path>'
}
}
);
export interface CsLocationService {
searchLocations(request?: SearchLocationRequests, config?: CsLocationServiceConfig): Observable<Location[]>;
}
CsLocationService
CsModule.instance.init({
...
services: {
courseServiceConfig: { // optional
apiPath: '<path>'
}
}
);
export interface CsCourseService {
getUserEnrollmentList(request: GetUserEnrollmentListRequests, additionalParams?: { [key: string]: string }, config?: CsCourseServiceConfig): Observable<Course[]>;
}