# @eduware/oneroster

Type-safe TypeScript SDK for the OneRoster API with LMS-specific client profiles.

<div align="left">
    <a href="https://www.npmjs.com/package/@eduware/oneroster">
        <img src="https://img.shields.io/npm/v/@eduware/oneroster.svg" alt="npm version" />
    </a>
    <a href="https://www.npmjs.com/package/@eduware/oneroster">
        <img src="https://img.shields.io/npm/dm/@eduware/oneroster.svg" alt="npm downloads" />
    </a>
    <a href="https://opensource.org/licenses/MIT">
        <img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT" />
    </a>
    <a href="#">
        <img src="https://img.shields.io/badge/OneRoster-v1.1%20%7C%20v1.2-green.svg" alt="OneRoster v1.1 | v1.2" />
    </a>
    <a href="#">
        <img src="https://img.shields.io/badge/TypeScript-5.0+-blue.svg" alt="TypeScript 5.0+" />
    </a>
</div>

## Features

- OneRoster v1.1 and v1.2 support
- LMS-specific client profiles (read-only vs full CRUD)
- Custom profiles: create your own profiles with TypeScript `Pick<>`
- OAuth 2.0 (v1.2) and OAuth 1.0a (v1.1)
- Automatic pagination with async iterables
- TypeScript-first with comprehensive types
- Tree-shakeable standalone functions for small bundles

## Installation

```bash
# npm
npm add @eduware/oneroster

# pnpm
pnpm add @eduware/oneroster

# yarn
yarn add @eduware/oneroster zod

# bun
bun add @eduware/oneroster
```

> Note: Yarn does not install peer dependencies automatically. Install `zod` manually.

## Changelog

See [CHANGELOG.md](./CHANGELOG.md) for release notes and breaking changes.

## Quick Start (recommended)

The main entry point is the full client:

```typescript
import { OneRoster } from '@eduware/oneroster';

const client = new OneRoster({
    serverURL: 'https://your-oneroster-server.com',
    security: {
        clientID: process.env.ONEROSTER_CLIENT_ID!,
        clientSecret: process.env.ONEROSTER_CLIENT_SECRET!,
        tokenURL: 'https://your-oneroster-server.com/oauth/token',
    },
});

const user = await client.usersManagement.getUser({
    sourcedId: 'user-id',
});

const schools = await client.schoolsManagement.getAllSchools({});
for await (const page of schools) {
    console.log(page.result.orgs);
}
```

## ClassLink Example (read-only profile)

Show LMS integrations explicitly by using the ClassLink client, which only exposes read endpoints:

```typescript
import { ClassLink } from '@eduware/oneroster/clients';

const client = new ClassLink({
    serverURL: 'https://example.classlink.com',
    security: {
        authType: 'bearer',
        bearerToken: process.env.CLASSLINK_BEARER_TOKEN!,
    },
});

// Read operations are available
const users = await client.usersManagement.getAllUsers({});

// Write operations are not available (TypeScript error)
// await client.usersManagement.createUser({ ... });
```

## Custom Profile Example (your LMS)

Define a profile that matches your LMS contract by picking only the methods you need:

```typescript
import { OneRoster } from '@eduware/oneroster';
import type { OneRosterClient } from '@eduware/oneroster/clients';
import type { UsersManagement, ClassesManagement } from '@eduware/oneroster';

interface CustomProfile {
    usersManagement: Pick<UsersManagement, 'getAllUsers' | 'getUser'>;
    classesManagement: Pick<ClassesManagement, 'getAllClasses' | 'getClass'>;
}

const client: OneRosterClient<CustomProfile> = new OneRoster({
    serverURL: 'https://your-roster-server.com',
    security: {
        clientID: process.env.ONEROSTER_CLIENT_ID!,
        clientSecret: process.env.ONEROSTER_CLIENT_SECRET!,
        tokenURL: 'https://your-roster-server.com/oauth/token',
    },
});

const users = await client.usersManagement.getAllUsers({});
```

This SDK works with any OneRoster-compliant LMS and includes profiles for common integrations.

## Recommended Import Path

Most users only need the main client:

```typescript
import { OneRoster } from '@eduware/oneroster';
```

