offcourse 0.0.2 → 1.0.0

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 (284) hide show
  1. package/.github/workflows/ci.yml +50 -0
  2. package/.husky/commit-msg +2 -0
  3. package/.husky/pre-commit +1 -0
  4. package/.husky/pre-push +3 -0
  5. package/.prettierrc +8 -0
  6. package/.release-it.json +23 -0
  7. package/ARCHITECTURE.md +233 -0
  8. package/CHANGELOG.md +78 -0
  9. package/README.md +255 -20
  10. package/commitlint.config.js +4 -0
  11. package/dist/ai/openRouter.d.ts +47 -0
  12. package/dist/ai/openRouter.d.ts.map +1 -0
  13. package/dist/ai/openRouter.js +116 -0
  14. package/dist/ai/openRouter.js.map +1 -0
  15. package/dist/ai/transcriptPolisher.d.ts +24 -0
  16. package/dist/ai/transcriptPolisher.d.ts.map +1 -0
  17. package/dist/ai/transcriptPolisher.js +89 -0
  18. package/dist/ai/transcriptPolisher.js.map +1 -0
  19. package/dist/cli/commands/config.d.ts +13 -0
  20. package/dist/cli/commands/config.d.ts.map +1 -0
  21. package/dist/cli/commands/config.js +66 -0
  22. package/dist/cli/commands/config.js.map +1 -0
  23. package/dist/cli/commands/enrich.d.ts +14 -0
  24. package/dist/cli/commands/enrich.d.ts.map +1 -0
  25. package/dist/cli/commands/enrich.js +271 -0
  26. package/dist/cli/commands/enrich.js.map +1 -0
  27. package/dist/cli/commands/inspect.d.ts +11 -0
  28. package/dist/cli/commands/inspect.d.ts.map +1 -0
  29. package/dist/cli/commands/inspect.js +365 -0
  30. package/dist/cli/commands/inspect.js.map +1 -0
  31. package/dist/cli/commands/login.d.ts +12 -0
  32. package/dist/cli/commands/login.d.ts.map +1 -0
  33. package/dist/cli/commands/login.js +55 -0
  34. package/dist/cli/commands/login.js.map +1 -0
  35. package/dist/cli/commands/status.d.ts +15 -0
  36. package/dist/cli/commands/status.d.ts.map +1 -0
  37. package/dist/cli/commands/status.js +118 -0
  38. package/dist/cli/commands/status.js.map +1 -0
  39. package/dist/cli/commands/sync.d.ts +16 -0
  40. package/dist/cli/commands/sync.d.ts.map +1 -0
  41. package/dist/cli/commands/sync.js +922 -0
  42. package/dist/cli/commands/sync.js.map +1 -0
  43. package/dist/cli/commands/syncGhl.d.ts +20 -0
  44. package/dist/cli/commands/syncGhl.d.ts.map +1 -0
  45. package/dist/cli/commands/syncGhl.js +483 -0
  46. package/dist/cli/commands/syncGhl.js.map +1 -0
  47. package/dist/cli/commands/syncHighLevel.d.ts +24 -0
  48. package/dist/cli/commands/syncHighLevel.d.ts.map +1 -0
  49. package/dist/cli/commands/syncHighLevel.js +483 -0
  50. package/dist/cli/commands/syncHighLevel.js.map +1 -0
  51. package/dist/cli/commands/syncHighLevel.test.d.ts +2 -0
  52. package/dist/cli/commands/syncHighLevel.test.d.ts.map +1 -0
  53. package/dist/cli/commands/syncHighLevel.test.js +102 -0
  54. package/dist/cli/commands/syncHighLevel.test.js.map +1 -0
  55. package/dist/cli/index.d.ts +3 -0
  56. package/dist/cli/index.d.ts.map +1 -0
  57. package/dist/cli/index.js +106 -0
  58. package/dist/cli/index.js.map +1 -0
  59. package/dist/config/configManager.d.ts +31 -0
  60. package/dist/config/configManager.d.ts.map +1 -0
  61. package/dist/config/configManager.js +64 -0
  62. package/dist/config/configManager.js.map +1 -0
  63. package/dist/config/paths.d.ts +21 -0
  64. package/dist/config/paths.d.ts.map +1 -0
  65. package/dist/config/paths.js +33 -0
  66. package/dist/config/paths.js.map +1 -0
  67. package/dist/config/paths.test.d.ts +2 -0
  68. package/dist/config/paths.test.d.ts.map +1 -0
  69. package/dist/config/paths.test.js +70 -0
  70. package/dist/config/paths.test.js.map +1 -0
  71. package/dist/config/schema.d.ts +60 -0
  72. package/dist/config/schema.d.ts.map +1 -0
  73. package/dist/config/schema.js +50 -0
  74. package/dist/config/schema.js.map +1 -0
  75. package/dist/config/schema.test.d.ts +2 -0
  76. package/dist/config/schema.test.d.ts.map +1 -0
  77. package/dist/config/schema.test.js +151 -0
  78. package/dist/config/schema.test.js.map +1 -0
  79. package/dist/downloader/hlsDownloader.d.ts +58 -0
  80. package/dist/downloader/hlsDownloader.d.ts.map +1 -0
  81. package/dist/downloader/hlsDownloader.js +254 -0
  82. package/dist/downloader/hlsDownloader.js.map +1 -0
  83. package/dist/downloader/hlsDownloader.test.d.ts +2 -0
  84. package/dist/downloader/hlsDownloader.test.d.ts.map +1 -0
  85. package/dist/downloader/hlsDownloader.test.js +116 -0
  86. package/dist/downloader/hlsDownloader.test.js.map +1 -0
  87. package/dist/downloader/hlsValidator.d.ts +35 -0
  88. package/dist/downloader/hlsValidator.d.ts.map +1 -0
  89. package/dist/downloader/hlsValidator.js +148 -0
  90. package/dist/downloader/hlsValidator.js.map +1 -0
  91. package/dist/downloader/index.d.ts +26 -0
  92. package/dist/downloader/index.d.ts.map +1 -0
  93. package/dist/downloader/index.js +52 -0
  94. package/dist/downloader/index.js.map +1 -0
  95. package/dist/downloader/loomDownloader.d.ts +56 -0
  96. package/dist/downloader/loomDownloader.d.ts.map +1 -0
  97. package/dist/downloader/loomDownloader.js +559 -0
  98. package/dist/downloader/loomDownloader.js.map +1 -0
  99. package/dist/downloader/loomDownloader.test.d.ts +2 -0
  100. package/dist/downloader/loomDownloader.test.d.ts.map +1 -0
  101. package/dist/downloader/loomDownloader.test.js +36 -0
  102. package/dist/downloader/loomDownloader.test.js.map +1 -0
  103. package/dist/downloader/queue.d.ts +56 -0
  104. package/dist/downloader/queue.d.ts.map +1 -0
  105. package/dist/downloader/queue.js +88 -0
  106. package/dist/downloader/queue.js.map +1 -0
  107. package/dist/downloader/queue.test.d.ts +2 -0
  108. package/dist/downloader/queue.test.d.ts.map +1 -0
  109. package/dist/downloader/queue.test.js +158 -0
  110. package/dist/downloader/queue.test.js.map +1 -0
  111. package/dist/downloader/videoDownloader.d.ts +32 -0
  112. package/dist/downloader/videoDownloader.d.ts.map +1 -0
  113. package/dist/downloader/videoDownloader.js +173 -0
  114. package/dist/downloader/videoDownloader.js.map +1 -0
  115. package/dist/downloader/vimeoDownloader.d.ts +52 -0
  116. package/dist/downloader/vimeoDownloader.d.ts.map +1 -0
  117. package/dist/downloader/vimeoDownloader.js +565 -0
  118. package/dist/downloader/vimeoDownloader.js.map +1 -0
  119. package/dist/downloader/vimeoDownloader.test.d.ts +2 -0
  120. package/dist/downloader/vimeoDownloader.test.d.ts.map +1 -0
  121. package/dist/downloader/vimeoDownloader.test.js +51 -0
  122. package/dist/downloader/vimeoDownloader.test.js.map +1 -0
  123. package/dist/scraper/auth.d.ts +29 -0
  124. package/dist/scraper/auth.d.ts.map +1 -0
  125. package/dist/scraper/auth.js +115 -0
  126. package/dist/scraper/auth.js.map +1 -0
  127. package/dist/scraper/extractor.d.ts +49 -0
  128. package/dist/scraper/extractor.d.ts.map +1 -0
  129. package/dist/scraper/extractor.js +627 -0
  130. package/dist/scraper/extractor.js.map +1 -0
  131. package/dist/scraper/extractor.test.d.ts +2 -0
  132. package/dist/scraper/extractor.test.d.ts.map +1 -0
  133. package/dist/scraper/extractor.test.js +65 -0
  134. package/dist/scraper/extractor.test.js.map +1 -0
  135. package/dist/scraper/ghl/auth.d.ts +25 -0
  136. package/dist/scraper/ghl/auth.d.ts.map +1 -0
  137. package/dist/scraper/ghl/auth.js +187 -0
  138. package/dist/scraper/ghl/auth.js.map +1 -0
  139. package/dist/scraper/ghl/extractor.d.ts +96 -0
  140. package/dist/scraper/ghl/extractor.d.ts.map +1 -0
  141. package/dist/scraper/ghl/extractor.js +345 -0
  142. package/dist/scraper/ghl/extractor.js.map +1 -0
  143. package/dist/scraper/ghl/index.d.ts +4 -0
  144. package/dist/scraper/ghl/index.d.ts.map +1 -0
  145. package/dist/scraper/ghl/index.js +4 -0
  146. package/dist/scraper/ghl/index.js.map +1 -0
  147. package/dist/scraper/ghl/navigator.d.ts +93 -0
  148. package/dist/scraper/ghl/navigator.d.ts.map +1 -0
  149. package/dist/scraper/ghl/navigator.js +447 -0
  150. package/dist/scraper/ghl/navigator.js.map +1 -0
  151. package/dist/scraper/highlevel/auth.d.ts +25 -0
  152. package/dist/scraper/highlevel/auth.d.ts.map +1 -0
  153. package/dist/scraper/highlevel/auth.js +189 -0
  154. package/dist/scraper/highlevel/auth.js.map +1 -0
  155. package/dist/scraper/highlevel/extractor.d.ts +97 -0
  156. package/dist/scraper/highlevel/extractor.d.ts.map +1 -0
  157. package/dist/scraper/highlevel/extractor.js +386 -0
  158. package/dist/scraper/highlevel/extractor.js.map +1 -0
  159. package/dist/scraper/highlevel/extractor.test.d.ts +2 -0
  160. package/dist/scraper/highlevel/extractor.test.d.ts.map +1 -0
  161. package/dist/scraper/highlevel/extractor.test.js +101 -0
  162. package/dist/scraper/highlevel/extractor.test.js.map +1 -0
  163. package/dist/scraper/highlevel/index.d.ts +3 -0
  164. package/dist/scraper/highlevel/index.d.ts.map +1 -0
  165. package/dist/scraper/highlevel/index.js +3 -0
  166. package/dist/scraper/highlevel/index.js.map +1 -0
  167. package/dist/scraper/highlevel/navigator.d.ts +93 -0
  168. package/dist/scraper/highlevel/navigator.d.ts.map +1 -0
  169. package/dist/scraper/highlevel/navigator.js +492 -0
  170. package/dist/scraper/highlevel/navigator.js.map +1 -0
  171. package/dist/scraper/highlevel/navigator.test.d.ts +2 -0
  172. package/dist/scraper/highlevel/navigator.test.d.ts.map +1 -0
  173. package/dist/scraper/highlevel/navigator.test.js +78 -0
  174. package/dist/scraper/highlevel/navigator.test.js.map +1 -0
  175. package/dist/scraper/navigator.d.ts +65 -0
  176. package/dist/scraper/navigator.d.ts.map +1 -0
  177. package/dist/scraper/navigator.js +300 -0
  178. package/dist/scraper/navigator.js.map +1 -0
  179. package/dist/scraper/navigator.test.d.ts +2 -0
  180. package/dist/scraper/navigator.test.d.ts.map +1 -0
  181. package/dist/scraper/navigator.test.js +63 -0
  182. package/dist/scraper/navigator.test.js.map +1 -0
  183. package/dist/scraper/skoolApi.d.ts +17 -0
  184. package/dist/scraper/skoolApi.d.ts.map +1 -0
  185. package/dist/scraper/skoolApi.js +72 -0
  186. package/dist/scraper/skoolApi.js.map +1 -0
  187. package/dist/scraper/videoInterceptor.d.ts +19 -0
  188. package/dist/scraper/videoInterceptor.d.ts.map +1 -0
  189. package/dist/scraper/videoInterceptor.js +315 -0
  190. package/dist/scraper/videoInterceptor.js.map +1 -0
  191. package/dist/shared/auth.d.ts +58 -0
  192. package/dist/shared/auth.d.ts.map +1 -0
  193. package/dist/shared/auth.js +211 -0
  194. package/dist/shared/auth.js.map +1 -0
  195. package/dist/shared/fs.d.ts +31 -0
  196. package/dist/shared/fs.d.ts.map +1 -0
  197. package/dist/shared/fs.js +73 -0
  198. package/dist/shared/fs.js.map +1 -0
  199. package/dist/shared/http.d.ts +15 -0
  200. package/dist/shared/http.d.ts.map +1 -0
  201. package/dist/shared/http.js +31 -0
  202. package/dist/shared/http.js.map +1 -0
  203. package/dist/shared/index.d.ts +4 -0
  204. package/dist/shared/index.d.ts.map +1 -0
  205. package/dist/shared/index.js +4 -0
  206. package/dist/shared/index.js.map +1 -0
  207. package/dist/state/database.d.ts +245 -0
  208. package/dist/state/database.d.ts.map +1 -0
  209. package/dist/state/database.js +676 -0
  210. package/dist/state/database.js.map +1 -0
  211. package/dist/state/database.test.d.ts +2 -0
  212. package/dist/state/database.test.d.ts.map +1 -0
  213. package/dist/state/database.test.js +34 -0
  214. package/dist/state/database.test.js.map +1 -0
  215. package/dist/state/index.d.ts +2 -0
  216. package/dist/state/index.d.ts.map +1 -0
  217. package/dist/state/index.js +2 -0
  218. package/dist/state/index.js.map +1 -0
  219. package/dist/storage/fileSystem.d.ts +56 -0
  220. package/dist/storage/fileSystem.d.ts.map +1 -0
  221. package/dist/storage/fileSystem.js +121 -0
  222. package/dist/storage/fileSystem.js.map +1 -0
  223. package/dist/transcription/whisperService.d.ts +27 -0
  224. package/dist/transcription/whisperService.d.ts.map +1 -0
  225. package/dist/transcription/whisperService.js +102 -0
  226. package/dist/transcription/whisperService.js.map +1 -0
  227. package/eslint.config.js +55 -0
  228. package/package.json +68 -11
  229. package/src/__fixtures__/highlevel-post-response.json +68 -0
  230. package/src/__fixtures__/hls-master-playlist.m3u8 +24 -0
  231. package/src/cli/commands/__snapshots__/syncHighLevel.test.ts.snap +38 -0
  232. package/src/cli/commands/config.ts +74 -0
  233. package/src/cli/commands/inspect.ts +441 -0
  234. package/src/cli/commands/login.ts +68 -0
  235. package/src/cli/commands/status.ts +147 -0
  236. package/src/cli/commands/sync.ts +1235 -0
  237. package/src/cli/commands/syncHighLevel.test.ts +144 -0
  238. package/src/cli/commands/syncHighLevel.ts +639 -0
  239. package/src/cli/index.ts +121 -0
  240. package/src/config/configManager.ts +75 -0
  241. package/src/config/paths.test.ts +83 -0
  242. package/src/config/paths.ts +36 -0
  243. package/src/config/schema.test.ts +173 -0
  244. package/src/config/schema.ts +65 -0
  245. package/src/downloader/hlsDownloader.test.ts +148 -0
  246. package/src/downloader/hlsDownloader.ts +327 -0
  247. package/src/downloader/hlsValidator.ts +196 -0
  248. package/src/downloader/index.ts +122 -0
  249. package/src/downloader/loomDownloader.test.ts +43 -0
  250. package/src/downloader/loomDownloader.ts +742 -0
  251. package/src/downloader/queue.test.ts +199 -0
  252. package/src/downloader/queue.ts +118 -0
  253. package/src/downloader/vimeoDownloader.test.ts +62 -0
  254. package/src/downloader/vimeoDownloader.ts +722 -0
  255. package/src/scraper/extractor.test.ts +124 -0
  256. package/src/scraper/extractor.ts +757 -0
  257. package/src/scraper/highlevel/__snapshots__/extractor.test.ts.snap +41 -0
  258. package/src/scraper/highlevel/extractor.test.ts +134 -0
  259. package/src/scraper/highlevel/extractor.ts +537 -0
  260. package/src/scraper/highlevel/index.ts +2 -0
  261. package/src/scraper/highlevel/navigator.test.ts +110 -0
  262. package/src/scraper/highlevel/navigator.ts +668 -0
  263. package/src/scraper/highlevel/schemas.ts +183 -0
  264. package/src/scraper/navigator.test.ts +122 -0
  265. package/src/scraper/navigator.ts +355 -0
  266. package/src/scraper/schemas.ts +177 -0
  267. package/src/scraper/videoInterceptor.ts +435 -0
  268. package/src/shared/auth.test.ts +58 -0
  269. package/src/shared/auth.ts +251 -0
  270. package/src/shared/firebase.ts +151 -0
  271. package/src/shared/fs.ts +80 -0
  272. package/src/shared/http.ts +34 -0
  273. package/src/shared/index.ts +6 -0
  274. package/src/shared/slug.ts +26 -0
  275. package/src/shared/url.test.ts +122 -0
  276. package/src/shared/url.ts +57 -0
  277. package/src/state/database.test.ts +49 -0
  278. package/src/state/database.ts +919 -0
  279. package/src/state/index.ts +14 -0
  280. package/src/storage/fileSystem.test.ts +64 -0
  281. package/src/storage/fileSystem.ts +175 -0
  282. package/tsconfig.json +28 -0
  283. package/vitest.config.ts +29 -0
  284. package/cli.js +0 -45
