@edx/frontend-platform 3.0.0 → 3.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.
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
- [![Build Status](https://github.com/edx/frontend-platform/actions/workflows/ci.yml/badge.svg)](https://github.com/edx/frontend-platform/actions/workflows/ci.yml)
1
+ [![Build Status](https://github.com/openedx/frontend-platform/actions/workflows/ci.yml/badge.svg)](https://github.com/openedx/frontend-platform/actions/workflows/ci.yml)
2
2
  [![Codecov](https://img.shields.io/codecov/c/github/edx/frontend-platform)](https://codecov.io/gh/edx/frontend-platform)
3
3
  [![NPM Version](https://img.shields.io/npm/v/@edx/frontend-platform.svg)](https://www.npmjs.com/package/@edx/frontend-platform)
4
4
  [![npm_downloads](https://img.shields.io/npm/dt/@edx/frontend-platform.svg)](https://www.npmjs.com/package/@edx/frontend-platform)
5
- [![license](https://img.shields.io/npm/l/@edx/frontend-platform.svg)](https://github.com/edx/frontend-platform/blob/master/LICENSE)
5
+ [![license](https://img.shields.io/npm/l/@edx/frontend-platform.svg)](https://github.com/openedx/frontend-platform/blob/master/LICENSE)
6
6
  [![semantic release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
7
7
 
8
8
  # Overview
@@ -27,7 +27,7 @@ In addition, frontend-platform provides an extensible application initialization
27
27
 
28
28
  ### One-time setup if you have not ugpraded node/npm
29
29
  IMPORTANT: There is now a new node/npm version being used by frontend-platform as of
30
- https://github.com/edx/frontend-platform/pull/259
30
+ https://github.com/openedx/frontend-platform/pull/259
31
31
 
32
32
  #### Install nvm
33
33
  This is highly recommended in order to be able to leverage different node/npm versions.
@@ -132,8 +132,24 @@ The included service implementations are:
132
132
 
133
133
  NOTE: As of this writing, i18n is _not_ configurable. The `initialize()` function does not allow applications to supply an alternate i18n implementation; this is because the interface and implementation for i18n has not yet been separated and modularized.
134
134
 
135
- # Local development & testing locally
135
+ # Local Development & Testing Locally
136
136
 
137
137
  When making changes to frontend-platform, be sure to manually run the included example app located in `./example`. The example app includes 2 routes to test for both unauthenticated and authenticated users. To start the example app, run `npm start` from the root directory.
138
138
 
139
- If you want to test changes to frontend-platform against a micro-frontend locally, follow the directions here: https://github.com/edx/frontend-build#local-module-configuration-for-webpack
139
+ If you want to test changes to frontend-platform against a micro-frontend locally, follow the directions here: https://github.com/openedx/frontend-build#local-module-configuration-for-webpack
140
+
141
+ # Production Deployment Strategy
142
+
143
+ For any MFE built on top of the frontend-platform, the deployment strategy will be something like the following:
144
+
145
+ 1. Run the build script with environment variables on the command line to pass in any relevant config. Example:
146
+
147
+ ```bash
148
+ NODE_ENV=development BASE_URL=open.edx.org ETC=etc npm run build
149
+ ```
150
+
151
+ This will create a dist/ directory that contains the deployable artifacts.
152
+
153
+ 2. Copy the contents of dist/ to a web server.
154
+
155
+ 3. Configure the platform to point at your MFE. (details on this coming soon)
@@ -188,6 +188,7 @@ var SegmentAnalyticsService = /*#__PURE__*/function () {
188
188
  value: function identifyAnonymousUser(traits) {
189
189
  var _this3 = this;
190
190
 
191
+ // eslint-disable-line no-unused-vars
191
192
  if (!this.segmentInitialized) {
192
193
  return Promise.resolve();
193
194
  } // if we do not have an authenticated user (indicated by being in this method),
@@ -201,9 +202,11 @@ var SegmentAnalyticsService = /*#__PURE__*/function () {
201
202
  global.analytics.ready(function () {
202
203
  if (global.analytics.user().id()) {
203
204
  global.analytics.reset();
204
- }
205
+ } // We don’t need to call `identify` for anonymous users and can just make the value of
206
+ // hasIdentifyBeenCalled true. Segment automatically assigns them an anonymousId, so
207
+ // just calling `page` and `track` works fine without identify.
208
+
205
209
 
206
- global.analytics.identify(traits);
207
210
  _this3.hasIdentifyBeenCalled = true;
208
211
  resolve();
209
212
  }); // this is added to handle a specific use-case where if a user has blocked the analytics
@@ -1 +1 @@
1
- {"version":3,"file":"SegmentAnalyticsService.js","names":["formurlencoded","snakeCaseObject","SegmentAnalyticsService","httpClient","loggingService","config","trackingLogApiUrl","LMS_BASE_URL","segmentKey","SEGMENT_KEY","hasIdentifyBeenCalled","segmentInitialized","initializeSegment","global","analytics","initialize","invoked","methods","factory","method","args","unshift","push","forEach","key","load","options","script","document","createElement","type","onerror","event","Event","dispatchEvent","async","src","first","getElementsByTagName","parentNode","insertBefore","_loadOptions","SNIPPET_VERSION","logError","eventName","properties","snakeEventData","deep","serverData","event_type","JSON","stringify","page","location","href","post","headers","error","userId","traits","Error","identify","Promise","resolve","reject","ready","user","id","reset","addEventListener","setTimeout","ga","create","google_tag_manager","checkIdentifyCalled","track","category","name"],"sources":["../../src/analytics/SegmentAnalyticsService.js"],"sourcesContent":["import formurlencoded from 'form-urlencoded';\nimport { snakeCaseObject } from '../utils';\n\n/**\n * @implements {AnalyticsService}\n * @memberof module:Analytics\n */\nclass SegmentAnalyticsService {\n constructor({ httpClient, loggingService, config }) {\n this.loggingService = loggingService;\n this.httpClient = httpClient;\n this.trackingLogApiUrl = `${config.LMS_BASE_URL}/event`;\n this.segmentKey = config.SEGMENT_KEY;\n this.hasIdentifyBeenCalled = false;\n this.segmentInitialized = false;\n\n if (this.segmentKey) {\n this.initializeSegment();\n }\n }\n\n // The code in this function is from Segment's website, with a few updates:\n // - It uses the segmentKey from the SegmentAnalyticsService instance.\n // - It also saves a \"segmentInitialized\" variable on the SegmentAnalyticsService instance so\n // that the service can keep track of its own initialization state.\n // Reference:\n // https://segment.com/docs/connections/sources/catalog/libraries/website/javascript/quickstart/\n initializeSegment() {\n // Create a queue, but don't obliterate an existing one!\n global.analytics = global.analytics || [];\n const { analytics } = global;\n\n // If the real analytics.js is already on the page return.\n if (analytics.initialize) {\n this.segmentInitialized = true;\n return;\n }\n\n // If the snippet was invoked do nothing.\n if (analytics.invoked) {\n this.segmentInitialized = true;\n return;\n }\n\n // Invoked flag, to make sure the snippet\n // is never invoked twice.\n analytics.invoked = true;\n\n // A list of the methods in Analytics.js to stub.\n analytics.methods = [\n 'trackSubmit',\n 'trackClick',\n 'trackLink',\n 'trackForm',\n 'pageview',\n 'identify',\n 'reset',\n 'group',\n 'track',\n 'ready',\n 'alias',\n 'debug',\n 'page',\n 'once',\n 'off',\n 'on',\n ];\n\n // Define a factory to create stubs. These are placeholders\n // for methods in Analytics.js so that you never have to wait\n // for it to load to actually record data. The `method` is\n // stored as the first argument, so we can replay the data.\n analytics.factory = method => ((...args) => {\n args.unshift(method);\n analytics.push(args);\n return analytics;\n });\n\n // For each of our methods, generate a queueing stub.\n analytics.methods.forEach((key) => {\n analytics[key] = analytics.factory(key);\n });\n\n // Define a method to load Analytics.js from our CDN,\n // and that will be sure to only ever load it once.\n analytics.load = (key, options) => {\n // Create an async script element based on your key.\n const script = document.createElement('script');\n script.type = 'text/javascript';\n script.onerror = () => {\n this.segmentInitialized = false;\n const event = new Event('segmentFailed');\n document.dispatchEvent(event);\n };\n script.async = true;\n script.src = `https://cdn.segment.com/analytics.js/v1/${key}/analytics.min.js`;\n\n // Insert our script next to the first script element.\n const first = document.getElementsByTagName('script')[0];\n first.parentNode.insertBefore(script, first);\n analytics._loadOptions = options; // eslint-disable-line no-underscore-dangle\n\n this.segmentInitialized = true;\n };\n\n // Add a version to keep track of what's in the wild.\n analytics.SNIPPET_VERSION = '4.1.0';\n\n // Load Analytics.js with your key, which will automatically\n // load the tools you've enabled for your account. Boosh!\n analytics.load(this.segmentKey);\n }\n\n /**\n * Checks that identify was first called. Otherwise, logs error.\n *\n */\n checkIdentifyCalled() {\n if (!this.hasIdentifyBeenCalled) {\n this.loggingService.logError('Identify must be called before other tracking events.');\n }\n }\n\n /**\n * Logs events to tracking log and downstream.\n * For tracking log event documentation, see\n * https://openedx.atlassian.net/wiki/spaces/AN/pages/13205895/Event+Design+and+Review+Process\n *\n * @param {string} eventName (event_type on backend, but named to match Segment api)\n * @param {Object} properties (event on backend, but named properties to match Segment api)\n * @returns {Promise} The promise returned by HttpClient.post.\n */\n sendTrackingLogEvent(eventName, properties) {\n const snakeEventData = snakeCaseObject(properties, { deep: true });\n const serverData = {\n event_type: eventName,\n event: JSON.stringify(snakeEventData),\n page: global.location.href,\n };\n return this.httpClient.post(\n this.trackingLogApiUrl,\n formurlencoded(serverData),\n {\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n },\n ).catch((error) => {\n this.loggingService.logError(error);\n });\n }\n\n /**\n * * Send identify call to Segment.\n *\n * @param {string} userId\n * @param {*} [traits]\n */\n identifyAuthenticatedUser(userId, traits) {\n if (!userId) {\n throw new Error('UserId is required for identifyAuthenticatedUser.');\n }\n\n if (!this.segmentInitialized) {\n return;\n }\n global.analytics.identify(userId, traits);\n this.hasIdentifyBeenCalled = true;\n }\n\n /**\n * Send anonymous identify call to Segment's identify.\n *\n * @param {*} [traits]\n * @returns {Promise} Promise that will resolve once the document readyState is complete\n */\n identifyAnonymousUser(traits) {\n if (!this.segmentInitialized) {\n return Promise.resolve();\n }\n // if we do not have an authenticated user (indicated by being in this method),\n // but we still have a user id associated in segment, reset the local segment state\n // This has to be wrapped in the analytics.ready() callback because the analytics.user()\n // function isn't available until the analytics.js package has finished initializing.\n return new Promise((resolve, reject) => { // eslint-disable-line no-unused-vars\n global.analytics.ready(() => {\n if (global.analytics.user().id()) {\n global.analytics.reset();\n }\n global.analytics.identify(traits);\n this.hasIdentifyBeenCalled = true;\n resolve();\n });\n\n // this is added to handle a specific use-case where if a user has blocked the analytics\n // tools in their browser, this promise does not get resolved and user sees a blank\n // page. Dispatching this event in script.onerror callback in analytics.load.\n document.addEventListener('segmentFailed', resolve);\n // This is added to handle the google analytics blocked case which is injected into\n // the DOM by segment.min.js.\n setTimeout(() => {\n if (!global.ga || !global.ga.create || !global.google_tag_manager) {\n this.segmentInitialized = false;\n resolve();\n }\n }, 2000);\n });\n }\n\n /**\n * Sends a track event to Segment and downstream.\n * Note: For links and forms, you should use trackLink and trackForm instead.\n *\n * @param {*} eventName\n * @param {*} [properties]\n */\n sendTrackEvent(eventName, properties) {\n if (!this.segmentInitialized) {\n return;\n }\n this.checkIdentifyCalled();\n global.analytics.track(eventName, properties);\n }\n\n /**\n * Sends a page event to Segment and downstream.\n *\n * @param {*} [name] If only one string arg provided, assumed to be name.\n * @param {*} [category] Name is required to pass a category.\n * @param {*} [properties]\n */\n sendPageEvent(category, name, properties) {\n if (!this.segmentInitialized) {\n return;\n }\n this.checkIdentifyCalled();\n global.analytics.page(category, name, properties);\n }\n}\n\nexport default SegmentAnalyticsService;\n"],"mappings":"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"}
1
+ {"version":3,"file":"SegmentAnalyticsService.js","names":["formurlencoded","snakeCaseObject","SegmentAnalyticsService","httpClient","loggingService","config","trackingLogApiUrl","LMS_BASE_URL","segmentKey","SEGMENT_KEY","hasIdentifyBeenCalled","segmentInitialized","initializeSegment","global","analytics","initialize","invoked","methods","factory","method","args","unshift","push","forEach","key","load","options","script","document","createElement","type","onerror","event","Event","dispatchEvent","async","src","first","getElementsByTagName","parentNode","insertBefore","_loadOptions","SNIPPET_VERSION","logError","eventName","properties","snakeEventData","deep","serverData","event_type","JSON","stringify","page","location","href","post","headers","error","userId","traits","Error","identify","Promise","resolve","reject","ready","user","id","reset","addEventListener","setTimeout","ga","create","google_tag_manager","checkIdentifyCalled","track","category","name"],"sources":["../../src/analytics/SegmentAnalyticsService.js"],"sourcesContent":["import formurlencoded from 'form-urlencoded';\nimport { snakeCaseObject } from '../utils';\n\n/**\n * @implements {AnalyticsService}\n * @memberof module:Analytics\n */\nclass SegmentAnalyticsService {\n constructor({ httpClient, loggingService, config }) {\n this.loggingService = loggingService;\n this.httpClient = httpClient;\n this.trackingLogApiUrl = `${config.LMS_BASE_URL}/event`;\n this.segmentKey = config.SEGMENT_KEY;\n this.hasIdentifyBeenCalled = false;\n this.segmentInitialized = false;\n\n if (this.segmentKey) {\n this.initializeSegment();\n }\n }\n\n // The code in this function is from Segment's website, with a few updates:\n // - It uses the segmentKey from the SegmentAnalyticsService instance.\n // - It also saves a \"segmentInitialized\" variable on the SegmentAnalyticsService instance so\n // that the service can keep track of its own initialization state.\n // Reference:\n // https://segment.com/docs/connections/sources/catalog/libraries/website/javascript/quickstart/\n initializeSegment() {\n // Create a queue, but don't obliterate an existing one!\n global.analytics = global.analytics || [];\n const { analytics } = global;\n\n // If the real analytics.js is already on the page return.\n if (analytics.initialize) {\n this.segmentInitialized = true;\n return;\n }\n\n // If the snippet was invoked do nothing.\n if (analytics.invoked) {\n this.segmentInitialized = true;\n return;\n }\n\n // Invoked flag, to make sure the snippet\n // is never invoked twice.\n analytics.invoked = true;\n\n // A list of the methods in Analytics.js to stub.\n analytics.methods = [\n 'trackSubmit',\n 'trackClick',\n 'trackLink',\n 'trackForm',\n 'pageview',\n 'identify',\n 'reset',\n 'group',\n 'track',\n 'ready',\n 'alias',\n 'debug',\n 'page',\n 'once',\n 'off',\n 'on',\n ];\n\n // Define a factory to create stubs. These are placeholders\n // for methods in Analytics.js so that you never have to wait\n // for it to load to actually record data. The `method` is\n // stored as the first argument, so we can replay the data.\n analytics.factory = method => ((...args) => {\n args.unshift(method);\n analytics.push(args);\n return analytics;\n });\n\n // For each of our methods, generate a queueing stub.\n analytics.methods.forEach((key) => {\n analytics[key] = analytics.factory(key);\n });\n\n // Define a method to load Analytics.js from our CDN,\n // and that will be sure to only ever load it once.\n analytics.load = (key, options) => {\n // Create an async script element based on your key.\n const script = document.createElement('script');\n script.type = 'text/javascript';\n script.onerror = () => {\n this.segmentInitialized = false;\n const event = new Event('segmentFailed');\n document.dispatchEvent(event);\n };\n script.async = true;\n script.src = `https://cdn.segment.com/analytics.js/v1/${key}/analytics.min.js`;\n\n // Insert our script next to the first script element.\n const first = document.getElementsByTagName('script')[0];\n first.parentNode.insertBefore(script, first);\n analytics._loadOptions = options; // eslint-disable-line no-underscore-dangle\n\n this.segmentInitialized = true;\n };\n\n // Add a version to keep track of what's in the wild.\n analytics.SNIPPET_VERSION = '4.1.0';\n\n // Load Analytics.js with your key, which will automatically\n // load the tools you've enabled for your account. Boosh!\n analytics.load(this.segmentKey);\n }\n\n /**\n * Checks that identify was first called. Otherwise, logs error.\n *\n */\n checkIdentifyCalled() {\n if (!this.hasIdentifyBeenCalled) {\n this.loggingService.logError('Identify must be called before other tracking events.');\n }\n }\n\n /**\n * Logs events to tracking log and downstream.\n * For tracking log event documentation, see\n * https://openedx.atlassian.net/wiki/spaces/AN/pages/13205895/Event+Design+and+Review+Process\n *\n * @param {string} eventName (event_type on backend, but named to match Segment api)\n * @param {Object} properties (event on backend, but named properties to match Segment api)\n * @returns {Promise} The promise returned by HttpClient.post.\n */\n sendTrackingLogEvent(eventName, properties) {\n const snakeEventData = snakeCaseObject(properties, { deep: true });\n const serverData = {\n event_type: eventName,\n event: JSON.stringify(snakeEventData),\n page: global.location.href,\n };\n return this.httpClient.post(\n this.trackingLogApiUrl,\n formurlencoded(serverData),\n {\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n },\n ).catch((error) => {\n this.loggingService.logError(error);\n });\n }\n\n /**\n * * Send identify call to Segment.\n *\n * @param {string} userId\n * @param {*} [traits]\n */\n identifyAuthenticatedUser(userId, traits) {\n if (!userId) {\n throw new Error('UserId is required for identifyAuthenticatedUser.');\n }\n\n if (!this.segmentInitialized) {\n return;\n }\n global.analytics.identify(userId, traits);\n this.hasIdentifyBeenCalled = true;\n }\n\n /**\n * Send anonymous identify call to Segment's identify.\n *\n * @param {*} [traits]\n * @returns {Promise} Promise that will resolve once the document readyState is complete\n */\n identifyAnonymousUser(traits) { // eslint-disable-line no-unused-vars\n if (!this.segmentInitialized) {\n return Promise.resolve();\n }\n // if we do not have an authenticated user (indicated by being in this method),\n // but we still have a user id associated in segment, reset the local segment state\n // This has to be wrapped in the analytics.ready() callback because the analytics.user()\n // function isn't available until the analytics.js package has finished initializing.\n return new Promise((resolve, reject) => { // eslint-disable-line no-unused-vars\n global.analytics.ready(() => {\n if (global.analytics.user().id()) {\n global.analytics.reset();\n }\n // We don’t need to call `identify` for anonymous users and can just make the value of\n // hasIdentifyBeenCalled true. Segment automatically assigns them an anonymousId, so\n // just calling `page` and `track` works fine without identify.\n this.hasIdentifyBeenCalled = true;\n resolve();\n });\n\n // this is added to handle a specific use-case where if a user has blocked the analytics\n // tools in their browser, this promise does not get resolved and user sees a blank\n // page. Dispatching this event in script.onerror callback in analytics.load.\n document.addEventListener('segmentFailed', resolve);\n // This is added to handle the google analytics blocked case which is injected into\n // the DOM by segment.min.js.\n setTimeout(() => {\n if (!global.ga || !global.ga.create || !global.google_tag_manager) {\n this.segmentInitialized = false;\n resolve();\n }\n }, 2000);\n });\n }\n\n /**\n * Sends a track event to Segment and downstream.\n * Note: For links and forms, you should use trackLink and trackForm instead.\n *\n * @param {*} eventName\n * @param {*} [properties]\n */\n sendTrackEvent(eventName, properties) {\n if (!this.segmentInitialized) {\n return;\n }\n this.checkIdentifyCalled();\n global.analytics.track(eventName, properties);\n }\n\n /**\n * Sends a page event to Segment and downstream.\n *\n * @param {*} [name] If only one string arg provided, assumed to be name.\n * @param {*} [category] Name is required to pass a category.\n * @param {*} [properties]\n */\n sendPageEvent(category, name, properties) {\n if (!this.segmentInitialized) {\n return;\n }\n this.checkIdentifyCalled();\n global.analytics.page(category, name, properties);\n }\n}\n\nexport default SegmentAnalyticsService;\n"],"mappings":"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"}
package/auth/interface.js CHANGED
@@ -11,7 +11,7 @@ function _asyncToGenerator(fn) { return function () { var self = this, args = ar
11
11
  *
12
12
  * Simplifies the process of making authenticated API requests to backend edX services by providing
13
13
  * common authN/authZ client code that enables the login/logout flow and handles ensuring the
14
- * presence of a valid [JWT cookie](https://github.com/edx/edx-platform/blob/master/openedx/core/djangoapps/oauth_dispatch/docs/decisions/0009-jwt-in-session-cookie.rst).
14
+ * presence of a valid [JWT cookie](https://github.com/openedx/edx-platform/blob/master/openedx/core/djangoapps/oauth_dispatch/docs/decisions/0009-jwt-in-session-cookie.rst).
15
15
  *
16
16
  * The `initialize` function performs much of the auth configuration for you. If, however, you're
17
17
  * not using the `initialize` function, an authenticated API client can be created via:
@@ -1 +1 @@
1
- {"version":3,"file":"interface.js","names":["PropTypes","publish","AUTHENTICATED_USER_TOPIC","AUTHENTICATED_USER_CHANGED","optionsShape","config","shape","BASE_URL","string","isRequired","LMS_BASE_URL","LOGIN_URL","LOGOUT_URL","REFRESH_ACCESS_TOKEN_ENDPOINT","ACCESS_TOKEN_COOKIE_NAME","CSRF_TOKEN_API_PATH","loggingService","logError","func","logInfo","serviceShape","getAuthenticatedHttpClient","getHttpClient","getLoginRedirectUrl","redirectToLogin","getLogoutRedirectUrl","redirectToLogout","getAuthenticatedUser","setAuthenticatedUser","fetchAuthenticatedUser","ensureAuthenticatedUser","hydrateAuthenticatedUser","service","configure","AuthService","options","checkPropTypes","getAuthService","Error","resetAuthService","redirectUrl","authUser"],"sources":["../../src/auth/interface.js"],"sourcesContent":["/**\n * #### Import members from **@edx/frontend-platform/auth**\n *\n * Simplifies the process of making authenticated API requests to backend edX services by providing\n * common authN/authZ client code that enables the login/logout flow and handles ensuring the\n * presence of a valid [JWT cookie](https://github.com/edx/edx-platform/blob/master/openedx/core/djangoapps/oauth_dispatch/docs/decisions/0009-jwt-in-session-cookie.rst).\n *\n * The `initialize` function performs much of the auth configuration for you. If, however, you're\n * not using the `initialize` function, an authenticated API client can be created via:\n *\n * ```\n * import {\n * configure,\n * fetchAuthenticatedUser,\n * getAuthenticatedHttpClient\n * } from '@edx/frontend-platform/auth';\n * import { getConfig } from '@edx/frontend-platform';\n * import { getLoggingService } from '@edx/frontend-platform/logging';\n *\n * configure({\n * loggingService: getLoggingService(),\n * config: getConfig(),\n * });\n *\n * const authenticatedUser = await fetchAuthenticatedUser(); // validates and decodes JWT token\n * const authenticatedHttpClient = getAuthenticatedHttpClient();\n * const response = await getAuthenticatedHttpClient().get(`https://example.com/api/user/data/${authenticatedUser.username}`); // fetching from an authenticated API using user data\n * ```\n *\n * As shown in this example, auth depends on the configuration document and logging.\n *\n * NOTE: The documentation for AxiosJwtAuthService is nearly the same as that for the top-level\n * auth interface, except that it contains some Axios-specific details.\n *\n * @module Auth\n */\nimport PropTypes from 'prop-types';\nimport { publish } from '../pubSub';\n\n/**\n * @constant\n * @private\n */\nexport const AUTHENTICATED_USER_TOPIC = 'AUTHENTICATED_USER';\n\n/**\n * Published when the authenticated user data changes. This can happen when the authentication\n * service determines that the user is authenticated or anonymous, as well as when we fetch\n * additional user account data if the `hydrateAuthenticatedUser` flag has been set in the\n * `initialize` function.\n *\n * @event\n * @see {@link module:Initialization~initialize}\n */\nexport const AUTHENTICATED_USER_CHANGED = `${AUTHENTICATED_USER_TOPIC}.CHANGED`;\n\nconst optionsShape = {\n config: PropTypes.shape({\n BASE_URL: PropTypes.string.isRequired,\n LMS_BASE_URL: PropTypes.string.isRequired,\n LOGIN_URL: PropTypes.string.isRequired,\n LOGOUT_URL: PropTypes.string.isRequired,\n REFRESH_ACCESS_TOKEN_ENDPOINT: PropTypes.string.isRequired,\n ACCESS_TOKEN_COOKIE_NAME: PropTypes.string.isRequired,\n CSRF_TOKEN_API_PATH: PropTypes.string.isRequired,\n }).isRequired,\n loggingService: PropTypes.shape({\n logError: PropTypes.func.isRequired,\n logInfo: PropTypes.func.isRequired,\n }).isRequired,\n};\n\nconst serviceShape = {\n getAuthenticatedHttpClient: PropTypes.func.isRequired,\n getHttpClient: PropTypes.func.isRequired,\n getLoginRedirectUrl: PropTypes.func.isRequired,\n redirectToLogin: PropTypes.func.isRequired,\n getLogoutRedirectUrl: PropTypes.func.isRequired,\n redirectToLogout: PropTypes.func.isRequired,\n getAuthenticatedUser: PropTypes.func.isRequired,\n setAuthenticatedUser: PropTypes.func.isRequired,\n fetchAuthenticatedUser: PropTypes.func.isRequired,\n ensureAuthenticatedUser: PropTypes.func.isRequired,\n hydrateAuthenticatedUser: PropTypes.func.isRequired,\n};\n\nlet service;\n\n/**\n *\n * @param {class} AuthService\n * @param {*} options\n * @returns {AuthService}\n */\nexport function configure(AuthService, options) {\n PropTypes.checkPropTypes(optionsShape, options, 'property', 'Auth');\n service = new AuthService(options);\n PropTypes.checkPropTypes(serviceShape, service, 'property', 'AuthService');\n return service;\n}\n\n/**\n *\n *\n * @returns {AuthService}\n */\nexport function getAuthService() {\n if (!service) {\n throw Error('You must first configure the auth service.');\n }\n\n return service;\n}\n\n/**\n *\n */\nexport function resetAuthService() {\n service = null;\n}\n\n/**\n * Gets the authenticated HTTP client for the service.\n *\n * @param {Object} [options] Optional options for how to configure the authenticated HTTP client\n * @param {boolean} [options.useCache] Whether to use front end caching for all requests made with the returned client\n *\n * @returns {HttpClient}\n */\nexport function getAuthenticatedHttpClient(options = {}) {\n return service.getAuthenticatedHttpClient(options);\n}\n\n/**\n * Gets the unauthenticated HTTP client for the service.\n *\n * @param {Object} [options] Optional options for how to configure the authenticated HTTP client\n * @param {boolean} [options.useCache] Whether to use front end caching for all requests made with the returned client\n *\n * @returns {HttpClient}\n */\nexport function getHttpClient(options = {}) {\n return service.getHttpClient(options);\n}\n\n/**\n * Builds a URL to the login page with a post-login redirect URL attached as a query parameter.\n *\n * ```\n * const url = getLoginRedirectUrl('http://localhost/mypage');\n * console.log(url); // http://localhost/login?next=http%3A%2F%2Flocalhost%2Fmypage\n * ```\n *\n * @param {string} redirectUrl The URL the user should be redirected to after logging in.\n */\nexport function getLoginRedirectUrl(redirectUrl) {\n return service.getLoginRedirectUrl(redirectUrl);\n}\n\n/**\n * Redirects the user to the login page.\n *\n * @param {string} redirectUrl The URL the user should be redirected to after logging in.\n */\nexport function redirectToLogin(redirectUrl) {\n return service.redirectToLogin(redirectUrl);\n}\n\n/**\n * Builds a URL to the logout page with a post-logout redirect URL attached as a query parameter.\n *\n * ```\n * const url = getLogoutRedirectUrl('http://localhost/mypage');\n * console.log(url); // http://localhost/logout?redirect_url=http%3A%2F%2Flocalhost%2Fmypage\n * ```\n *\n * @param {string} redirectUrl The URL the user should be redirected to after logging out.\n */\nexport function getLogoutRedirectUrl(redirectUrl) {\n return service.getLogoutRedirectUrl(redirectUrl);\n}\n\n/**\n * Redirects the user to the logout page.\n *\n * @param {string} redirectUrl The URL the user should be redirected to after logging out.\n */\nexport function redirectToLogout(redirectUrl) {\n return service.redirectToLogout(redirectUrl);\n}\n\n/**\n * If it exists, returns the user data representing the currently authenticated user. If the\n * user is anonymous, returns null.\n *\n * @returns {UserData|null}\n */\nexport function getAuthenticatedUser() {\n return service.getAuthenticatedUser();\n}\n\n/**\n * Sets the authenticated user to the provided value.\n *\n * @param {UserData} authUser\n * @emits AUTHENTICATED_USER_CHANGED\n */\nexport function setAuthenticatedUser(authUser) {\n service.setAuthenticatedUser(authUser);\n publish(AUTHENTICATED_USER_CHANGED);\n}\n\n/**\n * Reads the authenticated user's access token. Resolves to null if the user is\n * unauthenticated.\n *\n * @returns {Promise<UserData>|Promise<null>} Resolves to the user's access token if they are\n * logged in.\n */\nexport async function fetchAuthenticatedUser(options = {}) {\n return service.fetchAuthenticatedUser(options);\n}\n\n/**\n * Ensures a user is authenticated. It will redirect to login when not\n * authenticated.\n *\n * @param {string} [redirectUrl=config.BASE_URL] to return user after login when not\n * authenticated.\n * @returns {Promise<UserData>}\n */\nexport async function ensureAuthenticatedUser(redirectUrl) {\n return service.ensureAuthenticatedUser(redirectUrl);\n}\n\n/**\n * Fetches additional user account information for the authenticated user and merges it into the\n * existing authenticatedUser object, available via getAuthenticatedUser().\n *\n * ```\n * console.log(authenticatedUser); // Will be sparse and only contain basic information.\n * await hydrateAuthenticatedUser()\n * const authenticatedUser = getAuthenticatedUser();\n * console.log(authenticatedUser); // Will contain additional user information\n * ```\n *\n * @emits AUTHENTICATED_USER_CHANGED\n */\nexport async function hydrateAuthenticatedUser() {\n await service.hydrateAuthenticatedUser();\n publish(AUTHENTICATED_USER_CHANGED);\n}\n\n/**\n * @name AuthService\n * @interface\n * @memberof module:Auth\n * @property {function} getAuthenticatedHttpClient\n * @property {function} getHttpClient\n * @property {function} getLoginRedirectUrl\n * @property {function} redirectToLogin\n * @property {function} getLogoutRedirectUrl\n * @property {function} redirectToLogout\n * @property {function} getAuthenticatedUser\n * @property {function} setAuthenticatedUser\n * @property {function} fetchAuthenticatedUser\n * @property {function} ensureAuthenticatedUser\n * @property {function} hydrateAuthenticatedUser\n */\n\n/**\n * A configured axios client. See axios docs for more\n * info https://github.com/axios/axios. All the functions\n * below accept isPublic and isCsrfExempt in the request\n * config options. Setting these to true will prevent this\n * client from attempting to refresh the jwt access token\n * or a csrf token respectively.\n *\n * ```\n * // A public endpoint (no jwt token refresh)\n * apiClient.get('/path/to/endpoint', { isPublic: true });\n * ```\n *\n * ```\n * // A csrf exempt endpoint\n * apiClient.post('/path/to/endpoint', { data }, { isCsrfExempt: true });\n * ```\n *\n * @name HttpClient\n * @interface\n * @memberof module:Auth\n * @property {function} get\n * @property {function} head\n * @property {function} options\n * @property {function} delete (csrf protected)\n * @property {function} post (csrf protected)\n * @property {function} put (csrf protected)\n * @property {function} patch (csrf protected)\n */\n\n/**\n * @name UserData\n * @interface\n * @memberof module:Auth\n * @property {string} userId\n * @property {string} username\n * @property {Array} roles\n * @property {boolean} administrator\n */\n"],"mappings":"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"}
1
+ {"version":3,"file":"interface.js","names":["PropTypes","publish","AUTHENTICATED_USER_TOPIC","AUTHENTICATED_USER_CHANGED","optionsShape","config","shape","BASE_URL","string","isRequired","LMS_BASE_URL","LOGIN_URL","LOGOUT_URL","REFRESH_ACCESS_TOKEN_ENDPOINT","ACCESS_TOKEN_COOKIE_NAME","CSRF_TOKEN_API_PATH","loggingService","logError","func","logInfo","serviceShape","getAuthenticatedHttpClient","getHttpClient","getLoginRedirectUrl","redirectToLogin","getLogoutRedirectUrl","redirectToLogout","getAuthenticatedUser","setAuthenticatedUser","fetchAuthenticatedUser","ensureAuthenticatedUser","hydrateAuthenticatedUser","service","configure","AuthService","options","checkPropTypes","getAuthService","Error","resetAuthService","redirectUrl","authUser"],"sources":["../../src/auth/interface.js"],"sourcesContent":["/**\n * #### Import members from **@edx/frontend-platform/auth**\n *\n * Simplifies the process of making authenticated API requests to backend edX services by providing\n * common authN/authZ client code that enables the login/logout flow and handles ensuring the\n * presence of a valid [JWT cookie](https://github.com/openedx/edx-platform/blob/master/openedx/core/djangoapps/oauth_dispatch/docs/decisions/0009-jwt-in-session-cookie.rst).\n *\n * The `initialize` function performs much of the auth configuration for you. If, however, you're\n * not using the `initialize` function, an authenticated API client can be created via:\n *\n * ```\n * import {\n * configure,\n * fetchAuthenticatedUser,\n * getAuthenticatedHttpClient\n * } from '@edx/frontend-platform/auth';\n * import { getConfig } from '@edx/frontend-platform';\n * import { getLoggingService } from '@edx/frontend-platform/logging';\n *\n * configure({\n * loggingService: getLoggingService(),\n * config: getConfig(),\n * });\n *\n * const authenticatedUser = await fetchAuthenticatedUser(); // validates and decodes JWT token\n * const authenticatedHttpClient = getAuthenticatedHttpClient();\n * const response = await getAuthenticatedHttpClient().get(`https://example.com/api/user/data/${authenticatedUser.username}`); // fetching from an authenticated API using user data\n * ```\n *\n * As shown in this example, auth depends on the configuration document and logging.\n *\n * NOTE: The documentation for AxiosJwtAuthService is nearly the same as that for the top-level\n * auth interface, except that it contains some Axios-specific details.\n *\n * @module Auth\n */\nimport PropTypes from 'prop-types';\nimport { publish } from '../pubSub';\n\n/**\n * @constant\n * @private\n */\nexport const AUTHENTICATED_USER_TOPIC = 'AUTHENTICATED_USER';\n\n/**\n * Published when the authenticated user data changes. This can happen when the authentication\n * service determines that the user is authenticated or anonymous, as well as when we fetch\n * additional user account data if the `hydrateAuthenticatedUser` flag has been set in the\n * `initialize` function.\n *\n * @event\n * @see {@link module:Initialization~initialize}\n */\nexport const AUTHENTICATED_USER_CHANGED = `${AUTHENTICATED_USER_TOPIC}.CHANGED`;\n\nconst optionsShape = {\n config: PropTypes.shape({\n BASE_URL: PropTypes.string.isRequired,\n LMS_BASE_URL: PropTypes.string.isRequired,\n LOGIN_URL: PropTypes.string.isRequired,\n LOGOUT_URL: PropTypes.string.isRequired,\n REFRESH_ACCESS_TOKEN_ENDPOINT: PropTypes.string.isRequired,\n ACCESS_TOKEN_COOKIE_NAME: PropTypes.string.isRequired,\n CSRF_TOKEN_API_PATH: PropTypes.string.isRequired,\n }).isRequired,\n loggingService: PropTypes.shape({\n logError: PropTypes.func.isRequired,\n logInfo: PropTypes.func.isRequired,\n }).isRequired,\n};\n\nconst serviceShape = {\n getAuthenticatedHttpClient: PropTypes.func.isRequired,\n getHttpClient: PropTypes.func.isRequired,\n getLoginRedirectUrl: PropTypes.func.isRequired,\n redirectToLogin: PropTypes.func.isRequired,\n getLogoutRedirectUrl: PropTypes.func.isRequired,\n redirectToLogout: PropTypes.func.isRequired,\n getAuthenticatedUser: PropTypes.func.isRequired,\n setAuthenticatedUser: PropTypes.func.isRequired,\n fetchAuthenticatedUser: PropTypes.func.isRequired,\n ensureAuthenticatedUser: PropTypes.func.isRequired,\n hydrateAuthenticatedUser: PropTypes.func.isRequired,\n};\n\nlet service;\n\n/**\n *\n * @param {class} AuthService\n * @param {*} options\n * @returns {AuthService}\n */\nexport function configure(AuthService, options) {\n PropTypes.checkPropTypes(optionsShape, options, 'property', 'Auth');\n service = new AuthService(options);\n PropTypes.checkPropTypes(serviceShape, service, 'property', 'AuthService');\n return service;\n}\n\n/**\n *\n *\n * @returns {AuthService}\n */\nexport function getAuthService() {\n if (!service) {\n throw Error('You must first configure the auth service.');\n }\n\n return service;\n}\n\n/**\n *\n */\nexport function resetAuthService() {\n service = null;\n}\n\n/**\n * Gets the authenticated HTTP client for the service.\n *\n * @param {Object} [options] Optional options for how to configure the authenticated HTTP client\n * @param {boolean} [options.useCache] Whether to use front end caching for all requests made with the returned client\n *\n * @returns {HttpClient}\n */\nexport function getAuthenticatedHttpClient(options = {}) {\n return service.getAuthenticatedHttpClient(options);\n}\n\n/**\n * Gets the unauthenticated HTTP client for the service.\n *\n * @param {Object} [options] Optional options for how to configure the authenticated HTTP client\n * @param {boolean} [options.useCache] Whether to use front end caching for all requests made with the returned client\n *\n * @returns {HttpClient}\n */\nexport function getHttpClient(options = {}) {\n return service.getHttpClient(options);\n}\n\n/**\n * Builds a URL to the login page with a post-login redirect URL attached as a query parameter.\n *\n * ```\n * const url = getLoginRedirectUrl('http://localhost/mypage');\n * console.log(url); // http://localhost/login?next=http%3A%2F%2Flocalhost%2Fmypage\n * ```\n *\n * @param {string} redirectUrl The URL the user should be redirected to after logging in.\n */\nexport function getLoginRedirectUrl(redirectUrl) {\n return service.getLoginRedirectUrl(redirectUrl);\n}\n\n/**\n * Redirects the user to the login page.\n *\n * @param {string} redirectUrl The URL the user should be redirected to after logging in.\n */\nexport function redirectToLogin(redirectUrl) {\n return service.redirectToLogin(redirectUrl);\n}\n\n/**\n * Builds a URL to the logout page with a post-logout redirect URL attached as a query parameter.\n *\n * ```\n * const url = getLogoutRedirectUrl('http://localhost/mypage');\n * console.log(url); // http://localhost/logout?redirect_url=http%3A%2F%2Flocalhost%2Fmypage\n * ```\n *\n * @param {string} redirectUrl The URL the user should be redirected to after logging out.\n */\nexport function getLogoutRedirectUrl(redirectUrl) {\n return service.getLogoutRedirectUrl(redirectUrl);\n}\n\n/**\n * Redirects the user to the logout page.\n *\n * @param {string} redirectUrl The URL the user should be redirected to after logging out.\n */\nexport function redirectToLogout(redirectUrl) {\n return service.redirectToLogout(redirectUrl);\n}\n\n/**\n * If it exists, returns the user data representing the currently authenticated user. If the\n * user is anonymous, returns null.\n *\n * @returns {UserData|null}\n */\nexport function getAuthenticatedUser() {\n return service.getAuthenticatedUser();\n}\n\n/**\n * Sets the authenticated user to the provided value.\n *\n * @param {UserData} authUser\n * @emits AUTHENTICATED_USER_CHANGED\n */\nexport function setAuthenticatedUser(authUser) {\n service.setAuthenticatedUser(authUser);\n publish(AUTHENTICATED_USER_CHANGED);\n}\n\n/**\n * Reads the authenticated user's access token. Resolves to null if the user is\n * unauthenticated.\n *\n * @returns {Promise<UserData>|Promise<null>} Resolves to the user's access token if they are\n * logged in.\n */\nexport async function fetchAuthenticatedUser(options = {}) {\n return service.fetchAuthenticatedUser(options);\n}\n\n/**\n * Ensures a user is authenticated. It will redirect to login when not\n * authenticated.\n *\n * @param {string} [redirectUrl=config.BASE_URL] to return user after login when not\n * authenticated.\n * @returns {Promise<UserData>}\n */\nexport async function ensureAuthenticatedUser(redirectUrl) {\n return service.ensureAuthenticatedUser(redirectUrl);\n}\n\n/**\n * Fetches additional user account information for the authenticated user and merges it into the\n * existing authenticatedUser object, available via getAuthenticatedUser().\n *\n * ```\n * console.log(authenticatedUser); // Will be sparse and only contain basic information.\n * await hydrateAuthenticatedUser()\n * const authenticatedUser = getAuthenticatedUser();\n * console.log(authenticatedUser); // Will contain additional user information\n * ```\n *\n * @emits AUTHENTICATED_USER_CHANGED\n */\nexport async function hydrateAuthenticatedUser() {\n await service.hydrateAuthenticatedUser();\n publish(AUTHENTICATED_USER_CHANGED);\n}\n\n/**\n * @name AuthService\n * @interface\n * @memberof module:Auth\n * @property {function} getAuthenticatedHttpClient\n * @property {function} getHttpClient\n * @property {function} getLoginRedirectUrl\n * @property {function} redirectToLogin\n * @property {function} getLogoutRedirectUrl\n * @property {function} redirectToLogout\n * @property {function} getAuthenticatedUser\n * @property {function} setAuthenticatedUser\n * @property {function} fetchAuthenticatedUser\n * @property {function} ensureAuthenticatedUser\n * @property {function} hydrateAuthenticatedUser\n */\n\n/**\n * A configured axios client. See axios docs for more\n * info https://github.com/axios/axios. All the functions\n * below accept isPublic and isCsrfExempt in the request\n * config options. Setting these to true will prevent this\n * client from attempting to refresh the jwt access token\n * or a csrf token respectively.\n *\n * ```\n * // A public endpoint (no jwt token refresh)\n * apiClient.get('/path/to/endpoint', { isPublic: true });\n * ```\n *\n * ```\n * // A csrf exempt endpoint\n * apiClient.post('/path/to/endpoint', { data }, { isCsrfExempt: true });\n * ```\n *\n * @name HttpClient\n * @interface\n * @memberof module:Auth\n * @property {function} get\n * @property {function} head\n * @property {function} options\n * @property {function} delete (csrf protected)\n * @property {function} post (csrf protected)\n * @property {function} put (csrf protected)\n * @property {function} patch (csrf protected)\n */\n\n/**\n * @name UserData\n * @interface\n * @memberof module:Auth\n * @property {string} userId\n * @property {string} username\n * @property {Array} roles\n * @property {boolean} administrator\n */\n"],"mappings":";;+CACA,oJ;;;;;;AADA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAOA,SAAP,MAAsB,YAAtB;AACA,SAASC,OAAT,QAAwB,WAAxB;AAEA;AACA;AACA;AACA;;AACA,OAAO,IAAMC,wBAAwB,GAAG,oBAAjC;AAEP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,OAAO,IAAMC,0BAA0B,aAAMD,wBAAN,aAAhC;AAEP,IAAME,YAAY,GAAG;EACnBC,MAAM,EAAEL,SAAS,CAACM,KAAV,CAAgB;IACtBC,QAAQ,EAAEP,SAAS,CAACQ,MAAV,CAAiBC,UADL;IAEtBC,YAAY,EAAEV,SAAS,CAACQ,MAAV,CAAiBC,UAFT;IAGtBE,SAAS,EAAEX,SAAS,CAACQ,MAAV,CAAiBC,UAHN;IAItBG,UAAU,EAAEZ,SAAS,CAACQ,MAAV,CAAiBC,UAJP;IAKtBI,6BAA6B,EAAEb,SAAS,CAACQ,MAAV,CAAiBC,UAL1B;IAMtBK,wBAAwB,EAAEd,SAAS,CAACQ,MAAV,CAAiBC,UANrB;IAOtBM,mBAAmB,EAAEf,SAAS,CAACQ,MAAV,CAAiBC;EAPhB,CAAhB,EAQLA,UATgB;EAUnBO,cAAc,EAAEhB,SAAS,CAACM,KAAV,CAAgB;IAC9BW,QAAQ,EAAEjB,SAAS,CAACkB,IAAV,CAAeT,UADK;IAE9BU,OAAO,EAAEnB,SAAS,CAACkB,IAAV,CAAeT;EAFM,CAAhB,EAGbA;AAbgB,CAArB;AAgBA,IAAMW,YAAY,GAAG;EACnBC,0BAA0B,EAAErB,SAAS,CAACkB,IAAV,CAAeT,UADxB;EAEnBa,aAAa,EAAEtB,SAAS,CAACkB,IAAV,CAAeT,UAFX;EAGnBc,mBAAmB,EAAEvB,SAAS,CAACkB,IAAV,CAAeT,UAHjB;EAInBe,eAAe,EAAExB,SAAS,CAACkB,IAAV,CAAeT,UAJb;EAKnBgB,oBAAoB,EAAEzB,SAAS,CAACkB,IAAV,CAAeT,UALlB;EAMnBiB,gBAAgB,EAAE1B,SAAS,CAACkB,IAAV,CAAeT,UANd;EAOnBkB,oBAAoB,EAAE3B,SAAS,CAACkB,IAAV,CAAeT,UAPlB;EAQnBmB,oBAAoB,EAAE5B,SAAS,CAACkB,IAAV,CAAeT,UARlB;EASnBoB,sBAAsB,EAAE7B,SAAS,CAACkB,IAAV,CAAeT,UATpB;EAUnBqB,uBAAuB,EAAE9B,SAAS,CAACkB,IAAV,CAAeT,UAVrB;EAWnBsB,wBAAwB,EAAE/B,SAAS,CAACkB,IAAV,CAAeT;AAXtB,CAArB;AAcA,IAAIuB,OAAJ;AAEA;AACA;AACA;AACA;AACA;AACA;;AACA,OAAO,SAASC,SAAT,CAAmBC,WAAnB,EAAgCC,OAAhC,EAAyC;EAC9CnC,SAAS,CAACoC,cAAV,CAAyBhC,YAAzB,EAAuC+B,OAAvC,EAAgD,UAAhD,EAA4D,MAA5D;EACAH,OAAO,GAAG,IAAIE,WAAJ,CAAgBC,OAAhB,CAAV;EACAnC,SAAS,CAACoC,cAAV,CAAyBhB,YAAzB,EAAuCY,OAAvC,EAAgD,UAAhD,EAA4D,aAA5D;EACA,OAAOA,OAAP;AACD;AAED;AACA;AACA;AACA;AACA;;AACA,OAAO,SAASK,cAAT,GAA0B;EAC/B,IAAI,CAACL,OAAL,EAAc;IACZ,MAAMM,KAAK,CAAC,4CAAD,CAAX;EACD;;EAED,OAAON,OAAP;AACD;AAED;AACA;AACA;;AACA,OAAO,SAASO,gBAAT,GAA4B;EACjCP,OAAO,GAAG,IAAV;AACD;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,OAAO,SAASX,0BAAT,GAAkD;EAAA,IAAdc,OAAc,uEAAJ,EAAI;EACvD,OAAOH,OAAO,CAACX,0BAAR,CAAmCc,OAAnC,CAAP;AACD;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,OAAO,SAASb,aAAT,GAAqC;EAAA,IAAda,OAAc,uEAAJ,EAAI;EAC1C,OAAOH,OAAO,CAACV,aAAR,CAAsBa,OAAtB,CAAP;AACD;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,OAAO,SAASZ,mBAAT,CAA6BiB,WAA7B,EAA0C;EAC/C,OAAOR,OAAO,CAACT,mBAAR,CAA4BiB,WAA5B,CAAP;AACD;AAED;AACA;AACA;AACA;AACA;;AACA,OAAO,SAAShB,eAAT,CAAyBgB,WAAzB,EAAsC;EAC3C,OAAOR,OAAO,CAACR,eAAR,CAAwBgB,WAAxB,CAAP;AACD;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,OAAO,SAASf,oBAAT,CAA8Be,WAA9B,EAA2C;EAChD,OAAOR,OAAO,CAACP,oBAAR,CAA6Be,WAA7B,CAAP;AACD;AAED;AACA;AACA;AACA;AACA;;AACA,OAAO,SAASd,gBAAT,CAA0Bc,WAA1B,EAAuC;EAC5C,OAAOR,OAAO,CAACN,gBAAR,CAAyBc,WAAzB,CAAP;AACD;AAED;AACA;AACA;AACA;AACA;AACA;;AACA,OAAO,SAASb,oBAAT,GAAgC;EACrC,OAAOK,OAAO,CAACL,oBAAR,EAAP;AACD;AAED;AACA;AACA;AACA;AACA;AACA;;AACA,OAAO,SAASC,oBAAT,CAA8Ba,QAA9B,EAAwC;EAC7CT,OAAO,CAACJ,oBAAR,CAA6Ba,QAA7B;EACAxC,OAAO,CAACE,0BAAD,CAAP;AACD;AAED;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,gBAAsB0B,sBAAtB;EAAA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;uFAXO;IAAA;IAAA;IAAA;MAAA;QAAA;UAAA;YAAsCM,OAAtC,2DAAgD,EAAhD;YAAA,iCACEH,OAAO,CAACH,sBAAR,CAA+BM,OAA/B,CADF;;UAAA;UAAA;YAAA;QAAA;MAAA;IAAA;EAAA,C;;;;AAYP,gBAAsBL,uBAAtB;EAAA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;wFAhBO,kBAAuCU,WAAvC;IAAA;MAAA;QAAA;UAAA;YAAA,kCACER,OAAO,CAACF,uBAAR,CAAgCU,WAAhC,CADF;;UAAA;UAAA;YAAA;QAAA;MAAA;IAAA;EAAA,C;;;;AAiBP,gBAAsBT,wBAAtB;EAAA;AAAA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;yFA5DO;IAAA;MAAA;QAAA;UAAA;YAAA;YAAA,OACCC,OAAO,CAACD,wBAAR,EADD;;UAAA;YAEL9B,OAAO,CAACE,0BAAD,CAAP;;UAFK;UAAA;YAAA;QAAA;MAAA;IAAA;EAAA,C"}
package/i18n/index.js CHANGED
@@ -18,7 +18,7 @@
18
18
  *
19
19
  *
20
20
  * @module Internationalization
21
- * @see {@link https://github.com/edx/frontend-platform/blob/master/docs/how_tos/i18n.rst}
21
+ * @see {@link https://github.com/openedx/frontend-platform/blob/master/docs/how_tos/i18n.rst}
22
22
  * @see {@link https://formatjs.io/docs/react-intl/components/ Intl} for components exported from this module.
23
23
  *
24
24
  */
package/i18n/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["createIntl","FormattedDate","FormattedTime","FormattedRelativeTime","FormattedNumber","FormattedPlural","FormattedMessage","defineMessages","IntlProvider","useIntl","intlShape","configure","getPrimaryLanguageSubtag","getLocale","getMessages","isRtl","handleRtl","LOCALE_CHANGED","LOCALE_TOPIC","default","injectIntl","getCountryList","getCountryMessages","getLanguageList","getLanguageMessages"],"sources":["../../src/i18n/index.js"],"sourcesContent":["/**\n * #### Import members from **@edx/frontend-platform/i18n**\n * The i18n module relies on react-intl and re-exports all of that package's exports.\n *\n * For each locale we want to support, react-intl needs 1) the locale-data, which includes\n * information about how to format numbers, handle plurals, etc., and 2) the translations, as an\n * object holding message id / translated string pairs. A locale string and the messages object are\n * passed into the IntlProvider element that wraps your element hierarchy.\n *\n * Note that react-intl has no way of checking if the translations you give it actually have\n * anything to do with the locale you pass it; it will happily use whatever messages object you pass\n * in. However, if the locale data for the locale you passed into the IntlProvider was not\n * correctly installed with addLocaleData, all of your translations will fall back to the default\n * (in our case English), *even if you gave IntlProvider the correct messages object for that\n * locale*.\n *\n * Messages are provided to this module via the configure() function below.\n *\n *\n * @module Internationalization\n * @see {@link https://github.com/edx/frontend-platform/blob/master/docs/how_tos/i18n.rst}\n * @see {@link https://formatjs.io/docs/react-intl/components/ Intl} for components exported from this module.\n *\n */\n\n/**\n * @name createIntl\n * @kind function\n * @see {@link https://formatjs.io/docs/react-intl/api#createIntl Intl}\n */\n\n/**\n * @name FormattedDate\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#formatteddate Intl}\n */\n\n/**\n * @name FormattedTime\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#formattedtime Intl}\n */\n\n/**\n * @name FormattedRelativeTime\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#formattedrelativetime Intl}\n */\n\n/**\n * @name FormattedNumber\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#formattednumber Intl}\n */\n\n/**\n * @name FormattedPlural\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#formattedplural Intl}\n */\n\n/**\n * @name FormattedMessage\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#formattedmessage Intl}\n */\n\n/**\n * @name IntlProvider\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#intlprovider Intl}\n */\n\n/**\n * @name defineMessages\n * @kind function\n * @see {@link https://formatjs.io/docs/react-intl/api#definemessagesdefinemessage Intl}\n */\n\n/**\n * @name useIntl\n * @kind function\n * @see {@link https://formatjs.io/docs/react-intl/api#useIntl Intl}\n */\n\nexport {\n createIntl,\n FormattedDate,\n FormattedTime,\n FormattedRelativeTime,\n FormattedNumber,\n FormattedPlural,\n FormattedMessage,\n defineMessages,\n IntlProvider,\n useIntl,\n} from 'react-intl';\n\nexport {\n intlShape,\n configure,\n getPrimaryLanguageSubtag,\n getLocale,\n getMessages,\n isRtl,\n handleRtl,\n LOCALE_CHANGED,\n LOCALE_TOPIC,\n} from './lib';\n\nexport {\n default as injectIntl,\n} from './injectIntlWithShim';\n\nexport {\n getCountryList,\n getCountryMessages,\n} from './countries';\n\nexport {\n getLanguageList,\n getLanguageMessages,\n} from './languages';\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA,SACEA,UADF,EAEEC,aAFF,EAGEC,aAHF,EAIEC,qBAJF,EAKEC,eALF,EAMEC,eANF,EAOEC,gBAPF,EAQEC,cARF,EASEC,YATF,EAUEC,OAVF,QAWO,YAXP;AAaA,SACEC,SADF,EAEEC,SAFF,EAGEC,wBAHF,EAIEC,SAJF,EAKEC,WALF,EAMEC,KANF,EAOEC,SAPF,EAQEC,cARF,EASEC,YATF,QAUO,OAVP;AAYA,SACEC,OAAO,IAAIC,UADb,QAEO,sBAFP;AAIA,SACEC,cADF,EAEEC,kBAFF,QAGO,aAHP;AAKA,SACEC,eADF,EAEEC,mBAFF,QAGO,aAHP"}
1
+ {"version":3,"file":"index.js","names":["createIntl","FormattedDate","FormattedTime","FormattedRelativeTime","FormattedNumber","FormattedPlural","FormattedMessage","defineMessages","IntlProvider","useIntl","intlShape","configure","getPrimaryLanguageSubtag","getLocale","getMessages","isRtl","handleRtl","LOCALE_CHANGED","LOCALE_TOPIC","default","injectIntl","getCountryList","getCountryMessages","getLanguageList","getLanguageMessages"],"sources":["../../src/i18n/index.js"],"sourcesContent":["/**\n * #### Import members from **@edx/frontend-platform/i18n**\n * The i18n module relies on react-intl and re-exports all of that package's exports.\n *\n * For each locale we want to support, react-intl needs 1) the locale-data, which includes\n * information about how to format numbers, handle plurals, etc., and 2) the translations, as an\n * object holding message id / translated string pairs. A locale string and the messages object are\n * passed into the IntlProvider element that wraps your element hierarchy.\n *\n * Note that react-intl has no way of checking if the translations you give it actually have\n * anything to do with the locale you pass it; it will happily use whatever messages object you pass\n * in. However, if the locale data for the locale you passed into the IntlProvider was not\n * correctly installed with addLocaleData, all of your translations will fall back to the default\n * (in our case English), *even if you gave IntlProvider the correct messages object for that\n * locale*.\n *\n * Messages are provided to this module via the configure() function below.\n *\n *\n * @module Internationalization\n * @see {@link https://github.com/openedx/frontend-platform/blob/master/docs/how_tos/i18n.rst}\n * @see {@link https://formatjs.io/docs/react-intl/components/ Intl} for components exported from this module.\n *\n */\n\n/**\n * @name createIntl\n * @kind function\n * @see {@link https://formatjs.io/docs/react-intl/api#createIntl Intl}\n */\n\n/**\n * @name FormattedDate\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#formatteddate Intl}\n */\n\n/**\n * @name FormattedTime\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#formattedtime Intl}\n */\n\n/**\n * @name FormattedRelativeTime\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#formattedrelativetime Intl}\n */\n\n/**\n * @name FormattedNumber\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#formattednumber Intl}\n */\n\n/**\n * @name FormattedPlural\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#formattedplural Intl}\n */\n\n/**\n * @name FormattedMessage\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#formattedmessage Intl}\n */\n\n/**\n * @name IntlProvider\n * @kind class\n * @see {@link https://formatjs.io/docs/react-intl/components/#intlprovider Intl}\n */\n\n/**\n * @name defineMessages\n * @kind function\n * @see {@link https://formatjs.io/docs/react-intl/api#definemessagesdefinemessage Intl}\n */\n\n/**\n * @name useIntl\n * @kind function\n * @see {@link https://formatjs.io/docs/react-intl/api#useIntl Intl}\n */\n\nexport {\n createIntl,\n FormattedDate,\n FormattedTime,\n FormattedRelativeTime,\n FormattedNumber,\n FormattedPlural,\n FormattedMessage,\n defineMessages,\n IntlProvider,\n useIntl,\n} from 'react-intl';\n\nexport {\n intlShape,\n configure,\n getPrimaryLanguageSubtag,\n getLocale,\n getMessages,\n isRtl,\n handleRtl,\n LOCALE_CHANGED,\n LOCALE_TOPIC,\n} from './lib';\n\nexport {\n default as injectIntl,\n} from './injectIntlWithShim';\n\nexport {\n getCountryList,\n getCountryMessages,\n} from './countries';\n\nexport {\n getLanguageList,\n getLanguageMessages,\n} from './languages';\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA,SACEA,UADF,EAEEC,aAFF,EAGEC,aAHF,EAIEC,qBAJF,EAKEC,eALF,EAMEC,eANF,EAOEC,gBAPF,EAQEC,cARF,EASEC,YATF,EAUEC,OAVF,QAWO,YAXP;AAaA,SACEC,SADF,EAEEC,SAFF,EAGEC,wBAHF,EAIEC,SAJF,EAKEC,WALF,EAMEC,KANF,EAOEC,SAPF,EAQEC,cARF,EASEC,YATF,QAUO,OAVP;AAYA,SACEC,OAAO,IAAIC,UADb,QAEO,sBAFP;AAIA,SACEC,cADF,EAEEC,kBAFF,QAGO,aAHP;AAKA,SACEC,eADF,EAEEC,mBAFF,QAGO,aAHP"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edx/frontend-platform",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "Foundational application framework for Open edX micro-frontend applications.",
5
5
  "main": "index.js",
6
6
  "publishConfig": {
@@ -22,33 +22,33 @@
22
22
  },
23
23
  "repository": {
24
24
  "type": "git",
25
- "url": "git+https://github.com/edx/frontend-platform.git"
25
+ "url": "git+https://github.com/openedx/frontend-platform.git"
26
26
  },
27
27
  "author": "edX",
28
28
  "license": "AGPL-3.0",
29
29
  "bugs": {
30
- "url": "https://github.com/edx/frontend-platform/issues"
30
+ "url": "https://github.com/openedx/frontend-platform/issues"
31
31
  },
32
- "homepage": "https://github.com/edx/frontend-platform#readme",
32
+ "homepage": "https://github.com/openedx/frontend-platform#readme",
33
33
  "devDependencies": {
34
- "@edx/browserslist-config": "^1.1.0",
34
+ "@edx/browserslist-config": "1.1.1",
35
35
  "@edx/brand": "npm:@edx/brand-openedx@1.1.0",
36
- "@edx/frontend-build": "^12.0.3",
37
- "@edx/paragon": "20.2.0",
38
- "axios-mock-adapter": "1.20.0",
39
- "core-js": "3.21.1",
36
+ "@edx/frontend-build": "12.3.0",
37
+ "@edx/paragon": "20.18.0",
38
+ "axios-mock-adapter": "1.21.2",
39
+ "core-js": "3.26.0",
40
40
  "enzyme": "3.11.0",
41
41
  "enzyme-adapter-react-16": "1.15.6",
42
42
  "husky": "7.0.4",
43
- "jsdoc": "3.6.10",
44
- "nodemon": "2.0.16",
43
+ "jsdoc": "3.6.11",
44
+ "nodemon": "2.0.20",
45
45
  "prop-types": "15.8.1",
46
46
  "react": "16.14.0",
47
47
  "react-dom": "16.14.0",
48
- "react-redux": "7.2.8",
49
- "react-router-dom": "5.3.1",
50
- "redux": "4.1.2",
51
- "regenerator-runtime": "0.13.9"
48
+ "react-redux": "7.2.9",
49
+ "react-router-dom": "5.3.4",
50
+ "redux": "4.2.0",
51
+ "regenerator-runtime": "0.13.10"
52
52
  },
53
53
  "dependencies": {
54
54
  "@cospired/i18n-iso-languages": "2.2.0",