Move auth to the server

Experimenting with an weird redux based server
This commit is contained in:
Bruno Lemos
2018-11-21 04:19:38 -02:00
parent ab3c6969f0
commit bd371f8961
19 changed files with 298 additions and 62 deletions

View File

@@ -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"

View File

@@ -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",

View File

@@ -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
}
}
}

View File

@@ -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,
) {

View File

@@ -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,

View File

@@ -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(

View File

@@ -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(

View File

@@ -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<E extends HttpError>(error: E) {
return createErrorAction('LOGIN_FAILURE', error)
}
export function logout() {
return createAction('LOGOUT')
}

View File

@@ -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'

View File

@@ -34,7 +34,7 @@ export const authReducer: Reducer<State> = (state = initialState, action) => {
isLoggingIn: false,
lastLoginAt: new Date().toISOString(),
token: state.token,
user: action.payload,
user: action.payload.user,
}
case 'LOGIN_FAILURE':

View File

@@ -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))
}
}

View File

@@ -67,7 +67,7 @@ function getDefaultColumns(username: string): ColumnAndSubscriptions[] {
function* onLoginSuccess(
action: ExtractActionFromActionCreator<typeof actions.loginSuccess>,
) {
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)))

View File

@@ -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')
}

View File

@@ -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)

View File

@@ -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']

View File

@@ -0,0 +1,4 @@
export * from './auth'
export * from './columns'
export * from './config'
export * from './subscriptions'

View File

@@ -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)

View File

@@ -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<S = any> = (state: S | undefined, action: AllActions) => S

147
yarn.lock
View File

@@ -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==