@@ -0,0 +1,447 @@
1
+ /**
2
+ * Extracts the location ID from the GHL portal.
3
+ * The location ID is used in all API calls.
4
+ */
5
+ export async function extractLocationId(page) {
6
+ // Wait for API calls that contain the location ID
7
+ const locationId = await page.evaluate(() => {
8
+ // Try to find it in the URL of any API call
9
+ const scripts = Array.from(document.querySelectorAll("script"));
10
+ for (const script of scripts) {
11
+ const content = script.textContent ?? "";
12
+ // Look for location ID pattern in GHL (typically in API URLs)
13
+ const match = /locations\/([A-Za-z0-9]+)/.exec(content);
14
+ if (match?.[1] && match[1].length > 10) {
15
+ return match[1];
16
+ }
17
+ }
18
+ // Try to find it in localStorage or sessionStorage
19
+ for (const storage of [localStorage, sessionStorage]) {
20
+ for (let i = 0; i < storage.length; i++) {
21
+ const key = storage.key(i);
22
+ if (key) {
23
+ const value = storage.getItem(key);
24
+ if (value) {
25
+ const match = /"locationId":\s*"([A-Za-z0-9]+)"/.exec(value);
26
+ if (match?.[1])
27
+ return match[1];
28
+ }
29
+ }
30
+ }
31
+ }
32
+ return null;
33
+ });
34
+ return locationId;
35
+ }
36
+ /**
37
+ * Extracts portal settings including location ID from the API.
38
+ */
39
+ export async function extractPortalSettings(page, domain) {
40
+ try {
41
+ // Intercept the portal-settings API call
42
+ const response = await page.evaluate(async (domain) => {
43
+ const res = await fetch(`https://services.leadconnectorhq.com/clientclub/portal-settings?domain=${domain}`);
44
+ if (!res.ok)
45
+ return null;
46
+ return res.json();
47
+ }, domain);
48
+ if (response?.locationId) {
49
+ return {
50
+ locationId: response.locationId,
51
+ portalName: response.portalName ?? response.name ?? "GHL Course",
52
+ };
53
+ }
54
+ }
55
+ catch {
56
+ // Fall through
57
+ }
58
+ return null;
59
+ }
60
+ /**
61
+ * Extracts course list from the courses library page.
62
+ */
63
+ export async function extractCourses(page) {
64
+ // Wait for the course cards to load
65
+ await page.waitForTimeout(2000);
66
+ const courses = await page.evaluate(() => {
67
+ const results = [];
68
+ // Find course cards - GHL uses various patterns
69
+ const courseCards = document.querySelectorAll('[class*="course-card"], [class*="CourseCard"], [data-product-id], [class*="product-card"]');
70
+ // If no specific cards found, try to find links to course pages
71
+ if (courseCards.length === 0) {
72
+ const courseLinks = document.querySelectorAll('a[href*="/courses/products/"]');
73
+ const seen = new Set();
74
+ courseLinks.forEach((link) => {
75
+ const href = link.href;
76
+ const match = /\/courses\/products\/([a-f0-9-]+)/.exec(href);
77
+ if (match?.[1] && !seen.has(match[1])) {
78
+ seen.add(match[1]);
79
+ const title = link.querySelector("h3, h4, [class*='title']")?.textContent?.trim() ||
80
+ link.textContent?.trim() ||
81
+ `Course ${results.length + 1}`;
82
+ results.push({
83
+ id: match[1],
84
+ title,
85
+ description: "",
86
+ slug: match[1],
87
+ thumbnailUrl: link.querySelector("img")?.src ?? null,
88
+ instructor: null,
89
+ totalLessons: 0,
90
+ progress: 0,
91
+ });
92
+ }
93
+ });
94
+ }
95
+ return results;
96
+ });
97
+ return courses;
98
+ }
99
+ /**
100
+ * Extracts course details from the course overview page via API.
101
+ */
102
+ export async function extractCourseDetails(page, courseUrl, _locationId) {
103
+ // Extract product ID from provided courseUrl first
104
+ let productId;
105
+ const courseUrlMatch = /\/courses\/products\/([a-f0-9-]+)/.exec(courseUrl);
106
+ if (courseUrlMatch?.[1]) {
107
+ productId = courseUrlMatch[1];
108
+ }
109
+ // Fallback: try from current page URL
110
+ if (!productId) {
111
+ const pageUrlMatch = /\/courses\/products\/([a-f0-9-]+)/.exec(page.url());
112
+ productId = pageUrlMatch?.[1];
113
+ }
114
+ if (!productId) {
115
+ console.error("Could not extract product ID from URL:", courseUrl, "page:", page.url());
116
+ return null;
117
+ }
118
+ // Set up response interception to capture product data
119
+ let capturedProduct = null;
120
+ const responseHandler = async (response) => {
121
+ const url = response.url();
122
+ if (url.includes(`/products/${productId}`) && url.includes("leadconnectorhq.com")) {
123
+ try {
124
+ const data = await response.json();
125
+ if (data.product) {
126
+ capturedProduct = {
127
+ id: data.product.id,
128
+ title: data.product.title ?? "Unknown Course",
129
+ description: data.product.description ?? "",
130
+ slug: data.product.id,
131
+ thumbnailUrl: data.product.posterImage ?? null,
132
+ instructor: data.product.instructor ?? null,
133
+ totalLessons: data.product.postCount ?? 0,
134
+ progress: 0,
135
+ };
136
+ }
137
+ }
138
+ catch {
139
+ // Ignore JSON parse errors
140
+ }
141
+ }
142
+ };
143
+ page.on("response", responseHandler);
144
+ // Navigate to course page if not there (this triggers the API call)
145
+ const currentUrl = page.url();
146
+ const expectedPath = `/courses/products/${productId}`;
147
+ if (!currentUrl.includes(expectedPath)) {
148
+ await page.goto(courseUrl, { timeout: 30000 });
149
+ await page.waitForLoadState("domcontentloaded");
150
+ }
151
+ // Wait for potential API response
152
+ await page.waitForTimeout(3000);
153
+ // Remove the handler
154
+ page.off("response", responseHandler);
155
+ // If we captured the product, return it
156
+ if (capturedProduct) {
157
+ return capturedProduct;
158
+ }
159
+ // Wait for the page content to load
160
+ await page.waitForTimeout(2000);
161
+ // Fallback to DOM extraction if API fails
162
+ const domCourse = await page.evaluate(() => {
163
+ const urlMatch = /\/courses\/products\/([a-f0-9-]+)/.exec(window.location.href);
164
+ const id = urlMatch?.[1] ?? "";
165
+ // Look for the course title in various places
166
+ let title = "";
167
+ // Method 1: Look for a large heading that's not navigation
168
+ const headings = Array.from(document.querySelectorAll("h1, h2, h3"));
169
+ for (const h of headings) {
170
+ const text = h.textContent?.trim() ?? "";
171
+ const parent = h.closest("nav, header, [class*='nav'], [class*='Nav']");
172
+ // Skip if in navigation, or if it's a generic title
173
+ if (parent)
174
+ continue;
175
+ if (text.length < 4)
176
+ continue;
177
+ if (text.toLowerCase().includes("menu"))
178
+ continue;
179
+ if (text.toLowerCase().includes("login"))
180
+ continue;
181
+ if (text === "Memberships")
182
+ continue;
183
+ if (text === "Courses")
184
+ continue;
185
+ // Found a good candidate
186
+ title = text;
187
+ break;
188
+ }
189
+ // Method 2: Look for text with "lesson" count indicator nearby
190
+ if (!title) {
191
+ const lessonIndicators = Array.from(document.querySelectorAll("[class*='lesson'], [class*='Lesson']"));
192
+ for (const indicator of lessonIndicators) {
193
+ const parent = indicator.closest("[class*='card'], [class*='Card'], [class*='product'], [class*='Product']");
194
+ if (parent) {
195
+ const heading = parent.querySelector("h1, h2, h3, h4");
196
+ if (heading?.textContent?.trim()) {
197
+ title = heading.textContent.trim();
198
+ break;
199
+ }
200
+ }
201
+ }
202
+ }
203
+ if (!title || title.length < 3) {
204
+ title = "Unknown Course";
205
+ }
206
+ return {
207
+ id,
208
+ title,
209
+ description: "",
210
+ slug: id,
211
+ thumbnailUrl: null,
212
+ instructor: null,
213
+ totalLessons: 0,
214
+ progress: 0,
215
+ };
216
+ });
217
+ return domCourse.id ? domCourse : null;
218
+ }
219
+ /**
220
+ * Extracts categories (modules) from a course page.
221
+ */
222
+ export async function extractCategories(page, productId, locationId) {
223
+ // Try to get categories via API
224
+ const categories = await page.evaluate(async ({ productId, locationId }) => {
225
+ try {
226
+ // Get auth token from Firebase
227
+ const tokenKey = Object.keys(localStorage).find((k) => k.includes("firebase:authUser"));
228
+ const tokenData = tokenKey ? JSON.parse(localStorage.getItem(tokenKey) ?? "{}") : null;
229
+ const token = tokenData?.stsTokenManager?.accessToken;
230
+ if (!token) {
231
+ console.warn("No auth token found");
232
+ return [];
233
+ }
234
+ const res = await fetch(`https://services.leadconnectorhq.com/membership/locations/${locationId}/user-purchase/categories?product_id=${productId}&source=courses`, {
235
+ headers: {
236
+ Authorization: `Bearer ${token}`,
237
+ },
238
+ });
239
+ if (!res.ok) {
240
+ console.warn("Categories API returned", res.status);
241
+ return [];
242
+ }
243
+ const data = await res.json();
244
+ if (Array.isArray(data.categories)) {
245
+ return data.categories.map((cat) => ({
246
+ id: cat.id,
247
+ title: cat.title,
248
+ description: cat.description ?? null,
249
+ position: cat.position ?? 0,
250
+ postCount: cat.postCount ?? 0,
251
+ isLocked: cat.visibility === "locked",
252
+ }));
253
+ }
254
+ return [];
255
+ }
256
+ catch (error) {
257
+ console.error("Failed to fetch categories:", error);
258
+ return [];
259
+ }
260
+ }, { productId, locationId });
261
+ return categories;
262
+ }
263
+ /**
264
+ * Extracts posts (lessons) from a category.
265
+ */
266
+ export async function extractPosts(page, productId, categoryId, locationId) {
267
+ const posts = await page.evaluate(async ({ productId, categoryId, locationId }) => {
268
+ try {
269
+ // Get auth token
270
+ const tokenKey = Object.keys(localStorage).find((k) => k.includes("firebase:authUser"));
271
+ const tokenData = tokenKey ? JSON.parse(localStorage.getItem(tokenKey) ?? "{}") : null;
272
+ const token = tokenData?.stsTokenManager?.accessToken;
273
+ if (!token) {
274
+ return [];
275
+ }
276
+ const res = await fetch(`https://services.leadconnectorhq.com/membership/locations/${locationId}/user-purchase/categories/${categoryId}?product_id=${productId}&visibility=published&published_posts=true&source=courses`, {
277
+ headers: {
278
+ Authorization: `Bearer ${token}`,
279
+ },
280
+ });
281
+ if (!res.ok) {
282
+ return [];
283
+ }
284
+ const data = await res.json();
285
+ if (data.category?.posts && Array.isArray(data.category.posts)) {
286
+ return data.category.posts.map((post, index) => ({
287
+ id: post.id,
288
+ title: post.title,
289
+ position: post.indexPosition ?? index,
290
+ categoryId,
291
+ isLocked: post.visibility === "locked",
292
+ isCompleted: false,
293
+ }));
294
+ }
295
+ return [];
296
+ }
297
+ catch (error) {
298
+ console.error("Failed to fetch posts:", error);
299
+ return [];
300
+ }
301
+ }, { productId, categoryId, locationId });
302
+ return posts;
303
+ }
304
+ /**
305
+ * Builds the complete course structure.
306
+ */
307
+ export async function buildGHLCourseStructure(page, courseUrl, onProgress) {
308
+ // Extract domain and product ID from URL
309
+ const urlObj = new URL(courseUrl);
310
+ const domain = urlObj.hostname;
311
+ const productMatch = /\/courses\/products\/([a-f0-9-]+)/.exec(courseUrl);
312
+ const productId = productMatch?.[1];
313
+ // Get portal settings (includes location ID)
314
+ onProgress?.({ phase: "init" });
315
+ let locationId = null;
316
+ // Try to get location ID from portal settings API
317
+ const settings = await extractPortalSettings(page, domain);
318
+ if (settings) {
319
+ locationId = settings.locationId;
320
+ }
321
+ // Fallback: try to extract from page
322
+ if (!locationId) {
323
+ locationId = await extractLocationId(page);
324
+ }
325
+ if (!locationId) {
326
+ console.error("Could not determine location ID");
327
+ return null;
328
+ }
329
+ // Set up response interception to capture product data BEFORE navigation
330
+ let capturedCourseTitle = null;
331
+ const responseHandler = async (response) => {
332
+ const url = response.url();
333
+ if (productId && url.includes(`/products/${productId}`) && url.includes("leadconnectorhq.com")) {
334
+ try {
335
+ const data = await response.json();
336
+ if (data.product?.title) {
337
+ capturedCourseTitle = data.product.title;
338
+ }
339
+ }
340
+ catch {
341
+ // Ignore JSON parse errors
342
+ }
343
+ }
344
+ };
345
+ page.on("response", responseHandler);
346
+ // Navigate to course page
347
+ await page.goto(courseUrl, { timeout: 30000 });
348
+ await page.waitForLoadState("domcontentloaded");
349
+ await page.waitForTimeout(3000);
350
+ // Remove the handler
351
+ page.off("response", responseHandler);
352
+ // Extract course details
353
+ onProgress?.({ phase: "course" });
354
+ const course = await extractCourseDetails(page, courseUrl, locationId);
355
+ if (!course) {
356
+ console.error("Could not extract course details");
357
+ return null;
358
+ }
359
+ // Use captured title if available and course title is unknown
360
+ if (capturedCourseTitle && (course.title === "Unknown Course" || !course.title)) {
361
+ course.title = capturedCourseTitle;
362
+ }
363
+ onProgress?.({ phase: "course", courseName: course.title });
364
+ // Extract categories
365
+ onProgress?.({ phase: "categories" });
366
+ const categories = await extractCategories(page, course.id, locationId);
367
+ onProgress?.({ phase: "categories", totalCategories: categories.length });
368
+ // Extract posts for each category
369
+ const categoriesWithPosts = [];
370
+ for (let i = 0; i < categories.length; i++) {
371
+ const category = categories[i];
372
+ if (category.isLocked) {
373
+ onProgress?.({
374
+ phase: "posts",
375
+ currentCategory: category.title,
376
+ currentCategoryIndex: i,
377
+ skippedLocked: true,
378
+ });
379
+ continue;
380
+ }
381
+ onProgress?.({
382
+ phase: "posts",
383
+ currentCategory: category.title,
384
+ currentCategoryIndex: i,
385
+ });
386
+ const posts = await extractPosts(page, course.id, category.id, locationId);
387
+ onProgress?.({
388
+ phase: "posts",
389
+ currentCategory: category.title,
390
+ currentCategoryIndex: i,
391
+ postsFound: posts.length,
392
+ });
393
+ categoriesWithPosts.push({
394
+ ...category,
395
+ posts,
396
+ });
397
+ }
398
+ onProgress?.({ phase: "done" });
399
+ // Update total lessons count
400
+ course.totalLessons = categoriesWithPosts.reduce((total, cat) => total + cat.posts.length, 0);
401
+ return {
402
+ course,
403
+ categories: categoriesWithPosts,
404
+ locationId,
405
+ domain,
406
+ };
407
+ }
408
+ /**
409
+ * Creates a filesystem-safe name from a string.
410
+ */
411
+ export function slugify(name) {
412
+ return name
413
+ .toLowerCase()
414
+ .replace(/[äöüß]/g, (char) => {
415
+ const replacements = {
416
+ ä: "ae",
417
+ ö: "oe",
418
+ ü: "ue",
419
+ ß: "ss",
420
+ };
421
+ return replacements[char] ?? char;
422
+ })
423
+ .replace(/[^a-z0-9]+/g, "-")
424
+ .replace(/^-+|-+$/g, "")
425
+ .substring(0, 100);
426
+ }
427
+ /**
428
+ * Creates a folder name with index prefix.
429
+ */
430
+ export function createFolderName(index, name) {
431
+ const prefix = String(index + 1).padStart(2, "0");
432
+ const slug = slugify(name);
433
+ return `${prefix}-${slug}`;
434
+ }
435
+ /**
436
+ * Constructs the URL for a GHL course page.
437
+ */
438
+ export function getGHLCourseUrl(domain, productId) {
439
+ return `https://${domain}/courses/products/${productId}?source=courses`;
440
+ }
441
+ /**
442
+ * Constructs the URL for a GHL lesson (post) page.
443
+ */
444
+ export function getGHLPostUrl(domain, productId, categoryId, postId) {
445
+ return `https://${domain}/courses/products/${productId}/categories/${categoryId}/posts/${postId}?source=courses`;
446
+ }
447
+ //# sourceMappingURL=navigator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigator.js","sourceRoot":"","sources":["../../../src/scraper/ghl/navigator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { Browser, BrowserContext, Page } from "playwright";
2
+ export interface HighLevelAuthSession {
3
+ context: BrowserContext;
4
+ page: Page;
5
+ }
6
+ /**
7
+ * Checks if a valid HighLevel session exists for the given domain.
8
+ */
9
+ export declare function hasValidHighLevelSession(domain: string): boolean;
10
+ /**
11
+ * Performs interactive login for HighLevel by opening a browser window.
12
+ * The user logs in manually, and we capture the session.
13
+ */
14
+ export declare function performHighLevelInteractiveLogin(domain: string, portalUrl: string): Promise<HighLevelAuthSession>;
15
+ /**
16
+ * Gets an authenticated HighLevel session, either from cache or via interactive login.
17
+ */
18
+ export declare function getHighLevelAuthenticatedSession(domain: string, portalUrl: string, options?: {
19
+ forceLogin?: boolean;
20
+ headless?: boolean;
21
+ }): Promise<{
22
+ browser: Browser;
23
+ session: HighLevelAuthSession;
24
+ }>;
25
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/scraper/highlevel/auth.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAIhE,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,cAAc,CAAC;IACxB,IAAI,EAAE,IAAI,CAAC;CACZ;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAGhE;AAkED;;;GAGG;AACH,wBAAsB,gCAAgC,CACpD,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,oBAAoB,CAAC,CAgE/B;AAED;;GAEG;AACH,wBAAsB,gCAAgC,CACpD,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAO,GACzD,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,oBAAoB,CAAA;CAAE,CAAC,CAoE9D"}