Operation types use `@eduware/oneroster/types`:

```typescript
import type { GetAllUsersUser, GetAllSchoolsOrg } from '@eduware/oneroster/types';
```

Model types live at `@eduware/oneroster/models`:

```typescript
import type { User } from '@eduware/oneroster/models';
```

Enums live at `@eduware/oneroster/enums`:

```typescript
import { UserRole } from '@eduware/oneroster/enums';
```

Advanced import paths (standalone functions) are documented later in this README.

## Client Structure

The SDK is organized by management modules, grouped by domain:

### Rostering

- `usersManagement`
- `studentsManagement`
- `teachersManagement`
- `classesManagement`
- `coursesManagement`
- `enrollmentsManagement`
- `schoolsManagement`
- `organizationsManagement`

### Academic Calendar

- `academicSessionsManagement`
- `termsManagement`
- `gradingPeriodsManagement`

### Gradebook

- `lineItemsManagement`
- `resultsManagement`
- `categoriesManagement`
- `scoreScalesManagement`

### Resources

- `resourcesManagement`
- `courseComponentsManagement`
- `courseComponentResourcesManagement`

### Assessments

- `assessmentLineItemsManagement`
- `assessmentResultsManagement`

### Demographics

- `demographicsManagement`

## Common Operations

```typescript
// List with pagination
const users = await client.usersManagement.getAllUsers({ limit: 100 });
for await (const page of users) {
    console.log(page.result.users);
}

// Get by sourcedId
const student = await client.studentsManagement.getStudent({ sourcedId: 'student-id' });

// Create
await client.coursesManagement.createCourse({
    course: {
        title: 'Algebra I',
        org: { sourcedId: 'school-id' },
    },
});

// Update
await client.classesManagement.updateClass({
    sourcedId: 'class-id',
    class: { title: 'Math 101 - Period 2' },
});

// Delete
await client.organizationsManagement.deleteOrg({ sourcedId: 'org-id' });
```

## Filtering and Sorting

```typescript
import { OrderBy } from '@eduware/oneroster/enums';

const activeUsers = await client.usersManagement.getAllUsers({
    filter: "status='active'",
    sort: 'familyName',
    orderBy: OrderBy.Asc,
});

const teachers = await client.usersManagement.getAllUsers({
    filter: "role='teacher' AND status='active'",
});

const searchByEmail = await client.usersManagement.getAllUsers({
    search: 'teacher@district.edu',
    fields: 'sourcedId,username,email',
});
```

## Pagination and Total Count

List operations return an async iterator. If the provider sets `X-Total-Count`, it is exposed as `totalCount`.

```typescript
const pages = await client.usersManagement.getAllUsers({ limit: 200, offset: 0 });

for await (const page of pages) {
    console.log('page count', page.result.users.length);
    console.log('total count', page.totalCount);
}
```

## Nested Query Patterns

Use the module methods that reflect OneRoster relationships:

```typescript
// School -> class -> enrollments
const classes = await client.schoolsManagement.getClassesForSchool({ sourcedId: 'school-id' });
const enrollments = await client.schoolsManagement.getEnrollmentsForClassInSchool({
    schoolSourcedId: 'school-id',
    classSourcedId: 'class-id',
});

// Teacher -> classes
const teaching = await client.teachersManagement.getClassesForTeacher({
    sourcedId: 'teacher-id',
});

// Class -> line items -> results
const lineItems = await client.classesManagement.getLineItemsForClass({ sourcedId: 'class-id' });
const results = await client.classesManagement.getResultsForLineItemForClass({
    classSourcedId: 'class-id',
    lineItemSourcedId: 'line-item-id',
});
```

## OneRoster Versions

The SDK supports both OneRoster v1.1 and v1.2. Default is v1.2.

### v1.2 (OAuth 2.0)

```typescript
const client = new OneRoster({
    serverURL: 'https://your-server.com',
    security: {
        clientID: process.env.ONEROSTER_CLIENT_ID!,
        clientSecret: process.env.ONEROSTER_CLIENT_SECRET!,
        tokenURL: 'https://your-server.com/oauth/token',
    },
});
```

