CourseKitStarPlan
StarPlan Package
Framework-agnostic StarPlan ingestion — iCal parsing, RRULE normalization, content-hash change detection, room/instructor extraction, and study-block alignment
@hfu.digital/coursekit-starplan is the third package in CourseKit. It's framework-agnostic (no NestJS, no React, no Prisma) and contains the building blocks for ingesting an institution's StarPlan timetable feed and producing data that the backend (@hfu.digital/coursekit-nestjs) can store and materialize.
NestJS consumers typically wrap this package inside a service that orchestrates:
- Fetch programs/semesters via
StarPlanClient(or your own HTTP layer) - Fetch each semester's iCal feed
- Parse it with
parseIcal - Normalize each event's
rrulewithnormalizeRrule - Extract structured
room/instructormetadata with the extractors - Compute a stable
contentHashto detect changes across syncs - Diff against the previous snapshot with
detectChanges - Persist the result via your CourseKit Prisma adapter
Install
bun add @hfu.digital/coursekit-starplan@2026.04.1This package has one runtime dependency: rrule (used inside normalizeRrule). It works in Node.js and modern browsers.
Public surface
| Module | Exports |
|---|---|
client | StarPlanClient, StarPlanClientOptions, StarPlanProgram, StarPlanSemester |
parser | parseIcal, ParsedVEvent, ParseIcalOptions, groupBySchedule, groupBySummary |
recurrence | normalizeRrule, isValidRrule, NormalizedRecurrence |
extractors | extractRoom, ExtractedRoom, RoomExtractorConfig, extractInstructor, InstructorExtractorConfig |
identity | generateContentHash, hashIcalFeed |
study-blocks | HFU_STUDY_BLOCKS, HFU_STUDY_BLOCK_CONFIG, StudyBlock, StudyBlockConfig, getStudyBlockFromTime, getStudyBlockTimeRange |
changes | detectChanges, ChangeAction, ChangeRecord, DetectChangesOptions |
Quick example
import {
StarPlanClient,
parseIcal,
normalizeRrule,
extractRoom,
extractInstructor,
generateContentHash,
hashIcalFeed,
detectChanges,
} from '@hfu.digital/coursekit-starplan';
const client = new StarPlanClient({
baseUrl: 'https://splan.hs-furtwangen.de',
planningUnit: '5',
});
const semesters = await client.fetchSemesters('SOME_PROGRAM_ID');
const ical = await client.fetchIcal(semesters[0].id);
if (hashIcalFeed(ical) === lastSeenIcalHash) return; // no change
const events = parseIcal(ical).map((ev) => ({
id: generateContentHash({
semesterId: semesters[0].id,
summary: ev.summary,
weekday: ev.weekday,
studyBlock: ev.studyBlock,
startTime: ev.dtstart,
}),
title: ev.summary,
startTime: ev.dtstart,
rrule: ev.rrule ? (normalizeRrule(ev.rrule)?.normalized ?? null) : null,
room: extractRoom(ev.location),
instructor: extractInstructor(ev.description),
}));
const diff = detectChanges('starplan-event', previousSnapshot, events);When to use this package
- You sync from HFU StarPlan (or any iCal-based timetable feed) into a CourseKit-backed schedule.
- You want change detection that survives the upstream changing iCal
UIDvalues. - You want HFU's six-block daily grid out of the box, or you need a configurable equivalent for another institution.