diff --git a/now.json b/now.json index eaf7d939..8cc52ffc 100644 --- a/now.json +++ b/now.json @@ -3,10 +3,15 @@ "alias": "devhubapp.com", "version": 2, "builds": [ + { "src": "packages/server/dist/api/redux/index.js", "use": "@now/node" }, { "src": "packages/server/dist/oauth/providers/github/*.js", "use": "@now/node" }, { "src": "packages/web/dist/**", "use": "@now/static" } ], "routes": [ + { + "src": "/api/redux", + "dest": "/packages/server/dist/api/redux/index.js" + }, { "src": "/auth/github", "dest": "/packages/server/dist/oauth/providers/github/auth.js" diff --git a/packages/server/package.json b/packages/server/package.json index 00dc5195..36873a5c 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -12,7 +12,9 @@ "dependencies": { "axios": "^0.18.0", "lodash.omit": "^4.5.0", + "micro": "^9.3.3", "qs": "^6.5.2", + "shared-core": "0.17.1", "url": "^0.11.0" }, "devDependencies": { @@ -20,11 +22,13 @@ "@types/jest": "^23.3.9", "@types/lodash": "^4.14.118", "@types/lodash.omit": "^4.5.4", + "@types/micro": "^7.3.3", "@types/qs": "^6.5.1", "@types/ramda": "^0.26.0", "babel-jest": "^23.6.0", "husky": "^1.1.4", "jest": "^23.6.0", + "micro-dev": "^3.0.0", "postinstall-postinstall": "^2.0.0", "prettier": "^1.15.2", "ts-jest": "^23.10.4", diff --git a/packages/server/src/api/redux/index.ts b/packages/server/src/api/redux/index.ts new file mode 100644 index 00000000..3d5879d0 --- /dev/null +++ b/packages/server/src/api/redux/index.ts @@ -0,0 +1,72 @@ +import axios from 'axios' +import { IncomingMessage, ServerResponse } from 'http' +import { json, send } from 'micro' + +import { AllActions } from 'shared-core/dist/redux/types' + +const sendReduxResponse = ( + res: ServerResponse, + code: number, + data: { + action: AllActions + }, +) => send(res, code, data) + +module.exports = async (req: IncomingMessage, res: ServerResponse) => { + // res.setHeader('Access-Control-Allow-Origin', '*') + + if (req.method !== 'POST') { + send(res, 404) + return + } + + const body = await json(req) + + const { action } = (body || {}) as { action?: AllActions } + + if (!(action && action.type)) { + send( + res, + 400, + 'Invalid request. Required valid action field inside body object.', + ) + return + } + + switch (action.type) { + case 'LOGIN_REQUEST': { + try { + const { data, status } = await axios.get( + `https://api.github.com/user?access_token=${action.payload.token}`, + ) + + sendReduxResponse(res, status, { + action: { + type: 'LOGIN_SUCCESS', + payload: { + user: data, + }, + }, + }) + return + } catch (error) { + sendReduxResponse(res, error.response.status, { + action: { + type: 'LOGIN_FAILURE', + payload: undefined, + error: { + code: error.response.status, + message: error.response.data.message, + }, + }, + }) + return + } + } + + default: { + send(res, 400, 'Unknown action type.') + return + } + } +} diff --git a/packages/server/src/oauth/helpers/index.ts b/packages/server/src/oauth/helpers/index.ts index 355d3d0b..872c8b5a 100644 --- a/packages/server/src/oauth/helpers/index.ts +++ b/packages/server/src/oauth/helpers/index.ts @@ -1,4 +1,4 @@ -import { Http2ServerRequest } from 'http2' +import { IncomingMessage } from 'http' import omit from 'lodash.omit' import qs from 'qs' import { ParsedUrlQuery } from 'querystring' @@ -13,7 +13,7 @@ export function isLocalhost(host: string) { ) } -export function getCurrentHostURL(req: Http2ServerRequest) { +export function getCurrentHostURL(req: IncomingMessage) { const host = req.headers.host || '' return isLocalhost(host) @@ -21,12 +21,12 @@ export function getCurrentHostURL(req: Http2ServerRequest) { : `https://${host}` } -export function getDefaultCallbackURL(req: Http2ServerRequest) { +export function getDefaultCallbackURL(req: IncomingMessage) { return `${getCurrentHostURL(req)}/auth/github/callback` } export function getCallbackURLWithQuery( - req: Http2ServerRequest, + req: IncomingMessage, callbackUrl?: string, query?: object, ) { diff --git a/packages/server/src/oauth/lib/oauth.ts b/packages/server/src/oauth/lib/oauth.ts index 47e4f547..29f33514 100644 --- a/packages/server/src/oauth/lib/oauth.ts +++ b/packages/server/src/oauth/lib/oauth.ts @@ -1,11 +1,11 @@ import axios from 'axios' -import { Http2ServerRequest, Http2ServerResponse } from 'http2' +import { IncomingMessage, ServerResponse } from 'http' import qs from 'qs' import { mergeQueryWithURL } from '../helpers' const redirectUsingHTML = ( - res: Http2ServerResponse, + res: ServerResponse, _statusCode: number, url: string, ) => { @@ -20,7 +20,7 @@ const redirectUsingHTML = ( } const redirectUsingHTMLAndPostMessage = ( - res: Http2ServerResponse, + res: ServerResponse, _statusCode: number, url: string, ) => { @@ -58,8 +58,8 @@ const redirectUsingHTMLAndPostMessage = ( } export function authorize( - req: Http2ServerRequest, - res: Http2ServerResponse, + req: IncomingMessage, + res: ServerResponse, { AUTHORIZE_URL }: { AUTHORIZE_URL: string }, query?: object, ) { @@ -67,8 +67,8 @@ export function authorize( } export async function callback( - req: Http2ServerRequest, - res: Http2ServerResponse, + req: IncomingMessage, + res: ServerResponse, { CALLBACK_URL, CLIENT_ID, diff --git a/packages/server/src/oauth/providers/github/auth.ts b/packages/server/src/oauth/providers/github/auth.ts index 15ecd096..0680de38 100644 --- a/packages/server/src/oauth/providers/github/auth.ts +++ b/packages/server/src/oauth/providers/github/auth.ts @@ -1,4 +1,4 @@ -import { Http2ServerRequest, Http2ServerResponse } from 'http2' +import { IncomingMessage, ServerResponse } from 'http' import url from 'url' import { @@ -8,8 +8,8 @@ import { } from '../../helpers' import { authorize } from '../../lib/oauth' -module.exports = (req: Http2ServerRequest, res: Http2ServerResponse) => { - const query = url.parse(req.url, true).query || {} +module.exports = (req: IncomingMessage, res: ServerResponse) => { + const query = url.parse(req.url || '', true).query || {} const redirectUri = getFirstStringFromQuery(query, 'redirect_uri') authorize( diff --git a/packages/server/src/oauth/providers/github/callback.ts b/packages/server/src/oauth/providers/github/callback.ts index e9fdffac..85147502 100644 --- a/packages/server/src/oauth/providers/github/callback.ts +++ b/packages/server/src/oauth/providers/github/callback.ts @@ -1,11 +1,11 @@ -import { Http2ServerRequest, Http2ServerResponse } from 'http2' +import { IncomingMessage, ServerResponse } from 'http' import url from 'url' import { getFirstStringFromQuery } from '../../helpers' import { callback } from '../../lib/oauth' -module.exports = (req: Http2ServerRequest, res: Http2ServerResponse) => { - const query = url.parse(req.url, true).query || {} +module.exports = (req: IncomingMessage, res: ServerResponse) => { + const query = url.parse(req.url || '', true).query || {} const callbackUrl = getFirstStringFromQuery(query, 'callback_url') callback( diff --git a/packages/shared-components/src/redux/actions/auth.ts b/packages/shared-components/src/redux/actions/auth.ts deleted file mode 100644 index e62b4ea5..00000000 --- a/packages/shared-components/src/redux/actions/auth.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { GitHubUser } from 'shared-core/dist/types' -import { - createAction, - createErrorAction, -} from 'shared-core/dist/utils/helpers/redux' - -export function loginRequest(payload: { token: string }) { - return createAction('LOGIN_REQUEST', payload) -} - -export function loginSuccess(user: GitHubUser) { - return createAction('LOGIN_SUCCESS', user) -} - -type HttpError = Error & { code: number } // TODO: Get this type from somewhere else -export function loginFailure(error: E) { - return createErrorAction('LOGIN_FAILURE', error) -} - -export function logout() { - return createAction('LOGOUT') -} diff --git a/packages/shared-components/src/redux/actions/index.ts b/packages/shared-components/src/redux/actions/index.ts index 79e7a20b..e9c689ec 100644 --- a/packages/shared-components/src/redux/actions/index.ts +++ b/packages/shared-components/src/redux/actions/index.ts @@ -1,5 +1,2 @@ -export * from './auth' -export * from './columns' -export * from './config' +export * from 'shared-core/dist/redux/actions' export * from './navigation' -export * from './subscriptions' diff --git a/packages/shared-components/src/redux/reducers/auth.ts b/packages/shared-components/src/redux/reducers/auth.ts index 47940092..19c123f3 100644 --- a/packages/shared-components/src/redux/reducers/auth.ts +++ b/packages/shared-components/src/redux/reducers/auth.ts @@ -34,7 +34,7 @@ export const authReducer: Reducer = (state = initialState, action) => { isLoggingIn: false, lastLoginAt: new Date().toISOString(), token: state.token, - user: action.payload, + user: action.payload.user, } case 'LOGIN_FAILURE': diff --git a/packages/shared-components/src/redux/sagas/auth.ts b/packages/shared-components/src/redux/sagas/auth.ts index b47cf247..f47c556d 100644 --- a/packages/shared-components/src/redux/sagas/auth.ts +++ b/packages/shared-components/src/redux/sagas/auth.ts @@ -20,13 +20,33 @@ function* onLoginRequest( try { github.authenticate(action.payload.token || '') + const response = yield fetch('/api/redux', { + method: 'POST', + body: JSON.stringify({ action }), + }) + const body = yield response.json() + if (!(body && body.action && body.action.type)) + throw new Error('Invalid response') + + yield put(body.action) + return + } catch (error) { + console.error(error) + + if (error && error.response && error.response.action) { + yield put(error.response.action) + return + } + } + + try { const response = yield call(github.octokit.users.get, {}) const user = response.data as GitHubUser if (!(user && user.id && user.login)) throw new Error('Invalid response') - yield put(actions.loginSuccess(user)) - } catch (e) { - yield put(actions.loginFailure(e)) + yield put(actions.loginSuccess({ user })) + } catch (error) { + yield put(actions.loginFailure(error)) } } diff --git a/packages/shared-components/src/redux/sagas/columns.ts b/packages/shared-components/src/redux/sagas/columns.ts index 51035ae2..21ca97dc 100644 --- a/packages/shared-components/src/redux/sagas/columns.ts +++ b/packages/shared-components/src/redux/sagas/columns.ts @@ -67,7 +67,7 @@ function getDefaultColumns(username: string): ColumnAndSubscriptions[] { function* onLoginSuccess( action: ExtractActionFromActionCreator, ) { - const username = action.payload.login + const username = action.payload.user.login const hasCreatedColumn = yield select(selectors.hasCreatedColumnSelector) if (!hasCreatedColumn) yield put(actions.replaceColumns(getDefaultColumns(username))) diff --git a/packages/shared-core/src/redux/actions/auth.ts b/packages/shared-core/src/redux/actions/auth.ts new file mode 100644 index 00000000..ffda4073 --- /dev/null +++ b/packages/shared-core/src/redux/actions/auth.ts @@ -0,0 +1,18 @@ +import { GitHubUser } from '../../types' +import { createAction, createErrorAction } from '../../utils/helpers/redux' + +export function loginRequest(payload: { token: string }) { + return createAction('LOGIN_REQUEST', payload) +} + +export function loginSuccess(payload: { user: GitHubUser }) { + return createAction('LOGIN_SUCCESS', payload) +} + +export function loginFailure(error: { code: number; message: string }) { + return createErrorAction('LOGIN_FAILURE', error) +} + +export function logout() { + return createAction('LOGOUT') +} diff --git a/packages/shared-components/src/redux/actions/columns.ts b/packages/shared-core/src/redux/actions/columns.ts similarity index 92% rename from packages/shared-components/src/redux/actions/columns.ts rename to packages/shared-core/src/redux/actions/columns.ts index 7d7f5460..6891efe7 100644 --- a/packages/shared-components/src/redux/actions/columns.ts +++ b/packages/shared-core/src/redux/actions/columns.ts @@ -3,8 +3,8 @@ import { ColumnFilters, GitHubEvent, GitHubNotificationReason, -} from 'shared-core/dist/types' -import { createAction } from 'shared-core/dist/utils/helpers/redux' +} from '../../types' +import { createAction } from '../../utils/helpers/redux' export function replaceColumns(payload: ColumnAndSubscriptions[]) { return createAction('REPLACE_COLUMNS', payload) diff --git a/packages/shared-components/src/redux/actions/config.ts b/packages/shared-core/src/redux/actions/config.ts similarity index 76% rename from packages/shared-components/src/redux/actions/config.ts rename to packages/shared-core/src/redux/actions/config.ts index a0661e44..e9dc050f 100644 --- a/packages/shared-components/src/redux/actions/config.ts +++ b/packages/shared-core/src/redux/actions/config.ts @@ -1,5 +1,5 @@ -import { ThemePair } from 'shared-core/dist/types' -import { createAction } from 'shared-core/dist/utils/helpers/redux' +import { ThemePair } from '../../types' +import { createAction } from '../../utils/helpers/redux' export function setTheme(payload: { id: ThemePair['id'] diff --git a/packages/shared-core/src/redux/actions/index.ts b/packages/shared-core/src/redux/actions/index.ts new file mode 100644 index 00000000..8e16b8a1 --- /dev/null +++ b/packages/shared-core/src/redux/actions/index.ts @@ -0,0 +1,4 @@ +export * from './auth' +export * from './columns' +export * from './config' +export * from './subscriptions' diff --git a/packages/shared-components/src/redux/actions/subscriptions.ts b/packages/shared-core/src/redux/actions/subscriptions.ts similarity index 64% rename from packages/shared-components/src/redux/actions/subscriptions.ts rename to packages/shared-core/src/redux/actions/subscriptions.ts index 85ae0545..eeaf88dc 100644 --- a/packages/shared-components/src/redux/actions/subscriptions.ts +++ b/packages/shared-core/src/redux/actions/subscriptions.ts @@ -1,4 +1,4 @@ -import { createAction } from 'shared-core/dist/utils/helpers/redux' +import { createAction } from '../../utils/helpers/redux' export function deleteColumnSubscription(columnId: string) { return createAction('DELETE_COLUMN_SUBSCRIPTION', columnId) diff --git a/packages/shared-core/src/redux/types/index.ts b/packages/shared-core/src/redux/types/index.ts new file mode 100644 index 00000000..01d4b5c9 --- /dev/null +++ b/packages/shared-core/src/redux/types/index.ts @@ -0,0 +1,9 @@ +import { ExtractActionFromActionCreator } from '../../types' + +import * as actions from '../actions' + +export type AllActions = ExtractActionFromActionCreator< + typeof actions[keyof typeof actions] +> + +export type Reducer = (state: S | undefined, action: AllActions) => S diff --git a/yarn.lock b/yarn.lock index bc1ab507..a1568931 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1050,6 +1050,13 @@ resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.118.tgz#247bab39bfcc6d910d4927c6e06cbc70ec376f27" integrity sha512-iiJbKLZbhSa6FYRip/9ZDX6HXhayXLDGY2Fqws9cOkEQ6XeKfaxB0sC541mowZJueYyMnVUmmG+al5/4fCDrgw== +"@types/micro@^7.3.3": + version "7.3.3" + resolved "https://registry.npmjs.org/@types/micro/-/micro-7.3.3.tgz#31ead8df18ac10d58b7be1186d4b2d977b13a938" + integrity sha512-I3n3QYT7lqAxkyAoTZyg1yrvo38BxW/7ZafLAXZF/zZQOnAnQzg6j9XOuSmUEL5GGVFKWw4iqM+ZLnqb2154TA== + dependencies: + "@types/node" "*" + "@types/node@*", "@types/node@^10.12.6": version "10.12.6" resolved "https://registry.npmjs.org/@types/node/-/node-10.12.6.tgz#7fc213c1b811c90fc9a3edb6206742b95d697678" @@ -2601,6 +2608,15 @@ caseless@~0.12.0: resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= +chalk@2.4.0: + version "2.4.0" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.0.tgz#a060a297a6b57e15b61ca63ce84995daa0fe6e52" + integrity sha512-Wr/w0f4o9LuE7K53cD0qmbAMM+2XNLzR29vFn5hqko4sxGlUsyy363NvmyGIyk5tpe9cjTr9SJYbysEyPkRnFw== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + chalk@2.4.1, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4.0, chalk@^2.4.1: version "2.4.1" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" @@ -2636,6 +2652,25 @@ check-types@^7.3.0: resolved "https://registry.npmjs.org/check-types/-/check-types-7.4.0.tgz#0378ec1b9616ec71f774931a3c6516fad8c152f4" integrity sha512-YbulWHdfP99UfZ73NcUDlNJhEIDgm9Doq9GhpyXbF+7Aegi3CVV7qqMCKTTqJxlvEvnQBp9IA+dxsGN6xK/nSg== +chokidar@2.0.3: + version "2.0.3" + resolved "http://registry.npmjs.org/chokidar/-/chokidar-2.0.3.tgz#dcbd4f6cbb2a55b4799ba8a840ac527e5f4b1176" + integrity sha512-zW8iXYZtXMx4kux/nuZVXjkLP+CyIK5Al5FHnj1OgTKGZfp4Oy6/ymtMSKFv3GD8DviEmUPmJg9eFdJ/JzudMg== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.0" + braces "^2.3.0" + glob-parent "^3.1.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^2.1.1" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + upath "^1.0.0" + optionalDependencies: + fsevents "^1.1.2" + chokidar@^2.0.0, chokidar@^2.0.2, chokidar@^2.0.4: version "2.0.4" resolved "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" @@ -2996,7 +3031,7 @@ content-disposition@0.5.2: resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= -content-type@~1.0.4: +content-type@1.0.4, content-type@~1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== @@ -3406,6 +3441,11 @@ date-now@^0.1.4: resolved "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs= +debounce@1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/debounce/-/debounce-1.1.0.tgz#6a1a4ee2a9dc4b7c24bb012558dbcdb05b37f408" + integrity sha512-ZQVKfRVlwRfD150ndzEK8M90ABT+Y/JQKs4Y7U4MXdpuoUkkrr4DwKbVux3YjylA5bUMUj0Nc3pMxPJX6N2QQQ== + debounce@^1.1.0: version "1.2.0" resolved "https://registry.npmjs.org/debounce/-/debounce-1.2.0.tgz#44a540abc0ea9943018dc0eaa95cce87f65cd131" @@ -3554,6 +3594,11 @@ denodeify@^1.2.1: resolved "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz#3a36287f5034e699e7577901052c2e6c94251631" integrity sha1-OjYof1A05pnnV3kBBSwubJQlFjE= +depd@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" + integrity sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k= + depd@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" @@ -3751,6 +3796,11 @@ dotenv-expand@4.2.0: resolved "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-4.2.0.tgz#def1f1ca5d6059d24a766e587942c21106ce1275" integrity sha1-3vHxyl1gWdJKdm5YeULCEQbOEnU= +dotenv@5.0.1: + version "5.0.1" + resolved "http://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz#a5317459bd3d79ab88cff6e44057a6a3fbb1fcef" + integrity sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow== + dotenv@6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/dotenv/-/dotenv-6.0.0.tgz#24e37c041741c5f4b25324958ebbc34bca965935" @@ -4881,7 +4931,7 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@1.2.4, fsevents@^1.2.2, fsevents@^1.2.3: +fsevents@1.2.4, fsevents@^1.1.2, fsevents@^1.2.2, fsevents@^1.2.3: version "1.2.4" resolved "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" integrity sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg== @@ -4948,6 +4998,11 @@ get-own-enumerable-property-symbols@^3.0.0: resolved "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz#b877b49a5c16aefac3655f2ed2ea5b684df8d203" integrity sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg== +get-port@3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc" + integrity sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw= + get-stdin@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" @@ -5438,6 +5493,16 @@ http-deceiver@^1.2.7: resolved "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= +http-errors@1.6.2: + version "1.6.2" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" + integrity sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY= + dependencies: + depd "1.1.1" + inherits "2.0.3" + setprototypeof "1.0.3" + statuses ">= 1.3.1 < 2" + http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: version "1.6.3" resolved "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" @@ -5523,6 +5588,11 @@ hyphenate-style-name@^1.0.2: resolved "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz#31160a36930adaf1fc04c6074f7eb41465d4ec4b" integrity sha1-MRYKNpMK2vH8BMYHT360FGXU7Es= +iconv-lite@0.4.19: + version "0.4.19" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" + integrity sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ== + iconv-lite@0.4.23: version "0.4.23" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" @@ -5766,7 +5836,7 @@ ip-regex@^2.1.0: resolved "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= -ip@^1.1.0, ip@^1.1.5: +ip@1.1.5, ip@^1.1.0, ip@^1.1.5: version "1.1.5" resolved "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= @@ -6091,7 +6161,7 @@ is-root@2.0.0: resolved "https://registry.npmjs.org/is-root/-/is-root-2.0.0.tgz#838d1e82318144e5a6f77819d90207645acc7019" integrity sha512-F/pJIk8QD6OX5DNhRB7hWamLsUilmkDGho48KbgZ6xg/lmAZXHxzXQ91jzB3yRSw5kdQGGGc4yz8HYhTYIMWPg== -is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: +is-stream@1.1.0, is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= @@ -6740,6 +6810,15 @@ jsesc@~0.5.0: resolved "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= +jsome@2.5.0: + version "2.5.0" + resolved "https://registry.npmjs.org/jsome/-/jsome-2.5.0.tgz#5e417eef4341ffeb83ee8bfa9265b36d56fe49ed" + integrity sha1-XkF+70NB/+uD7ov6kmWzbVb+Se0= + dependencies: + chalk "^2.3.0" + json-stringify-safe "^5.0.1" + yargs "^11.0.0" + json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" @@ -6767,7 +6846,7 @@ json-stable-stringify@^1.0.1: dependencies: jsonify "~0.0.0" -json-stringify-safe@~5.0.1: +json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= @@ -7566,6 +7645,36 @@ metro@0.48.3, metro@^0.48.1: xpipe "^1.0.5" yargs "^9.0.0" +micro-dev@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/micro-dev/-/micro-dev-3.0.0.tgz#cea7ef2b4318765b74004e98ec92ac7e12fcff37" + integrity sha512-hxI93KdT7Y8utmVn3NsXqMEKOQj0RpHiY1+PW8rtbiDyd3e/D6NN7OEdG8R0uSFI3GuJbkYN76Z2QTZafyfN/w== + dependencies: + boxen "1.3.0" + chalk "2.4.1" + chokidar "2.0.3" + clipboardy "1.2.3" + debounce "1.1.0" + dotenv "5.0.1" + get-port "3.2.0" + ip "1.1.5" + jsome "2.5.0" + mri "1.1.1" + pkg-up "2.0.0" + pretty-error "2.1.1" + string-length "2.0.0" + +micro@^9.3.3: + version "9.3.3" + resolved "https://registry.npmjs.org/micro/-/micro-9.3.3.tgz#32728c7be15e807691ead85da27fd8117a8bca24" + integrity sha512-GbCp4NFQguARch0odX+BuWDja2Kc1pbYZqWfRvEDihGFTJG8U77C0L+Owg2j7TPyhQ5Tc+7z/SxspRqjdiZCjQ== + dependencies: + arg "2.0.0" + chalk "2.4.0" + content-type "1.0.4" + is-stream "1.1.0" + raw-body "2.3.2" + micromatch@^2.3.11: version "2.3.11" resolved "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" @@ -7814,6 +7923,11 @@ move-concurrently@^1.0.1: rimraf "^2.5.4" run-queue "^1.0.3" +mri@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/mri/-/mri-1.1.1.tgz#85aa26d3daeeeedf80dc5984af95cc5ca5cad9f1" + integrity sha1-haom09ru7t+A3FmEr5XMXKXK2fE= + ms@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -9372,7 +9486,7 @@ pretty-bytes@^4.0.2: resolved "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-4.0.2.tgz#b2bf82e7350d65c6c33aa95aaa5a4f6327f61cd9" integrity sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk= -pretty-error@^2.0.2: +pretty-error@2.1.1, pretty-error@^2.0.2: version "2.1.1" resolved "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz#5f4f87c8f91e5ae3f3ba87ab4cf5e03b1a17f1a3" integrity sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM= @@ -9594,6 +9708,16 @@ range-parser@1.2.0, range-parser@^1.0.3, range-parser@~1.2.0: resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= +raw-body@2.3.2: + version "2.3.2" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" + integrity sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k= + dependencies: + bytes "3.0.0" + http-errors "1.6.2" + iconv-lite "0.4.19" + unpipe "1.0.0" + raw-body@2.3.3: version "2.3.3" resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" @@ -10688,6 +10812,11 @@ setimmediate@^1.0.4, setimmediate@^1.0.5: resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= +setprototypeof@1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" + integrity sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ= + setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" @@ -11040,7 +11169,7 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" -"statuses@>= 1.4.0 < 2": +"statuses@>= 1.3.1 < 2", "statuses@>= 1.4.0 < 2": version "1.5.0" resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= @@ -11102,7 +11231,7 @@ string-argv@^0.0.2: resolved "https://registry.npmjs.org/string-argv/-/string-argv-0.0.2.tgz#dac30408690c21f3c3630a3ff3a05877bdcbd736" integrity sha1-2sMECGkMIfPDYwo/86BYd73L1zY= -string-length@^2.0.0: +string-length@2.0.0, string-length@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed" integrity sha1-1A27aGo6zpYMHP/KVivyxF+DY+0= @@ -11793,7 +11922,7 @@ unzip-response@^2.0.1: resolved "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" integrity sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c= -upath@^1.0.5: +upath@^1.0.0, upath@^1.0.5: version "1.1.0" resolved "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" integrity sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==