hapi-oauth
Advanced tools
Comparing version 0.4.0 to 0.5.0
@@ -0,0 +0,0 @@ export * from './src/plugin'; |
@@ -0,0 +0,0 @@ "use strict"; |
@@ -1,3 +0,3 @@ | ||
import { Request, ReplyNoContinue } from 'hapi'; | ||
import { Provider } from './provider'; | ||
import { Request } from "hapi"; | ||
import { Provider } from "./provider"; | ||
export interface LinkSuccess { | ||
@@ -12,5 +12,5 @@ provider: Provider; | ||
export declare class OAuthHandler { | ||
onLink(res: LinkSuccess, request: Request, reply: ReplyNoContinue): void; | ||
onError(res: LinkError, request: Request, reply: ReplyNoContinue): void; | ||
onLink(res: LinkSuccess, request: Request): Promise<any>; | ||
onError(res: LinkError, request: Request): Promise<any>; | ||
preAuthUrl(query: any, provider: Provider, request: Request): Promise<void>; | ||
} |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const Boom = require("boom"); | ||
class OAuthHandler { | ||
onLink(res, request, reply) { | ||
reply(res.data); | ||
onLink(res, request) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return res.data; | ||
}); | ||
} | ||
onError(res, request, reply) { | ||
reply(Boom.badImplementation(res.error)); | ||
onError(res, request) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
throw Boom.badImplementation(res.error); | ||
}); | ||
} | ||
preAuthUrl(query, provider, request) { | ||
return Promise.resolve(); | ||
return __awaiter(this, void 0, void 0, function* () { }); | ||
} | ||
} | ||
exports.OAuthHandler = OAuthHandler; |
@@ -1,13 +0,4 @@ | ||
import * as Hapi from 'hapi'; | ||
import { OAuthHandler } from './handler'; | ||
import { Provider } from './provider'; | ||
export declare type NextFunc = (err?: any) => void; | ||
export interface Plugin { | ||
(): void; | ||
attributes: { | ||
pkg?: any; | ||
name?: string; | ||
version?: string; | ||
}; | ||
} | ||
import * as Hapi from "hapi"; | ||
import { OAuthHandler } from "./handler"; | ||
import { Provider } from "./provider"; | ||
export interface PluginOptions { | ||
@@ -17,5 +8,5 @@ providers: Provider[]; | ||
handler?: OAuthHandler; | ||
requestConfig?: Hapi.RouteAdditionalConfigurationOptions; | ||
linkConfig?: Hapi.RouteAdditionalConfigurationOptions; | ||
requestConfig?: Hapi.RouteOptions; | ||
linkConfig?: Hapi.RouteOptions; | ||
} | ||
export declare const register: Plugin; | ||
export declare const plugin: Hapi.Plugin<PluginOptions>; |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const handler_1 = require("./handler"); | ||
const provider_1 = require("./provider"); | ||
exports.register = function (server, options, next) { | ||
if (!options.providers) { | ||
throw new Error('Providers array not supplied'); | ||
} | ||
options.baseUrl = options.baseUrl || server.info.uri; | ||
options.handler = options.handler || new handler_1.OAuthHandler(); | ||
options.providers.forEach((provider) => { | ||
provider_1.registerProvider(server, options, provider); | ||
}); | ||
next(); | ||
const pkg = require('../package.json'); | ||
exports.plugin = { | ||
name: pkg.name, | ||
version: pkg.version, | ||
register(server, options) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (!options.providers) { | ||
throw new Error("Providers array not supplied"); | ||
} | ||
options.baseUrl = options.baseUrl || server.info.uri; | ||
options.handler = options.handler || new handler_1.OAuthHandler(); | ||
options.providers.forEach(provider => { | ||
provider_1.registerProvider(server, options, provider); | ||
}); | ||
}); | ||
}, | ||
}; | ||
exports.register.attributes = { | ||
name: 'hapi-oauth', | ||
version: '0.0.0', | ||
}; |
export interface Profile { | ||
getUniqueId(): any; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); |
@@ -1,4 +0,4 @@ | ||
import * as Hapi from 'hapi'; | ||
import { PluginOptions } from './plugin'; | ||
import { Profile } from './profile'; | ||
import * as Hapi from "hapi"; | ||
import { PluginOptions } from "./plugin"; | ||
import { Profile } from "./profile"; | ||
export declare type Scopes = string[] | ((provider: string, req: Hapi.Request) => string[]); | ||
@@ -21,5 +21,5 @@ export interface AccessTokens { | ||
extractCode(req: Hapi.Request): any; | ||
handleCode(request: Hapi.Request, options: PluginOptions, redirectUri: string, reply: Hapi.ReplyNoContinue): void; | ||
handleCode(request: Hapi.Request, options: PluginOptions, redirectUri: string): Promise<any>; | ||
getProfile(tokens: AccessTokens): Promise<Profile>; | ||
} | ||
export declare function registerProvider(server: Hapi.Server, options: PluginOptions, provider: Provider): void; |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -11,6 +19,6 @@ const qs = require("querystring"); | ||
} | ||
return this.getScopes(req).join(' '); | ||
return this.getScopes(req).join(" "); | ||
} | ||
getScopes(req) { | ||
if (typeof this.scopes === 'function') { | ||
if (typeof this.scopes === "function") { | ||
return this.scopes(this.name, req); | ||
@@ -22,3 +30,3 @@ } | ||
const query = { | ||
response_type: 'code', | ||
response_type: "code", | ||
redirect_uri: redirectUri, | ||
@@ -29,5 +37,6 @@ client_id: this.clientId, | ||
if (scopes) { | ||
query['scope'] = scopes; | ||
query["scope"] = scopes; | ||
} | ||
return options.handler.preAuthUrl(query, this, req) | ||
return options.handler | ||
.preAuthUrl(query, this, req) | ||
.then(() => `${this.authUrl}?${qs.stringify(query)}`); | ||
@@ -40,7 +49,8 @@ } | ||
payload: { | ||
code, redirect_uri, | ||
code, | ||
redirect_uri, | ||
client_id: this.clientId, | ||
client_secret: this.clientSecret, | ||
grant_type: 'authorization_code', | ||
} | ||
grant_type: "authorization_code", | ||
}, | ||
}, (err, message, res) => { | ||
@@ -62,17 +72,16 @@ if (err) { | ||
extractCode(req) { | ||
return req.query['code']; | ||
return req.query["code"]; | ||
} | ||
handleCode(request, options, redirectUri, reply) { | ||
const code = this.extractCode(request); | ||
if (!code) { | ||
reply(Boom.unauthorized('Missing code')); | ||
return; | ||
} | ||
this.requestToken(code, redirectUri) | ||
.then(data => options.handler.onLink({ provider: this, data }, request, reply), error => options.handler.onError({ provider: this, error }, request, reply)); | ||
handleCode(request, options, redirectUri) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const code = this.extractCode(request); | ||
if (!code) { | ||
throw Boom.unauthorized("Missing code"); | ||
} | ||
return this.requestToken(code, redirectUri).then(data => options.handler.onLink({ provider: this, data }, request), error => options.handler.onError({ provider: this, error }, request)); | ||
}); | ||
} | ||
/*abstract*/ getProfile(tokens) { | ||
throw new Error('Not implemented'); | ||
throw new Error("Not implemented"); | ||
} | ||
; | ||
} | ||
@@ -83,19 +92,20 @@ exports.Provider = Provider; | ||
server.route({ | ||
method: 'GET', | ||
method: "GET", | ||
path: `/oauth/${provider.name}/request`, | ||
config: options.requestConfig, | ||
options: options.requestConfig, | ||
handler: function (request, reply) { | ||
provider.compileAuthUrl(request, options, redirectUri) | ||
.then(url => reply({ url })); | ||
return provider | ||
.compileAuthUrl(request, options, redirectUri) | ||
.then(url => ({ url })); | ||
}, | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
method: "GET", | ||
path: `/oauth/${provider.name}`, | ||
config: options.linkConfig, | ||
options: options.linkConfig, | ||
handler: function (request, reply) { | ||
provider.handleCode(request, options, redirectUri, reply); | ||
} | ||
return provider.handleCode(request, options, redirectUri); | ||
}, | ||
}); | ||
} | ||
exports.registerProvider = registerProvider; |
@@ -1,3 +0,3 @@ | ||
import { Provider, Scopes, AccessTokens } from '../provider'; | ||
import { Profile } from '../profile'; | ||
import { Provider, Scopes, AccessTokens } from "../provider"; | ||
import { Profile } from "../profile"; | ||
export declare class DiscordProfile implements Profile { | ||
@@ -4,0 +4,0 @@ id: string; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const { name, version } = require('../../../package.json'); | ||
const { name, version } = require("../../../package.json"); | ||
const node_fetch_1 = require("node-fetch"); | ||
@@ -22,21 +22,22 @@ const querystring_1 = require("querystring"); | ||
this.scopes = scopes; | ||
this.name = 'discord'; | ||
this.tokenUrl = 'https://discordapp.com/api/oauth2/token'; | ||
this.authUrl = 'https://discordapp.com/api/oauth2/authorize'; | ||
this.profileUrl = 'https://discordapp.com/api/users/@me'; | ||
this.name = "discord"; | ||
this.tokenUrl = "https://discordapp.com/api/oauth2/token"; | ||
this.authUrl = "https://discordapp.com/api/oauth2/authorize"; | ||
this.profileUrl = "https://discordapp.com/api/users/@me"; | ||
} | ||
requestToken(code, redirect_uri) { | ||
return node_fetch_1.default(this.tokenUrl, { | ||
method: 'POST', | ||
method: "POST", | ||
headers: { | ||
'Accept-Encoding': 'gzip,deflate', | ||
'Content-Type': 'application/x-www-form-urlencoded' | ||
"Accept-Encoding": "gzip,deflate", | ||
"Content-Type": "application/x-www-form-urlencoded", | ||
}, | ||
body: querystring_1.stringify({ | ||
code, redirect_uri, | ||
code, | ||
redirect_uri, | ||
client_id: this.clientId, | ||
client_secret: this.clientSecret, | ||
grant_type: 'authorization_code', | ||
grant_type: "authorization_code", | ||
}), | ||
compress: true | ||
compress: true, | ||
}) | ||
@@ -50,6 +51,6 @@ .then(res => res.json()) | ||
Authorization: `Bearer ${tokens.access_token}`, | ||
'Accept-Encoding': 'gzip,deflate', | ||
'User-Agent': `${name} (https://github.com/UnwrittenFun/hapi-oauth, ${version})`, | ||
"Accept-Encoding": "gzip,deflate", | ||
"User-Agent": `${name} (https://github.com/UnwrittenFun/hapi-oauth, ${version})`, | ||
}, | ||
compress: true | ||
compress: true, | ||
}) | ||
@@ -56,0 +57,0 @@ .then(res => res.json()) |
@@ -1,6 +0,6 @@ | ||
export * from './discord'; | ||
export * from './mixer'; | ||
export * from './patreon'; | ||
export * from './picarto'; | ||
export * from './smashcast'; | ||
export * from './twitch'; | ||
export * from "./discord"; | ||
export * from "./mixer"; | ||
export * from "./patreon"; | ||
export * from "./picarto"; | ||
export * from "./smashcast"; | ||
export * from "./twitch"; |
@@ -0,0 +0,0 @@ "use strict"; |
@@ -1,3 +0,3 @@ | ||
import { Provider, Scopes, AccessTokens } from '../provider'; | ||
import { Profile } from '../profile'; | ||
import { Provider, Scopes, AccessTokens } from "../provider"; | ||
import { Profile } from "../profile"; | ||
export declare class MixerProfile implements Profile { | ||
@@ -4,0 +4,0 @@ id: number; |
@@ -20,6 +20,6 @@ "use strict"; | ||
this.scopes = scopes; | ||
this.name = 'mixer'; | ||
this.tokenUrl = 'https://mixer.com/api/v1/oauth/token'; | ||
this.authUrl = 'https://mixer.com/oauth/authorize'; | ||
this.profileUrl = 'https://mixer.com/api/v1/users/current'; | ||
this.name = "mixer"; | ||
this.tokenUrl = "https://mixer.com/api/v1/oauth/token"; | ||
this.authUrl = "https://mixer.com/oauth/authorize"; | ||
this.profileUrl = "https://mixer.com/api/v1/users/current"; | ||
} | ||
@@ -26,0 +26,0 @@ getProfile(tokens) { |
@@ -1,2 +0,2 @@ | ||
import { Provider, Scopes } from '../provider'; | ||
import { Provider, Scopes } from "../provider"; | ||
export declare class PatreonProvider extends Provider { | ||
@@ -3,0 +3,0 @@ clientId: string; |
@@ -12,5 +12,5 @@ "use strict"; | ||
this.scopes = scopes; | ||
this.name = 'patreon'; | ||
this.tokenUrl = 'https://api.patreon.com/oauth2/token'; | ||
this.authUrl = 'https://www.patreon.com/oauth2/authorize'; | ||
this.name = "patreon"; | ||
this.tokenUrl = "https://api.patreon.com/oauth2/token"; | ||
this.authUrl = "https://www.patreon.com/oauth2/authorize"; | ||
} | ||
@@ -20,9 +20,10 @@ requestToken(code, redirect_uri) { | ||
const query = { | ||
code, redirect_uri, | ||
code, | ||
redirect_uri, | ||
client_id: this.clientId, | ||
client_secret: this.clientSecret, | ||
grant_type: 'authorization_code', | ||
grant_type: "authorization_code", | ||
}; | ||
Wreck.post(`${this.tokenUrl}?${qs.stringify(query)}`, { | ||
json: true | ||
json: true, | ||
}, (err, message, res) => { | ||
@@ -29,0 +30,0 @@ if (err) { |
@@ -1,3 +0,3 @@ | ||
import { Provider, Scopes, AccessTokens } from '../provider'; | ||
import { Profile } from '../profile'; | ||
import { Provider, Scopes, AccessTokens } from "../provider"; | ||
import { Profile } from "../profile"; | ||
export declare class PicartoProfile implements Profile { | ||
@@ -4,0 +4,0 @@ channel_details: { |
@@ -22,6 +22,6 @@ "use strict"; | ||
this.scopes = scopes; | ||
this.name = 'picarto'; | ||
this.tokenUrl = 'https://oauth.picarto.tv/token'; | ||
this.authUrl = 'https://oauth.picarto.tv/authorize'; | ||
this.profileUrl = 'https://api.picarto.tv/v1/user'; | ||
this.name = "picarto"; | ||
this.tokenUrl = "https://oauth.picarto.tv/token"; | ||
this.authUrl = "https://oauth.picarto.tv/authorize"; | ||
this.profileUrl = "https://api.picarto.tv/v1/user"; | ||
} | ||
@@ -31,9 +31,10 @@ requestToken(code, redirect_uri) { | ||
const query = { | ||
code, redirect_uri, | ||
code, | ||
redirect_uri, | ||
client_id: this.clientId, | ||
client_secret: this.clientSecret, | ||
grant_type: 'authorization_code', | ||
grant_type: "authorization_code", | ||
}; | ||
Wreck.post(`${this.tokenUrl}?${qs.stringify(query)}`, { | ||
json: true | ||
json: true, | ||
}, (err, message, res) => { | ||
@@ -58,3 +59,3 @@ if (err) { | ||
Authorization: `Bearer ${tokens.access_token}`, | ||
} | ||
}, | ||
}) | ||
@@ -61,0 +62,0 @@ .then(res => res.json()) |
@@ -1,4 +0,4 @@ | ||
import * as Hapi from 'hapi'; | ||
import { Provider } from '../provider'; | ||
import { PluginOptions } from '../plugin'; | ||
import * as Hapi from "hapi"; | ||
import { Provider } from "../provider"; | ||
import { PluginOptions } from "../plugin"; | ||
export declare class SmashcastProvider extends Provider { | ||
@@ -15,3 +15,3 @@ clientId: string; | ||
requestToken(code: string, redirect_uri: string): Promise<{}>; | ||
handleCode(request: Hapi.Request, options: PluginOptions, redirectUri: string, reply: Hapi.ReplyNoContinue): void; | ||
handleCode(request: Hapi.Request, options: PluginOptions, redirectUri: string): any; | ||
} |
@@ -11,6 +11,6 @@ "use strict"; | ||
this.clientSecret = clientSecret; | ||
this.name = 'smashcast'; | ||
this.tokenUrl = 'https://api.smashcast.tv/oauth/exchange'; | ||
this.authUrl = 'https://api.smashcast.tv/oauth/login'; | ||
this.hash = new Buffer(`${clientId} ${clientSecret}`).toString('base64'); | ||
this.name = "smashcast"; | ||
this.tokenUrl = "https://api.smashcast.tv/oauth/exchange"; | ||
this.authUrl = "https://api.smashcast.tv/oauth/login"; | ||
this.hash = new Buffer(`${clientId} ${clientSecret}`).toString("base64"); | ||
} | ||
@@ -21,7 +21,8 @@ compileAuthUrl(req, options, redirectUri) { | ||
}; | ||
return options.handler.preAuthUrl(query, this, req) | ||
return options.handler | ||
.preAuthUrl(query, this, req) | ||
.then(() => `${this.authUrl}?${qs.stringify(query)}`); | ||
} | ||
extractCode(req) { | ||
return req.query['request_token']; | ||
return req.query["request_token"]; | ||
} | ||
@@ -36,3 +37,3 @@ requestToken(code, redirect_uri) { | ||
hash: this.hash, | ||
} | ||
}, | ||
}, (err, message, res) => { | ||
@@ -44,7 +45,7 @@ if (err) { | ||
if (res instanceof Buffer) { | ||
res = res.toString('utf8'); | ||
res = res.toString("utf8"); | ||
try { | ||
res = JSON.parse(res); | ||
} | ||
catch (_) { | ||
catch (_a) { | ||
reject(new Error(res)); | ||
@@ -64,13 +65,12 @@ return; | ||
} | ||
handleCode(request, options, redirectUri, reply) { | ||
if (request.query['authToken']) { | ||
handleCode(request, options, redirectUri) { | ||
if (request.query["authToken"]) { | ||
const data = { | ||
access_token: request.query['authToken'], | ||
access_token: request.query["authToken"], | ||
}; | ||
options.handler.onLink({ provider: this, data }, request, reply); | ||
return; | ||
return options.handler.onLink({ provider: this, data }, request); | ||
} | ||
super.handleCode(request, options, redirectUri, reply); | ||
return super.handleCode(request, options, redirectUri); | ||
} | ||
} | ||
exports.SmashcastProvider = SmashcastProvider; |
@@ -1,2 +0,2 @@ | ||
import { Provider, Scopes, AccessTokens } from '../provider'; | ||
import { Provider, Scopes, AccessTokens } from "../provider"; | ||
import { Profile } from "../profile"; | ||
@@ -3,0 +3,0 @@ export declare class TwitchProfile implements Profile { |
@@ -20,6 +20,6 @@ "use strict"; | ||
this.scopes = scopes; | ||
this.name = 'twitch'; | ||
this.tokenUrl = 'https://api.twitch.tv/kraken/oauth2/token'; | ||
this.authUrl = 'https://api.twitch.tv/kraken/oauth2/authorize'; | ||
this.profileUrl = 'https://api.twitch.tv/kraken/user'; | ||
this.name = "twitch"; | ||
this.tokenUrl = "https://api.twitch.tv/kraken/oauth2/token"; | ||
this.authUrl = "https://api.twitch.tv/kraken/oauth2/authorize"; | ||
this.profileUrl = "https://api.twitch.tv/kraken/user"; | ||
} | ||
@@ -29,6 +29,6 @@ getProfile(tokens) { | ||
headers: { | ||
Accept: 'application/vnd.twitchtv.v5+json', | ||
'Client-ID': this.clientId, | ||
Accept: "application/vnd.twitchtv.v5+json", | ||
"Client-ID": this.clientId, | ||
Authorization: `OAuth ${tokens.access_token}`, | ||
} | ||
}, | ||
}) | ||
@@ -35,0 +35,0 @@ .then(res => res.json()) |
{ | ||
"name": "hapi-oauth", | ||
"version": "0.4.0", | ||
"version": "0.5.0", | ||
"description": "Hapi oauth plugin", | ||
@@ -8,3 +8,3 @@ "main": "dist/index.js", | ||
"scripts": { | ||
"build": "tsc", | ||
"build": "rm -rf dist && tsc", | ||
"prepublish": "npm run build" | ||
@@ -19,14 +19,14 @@ }, | ||
"dependencies": { | ||
"boom": "^5.1.0", | ||
"hapi": "^16.4.3", | ||
"node-fetch": "^1.6.3", | ||
"wreck": "^12.2.2" | ||
"boom": "^7.1.1", | ||
"hapi": "^17.2.0", | ||
"node-fetch": "^2.0.0", | ||
"wreck": "^14.0.2" | ||
}, | ||
"devDependencies": { | ||
"@types/boom": "^4.3.5", | ||
"@types/hapi": "^16.1.5", | ||
"@types/node-fetch": "^1.6.5", | ||
"@types/wreck": "^7.0.28", | ||
"typescript": "^2.0.3" | ||
"@types/boom": "^7.1.1", | ||
"@types/hapi": "^17.0.1", | ||
"@types/node-fetch": "^1.6.7", | ||
"@types/wreck": "^7.0.29", | ||
"typescript": "^2.7.2" | ||
} | ||
} |
@@ -1,5 +0,5 @@ | ||
import * as Boom from 'boom'; | ||
import { Request, ReplyNoContinue } from 'hapi'; | ||
import * as Boom from "boom"; | ||
import { Request } from "hapi"; | ||
import { Provider } from './provider'; | ||
import { Provider } from "./provider"; | ||
@@ -17,13 +17,15 @@ export interface LinkSuccess { | ||
export class OAuthHandler { | ||
public onLink(res: LinkSuccess, request: Request, reply: ReplyNoContinue): void { | ||
reply(res.data); | ||
public async onLink(res: LinkSuccess, request: Request): Promise<any> { | ||
return res.data; | ||
} | ||
public onError(res: LinkError, request: Request, reply: ReplyNoContinue): void { | ||
reply(Boom.badImplementation(res.error)); | ||
public async onError(res: LinkError, request: Request): Promise<any> { | ||
throw Boom.badImplementation(res.error); | ||
} | ||
public preAuthUrl(query: any, provider: Provider, request: Request): Promise<void> { | ||
return Promise.resolve(); | ||
} | ||
public async preAuthUrl( | ||
query: any, | ||
provider: Provider, | ||
request: Request, | ||
): Promise<void> {} | ||
} |
@@ -1,15 +0,7 @@ | ||
import * as Hapi from 'hapi'; | ||
import * as Hapi from "hapi"; | ||
import { OAuthHandler } from './handler'; | ||
import { Provider, registerProvider } from './provider'; | ||
import { OAuthHandler } from "./handler"; | ||
import { Provider, registerProvider } from "./provider"; | ||
export type NextFunc = (err?: any) => void; | ||
export interface Plugin { | ||
(): void; | ||
attributes: { | ||
pkg?: any; | ||
name?: string; | ||
version?: string; | ||
} | ||
} | ||
const pkg = require('../package.json'); | ||
@@ -21,24 +13,21 @@ export interface PluginOptions { | ||
handler?: OAuthHandler; | ||
requestConfig?: Hapi.RouteAdditionalConfigurationOptions; | ||
linkConfig?: Hapi.RouteAdditionalConfigurationOptions; | ||
requestConfig?: Hapi.RouteOptions; | ||
linkConfig?: Hapi.RouteOptions; | ||
} | ||
export const register = <Plugin> function (server: Hapi.Server, options: PluginOptions, next: NextFunc) { | ||
if (!options.providers) { | ||
throw new Error('Providers array not supplied'); | ||
} | ||
export const plugin: Hapi.Plugin<PluginOptions> = { | ||
name: pkg.name, | ||
version: pkg.version, | ||
async register(server, options) { | ||
if (!options.providers) { | ||
throw new Error("Providers array not supplied"); | ||
} | ||
options.baseUrl = options.baseUrl || server.info.uri; | ||
options.handler = options.handler || new OAuthHandler(); | ||
options.baseUrl = options.baseUrl || server.info.uri; | ||
options.handler = options.handler || new OAuthHandler(); | ||
options.providers.forEach((provider) => { | ||
registerProvider(server, options, provider); | ||
}); | ||
next(); | ||
options.providers.forEach(provider => { | ||
registerProvider(server, options, provider); | ||
}); | ||
}, | ||
}; | ||
register.attributes = { | ||
name: 'hapi-oauth', | ||
version: '0.0.0', | ||
}; |
@@ -1,10 +0,12 @@ | ||
import * as Hapi from 'hapi'; | ||
import * as qs from 'querystring'; | ||
import * as Boom from 'boom'; | ||
import * as Wreck from 'wreck'; | ||
import * as Hapi from "hapi"; | ||
import * as qs from "querystring"; | ||
import * as Boom from "boom"; | ||
import * as Wreck from "wreck"; | ||
import { PluginOptions } from './plugin'; | ||
import { Profile } from './profile'; | ||
import { PluginOptions } from "./plugin"; | ||
import { Profile } from "./profile"; | ||
export type Scopes = string[] | ((provider: string, req: Hapi.Request) => string[]); | ||
export type Scopes = | ||
| string[] | ||
| ((provider: string, req: Hapi.Request) => string[]); | ||
export interface AccessTokens { | ||
@@ -28,7 +30,7 @@ access_token: string; | ||
return this.getScopes(req).join(' '); | ||
return this.getScopes(req).join(" "); | ||
} | ||
getScopes(req: Hapi.Request): string[] { | ||
if (typeof this.scopes === 'function') { | ||
if (typeof this.scopes === "function") { | ||
return this.scopes(this.name, req); | ||
@@ -40,5 +42,9 @@ } | ||
compileAuthUrl(req: Hapi.Request, options: PluginOptions, redirectUri: string) { | ||
compileAuthUrl( | ||
req: Hapi.Request, | ||
options: PluginOptions, | ||
redirectUri: string, | ||
) { | ||
const query = { | ||
response_type: 'code', | ||
response_type: "code", | ||
redirect_uri: redirectUri, | ||
@@ -50,7 +56,8 @@ client_id: this.clientId, | ||
if (scopes) { | ||
query['scope'] = scopes; | ||
query["scope"] = scopes; | ||
} | ||
return options.handler.preAuthUrl(query, this, req) | ||
.then(() => `${this.authUrl}?${qs.stringify(query)}`) | ||
return options.handler | ||
.preAuthUrl(query, this, req) | ||
.then(() => `${this.authUrl}?${qs.stringify(query)}`); | ||
} | ||
@@ -60,62 +67,77 @@ | ||
return new Promise((resolve, reject) => { | ||
Wreck.post(this.tokenUrl, { | ||
json: true, | ||
payload: { | ||
code, redirect_uri, | ||
client_id: this.clientId, | ||
client_secret: this.clientSecret, | ||
grant_type: 'authorization_code', | ||
} | ||
}, (err, message, res) => { | ||
if (err) { | ||
reject(err); | ||
return; | ||
} | ||
Wreck.post( | ||
this.tokenUrl, | ||
{ | ||
json: true, | ||
payload: { | ||
code, | ||
redirect_uri, | ||
client_id: this.clientId, | ||
client_secret: this.clientSecret, | ||
grant_type: "authorization_code", | ||
}, | ||
}, | ||
(err, message, res) => { | ||
if (err) { | ||
reject(err); | ||
return; | ||
} | ||
if (res.error) { | ||
const error = new Error(res.error_description || res.message); | ||
error.name = res.error; | ||
reject(error); | ||
return; | ||
} | ||
if (res.error) { | ||
const error = new Error( | ||
res.error_description || res.message, | ||
); | ||
error.name = res.error; | ||
reject(error); | ||
return; | ||
} | ||
resolve(res); | ||
}); | ||
}) | ||
resolve(res); | ||
}, | ||
); | ||
}); | ||
} | ||
extractCode(req: Hapi.Request) { | ||
return req.query['code']; | ||
return req.query["code"]; | ||
} | ||
handleCode(request: Hapi.Request, options: PluginOptions, redirectUri: string, reply: Hapi.ReplyNoContinue) { | ||
async handleCode( | ||
request: Hapi.Request, | ||
options: PluginOptions, | ||
redirectUri: string, | ||
) { | ||
const code = this.extractCode(request); | ||
if (!code) { | ||
reply(Boom.unauthorized('Missing code')); | ||
return; | ||
throw Boom.unauthorized("Missing code"); | ||
} | ||
this.requestToken(code, redirectUri) | ||
.then( | ||
data => options.handler.onLink({ provider: this, data }, request, reply), | ||
error => options.handler.onError({ provider: this, error }, request, reply) | ||
) | ||
return this.requestToken(code, redirectUri).then( | ||
data => options.handler.onLink({ provider: this, data }, request), | ||
error => | ||
options.handler.onError({ provider: this, error }, request), | ||
); | ||
} | ||
/*abstract*/ getProfile(tokens: AccessTokens): Promise<Profile> { | ||
throw new Error('Not implemented'); | ||
}; | ||
throw new Error("Not implemented"); | ||
} | ||
} | ||
export function registerProvider(server: Hapi.Server, options: PluginOptions, provider: Provider) { | ||
export function registerProvider( | ||
server: Hapi.Server, | ||
options: PluginOptions, | ||
provider: Provider, | ||
) { | ||
const redirectUri = `${options.baseUrl}/oauth/${provider.name}`; | ||
server.route({ | ||
method: 'GET', | ||
method: "GET", | ||
path: `/oauth/${provider.name}/request`, | ||
config: options.requestConfig, | ||
handler: function (request, reply) { | ||
provider.compileAuthUrl(request, options, redirectUri) | ||
.then(url => reply({ url })); | ||
options: options.requestConfig, | ||
handler: function(request, reply) { | ||
return provider | ||
.compileAuthUrl(request, options, redirectUri) | ||
.then(url => ({ url })); | ||
}, | ||
@@ -125,9 +147,9 @@ }); | ||
server.route({ | ||
method: 'GET', | ||
method: "GET", | ||
path: `/oauth/${provider.name}`, | ||
config: options.linkConfig, | ||
handler: function (request, reply) { | ||
provider.handleCode(request, options, redirectUri, reply); | ||
} | ||
options: options.linkConfig, | ||
handler: function(request, reply) { | ||
return provider.handleCode(request, options, redirectUri); | ||
}, | ||
}); | ||
} |
@@ -1,8 +0,8 @@ | ||
const { name, version } = require('../../../package.json'); | ||
const { name, version } = require("../../../package.json"); | ||
import fetch from 'node-fetch'; | ||
import { stringify } from 'querystring'; | ||
import fetch from "node-fetch"; | ||
import { stringify } from "querystring"; | ||
import { Provider, Scopes, AccessTokens } from '../provider'; | ||
import { Profile } from '../profile'; | ||
import { Provider, Scopes, AccessTokens } from "../provider"; | ||
import { Profile } from "../profile"; | ||
@@ -26,11 +26,15 @@ export class DiscordProfile implements Profile { | ||
} | ||
} | ||
} | ||
export class DiscordProvider extends Provider { | ||
public name = 'discord'; | ||
public tokenUrl = 'https://discordapp.com/api/oauth2/token'; | ||
public authUrl = 'https://discordapp.com/api/oauth2/authorize'; | ||
public profileUrl = 'https://discordapp.com/api/users/@me'; | ||
public name = "discord"; | ||
public tokenUrl = "https://discordapp.com/api/oauth2/token"; | ||
public authUrl = "https://discordapp.com/api/oauth2/authorize"; | ||
public profileUrl = "https://discordapp.com/api/users/@me"; | ||
constructor(public clientId: string, public clientSecret: string, public scopes: Scopes = []) { | ||
constructor( | ||
public clientId: string, | ||
public clientSecret: string, | ||
public scopes: Scopes = [], | ||
) { | ||
super(); | ||
@@ -41,17 +45,18 @@ } | ||
return fetch(this.tokenUrl, { | ||
method: 'POST', | ||
method: "POST", | ||
headers: { | ||
'Accept-Encoding': 'gzip,deflate', | ||
'Content-Type': 'application/x-www-form-urlencoded' | ||
"Accept-Encoding": "gzip,deflate", | ||
"Content-Type": "application/x-www-form-urlencoded", | ||
}, | ||
body: stringify({ | ||
code, redirect_uri, | ||
code, | ||
redirect_uri, | ||
client_id: this.clientId, | ||
client_secret: this.clientSecret, | ||
grant_type: 'authorization_code', | ||
grant_type: "authorization_code", | ||
}), | ||
compress: true | ||
compress: true, | ||
}) | ||
.then(res => res.json()) | ||
.then(token => token); | ||
.then(res => res.json()) | ||
.then(token => token); | ||
} | ||
@@ -63,10 +68,10 @@ | ||
Authorization: `Bearer ${tokens.access_token}`, | ||
'Accept-Encoding': 'gzip,deflate', | ||
'User-Agent': `${name} (https://github.com/UnwrittenFun/hapi-oauth, ${version})`, | ||
"Accept-Encoding": "gzip,deflate", | ||
"User-Agent": `${name} (https://github.com/UnwrittenFun/hapi-oauth, ${version})`, | ||
}, | ||
compress: true | ||
compress: true, | ||
}) | ||
.then(res => res.json()) | ||
.then(profile => new DiscordProfile(profile)); | ||
.then(res => res.json()) | ||
.then(profile => new DiscordProfile(profile)); | ||
} | ||
} |
@@ -1,6 +0,6 @@ | ||
export * from './discord'; | ||
export * from './mixer'; | ||
export * from './patreon'; | ||
export * from './picarto'; | ||
export * from './smashcast'; | ||
export * from './twitch'; | ||
export * from "./discord"; | ||
export * from "./mixer"; | ||
export * from "./patreon"; | ||
export * from "./picarto"; | ||
export * from "./smashcast"; | ||
export * from "./twitch"; |
@@ -1,5 +0,5 @@ | ||
import fetch from 'node-fetch'; | ||
import fetch from "node-fetch"; | ||
import { Provider, Scopes, AccessTokens } from '../provider'; | ||
import { Profile } from '../profile'; | ||
import { Provider, Scopes, AccessTokens } from "../provider"; | ||
import { Profile } from "../profile"; | ||
@@ -31,8 +31,12 @@ export class MixerProfile implements Profile { | ||
export class MixerProvider extends Provider { | ||
public name = 'mixer'; | ||
public tokenUrl = 'https://mixer.com/api/v1/oauth/token'; | ||
public authUrl = 'https://mixer.com/oauth/authorize'; | ||
public profileUrl = 'https://mixer.com/api/v1/users/current'; | ||
public name = "mixer"; | ||
public tokenUrl = "https://mixer.com/api/v1/oauth/token"; | ||
public authUrl = "https://mixer.com/oauth/authorize"; | ||
public profileUrl = "https://mixer.com/api/v1/users/current"; | ||
constructor(public clientId: string, public clientSecret: string, public scopes: Scopes) { | ||
constructor( | ||
public clientId: string, | ||
public clientSecret: string, | ||
public scopes: Scopes, | ||
) { | ||
super(); | ||
@@ -47,5 +51,5 @@ } | ||
}) | ||
.then(res => res.json()) | ||
.then(profile => new MixerProfile(profile)); | ||
.then(res => res.json()) | ||
.then(profile => new MixerProfile(profile)); | ||
} | ||
} |
@@ -1,12 +0,16 @@ | ||
import * as Wreck from 'wreck'; | ||
import * as qs from 'querystring'; | ||
import * as Wreck from "wreck"; | ||
import * as qs from "querystring"; | ||
import { Provider, Scopes } from '../provider'; | ||
import { Provider, Scopes } from "../provider"; | ||
export class PatreonProvider extends Provider { | ||
public name = 'patreon'; | ||
public tokenUrl = 'https://api.patreon.com/oauth2/token'; | ||
public authUrl = 'https://www.patreon.com/oauth2/authorize'; | ||
public name = "patreon"; | ||
public tokenUrl = "https://api.patreon.com/oauth2/token"; | ||
public authUrl = "https://www.patreon.com/oauth2/authorize"; | ||
constructor(public clientId: string, public clientSecret: string, public scopes: Scopes = []) { | ||
constructor( | ||
public clientId: string, | ||
public clientSecret: string, | ||
public scopes: Scopes = [], | ||
) { | ||
super(); | ||
@@ -18,26 +22,31 @@ } | ||
const query = { | ||
code, redirect_uri, | ||
code, | ||
redirect_uri, | ||
client_id: this.clientId, | ||
client_secret: this.clientSecret, | ||
grant_type: 'authorization_code', | ||
} | ||
Wreck.post(`${this.tokenUrl}?${qs.stringify(query)}`, { | ||
json: true | ||
}, (err, message, res) => { | ||
if (err) { | ||
reject(err); | ||
return; | ||
} | ||
grant_type: "authorization_code", | ||
}; | ||
Wreck.post( | ||
`${this.tokenUrl}?${qs.stringify(query)}`, | ||
{ | ||
json: true, | ||
}, | ||
(err, message, res) => { | ||
if (err) { | ||
reject(err); | ||
return; | ||
} | ||
if (res.error) { | ||
const error = new Error(res.error_description); | ||
error.name = err.error; | ||
reject(error); | ||
return; | ||
} | ||
if (res.error) { | ||
const error = new Error(res.error_description); | ||
error.name = err.error; | ||
reject(error); | ||
return; | ||
} | ||
resolve(res); | ||
}); | ||
}) | ||
resolve(res); | ||
}, | ||
); | ||
}); | ||
} | ||
} |
@@ -1,7 +0,7 @@ | ||
import * as Wreck from 'wreck'; | ||
import * as qs from 'querystring'; | ||
import fetch from 'node-fetch'; | ||
import * as Wreck from "wreck"; | ||
import * as qs from "querystring"; | ||
import fetch from "node-fetch"; | ||
import { Provider, Scopes, AccessTokens } from '../provider'; | ||
import { Profile } from '../profile'; | ||
import { Provider, Scopes, AccessTokens } from "../provider"; | ||
import { Profile } from "../profile"; | ||
@@ -51,8 +51,12 @@ export class PicartoProfile implements Profile { | ||
export class PicartoProvider extends Provider { | ||
public name = 'picarto'; | ||
public tokenUrl = 'https://oauth.picarto.tv/token'; | ||
public authUrl = 'https://oauth.picarto.tv/authorize'; | ||
public profileUrl = 'https://api.picarto.tv/v1/user'; | ||
public name = "picarto"; | ||
public tokenUrl = "https://oauth.picarto.tv/token"; | ||
public authUrl = "https://oauth.picarto.tv/authorize"; | ||
public profileUrl = "https://api.picarto.tv/v1/user"; | ||
constructor(public clientId: string, public clientSecret: string, public scopes: Scopes) { | ||
constructor( | ||
public clientId: string, | ||
public clientSecret: string, | ||
public scopes: Scopes, | ||
) { | ||
super(); | ||
@@ -64,25 +68,30 @@ } | ||
const query = { | ||
code, redirect_uri, | ||
code, | ||
redirect_uri, | ||
client_id: this.clientId, | ||
client_secret: this.clientSecret, | ||
grant_type: 'authorization_code', | ||
} | ||
Wreck.post(`${this.tokenUrl}?${qs.stringify(query)}`, { | ||
json: true | ||
}, (err, message, res) => { | ||
if (err) { | ||
reject(err); | ||
return; | ||
} | ||
grant_type: "authorization_code", | ||
}; | ||
Wreck.post( | ||
`${this.tokenUrl}?${qs.stringify(query)}`, | ||
{ | ||
json: true, | ||
}, | ||
(err, message, res) => { | ||
if (err) { | ||
reject(err); | ||
return; | ||
} | ||
if (res.error) { | ||
const error = new Error(res.error_description); | ||
error.name = err.error; | ||
reject(error); | ||
return; | ||
} | ||
if (res.error) { | ||
const error = new Error(res.error_description); | ||
error.name = err.error; | ||
reject(error); | ||
return; | ||
} | ||
resolve(res); | ||
}); | ||
}) | ||
resolve(res); | ||
}, | ||
); | ||
}); | ||
} | ||
@@ -94,3 +103,3 @@ | ||
Authorization: `Bearer ${tokens.access_token}`, | ||
} | ||
}, | ||
}) | ||
@@ -97,0 +106,0 @@ .then(res => res.json()) |
@@ -1,13 +0,13 @@ | ||
import * as Hapi from 'hapi'; | ||
import * as Boom from 'boom'; | ||
import * as Wreck from 'wreck'; | ||
import * as qs from 'querystring'; | ||
import * as Hapi from "hapi"; | ||
import * as Boom from "boom"; | ||
import * as Wreck from "wreck"; | ||
import * as qs from "querystring"; | ||
import { Provider, Scopes } from '../provider'; | ||
import { PluginOptions } from '../plugin'; | ||
import { Provider, Scopes } from "../provider"; | ||
import { PluginOptions } from "../plugin"; | ||
export class SmashcastProvider extends Provider { | ||
public name = 'smashcast'; | ||
public tokenUrl = 'https://api.smashcast.tv/oauth/exchange'; | ||
public authUrl = 'https://api.smashcast.tv/oauth/login'; | ||
public name = "smashcast"; | ||
public tokenUrl = "https://api.smashcast.tv/oauth/exchange"; | ||
public authUrl = "https://api.smashcast.tv/oauth/login"; | ||
@@ -19,6 +19,12 @@ private hash: string; | ||
this.hash = new Buffer(`${clientId} ${clientSecret}`).toString('base64'); | ||
this.hash = new Buffer(`${clientId} ${clientSecret}`).toString( | ||
"base64", | ||
); | ||
} | ||
compileAuthUrl(req: Hapi.Request, options: PluginOptions, redirectUri: string) { | ||
compileAuthUrl( | ||
req: Hapi.Request, | ||
options: PluginOptions, | ||
redirectUri: string, | ||
) { | ||
const query = { | ||
@@ -28,8 +34,9 @@ app_token: this.clientId, | ||
return options.handler.preAuthUrl(query, this, req) | ||
.then(() => `${this.authUrl}?${qs.stringify(query)}`) | ||
return options.handler | ||
.preAuthUrl(query, this, req) | ||
.then(() => `${this.authUrl}?${qs.stringify(query)}`); | ||
} | ||
extractCode(req: Hapi.Request) { | ||
return req.query['request_token']; | ||
return req.query["request_token"]; | ||
} | ||
@@ -39,49 +46,56 @@ | ||
return new Promise((resolve, reject) => { | ||
Wreck.post(this.tokenUrl, { | ||
json: true, | ||
payload: { | ||
request_token: code, | ||
app_token: this.clientId, | ||
hash: this.hash, | ||
} | ||
}, (err, message, res) => { | ||
if (err) { | ||
reject(err); | ||
return; | ||
} | ||
Wreck.post( | ||
this.tokenUrl, | ||
{ | ||
json: true, | ||
payload: { | ||
request_token: code, | ||
app_token: this.clientId, | ||
hash: this.hash, | ||
}, | ||
}, | ||
(err, message, res) => { | ||
if (err) { | ||
reject(err); | ||
return; | ||
} | ||
if (res instanceof Buffer) { | ||
res = res.toString('utf8'); | ||
try { | ||
res = JSON.parse(res); | ||
} catch (_) { | ||
reject(new Error(res)); | ||
if (res instanceof Buffer) { | ||
res = res.toString("utf8"); | ||
try { | ||
res = JSON.parse(res); | ||
} catch { | ||
reject(new Error(res)); | ||
return; | ||
} | ||
} | ||
if (res.error) { | ||
const error = new Error(res.error_description); | ||
error.name = err.error; | ||
reject(error); | ||
return; | ||
} | ||
} | ||
if (res.error) { | ||
const error = new Error(res.error_description); | ||
error.name = err.error; | ||
reject(error); | ||
return; | ||
} | ||
resolve(res); | ||
}); | ||
}) | ||
resolve(res); | ||
}, | ||
); | ||
}); | ||
} | ||
handleCode(request: Hapi.Request, options: PluginOptions, redirectUri: string, reply: Hapi.ReplyNoContinue) { | ||
if (request.query['authToken']) { | ||
handleCode( | ||
request: Hapi.Request, | ||
options: PluginOptions, | ||
redirectUri: string, | ||
) { | ||
if (request.query["authToken"]) { | ||
const data = { | ||
access_token: request.query['authToken'], | ||
} | ||
access_token: request.query["authToken"], | ||
}; | ||
options.handler.onLink({ provider: this, data }, request, reply); | ||
return; | ||
return options.handler.onLink({ provider: this, data }, request); | ||
} | ||
super.handleCode(request, options, redirectUri, reply); | ||
return super.handleCode(request, options, redirectUri); | ||
} | ||
} |
@@ -1,4 +0,4 @@ | ||
import { Provider, Scopes, AccessTokens } from '../provider'; | ||
import { Provider, Scopes, AccessTokens } from "../provider"; | ||
import { Profile } from "../profile"; | ||
import fetch from 'node-fetch'; | ||
import fetch from "node-fetch"; | ||
@@ -28,8 +28,12 @@ export class TwitchProfile implements Profile { | ||
export class TwitchProvider extends Provider { | ||
public name = 'twitch'; | ||
public tokenUrl = 'https://api.twitch.tv/kraken/oauth2/token'; | ||
public authUrl = 'https://api.twitch.tv/kraken/oauth2/authorize'; | ||
public profileUrl = 'https://api.twitch.tv/kraken/user'; | ||
public name = "twitch"; | ||
public tokenUrl = "https://api.twitch.tv/kraken/oauth2/token"; | ||
public authUrl = "https://api.twitch.tv/kraken/oauth2/authorize"; | ||
public profileUrl = "https://api.twitch.tv/kraken/user"; | ||
constructor(public clientId: string, public clientSecret: string, public scopes: Scopes) { | ||
constructor( | ||
public clientId: string, | ||
public clientSecret: string, | ||
public scopes: Scopes, | ||
) { | ||
super(); | ||
@@ -41,10 +45,10 @@ } | ||
headers: { | ||
Accept: 'application/vnd.twitchtv.v5+json', | ||
'Client-ID': this.clientId, | ||
Accept: "application/vnd.twitchtv.v5+json", | ||
"Client-ID": this.clientId, | ||
Authorization: `OAuth ${tokens.access_token}`, | ||
} | ||
}, | ||
}) | ||
.then(res => res.json()) | ||
.then(profile => new TwitchProfile(profile)); | ||
.then(res => res.json()) | ||
.then(profile => new TwitchProfile(profile)); | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
45232
1302
39
+ Addedaccept@3.1.3(transitive)
+ Addedammo@3.0.3(transitive)
+ Addedb64@4.1.2(transitive)
+ Addedbig-time@2.0.1(transitive)
+ Addedboom@7.3.0(transitive)
+ Addedbounce@1.2.3(transitive)
+ Addedcall@5.0.3(transitive)
+ Addedcatbox@10.0.6(transitive)
+ Addedcatbox-memory@3.1.4(transitive)
+ Addedcontent@4.0.6(transitive)
+ Addedcryptiles@4.1.3(transitive)
+ Addedhapi@17.8.5(transitive)
+ Addedheavy@6.1.2(transitive)
+ Addedhoek@6.1.3(transitive)
+ Addediron@5.0.6(transitive)
+ Addedisemail@3.2.0(transitive)
+ Addedjoi@14.3.1(transitive)
+ Addedmimos@4.0.2(transitive)
+ Addednigel@3.0.4(transitive)
+ Addednode-fetch@2.7.0(transitive)
+ Addedpez@4.0.5(transitive)
+ Addedpodium@3.2.0(transitive)
+ Addedpunycode@2.3.1(transitive)
+ Addedshot@4.0.7(transitive)
+ Addedsomever@2.0.0(transitive)
+ Addedstatehood@6.0.9(transitive)
+ Addedsubtext@6.0.12(transitive)
+ Addedteamwork@3.2.0(transitive)
+ Addedtopo@3.0.3(transitive)
+ Addedtr46@0.0.3(transitive)
+ Addedvise@3.0.2(transitive)
+ Addedwebidl-conversions@3.0.1(transitive)
+ Addedwhatwg-url@5.0.0(transitive)
+ Addedwreck@14.2.0(transitive)
- Removed@hapi/address@1.0.1(transitive)
- Removedaccept@2.2.3(transitive)
- Removedammo@2.1.2(transitive)
- Removedb64@3.1.1(transitive)
- Removedboom@5.3.3(transitive)
- Removedcall@4.1.2(transitive)
- Removedcatbox@7.2.1(transitive)
- Removedcatbox-memory@2.1.1(transitive)
- Removedcontent@3.1.2(transitive)
- Removedcryptiles@3.2.1(transitive)
- Removedencoding@0.1.13(transitive)
- Removedhapi@16.8.4(transitive)
- Removedheavy@4.1.1(transitive)
- Removedhoek@4.3.1(transitive)
- Removediconv-lite@0.6.3(transitive)
- Removediron@4.1.1(transitive)
- Removedis-stream@1.1.0(transitive)
- Removeditems@2.2.1(transitive)
- Removedjoi@12.1.1(transitive)
- Removedmimos@3.1.1(transitive)
- Removednigel@2.1.1(transitive)
- Removednode-fetch@1.7.3(transitive)
- Removedpez@2.2.2(transitive)
- Removedpodium@1.4.1(transitive)
- Removedsafer-buffer@2.1.2(transitive)
- Removedshot@3.5.2(transitive)
- Removedsomever@1.1.1(transitive)
- Removedstatehood@5.1.1(transitive)
- Removedsubtext@5.1.3(transitive)
- Removedtopo@2.1.1(transitive)
- Removedvise@2.1.1(transitive)
- Removedwreck@12.6.2(transitive)
Updatedboom@^7.1.1
Updatedhapi@^17.2.0
Updatednode-fetch@^2.0.0
Updatedwreck@^14.0.2