UNPKG

5.02 kBJavaScriptView Raw
1
2/**
3 * The available states.
4 */
5const States = {};
6
7/**
8 * A list of actions that would default the credential's action status to 'error'.
9 */
10const ERROR_ACTIONS = [
11 'unauthorized',
12 'needsBasic',
13 'needsAPIKey',
14 'needsClient',
15 'authError',
16 'refreshError'
17];
18
19/**
20 * A list of actions that would default credential's action status to 'warning'(needs user
21 * interaction).
22 */
23const WARNING_ACTIONS = [
24 'needsAuth',
25 'needsRefresh'
26];
27
28/**
29 * A list of actions that would default credential's action status to 'ready'.
30 */
31const READY_ACTIONS = [
32 'none'
33];
34
35Object.entries({
36 credential: [ 'none', 'expired', 'ok' ],
37 action: [].concat(ERROR_ACTIONS, WARNING_ACTIONS, READY_ACTIONS)
38}).forEach(([ key, states ]) => {
39 States[key] = States[key] || {};
40 states.forEach(state => {
41 States[key][state] = state;
42 });
43});
44
45/**
46 * A set of status, which is used to group credentials, based on the action required.
47 */
48const ACTION_STATUS = {
49 error: 'error',
50 warning: 'warning',
51 ready: 'ok',
52};
53
54/**
55 * Get the name of the status group the action belongs to.
56 *
57 * @param {string} action The name of the action for the given credential.
58 *
59 * @returns {string} The name of the status group this action belongs to.
60 */
61function getActionStatus(action) {
62 if (ERROR_ACTIONS.indexOf(action) !== -1) {
63 return ACTION_STATUS.error;
64 } else if (WARNING_ACTIONS.indexOf(action) !== -1) {
65 return ACTION_STATUS.warning;
66 } else if (READY_ACTIONS.indexOf(action) !== -1) {
67 return ACTION_STATUS.ready;
68 }
69
70 throw new Error('Invalid action name.');
71}
72
73/**
74 * Status is a multi-factor concept. There are 3 factors:
75 * - status of the configuration (For the current implementation invalid config fails to start so
76 * this isn't a concern).
77 * - status of the credential.
78 * - status of lifecycle actions.
79 *
80 * For example it's possible to have a valid credential whose refresh has errored. The credential
81 * is still valid and usable. Hopefully refresh will succeed prior to expiry of the credential.
82 *
83 * A chart of what it means:
84 * | Credential | Action | Description |
85 * |------------|---------------|-------------|
86 * | none | needsAuth | There is no credential and no way to get one. Requires user
87 * authorization. |
88 * | none | needsBasic | There is no credential and the basic credentials are null. |
89 * | none | needsAPIKey | There is no credential and the apiKey is null. |
90 * | none | needsClient | There is no credential and the client_id and/or client_secret are
91 * null |
92 * | none | authError | There is no credential and was an error in the user
93 * authorization. |
94 * | none | unauthorized | There is no credential and user didn't authorize it. |
95 * | none | needsRefresh | There is no credential but there is sufficient config to
96 * bootstrap it. |
97 * | none | refreshError | There is no credential and bootstrapping failed. |
98 * | expired | needsAuth | There credential is expired and no way to refresh. Requires user
99 * authorization. |
100 * | expired | authError | There credential is expired and was an error in the user
101 * authorization. |
102 * | expired | unauthorized | There credential is expired and user didn't authorize it. |
103 * | expired | needsRefresh | There credential is expired but there is sufficient config to
104 * refresh it. |
105 * | expired | refreshError | There credential is expired and refresh failed. |
106 * | ok | refreshError | There credential is valid but the background refresh of it
107 * failed. |
108 * | ok | none | There credential is valid and no action required. |
109 *
110 * @param {object} prevState The previous status state.
111 * @param {object} newState The new status delta.
112 * @returns {object} The new status.
113 */
114function status(prevState, newState) {
115 prevState = prevState || {};
116 if (newState === undefined) {
117 newState = prevState;
118 prevState = {};
119 }
120
121 if (newState && newState.credential && !States.credential[newState.credential]) {
122 throw new Error(`Invalid state for credential: ${newState.credential}`);
123 }
124
125 if (newState && newState.action && !States.action[newState.action]) {
126 throw new Error(`Invalid state for action: ${newState.action}`);
127 }
128 const action = newState.action || prevState.action || States.action.none;
129 return {
130 credential: newState.credential || prevState.credential || States.credential.none,
131 action,
132 action_status: getActionStatus(action)
133 };
134}
135
136/**
137 * Convenience to generate an "ok" status.
138 *
139 * @returns {Object} An "ok" status object.
140 */
141status.ok = function () {
142 return status({
143 credential: States.credential.ok,
144 action: States.action.none,
145 action_status: ACTION_STATUS.ready
146 });
147};
148
149module.exports = {
150 status,
151 States,
152 getActionStatus
153};