offcourse 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/dist/cli/commands/config.js.map +1 -1
  2. package/dist/cli/commands/inspect.js +1 -1
  3. package/dist/cli/commands/inspect.js.map +1 -1
  4. package/dist/cli/commands/sync.d.ts +1 -2
  5. package/dist/cli/commands/sync.d.ts.map +1 -1
  6. package/dist/cli/commands/sync.js +13 -14
  7. package/dist/cli/commands/sync.js.map +1 -1
  8. package/dist/cli/commands/syncHighLevel.d.ts +1 -2
  9. package/dist/cli/commands/syncHighLevel.d.ts.map +1 -1
  10. package/dist/cli/commands/syncHighLevel.js +4 -8
  11. package/dist/cli/commands/syncHighLevel.js.map +1 -1
  12. package/dist/cli/index.js +1 -1
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/config/configManager.d.ts.map +1 -1
  15. package/dist/config/configManager.js +4 -0
  16. package/dist/config/configManager.js.map +1 -1
  17. package/dist/downloader/hlsDownloader.d.ts.map +1 -1
  18. package/dist/downloader/hlsDownloader.js +23 -14
  19. package/dist/downloader/hlsDownloader.js.map +1 -1
  20. package/dist/downloader/hlsValidator.d.ts.map +1 -1
  21. package/dist/downloader/hlsValidator.js +6 -2
  22. package/dist/downloader/hlsValidator.js.map +1 -1
  23. package/dist/downloader/index.d.ts +3 -0
  24. package/dist/downloader/index.d.ts.map +1 -1
  25. package/dist/downloader/index.js +3 -0
  26. package/dist/downloader/index.js.map +1 -1
  27. package/dist/downloader/loomDownloader.d.ts.map +1 -1
  28. package/dist/downloader/loomDownloader.js +23 -20
  29. package/dist/downloader/loomDownloader.js.map +1 -1
  30. package/dist/downloader/queue.d.ts +4 -4
  31. package/dist/downloader/queue.d.ts.map +1 -1
  32. package/dist/downloader/queue.js.map +1 -1
  33. package/dist/downloader/vimeoDownloader.d.ts.map +1 -1
  34. package/dist/downloader/vimeoDownloader.js +7 -3
  35. package/dist/downloader/vimeoDownloader.js.map +1 -1
  36. package/dist/scraper/extractor.d.ts +4 -0
  37. package/dist/scraper/extractor.d.ts.map +1 -1
  38. package/dist/scraper/extractor.js +79 -79
  39. package/dist/scraper/extractor.js.map +1 -1
  40. package/dist/scraper/highlevel/extractor.d.ts +11 -19
  41. package/dist/scraper/highlevel/extractor.d.ts.map +1 -1
  42. package/dist/scraper/highlevel/extractor.js +72 -85
  43. package/dist/scraper/highlevel/extractor.js.map +1 -1
  44. package/dist/scraper/highlevel/navigator.d.ts +3 -10
  45. package/dist/scraper/highlevel/navigator.d.ts.map +1 -1
  46. package/dist/scraper/highlevel/navigator.js +140 -127
  47. package/dist/scraper/highlevel/navigator.js.map +1 -1
  48. package/dist/scraper/highlevel/schemas.d.ts +188 -0
  49. package/dist/scraper/highlevel/schemas.d.ts.map +1 -0
  50. package/dist/scraper/highlevel/schemas.js +139 -0
  51. package/dist/scraper/highlevel/schemas.js.map +1 -0
  52. package/dist/scraper/navigator.d.ts +14 -11
  53. package/dist/scraper/navigator.d.ts.map +1 -1
  54. package/dist/scraper/navigator.js +61 -104
  55. package/dist/scraper/navigator.js.map +1 -1
  56. package/dist/scraper/schemas.d.ts +57 -0
  57. package/dist/scraper/schemas.d.ts.map +1 -0
  58. package/dist/scraper/schemas.js +135 -0
  59. package/dist/scraper/schemas.js.map +1 -0
  60. package/dist/scraper/videoInterceptor.d.ts +4 -0
  61. package/dist/scraper/videoInterceptor.d.ts.map +1 -1
  62. package/dist/scraper/videoInterceptor.js +66 -51
  63. package/dist/scraper/videoInterceptor.js.map +1 -1
  64. package/dist/shared/auth.d.ts +9 -9
  65. package/dist/shared/auth.d.ts.map +1 -1
  66. package/dist/shared/auth.js +24 -38
  67. package/dist/shared/auth.js.map +1 -1
  68. package/dist/shared/firebase.d.ts +60 -0
  69. package/dist/shared/firebase.d.ts.map +1 -0
  70. package/dist/shared/firebase.js +102 -0
  71. package/dist/shared/firebase.js.map +1 -0
  72. package/dist/shared/fs.d.ts.map +1 -1
  73. package/dist/shared/fs.js +4 -0
  74. package/dist/shared/fs.js.map +1 -1
  75. package/dist/shared/index.d.ts +3 -0
  76. package/dist/shared/index.d.ts.map +1 -1
  77. package/dist/shared/index.js +3 -0
  78. package/dist/shared/index.js.map +1 -1
  79. package/dist/shared/slug.d.ts +11 -0
  80. package/dist/shared/slug.d.ts.map +1 -0
  81. package/{src/shared/slug.ts → dist/shared/slug.js} +10 -11
  82. package/dist/shared/slug.js.map +1 -0
  83. package/dist/shared/url.d.ts +43 -0
  84. package/dist/shared/url.d.ts.map +1 -0
  85. package/{src/shared/url.ts → dist/shared/url.js} +12 -15
  86. package/dist/shared/url.js.map +1 -0
  87. package/dist/state/database.d.ts +1 -0
  88. package/dist/state/database.d.ts.map +1 -1
  89. package/dist/state/database.js +3 -0
  90. package/dist/state/database.js.map +1 -1
  91. package/dist/storage/fileSystem.d.ts +17 -17
  92. package/dist/storage/fileSystem.d.ts.map +1 -1
  93. package/dist/storage/fileSystem.js +39 -31
  94. package/dist/storage/fileSystem.js.map +1 -1
  95. package/package.json +5 -2
  96. package/.github/workflows/ci.yml +0 -50
  97. package/.husky/commit-msg +0 -2
  98. package/.husky/pre-commit +0 -1
  99. package/.husky/pre-push +0 -3
  100. package/.prettierrc +0 -8
  101. package/.release-it.json +0 -23
  102. package/ARCHITECTURE.md +0 -233
  103. package/CHANGELOG.md +0 -78
  104. package/commitlint.config.js +0 -4
  105. package/dist/ai/openRouter.d.ts +0 -47
  106. package/dist/ai/openRouter.d.ts.map +0 -1
  107. package/dist/ai/openRouter.js +0 -116
  108. package/dist/ai/openRouter.js.map +0 -1
  109. package/dist/ai/transcriptPolisher.d.ts +0 -24
  110. package/dist/ai/transcriptPolisher.d.ts.map +0 -1
  111. package/dist/ai/transcriptPolisher.js +0 -89
  112. package/dist/ai/transcriptPolisher.js.map +0 -1
  113. package/dist/cli/commands/enrich.d.ts +0 -14
  114. package/dist/cli/commands/enrich.d.ts.map +0 -1
  115. package/dist/cli/commands/enrich.js +0 -271
  116. package/dist/cli/commands/enrich.js.map +0 -1
  117. package/dist/cli/commands/syncGhl.d.ts +0 -20
  118. package/dist/cli/commands/syncGhl.d.ts.map +0 -1
  119. package/dist/cli/commands/syncGhl.js +0 -483
  120. package/dist/cli/commands/syncGhl.js.map +0 -1
  121. package/dist/cli/commands/syncHighLevel.test.d.ts +0 -2
  122. package/dist/cli/commands/syncHighLevel.test.d.ts.map +0 -1
  123. package/dist/cli/commands/syncHighLevel.test.js +0 -102
  124. package/dist/cli/commands/syncHighLevel.test.js.map +0 -1
  125. package/dist/config/paths.test.d.ts +0 -2
  126. package/dist/config/paths.test.d.ts.map +0 -1
  127. package/dist/config/paths.test.js +0 -70
  128. package/dist/config/paths.test.js.map +0 -1
  129. package/dist/config/schema.test.d.ts +0 -2
  130. package/dist/config/schema.test.d.ts.map +0 -1
  131. package/dist/config/schema.test.js +0 -151
  132. package/dist/config/schema.test.js.map +0 -1
  133. package/dist/downloader/hlsDownloader.test.d.ts +0 -2
  134. package/dist/downloader/hlsDownloader.test.d.ts.map +0 -1
  135. package/dist/downloader/hlsDownloader.test.js +0 -116
  136. package/dist/downloader/hlsDownloader.test.js.map +0 -1
  137. package/dist/downloader/loomDownloader.test.d.ts +0 -2
  138. package/dist/downloader/loomDownloader.test.d.ts.map +0 -1
  139. package/dist/downloader/loomDownloader.test.js +0 -36
  140. package/dist/downloader/loomDownloader.test.js.map +0 -1
  141. package/dist/downloader/queue.test.d.ts +0 -2
  142. package/dist/downloader/queue.test.d.ts.map +0 -1
  143. package/dist/downloader/queue.test.js +0 -158
  144. package/dist/downloader/queue.test.js.map +0 -1
  145. package/dist/downloader/videoDownloader.d.ts +0 -32
  146. package/dist/downloader/videoDownloader.d.ts.map +0 -1
  147. package/dist/downloader/videoDownloader.js +0 -173
  148. package/dist/downloader/videoDownloader.js.map +0 -1
  149. package/dist/downloader/vimeoDownloader.test.d.ts +0 -2
  150. package/dist/downloader/vimeoDownloader.test.d.ts.map +0 -1
  151. package/dist/downloader/vimeoDownloader.test.js +0 -51
  152. package/dist/downloader/vimeoDownloader.test.js.map +0 -1
  153. package/dist/scraper/auth.d.ts +0 -29
  154. package/dist/scraper/auth.d.ts.map +0 -1
  155. package/dist/scraper/auth.js +0 -115
  156. package/dist/scraper/auth.js.map +0 -1
  157. package/dist/scraper/extractor.test.d.ts +0 -2
  158. package/dist/scraper/extractor.test.d.ts.map +0 -1
  159. package/dist/scraper/extractor.test.js +0 -65
  160. package/dist/scraper/extractor.test.js.map +0 -1
  161. package/dist/scraper/ghl/auth.d.ts +0 -25
  162. package/dist/scraper/ghl/auth.d.ts.map +0 -1
  163. package/dist/scraper/ghl/auth.js +0 -187
  164. package/dist/scraper/ghl/auth.js.map +0 -1
  165. package/dist/scraper/ghl/extractor.d.ts +0 -96
  166. package/dist/scraper/ghl/extractor.d.ts.map +0 -1
  167. package/dist/scraper/ghl/extractor.js +0 -345
  168. package/dist/scraper/ghl/extractor.js.map +0 -1
  169. package/dist/scraper/ghl/index.d.ts +0 -4
  170. package/dist/scraper/ghl/index.d.ts.map +0 -1
  171. package/dist/scraper/ghl/index.js +0 -4
  172. package/dist/scraper/ghl/index.js.map +0 -1
  173. package/dist/scraper/ghl/navigator.d.ts +0 -93
  174. package/dist/scraper/ghl/navigator.d.ts.map +0 -1
  175. package/dist/scraper/ghl/navigator.js +0 -447
  176. package/dist/scraper/ghl/navigator.js.map +0 -1
  177. package/dist/scraper/highlevel/auth.d.ts +0 -25
  178. package/dist/scraper/highlevel/auth.d.ts.map +0 -1
  179. package/dist/scraper/highlevel/auth.js +0 -189
  180. package/dist/scraper/highlevel/auth.js.map +0 -1
  181. package/dist/scraper/highlevel/extractor.test.d.ts +0 -2
  182. package/dist/scraper/highlevel/extractor.test.d.ts.map +0 -1
  183. package/dist/scraper/highlevel/extractor.test.js +0 -101
  184. package/dist/scraper/highlevel/extractor.test.js.map +0 -1
  185. package/dist/scraper/highlevel/navigator.test.d.ts +0 -2
  186. package/dist/scraper/highlevel/navigator.test.d.ts.map +0 -1
  187. package/dist/scraper/highlevel/navigator.test.js +0 -78
  188. package/dist/scraper/highlevel/navigator.test.js.map +0 -1
  189. package/dist/scraper/navigator.test.d.ts +0 -2
  190. package/dist/scraper/navigator.test.d.ts.map +0 -1
  191. package/dist/scraper/navigator.test.js +0 -63
  192. package/dist/scraper/navigator.test.js.map +0 -1
  193. package/dist/scraper/skoolApi.d.ts +0 -17
  194. package/dist/scraper/skoolApi.d.ts.map +0 -1
  195. package/dist/scraper/skoolApi.js +0 -72
  196. package/dist/scraper/skoolApi.js.map +0 -1
  197. package/dist/state/database.test.d.ts +0 -2
  198. package/dist/state/database.test.d.ts.map +0 -1
  199. package/dist/state/database.test.js +0 -34
  200. package/dist/state/database.test.js.map +0 -1
  201. package/dist/transcription/whisperService.d.ts +0 -27
  202. package/dist/transcription/whisperService.d.ts.map +0 -1
  203. package/dist/transcription/whisperService.js +0 -102
  204. package/dist/transcription/whisperService.js.map +0 -1
  205. package/eslint.config.js +0 -55
  206. package/src/__fixtures__/highlevel-post-response.json +0 -68
  207. package/src/__fixtures__/hls-master-playlist.m3u8 +0 -24
  208. package/src/cli/commands/__snapshots__/syncHighLevel.test.ts.snap +0 -38
  209. package/src/cli/commands/config.ts +0 -74
  210. package/src/cli/commands/inspect.ts +0 -441
  211. package/src/cli/commands/login.ts +0 -68
  212. package/src/cli/commands/status.ts +0 -147
  213. package/src/cli/commands/sync.ts +0 -1235
  214. package/src/cli/commands/syncHighLevel.test.ts +0 -144
  215. package/src/cli/commands/syncHighLevel.ts +0 -639
  216. package/src/cli/index.ts +0 -121
  217. package/src/config/configManager.ts +0 -75
  218. package/src/config/paths.test.ts +0 -83
  219. package/src/config/paths.ts +0 -36
  220. package/src/config/schema.test.ts +0 -173
  221. package/src/config/schema.ts +0 -65
  222. package/src/downloader/hlsDownloader.test.ts +0 -148
  223. package/src/downloader/hlsDownloader.ts +0 -327
  224. package/src/downloader/hlsValidator.ts +0 -196
  225. package/src/downloader/index.ts +0 -122
  226. package/src/downloader/loomDownloader.test.ts +0 -43
  227. package/src/downloader/loomDownloader.ts +0 -742
  228. package/src/downloader/queue.test.ts +0 -199
  229. package/src/downloader/queue.ts +0 -118
  230. package/src/downloader/vimeoDownloader.test.ts +0 -62
  231. package/src/downloader/vimeoDownloader.ts +0 -722
  232. package/src/scraper/extractor.test.ts +0 -124
  233. package/src/scraper/extractor.ts +0 -757
  234. package/src/scraper/highlevel/__snapshots__/extractor.test.ts.snap +0 -41
  235. package/src/scraper/highlevel/extractor.test.ts +0 -134
  236. package/src/scraper/highlevel/extractor.ts +0 -537
  237. package/src/scraper/highlevel/index.ts +0 -2
  238. package/src/scraper/highlevel/navigator.test.ts +0 -110
  239. package/src/scraper/highlevel/navigator.ts +0 -668
  240. package/src/scraper/highlevel/schemas.ts +0 -183
  241. package/src/scraper/navigator.test.ts +0 -122
  242. package/src/scraper/navigator.ts +0 -355
  243. package/src/scraper/schemas.ts +0 -177
  244. package/src/scraper/videoInterceptor.ts +0 -435
  245. package/src/shared/auth.test.ts +0 -58
  246. package/src/shared/auth.ts +0 -251
  247. package/src/shared/firebase.ts +0 -151
  248. package/src/shared/fs.ts +0 -80
  249. package/src/shared/http.ts +0 -34
  250. package/src/shared/index.ts +0 -6
  251. package/src/shared/url.test.ts +0 -122
  252. package/src/state/database.test.ts +0 -49
  253. package/src/state/database.ts +0 -919
  254. package/src/state/index.ts +0 -14
  255. package/src/storage/fileSystem.test.ts +0 -64
  256. package/src/storage/fileSystem.ts +0 -175
  257. package/tsconfig.json +0 -28
  258. package/vitest.config.ts +0 -29
