Giter VIP home page Giter VIP logo

one-app-ducks's Introduction

One App Ducks - One Amex

npm Health Check

Redux ducks used within the One App ecosystem.

👩‍💻 Hiring 👨‍💻

Want to get paid for your contributions to one-app-ducks?

Send your resume to [email protected]

📖 Table of Contents

✨ Features

  • Combine your reducers with the global reducers within the One App ecosystem.

🤹‍ Usage

Installation

npm i @americanexpress/one-app-ducks

How to use

import { combineReducers } from 'redux-immutable';
import { createStore } from 'redux';
import globalReducers from '@americanexpress/one-app-ducks';

const appReducer = combineReducers({
  ...globalReducers,
  ...otherReducers, // Your specific reducers
});

const store = createStore(
  appReducer
);

🎛️ One App Ducks API

Overview

Ducks include the reducer, selectors and action creators for a given branch of state. These ducks make up the core of One App's state.

The default export is an object of reducers meant to be included in a call to Redux immutable's combineReducers when setting up the store. Included reducers are browser, error, errorReporting, intl, redirection and rendering.

Contents:

browser Duck

This duck is for reading information about the user's browser. It is particularly helpful on the server where this information is not readily available.

Contents:

State Shape

const state = new Map({
  browser: new Map({
    cookies: new Map({
      [cookieName]: String, // value for the cookie
    }),
    location: new Map({
      origin: String, // origin of the request
    }),
    userAgent: String, // UA string for the browser
  }),
  // ...
});

Selectors

getCookies

This selector can be used to access cookies both on the server and the client.

This action creator can take the following argument:

Argument Type Description
state Object (required) current state of the your application
import { getCookies } from '@americanexpress/one-app-ducks';

// ...

const cookies = getCookies(store.getState());

Action Creators

setUserAgent

This action creator can be used to set the User-Agent. It is used directly by One App, and it is unlikely that any module would need it.

This action creator can take the following argument:

Argument Type Description
User-Agent String (required) User-Agent to be set
import { setUserAgent } from '@americanexpress/one-app-ducks';

// ...

store.dispatch(setUserAgent('curl/7.35.0?'));
setOrigin

This action creator can be used to set the Origin. It is used directly by One App, and it is unlikely that any module would need it.

This action creator can take the following argument:

Argument Type Description
Origin String (required) Origin to be set
import { setOrigin } from '@americanexpress/one-app-ducks';

// ...

store.dispatch(setOrigin('https://example.com'));

error Duck

The error duck tracks whether One App is in an error state and what the HTTP status code is for the error.

Contents:

State Shape

const state = new Map({
  error: new Map({
    code: Number, // HTTP error code (undefined if not set)
  }),
  // ...
});

Action creators

applicationError

This action creator will put the application in an error state and afterwards addErrorToReport is dispatched.

This action creator can take the following argument:

Argument Type Description
code Number (required) This is the error code to set e.g 500, 401 refer to this
import { applicationError } from '@americanexpress/one-app-ducks';

// ...

store.dispatch(applicationError(500));
clearError

This action creator can be used to clear the error code.

import { clearError } from '@americanexpress/one-app-ducks';

// ...

store.dispatch(clearError());

errorReporting Duck

The error reporting duck is for sending client side errors to the reportingUrl configured by the environment variable ONE_CLIENT_REPORTING_URL. You can find more documentation on environment variables for One App in the One App documentation. On the server the errors reported are simply logged with the assumption that the underlying infrastructure will pick up those logs and ship them to where they can be better kept and analyzed. Reported errors will have the following format:

({
  msg: String, // Error message (error.message)
  stack: String, // Error stack (error.stack) IE >= 10
  href: String, // href to the page reporting the error (client side only)
  otherData: Object, // Any other data included when adding the error to the report
});

Contents:

State Shape

const state = new Map({
  errorReporting: new Map({
    queue: List, // Errors to report
    pending: List, // Errors that have been sent but have not returned a success response yet
    pendingPromise: Promise, // From the request that posted the pending errors
    retryWait: Number, // Time (ms) to wait before sending again after a failure
  }),
  // ...
});

Action creators

addErrorToReport

This action creator is for reporting both client side and server side errors to your server logs.

This action creator can take the following arguments:

Argument Type Description
error Object (required) This is the error stack
otherData Object This is any other data that you'd like to send alongside the error message
import { addErrorToReport } from '@americanexpress/one-app-ducks';

// ...

store.dispatch(addErrorToReport(error, {
  collectionMethod: 'componentDidCatch',
  moduleID: 'my-module',
}));
sendErrorReport

This action creator is used to send any pending error reports. You can use this along side applicationError to post your own custom errors.

import { sendErrorReport } from '@americanexpress/one-app-ducks';

// ...

store.dispatch(sendErrorReport());

intl Duck

The intl duck is for enabling internationalization. It is used to load the language packs bundled with each module. See usage in the one-app-locale-bundler README for details on how to include language packs in your module bundles.

Contents:

State Shape

const state = new Map({
  intl: new Map({
    activeLocale: String, // BCP47 code for the locale served to the user
    languagePacks: new Map({
      [locale]: new Map({
        [moduleName]: new Map({
          data: Map, // Contents of the module's language pack
          isLoading: Boolean, // Indicates if the language pack request is in flight
          error: Error, // Error from language pack fetch
          errorExpiration: Number, // Time for error to expire so that reload attempt can be made
          _loadedOnServer: Boolean, // Indicates if the language pack was initially loaded on the
          // server
          _pendingDeferredForceLoad: Boolean, // Indicates if the client side request of server
          // loaded language pack is pending
        }),
      }),
    }),
  }),
  // ...
});

Action creators

loadLanguagePack

An async action creator for fetching your module's language pack. This action creator can take the following arguments:

Argument Type Description
moduleName String (required) Gets the language pack for the module specified.
options.locale String Gets the language pack for the given locale, as opposed to the locale in state.
options.url String URL to fetch the language pack from if not using language packs generated via one-app-bundler
options.force Boolean Force fetches the language pack if you don't want to use what is in state
options.fallbackLocale String If the language pack does not exist, fetches this lang pack instead.
options.fallbackUrl String URL to use for fallback locale if not using language packs generated with one-app-bundler
import { loadLanguagePack } from '@americanexpress/one-app-ducks';

// ...

export default holocronModule({
  name: 'my-module',
  load: () => (dispatch) => dispatch(loadLanguagePack('my-module', { locale: 'en-US' })),
})(MyModule);
queryLanguagePack

queryLanguagePack is the iguazu equivalent for loadLanguagePack. A fallback locale can be provided if there is a language pack you'd like to fallback to in case that the requested language pack is not available.

This action creator can take the following arguments:

Argument Type Description
moduleName String (required) Gets the language pack for the module specified.
fallbackLocale String If the language pack does not exist, fetches this lang pack instead.
import { queryLanguagePack } from '@americanexpress/one-app-ducks';

// ...

const loadDataAsProps = ({ store: { dispatch } }) => ({
  langPack: () => dispatch(queryLanguagePack('my-module', { fallbackLocale: 'en-US' })),
});
updateLocale

This action creator is used to set the active locale for One App. The promise will resolve once the locale bundle (containing locale data for Intl.js, React Intl and Moment.js) is loaded and the active locale is set. It will reject if Lean-Intl does not have a bundle for the locale.

The locale bundles don't need to be an exact match. For instance setting the locale to 'en-XA' will load i18n/en.js and 'zh-Hans-XB' will load i18n/zh-Hans.js.

If the Environment Variable ONE_CONFIG_USE_NATIVE_INTL is set to true, then updateLocale will not try to add the Lean-Intl bundle, but will still update the active locale.

This action creator can take the following argument:

Argument Type Description
locale String (required) Locale provided
import { updateLocale } from '@americanexpress/one-app-ducks';

// ...

store.dispatch(updateLocale('be-BY'));
getLocalePack

Similar to updateLocale, but will attempt to load the locale of the requested country that is closest to the current active locale. This is used directly by One App, and it is unlikely that any module would need it.

This action creator can take the following argument:

prop name type value
locale String (required) Locale provided
import { getLocalePack } from '@americanexpress/one-app-ducks';

// ...

store.dispatch(getLocalePack('en-GB'));

redirection Duck

The redirection duck is for managing redirection of users. It is particularly useful on the server where it is used to send a 302 response.

Contents:

State Shape

const state = new Map({
  redirection: new Map({
    destination: String, // Fully qualified external URL to redirect to
    redirectionInFlight: Boolean, // Indicates redirection has started
  }),
  // ...
});

Action creators

externalRedirect

This action creator can be used to redirect a user out of your one app instance either on the server (via 302 response) or on the client.

Argument Type Description
redirectUrl String (required) fully qualified URL to redirect the user to
import { externalRedirect } from '@americanexpress/one-app-ducks';

// ...

store.dispatch(externalRedirect('https://example.com'));

rendering Duck

The rendering duck controls how the server renders the HTML page sent to the client.

Contents:

State Shape

const state = new Map({
  rendering: new Map({
    disableScripts: Boolean, // Indicates if script tags should be omitted from HTML response
    disableStyles: Boolean, // Indicates if style tags should be omitted from HTML response
    renderPartialOnly: Boolean, // Indicates if the response should return just the rendered HTML
    // from the matched module rather than a complete HTML page
    renderTextOnly: Boolean, // Indicates if HTML tags should be removed from the HTML response
    renderTextOnlyOptions: new Map({
      htmlTagReplacement: String, // Replace all html tags with the character passed to this option.
      allowedHtmlTags: List, // List of HTML tags that should not be removed from the HTML response
    }),
  }),
  // ...
});