### v1.1 (OAuth 1.0a)

```typescript
const client = new OneRoster({
    serverURL: 'https://your-server.com',
    oneRosterVersion: '1.1',
    security: {
        authType: 'oauth1',
        clientID: process.env.ONEROSTER_CLIENT_ID!,
        clientSecret: process.env.ONEROSTER_CLIENT_SECRET!,
    },
});
```

### Bearer Token (provider-specific)

```typescript
const client = new OneRoster({
    serverURL: 'https://your-server.com',
    security: {
        authType: 'bearer',
        bearerToken: process.env.ONEROSTER_BEARER_TOKEN!,
    },
});
```

## Error Handling

```typescript
import { OneRoster, OneRosterError, NotFoundResponseError } from '@eduware/oneroster';

const client = new OneRoster({
    /* ... */
});

try {
    await client.usersManagement.getUser({ sourcedId: 'missing-id' });
} catch (error) {
    if (error instanceof NotFoundResponseError) {
        console.log('User not found');
    } else if (error instanceof OneRosterError) {
        console.log('HTTP Error:', error.statusCode, error.message);
    }
}
```

## Standalone Functions (tree-shaking)

Use standalone functions for minimal bundles or serverless environments:

```typescript
import { OneRosterCore } from '@eduware/oneroster/core.js';
import { usersManagementGetAllUsers } from '@eduware/oneroster/funcs/usersManagementGetAllUsers.js';

const core = new OneRosterCore({
    security: {
        clientID: process.env.ONEROSTER_CLIENT_ID!,
        clientSecret: process.env.ONEROSTER_CLIENT_SECRET!,
    },
});

const result = await usersManagementGetAllUsers(core, {});
if (result.ok) {
    for await (const page of result.value) {
        console.log(page.result.users);
    }
}
```

See [FUNCTIONS.md](./FUNCTIONS.md) for the full list.

## Function Index (by Module)

Each function maps to `@eduware/oneroster/funcs/<name>.js`.

### academicSessionsManagement

```text
academicSessionsManagementDeleteAcademicSession
academicSessionsManagementGetAcademicSession
academicSessionsManagementGetAllAcademicSessions
academicSessionsManagementPostAcademicSession
academicSessionsManagementPutAcademicSession
```

### assessmentLineItemsManagement

```text
assessmentLineItemsManagementCreateAssessmentLineItem
assessmentLineItemsManagementDeleteAssessmentLineItem
assessmentLineItemsManagementGetAllAssessmentLineItems
assessmentLineItemsManagementGetAssessmentLineItem
assessmentLineItemsManagementUpdateAssessmentLineItem
```

### assessmentResultsManagement

```text
assessmentResultsManagementCreateAssessmentResult
assessmentResultsManagementDeleteAssessmentResult
assessmentResultsManagementGetAllAssessmentResults
assessmentResultsManagementGetAssessmentResult
assessmentResultsManagementUpdateAssessmentResult
```

### categoriesManagement

```text
categoriesManagementCreateCategory
categoriesManagementDeleteCategory
categoriesManagementGetAllCategories
categoriesManagementGetCategory
categoriesManagementUpdateCategory
```

### classesManagement

```text
classesManagementAddStudentToClass
classesManagementAddTeacherToClass
classesManagementCreateClass
classesManagementDeleteClass
classesManagementGetAllClasses
classesManagementGetCategoriesForClass
classesManagementGetClass
classesManagementGetClassesForStudent
classesManagementGetClassesForTeacher
classesManagementGetClassesForTerm
classesManagementGetClassesForUser
classesManagementGetLineItemsForClass
classesManagementGetResultsForClass
classesManagementGetResultsForLineItemForClass
classesManagementGetResultsForStudentForClass
classesManagementGetScoreScalesForClass
classesManagementGetStudentsForClass
classesManagementGetTeachersForClass
classesManagementPostResultsForAcademicSessionForClass
classesManagementUpdateClass
```

### coursesManagement