@@ -1,14 +0,0 @@
1
- export {
2
- CourseDatabase,
3
- LessonStatus,
4
- VideoType,
5
- extractCommunitySlug,
6
- getDbDir,
7
- getDbPath,
8
- type CourseMetadata,
9
- type LessonRecord,
10
- type LessonStatusType,
11
- type LessonWithModule,
12
- type ModuleRecord,
13
- type VideoTypeValue,
14
- } from "./database.js";
@@ -1,64 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import {
3
- getLessonBasename,
4
- getVideoPath,
5
- getMarkdownPath,
6
- getDownloadFilePath,
7
- } from "./fileSystem.js";
8
-
9
- describe("fileSystem", () => {
10
- describe("getLessonBasename", () => {
11
- it("creates numbered filename from lesson name", () => {
12
- expect(getLessonBasename(0, "Introduction")).toBe("01-introduction");
13
- expect(getLessonBasename(9, "Final Lesson")).toBe("10-final-lesson");
14
- expect(getLessonBasename(99, "Bonus")).toBe("100-bonus");
15
- });
16
-
17
- it("handles special characters", () => {
18
- expect(getLessonBasename(0, "What's Next?")).toBe("01-whats-next");
19
- expect(getLessonBasename(0, "Module 1: Basics")).toBe("01-module-1-basics");
20
- });
21
- });
22
-
23
- describe("getVideoPath", () => {
24
- it("creates video path with .mp4 extension", () => {
25
- const path = getVideoPath("/courses/my-course/01-intro", 0, "Welcome");
26
- expect(path).toBe("/courses/my-course/01-intro/01-welcome.mp4");
27
- });
28
-
29
- it("handles nested paths", () => {
30
- const path = getVideoPath("/home/user/Downloads/courses/test", 5, "Lesson Six");
31
- expect(path).toBe("/home/user/Downloads/courses/test/06-lesson-six.mp4");
32
- });
33
- });
34
-
35
- describe("getMarkdownPath", () => {
36
- it("creates markdown path with .md extension", () => {
37
- const path = getMarkdownPath("/courses/my-course/01-intro", 0, "Welcome");
38
- expect(path).toBe("/courses/my-course/01-intro/01-welcome.md");
39
- });
40
- });
41
-
42
- describe("getDownloadFilePath", () => {
43
- it("prefixes filename with lesson basename", () => {
44
- const path = getDownloadFilePath("/module", 2, "Resources", "workbook.pdf");
45
- expect(path).toBe("/module/03-resources-workbook.pdf");
46
- });
47
-
48
- it("sanitizes dangerous filename characters", () => {
49
- // Characters that are invalid in filenames on various OS
50
- const path = getDownloadFilePath("/module", 0, "Intro", 'file<>:"/\\|?*.pdf');
51
- expect(path).toBe("/module/01-intro-file_________.pdf");
52
- });
53
-
54
- it("preserves safe special characters", () => {
55
- const path = getDownloadFilePath("/module", 0, "Intro", "my-file_v2 (1).pdf");
56
- expect(path).toBe("/module/01-intro-my-file_v2 (1).pdf");
57
- });
58
-
59
- it("handles filenames with multiple extensions", () => {
60
- const path = getDownloadFilePath("/module", 0, "Intro", "archive.tar.gz");
61
- expect(path).toBe("/module/01-intro-archive.tar.gz");
62
- });
63
- });
64
- });
@@ -1,175 +0,0 @@
1
- import { createWriteStream } from "node:fs";
2
- import { join } from "node:path";
3
- import { Readable } from "node:stream";
4
- import { pipeline } from "node:stream/promises";
5
- import { expandPath, getSyncStatePath } from "../config/paths.js";
6
- import type { CourseSyncState } from "../config/schema.js";
7
- import { courseSyncStateSchema } from "../config/schema.js";
8
- import { createFolderName } from "../scraper/navigator.js";
9
- import { ensureDir, outputFile, pathExists, readJson, outputJson } from "../shared/fs.js";
10
- import { http } from "../shared/http.js";
11
-
12
- // ============================================
13
- // Pure functions - testable without mocking
14
- // ============================================
15
-
16
- /**
17
- * Gets the base filename for a lesson (without extension).
18
- * Format: "01-lesson-name"
19
- */
20
- export function getLessonBasename(lessonIndex: number, lessonName: string): string {
21
- return createFolderName(lessonIndex, lessonName);
22
- }
23
-
24
- /**
25
- * Gets the video file path for a lesson.
26
- * Videos are stored directly in the module directory with lesson name.
27
- */
28
- export function getVideoPath(moduleDir: string, lessonIndex: number, lessonName: string): string {
29
- return join(moduleDir, `${getLessonBasename(lessonIndex, lessonName)}.mp4`);
30
- }
31
-
32
- /**
33
- * Gets the markdown file path for a lesson.
34
- * Markdown files are stored directly in the module directory with lesson name.
35
- */
36
- export function getMarkdownPath(
37
- moduleDir: string,
38
- lessonIndex: number,
39
- lessonName: string
40
- ): string {
41
- return join(moduleDir, `${getLessonBasename(lessonIndex, lessonName)}.md`);
42
- }
43
-
44
- /**
45
- * Gets the path for a downloadable file.
46
- * Files are stored in the module directory with lesson prefix.
47
- */
48
- export function getDownloadFilePath(
49
- moduleDir: string,
50
- lessonIndex: number,
51
- lessonName: string,
52
- filename: string
53
- ): string {
54
- const lessonPrefix = getLessonBasename(lessonIndex, lessonName);
55
- // Sanitize filename
56
- const safeFilename = filename.replace(/[<>:"/\\|?*]/g, "_");
57
- return join(moduleDir, `${lessonPrefix}-${safeFilename}`);
58
- }
59
-
60
- // ============================================
61
- // I/O functions - require filesystem access
62
- // ============================================
63
- /* v8 ignore start */
64
-
65
- /**
66
- * Creates the output directory structure for a course.
67
- */
68
- export async function createCourseDirectory(
69
- outputBase: string,
70
- courseName: string
71
- ): Promise<string> {
72
- const expanded = expandPath(outputBase);
73
- const courseDir = join(expanded, createFolderName(0, courseName).replace(/^\d+-/, ""));
74
- await ensureDir(courseDir);
75
- return courseDir;
76
- }
77
-
78
- /**
79
- * Creates a module directory within a course.
80
- */
81
- export async function createModuleDirectory(
82
- courseDir: string,
83
- moduleIndex: number,
84
- moduleName: string
85
- ): Promise<string> {
86
- const moduleDir = join(courseDir, createFolderName(moduleIndex, moduleName));
87
- await ensureDir(moduleDir);
88
- return moduleDir;
89
- }
90
-
91
- /**
92
- * Saves markdown content to a file.
93
- */
94
- export async function saveMarkdown(
95
- directory: string,
96
- filename: string,
97
- content: string
98
- ): Promise<string> {
99
- const filePath = join(directory, filename);
100
- await outputFile(filePath, content);
101
- return filePath;
102
- }
103
-
104
- /**
105
- * Loads the sync state for a course.
106
- */
107
- export async function loadSyncState(courseSlug: string): Promise<CourseSyncState | null> {
108
- const statePath = getSyncStatePath(courseSlug);
109
- const data = await readJson(statePath);
110
-
111
- if (!data) {
112
- return null;
113
- }
114
-
115
- try {
116
- return courseSyncStateSchema.parse(data);
117
- } catch {
118
- return null;
119
- }
120
- }
121
-
122
- /**
123
- * Saves the sync state for a course.
124
- */
125
- export async function saveSyncState(courseSlug: string, state: CourseSyncState): Promise<void> {
126
- const statePath = getSyncStatePath(courseSlug);
127
- await outputJson(statePath, state);
128
- }
129
-
130
- /**
131
- * Checks if a lesson has been fully synced.
132
- */
133
- export async function isLessonSynced(
134
- moduleDir: string,
135
- lessonIndex: number,
136
- lessonName: string
137
- ): Promise<{ video: boolean; content: boolean }> {
138
- const [video, content] = await Promise.all([
139
- pathExists(getVideoPath(moduleDir, lessonIndex, lessonName)),
140
- pathExists(getMarkdownPath(moduleDir, lessonIndex, lessonName)),
141
- ]);
142
- return { video, content };
143
- }
144
-
145
- /**
146
- * Downloads a file from a URL to the specified path.
147
- */
148
- export async function downloadFile(
149
- url: string,
150
- outputPath: string
151
- ): Promise<{ success: boolean; error?: string }> {
152
- if (await pathExists(outputPath)) {
153
- return { success: true }; // Already downloaded
154
- }
155
-
156
- await ensureDir(join(outputPath, ".."));
157
-
158
- try {
159
- const response = await http.get(url);
160
- const body = response.body;
161
-
162
- if (!body) {
163
- return { success: false, error: "No response body" };
164
- }
165
-
166
- const fileStream = createWriteStream(outputPath);
167
- await pipeline(Readable.fromWeb(body as import("stream/web").ReadableStream), fileStream);
168
-
169
- return { success: true };
170
- } catch (error) {
171
- return { success: false, error: String(error) };
172
- }
173
- }
174
-
175
- /* v8 ignore stop */
package/tsconfig.json DELETED
@@ -1,28 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2024",
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
6
- "lib": ["ES2024", "DOM"],
7
- "outDir": "./dist",
8
- "rootDir": "./src",
9
- "strict": true,
10
- "esModuleInterop": true,
11
- "skipLibCheck": true,
12
- "forceConsistentCasingInFileNames": true,
13
- "declaration": true,
14
- "declarationMap": true,
15
- "sourceMap": true,
16
- "resolveJsonModule": true,
17
- "noUncheckedIndexedAccess": true,
18
- "noImplicitReturns": true,
19
- "noFallthroughCasesInSwitch": true,
20
- "noUnusedLocals": true,
21
- "noUnusedParameters": true,
22
- "exactOptionalPropertyTypes": true,
23
- "isolatedModules": true
24
- },
25
- "include": ["src/**/*"],
26
- "exclude": ["node_modules", "dist"]
27
- }
28
-
package/vitest.config.ts DELETED
@@ -1,29 +0,0 @@
1
- import { defineConfig } from "vitest/config";
2
-
3
- export default defineConfig({
4
- test: {
5
- globals: true,
6
- environment: "node",
7
- include: ["src/**/*.test.ts"],
8
- coverage: {
9
- provider: "v8",
10
- reporter: ["text", "html", "lcov"],
11
- include: ["src/**/*.ts"],
12
- exclude: [
13
- // Test files
14
- "src/**/*.test.ts",
15
- // CLI commands (interactive, hard to test)
16
- "src/cli/**",
17
- // Re-export index files
18
- "src/**/index.ts",
19
- // Pure I/O wrappers (testing would just test Node.js/packages)
20
- "src/shared/fs.ts",
21
- "src/config/configManager.ts",
22
- // Browser automation (requires Playwright, not unit testable)
23
- "src/scraper/videoInterceptor.ts",
24
- // Network validation (requires live connections)
25
- "src/downloader/hlsValidator.ts",
26
- ],
27
- },
28
- },
29
- });