coursecode 0.1.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 (362) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +322 -0
  3. package/THIRD_PARTY_NOTICES.md +22 -0
  4. package/bin/cli.js +331 -0
  5. package/framework/assets/logo-coursecode-black.svg +14 -0
  6. package/framework/assets/logo-coursecode-white.svg +14 -0
  7. package/framework/assets/logo-coursecode.svg +14 -0
  8. package/framework/css/01-base.css +160 -0
  9. package/framework/css/02-layout.css +499 -0
  10. package/framework/css/accessibility.css +834 -0
  11. package/framework/css/components/accordions.css +710 -0
  12. package/framework/css/components/assessments.css +520 -0
  13. package/framework/css/components/audio-player.css +570 -0
  14. package/framework/css/components/badges.css +80 -0
  15. package/framework/css/components/breadcrumbs.css +87 -0
  16. package/framework/css/components/buttons.css +707 -0
  17. package/framework/css/components/callouts.css +1280 -0
  18. package/framework/css/components/cards.css +475 -0
  19. package/framework/css/components/carousel.css +193 -0
  20. package/framework/css/components/checkbox-group.css +123 -0
  21. package/framework/css/components/checklist.css +203 -0
  22. package/framework/css/components/collapse.css +96 -0
  23. package/framework/css/components/comparison.css +33 -0
  24. package/framework/css/components/content-image.css +36 -0
  25. package/framework/css/components/document-gallery.css +425 -0
  26. package/framework/css/components/dropdown.css +115 -0
  27. package/framework/css/components/embed-frame.css +142 -0
  28. package/framework/css/components/engagement.css +412 -0
  29. package/framework/css/components/features.css +35 -0
  30. package/framework/css/components/flip-cards.css +253 -0
  31. package/framework/css/components/footer.css +353 -0
  32. package/framework/css/components/forms.css +294 -0
  33. package/framework/css/components/hero.css +216 -0
  34. package/framework/css/components/images.css +528 -0
  35. package/framework/css/components/interactive-timeline.css +274 -0
  36. package/framework/css/components/intro-cards.css +30 -0
  37. package/framework/css/components/lightbox.css +666 -0
  38. package/framework/css/components/loading.css +65 -0
  39. package/framework/css/components/modals.css +235 -0
  40. package/framework/css/components/notifications.css +107 -0
  41. package/framework/css/components/quote.css +150 -0
  42. package/framework/css/components/sidebar.css +684 -0
  43. package/framework/css/components/slide-header.css +52 -0
  44. package/framework/css/components/spinner.css +62 -0
  45. package/framework/css/components/stats.css +44 -0
  46. package/framework/css/components/steps.css +232 -0
  47. package/framework/css/components/tables.css +90 -0
  48. package/framework/css/components/tabs.css +347 -0
  49. package/framework/css/components/timeline.css +154 -0
  50. package/framework/css/components/toggle.css +95 -0
  51. package/framework/css/components/tooltip.css +226 -0
  52. package/framework/css/components/video-player.css +438 -0
  53. package/framework/css/design-tokens.css +707 -0
  54. package/framework/css/framework.css +86 -0
  55. package/framework/css/interactions/accessibility.css +75 -0
  56. package/framework/css/interactions/base.css +92 -0
  57. package/framework/css/interactions/drag-drop.css +295 -0
  58. package/framework/css/interactions/fill-in-the-blank.css +236 -0
  59. package/framework/css/interactions/hotspots.css +69 -0
  60. package/framework/css/interactions/index.css +45 -0
  61. package/framework/css/interactions/interactive-image.css +359 -0
  62. package/framework/css/interactions/likert.css +126 -0
  63. package/framework/css/interactions/matching.css +354 -0
  64. package/framework/css/interactions/numeric-input.css +78 -0
  65. package/framework/css/interactions/sequencing.css +378 -0
  66. package/framework/css/interactions/true-false.css +177 -0
  67. package/framework/css/layouts/article.css +258 -0
  68. package/framework/css/layouts/base.css +30 -0
  69. package/framework/css/layouts/canvas.css +38 -0
  70. package/framework/css/layouts/focused.css +236 -0
  71. package/framework/css/layouts/index.css +29 -0
  72. package/framework/css/layouts/presentation.css +191 -0
  73. package/framework/css/layouts/traditional.css +52 -0
  74. package/framework/css/responsive.css +439 -0
  75. package/framework/css/utilities/accessibility-utils.css +59 -0
  76. package/framework/css/utilities/animations.css +419 -0
  77. package/framework/css/utilities/borders.css +72 -0
  78. package/framework/css/utilities/colors.css +76 -0
  79. package/framework/css/utilities/container.css +46 -0
  80. package/framework/css/utilities/decorative.css +442 -0
  81. package/framework/css/utilities/display.css +257 -0
  82. package/framework/css/utilities/flexbox.css +80 -0
  83. package/framework/css/utilities/grid.css +69 -0
  84. package/framework/css/utilities/icons.css +534 -0
  85. package/framework/css/utilities/lists.css +190 -0
  86. package/framework/css/utilities/spacing.css +167 -0
  87. package/framework/css/utilities/tables.css +81 -0
  88. package/framework/css/utilities/typography.css +159 -0
  89. package/framework/css/utilities/visibility.css +117 -0
  90. package/framework/docs/COURSE_AUTHORING_GUIDE.md +1773 -0
  91. package/framework/docs/COURSE_OUTLINE_GUIDE.md +725 -0
  92. package/framework/docs/COURSE_OUTLINE_TEMPLATE.md +161 -0
  93. package/framework/docs/DATA_MODEL.md +409 -0
  94. package/framework/docs/FRAMEWORK_GUIDE.md +1088 -0
  95. package/framework/docs/USER_GUIDE.md +583 -0
  96. package/framework/docs/examples/cloudflare-channel-relay.js +169 -0
  97. package/framework/docs/examples/cloudflare-data-worker.js +102 -0
  98. package/framework/docs/examples/cloudflare-error-worker.js +228 -0
  99. package/framework/index.html +175 -0
  100. package/framework/js/app/AppActions.js +410 -0
  101. package/framework/js/app/AppState.js +225 -0
  102. package/framework/js/app/AppUI.js +616 -0
  103. package/framework/js/assessment/AssessmentActions.js +615 -0
  104. package/framework/js/assessment/AssessmentFactory.js +471 -0
  105. package/framework/js/assessment/AssessmentState.js +322 -0
  106. package/framework/js/assessment/AssessmentUI.js +451 -0
  107. package/framework/js/automation/api-engagement.js +196 -0
  108. package/framework/js/automation/api-interactions.js +167 -0
  109. package/framework/js/automation/api.js +242 -0
  110. package/framework/js/automation/index.js +41 -0
  111. package/framework/js/components/interactions/drag-drop.js +884 -0
  112. package/framework/js/components/interactions/fill-in.js +535 -0
  113. package/framework/js/components/interactions/hotspot.js +702 -0
  114. package/framework/js/components/interactions/interaction-base.js +511 -0
  115. package/framework/js/components/interactions/likert.js +301 -0
  116. package/framework/js/components/interactions/matching.js +699 -0
  117. package/framework/js/components/interactions/multiple-choice.js +377 -0
  118. package/framework/js/components/interactions/numeric.js +271 -0
  119. package/framework/js/components/interactions/sequencing.js +423 -0
  120. package/framework/js/components/interactions/true-false.js +241 -0
  121. package/framework/js/components/ui-components/accordion.js +442 -0
  122. package/framework/js/components/ui-components/alert.js +88 -0
  123. package/framework/js/components/ui-components/audio-player.js +1193 -0
  124. package/framework/js/components/ui-components/callout.js +121 -0
  125. package/framework/js/components/ui-components/carousel.js +145 -0
  126. package/framework/js/components/ui-components/checkbox-group.js +87 -0
  127. package/framework/js/components/ui-components/checklist.js +40 -0
  128. package/framework/js/components/ui-components/collapse.js +114 -0
  129. package/framework/js/components/ui-components/comparison.js +30 -0
  130. package/framework/js/components/ui-components/conditional-display.js +150 -0
  131. package/framework/js/components/ui-components/content-image.js +41 -0
  132. package/framework/js/components/ui-components/dropdown.js +262 -0
  133. package/framework/js/components/ui-components/embed-frame.js +274 -0
  134. package/framework/js/components/ui-components/features.js +33 -0
  135. package/framework/js/components/ui-components/flip-card.js +230 -0
  136. package/framework/js/components/ui-components/form-validator.js +76 -0
  137. package/framework/js/components/ui-components/hero.js +49 -0
  138. package/framework/js/components/ui-components/index.js +12 -0
  139. package/framework/js/components/ui-components/interactive-image.js +235 -0
  140. package/framework/js/components/ui-components/interactive-timeline.js +285 -0
  141. package/framework/js/components/ui-components/intro-cards.js +35 -0
  142. package/framework/js/components/ui-components/lightbox.js +652 -0
  143. package/framework/js/components/ui-components/modal.js +386 -0
  144. package/framework/js/components/ui-components/notifications.js +145 -0
  145. package/framework/js/components/ui-components/progress.js +88 -0
  146. package/framework/js/components/ui-components/quote.js +41 -0
  147. package/framework/js/components/ui-components/stats.js +33 -0
  148. package/framework/js/components/ui-components/steps.js +41 -0
  149. package/framework/js/components/ui-components/tabs.js +255 -0
  150. package/framework/js/components/ui-components/timeline.js +42 -0
  151. package/framework/js/components/ui-components/toggle-group.js +73 -0
  152. package/framework/js/components/ui-components/tooltip.js +458 -0
  153. package/framework/js/components/ui-components/value-display.js +133 -0
  154. package/framework/js/components/ui-components/video-player.js +686 -0
  155. package/framework/js/core/component-catalog.js +121 -0
  156. package/framework/js/core/event-bus.js +178 -0
  157. package/framework/js/core/interaction-catalog.js +149 -0
  158. package/framework/js/dev/runtime-linter.js +1725 -0
  159. package/framework/js/drivers/cmi5-driver.js +768 -0
  160. package/framework/js/drivers/driver-factory.js +77 -0
  161. package/framework/js/drivers/driver-interface.js +110 -0
  162. package/framework/js/drivers/http-driver-base.js +241 -0
  163. package/framework/js/drivers/lti-driver.js +508 -0
  164. package/framework/js/drivers/proxy-driver.js +444 -0
  165. package/framework/js/drivers/scorm-12-driver.js +560 -0
  166. package/framework/js/drivers/scorm-2004-driver.js +775 -0
  167. package/framework/js/drivers/scorm-driver-base.js +112 -0
  168. package/framework/js/engagement/engagement-manager.js +404 -0
  169. package/framework/js/engagement/engagement-progress.js +191 -0
  170. package/framework/js/engagement/engagement-trackers.js +215 -0
  171. package/framework/js/engagement/requirement-strategies.js +268 -0
  172. package/framework/js/main.js +727 -0
  173. package/framework/js/managers/accessibility-manager.js +499 -0
  174. package/framework/js/managers/assessment-manager.js +230 -0
  175. package/framework/js/managers/audio-manager.js +944 -0
  176. package/framework/js/managers/comment-manager.js +88 -0
  177. package/framework/js/managers/flag-manager.js +86 -0
  178. package/framework/js/managers/interaction-manager.js +254 -0
  179. package/framework/js/managers/interaction-registry.js +96 -0
  180. package/framework/js/managers/objective-manager.js +423 -0
  181. package/framework/js/managers/score-manager.js +441 -0
  182. package/framework/js/managers/video-manager.js +536 -0
  183. package/framework/js/navigation/Breadcrumbs.js +234 -0
  184. package/framework/js/navigation/NavigationActions.js +1132 -0
  185. package/framework/js/navigation/NavigationState.js +276 -0
  186. package/framework/js/navigation/NavigationUI.js +574 -0
  187. package/framework/js/navigation/document-gallery.js +357 -0
  188. package/framework/js/navigation/navigation-helpers.js +175 -0
  189. package/framework/js/navigation/navigation-validators.js +174 -0
  190. package/framework/js/state/index.js +8 -0
  191. package/framework/js/state/lms-connection.js +482 -0
  192. package/framework/js/state/lms-error-utils.js +58 -0
  193. package/framework/js/state/state-commits.js +200 -0
  194. package/framework/js/state/state-domains.js +86 -0
  195. package/framework/js/state/state-manager.js +502 -0
  196. package/framework/js/state/state-validation.js +311 -0
  197. package/framework/js/state/transaction-log.js +41 -0
  198. package/framework/js/state/xapi-statement-service.js +325 -0
  199. package/framework/js/utilities/access-control.js +99 -0
  200. package/framework/js/utilities/breakpoint-manager.js +315 -0
  201. package/framework/js/utilities/canvas-slide.js +35 -0
  202. package/framework/js/utilities/conditional-display.js +388 -0
  203. package/framework/js/utilities/course-channel.js +214 -0
  204. package/framework/js/utilities/course-helpers.js +420 -0
  205. package/framework/js/utilities/data-reporter.js +273 -0
  206. package/framework/js/utilities/error-reporter.js +313 -0
  207. package/framework/js/utilities/hotspot-helper.js +341 -0
  208. package/framework/js/utilities/icons.js +348 -0
  209. package/framework/js/utilities/logger.js +92 -0
  210. package/framework/js/utilities/markdown-renderer.js +45 -0
  211. package/framework/js/utilities/scroll-tracker.js +68 -0
  212. package/framework/js/utilities/ui-initializer.js +146 -0
  213. package/framework/js/utilities/utilities.js +293 -0
  214. package/framework/js/utilities/view-manager.js +227 -0
  215. package/framework/js/validation/html-validators.js +422 -0
  216. package/framework/js/validation/scorm-validators.js +438 -0
  217. package/framework/js/vendor/pipwerks.js +931 -0
  218. package/framework/scripts/generate-narration.js +629 -0
  219. package/framework/scripts/tts-providers/azure-provider.js +178 -0
  220. package/framework/scripts/tts-providers/base-provider.js +81 -0
  221. package/framework/scripts/tts-providers/deepgram-provider.js +135 -0
  222. package/framework/scripts/tts-providers/elevenlabs-provider.js +148 -0
  223. package/framework/scripts/tts-providers/google-provider.js +272 -0
  224. package/framework/scripts/tts-providers/index.js +158 -0
  225. package/framework/scripts/tts-providers/openai-provider.js +143 -0
  226. package/framework/version.json +63 -0
  227. package/lib/authoring-api.js +919 -0
  228. package/lib/build-linter.js +450 -0
  229. package/lib/build-packaging.js +186 -0
  230. package/lib/build.js +88 -0
  231. package/lib/cloud.js +691 -0
  232. package/lib/convert.js +341 -0
  233. package/lib/course-parser.js +936 -0
  234. package/lib/course-writer.js +258 -0
  235. package/lib/create.js +248 -0
  236. package/lib/css-index.js +237 -0
  237. package/lib/dev.js +51 -0
  238. package/lib/export-content.js +1246 -0
  239. package/lib/headless-browser.js +413 -0
  240. package/lib/import.js +377 -0
  241. package/lib/index.js +80 -0
  242. package/lib/info.js +79 -0
  243. package/lib/interaction-formatters.js +568 -0
  244. package/lib/manifest/cmi5-manifest.js +63 -0
  245. package/lib/manifest/lti-tool-config.js +53 -0
  246. package/lib/manifest/manifest-factory.js +99 -0
  247. package/lib/manifest/scorm-12-manifest.js +61 -0
  248. package/lib/manifest/scorm-2004-manifest.js +94 -0
  249. package/lib/manifest/scorm-proxy-manifest.js +104 -0
  250. package/lib/manifest-parser.js +96 -0
  251. package/lib/mcp-prompts.js +753 -0
  252. package/lib/mcp-server.js +316 -0
  253. package/lib/narration.js +53 -0
  254. package/lib/pdf-structure.js +142 -0
  255. package/lib/preview-export.js +231 -0
  256. package/lib/preview-routes-api.js +662 -0
  257. package/lib/preview-routes-editing.js +159 -0
  258. package/lib/preview-routes-lms.js +230 -0
  259. package/lib/preview-server.js +564 -0
  260. package/lib/project-utils.js +269 -0
  261. package/lib/proxy-templates/proxy.html +68 -0
  262. package/lib/proxy-templates/scorm-bridge.js +112 -0
  263. package/lib/scaffold.js +193 -0
  264. package/lib/schema-extractor.js +361 -0
  265. package/lib/slide-source-editor.js +586 -0
  266. package/lib/stub-player/app-viewer.js +195 -0
  267. package/lib/stub-player/app.js +370 -0
  268. package/lib/stub-player/catalog-panel.js +312 -0
  269. package/lib/stub-player/config-panel.js +1303 -0
  270. package/lib/stub-player/content-generator.js +586 -0
  271. package/lib/stub-player/content-viewer.js +173 -0
  272. package/lib/stub-player/debug-panel.js +420 -0
  273. package/lib/stub-player/edit-mode.js +922 -0
  274. package/lib/stub-player/edit-utils.js +400 -0
  275. package/lib/stub-player/header-bar.js +354 -0
  276. package/lib/stub-player/interaction-editor.js +210 -0
  277. package/lib/stub-player/interactions-panel.js +565 -0
  278. package/lib/stub-player/lms-api.js +1094 -0
  279. package/lib/stub-player/login-screen.js +74 -0
  280. package/lib/stub-player/outline-mode.js +689 -0
  281. package/lib/stub-player/styles/_assessments-panel.css +245 -0
  282. package/lib/stub-player/styles/_base.css +89 -0
  283. package/lib/stub-player/styles/_catalog-icons.css +96 -0
  284. package/lib/stub-player/styles/_catalog-panel.css +291 -0
  285. package/lib/stub-player/styles/_config-panel.css +636 -0
  286. package/lib/stub-player/styles/_content-viewer.css +834 -0
  287. package/lib/stub-player/styles/_debug-panel.css +576 -0
  288. package/lib/stub-player/styles/_edit-mode.css +128 -0
  289. package/lib/stub-player/styles/_header-bar.css +343 -0
  290. package/lib/stub-player/styles/_interaction-editor.css +140 -0
  291. package/lib/stub-player/styles/_interactions-panel.css +1038 -0
  292. package/lib/stub-player/styles/_login-screen.css +102 -0
  293. package/lib/stub-player/styles/_outline-mode.css +752 -0
  294. package/lib/stub-player/styles.css +15 -0
  295. package/lib/stub-player.js +160 -0
  296. package/lib/test-data-reporting.js +176 -0
  297. package/lib/test-error-reporting.js +146 -0
  298. package/lib/token.js +86 -0
  299. package/lib/upgrade.js +257 -0
  300. package/lib/validation-rules.js +517 -0
  301. package/lib/vite-plugin-content-discovery.js +296 -0
  302. package/package.json +108 -0
  303. package/schemas/XMLSchema.dtd +402 -0
  304. package/schemas/adlcp_v1p3.xsd +111 -0
  305. package/schemas/adlnav_v1p3.xsd +61 -0
  306. package/schemas/adlseq_v1p3.xsd +93 -0
  307. package/schemas/common/anyElement.xsd +27 -0
  308. package/schemas/common/dataTypes.xsd +138 -0
  309. package/schemas/common/elementNames.xsd +767 -0
  310. package/schemas/common/elementTypes.xsd +786 -0
  311. package/schemas/common/rootElement.xsd +31 -0
  312. package/schemas/common/vocabTypes.xsd +345 -0
  313. package/schemas/common/vocabValues.xsd +257 -0
  314. package/schemas/datatypes.dtd +203 -0
  315. package/schemas/ims_xml.xsd +35 -0
  316. package/schemas/imscp_v1p1.xsd +368 -0
  317. package/schemas/imsss_v1p0.xsd +67 -0
  318. package/schemas/imsss_v1p0auxresource.xsd +19 -0
  319. package/schemas/imsss_v1p0control.xsd +20 -0
  320. package/schemas/imsss_v1p0delivery.xsd +17 -0
  321. package/schemas/imsss_v1p0limit.xsd +47 -0
  322. package/schemas/imsss_v1p0objective.xsd +67 -0
  323. package/schemas/imsss_v1p0random.xsd +16 -0
  324. package/schemas/imsss_v1p0rollup.xsd +46 -0
  325. package/schemas/imsss_v1p0seqrule.xsd +108 -0
  326. package/schemas/imsss_v1p0util.xsd +94 -0
  327. package/schemas/license.txt +17 -0
  328. package/schemas/lom.xsd +102 -0
  329. package/schemas/lomCustom.xsd +62 -0
  330. package/schemas/lomLoose.xsd +62 -0
  331. package/schemas/lomStrict.xsd +62 -0
  332. package/schemas/xml.xsd +81 -0
  333. package/template/.env.example +92 -0
  334. package/template/course/assets/audio/example-intro.mp3 +0 -0
  335. package/template/course/assets/audio/example-ui-demo--compact-player.mp3 +0 -0
  336. package/template/course/assets/audio/example-ui-demo--demo-modal.mp3 +0 -0
  337. package/template/course/assets/audio/example-ui-demo--full-player.mp3 +0 -0
  338. package/template/course/assets/docs/example_md_1.md +39 -0
  339. package/template/course/assets/docs/example_md_2.md +41 -0
  340. package/template/course/assets/docs/example_pdf_1_thumbnail.png +0 -0
  341. package/template/course/assets/docs/example_pdf_2.pdf +0 -0
  342. package/template/course/assets/images/course-architecture.svg +36 -0
  343. package/template/course/assets/images/logo.svg +14 -0
  344. package/template/course/assets/widgets/counter-demo.html +190 -0
  345. package/template/course/assets/widgets/gravity-painter.html +384 -0
  346. package/template/course/course-config.js +539 -0
  347. package/template/course/icons.js +19 -0
  348. package/template/course/interactions/PLUGIN_GUIDE.md +97 -0
  349. package/template/course/slides/example-course-structure.js +138 -0
  350. package/template/course/slides/example-final-exam.js +144 -0
  351. package/template/course/slides/example-finishing.js +127 -0
  352. package/template/course/slides/example-interactions-showcase.js +615 -0
  353. package/template/course/slides/example-preview-tour.js +129 -0
  354. package/template/course/slides/example-remedial.js +143 -0
  355. package/template/course/slides/example-summary.js +103 -0
  356. package/template/course/slides/example-ui-showcase.js +1805 -0
  357. package/template/course/slides/example-welcome.js +123 -0
  358. package/template/course/slides/example-workflow.js +140 -0
  359. package/template/course/theme.css +165 -0
  360. package/template/eslint.config.js +47 -0
  361. package/template/package.json +28 -0
  362. package/template/vite.config.js +339 -0
