hapi-nextauth: update packages, fix linter and typescript
This commit is contained in:
parent
7aa1ec74eb
commit
fbe33c5c7b
6 changed files with 595 additions and 3870 deletions
4209
package-lock.json
generated
4209
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,18 +0,0 @@
|
||||||
.PHONY: fmt test yarn
|
|
||||||
.npmrc:
|
|
||||||
echo '@guardianproject-ops:registry=https://gitlab.com/api/v4/packages/npm/' > .npmrc
|
|
||||||
echo '//gitlab.com/api/v4/packages/npm/:_authToken=${CI_JOB_TOKEN}' >> .npmrc
|
|
||||||
echo '//gitlab.com/api/v4/projects/:_authToken=${CI_JOB_TOKEN}' >> .npmrc
|
|
||||||
echo '//gitlab.com/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=${CI_JOB_TOKEN}' >> .npmrc
|
|
||||||
|
|
||||||
yarn:
|
|
||||||
yarn
|
|
||||||
|
|
||||||
test: yarn
|
|
||||||
mkdir -p coverage
|
|
||||||
yarn lint
|
|
||||||
yarn test
|
|
||||||
|
|
||||||
publish: test .npmrc
|
|
||||||
npm publish
|
|
||||||
|
|
||||||
|
|
@ -8,28 +8,26 @@
|
||||||
"private": false,
|
"private": false,
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^27.0.2",
|
"@types/jest": "^27.0.2",
|
||||||
"@hapi/basic": "^6.0.0",
|
"@hapi/basic": "^7.0.1",
|
||||||
"tsconfig-link": "*",
|
"tsconfig-link": "*",
|
||||||
"eslint-config-link": "*",
|
"eslint-config-link": "*",
|
||||||
"jest-config-link": "*"
|
"jest-config-link": "*",
|
||||||
|
"babel-preset-link": "*"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hapi/hapi": "^20.2.0",
|
"@hapi/hapi": "^21.3.0",
|
||||||
"@hapi/hoek": "^9.2.1",
|
"@hapi/hoek": "^11.0.1",
|
||||||
"joi": "^17.4.2",
|
"joi": "^17.6.1",
|
||||||
"@hapipal/toys": "^3.1.0",
|
|
||||||
"next-auth": "3.29.0"
|
"next-auth": "3.29.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc -p tsconfig.json",
|
"build": "tsc -p tsconfig.json",
|
||||||
"fix:lint": "eslint src --ext .ts --fix",
|
"fix:lint": "eslint src --ext .ts --fix",
|
||||||
"fix:prettier": "prettier \"src/**/*.ts\" --write",
|
"fmt": "prettier \"src/**/*.ts\" --write",
|
||||||
"test": "yarn test:jest && yarn test:lint && yarn test:prettier",
|
"test": "jest --coverage --forceExit --detectOpenHandles --reporters=default --reporters=jest-junit",
|
||||||
"test:lint": "eslint src --ext .ts",
|
"lint": "eslint src --ext .ts",
|
||||||
"test:prettier": "prettier \"src/**/*.ts\" --list-different",
|
"lint-fmt": "prettier \"src/**/*.ts\" --list-different",
|
||||||
"test:jest": "jest --coverage --forceExit --detectOpenHandles --reporters=default --reporters=jest-junit",
|
"doc": "typedoc src/ --exclude '**/*.test.ts' --exclude '**/*.spec.ts' --name $npm_package_name --readme README.md --target es2019 --mode file --out build/docs",
|
||||||
"doc": "yarn run doc:html",
|
|
||||||
"doc:html": "typedoc src/ --exclude '**/*.test.ts' --exclude '**/*.spec.ts' --name $npm_package_name --readme README.md --target es2019 --mode file --out build/docs",
|
|
||||||
"watch:build": "tsc -p tsconfig.json -w"
|
"watch:build": "tsc -p tsconfig.json -w"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,11 +62,8 @@ const register = async <TUser, TProfile, TSession>(
|
||||||
server: Hapi.Server,
|
server: Hapi.Server,
|
||||||
pluginOpts?: NextAuthPluginOptions<TUser, TProfile, TSession>
|
pluginOpts?: NextAuthPluginOptions<TUser, TProfile, TSession>
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
const options: NextAuthPluginOptions<
|
const options: NextAuthPluginOptions<TUser, TProfile, TSession> =
|
||||||
TUser,
|
Hoek.applyToDefaults(
|
||||||
TProfile,
|
|
||||||
TSession
|
|
||||||
> = Hoek.applyToDefaults(
|
|
||||||
// a little type gymnastics here to workaround poor typing
|
// a little type gymnastics here to workaround poor typing
|
||||||
defaultOptions as unknown,
|
defaultOptions as unknown,
|
||||||
pluginOpts
|
pluginOpts
|
||||||
|
|
|
||||||
|
|
@ -1,138 +1,155 @@
|
||||||
/* eslint-disable unicorn/no-null */
|
/* eslint-disable unicorn/no-null */
|
||||||
import Toys from "@hapipal/toys";
|
|
||||||
import * as Joi from "joi";
|
import * as Joi from "joi";
|
||||||
import * as Hapi from "@hapi/hapi";
|
import * as Hapi from "@hapi/hapi";
|
||||||
import { NextAuthPluginOptions } from "./types";
|
import { NextAuthPluginOptions } from "./types";
|
||||||
|
import { ResponseToolkit, ResponseObject } from "@hapi/hapi";
|
||||||
|
|
||||||
|
export interface LinkAccountPayload {
|
||||||
|
userId: string;
|
||||||
|
providerType: string;
|
||||||
|
providerId: string;
|
||||||
|
providerAccountId: string;
|
||||||
|
refreshToken: string;
|
||||||
|
accessToken: string;
|
||||||
|
accessTokenExpires?: null;
|
||||||
|
}
|
||||||
|
|
||||||
export const register = async <TUser, TProfile, TSession>(
|
export const register = async <TUser, TProfile, TSession>(
|
||||||
server: Hapi.Server,
|
server: Hapi.Server,
|
||||||
opts: NextAuthPluginOptions<TUser, TProfile, TSession>,
|
opts: NextAuthPluginOptions<TUser, TProfile, TSession>,
|
||||||
auth?: string
|
auth?: string
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
const withDefaults = Toys.withRouteDefaults({
|
const { tags, basePath, validators } = opts;
|
||||||
|
const { session, user, userId, profile } = validators;
|
||||||
|
server.route([
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
path: `${basePath}/createUser`,
|
||||||
options: {
|
options: {
|
||||||
auth,
|
auth,
|
||||||
tags: opts.tags,
|
tags,
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
server.route([
|
|
||||||
withDefaults({
|
|
||||||
method: "POST",
|
|
||||||
path: `${opts.basePath}/createUser`,
|
|
||||||
options: {
|
|
||||||
validate: {
|
validate: {
|
||||||
payload: opts.validators.profile,
|
payload: profile,
|
||||||
},
|
},
|
||||||
handler: async (
|
async handler(
|
||||||
request: Hapi.Request,
|
request: Hapi.Request,
|
||||||
h: Hapi.Toolkit
|
h: ResponseToolkit
|
||||||
): Promise<TUser> => {
|
): Promise<Hapi.ResponseObject> {
|
||||||
const payload: TProfile = request.payload as TProfile;
|
const payload: TProfile = request.payload as TProfile;
|
||||||
const r = await opts
|
const r = await opts
|
||||||
.nextAuthAdapterFactory(request)
|
.nextAuthAdapterFactory(request)
|
||||||
.createUser(payload);
|
.createUser(payload);
|
||||||
return h.response(r);
|
return h.response(r as object);
|
||||||
},
|
},
|
||||||
description: "Create a user from a profile",
|
description: "Create a user from a profile",
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
withDefaults({
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
path: `${opts.basePath}/getUser/{userId}`,
|
path: `${basePath}/getUser/{userId}`,
|
||||||
options: {
|
options: {
|
||||||
|
auth,
|
||||||
|
tags,
|
||||||
validate: {
|
validate: {
|
||||||
params: {
|
params: {
|
||||||
userId: opts.validators.userId,
|
userId,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
handler: async (
|
async handler(
|
||||||
request: Hapi.Request,
|
request: Hapi.Request,
|
||||||
h: Hapi.Toolkit
|
h: ResponseToolkit
|
||||||
): Promise<TUser | null> => {
|
): Promise<ResponseObject> {
|
||||||
const id = request.params.userId;
|
const id = request.params.userId;
|
||||||
const r = await opts.nextAuthAdapterFactory(request).getUser(id);
|
const r = await opts.nextAuthAdapterFactory(request).getUser(id);
|
||||||
if (!r) return h.response().code(404);
|
if (!r) return h.response().code(404);
|
||||||
return h.response(r);
|
return h.response(r as object);
|
||||||
},
|
},
|
||||||
description: "Get a user by id",
|
description: "Get a user by id",
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
withDefaults({
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
path: `${opts.basePath}/getUserByEmail/{userEmail}`,
|
path: `${basePath}/getUserByEmail/{userEmail}`,
|
||||||
options: {
|
options: {
|
||||||
|
auth,
|
||||||
|
tags,
|
||||||
validate: {
|
validate: {
|
||||||
params: {
|
params: {
|
||||||
userEmail: Joi.string().email(),
|
userEmail: Joi.string().email(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
handler: async (
|
async handler(
|
||||||
request: Hapi.Request,
|
request: Hapi.Request,
|
||||||
h: Hapi.Toolkit
|
h: ResponseToolkit
|
||||||
): Promise<TUser | null> => {
|
): Promise<ResponseObject> {
|
||||||
const email = request.params.userEmail;
|
const email = request.params.userEmail;
|
||||||
const r = await opts
|
const r = await opts
|
||||||
.nextAuthAdapterFactory(request)
|
.nextAuthAdapterFactory(request)
|
||||||
.getUserByEmail(email);
|
.getUserByEmail(email);
|
||||||
if (!r) return h.response().code(404);
|
if (!r) return h.response().code(404);
|
||||||
return h.response(r);
|
return h.response(r as object);
|
||||||
},
|
},
|
||||||
description: "Get a user by email",
|
description: "Get a user by email",
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
withDefaults({
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
path: `${opts.basePath}/getUserByProviderAccountId/{providerId}/{providerAccountId}`,
|
path: `${basePath}/getUserByProviderAccountId/{providerId}/{providerAccountId}`,
|
||||||
options: {
|
options: {
|
||||||
|
auth,
|
||||||
|
tags,
|
||||||
validate: {
|
validate: {
|
||||||
params: {
|
params: {
|
||||||
providerId: Joi.string(),
|
providerId: Joi.string(),
|
||||||
providerAccountId: Joi.string(),
|
providerAccountId: Joi.string(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
handler: async (
|
async handler(
|
||||||
request: Hapi.Request,
|
request: Hapi.Request,
|
||||||
h: Hapi.Toolkit
|
h: ResponseToolkit
|
||||||
): Promise<TUser | null> => {
|
): Promise<ResponseObject> {
|
||||||
const { providerId, providerAccountId } = request.params;
|
const { providerId, providerAccountId } = request.params;
|
||||||
const r = await opts
|
const r = await opts
|
||||||
.nextAuthAdapterFactory(request)
|
.nextAuthAdapterFactory(request)
|
||||||
.getUserByProviderAccountId(providerId, providerAccountId);
|
.getUserByProviderAccountId(providerId, providerAccountId);
|
||||||
if (!r) return h.response().code(404);
|
if (!r) return h.response().code(404);
|
||||||
return h.response(r);
|
return h.response(r as object);
|
||||||
},
|
},
|
||||||
description: "Get a user by provider id and provider account id",
|
description: "Get a user by provider id and provider account id",
|
||||||
},
|
},
|
||||||
}),
|
|
||||||
withDefaults({
|
|
||||||
method: "PUT",
|
|
||||||
path: `${opts.basePath}/updateUser`,
|
|
||||||
options: {
|
|
||||||
validate: {
|
|
||||||
payload: opts.validators.user,
|
|
||||||
},
|
},
|
||||||
handler: async (
|
{
|
||||||
|
method: "PUT",
|
||||||
|
path: `${basePath}/updateUser`,
|
||||||
|
options: {
|
||||||
|
auth,
|
||||||
|
tags,
|
||||||
|
validate: {
|
||||||
|
payload: user,
|
||||||
|
},
|
||||||
|
async handler(
|
||||||
request: Hapi.Request,
|
request: Hapi.Request,
|
||||||
h: Hapi.Toolkit
|
h: ResponseToolkit
|
||||||
): Promise<TUser> => {
|
): Promise<ResponseObject> {
|
||||||
const payload: TUser = request.payload as TUser;
|
const payload: TUser = request.payload as TUser;
|
||||||
const r = await opts
|
const r = await opts
|
||||||
.nextAuthAdapterFactory(request)
|
.nextAuthAdapterFactory(request)
|
||||||
.updateUser(payload);
|
.updateUser(payload);
|
||||||
if (!r) return h.response().code(404);
|
if (!r) return h.response().code(404);
|
||||||
return h.response(r);
|
return h.response(r as object);
|
||||||
},
|
},
|
||||||
description: "Update a user's data",
|
description: "Update a user's data",
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
withDefaults({
|
{
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
path: `${opts.basePath}/linkAccount`,
|
path: `${basePath}/linkAccount`,
|
||||||
options: {
|
options: {
|
||||||
|
auth,
|
||||||
|
tags,
|
||||||
validate: {
|
validate: {
|
||||||
payload: Joi.object({
|
payload: Joi.object({
|
||||||
userId: opts.validators.userId,
|
userId,
|
||||||
providerId: Joi.string(),
|
providerId: Joi.string(),
|
||||||
providerType: Joi.string(),
|
providerType: Joi.string(),
|
||||||
providerAccountId: Joi.string(),
|
providerAccountId: Joi.string(),
|
||||||
|
|
@ -141,10 +158,10 @@ export const register = async <TUser, TProfile, TSession>(
|
||||||
accessTokenExpires: Joi.number().optional().allow(null),
|
accessTokenExpires: Joi.number().optional().allow(null),
|
||||||
}).options({ presence: "required" }),
|
}).options({ presence: "required" }),
|
||||||
},
|
},
|
||||||
handler: async (
|
async handler(
|
||||||
request: Hapi.Request,
|
request: Hapi.Request,
|
||||||
h: Hapi.Toolkit
|
h: ResponseToolkit
|
||||||
): Promise<void> => {
|
): Promise<ResponseObject> {
|
||||||
const {
|
const {
|
||||||
userId,
|
userId,
|
||||||
providerId,
|
providerId,
|
||||||
|
|
@ -153,7 +170,7 @@ export const register = async <TUser, TProfile, TSession>(
|
||||||
refreshToken,
|
refreshToken,
|
||||||
accessToken,
|
accessToken,
|
||||||
accessTokenExpires,
|
accessTokenExpires,
|
||||||
} = request.payload;
|
} = request.payload as LinkAccountPayload;
|
||||||
await opts
|
await opts
|
||||||
.nextAuthAdapterFactory(request)
|
.nextAuthAdapterFactory(request)
|
||||||
.linkAccount(
|
.linkAccount(
|
||||||
|
|
@ -169,94 +186,104 @@ export const register = async <TUser, TProfile, TSession>(
|
||||||
},
|
},
|
||||||
description: "Link a provider account with a user",
|
description: "Link a provider account with a user",
|
||||||
},
|
},
|
||||||
}),
|
|
||||||
withDefaults({
|
|
||||||
method: "POST",
|
|
||||||
path: `${opts.basePath}/createSession`,
|
|
||||||
options: {
|
|
||||||
validate: {
|
|
||||||
payload: opts.validators.user,
|
|
||||||
},
|
},
|
||||||
handler: async (
|
{
|
||||||
|
method: "POST",
|
||||||
|
path: `${basePath}/createSession`,
|
||||||
|
options: {
|
||||||
|
auth,
|
||||||
|
tags,
|
||||||
|
validate: {
|
||||||
|
payload: user,
|
||||||
|
},
|
||||||
|
async handler(
|
||||||
request: Hapi.Request,
|
request: Hapi.Request,
|
||||||
h: Hapi.Toolkit
|
h: ResponseToolkit
|
||||||
): Promise<TSession> => {
|
): Promise<ResponseObject> {
|
||||||
const payload: TUser = request.payload as TUser;
|
const payload: TUser = request.payload as TUser;
|
||||||
const r = await opts
|
const r = await opts
|
||||||
.nextAuthAdapterFactory(request)
|
.nextAuthAdapterFactory(request)
|
||||||
.createSession(payload);
|
.createSession(payload);
|
||||||
return h.response(r);
|
return h.response(r as object);
|
||||||
},
|
},
|
||||||
description: "Create a new session for a user",
|
description: "Create a new session for a user",
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
withDefaults({
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
path: `${opts.basePath}/getSession/{sessionToken}`,
|
path: `${basePath}/getSession/{sessionToken}`,
|
||||||
options: {
|
options: {
|
||||||
|
auth,
|
||||||
|
tags,
|
||||||
validate: {
|
validate: {
|
||||||
params: {
|
params: {
|
||||||
sessionToken: Joi.string(),
|
sessionToken: Joi.string(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
handler: async (
|
async handler(
|
||||||
request: Hapi.Request,
|
request: Hapi.Request,
|
||||||
h: Hapi.Toolkit
|
h: ResponseToolkit
|
||||||
): Promise<TSession | null> => {
|
): Promise<ResponseObject> {
|
||||||
const token = request.params.sessionToken;
|
const token = request.params.sessionToken;
|
||||||
const r = await opts
|
const r = await opts
|
||||||
.nextAuthAdapterFactory(request)
|
.nextAuthAdapterFactory(request)
|
||||||
.getSession(token);
|
.getSession(token);
|
||||||
if (!r) return h.response().code(404);
|
if (!r) return h.response().code(404);
|
||||||
return h.response(r);
|
return h.response(r as object);
|
||||||
},
|
},
|
||||||
description: "Get a session by its token",
|
description: "Get a session by its token",
|
||||||
},
|
},
|
||||||
}),
|
|
||||||
withDefaults({
|
|
||||||
method: "PUT",
|
|
||||||
path: `${opts.basePath}/updateSession`,
|
|
||||||
options: {
|
|
||||||
validate: {
|
|
||||||
payload: opts.validators.session,
|
|
||||||
},
|
},
|
||||||
handler: async (
|
{
|
||||||
|
method: "PUT",
|
||||||
|
path: `${basePath}/updateSession`,
|
||||||
|
options: {
|
||||||
|
auth,
|
||||||
|
tags,
|
||||||
|
validate: {
|
||||||
|
payload: session,
|
||||||
|
},
|
||||||
|
async handler(
|
||||||
request: Hapi.Request,
|
request: Hapi.Request,
|
||||||
h: Hapi.Toolkit
|
h: ResponseToolkit
|
||||||
): Promise<TSession> => {
|
): Promise<ResponseObject> {
|
||||||
|
const inputPayload = request.payload as any;
|
||||||
|
const { expires } = inputPayload;
|
||||||
const payload = {
|
const payload = {
|
||||||
...request.payload,
|
...inputPayload,
|
||||||
expires: new Date(request.payload.expires),
|
expires: new Date(expires),
|
||||||
};
|
};
|
||||||
const force = Boolean(request.query.force);
|
const force = Boolean(request.query.force);
|
||||||
const r = await opts
|
const r = await opts
|
||||||
.nextAuthAdapterFactory(request)
|
.nextAuthAdapterFactory(request)
|
||||||
.updateSession(payload, force);
|
.updateSession(payload, force);
|
||||||
if (!r) return h.response().code(204);
|
if (!r) return h.response().code(204);
|
||||||
return h.response(r);
|
return h.response(r as object);
|
||||||
},
|
},
|
||||||
description: "Update a session for a user",
|
description: "Update a session for a user",
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
withDefaults({
|
{
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
path: `${opts.basePath}/deleteSession/{sessionToken}`,
|
path: `${basePath}/deleteSession/{sessionToken}`,
|
||||||
options: {
|
options: {
|
||||||
|
auth,
|
||||||
|
tags,
|
||||||
validate: {
|
validate: {
|
||||||
params: {
|
params: {
|
||||||
sessionToken: Joi.string(),
|
sessionToken: Joi.string(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
handler: async (
|
async handler(
|
||||||
request: Hapi.Request,
|
request: Hapi.Request,
|
||||||
h: Hapi.Toolkit
|
h: ResponseToolkit
|
||||||
): Promise<void> => {
|
): Promise<ResponseObject> {
|
||||||
const token = request.params.sessionToken;
|
const token = request.params.sessionToken;
|
||||||
await opts.nextAuthAdapterFactory(request).deleteSession(token);
|
await opts.nextAuthAdapterFactory(request).deleteSession(token);
|
||||||
return h.response().code(204);
|
return h.response().code(204);
|
||||||
},
|
},
|
||||||
description: "Delete a user's session",
|
description: "Delete a user's session",
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"extends": "tsconfig",
|
"extends": "tsconfig-link",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"incremental": true,
|
"incremental": true,
|
||||||
"outDir": "build/main",
|
"outDir": "build/main",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue