@interledger/open-payments
Advanced tools
Comparing version 6.12.0 to 6.13.0
@@ -37,12 +37,11 @@ "use strict"; | ||
__exportStar(require("./error"), exports); | ||
const parseKey = (args) => { | ||
if (!args.privateKey) { | ||
return undefined; | ||
const parseKey = (deps, privateKey) => { | ||
if (privateKey instanceof crypto_1.KeyObject) { | ||
deps.logger.debug('Loading key from KeyObject'); | ||
return privateKey; | ||
} | ||
if (args.privateKey instanceof crypto_1.KeyObject) { | ||
return args.privateKey; | ||
} | ||
if (args.privateKey instanceof Buffer) { | ||
if (privateKey instanceof Buffer) { | ||
try { | ||
return (0, crypto_1.createPrivateKey)(args.privateKey); | ||
deps.logger.debug('Loading key from Buffer'); | ||
return (0, crypto_1.createPrivateKey)(privateKey); | ||
} | ||
@@ -53,7 +52,10 @@ catch { | ||
} | ||
if (fs_1.default.existsSync(path_1.default.resolve(process.cwd(), args.privateKey))) { | ||
return (0, http_signature_utils_1.loadKey)(path_1.default.resolve(process.cwd(), args.privateKey)); | ||
const keyFilePath = path_1.default.resolve(process.cwd(), privateKey); | ||
if (fs_1.default.existsSync(keyFilePath)) { | ||
deps.logger.debug(`Loading key from file path: ${keyFilePath}`); | ||
return (0, http_signature_utils_1.loadKey)(keyFilePath); | ||
} | ||
try { | ||
return (0, crypto_1.createPrivateKey)(args.privateKey); | ||
deps.logger.debug('Loading key from string'); | ||
return (0, crypto_1.createPrivateKey)(privateKey); | ||
} | ||
@@ -65,3 +67,4 @@ catch { | ||
const createUnauthenticatedDeps = async ({ useHttp = false, validateResponses = true, ...args } = {}) => { | ||
const logger = args?.logger ?? (0, pino_1.default)({ name: 'Open Payments Client' }); | ||
const logger = args.logger ?? | ||
(0, pino_1.default)({ name: 'Open Payments Client', level: 'silent' }); | ||
if (args.logLevel) { | ||
@@ -71,3 +74,4 @@ logger.level = args.logLevel; | ||
const httpClient = await (0, requests_1.createHttpClient)({ | ||
requestTimeoutMs: args?.requestTimeoutMs ?? config_1.default.DEFAULT_REQUEST_TIMEOUT_MS | ||
logger, | ||
requestTimeoutMs: args.requestTimeoutMs ?? config_1.default.DEFAULT_REQUEST_TIMEOUT_MS | ||
}); | ||
@@ -89,30 +93,37 @@ let walletAddressServerOpenApi; | ||
const createAuthenticatedClientDeps = async ({ useHttp = false, validateResponses = true, ...args }) => { | ||
const logger = args?.logger ?? (0, pino_1.default)({ name: 'Open Payments Client' }); | ||
const logger = args.logger ?? | ||
(0, pino_1.default)({ name: 'Open Payments Client', level: 'silent' }); | ||
if (args.logLevel) { | ||
logger.level = args.logLevel; | ||
} | ||
let privateKey; | ||
try { | ||
privateKey = parseKey(args); | ||
} | ||
catch (error) { | ||
const errorMessage = 'Could not load private key when creating Open Payments client'; | ||
const description = error instanceof Error ? error.message : 'Unknown error'; | ||
logger.error({ description }, errorMessage); | ||
throw new error_1.OpenPaymentsClientError(errorMessage, { | ||
description | ||
}); | ||
} | ||
let httpClient; | ||
if ('authenticatedRequestInterceptor' in args) { | ||
httpClient = await (0, requests_1.createHttpClient)({ | ||
requestTimeoutMs: args?.requestTimeoutMs ?? config_1.default.DEFAULT_REQUEST_TIMEOUT_MS, | ||
authenticatedRequestInterceptor: args.authenticatedRequestInterceptor | ||
logger, | ||
requestTimeoutMs: args.requestTimeoutMs ?? config_1.default.DEFAULT_REQUEST_TIMEOUT_MS, | ||
requestSigningArgs: { | ||
authenticatedRequestInterceptor: args.authenticatedRequestInterceptor | ||
} | ||
}); | ||
} | ||
else { | ||
let privateKey; | ||
try { | ||
privateKey = parseKey({ logger }, args.privateKey); | ||
} | ||
catch (error) { | ||
const errorMessage = 'Could not load private key when creating authenticated client'; | ||
const description = error instanceof Error ? error.message : 'Unknown error'; | ||
logger.error({ description }, errorMessage); | ||
throw new error_1.OpenPaymentsClientError(errorMessage, { | ||
description | ||
}); | ||
} | ||
httpClient = await (0, requests_1.createHttpClient)({ | ||
requestTimeoutMs: args?.requestTimeoutMs ?? config_1.default.DEFAULT_REQUEST_TIMEOUT_MS, | ||
privateKey, | ||
keyId: args.keyId | ||
logger, | ||
requestTimeoutMs: args.requestTimeoutMs ?? config_1.default.DEFAULT_REQUEST_TIMEOUT_MS, | ||
requestSigningArgs: { | ||
privateKey, | ||
keyId: args.keyId | ||
} | ||
}); | ||
@@ -142,2 +153,7 @@ } | ||
const { resourceServerOpenApi, walletAddressServerOpenApi, ...baseDeps } = await createUnauthenticatedDeps(args); | ||
baseDeps.logger.debug({ | ||
validateResponses: !!args.validateResponses, | ||
useHttp: baseDeps.useHttp, | ||
requestTimeoutMs: args.requestTimeoutMs ?? config_1.default.DEFAULT_REQUEST_TIMEOUT_MS | ||
}, 'Created unauthenticated client'); | ||
return { | ||
@@ -163,2 +179,9 @@ walletAddress: (0, wallet_address_1.createWalletAddressRoutes)({ | ||
const { resourceServerOpenApi, authServerOpenApi, walletAddressServerOpenApi, ...baseDeps } = await createAuthenticatedClientDeps(args); | ||
baseDeps.logger.debug({ | ||
walletAddressUrl: args.walletAddressUrl, | ||
...('keyId' in args ? { keyId: args.keyId } : {}), | ||
validateResponses: !!args.validateResponses, | ||
useHttp: baseDeps.useHttp, | ||
requestTimeoutMs: args.requestTimeoutMs ?? config_1.default.DEFAULT_REQUEST_TIMEOUT_MS | ||
}, 'Created authenticated client'); | ||
return { | ||
@@ -165,0 +188,0 @@ incomingPayment: (0, incoming_payment_1.createIncomingPaymentRoutes)({ |
@@ -6,2 +6,3 @@ /// <reference types="node" /> | ||
import { BaseDeps } from '.'; | ||
import { Logger } from 'pino'; | ||
import type { KyInstance } from 'ky'; | ||
@@ -31,12 +32,15 @@ interface GetArgs { | ||
export declare const handleError: (deps: BaseDeps, args: HandleErrorArgs) => Promise<never>; | ||
type CreateHttpClientArgs = { | ||
interface CreateHttpClientArgs { | ||
logger: Logger; | ||
requestTimeoutMs: number; | ||
} & ({ | ||
privateKey?: KeyObject; | ||
keyId?: string; | ||
requestSigningArgs?: AuthenticatedHttpClientArgs; | ||
} | ||
type AuthenticatedHttpClientArgs = { | ||
privateKey: KeyObject; | ||
keyId: string; | ||
} | { | ||
authenticatedRequestInterceptor: InterceptorFn; | ||
}); | ||
}; | ||
export type HttpClient = KyInstance; | ||
export type InterceptorFn = (request: Request) => Request | Promise<Request>; | ||
export type InterceptorFn = (request: Request) => Request | Promise<Request> | void | Promise<void>; | ||
export declare const createHttpClient: (args: CreateHttpClientArgs) => Promise<HttpClient>; | ||
@@ -43,0 +47,0 @@ export declare const requestShouldBeAuthorized: (request: Request) => boolean; |
@@ -158,4 +158,5 @@ "use strict"; | ||
const { default: ky } = await import('ky'); | ||
const { requestTimeoutMs, requestSigningArgs, logger } = args; | ||
const kyInstance = ky.create({ | ||
timeout: args.requestTimeoutMs, | ||
timeout: requestTimeoutMs, | ||
headers: { | ||
@@ -166,28 +167,57 @@ Accept: 'application/json', | ||
}); | ||
let requestInterceptor; | ||
if ('authenticatedRequestInterceptor' in args) { | ||
requestInterceptor = (request) => { | ||
if ((0, exports.requestShouldBeAuthorized)(request)) { | ||
return args.authenticatedRequestInterceptor(request); | ||
} | ||
return request; | ||
}; | ||
const beforeRequestHooks = []; | ||
const afterResponseHooks = []; | ||
const requestLogger = async (request) => { | ||
const requestBody = request.body ? await request.clone().json() : undefined; | ||
logger.debug({ | ||
method: request.method, | ||
url: request.url, | ||
body: requestBody | ||
}, 'Sending request'); | ||
}; | ||
const responseLogger = async (request, _, response) => { | ||
let responseBody; | ||
try { | ||
responseBody = await response.clone().text(); | ||
responseBody = JSON.parse(responseBody); | ||
} | ||
catch { | ||
// Ignore if we can't parse the response body (or no body exists) | ||
} | ||
logger.debug({ | ||
method: request.method, | ||
url: response.url, | ||
body: responseBody, | ||
status: response.status | ||
}, 'Received response'); | ||
}; | ||
beforeRequestHooks.push(requestLogger); | ||
afterResponseHooks.push(responseLogger); | ||
if (requestSigningArgs) { | ||
let requestInterceptor; | ||
if ('authenticatedRequestInterceptor' in requestSigningArgs) { | ||
requestInterceptor = (request) => { | ||
if ((0, exports.requestShouldBeAuthorized)(request)) { | ||
return requestSigningArgs.authenticatedRequestInterceptor(request); | ||
} | ||
return request; | ||
}; | ||
} | ||
else { | ||
requestInterceptor = (request) => { | ||
const { privateKey, keyId } = requestSigningArgs; | ||
if ((0, exports.requestShouldBeAuthorized)(request)) { | ||
return (0, exports.signRequest)(request, { privateKey, keyId }); | ||
} | ||
return request; | ||
}; | ||
} | ||
beforeRequestHooks.push(requestInterceptor); | ||
} | ||
else { | ||
requestInterceptor = (request) => { | ||
const { privateKey, keyId } = args; | ||
if ((0, exports.requestShouldBeAuthorized)(request)) { | ||
return (0, exports.signRequest)(request, { privateKey, keyId }); | ||
} | ||
return request; | ||
}; | ||
} | ||
if (requestInterceptor) { | ||
return kyInstance.extend({ | ||
hooks: { | ||
beforeRequest: [requestInterceptor] | ||
} | ||
}); | ||
} | ||
return kyInstance; | ||
return kyInstance.extend({ | ||
hooks: { | ||
beforeRequest: beforeRequestHooks, | ||
afterResponse: afterResponseHooks | ||
} | ||
}); | ||
}; | ||
@@ -194,0 +224,0 @@ exports.createHttpClient = createHttpClient; |
@@ -17,5 +17,8 @@ "use strict"; | ||
const getDefaultHttpClient = async () => (0, requests_1.createHttpClient)({ | ||
logger: exports.silentLogger, | ||
requestTimeoutMs: 1000, | ||
keyId: exports.keyId, | ||
privateKey: (0, crypto_1.generateKeyPairSync)('ed25519').privateKey | ||
requestSigningArgs: { | ||
keyId: exports.keyId, | ||
privateKey: (0, crypto_1.generateKeyPairSync)('ed25519').privateKey | ||
} | ||
}); | ||
@@ -22,0 +25,0 @@ exports.getDefaultHttpClient = getDefaultHttpClient; |
{ | ||
"name": "@interledger/open-payments", | ||
"version": "6.12.0", | ||
"version": "6.13.0", | ||
"description": "Tools for interacting with the Open Payments API", | ||
@@ -5,0 +5,0 @@ "author": "Interledger Tech Team <tech@interledger.org>", |
@@ -59,3 +59,3 @@ # Open Payments | ||
| `logger` | (optional) The custom logger to provide for the client. Defaults to pino logger. | | ||
| `logLevel` | (optional) The log level for the client. Defaults to `info`. | | ||
| `logLevel` | (optional) The log level for the client. Defaults to `silent`. | | ||
| `validateResponses` | (optional) Enables or disables response validation against the Open Payments OpenAPI specs. Defaults to `true`. | | ||
@@ -62,0 +62,0 @@ |
260949
3079