```text
coursesManagementCreateComponentResource
coursesManagementCreateCourse
coursesManagementCreateCourseComponent
coursesManagementDeleteComponentResource
coursesManagementDeleteCourse
coursesManagementDeleteCourseComponent
coursesManagementGetAllComponentResources
coursesManagementGetAllCourseComponents
coursesManagementGetAllCourses
coursesManagementGetClassesForCourse
coursesManagementGetComponentResource
coursesManagementGetCourse
coursesManagementGetCourseComponent
coursesManagementPutComponentResource
coursesManagementPutCourse
coursesManagementPutCourseComponent
```

### demographicsManagement

```text
demographicsManagementDeleteDemographics
demographicsManagementGetAllDemographics
demographicsManagementGetDemographics
demographicsManagementPostDemographics
demographicsManagementPutDemographics
```

### enrollmentsManagement

```text
enrollmentsManagementCreateEnrollment
enrollmentsManagementDeleteEnrollment
enrollmentsManagementGetAllEnrollments
enrollmentsManagementGetEnrollment
enrollmentsManagementUpdateEnrollment
```

### gradingPeriodsManagement

```text
gradingPeriodsManagementCreateGradingPeriod
gradingPeriodsManagementDeleteGradingPeriod
gradingPeriodsManagementGetAllGradingPeriods
gradingPeriodsManagementGetGradingPeriod
gradingPeriodsManagementUpdateGradingPeriod
```

### lineItemsManagement

```text
lineItemsManagementCreateLineItem
lineItemsManagementCreateResultForLineItem
lineItemsManagementDeleteLineItem
lineItemsManagementGetAllLineItems
lineItemsManagementGetLineItem
lineItemsManagementUpdateLineItem
```

### organizationsManagement

```text
organizationsManagementCreateOrg
organizationsManagementDeleteOrg
organizationsManagementGetAllOrgs
organizationsManagementGetOrg
organizationsManagementUpdateOrg
```

### resourcesManagement

```text
resourcesManagementCreateResource
resourcesManagementDeleteResource
resourcesManagementExportResourceToCommonCartridge
resourcesManagementGetAllResources
resourcesManagementGetResource
resourcesManagementGetResourcesForClass
resourcesManagementGetResourcesForCourse
resourcesManagementGetResourcesForUser
resourcesManagementUpdateResource
```

### resultsManagement

```text
resultsManagementCreateResult
resultsManagementDeleteResult
resultsManagementGetAllResults
resultsManagementGetResult
resultsManagementUpdateResult
```

### schoolsManagement

```text
schoolsManagementCreateLineItemsForSchool
schoolsManagementCreateSchool
schoolsManagementDeleteSchool
schoolsManagementGetAllSchools
schoolsManagementGetClassesForSchool
schoolsManagementGetCoursesForSchool
schoolsManagementGetEnrollmentsForClassInSchool
schoolsManagementGetEnrollmentsForSchool
schoolsManagementGetLineItemsForSchool
schoolsManagementGetSchool
schoolsManagementGetStudentsForClassInSchool
schoolsManagementGetStudentsForSchool
schoolsManagementGetTeachersForClassInSchool
schoolsManagementGetTeachersForSchool
schoolsManagementGetTermsForSchool
schoolsManagementUpdateSchool
```

### scoreScalesManagement

```text
scoreScalesManagementCreateScoreScale
scoreScalesManagementDeleteScoreScale
scoreScalesManagementGetAllScoreScales
scoreScalesManagementGetScoreScale
scoreScalesManagementGetScoreScalesForSchool
scoreScalesManagementUpdateScoreScale
```

### studentsManagement

```text
studentsManagementGetAllStudents
studentsManagementGetStudent
```

### teachersManagement

```text
teachersManagementGetAllTeachers
teachersManagementGetTeacher
```

### termsManagement

```text
termsManagementCreateGradingPeriodForTerm
termsManagementGetAllTerms
termsManagementGetGradingPeriodsForTerm
termsManagementGetTerm
```

### usersManagement

```text
usersManagementCreateUser
usersManagementDeleteUser
usersManagementGetAllUsers
usersManagementGetUser
usersManagementGetUserWithDemographics
usersManagementUpdateUser
```

## LMS Provider Support

Support varies by LMS provider and contract. The profile you choose reflects LMS capabilities, not library limitations.

