diff --git a/src/app/extend/context.ts b/src/app/extend/context.ts index 6a1c3e4fc5..c986fea74d 100644 --- a/src/app/extend/context.ts +++ b/src/app/extend/context.ts @@ -14,8 +14,6 @@ import type Request from './request.js'; import type Response from './response.js'; import type Helper from './helper.js'; -import './context.types.js'; - const HELPER = Symbol('ctx helper'); const LOCALS = Symbol('ctx locals'); const LOCALS_LIST = Symbol('ctx localsList'); @@ -306,3 +304,19 @@ export default class Context extends EggCoreContext { this.response.realStatus = val; } } + +declare module '@eggjs/core' { + // add Context overrides types + interface Context { + curl(url: HttpClientRequestURL, options?: HttpClientRequestOptions): ReturnType; + get router(): Router; + set router(val: Router); + get helper(): Helper; + get httpclient(): HttpClient; + get httpClient(): HttpClient; + getLogger(name: string): EggLogger; + get logger(): EggLogger; + get coreLogger(): EggLogger; + get locals(): Record; + } +} diff --git a/src/app/extend/context.types.ts b/src/app/extend/context.types.ts deleted file mode 100644 index 417b7edcd1..0000000000 --- a/src/app/extend/context.types.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { - Router, -} from '@eggjs/core'; -import type { EggLogger } from 'egg-logger'; -import type { - HttpClientRequestURL, HttpClientRequestOptions, HttpClient, -} from '../../lib/core/httpclient.js'; -import type Helper from './helper.js'; - -declare module '@eggjs/core' { - // add Context overrides types - interface Context { - curl(url: HttpClientRequestURL, options?: HttpClientRequestOptions): ReturnType; - get router(): Router; - set router(val: Router); - get helper(): Helper; - get httpclient(): HttpClient; - get httpClient(): HttpClient; - getLogger(name: string): EggLogger; - get logger(): EggLogger; - get coreLogger(): EggLogger; - get locals(): Record; - } -} diff --git a/src/app/extend/request.ts b/src/app/extend/request.ts index 623d248e54..e4819768ef 100644 --- a/src/app/extend/request.ts +++ b/src/app/extend/request.ts @@ -11,8 +11,6 @@ const HOST = Symbol('request host'); const IPS = Symbol('request ips'); const RE_ARRAY_KEY = /[^\[\]]+\[\]$/; -import './request.types.js'; - export default class Request extends EggCoreRequest { declare app: Application; declare ctx: Context; @@ -266,6 +264,17 @@ export default class Request extends EggCoreRequest { } } +declare module '@eggjs/core' { + // add Request overrides types + interface Request { + body: any; + get acceptJSON(): boolean; + get query(): Record; + set query(obj: Record); + get queries(): Record; + } +} + function firstValue(value: string | string[]) { if (Array.isArray(value)) { value = value[0]; diff --git a/src/app/extend/request.types.ts b/src/app/extend/request.types.ts deleted file mode 100644 index 8ee501396c..0000000000 --- a/src/app/extend/request.types.ts +++ /dev/null @@ -1,10 +0,0 @@ -declare module '@eggjs/core' { - // add Request overrides types - interface Request { - body: any; - get acceptJSON(): boolean; - get query(): Record; - set query(obj: Record); - get queries(): Record; - } -} diff --git a/src/app/extend/response.ts b/src/app/extend/response.ts index 5c0e029047..097df423c3 100644 --- a/src/app/extend/response.ts +++ b/src/app/extend/response.ts @@ -2,8 +2,6 @@ import { Response as KoaResponse } from '@eggjs/core'; const REAL_STATUS = Symbol('response realStatus'); -import './response.types.js'; - export default class Response extends KoaResponse { /** * Get or set a real status code. @@ -36,3 +34,11 @@ export default class Response extends KoaResponse { this[REAL_STATUS] = status; } } + +declare module '@eggjs/core' { + // add Response overrides types + interface Response { + get realStatus(): number; + set realStatus(status: number); + } +} diff --git a/src/app/extend/response.types.ts b/src/app/extend/response.types.ts deleted file mode 100644 index 00a2180b6a..0000000000 --- a/src/app/extend/response.types.ts +++ /dev/null @@ -1,7 +0,0 @@ -declare module '@eggjs/core' { - // add Response overrides types - interface Response { - get realStatus(): number; - set realStatus(status: number); - } -} diff --git a/src/lib/core/httpclient.ts b/src/lib/core/httpclient.ts index ea47566d2d..053aecdef4 100644 --- a/src/lib/core/httpclient.ts +++ b/src/lib/core/httpclient.ts @@ -2,6 +2,7 @@ import { HttpClient as RawHttpClient, RequestURL as HttpClientRequestURL, RequestOptions, + ClientOptions as HttpClientOptions, } from 'urllib'; import { ms } from 'humanize-ms'; import type { EggApplicationCore } from '../egg.js'; @@ -9,6 +10,7 @@ import type { EggApplicationCore } from '../egg.js'; export type { HttpClientResponse, RequestURL as HttpClientRequestURL, + ClientOptions as HttpClientOptions, } from 'urllib'; export interface HttpClientRequestOptions extends RequestOptions { @@ -19,12 +21,17 @@ export interface HttpClientRequestOptions extends RequestOptions { export class HttpClient extends RawHttpClient { readonly #app: EggApplicationCore & { tracer?: any }; - constructor(app: EggApplicationCore) { + constructor(app: EggApplicationCore, options: HttpClientOptions = {}) { normalizeConfig(app); const config = app.config.httpclient; - super({ - defaultArgs: config.request, - }); + const initOptions: HttpClientOptions = { + ...options, + defaultArgs: { + ...config.request, + ...options.defaultArgs, + }, + }; + super(initOptions); this.#app = app; } diff --git a/src/lib/egg.ts b/src/lib/egg.ts index d78c7d297f..cf0a5a184f 100644 --- a/src/lib/egg.ts +++ b/src/lib/egg.ts @@ -31,7 +31,9 @@ import type { EggAppConfig } from './types.js'; import { create as createMessenger, IMessenger } from './core/messenger/index.js'; import { ContextHttpClient } from './core/context_httpclient.js'; import { - HttpClient, type HttpClientRequestOptions, type HttpClientRequestURL, type HttpClientResponse, + HttpClient, + type HttpClientRequestOptions, type HttpClientRequestURL, type HttpClientResponse, + type HttpClientOptions, } from './core/httpclient.js'; import { createLoggers } from './core/logger.js'; import { @@ -43,8 +45,6 @@ import { BaseHookClass } from './core/base_hook_class.js'; import type { EggApplicationLoader } from './loader/index.js'; import { getSourceDirname } from './utils.js'; -import './egg.types.js'; - const EGG_PATH = Symbol.for('egg#eggPath'); export interface EggApplicationCoreOptions extends Omit { @@ -387,14 +387,22 @@ export class EggApplicationCore extends EggCore { return await this.httpClient.request(url, options); } + /** + * Create a new HttpClient instance with custom options + * @param {Object} [options] HttpClient init options + */ + createHttpClient(options?: HttpClientOptions): HttpClient { + return new this.HttpClient(this, options); + } + /** * HttpClient instance * @see https://github.com/node-modules/urllib * @member {HttpClient} */ - get httpClient() { + get httpClient(): HttpClient { if (!this.#httpClient) { - this.#httpClient = new this.HttpClient(this); + this.#httpClient = this.createHttpClient(); } return this.#httpClient; } @@ -680,3 +688,19 @@ export class EggApplicationCore extends EggCore { return context; } } + +declare module '@eggjs/core' { + // add EggApplicationCore overrides types + interface EggCore { + inspect(): any; + get currentContext(): EggContext | undefined; + ctxStorage: AsyncLocalStorage; + get logger(): EggLogger; + get coreLogger(): EggLogger; + getLogger(name: string): EggLogger; + createHttpClient(options?: HttpClientOptions): HttpClient; + HttpClient: typeof HttpClient; + get httpClient(): HttpClient; + curl(url: HttpClientRequestURL, options?: HttpClientRequestOptions): Promise>; + } +} diff --git a/src/lib/egg.types.ts b/src/lib/egg.types.ts deleted file mode 100644 index ebff5c81d7..0000000000 --- a/src/lib/egg.types.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { AsyncLocalStorage } from 'node:async_hooks'; -import type EggContext from '../app/extend/context.js'; -import type { EggLogger } from 'egg-logger'; - -declare module '@eggjs/core' { - // add EggApplicationCore overrides types - interface EggCore { - inspect(): any; - get currentContext(): EggContext | undefined; - ctxStorage: AsyncLocalStorage; - get logger(): EggLogger; - get coreLogger(): EggLogger; - getLogger(name: string): EggLogger; - } -} diff --git a/src/lib/types.ts b/src/lib/types.ts index 5efbe274ef..8adbed71fe 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -66,6 +66,17 @@ export interface CustomLoaderConfig extends Omit { assert(res.status === 200); }); }); + + describe('app.createHttpClient(options)', () => { + let app: MockApplication; + before(() => { + app = createApp('apps/httpclient-retry'); + return app.ready(); + }); + after(() => app.close()); + + it('should work', async () => { + const client1 = app.createHttpClient(); + const client2 = app.createHttpClient(); + assert.notEqual(client1, client2); + const res = await client1.request(url, { + method: 'GET', + }); + assert.equal(res.status, 200); + }); + }); }); diff --git a/test/lib/core/loader/load_plugin.test.ts b/test/lib/core/loader/load_plugin.test.ts index f8bf89bf2c..e80ea76828 100644 --- a/test/lib/core/loader/load_plugin.test.ts +++ b/test/lib/core/loader/load_plugin.test.ts @@ -3,7 +3,7 @@ import path from 'node:path'; import { mm } from '@eggjs/mock'; import { EggConsoleLogger } from 'egg-logger'; import { MockApplication, createApp, getFilepath } from '../../../utils.js'; -import { AppWorkerLoader, AgentWorkerLoader } from '../../../../src/index.js'; +import { AppWorkerLoader, AgentWorkerLoader, EggApplicationCore } from '../../../../src/index.js'; const EGG_BASE = getFilepath('../..'); @@ -22,7 +22,7 @@ describe('test/lib/core/loader/load_plugin.test.ts', () => { const appLoader = new AppWorkerLoader({ env: 'unittest', baseDir, - app, + app: app as unknown as EggApplicationCore, logger, }); await appLoader.loadConfig(); @@ -66,7 +66,7 @@ describe('test/lib/core/loader/load_plugin.test.ts', () => { const appLoader = new AppWorkerLoader({ env: 'unittest', baseDir, - app, + app: app as unknown as EggApplicationCore, logger, }); await appLoader.loadConfig(); @@ -88,7 +88,7 @@ describe('test/lib/core/loader/load_plugin.test.ts', () => { const appLoader = new AppWorkerLoader({ env: 'unittest', baseDir, - app, + app: app as unknown as EggApplicationCore, logger, }); await appLoader.loadConfig(); @@ -110,7 +110,7 @@ describe('test/lib/core/loader/load_plugin.test.ts', () => { const appLoader = new AppWorkerLoader({ env: 'unittest', baseDir, - app, + app: app as unknown as EggApplicationCore, logger, }); await appLoader.loadConfig(); @@ -136,7 +136,7 @@ describe('test/lib/core/loader/load_plugin.test.ts', () => { const appLoader = new AppWorkerLoader({ env: 'unittest', baseDir, - app, + app: app as unknown as EggApplicationCore, logger, }); await appLoader.loadConfig(); @@ -161,7 +161,7 @@ describe('test/lib/core/loader/load_plugin.test.ts', () => { env: 'unittest', baseDir, plugins, - app, + app: app as unknown as EggApplicationCore, logger, }); await appLoader.loadConfig(); @@ -194,7 +194,7 @@ describe('test/lib/core/loader/load_plugin.test.ts', () => { const appLoader = new AppWorkerLoader({ env: 'unittest', baseDir, - app, + app: app as unknown as EggApplicationCore, logger, }); await appLoader.loadConfig(); @@ -207,7 +207,7 @@ describe('test/lib/core/loader/load_plugin.test.ts', () => { const appLoader = new AppWorkerLoader({ env: 'unittest', baseDir, - app, + app: app as unknown as EggApplicationCore, logger, }); await appLoader.loadConfig(); @@ -220,7 +220,7 @@ describe('test/lib/core/loader/load_plugin.test.ts', () => { const appLoader = new AppWorkerLoader({ env: 'local', baseDir, - app, + app: app as unknown as EggApplicationCore, logger, }); await appLoader.loadConfig(); @@ -254,7 +254,7 @@ describe('test/lib/core/loader/load_plugin.test.ts', () => { const appLoader = new AppWorkerLoader({ env: 'unittest', baseDir, - app, + app: app as unknown as EggApplicationCore, logger, }); await appLoader.loadConfig(); @@ -267,7 +267,7 @@ describe('test/lib/core/loader/load_plugin.test.ts', () => { const appLoader = new AppWorkerLoader({ env: 'unittest', baseDir, - app, + app: app as unknown as EggApplicationCore, logger, }); await appLoader.loadConfig(); @@ -280,7 +280,7 @@ describe('test/lib/core/loader/load_plugin.test.ts', () => { const appLoader1 = new AppWorkerLoader({ env: 'unittest', baseDir, - app, + app: app as unknown as EggApplicationCore, logger, }); await appLoader1.loadConfig(); @@ -295,7 +295,7 @@ describe('test/lib/core/loader/load_plugin.test.ts', () => { const appLoader2 = new AppWorkerLoader({ env: 'local', baseDir, - app, + app: app as unknown as EggApplicationCore, logger, }); await appLoader2.loadConfig(); @@ -327,7 +327,7 @@ describe('test/lib/core/loader/load_plugin.test.ts', () => { const appLoader = new CustomAppLoader({ env: 'unittest', baseDir, - app, + app: app as unknown as EggApplicationCore, logger, }); await appLoader.loadConfig(); @@ -343,7 +343,7 @@ describe('test/lib/core/loader/load_plugin.test.ts', () => { const agentLoader = new CustomAgentLoader({ env: 'unittest', baseDir, - app, + app: app as unknown as EggApplicationCore, logger, }); await agentLoader.loadConfig();