From 8303115d9100d5711ae92418478ab70a464ff5f4 Mon Sep 17 00:00:00 2001 From: Mohammad Al Faiyaz Date: Tue, 10 Jun 2025 14:40:26 -0400 Subject: [PATCH] feat(ebe): api-tsify ebe Ticket: WP-4662 # Conflicts: # package.json --- .gitignore | 1 + package.json | 4 +- src/__tests__/routes.test.ts | 11 +- src/api/enclaved/postIndependentKey.ts | 17 ++- src/api/enclaved/signMultisigTransaction.ts | 21 +-- src/enclavedApp.ts | 2 +- .../routers/enclavedApiSpec.ts | 125 ++++++++++++++++++ .../routers/healthCheck.ts | 70 ++++++++++ src/masterBitgoExpress/generateWallet.ts | 7 + .../routers/enclavedExpressHealth.ts | 4 +- src/masterBitgoExpress/routers/healthCheck.ts | 6 +- .../routers/masterApiSpec.ts | 42 +----- src/routes/enclaved.ts | 63 +-------- src/shared/bitgoUtils.ts | 0 src/shared/middleware.ts | 44 ++++++ src/shared/responseHandler.ts | 15 +-- src/types/request.ts | 12 +- yarn.lock | 32 ++++- 18 files changed, 340 insertions(+), 136 deletions(-) create mode 100644 src/enclavedBitgoExpress/routers/enclavedApiSpec.ts create mode 100644 src/enclavedBitgoExpress/routers/healthCheck.ts create mode 100644 src/shared/bitgoUtils.ts create mode 100644 src/shared/middleware.ts diff --git a/.gitignore b/.gitignore index 2074c131..7cbe2d70 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ coverage/ .idea/ logs/ tsconfig.tsbuildinfo +out/ diff --git a/package.json b/package.json index 72586b6e..46f95e8d 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,9 @@ "dependencies": { "@api-ts/io-ts-http": "^3.2.1", "@api-ts/openapi-generator": "^5.7.0", + "@api-ts/typed-express-router": "^1.1.13", + "@api-ts/superagent-wrapper": "^1.3.3", "@api-ts/response": "^2.1.0", - "@api-ts/typed-express-router": "^1.1.13", "@bitgo/sdk-core": "^35.2.0", "bitgo": "^48.0.0", "body-parser": "^1.20.3", @@ -51,6 +52,7 @@ "@types/sinon": "^10.0.11", "@types/supertest": "^2.0.11", "@types/winston": "^2.4.4", + "@types/superagent": "^8.1.9", "@typescript-eslint/eslint-plugin": "^5.0.0", "@typescript-eslint/parser": "^5.0.0", "eslint": "^8.0.0", diff --git a/src/__tests__/routes.test.ts b/src/__tests__/routes.test.ts index 4276b801..6d639dae 100644 --- a/src/__tests__/routes.test.ts +++ b/src/__tests__/routes.test.ts @@ -2,13 +2,22 @@ import 'should'; import express from 'express'; import request from 'supertest'; import { setupRoutes } from '../routes/enclaved'; +import { AppMode, TlsMode } from '../types'; describe('Routes', () => { let app: express.Application; beforeEach(() => { app = express(); - setupRoutes(app); + setupRoutes(app, { + appMode: AppMode.ENCLAVED, + tlsMode: TlsMode.DISABLED, + mtlsRequestCert: false, + kmsUrl: 'http://localhost:3000/kms', + timeout: 5000, + port: 3000, + bind: 'localhost', + }); }); describe('Health Check Routes', () => { diff --git a/src/api/enclaved/postIndependentKey.ts b/src/api/enclaved/postIndependentKey.ts index d4a8af6c..f84519fa 100644 --- a/src/api/enclaved/postIndependentKey.ts +++ b/src/api/enclaved/postIndependentKey.ts @@ -1,18 +1,17 @@ import { BitGo } from 'bitgo'; -import * as express from 'express'; import { KmsClient } from '../../kms/kmsClient'; +import { EnclavedApiSpecRouteRequest } from '../../enclavedBitgoExpress/routers/enclavedApiSpec'; export async function postIndependentKey( - req: express.Request, - res: express.Response, -): Promise { - const { source, seed }: { source: string; seed?: string } = req.body; + req: EnclavedApiSpecRouteRequest<'v1.key.independent', 'post'>, +) { + const { source, seed }: { source: string; seed?: string } = req.decoded; if (!source) { throw new Error('Source is required for key generation'); } // setup clients - const bitgo: BitGo = req.body.bitgo; + const bitgo: BitGo = req.bitgo; const kms = new KmsClient(); // create public and private key pairs on BitGo SDK @@ -34,9 +33,9 @@ export async function postIndependentKey( seed, }); } catch (error: any) { - res.status(error.status || 500).json({ + throw { + status: error.status || 500, message: error.message || 'Failed to post key to KMS', - }); - return; + }; } } diff --git a/src/api/enclaved/signMultisigTransaction.ts b/src/api/enclaved/signMultisigTransaction.ts index d3f21c9d..c29552f7 100644 --- a/src/api/enclaved/signMultisigTransaction.ts +++ b/src/api/enclaved/signMultisigTransaction.ts @@ -1,11 +1,10 @@ -import * as express from 'express'; import { KmsClient } from '../../kms/kmsClient'; -import { BitGo, RequestTracer, TransactionPrebuild } from 'bitgo'; +import { RequestTracer, TransactionPrebuild } from 'bitgo'; import logger from '../../logger'; +import { EnclavedApiSpecRouteRequest } from '../../enclavedBitgoExpress/routers/enclavedApiSpec'; export async function signMultisigTransaction( - req: express.Request, - res: express.Response, + req: EnclavedApiSpecRouteRequest<'v1.multisig.sign', 'post'>, ): Promise { const { source, @@ -20,7 +19,7 @@ export async function signMultisigTransaction( } const reqId = new RequestTracer(); - const bitgo: BitGo = req.body.bitgo; + const bitgo = req.bitgo; const baseCoin = bitgo.coin(req.params.coin); const kms = new KmsClient(); @@ -47,18 +46,20 @@ export async function signMultisigTransaction( const res = await kms.getKey({ pub, source }); prv = res.prv; } catch (error: any) { - res.status(error.status || 500).json({ + throw { + status: error.status || 500, message: error.message || 'Failed to retrieve key from KMS', - }); - return; + }; } // Sign the transaction using BitGo SDK const coin = bitgo.coin(req.params.coin); try { - return await coin.signTransaction({ txPrebuild, prv }); + const signedTx = await coin.signTransaction({ txPrebuild, prv }); + // The signed transaction format depends on the coin type + return signedTx; } catch (error) { - console.log('error while signing wallet transaction ', error); + logger.error('error while signing wallet transaction:', error); throw error; } } diff --git a/src/enclavedApp.ts b/src/enclavedApp.ts index 21feca92..d1809407 100644 --- a/src/enclavedApp.ts +++ b/src/enclavedApp.ts @@ -108,7 +108,7 @@ export function app(cfg: EnclavedConfig): express.Application { } // Setup routes - setupRoutes(app); + setupRoutes(app, cfg); // Add error handler app.use(createErrorHandler()); diff --git a/src/enclavedBitgoExpress/routers/enclavedApiSpec.ts b/src/enclavedBitgoExpress/routers/enclavedApiSpec.ts new file mode 100644 index 00000000..663c78e6 --- /dev/null +++ b/src/enclavedBitgoExpress/routers/enclavedApiSpec.ts @@ -0,0 +1,125 @@ +import * as t from 'io-ts'; +import { + apiSpec, + httpRoute, + httpRequest, + HttpResponse, + Method as HttpMethod, +} from '@api-ts/io-ts-http'; +import { + createRouter, + type WrappedRouter, + TypedRequestHandler, +} from '@api-ts/typed-express-router'; +import { Response } from '@api-ts/response'; +import express from 'express'; +import { BitGoRequest } from '../../types/request'; +import { EnclavedConfig } from '../../types'; +import { postIndependentKey } from '../../api/enclaved/postIndependentKey'; +import { signMultisigTransaction } from '../../api/enclaved/signMultisigTransaction'; +import { prepareBitGo, responseHandler } from '../../shared/middleware'; + +// Request type for /key/independent endpoint +const IndependentKeyRequest = { + source: t.string, + seed: t.union([t.undefined, t.string]), +}; + +// Response type for /key/independent endpoint +const IndependentKeyResponse: HttpResponse = { + // TODO: Define proper response type + 200: t.any, + 500: t.type({ + error: t.string, + details: t.string, + }), +}; + +// Request type for /multisig/sign endpoint +const SignMultisigRequest = { + source: t.string, + pub: t.string, + txPrebuild: t.any, // TransactionPrebuild type from BitGo +}; + +// Response type for /multisig/sign endpoint +const SignMultisigResponse: HttpResponse = { + // TODO: Define proper response type for signed multisig transaction + 200: t.any, + 500: t.type({ + error: t.string, + details: t.string, + }), +}; + +// API Specification +export const EnclavedAPiSpec = apiSpec({ + 'v1.multisig.sign': { + post: httpRoute({ + method: 'POST', + path: '/{coin}/multisig/sign', + request: httpRequest({ + params: { + coin: t.string, + }, + body: SignMultisigRequest, + }), + response: SignMultisigResponse, + description: 'Sign a multisig transaction', + }), + }, + 'v1.key.independent': { + post: httpRoute({ + method: 'POST', + path: '/{coin}/key/independent', + request: httpRequest({ + params: { + coin: t.string, + }, + body: IndependentKeyRequest, + }), + response: IndependentKeyResponse, + description: 'Generate an independent key', + }), + }, +}); + +export type EnclavedApiSpecRouteHandler< + ApiName extends keyof typeof EnclavedAPiSpec, + Method extends keyof (typeof EnclavedAPiSpec)[ApiName] & HttpMethod, +> = TypedRequestHandler; + +export type EnclavedApiSpecRouteRequest< + ApiName extends keyof typeof EnclavedAPiSpec, + Method extends keyof (typeof EnclavedAPiSpec)[ApiName] & HttpMethod, +> = BitGoRequest & Parameters>[0]; + +export type GenericEnclavedApiSpecRouteRequest = EnclavedApiSpecRouteRequest; + +// Create router with handlers +export function createKeyGenRouter(config: EnclavedConfig): WrappedRouter { + const router = createRouter(EnclavedAPiSpec); + // Add middleware + router.use(express.json()); + router.use(prepareBitGo(config)); + + // Independent key generation endpoint handler + router.post('v1.key.independent', [ + responseHandler(async (req) => { + const typedReq = req as EnclavedApiSpecRouteRequest<'v1.key.independent', 'post'>; + const result = await postIndependentKey(typedReq); + return Response.ok(result); + }), + ]); + + // Multisig transaction signing endpoint handler + router.post('v1.multisig.sign', [ + responseHandler(async (req) => { + const typedReq = req as EnclavedApiSpecRouteRequest<'v1.multisig.sign', 'post'>; + const result = await signMultisigTransaction(typedReq); + return Response.ok(result); + }), + ]); + + return router; +} diff --git a/src/enclavedBitgoExpress/routers/healthCheck.ts b/src/enclavedBitgoExpress/routers/healthCheck.ts new file mode 100644 index 00000000..c8a89519 --- /dev/null +++ b/src/enclavedBitgoExpress/routers/healthCheck.ts @@ -0,0 +1,70 @@ +import * as t from 'io-ts'; +import { apiSpec, httpRoute, httpRequest, HttpResponse } from '@api-ts/io-ts-http'; +import { createRouter, type WrappedRouter } from '@api-ts/typed-express-router'; +import { Response } from '@api-ts/response'; +import pjson from '../../../package.json'; +import { responseHandler } from '../../shared/middleware'; + +// Response type for /ping endpoint +const PingResponse: HttpResponse = { + 200: t.type({ + status: t.string, + timestamp: t.string, + }), +}; + +// Response type for /version endpoint +const VersionResponse: HttpResponse = { + 200: t.type({ + version: t.string, + name: t.string, + }), +}; + +// API Specification +export const HealthCheckApiSpec = apiSpec({ + 'v1.health.ping': { + post: httpRoute({ + method: 'POST', + path: '/ping', + request: httpRequest({}), + response: PingResponse, + description: 'Health check endpoint that returns server status', + }), + }, + 'v1.health.version': { + get: httpRoute({ + method: 'GET', + path: '/version', + request: httpRequest({}), + response: VersionResponse, + description: 'Returns the current version of the server', + }), + }, +}); + +// Create router with handlers +export function createHealthCheckRouter(): WrappedRouter { + const router = createRouter(HealthCheckApiSpec); + // Ping endpoint handler + router.post('v1.health.ping', [ + responseHandler(() => + Response.ok({ + status: 'enclaved express server is ok!', + timestamp: new Date().toISOString(), + }), + ), + ]); + + // Version endpoint handler + router.get('v1.health.version', [ + responseHandler(() => + Response.ok({ + version: pjson.version, + name: pjson.name, + }), + ), + ]); + + return router; +} diff --git a/src/masterBitgoExpress/generateWallet.ts b/src/masterBitgoExpress/generateWallet.ts index c7c1a54c..8bffa9a6 100644 --- a/src/masterBitgoExpress/generateWallet.ts +++ b/src/masterBitgoExpress/generateWallet.ts @@ -11,6 +11,8 @@ import { import { createEnclavedExpressClient } from './enclavedExpressClient'; import _ from 'lodash'; import { MasterApiSpecRouteRequest } from './routers/masterApiSpec'; +import { isMasterExpressConfig } from '../types'; +import assert from 'assert'; /** * This route is used to generate a multisig wallet when enclaved express is enabled @@ -21,6 +23,11 @@ export async function handleGenerateWalletOnPrem( const bitgo = req.bitgo; const baseCoin = bitgo.coin(req.params.coin); + assert( + isMasterExpressConfig(req.config), + 'Expected req.config to be of type MasterExpressConfig', + ); + const enclavedExpressClient = createEnclavedExpressClient(req.config, req.params.coin); if (!enclavedExpressClient) { throw new Error( diff --git a/src/masterBitgoExpress/routers/enclavedExpressHealth.ts b/src/masterBitgoExpress/routers/enclavedExpressHealth.ts index bd3b6a78..fb91dd72 100644 --- a/src/masterBitgoExpress/routers/enclavedExpressHealth.ts +++ b/src/masterBitgoExpress/routers/enclavedExpressHealth.ts @@ -6,7 +6,7 @@ import https from 'https'; import superagent from 'superagent'; import { MasterExpressConfig, TlsMode } from '../../config'; import logger from '../../logger'; -import { withResponseHandler } from '../../shared/responseHandler'; +import { responseHandler } from '../../shared/middleware'; // Response type for /ping/enclavedExpress endpoint const PingEnclavedResponse: HttpResponse = { @@ -52,7 +52,7 @@ export function createEnclavedExpressRouter( // Ping endpoint handler router.post('v1.enclaved.ping', [ - withResponseHandler(async () => { + responseHandler(async () => { logger.debug('Pinging enclaved express'); try { diff --git a/src/masterBitgoExpress/routers/healthCheck.ts b/src/masterBitgoExpress/routers/healthCheck.ts index b2a33058..2b5b746c 100644 --- a/src/masterBitgoExpress/routers/healthCheck.ts +++ b/src/masterBitgoExpress/routers/healthCheck.ts @@ -3,7 +3,7 @@ import { apiSpec, httpRoute, httpRequest, HttpResponse } from '@api-ts/io-ts-htt import { createRouter, type WrappedRouter } from '@api-ts/typed-express-router'; import { Response } from '@api-ts/response'; import pjson from '../../../package.json'; -import { withResponseHandler } from '../../shared/responseHandler'; +import { responseHandler } from '../../shared/middleware'; // Response type for /ping endpoint const PingResponse: HttpResponse = { @@ -58,7 +58,7 @@ export function createHealthCheckRouter( // Ping endpoint handler router.post('v1.health.ping', [ - withResponseHandler(() => + responseHandler(() => Response.ok({ status: `${serverType} server is ok!`, timestamp: new Date().toISOString(), @@ -68,7 +68,7 @@ export function createHealthCheckRouter( // Version endpoint handler router.get('v1.health.version', [ - withResponseHandler(() => + responseHandler(() => Response.ok({ version: pjson.version, name: pjson.name, diff --git a/src/masterBitgoExpress/routers/masterApiSpec.ts b/src/masterBitgoExpress/routers/masterApiSpec.ts index e35a17b7..a8007f67 100644 --- a/src/masterBitgoExpress/routers/masterApiSpec.ts +++ b/src/masterBitgoExpress/routers/masterApiSpec.ts @@ -13,11 +13,10 @@ import { } from '@api-ts/typed-express-router'; import { Response } from '@api-ts/response'; import express from 'express'; -import { BitGo } from 'bitgo'; import { BitGoRequest } from '../../types/request'; import { MasterExpressConfig } from '../../config'; import { handleGenerateWalletOnPrem } from '../generateWallet'; -import { withResponseHandler } from '../../shared/responseHandler'; +import { prepareBitGo, responseHandler } from '../../shared/middleware'; // Middleware functions export function parseBody(req: express.Request, res: express.Response, next: express.NextFunction) { @@ -25,40 +24,6 @@ export function parseBody(req: express.Request, res: express.Response, next: exp return express.json({ limit: '20mb' })(req, res, next); } -export function prepareBitGo(config: MasterExpressConfig) { - const { env, customRootUri } = config; - const BITGOEXPRESS_USER_AGENT = `BitGoExpress/${process.env.npm_package_version}`; - - return function prepBitGo( - req: express.Request, - res: express.Response, - next: express.NextFunction, - ) { - let accessToken; - if (req.headers.authorization) { - const authSplit = req.headers.authorization.split(' '); - if (authSplit.length === 2 && authSplit[0].toLowerCase() === 'bearer') { - accessToken = authSplit[1]; - } - } - const userAgent = req.headers['user-agent'] - ? BITGOEXPRESS_USER_AGENT + ' ' + req.headers['user-agent'] - : BITGOEXPRESS_USER_AGENT; - - const bitgoConstructorParams = { - env, - customRootURI: customRootUri, - accessToken, - userAgent, - }; - - (req as BitGoRequest).bitgo = new BitGo(bitgoConstructorParams); - (req as BitGoRequest).config = config; - - next(); - }; -} - // Response type for /generate endpoint const GenerateWalletResponse: HttpResponse = { // TODO: Get type from public types repo @@ -122,8 +87,9 @@ export function createMasterApiRouter( // Generate wallet endpoint handler router.post('v1.wallet.generate', [ - withResponseHandler(async (req: GenericMasterApiSpecRouteRequest) => { - const result = await handleGenerateWalletOnPrem(req); + responseHandler(async (req: express.Request) => { + const typedReq = req as GenericMasterApiSpecRouteRequest; + const result = await handleGenerateWalletOnPrem(typedReq); return Response.ok(result); }), ]); diff --git a/src/routes/enclaved.ts b/src/routes/enclaved.ts index 24d2033b..729c16c7 100644 --- a/src/routes/enclaved.ts +++ b/src/routes/enclaved.ts @@ -1,72 +1,21 @@ import express from 'express'; import debug from 'debug'; -import pjson from '../../package.json'; -import type { BitGoOptions } from 'bitgo'; -import { postIndependentKey } from '../api/enclaved/postIndependentKey'; -import { promiseWrapper } from './utils'; -import { signMultisigTransaction } from '../api/enclaved/signMultisigTransaction'; +import { createHealthCheckRouter } from '../enclavedBitgoExpress/routers/healthCheck'; +import { createKeyGenRouter } from '../enclavedBitgoExpress/routers/enclavedApiSpec'; +import { EnclavedConfig } from '../types'; const debugLogger = debug('enclaved:routes'); - -/** - * Handler for express ping to check service health - */ -function handlePingExpress(_req: express.Request) { - return { - status: 'enclaved express server is ok!', - timestamp: new Date().toISOString(), - }; -} - -/** - * Handler for version info - */ -function handleVersionInfo(_req: express.Request) { - return { - version: pjson.version, - name: pjson.name, - }; -} - -/** - * Adds the ping route handlers - * @param app Express application - */ -function setupPingRoutes(app: express.Application) { - app.post('/ping', promiseWrapper(handlePingExpress)); - app.get('/version', promiseWrapper(handleVersionInfo)); -} - -async function prepBitGo(req: express.Request, res: express.Response, next: express.NextFunction) { - try { - // Lazy load BitGo only when needed - const { BitGo } = await import('bitgo'); - const bitgoConstructorParams: BitGoOptions = {}; - req.body.bitgo = new BitGo(bitgoConstructorParams); - next(); - } catch (error) { - next(error); - } -} - -function setupKeyGenRoutes(app: express.Application) { - app.post('/api/:coin/key/independent', prepBitGo, promiseWrapper(postIndependentKey)); - app.post('/api/:coin/multisig/sign', prepBitGo, promiseWrapper(signMultisigTransaction)); - debugLogger('KeyGen routes configured'); -} - /** * Setup all routes for the Enclaved Express application * @param app Express application */ -export function setupRoutes(app: express.Application): void { +export function setupRoutes(app: express.Application, config: EnclavedConfig): void { // Register health check routes - setupPingRoutes(app); + app.use(createHealthCheckRouter()); // Register keygen routes - setupKeyGenRoutes(app); + app.use('/api', createKeyGenRouter(config)); - // Add a catch-all for unsupported routes app.use('*', (_req, res) => { res.status(404).json({ error: 'Route not found or not supported in enclaved mode', diff --git a/src/shared/bitgoUtils.ts b/src/shared/bitgoUtils.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/shared/middleware.ts b/src/shared/middleware.ts new file mode 100644 index 00000000..b397ecb2 --- /dev/null +++ b/src/shared/middleware.ts @@ -0,0 +1,44 @@ +import { Config, isMasterExpressConfig } from '../types'; +import express from 'express'; +import { BitGoRequest } from '../types/request'; +import { BitGo } from 'bitgo'; + +export * from './responseHandler'; + +export function prepareBitGo(config: Config) { + const BITGOEXPRESS_USER_AGENT = `BitGoExpress/${process.env.npm_package_version}`; + + return function prepBitGo( + req: express.Request, + res: express.Response, + next: express.NextFunction, + ) { + let accessToken; + if (req.headers.authorization) { + const authSplit = req.headers.authorization.split(' '); + if (authSplit.length === 2 && authSplit[0].toLowerCase() === 'bearer') { + accessToken = authSplit[1]; + } + } + + const userAgent = req.headers['user-agent'] + ? BITGOEXPRESS_USER_AGENT + ' ' + req.headers['user-agent'] + : BITGOEXPRESS_USER_AGENT; + + const bitgoConstructorParams: any = { + userAgent, + }; + + // Add master express specific params + if (isMasterExpressConfig(config)) { + bitgoConstructorParams.env = config.env; + bitgoConstructorParams.customRootURI = config.customRootUri; + bitgoConstructorParams.accessToken = accessToken; + } + + (req as BitGoRequest).bitgo = new BitGo(bitgoConstructorParams); + (req as BitGoRequest).config = config; + + next(); + }; +} diff --git a/src/shared/responseHandler.ts b/src/shared/responseHandler.ts index 34493f09..db247a7f 100644 --- a/src/shared/responseHandler.ts +++ b/src/shared/responseHandler.ts @@ -1,8 +1,6 @@ import { Request, Response as ExpressResponse, NextFunction } from 'express'; -import { - GenericMasterApiSpecRouteRequest, - MasterApiSpecRouteRequest, -} from '../masterBitgoExpress/routers/masterApiSpec'; +import { Config } from '../types'; +import { BitGoRequest } from '../types/request'; // Extend Express Response to include sendEncoded interface EncodedResponse extends ExpressResponse { @@ -15,8 +13,9 @@ interface ApiResponse { payload: unknown; } -type ServiceFunction = ( - req: MasterApiSpecRouteRequest, +// Generic service function type that works with both express instances +export type ServiceFunction = ( + req: BitGoRequest, res: EncodedResponse, next: NextFunction, ) => Promise | ApiResponse; @@ -26,10 +25,10 @@ type ServiceFunction = ( * @param fn Service function that returns a Response object * @returns Express middleware function that handles the response encoding */ -export function withResponseHandler(fn: ServiceFunction) { +export function responseHandler(fn: ServiceFunction) { return async (req: Request, res: EncodedResponse, next: NextFunction) => { try { - const result = await fn(req as unknown as GenericMasterApiSpecRouteRequest, res, next); + const result = await fn(req as BitGoRequest, res, next); return res.sendEncoded(result.type, result.payload); } catch (error) { // Log the error diff --git a/src/types/request.ts b/src/types/request.ts index ac394ad9..f7c281ce 100644 --- a/src/types/request.ts +++ b/src/types/request.ts @@ -1,13 +1,15 @@ import express from 'express'; import { type BitGo } from 'bitgo'; -import { MasterExpressConfig } from '../types'; +import { Config } from '../types'; // Extended request type for BitGo Express -export interface BitGoRequest extends express.Request { +export interface BitGoRequest extends express.Request { bitgo: BitGo; - config: MasterExpressConfig; + config: T; } -export function isBitGoRequest(req: express.Request): req is BitGoRequest { - return (req as BitGoRequest).bitgo !== undefined && (req as BitGoRequest).config !== undefined; +export function isBitGoRequest(req: express.Request): req is BitGoRequest { + return ( + (req as BitGoRequest).bitgo !== undefined && (req as BitGoRequest).config !== undefined + ); } diff --git a/yarn.lock b/yarn.lock index 254c0c2b..689b8978 100644 --- a/yarn.lock +++ b/yarn.lock @@ -42,6 +42,16 @@ resolved "https://registry.yarnpkg.com/@api-ts/response/-/response-2.1.0.tgz#9691128e02949cdc9b2cd3277133b2c7e68220b8" integrity sha512-x9yt3IShvz9shSw4owsgC39zmPEBh9ha7MOXSMYFDsdZT7NCP4730w6fsGkYTkbQLpF3oNTMFqZONxOwE1aK5Q== +"@api-ts/superagent-wrapper@^1.3.3": + version "1.3.3" + resolved "https://registry.yarnpkg.com/@api-ts/superagent-wrapper/-/superagent-wrapper-1.3.3.tgz#6895e8037f180762300875c65313e9e1a821a232" + integrity sha512-URKLPRiyMzsUPOOBEpTCSTs88A9FRwy/ugMAOdwPrT72xLmX4JIpV2FbBVHi6t0OHqwnoqZlevVqdJjKMHbrSw== + dependencies: + "@api-ts/io-ts-http" "3.2.1" + fp-ts "^2.0.0" + io-ts "2.1.3" + whatwg-url "14.1.0" + "@api-ts/typed-express-router@^1.1.13": version "1.1.13" resolved "https://registry.yarnpkg.com/@api-ts/typed-express-router/-/typed-express-router-1.1.13.tgz#baf8d2859b7742c07f7885181f31acb4a68d68d3" @@ -5138,7 +5148,7 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== -"@types/superagent@*": +"@types/superagent@*", "@types/superagent@^8.1.9": version "8.1.9" resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-8.1.9.tgz#28bfe4658e469838ed0bf66d898354bcab21f49f" integrity sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ== @@ -13252,6 +13262,13 @@ tough-cookie@~2.5.0: psl "^1.1.28" punycode "^2.1.1" +tr46@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-5.1.1.tgz#96ae867cddb8fdb64a49cc3059a8d428bcf238ca" + integrity sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw== + dependencies: + punycode "^2.3.1" + tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" @@ -13931,6 +13948,11 @@ webidl-conversions@^3.0.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== +webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== + webpack-sources@^3.2.3: version "3.3.2" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.3.2.tgz#0ab55ab0b380ce53c45ca40cb7b33bab3149ea85" @@ -13983,6 +14005,14 @@ whatwg-fetch@^3.4.1: resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz#580ce6d791facec91d37c72890995a0b48d31c70" integrity sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg== +whatwg-url@14.1.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-14.1.0.tgz#fffebec86cc8e6c2a657e50dc606207b870f0ab3" + integrity sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w== + dependencies: + tr46 "^5.0.0" + webidl-conversions "^7.0.0" + whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"