### LMS Profiles

| Provider  | Profile     | Notes                      |
| --------- | ----------- | -------------------------- |
| OneRoster | full        | All endpoints available    |
| ClassLink | classlink   | Read-only rostering access |
| (future)  | coming soon | Add new LMS profiles here  |

### CRUD Operations by Module

| Module                               | Create | Read | Update | Delete |
| ------------------------------------ | :----: | :--: | :----: | :----: |
| `usersManagement`                    |   ✅   |  ✅  |   ✅   |   ✅   |
| `studentsManagement`                 |   —    |  ✅  |   —    |   —    |
| `teachersManagement`                 |   —    |  ✅  |   —    |   —    |
| `classesManagement`                  |   ✅   |  ✅  |   ✅   |   ✅   |
| `coursesManagement`                  |   ✅   |  ✅  |   ✅   |   ✅   |
| `enrollmentsManagement`              |   ✅   |  ✅  |   ✅   |   ✅   |
| `schoolsManagement`                  |   ✅   |  ✅  |   ✅   |   ✅   |
| `organizationsManagement`            |   ✅   |  ✅  |   ✅   |   ✅   |
| `academicSessionsManagement`         |   ✅   |  ✅  |   ✅   |   ✅   |
| `termsManagement`                    |   —    |  ✅  |   —    |   —    |
| `gradingPeriodsManagement`           |   ✅   |  ✅  |   ✅   |   ✅   |
| `demographicsManagement`             |   ✅   |  ✅  |   ✅   |   ✅   |
| `lineItemsManagement`                |   ✅   |  ✅  |   ✅   |   ✅   |
| `resultsManagement`                  |   ✅   |  ✅  |   ✅   |   ✅   |
| `categoriesManagement`               |   ✅   |  ✅  |   ✅   |   ✅   |
| `scoreScalesManagement`              |   ✅   |  ✅  |   ✅   |   ✅   |
| `resourcesManagement`                |   ✅   |  ✅  |   ✅   |   ✅   |
| `courseComponentsManagement`         |   ✅   |  ✅  |   ✅   |   ✅   |
| `courseComponentResourcesManagement` |   ✅   |  ✅  |   ✅   |   ✅   |
| `assessmentLineItemsManagement`      |   ✅   |  ✅  |   ✅   |   ✅   |
| `assessmentResultsManagement`        |   ✅   |  ✅  |   ✅   |   ✅   |

_Note: — indicates the module uses parent module operations (students/teachers map to usersManagement for create/update/delete)._

### Example Provider Matrix (LMS-Specific)

| Module                               | OneRoster (Full) | ClassLink |
| ------------------------------------ | :--------------: | :-------: |
| `usersManagement`                    |     ✅ CRUD      |  ✅ Read  |
| `studentsManagement`                 |     ✅ Read      |  ✅ Read  |
| `teachersManagement`                 |     ✅ Read      |  ✅ Read  |
| `classesManagement`                  |     ✅ CRUD      |  ✅ Read  |
| `coursesManagement`                  |     ✅ CRUD      |  ✅ Read  |
| `enrollmentsManagement`              |     ✅ CRUD      |  ✅ Read  |
| `schoolsManagement`                  |     ✅ CRUD      |  ✅ Read  |
| `organizationsManagement`            |     ✅ CRUD      |  ✅ Read  |
| `academicSessionsManagement`         |     ✅ CRUD      |  ✅ Read  |
| `termsManagement`                    |     ✅ Read      |  ✅ Read  |
| `gradingPeriodsManagement`           |     ✅ CRUD      |  ✅ Read  |
| `demographicsManagement`             |     ✅ CRUD      |    ❌     |
| `lineItemsManagement`                |     ✅ CRUD      |    ❌     |
| `resultsManagement`                  |     ✅ CRUD      |    ❌     |
| `categoriesManagement`               |     ✅ CRUD      |    ❌     |
| `scoreScalesManagement`              |     ✅ CRUD      |    ❌     |
| `resourcesManagement`                |     ✅ CRUD      |    ❌     |
| `courseComponentsManagement`         |     ✅ CRUD      |    ❌     |
| `courseComponentResourcesManagement` |     ✅ CRUD      |    ❌     |
| `assessmentLineItemsManagement`      |     ✅ CRUD      |    ❌     |
| `assessmentResultsManagement`        |     ✅ CRUD      |    ❌     |

