@openedx/frontend-base 1.0.0-alpha.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 (356) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +112 -0
  3. package/config/babel/babel.config.js +28 -0
  4. package/config/config-helpers/createConfig.js +13 -0
  5. package/config/config-helpers/createLintConfig.js +16 -0
  6. package/config/config-helpers/getBaseConfig.js +12 -0
  7. package/config/defaultConfigPaths.js +35 -0
  8. package/config/eslint/base.eslint.config.js +113 -0
  9. package/config/index.js +12 -0
  10. package/config/jest/jest.config.js +30 -0
  11. package/config/tsconfig.json +32 -0
  12. package/config/types.js +25 -0
  13. package/config/webpack/common-config/all/getCodeRules.js +52 -0
  14. package/config/webpack/common-config/all/getFileLoaderRules.js +26 -0
  15. package/config/webpack/common-config/all/getIgnoreWarnings.js +14 -0
  16. package/config/webpack/common-config/all/getImageMinimizer.js +25 -0
  17. package/config/webpack/common-config/all/getStylesheetRule.js +112 -0
  18. package/config/webpack/common-config/dev/getDevServer.js +38 -0
  19. package/config/webpack/common-config/index.js +18 -0
  20. package/config/webpack/common-config/site/getHtmlWebpackPlugin.js +16 -0
  21. package/config/webpack/plugins/html-webpack-new-relic-plugin/HtmlWebpackNewRelicPlugin.js +91 -0
  22. package/config/webpack/plugins/html-webpack-new-relic-plugin/index.js +7 -0
  23. package/config/webpack/plugins/html-webpack-new-relic-plugin/test/fixtures/entry.js +3 -0
  24. package/config/webpack/plugins/paragon-webpack-plugin/ParagonWebpackPlugin.js +108 -0
  25. package/config/webpack/plugins/paragon-webpack-plugin/index.js +7 -0
  26. package/config/webpack/plugins/paragon-webpack-plugin/utils/assetUtils.js +64 -0
  27. package/config/webpack/plugins/paragon-webpack-plugin/utils/htmlUtils.js +53 -0
  28. package/config/webpack/plugins/paragon-webpack-plugin/utils/index.js +9 -0
  29. package/config/webpack/plugins/paragon-webpack-plugin/utils/paragonStylesheetUtils.js +114 -0
  30. package/config/webpack/plugins/paragon-webpack-plugin/utils/scriptUtils.js +146 -0
  31. package/config/webpack/plugins/paragon-webpack-plugin/utils/stylesheetUtils.js +126 -0
  32. package/config/webpack/plugins/paragon-webpack-plugin/utils/tagUtils.js +57 -0
  33. package/config/webpack/types.js +2 -0
  34. package/config/webpack/utils/getLocalAliases.js +65 -0
  35. package/config/webpack/utils/getPublicPath.js +6 -0
  36. package/config/webpack/utils/getResolvedSiteConfigPath.js +32 -0
  37. package/config/webpack/utils/paragonUtils.js +138 -0
  38. package/config/webpack/webpack.config.build.js +80 -0
  39. package/config/webpack/webpack.config.dev.js +76 -0
  40. package/config/webpack/webpack.config.dev.shell.js +110 -0
  41. package/eslint.config.js +18 -0
  42. package/frontend-base.d.ts +8 -0
  43. package/index.ts +7 -0
  44. package/jest.config.js +7 -0
  45. package/openedx-frontend-base.tgz +0 -0
  46. package/package.json +149 -0
  47. package/runtime/analytics/MockAnalyticsService.js +71 -0
  48. package/runtime/analytics/SegmentAnalyticsService.js +243 -0
  49. package/runtime/analytics/index.ts +12 -0
  50. package/runtime/analytics/interface.js +145 -0
  51. package/runtime/auth/AxiosCsrfTokenService.js +60 -0
  52. package/runtime/auth/AxiosJwtAuthService.js +363 -0
  53. package/runtime/auth/AxiosJwtTokenService.js +134 -0
  54. package/runtime/auth/LocalForageCache.js +76 -0
  55. package/runtime/auth/MockAuthService.js +278 -0
  56. package/runtime/auth/index.ts +19 -0
  57. package/runtime/auth/interceptors/createCsrfTokenProviderInterceptor.js +36 -0
  58. package/runtime/auth/interceptors/createJwtTokenProviderInterceptor.js +37 -0
  59. package/runtime/auth/interceptors/createProcessAxiosRequestErrorInterceptor.js +20 -0
  60. package/runtime/auth/interceptors/createRetryInterceptor.js +74 -0
  61. package/runtime/auth/interface.js +309 -0
  62. package/runtime/auth/utils.js +105 -0
  63. package/runtime/babel.config.js +3 -0
  64. package/runtime/config/index.ts +295 -0
  65. package/runtime/constants.ts +68 -0
  66. package/runtime/i18n/index.js +118 -0
  67. package/runtime/i18n/injectIntlWithShim.jsx +48 -0
  68. package/runtime/i18n/lib.ts +272 -0
  69. package/runtime/index.ts +134 -0
  70. package/runtime/initialize.js +352 -0
  71. package/runtime/jest.config.js +32 -0
  72. package/runtime/logging/MockLoggingService.js +31 -0
  73. package/runtime/logging/NewRelicLoggingService.js +184 -0
  74. package/runtime/logging/index.ts +9 -0
  75. package/runtime/logging/interface.js +109 -0
  76. package/runtime/logging/types.ts +4 -0
  77. package/runtime/react/AuthenticatedPageRoute.jsx +43 -0
  78. package/runtime/react/CombinedAppProvider.tsx +46 -0
  79. package/runtime/react/CurrentAppContext.tsx +25 -0
  80. package/runtime/react/CurrentAppProvider.tsx +46 -0
  81. package/runtime/react/Divider.tsx +5 -0
  82. package/runtime/react/ErrorBoundary.jsx +47 -0
  83. package/runtime/react/ErrorPage.jsx +72 -0
  84. package/runtime/react/LoginRedirect.jsx +16 -0
  85. package/runtime/react/PageWrap.jsx +24 -0
  86. package/runtime/react/SiteContext.tsx +32 -0
  87. package/runtime/react/SiteProvider.tsx +78 -0
  88. package/runtime/react/hooks.ts +106 -0
  89. package/runtime/react/index.ts +19 -0
  90. package/runtime/routing/index.ts +1 -0
  91. package/runtime/routing/utils.ts +34 -0
  92. package/runtime/scripts/GoogleAnalyticsLoader.ts +59 -0
  93. package/runtime/scripts/index.ts +1 -0
  94. package/runtime/setupTest.js +49 -0
  95. package/runtime/slots/Slot.tsx +32 -0
  96. package/runtime/slots/SlotContext.tsx +8 -0
  97. package/runtime/slots/hooks.ts +35 -0
  98. package/runtime/slots/index.ts +7 -0
  99. package/runtime/slots/layout/DefaultSlotLayout.tsx +9 -0
  100. package/runtime/slots/layout/hooks.ts +65 -0
  101. package/runtime/slots/layout/index.ts +5 -0
  102. package/runtime/slots/layout/types.ts +45 -0
  103. package/runtime/slots/layout/utils.ts +14 -0
  104. package/runtime/slots/types.ts +23 -0
  105. package/runtime/slots/utils.ts +59 -0
  106. package/runtime/slots/widget/WidgetContext.tsx +9 -0
  107. package/runtime/slots/widget/WidgetProvider.tsx +30 -0
  108. package/runtime/slots/widget/hooks.ts +105 -0
  109. package/runtime/slots/widget/iframe/IFrameContentWrapper.messages.tsx +16 -0
  110. package/runtime/slots/widget/iframe/IFrameContentWrapper.tsx +84 -0
  111. package/runtime/slots/widget/iframe/IFrameWidget.tsx +59 -0
  112. package/runtime/slots/widget/iframe/constants.ts +19 -0
  113. package/runtime/slots/widget/iframe/hooks.ts +179 -0
  114. package/runtime/slots/widget/iframe/index.ts +6 -0
  115. package/runtime/slots/widget/iframe/types.ts +7 -0
  116. package/runtime/slots/widget/index.ts +6 -0
  117. package/runtime/slots/widget/types.ts +134 -0
  118. package/runtime/slots/widget/utils.tsx +201 -0
  119. package/runtime/subscriptions.ts +60 -0
  120. package/runtime/testing/index.ts +9 -0
  121. package/runtime/testing/initializeMockApp.ts +81 -0
  122. package/runtime/testing/mockMessages.ts +23 -0
  123. package/runtime/utils.js +178 -0
  124. package/shell/DefaultLayout.tsx +18 -0
  125. package/shell/DefaultMain.tsx +7 -0
  126. package/shell/Logo.tsx +28 -0
  127. package/shell/Shell.messages.ts +61 -0
  128. package/shell/Shell.tsx +18 -0
  129. package/shell/app.scss +149 -0
  130. package/shell/app.ts +24 -0
  131. package/shell/babel.config.js +3 -0
  132. package/shell/dev/devFooter/app.tsx +43 -0
  133. package/shell/dev/devFooter/index.ts +1 -0
  134. package/shell/dev/devHeader/BarContext.tsx +13 -0
  135. package/shell/dev/devHeader/BarLink.tsx +16 -0
  136. package/shell/dev/devHeader/BarProvider.tsx +25 -0
  137. package/shell/dev/devHeader/CoursesLink.tsx +16 -0
  138. package/shell/dev/devHeader/FooContext.tsx +13 -0
  139. package/shell/dev/devHeader/FooLink.tsx +16 -0
  140. package/shell/dev/devHeader/FooProvider.tsx +25 -0
  141. package/shell/dev/devHeader/app.tsx +53 -0
  142. package/shell/dev/devHeader/index.ts +1 -0
  143. package/shell/dev/devHeader/providers.tsx +11 -0
  144. package/shell/dev/devHome/HomePage.tsx +28 -0
  145. package/shell/dev/devHome/app.ts +18 -0
  146. package/shell/dev/devHome/i18n/index.ts +27 -0
  147. package/shell/dev/devHome/index.ts +1 -0
  148. package/shell/dev/devHome/messages.ts +11 -0
  149. package/shell/dev/devUser/app.tsx +24 -0
  150. package/shell/dev/devUser/index.ts +1 -0
  151. package/shell/dev/index.ts +5 -0
  152. package/shell/dev/slotShowcase/HorizontalSlotLayout.tsx +11 -0
  153. package/shell/dev/slotShowcase/LayoutWithOptions.tsx +17 -0
  154. package/shell/dev/slotShowcase/SlotShowcasePage.tsx +66 -0
  155. package/shell/dev/slotShowcase/WidgetWithOptions.tsx +11 -0
  156. package/shell/dev/slotShowcase/app.tsx +373 -0
  157. package/shell/dev/slotShowcase/index.ts +1 -0
  158. package/shell/footer/CenterLinks.tsx +11 -0
  159. package/shell/footer/CopyrightNotice.tsx +36 -0
  160. package/shell/footer/Footer.tsx +34 -0
  161. package/shell/footer/LabeledLinkColumn.tsx +19 -0
  162. package/shell/footer/LanguageMenu.tsx +35 -0
  163. package/shell/footer/LanguageMenuItem.tsx +23 -0
  164. package/shell/footer/LeftLinks.tsx +11 -0
  165. package/shell/footer/LegalNotices.tsx +17 -0
  166. package/shell/footer/PoweredBy.tsx +17 -0
  167. package/shell/footer/RevealLinks.tsx +43 -0
  168. package/shell/footer/RightLinks.tsx +11 -0
  169. package/shell/footer/app.tsx +73 -0
  170. package/shell/footer/data/api.ts +48 -0
  171. package/shell/footer/index.ts +2 -0
  172. package/shell/header/AuthenticatedMenu.tsx +32 -0
  173. package/shell/header/Header.tsx +17 -0
  174. package/shell/header/anonymous-menu/AnonymousMenu.tsx +14 -0
  175. package/shell/header/anonymous-menu/LoginButton.tsx +14 -0
  176. package/shell/header/anonymous-menu/RegisterButton.tsx +15 -0
  177. package/shell/header/app.tsx +142 -0
  178. package/shell/header/desktop/DesktopLayout.tsx +22 -0
  179. package/shell/header/desktop/PrimaryNavLinks.tsx +10 -0
  180. package/shell/header/desktop/SecondaryNavLinks.tsx +10 -0
  181. package/shell/header/index.ts +2 -0
  182. package/shell/header/mobile/MobileLayout.tsx +47 -0
  183. package/shell/header/mobile/MobileNavLinks.tsx +10 -0
  184. package/shell/i18n/index.ts +25 -0
  185. package/shell/index.ts +7 -0
  186. package/shell/jest.config.js +30 -0
  187. package/shell/menus/LinkMenuItem.tsx +64 -0
  188. package/shell/menus/NavDropdownMenuSlot.tsx +29 -0
  189. package/shell/menus/ProfileLinkMenuItem.tsx +33 -0
  190. package/shell/menus/data/utils.ts +19 -0
  191. package/shell/public/index.html +10 -0
  192. package/shell/router/createRouter.ts +17 -0
  193. package/shell/router/getAppRoutes.ts +21 -0
  194. package/shell/setupTest.js +48 -0
  195. package/shell/site.config.dev.tsx +49 -0
  196. package/shell/site.tsx +41 -0
  197. package/test-site/app.d.ts +15 -0
  198. package/test-site/dist/176.436443549ebb858db483.js +2 -0
  199. package/test-site/dist/176.436443549ebb858db483.js.map +1 -0
  200. package/test-site/dist/362.536eff787d2380fe246c.js +2 -0
  201. package/test-site/dist/362.536eff787d2380fe246c.js.map +1 -0
  202. package/test-site/dist/653.486966b108d224551296.js +2 -0
  203. package/test-site/dist/653.486966b108d224551296.js.map +1 -0
  204. package/test-site/dist/74e025d3fe9a7b7f8503054e2563b353.jpg +0 -0
  205. package/test-site/dist/806.323cf6496ad0a7fe73a7.js +3 -0
  206. package/test-site/dist/806.323cf6496ad0a7fe73a7.js.LICENSE.txt +106 -0
  207. package/test-site/dist/806.323cf6496ad0a7fe73a7.js.map +1 -0
  208. package/test-site/dist/95ec738c0b7faac5b5c9126794446bbd.svg +4 -0
  209. package/test-site/dist/app.612058b36c74787759ac.css +61 -0
  210. package/test-site/dist/app.612058b36c74787759ac.css.map +1 -0
  211. package/test-site/dist/app.612058b36c74787759ac.js +2 -0
  212. package/test-site/dist/app.612058b36c74787759ac.js.map +1 -0
  213. package/test-site/dist/cb28cdb1468c915e27e5cec9af64f22f.svg +1 -0
  214. package/test-site/dist/index.html +1 -0
  215. package/test-site/dist/report.html +39 -0
  216. package/test-site/dist/runtime.c7aeaf7b967496cb076f.js +2 -0
  217. package/test-site/dist/runtime.c7aeaf7b967496cb076f.js.map +1 -0
  218. package/test-site/eslint.config.js +12 -0
  219. package/test-site/package-lock.json +19226 -0
  220. package/test-site/package.json +29 -0
  221. package/test-site/public/index.html +10 -0
  222. package/test-site/site.config.build.tsx +27 -0
  223. package/test-site/site.config.dev.tsx +27 -0
  224. package/test-site/src/authenticated-page/AuthenticatedPage.tsx +18 -0
  225. package/test-site/src/authenticated-page/i18n/index.ts +27 -0
  226. package/test-site/src/authenticated-page/index.tsx +28 -0
  227. package/test-site/src/example-page/ExamplePage.tsx +79 -0
  228. package/test-site/src/example-page/Image.tsx +11 -0
  229. package/test-site/src/example-page/ParagonPreview.jsx +66 -0
  230. package/test-site/src/example-page/apple.jpg +0 -0
  231. package/test-site/src/example-page/apple.svg +1 -0
  232. package/test-site/src/example-page/index.ts +16 -0
  233. package/test-site/src/i18n/README.md +3 -0
  234. package/test-site/src/i18n/messages/frontend-app-sample/ar.json +4 -0
  235. package/test-site/src/i18n/messages/frontend-app-sample/eo.json +1 -0
  236. package/test-site/src/i18n/messages/frontend-app-sample/es_419.json +4 -0
  237. package/test-site/src/i18n/messages/frontend-component-emptylangs/ar.json +1 -0
  238. package/test-site/src/i18n/messages/frontend-component-singlelang/ar.json +3 -0
  239. package/test-site/src/iframe-widget/IframeWidget.tsx +14 -0
  240. package/test-site/src/iframe-widget/index.ts +16 -0
  241. package/test-site/src/index.tsx +3 -0
  242. package/test-site/src/messages.js +11 -0
  243. package/test-site/src/site.scss +11 -0
  244. package/test-site/tsconfig.json +14 -0
  245. package/tools/babel/babel.config.js +27 -0
  246. package/tools/babel.config.js +3 -0
  247. package/tools/cli/README.md +29 -0
  248. package/tools/cli/commands/pack.ts +9 -0
  249. package/tools/cli/commands/release.ts +27 -0
  250. package/tools/cli/commands/serve.ts +43 -0
  251. package/tools/cli/intl-imports.ts +274 -0
  252. package/tools/cli/openedx.ts +101 -0
  253. package/tools/cli/transifex-utils.ts +75 -0
  254. package/tools/cli/utils/ensureConfigFilenameOption.ts +40 -0
  255. package/tools/cli/utils/formatter.ts +10 -0
  256. package/tools/cli/utils/getResolvedConfigPath.ts +23 -0
  257. package/tools/cli/utils/prettyPrintTitle.ts +15 -0
  258. package/tools/cli/utils/printUsage.ts +53 -0
  259. package/tools/config-helpers/createConfig.ts +8 -0
  260. package/tools/config-helpers/createLintConfig.ts +14 -0
  261. package/tools/config-helpers/getBaseConfig.ts +11 -0
  262. package/tools/defaultConfigPaths.ts +30 -0
  263. package/tools/dist/babel/babel.config.js +28 -0
  264. package/tools/dist/cli/commands/pack.js +14 -0
  265. package/tools/dist/cli/commands/release.js +28 -0
  266. package/tools/dist/cli/commands/serve.js +44 -0
  267. package/tools/dist/cli/intl-imports.js +233 -0
  268. package/tools/dist/cli/openedx.js +100 -0
  269. package/tools/dist/cli/transifex-utils.js +68 -0
  270. package/tools/dist/cli/utils/ensureConfigFilenameOption.js +42 -0
  271. package/tools/dist/cli/utils/formatter.js +10 -0
  272. package/tools/dist/cli/utils/getResolvedConfigPath.js +28 -0
  273. package/tools/dist/cli/utils/prettyPrintTitle.js +17 -0
  274. package/tools/dist/cli/utils/printUsage.js +48 -0
  275. package/tools/dist/config-helpers/createConfig.js +13 -0
  276. package/tools/dist/config-helpers/createLintConfig.js +16 -0
  277. package/tools/dist/config-helpers/getBaseConfig.js +12 -0
  278. package/tools/dist/defaultConfigPaths.js +35 -0
  279. package/tools/dist/eslint/base.eslint.config.js +113 -0
  280. package/tools/dist/eslint.config.js +11 -0
  281. package/tools/dist/index.js +12 -0
  282. package/tools/dist/jest/jest.config.js +30 -0
  283. package/tools/dist/jest.config.js +20 -0
  284. package/tools/dist/types.js +25 -0
  285. package/tools/dist/typescript/tsconfig.json +32 -0
  286. package/tools/dist/webpack/common-config/all/getCodeRules.js +52 -0
  287. package/tools/dist/webpack/common-config/all/getFileLoaderRules.js +26 -0
  288. package/tools/dist/webpack/common-config/all/getIgnoreWarnings.js +14 -0
  289. package/tools/dist/webpack/common-config/all/getImageMinimizer.js +25 -0
  290. package/tools/dist/webpack/common-config/all/getStylesheetRule.js +112 -0
  291. package/tools/dist/webpack/common-config/dev/getDevServer.js +38 -0
  292. package/tools/dist/webpack/common-config/index.js +18 -0
  293. package/tools/dist/webpack/common-config/site/getHtmlWebpackPlugin.js +16 -0
  294. package/tools/dist/webpack/plugins/html-webpack-new-relic-plugin/HtmlWebpackNewRelicPlugin.js +91 -0
  295. package/tools/dist/webpack/plugins/html-webpack-new-relic-plugin/index.js +7 -0
  296. package/tools/dist/webpack/plugins/html-webpack-new-relic-plugin/test/fixtures/entry.js +3 -0
  297. package/tools/dist/webpack/plugins/paragon-webpack-plugin/ParagonWebpackPlugin.js +108 -0
  298. package/tools/dist/webpack/plugins/paragon-webpack-plugin/index.js +7 -0
  299. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/assetUtils.js +64 -0
  300. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/htmlUtils.js +53 -0
  301. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/index.js +9 -0
  302. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/paragonStylesheetUtils.js +114 -0
  303. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/scriptUtils.js +146 -0
  304. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/stylesheetUtils.js +126 -0
  305. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/tagUtils.js +57 -0
  306. package/tools/dist/webpack/types.js +2 -0
  307. package/tools/dist/webpack/utils/getLocalAliases.js +65 -0
  308. package/tools/dist/webpack/utils/getPublicPath.js +6 -0
  309. package/tools/dist/webpack/utils/getResolvedSiteConfigPath.js +32 -0
  310. package/tools/dist/webpack/utils/paragonUtils.js +138 -0
  311. package/tools/dist/webpack/webpack.config.build.js +80 -0
  312. package/tools/dist/webpack/webpack.config.dev.js +76 -0
  313. package/tools/dist/webpack/webpack.config.dev.shell.js +110 -0
  314. package/tools/eslint/base.eslint.config.js +124 -0
  315. package/tools/eslint/modules.d.ts +5 -0
  316. package/tools/eslint.config.js +15 -0
  317. package/tools/index.ts +3 -0
  318. package/tools/jest/jest.config.js +30 -0
  319. package/tools/jest.config.js +19 -0
  320. package/tools/tsconfig.json +24 -0
  321. package/tools/types.ts +21 -0
  322. package/tools/typescript/tsconfig.json +32 -0
  323. package/tools/webpack/common-config/README.md +15 -0
  324. package/tools/webpack/common-config/all/getCodeRules.ts +51 -0
  325. package/tools/webpack/common-config/all/getFileLoaderRules.ts +23 -0
  326. package/tools/webpack/common-config/all/getIgnoreWarnings.ts +13 -0
  327. package/tools/webpack/common-config/all/getImageMinimizer.ts +26 -0
  328. package/tools/webpack/common-config/all/getStylesheetRule.ts +111 -0
  329. package/tools/webpack/common-config/dev/getDevServer.ts +35 -0
  330. package/tools/webpack/common-config/index.ts +6 -0
  331. package/tools/webpack/common-config/site/getHtmlWebpackPlugin.ts +11 -0
  332. package/tools/webpack/modules.d.ts +6 -0
  333. package/tools/webpack/plugins/html-webpack-new-relic-plugin/HtmlWebpackNewRelicPlugin.ts +102 -0
  334. package/tools/webpack/plugins/html-webpack-new-relic-plugin/LICENSE +21 -0
  335. package/tools/webpack/plugins/html-webpack-new-relic-plugin/README.md +7 -0
  336. package/tools/webpack/plugins/html-webpack-new-relic-plugin/index.js +3 -0
  337. package/tools/webpack/plugins/html-webpack-new-relic-plugin/test/fixtures/entry.js +1 -0
  338. package/tools/webpack/plugins/paragon-webpack-plugin/ParagonWebpackPlugin.ts +134 -0
  339. package/tools/webpack/plugins/paragon-webpack-plugin/index.ts +3 -0
  340. package/tools/webpack/plugins/paragon-webpack-plugin/utils/assetUtils.ts +71 -0
  341. package/tools/webpack/plugins/paragon-webpack-plugin/utils/htmlUtils.ts +72 -0
  342. package/tools/webpack/plugins/paragon-webpack-plugin/utils/index.ts +6 -0
  343. package/tools/webpack/plugins/paragon-webpack-plugin/utils/paragonStylesheetUtils.ts +131 -0
  344. package/tools/webpack/plugins/paragon-webpack-plugin/utils/scriptUtils.ts +144 -0
  345. package/tools/webpack/plugins/paragon-webpack-plugin/utils/stylesheetUtils.ts +106 -0
  346. package/tools/webpack/plugins/paragon-webpack-plugin/utils/tagUtils.ts +54 -0
  347. package/tools/webpack/types.ts +69 -0
  348. package/tools/webpack/utils/getLocalAliases.ts +65 -0
  349. package/tools/webpack/utils/getPublicPath.ts +3 -0
  350. package/tools/webpack/utils/getResolvedSiteConfigPath.ts +28 -0
  351. package/tools/webpack/utils/paragonUtils.ts +152 -0
  352. package/tools/webpack/webpack.config.build.ts +93 -0
  353. package/tools/webpack/webpack.config.dev.shell.ts +122 -0
  354. package/tools/webpack/webpack.config.dev.ts +90 -0
  355. package/tsconfig.json +23 -0
  356. package/types.ts +99 -0
