feat: HLS streaming, transcripts, agent course generation & landing-page course previews (#663)

New features:
- HLS video encoding/streaming (hls routes, hls-encoder) and a media
  transcripts pipeline (transcripts route + media-transcript queries)
- AI assistant chat vs. run model: agent-course-generation worker/queue,
  run-monitor pane, chat-changes card, content ask-ai bar
- Per-theme course-page previews across org landing-page themes (bold,
  classic, corporate, editorial, etc.) with a shared course token/component set
- View-as-student mode and login-link / link-invite invite flows

Refactor:
- Extract packages/core consolidating config (env, storage, dashboard-url),
  services and utils previously duplicated under apps/api/src/config
- Remove legacy agent service modules (chat-tools, chat-context,
  context-window, document, fetch-url, lesson-content)
- Relax Cross-Origin-Resource-Policy to allow cross-origin media embedding
- Add format script to tenant-router so turbo run format covers it
This commit is contained in:
Rotimi Best
2026-06-07 18:43:05 +01:00
committed by GitHub
parent a2e70779a0
commit d5b07d356e
496 changed files with 19050 additions and 8312 deletions
@@ -0,0 +1,52 @@
import type { CoursePricing, CourseLandingPageProps, CourseLandingPageLabels } from './types';
export function alignHeroCtaWithPricing(
hero: CourseLandingPageProps['hero'],
pricing: CoursePricing
): CourseLandingPageProps['hero'] {
return {
...hero,
primaryAction: {
label: pricing.ctaLabel,
href: pricing.ctaHref ?? '#pricing',
disabled: hero.primaryAction.disabled
}
};
}
export interface SectionNavItem {
id: string;
label: string;
}
export function buildCourseSectionNavItems(
props: Pick<CourseLandingPageProps, 'info' | 'curriculum' | 'chips' | 'instructor' | 'reviews'>,
labels?: CourseLandingPageLabels
): SectionNavItem[] {
const items: SectionNavItem[] = [];
const { info, curriculum, chips, reviews } = props;
const hasInfo = Boolean(info.requirements || info.description || info.goals || info.certificateUrl);
if (hasInfo) {
items.push({ id: 'course-info', label: labels?.navAboutLabel ?? 'About' });
}
if (curriculum.sections.length > 0) {
items.push({ id: 'curriculum', label: labels?.navCurriculumLabel ?? 'Modules' });
}
const hasChips = Boolean((chips?.skills?.length ?? 0) > 0 || (chips?.tools?.length ?? 0) > 0);
if (hasChips) {
items.push({ id: 'course-chips', label: labels?.navSkillsLabel ?? 'Skills' });
}
items.push({ id: 'instructor', label: labels?.navInstructorLabel ?? 'Instructor' });
if (reviews.items.length > 0) {
items.push({ id: 'reviews', label: labels?.navReviewsLabel ?? 'Reviews' });
}
items.push({ id: 'pricing', label: labels?.navPricingLabel ?? 'Pricing' });
return items;
}