> This matrix reflects typical provider behavior. Actual availability may vary by contract or configuration.

## Advanced Import Paths

Use these only when you need them.

### Runtime entrypoints

```text
@eduware/oneroster            # Full client + common exports (recommended)
@eduware/oneroster/clients    # LMS profiles (ClassLink, custom profiles)
@eduware/oneroster/core.js    # Lightweight core client for funcs
@eduware/oneroster/funcs/*    # Standalone functions
```

### Type-first entrypoints (prefer `import type` when you only need types)

```text
@eduware/oneroster/models     # Data models (component schemas)
@eduware/oneroster/enums      # Shared enums (runtime + types)
@eduware/oneroster/types      # Operation request/response types (runtime alias)
```

## MCP Server

This SDK includes an MCP (Model Context Protocol) server for AI applications.

### OAuth 2.0 Configuration

```json
{
    "mcpServers": {
        "OneRoster": {
            "command": "npx",
            "args": [
                "-y",
                "--package",
                "@eduware/oneroster",
                "--",
                "mcp",
                "start",
                "--server-url",
                "https://your-oneroster-server.com",
                "--client-id",
                "your-client-id",
                "--client-secret",
                "your-client-secret",
                "--token-url",
                "https://your-server.com/oauth/token"
            ]
        }
    }
}
```

### ClassLink Configuration (Bearer Token)

```json
{
    "mcpServers": {
        "OneRoster": {
            "command": "npx",
            "args": [
                "-y",
                "--package",
                "@eduware/oneroster",
                "--",
                "mcp",
                "start",
                "--server-url",
                "https://oneroster-proxy.apis.classlink.com/YOUR_TENANT_ID",
                "--auth-type",
                "bearer",
                "--bearer-token",
                "your-bearer-token",
                "--client-profile",
                "classlink"
            ]
        }
    }
}
```

### OAuth 1.0a Configuration (v1.1)

```json
{
    "mcpServers": {
        "OneRoster": {
            "command": "npx",
            "args": [
                "-y",
                "--package",
                "@eduware/oneroster",
                "--",
                "mcp",
                "start",
                "--server-url",
                "https://your-oneroster-server.com",
                "--auth-type",
                "oauth1",
                "--oneroster-version",
                "1.1",
                "--client-id",
                "your-client-id",
                "--client-secret",
                "your-client-secret"
            ]
        }
    }
}
```

### MCP Arguments

| Argument              | Description                                                   | Default   | Required          |
| --------------------- | ------------------------------------------------------------- | --------- | ----------------- |
| `--server-url`        | OneRoster API server URL                                      | —         | Yes               |
| `--auth-type`         | Authentication type: `oauth1`, `oauth2`, or `bearer`          | `oauth2`  | No                |
| `--client-id`         | OAuth client ID                                               | —         | For oauth1/oauth2 |
| `--client-secret`     | OAuth client secret                                           | —         | For oauth1/oauth2 |
| `--token-url`         | OAuth 2.0 token endpoint URL                                  | —         | For oauth2        |
| `--bearer-token`      | Pre-authenticated bearer token                                | —         | For bearer        |
| `--client-profile`    | Client profile: `full` (all tools) or `classlink` (read-only) | `full`    | No                |
| `--oneroster-version` | OneRoster API version: `1.1` or `1.2`                         | `1.2`     | No                |
| `--transport`         | Transport protocol: `stdio` or `sse`                          | `stdio`   | No                |
| `--port`              | Port for SSE transport                                        | `2718`    | No                |
| `--tool`              | Specific tools to mount (repeatable)                          | All tools | No                |
| `--log-level`         | Log level: `debug`, `info`, `warn`, `error`                   | `info`    | No                |
| `--env`               | Environment variables (format: `KEY=value`, repeatable)       | —         | No                |

## API Reference

See [FUNCTIONS.md](./FUNCTIONS.md) for the full method list.

## License

MIT