@@ -0,0 +1,243 @@
1
+ import formurlencoded from 'form-urlencoded';
2
+ import { snakeCaseObject } from '../utils';
3
+
4
+ /**
5
+ * @implements {AnalyticsService}
6
+ * @memberof module:Analytics
7
+ */
8
+ class SegmentAnalyticsService {
9
+ constructor({ httpClient, loggingService, config }) {
10
+ this.loggingService = loggingService;
11
+ this.httpClient = httpClient;
12
+ this.trackingLogApiUrl = `${config.lmsBaseUrl}/event`;
13
+ this.segmentKey = config.segmentKey;
14
+ this.hasIdentifyBeenCalled = false;
15
+ this.segmentInitialized = false;
16
+
17
+ if (this.segmentKey) {
18
+ this.initializeSegment();
19
+ }
20
+ }
21
+
22
+ // The code in this function is from Segment's website, with a few updates:
23
+ // - It uses the segmentKey from the SegmentAnalyticsService instance.
24
+ // - It also saves a "segmentInitialized" variable on the SegmentAnalyticsService instance so
25
+ // that the service can keep track of its own initialization state.
26
+ // Reference:
27
+ // https://segment.com/docs/connections/sources/catalog/libraries/website/javascript/quickstart/
28
+ initializeSegment() {
29
+ // Create a queue, but don't obliterate an existing one!
30
+ global.analytics = global.analytics || [];
31
+ const { analytics } = global;
32
+
33
+ // If the real analytics.js is already on the page return.
34
+ if (analytics.initialize) {
35
+ this.segmentInitialized = true;
36
+ return;
37
+ }
38
+
39
+ // If the snippet was invoked do nothing.
40
+ if (analytics.invoked) {
41
+ this.segmentInitialized = true;
42
+ return;
43
+ }
44
+
45
+ // Invoked flag, to make sure the snippet
46
+ // is never invoked twice.
47
+ analytics.invoked = true;
48
+
49
+ // A list of the methods in Analytics.js to stub.
50
+ analytics.methods = [
51
+ 'trackSubmit',
52
+ 'trackClick',
53
+ 'trackLink',
54
+ 'trackForm',
55
+ 'pageview',
56
+ 'identify',
57
+ 'reset',
58
+ 'group',
59
+ 'track',
60
+ 'ready',
61
+ 'alias',
62
+ 'debug',
63
+ 'page',
64
+ 'once',
65
+ 'off',
66
+ 'on',
67
+ ];
68
+
69
+ // Define a factory to create stubs. These are placeholders
70
+ // for methods in Analytics.js so that you never have to wait
71
+ // for it to load to actually record data. The `method` is
72
+ // stored as the first argument, so we can replay the data.
73
+ analytics.factory = method => (...args) => {
74
+ args.unshift(method);
75
+ analytics.push(args);
76
+ return analytics;
77
+ };
78
+
79
+ // For each of our methods, generate a queueing stub.
80
+ analytics.methods.forEach((key) => {
81
+ analytics[key] = analytics.factory(key);
82
+ });
83
+
84
+ // Define a method to load Analytics.js from our CDN,
85
+ // and that will be sure to only ever load it once.
86
+ analytics.load = (key, options) => {
87
+ // Create an async script element based on your key.
88
+ const script = document.createElement('script');
89
+ script.type = 'text/javascript';
90
+ script.onerror = () => {
91
+ this.segmentInitialized = false;
92
+ const event = new Event('segmentFailed');
93
+ document.dispatchEvent(event);
94
+ };
95
+ script.async = true;
96
+ script.src = `https://cdn.segment.com/analytics.js/v1/${key}/analytics.min.js`;
97
+
98
+ // Insert our script next to the first script element.
99
+ const first = document.getElementsByTagName('script')[0];
100
+ first.parentNode.insertBefore(script, first);
101
+ analytics._loadOptions = options;
102
+
103
+ this.segmentInitialized = true;
104
+ };
105
+
106
+ // Add a version to keep track of what's in the wild.
107
+ analytics.SNIPPET_VERSION = '4.1.0';
108
+
109
+ // Load Analytics.js with your key, which will automatically
110
+ // load the tools you've enabled for your account. Boosh!
111
+ analytics.load(this.segmentKey);
112
+ }
113
+
114
+ /**
115
+ * Checks that identify was first called. Otherwise, logs error.
116
+ *
117
+ */
118
+ checkIdentifyCalled() {
119
+ if (!this.hasIdentifyBeenCalled) {
120
+ this.loggingService.logError('Identify must be called before other tracking events.');
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Logs events to tracking log and downstream.
126
+ * For tracking log event documentation, see
127
+ * https://openedx.atlassian.net/wiki/spaces/AN/pages/13205895/Event+Design+and+Review+Process
128
+ *
129
+ * @param {string} eventName (event_type on backend, but named to match Segment api)
130
+ * @param {Object} properties (event on backend, but named properties to match Segment api)
131
+ * @returns {Promise} The promise returned by HttpClient.post.
132
+ */
133
+ sendTrackingLogEvent(eventName, properties) {
134
+ const snakeEventData = snakeCaseObject(properties, { deep: true });
135
+ const serverData = {
136
+ event_type: eventName,
137
+ event: JSON.stringify(snakeEventData),
138
+ page: global.location.href,
139
+ };
140
+ return this.httpClient.post(
141
+ this.trackingLogApiUrl,
142
+ formurlencoded(serverData),
143
+ {
144
+ headers: {
145
+ 'Content-Type': 'application/x-www-form-urlencoded',
146
+ },
147
+ },
148
+ ).catch((error) => {
149
+ this.loggingService.logError(error);
150
+ });
151
+ }
152
+
153
+ /**
154
+ * * Send identify call to Segment.
155
+ *
156
+ * @param {string} userId
157
+ * @param {*} [traits]
158
+ */
159
+ identifyAuthenticatedUser(userId, traits) {
160
+ if (!userId) {
161
+ throw new Error('UserId is required for identifyAuthenticatedUser.');
162
+ }
163
+
164
+ if (!this.segmentInitialized) {
165
+ return;
166
+ }
167
+ global.analytics.identify(userId, traits);
168
+ this.hasIdentifyBeenCalled = true;
169
+ }
170
+
171
+ /**
172
+ * Send anonymous identify call to Segment's identify.
173
+ *
174
+ * @param {*} [traits]
175
+ * @returns {Promise} Promise that will resolve once the document readyState is complete
176
+ */
177
+ identifyAnonymousUser(traits) { // eslint-disable-line @typescript-eslint/no-unused-vars
178
+ if (!this.segmentInitialized) {
179
+ return Promise.resolve();
180
+ }
181
+ // if we do not have an authenticated user (indicated by being in this method),
182
+ // but we still have a user id associated in segment, reset the local segment state
183
+ // This has to be wrapped in the analytics.ready() callback because the analytics.user()
184
+ // function isn't available until the analytics.js package has finished initializing.
185
+ return new Promise((resolve, reject) => { // eslint-disable-line @typescript-eslint/no-unused-vars
186
+ global.analytics.ready(() => {
187
+ if (global.analytics.user().id()) {
188
+ global.analytics.reset();
189
+ }
190
+ // We don’t need to call `identify` for anonymous users and can just make the value of
191
+ // hasIdentifyBeenCalled true. Segment automatically assigns them an anonymousId, so
192
+ // just calling `page` and `track` works fine without identify.
193
+ this.hasIdentifyBeenCalled = true;
194
+ resolve();
195
+ });
196
+
197
+ // this is added to handle a specific use-case where if a user has blocked the analytics
198
+ // tools in their browser, this promise does not get resolved and user sees a blank
199
+ // page. Dispatching this event in script.onerror callback in analytics.load.
200
+ document.addEventListener('segmentFailed', resolve);
201
+ // This is added to handle the google analytics blocked case which is injected into
202
+ // the DOM by segment.min.js.
203
+ setTimeout(() => {
204
+ if (!global.ga?.create || !global.google_tag_manager) {
205
+ this.segmentInitialized = false;
206
+ resolve();
207
+ }
208
+ }, 2000);
209
+ });
210
+ }
211
+
212
+ /**
213
+ * Sends a track event to Segment and downstream.
214
+ * Note: For links and forms, you should use trackLink and trackForm instead.
215
+ *
216
+ * @param {*} eventName
217
+ * @param {*} [properties]
218
+ */
219
+ sendTrackEvent(eventName, properties) {
220
+ if (!this.segmentInitialized) {
221
+ return;
222
+ }
223
+ this.checkIdentifyCalled();
224
+ global.analytics.track(eventName, properties);
225
+ }
226
+
227
+ /**
228
+ * Sends a page event to Segment and downstream.
229
+ *
230
+ * @param {*} [name] If only one string arg provided, assumed to be name.
231
+ * @param {*} [category] Name is required to pass a category.
232
+ * @param {*} [properties]
233
+ */
234
+ sendPageEvent(category, name, properties) {
235
+ if (!this.segmentInitialized) {
236
+ return;
237
+ }
238
+ this.checkIdentifyCalled();
239
+ global.analytics.page(category, name, properties);
240
+ }
241
+ }
242
+
243
+ export default SegmentAnalyticsService;
@@ -0,0 +1,12 @@
1
+ export {
2
+ configureAnalytics,
3
+ getAnalyticsService,
4
+ identifyAnonymousUser,
5
+ identifyAuthenticatedUser,
6
+ resetAnalyticsService,
7
+ sendPageEvent,
8
+ sendTrackEvent,
9
+ sendTrackingLogEvent
10
+ } from './interface';
11
+ export { default as MockAnalyticsService } from './MockAnalyticsService';
12
+ export { default as SegmentAnalyticsService } from './SegmentAnalyticsService';
@@ -0,0 +1,145 @@
1
+ /**
2
+ * #### Import members from **@openedx/frontend-base** Analytics
3
+ *
4
+ * Contains a shared interface for tracking events. Has a default implementation of
5
+ * SegmentAnalyticsService, which supports Segment and the Tracking Log API (hosted in LMS).
6
+ *
7
+ * The `initialize` function performs much of the analytics configuration for you. If, however,
8
+ * you're not using the `initialize` function, analytics can be configured via:
9
+ *
10
+ * ```
11
+ * import {
12
+ * getSiteConfig,
13
+ * getAuthenticatedHttpClient,
14
+ * getLoggingService,
15
+ * configureAnalytics,
16
+ * SegmentAnalyticsService
17
+ * } from '@openedx/frontend-base';
18
+ *
19
+ * configureAnalytics(SegmentAnalyticsService, {
20
+ * config: getSiteConfig(),
21
+ * loggingService: getLoggingService(),
22
+ * httpClient: getAuthenticatedHttpClient(),
23
+ * });
24
+ * ```
25
+ *
26
+ * As shown in this example, analytics depends on the configuration document, logging, and having
27
+ * an authenticated HTTP client.
28
+ *
29
+ * @module Analytics
30
+ */
31
+ import PropTypes from 'prop-types';
32
+
33
+ const optionsShape = {
34
+ config: PropTypes.object.isRequired,
35
+ httpClient: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired,
36
+ loggingService: PropTypes.shape({
37
+ logError: PropTypes.func.isRequired,
38
+ logInfo: PropTypes.func.isRequired,
39
+ }).isRequired,
40
+ };
41
+
42
+ const serviceShape = {
43
+ sendTrackingLogEvent: PropTypes.func.isRequired,
44
+ identifyAuthenticatedUser: PropTypes.func.isRequired,
45
+ identifyAnonymousUser: PropTypes.func.isRequired,
46
+ sendTrackEvent: PropTypes.func.isRequired,
47
+ sendPageEvent: PropTypes.func.isRequired,
48
+ };
49
+
50
+ let service;
51
+
52
+ /**
53
+ *
54
+ * @param {class} AnalyticsService
55
+ * @param {*} options
56
+ * @returns {AnalyticsService}
57
+ */
58
+ export function configureAnalytics(AnalyticsService, options) {
59
+ PropTypes.checkPropTypes(optionsShape, options, 'property', 'Analytics');
60
+ service = new AnalyticsService(options);
61
+ PropTypes.checkPropTypes(serviceShape, service, 'property', 'AnalyticsService');
62
+ return service;
63
+ }
64
+
65
+ /**
66
+ *
67
+ * @param {*} eventName
68
+ * @param {*} properties
69
+ * @returns {Promise}
70
+ */
71
+ export function sendTrackingLogEvent(eventName, properties) {
72
+ return service.sendTrackingLogEvent(eventName, properties);
73
+ }
74
+
75
+ /**
76
+ *
77
+ *
78
+ * @param {*} userId
79
+ * @param {*} traits
80
+ */
81
+ export function identifyAuthenticatedUser(userId, traits) {
82
+ service.identifyAuthenticatedUser(userId, traits);
83
+ }
84
+
85
+ /**
86
+ *
87
+ *
88
+ * @param {*} traits
89
+ * @returns {Promise}
90
+ */
91
+ export function identifyAnonymousUser(traits) {
92
+ return service.identifyAnonymousUser(traits);
93
+ }
94
+
95
+ /**
96
+ *
97
+ *
98
+ * @param {*} eventName
99
+ * @param {*} properties
100
+ */
101
+ export function sendTrackEvent(eventName, properties) {
102
+ service.sendTrackEvent(eventName, properties);
103
+ }
104
+
105
+ /**
106
+ *
107
+ *
108
+ * @param {*} category
109
+ * @param {*} name
110
+ * @param {*} properties
111
+ */
112
+ export function sendPageEvent(category, name, properties) {
113
+ service.sendPageEvent(category, name, properties);
114
+ }
115
+
116
+ /**
117
+ *
118
+ *
119
+ * @returns {AnalyticsService}
120
+ */
121
+ export function getAnalyticsService() {
122
+ if (!service) {
123
+ throw Error('You must first configure the analytics service.');
124
+ }
125
+
126
+ return service;
127
+ }
128
+
129
+ /**
130
+ *
131
+ */
132
+ export function resetAnalyticsService() {
133
+ service = null;
134
+ }
135
+
136
+ /**
137
+ * @name AnalyticsService
138
+ * @interface
139
+ * @memberof module:Analytics
140
+ * @property {function} identifyAnonymousUser
141
+ * @property {function} identifyAuthenticatedUser
142
+ * @property {function} sendPageEvent
143
+ * @property {function} sendTrackEvent
144
+ * @property {function} sendTrackingLogEvent
145
+ */
@@ -0,0 +1,60 @@
1
+ import axios from 'axios';
2
+ import { getUrlParts, processAxiosErrorAndThrow } from './utils';
3
+
4
+ export default class AxiosCsrfTokenService {
5
+ constructor(csrfTokenApiPath) {
6
+ this.csrfTokenApiPath = csrfTokenApiPath;
7
+ this.httpClient = axios.create();
8
+ // Set withCredentials to true. Enables cross-site Access-Control requests
9
+ // to be made using cookies, authorization headers or TLS client
10
+ // certificates. More on MDN:
11
+ // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials
12
+ this.httpClient.defaults.withCredentials = true;
13
+ this.httpClient.defaults.headers['USE-JWT-COOKIE'] = true;
14
+
15
+ this.csrfTokenCache = {};
16
+ this.csrfTokenRequestPromises = {};
17
+ }
18
+
19
+ async getCsrfToken(url) {
20
+ let urlParts;
21
+ try {
22
+ urlParts = getUrlParts(url);
23
+ } catch (e) {
24
+ // If the url is not parsable it's likely because a relative
25
+ // path was supplied as the url. This is acceptable and in
26
+ // this case we should use the current origin of the page.
27
+ urlParts = getUrlParts(global.location.origin);
28
+ }
29
+
30
+ const { protocol, domain } = urlParts;
31
+ const csrfToken = this.csrfTokenCache[domain];
32
+
33
+ if (csrfToken) {
34
+ return csrfToken;
35
+ }
36
+
37
+ if (!this.csrfTokenRequestPromises[domain]) {
38
+ this.csrfTokenRequestPromises[domain] = this.httpClient
39
+ .get(`${protocol}://${domain}${this.csrfTokenApiPath}`)
40
+ .then((response) => {
41
+ this.csrfTokenCache[domain] = response.data.csrfToken;
42
+ return this.csrfTokenCache[domain];
43
+ })
44
+ .catch(processAxiosErrorAndThrow)
45
+ .finally(() => {
46
+ delete this.csrfTokenRequestPromises[domain];
47
+ });
48
+ }
49
+
50
+ return this.csrfTokenRequestPromises[domain];
51
+ }
52
+
53
+ clearCsrfTokenCache() {
54
+ this.csrfTokenCache = {};
55
+ }
56
+
57
+ getHttpClient() {
58
+ return this.httpClient;
59
+ }
60
+ }