@@ -0,0 +1,167 @@
1
+ /**
2
+ * @file api-interactions.js
3
+ * Interaction discovery, state access, mutation, and evaluation methods
4
+ * for the CourseCodeAutomation API.
5
+ */
6
+
7
+ import interactionRegistry from '../managers/interaction-registry.js';
8
+ import { courseConfig } from '../../../course/course-config.js';
9
+ import { recordInteractionResult } from '../components/interactions/interaction-base.js';
10
+ import { logger } from '../utilities/logger.js';
11
+
12
+ /**
13
+ * Creates interaction API methods bound to the shared logTrace function.
14
+ * @param {Function} logTrace - Shared trace logger
15
+ * @returns {Object} Interaction API methods
16
+ */
17
+ export function createInteractionMethods(logTrace) {
18
+ return {
19
+ listInteractions() {
20
+ const interactions = interactionRegistry.getAll();
21
+ const simplifiedList = interactions.map(i => ({
22
+ id: i.id,
23
+ type: i.type,
24
+ description: i.description
25
+ }));
26
+ logTrace('listInteractions', { count: simplifiedList.length });
27
+ return simplifiedList;
28
+ },
29
+
30
+ getInteractionMetadata(interactionId) {
31
+ const entry = interactionRegistry.getAll().find(i => i.id === interactionId);
32
+ if (!entry) {
33
+ throw new Error(`CourseCodeAutomation: Interaction "${interactionId}" not found on the current slide`);
34
+ }
35
+ logTrace('getInteractionMetadata', { interactionId });
36
+ return {
37
+ id: entry.id,
38
+ type: entry.type,
39
+ description: entry.description
40
+ };
41
+ },
42
+
43
+ getResponse(interactionId) {
44
+ const entry = interactionRegistry.getAll().find(i => i.id === interactionId);
45
+ if (!entry || !entry.instance) {
46
+ throw new Error(`CourseCodeAutomation: Interaction "${interactionId}" not found or has no instance`);
47
+ }
48
+
49
+ if (typeof entry.instance.getResponse !== 'function') {
50
+ throw new Error(`CourseCodeAutomation: Interaction "${interactionId}" does not support getResponse`);
51
+ }
52
+
53
+ const response = entry.instance.getResponse();
54
+ logTrace('getResponse', { interactionId, response });
55
+ return response;
56
+ },
57
+
58
+ getCorrectResponse(interactionId) {
59
+ if (!courseConfig.environment?.automation?.exposeCorrectAnswers) {
60
+ throw new Error('CourseCodeAutomation: getCorrectResponse requires automation.exposeCorrectAnswers=true in course config');
61
+ }
62
+
63
+ const entry = interactionRegistry.getAll().find(i => i.id === interactionId);
64
+ if (!entry || !entry.instance) {
65
+ throw new Error(`CourseCodeAutomation: Interaction "${interactionId}" not found or has no instance`);
66
+ }
67
+
68
+ if (typeof entry.instance.getCorrectAnswer !== 'function') {
69
+ throw new Error(`CourseCodeAutomation: Interaction "${interactionId}" does not support getCorrectAnswer`);
70
+ }
71
+
72
+ const correctAnswer = entry.instance.getCorrectAnswer();
73
+ logTrace('getCorrectResponse', { interactionId });
74
+ return correctAnswer;
75
+ },
76
+
77
+ setResponse(interactionId, response) {
78
+ const entry = interactionRegistry.getAll().find(i => i.id === interactionId);
79
+ if (!entry || !entry.instance) {
80
+ throw new Error(`CourseCodeAutomation: Interaction "${interactionId}" not found or has no instance`);
81
+ }
82
+
83
+ if (typeof entry.instance.setResponse !== 'function') {
84
+ throw new Error(`CourseCodeAutomation: Interaction "${interactionId}" does not support setResponse`);
85
+ }
86
+
87
+ try {
88
+ entry.instance.setResponse(response);
89
+ logTrace('setResponse', { interactionId, response });
90
+ } catch (error) {
91
+ logTrace('setResponse:error', { interactionId, response, error: error.message });
92
+ throw new Error(`CourseCodeAutomation: Failed to set response for "${interactionId}": ${error.message}`);
93
+ }
94
+ },
95
+
96
+ checkAnswer(interactionId) {
97
+ const entry = interactionRegistry.getAll().find(i => i.id === interactionId);
98
+ if (!entry || !entry.instance) {
99
+ throw new Error(`CourseCodeAutomation: Interaction "${interactionId}" not found or has no instance`);
100
+ }
101
+
102
+ if (typeof entry.instance.checkAnswer !== 'function') {
103
+ throw new Error(`CourseCodeAutomation: Interaction "${interactionId}" does not support checkAnswer`);
104
+ }
105
+
106
+ try {
107
+ const evaluation = entry.instance.checkAnswer();
108
+ logTrace('checkAnswer', { interactionId, evaluation });
109
+
110
+ const config = entry.config;
111
+ if (!config.controlled) {
112
+ try {
113
+ recordInteractionResult(config, evaluation);
114
+ } catch (recordError) {
115
+ logger.warn(`[CourseCodeAutomation] Failed to record interaction "${interactionId}" to SCORM: ${recordError.message}`);
116
+ }
117
+ }
118
+
119
+ return evaluation;
120
+ } catch (error) {
121
+ logTrace('checkAnswer:error', { interactionId, error: error.message });
122
+ throw new Error(`CourseCodeAutomation: Failed to check answer for "${interactionId}": ${error.message}`);
123
+ }
124
+ },
125
+
126
+ checkSlideAnswers(getCurrentSlide) {
127
+ const slideId = getCurrentSlide();
128
+ const slideInteractions = interactionRegistry.getAll();
129
+
130
+ if (slideInteractions.length === 0) {
131
+ logTrace('checkSlideAnswers', {
132
+ slideId,
133
+ found: 0,
134
+ message: 'No interactions found on slide'
135
+ });
136
+ return [];
137
+ }
138
+
139
+ const results = [];
140
+ for (const interactionInfo of slideInteractions) {
141
+ try {
142
+ const evaluation = this.checkAnswer(interactionInfo.id);
143
+ results.push({
144
+ interactionId: interactionInfo.id,
145
+ type: interactionInfo.type,
146
+ evaluation
147
+ });
148
+ } catch (error) {
149
+ results.push({
150
+ interactionId: interactionInfo.id,
151
+ type: interactionInfo.type,
152
+ error: error.message
153
+ });
154
+ }
155
+ }
156
+
157
+ logTrace('checkSlideAnswers', {
158
+ slideId,
159
+ total: slideInteractions.length,
160
+ successful: results.filter(r => !r.error).length,
161
+ failed: results.filter(r => r.error).length
162
+ });
163
+
164
+ return results;
165
+ }
166
+ };
167
+ }
@@ -0,0 +1,242 @@
1
+ /**
2
+ * @file api.js
3
+ * @description Public automation API exposed on window.CourseCodeAutomation
4
+ * Provides programmatic control over interactions, navigation, and course state
5
+ * for testing and AI-driven automation.
6
+ *
7
+ * This module is ONLY loaded in development/testing mode and is completely excluded
8
+ * from production builds via Vite's tree-shaking.
9
+ *
10
+ * Delegates to domain-specific modules:
11
+ * api-interactions.js – discovery, state, mutation, evaluation
12
+ * api-engagement.js – engagement, flags, audio
13
+ */
14
+
15
+ import { logger } from '../utilities/logger.js';
16
+ import { eventBus } from '../core/event-bus.js';
17
+ import * as NavigationActions from '../navigation/NavigationActions.js';
18
+ import { courseConfig } from '../../../course/course-config.js';
19
+ import stateManager from '../state/index.js';
20
+ import accessibilityManager from '../managers/accessibility-manager.js';
21
+ import objectiveManager from '../managers/objective-manager.js';
22
+
23
+ import { createInteractionMethods } from './api-interactions.js';
24
+ import { createEngagementMethods } from './api-engagement.js';
25
+
26
+ /** Automation trace log for observability */
27
+ const automationTrace = [];
28
+
29
+ /** Framework log buffer — captures structured log:warn and log:error events */
30
+ const frameworkLogs = [];
31
+ const MAX_FRAMEWORK_LOGS = 100;
32
+
33
+ eventBus.on('log:warn', (payload) => {
34
+ frameworkLogs.push({ ...payload, timestamp: new Date().toISOString() });
35
+ if (frameworkLogs.length > MAX_FRAMEWORK_LOGS) frameworkLogs.shift();
36
+ });
37
+ eventBus.on('log:error', (payload) => {
38
+ frameworkLogs.push({ ...payload, timestamp: new Date().toISOString() });
39
+ if (frameworkLogs.length > MAX_FRAMEWORK_LOGS) frameworkLogs.shift();
40
+ });
41
+
42
+ /** Adds an entry to the automation trace log */
43
+ function logTrace(action, details) {
44
+ const entry = {
45
+ timestamp: new Date().toISOString(),
46
+ action,
47
+ ...details
48
+ };
49
+ automationTrace.push(entry);
50
+ eventBus.emit('automation:trace', entry);
51
+ }
52
+
53
+ // Build delegated method sets
54
+ const interactionMethods = createInteractionMethods(logTrace);
55
+ const engagementMethods = createEngagementMethods(logTrace);
56
+
57
+ /**
58
+ * CourseCodeAutomation API
59
+ * All methods throw errors on failure (no silent failures)
60
+ */
61
+ const CourseCodeAutomationAPI = {
62
+ // ===== Discovery & Interaction Methods =====
63
+ listInteractions: interactionMethods.listInteractions,
64
+ getInteractionMetadata: interactionMethods.getInteractionMetadata,
65
+ getResponse: interactionMethods.getResponse,
66
+ getCorrectResponse: interactionMethods.getCorrectResponse,
67
+ setResponse: interactionMethods.setResponse,
68
+ checkAnswer: interactionMethods.checkAnswer,
69
+ checkSlideAnswers() {
70
+ return interactionMethods.checkSlideAnswers.call(
71
+ interactionMethods,
72
+ () => this.getCurrentSlide()
73
+ );
74
+ },
75
+
76
+ // ===== Navigation Methods =====
77
+
78
+ getToc() {
79
+ const toc = [];
80
+ const flatten = (items) => {
81
+ for (const item of items) {
82
+ if (item.type === 'section') {
83
+ toc.push({ id: item.id, type: 'section', title: item.menu?.label });
84
+ if (item.children) flatten(item.children);
85
+ } else {
86
+ toc.push({ id: item.id, type: item.type, title: item.title, file: item.component });
87
+ }
88
+ }
89
+ };
90
+ flatten(courseConfig.structure);
91
+ logTrace('getToc', { count: toc.length });
92
+ return toc;
93
+ },
94
+
95
+ getCurrentSlide() {
96
+ const currentSlide = NavigationActions.getCurrentSlide();
97
+ logTrace('getCurrentSlide', { slideId: currentSlide?.id });
98
+ return currentSlide?.id || null;
99
+ },
100
+
101
+ async goToSlide(slideId, context = {}) {
102
+ try {
103
+ await NavigationActions.goToSlide(slideId, context);
104
+ logTrace('goToSlide', { slideId, context });
105
+ } catch (error) {
106
+ logTrace('goToSlide:error', { slideId, context, error: error.message });
107
+ throw new Error(`CourseCodeAutomation: Failed to navigate to "${slideId}": ${error.message}`);
108
+ }
109
+ },
110
+
111
+ // ===== Observability Methods =====
112
+
113
+ getAutomationTrace() {
114
+ return [...automationTrace];
115
+ },
116
+
117
+ clearAutomationTrace() {
118
+ const count = automationTrace.length;
119
+ automationTrace.length = 0;
120
+ logTrace('clearAutomationTrace', { clearedCount: count });
121
+ logger.debug(`[CourseCodeAutomation] Cleared ${count} trace entries`);
122
+ },
123
+
124
+ getFrameworkLogs() {
125
+ const logs = frameworkLogs.splice(0);
126
+ logTrace('getFrameworkLogs', { count: logs.length });
127
+ return logs;
128
+ },
129
+
130
+
131
+ // ===== Engagement Methods =====
132
+ getEngagementState: engagementMethods.getEngagementState,
133
+ getEngagementProgress: engagementMethods.getEngagementProgress,
134
+ markTabViewed: engagementMethods.markTabViewed,
135
+ markFlipCardViewed: engagementMethods.markFlipCardViewed,
136
+ setScrollDepth: engagementMethods.setScrollDepth,
137
+ resetEngagement: engagementMethods.resetEngagement,
138
+
139
+ // ===== Flag Management =====
140
+ getFlag: engagementMethods.getFlag,
141
+ setFlag: engagementMethods.setFlag,
142
+ getAllFlags: engagementMethods.getAllFlags,
143
+ removeFlag: engagementMethods.removeFlag,
144
+
145
+ // ===== Audio Methods =====
146
+ getAudioState: engagementMethods.getAudioState,
147
+ hasAudio: engagementMethods.hasAudio,
148
+ simulateAudioComplete: engagementMethods.simulateAudioComplete,
149
+ isAudioCompletedForContext: engagementMethods.isAudioCompletedForContext,
150
+ getAudioProgress: engagementMethods.getAudioProgress,
151
+
152
+ // ===== LMS State =====
153
+
154
+ /**
155
+ * Returns the full LMS data model:
156
+ * - Direct CMI writes: score, completion, success, bookmark
157
+ * - CMI-backed domains: objectives
158
+ * - All suspend_data domains: the full state blob
159
+ */
160
+ getLmsState() {
161
+ const score = stateManager.getScore();
162
+ const completion = stateManager.getCompletion();
163
+ const success = stateManager.getSuccess();
164
+ const bookmark = stateManager.getBookmark();
165
+ const format = stateManager.getFormat();
166
+
167
+ // Objectives from ObjectiveManager (driver-agnostic)
168
+ const rawObjectives = objectiveManager.getObjectives();
169
+ const objectives = {};
170
+ for (const obj of rawObjectives) {
171
+ objectives[obj.id] = {
172
+ completion_status: obj.completion_status,
173
+ success_status: obj.success_status,
174
+ score: obj.score ?? null
175
+ };
176
+ }
177
+
178
+ // Full suspend_data domains
179
+ const state = stateManager.getState();
180
+
181
+ logTrace('getLmsState', { format, hasScore: score !== null });
182
+
183
+ return {
184
+ score,
185
+ completion,
186
+ success,
187
+ bookmark,
188
+ format,
189
+ objectives,
190
+ state
191
+ };
192
+ },
193
+
194
+ // ===== Accessibility / Theme =====
195
+
196
+ /**
197
+ * Set an accessibility preference (theme, highContrast, largeFont, reducedMotion).
198
+ * @param {'theme'|'highContrast'|'largeFont'|'reducedMotion'} key
199
+ * @param {string|boolean} value - 'light'|'dark' for theme, boolean for others
200
+ */
201
+ setAccessibilityPreference(key, value) {
202
+ accessibilityManager.setPreference(key, value);
203
+ logTrace('setAccessibilityPreference', { key, value });
204
+ },
205
+
206
+ /**
207
+ * Get current accessibility state (theme, highContrast, largeFont, reducedMotion).
208
+ */
209
+ getAccessibilityState() {
210
+ const state = { ...accessibilityManager.state };
211
+ logTrace('getAccessibilityState', state);
212
+ return state;
213
+ },
214
+
215
+ // ===== Version Info =====
216
+
217
+ getVersion() {
218
+ return {
219
+ api: '2.2.0',
220
+ phase: 8,
221
+ features: [
222
+ 'discovery',
223
+ 'state-access',
224
+ 'state-mutation',
225
+ 'evaluation',
226
+ 'navigation',
227
+ 'observability',
228
+ 'ergonomic-helpers',
229
+ 'engagement-tracking',
230
+ 'flip-card-tracking',
231
+ 'flag-management',
232
+ 'audio-state',
233
+ 'audio-completion-simulation',
234
+ 'framework-logs',
235
+ 'lms-state',
236
+ 'accessibility-preferences'
237
+ ]
238
+ };
239
+ }
240
+ };
241
+
242
+ export default CourseCodeAutomationAPI;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * @file index.js
3
+ * @description Entry point for the automation module.
4
+ * Initializes and exposes the CourseCodeAutomation API on window.
5
+ *
6
+ * This entire module is ONLY loaded in development/testing mode when:
7
+ * 1. import.meta.env.MODE !== 'production'
8
+ * 2. courseConfig.environment.automation.enabled === true
9
+ *
10
+ * In production builds, Vite's tree-shaking will completely eliminate this code.
11
+ */
12
+
13
+ import CourseCodeAutomationAPI from './api.js';
14
+ import { eventBus } from '../core/event-bus.js';
15
+ import { logger } from '../utilities/logger.js';
16
+
17
+ /**
18
+ * Initializes the automation system
19
+ * - Exposes window.CourseCodeAutomation API
20
+ * - Sets up event listeners for tracking
21
+ */
22
+ export function initializeAutomation() {
23
+ logger.debug('[Automation] Initializing automation system...');
24
+
25
+ // Expose the API globally
26
+ window.CourseCodeAutomation = CourseCodeAutomationAPI;
27
+
28
+ // Log when interactions are registered
29
+ eventBus.on('interaction:registered', ({ id, type }) => {
30
+ logger.debug(`[Automation] ✓ Registered: ${id} (${type || 'unknown'})`);
31
+ });
32
+
33
+ logger.debug('[Automation] ✓ Automation system initialized');
34
+ logger.debug('[Automation] window.CourseCodeAutomation API is now available');
35
+ logger.debug('[Automation] Use window.CourseCodeAutomation.getVersion() for feature info');
36
+
37
+ // Emit initialization event
38
+ eventBus.emit('automation:initialized', {
39
+ version: CourseCodeAutomationAPI.getVersion()
40
+ });
41
+ }