Action creators

setRenderPartialOnly

Use this action creator to render static markup from a holocron module, rather than a complete page.

Argument Type Description
renderPartialOnly Boolean (required) set whether a partial should be rendered or not
import { setRenderPartialOnly } from '@americanexpress/one-app-ducks';

// ...

dispatch(setRenderPartialOnly(true));
setRenderTextOnly

Use this action creator to render text only from a holocron module, rather than a HTML.

Argument Type Description
renderTextOnly Boolean (required) set whether to return text instead of HTML
options Object Replace html tags with the character passed to this option i.e. '/n'. Defaults to empty string.
options.htmlTagReplacement String Replace html tags with the character passed to this option i.e. '/n'. Defaults to empty string.
options.allowedHtmlTags Array Comma separated list of HTML tags that are allowed to remain in the text response i.e. ['a','strong']. Defaults to empty array.
import { setRenderTextOnly } from '@americanexpress/one-app-ducks';

// ...

dispatch(setRenderTextOnly(true, { htmlTagReplacement: '\n', allowedHtmlTags: ['a'] }));
setDangerouslyDisableScripts

Use this action creator to disable scripts for being added to the rendered page.

Argument Type Description
disableScripts Boolean (required) set whether scripts should be disabled
import { setDangerouslyDisableScripts } from '@americanexpress/one-app-ducks';

// ...

dispatch(setDangerouslyDisableScripts(true));
setDangerouslyDisableScriptsAndStyles

Use this action creator to disable scripts and styles for being added to the rendered page.

Argument Type Description
disableScriptsAndStyles Boolean (required) set whether both scripts and styles should be disabled
import { setDangerouslyDisableScriptsAndStyles } from '@americanexpress/one-app-ducks';

// ...

dispatch(setDangerouslyDisableScriptsAndStyles(true));

🏆 Contributing

We welcome Your interest in the American Express Open Source Community on Github. Any Contributor to any Open Source Project managed by the American Express Open Source Community must accept and sign an Agreement indicating agreement to the terms below. Except for the rights granted in this Agreement to American Express and to recipients of software distributed by American Express, You reserve all right, title, and interest, if any, in and to Your Contributions. Please fill out the Agreement.

Please feel free to open pull requests and see CONTRIBUTING.md to learn how to get started contributing.

🗝️ License

Any contributions made under this project will be governed by the Apache License 2.0.

🗣️ Code of Conduct

This project adheres to the American Express Community Guidelines. By participating, you are expected to honor these guidelines.

one-app-ducks's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

one-app-ducks's Issues

Entire language file is dumped to logs every ten minutes

🐞 Bug Report

Describe the bug

This line prints the entire contents for each language file to the console (and thus logs) when the cache is refreshed every ten minutes.

console.info(`setting serverLangPackCache: url ${url}, data`, data);

This doesn't seem to have any real value and makes it more difficult to search logs.

To Reproduce

Run one-app with one-app-ducks. You should see console logs like this every ten minutes if there is steady traffic:

setting serverLangPackCache: url https://<url>, data {\n  locale: 'en-US',\n  ...

Expected behavior

Whole files should not be dumped into the logs.

System information

Version of one-app-ducks: 4.3.1

"Accept-Language: *" header incorrectly sets activeLocale to "*"

🐞 Bug Report

Describe the bug

If the Accept-Language header on a request is set to "*", the value of the activeLocale in state will also be set to "*", which is not generally going to be a valid locale value by consumers.

For instance, if passed to react-intl, the following error occurs:

RangeError: '*' is not a structurally valid language tag

Using a wildcard for Accept-Language is not common but it is in the spec: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language

To Reproduce

  1. Make a request to a One App server using one-app-ducks with a header of "Accept-Language: *"
  2. Use the resulting locale value with react-intl.

Expected behavior

"Accept-Language: *" should set the activeLocale to the default locale, as if there was no Accept-Language header.

System information

  • Version of one-app-ducks: 4.3.1

Console error after calling error reporting URL

🐞 Bug Report

Describe the bug

After an error that results in calling the reporting URL, this console error is printed:

Uncaught (in promise) SyntaxError: Unexpected end of JSON input

It appears to be due to calling .toJson on the result of the call, but the default one-app reporting URL returns a 204 response with no body.

To Reproduce

  1. Trigger a reporting error.
  2. Check the log.

Expected behavior

No console error.

System information

  • OS: Mac
  • Browser (if applies): Chrome
  • Version of one-app-ducks: 4.1.1
  • Node version: 12.8.1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.