@equinor/fusion-framework-module-http 8.1.0 → 8.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/esm/version.js +1 -1
  2. package/dist/tsconfig.tsbuildinfo +1 -1
  3. package/dist/types/version.d.ts +1 -1
  4. package/package.json +6 -3
  5. package/CHANGELOG.md +0 -1299
  6. package/docs/client-configuration.md +0 -175
  7. package/docs/observable-patterns.md +0 -103
  8. package/docs/selectors-and-handlers.md +0 -112
  9. package/docs/server-sent-events.md +0 -125
  10. package/docs/testing.md +0 -78
  11. package/src/configurator.ts +0 -249
  12. package/src/errors/ClientNotFoundException.ts +0 -9
  13. package/src/errors/HttpJsonResponseError.ts +0 -32
  14. package/src/errors/HttpResponseError.ts +0 -21
  15. package/src/errors/ServerSentEventResponseError.ts +0 -30
  16. package/src/errors/index.ts +0 -4
  17. package/src/index.ts +0 -15
  18. package/src/lib/client/client-msal.ts +0 -80
  19. package/src/lib/client/client.ts +0 -496
  20. package/src/lib/client/index.ts +0 -4
  21. package/src/lib/client/types.ts +0 -244
  22. package/src/lib/index.ts +0 -3
  23. package/src/lib/operators/HttpMiddlewareHandler.ts +0 -58
  24. package/src/lib/operators/HttpRequestHandler.ts +0 -29
  25. package/src/lib/operators/HttpResponseHandler.ts +0 -11
  26. package/src/lib/operators/ProcessOperators.ts +0 -113
  27. package/src/lib/operators/capitalize-request-method-operator.ts +0 -26
  28. package/src/lib/operators/fetch-request.schemas.ts +0 -104
  29. package/src/lib/operators/index.ts +0 -9
  30. package/src/lib/operators/request-operator-header.ts +0 -19
  31. package/src/lib/operators/request-validation-operator.ts +0 -51
  32. package/src/lib/operators/sse-map.operator.ts +0 -45
  33. package/src/lib/operators/types.ts +0 -174
  34. package/src/lib/selectors/blob-selector.ts +0 -42
  35. package/src/lib/selectors/create-sse-selector.ts +0 -279
  36. package/src/lib/selectors/index.ts +0 -11
  37. package/src/lib/selectors/json-selector.ts +0 -52
  38. package/src/mock/create-open-api-mock-middleware.ts +0 -40
  39. package/src/mock/create-router-middleware.ts +0 -158
  40. package/src/mock/index.ts +0 -26
  41. package/src/mock/resolve-open-api-mock-response.ts +0 -36
  42. package/src/module.ts +0 -149
  43. package/src/provider.ts +0 -225
  44. package/src/version.ts +0 -2
  45. package/tests/HttpClient.test.ts +0 -173
  46. package/tests/HttpMiddlewareHandler.test.ts +0 -58
  47. package/tests/mock/adapters.test.ts +0 -62
  48. package/tests/mock/router-middleware.test.ts +0 -135
  49. package/tests/operators.test.ts +0 -137
  50. package/tests/sse.selector.test.ts +0 -162
  51. package/tsconfig.json +0 -18
  52. package/vitest.config.ts +0 -12
@@ -1,158 +0,0 @@
1
- import type { HttpMiddleware } from '../lib/operators/types';
2
-
3
- /**
4
- * A route match handed to a {@link MockRouteHandler} once its pattern has matched a request.
5
- */
6
- export interface MockRouteMatch {
7
- /** Path parameters extracted from named segments in the route pattern, e.g. `:id` -> `params.id`. */
8
- params: Record<string, string>;
9
- /** The fully resolved request URL, for reading query parameters via `url.searchParams`. */
10
- url: URL;
11
- /** The request as a Fetch-standard `Request`, for reading headers or a JSON/text body. */
12
- request: Request;
13
- }
14
-
15
- /** Builds the `Response` for one matched route. */
16
- export type MockRouteHandler = (match: MockRouteMatch) => Response | Promise<Response>;
17
-
18
- /**
19
- * Registers route handlers for {@link createRouterMiddleware}, in the style of a minimal
20
- * Express-like router — path templates (`:id`) and per-method registration, without pulling
21
- * in a real routing library.
22
- */
23
- export interface IMockRouterBuilder {
24
- /** Registers `handler` for `GET` requests matching `path`. @see {@link IMockRouterBuilder.on} */
25
- get(path: string, handler: MockRouteHandler): IMockRouterBuilder;
26
- /** Registers `handler` for `POST` requests matching `path`. @see {@link IMockRouterBuilder.on} */
27
- post(path: string, handler: MockRouteHandler): IMockRouterBuilder;
28
- /** Registers `handler` for `PUT` requests matching `path`. @see {@link IMockRouterBuilder.on} */
29
- put(path: string, handler: MockRouteHandler): IMockRouterBuilder;
30
- /** Registers `handler` for `PATCH` requests matching `path`. @see {@link IMockRouterBuilder.on} */
31
- patch(path: string, handler: MockRouteHandler): IMockRouterBuilder;
32
- /** Registers `handler` for `DELETE` requests matching `path`. @see {@link IMockRouterBuilder.on} */
33
- delete(path: string, handler: MockRouteHandler): IMockRouterBuilder;
34
- /**
35
- * Registers `handler` for a method and path template.
36
- * @param method - The HTTP method to match, case-insensitively, or `undefined` to match any method.
37
- * @param path - A path template relative to the router's base URI. A segment starting with
38
- * `:` (e.g. `/contexts/:id`) captures that segment into `params`; every other segment must
39
- * match literally. A trailing slash is always optional.
40
- * @param handler - Builds the `Response` for a matching request.
41
- */
42
- on(method: string | undefined, path: string, handler: MockRouteHandler): IMockRouterBuilder;
43
- }
44
-
45
- interface RegisteredRoute {
46
- method: string | undefined;
47
- regexp: RegExp;
48
- keys: string[];
49
- handler: MockRouteHandler;
50
- }
51
-
52
- /**
53
- * Compiles a path template into a matching `RegExp` plus the ordered list of named parameters
54
- * it captures.
55
- *
56
- * @param path - A path template such as `/contexts/:id`.
57
- * @returns The compiled pattern and the parameter names it captures, in segment order.
58
- */
59
- function compilePath(path: string): { regexp: RegExp; keys: string[] } {
60
- const keys: string[] = [];
61
- const pattern = path
62
- .split('/')
63
- // each segment either captures a path parameter or must match literally
64
- .map((segment) => {
65
- // only `:name` segments become capture groups; everything else must match literally
66
- if (!segment.startsWith(':')) {
67
- return segment.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
68
- }
69
- keys.push(segment.slice(1));
70
- return '([^/]+)';
71
- })
72
- .join('/');
73
- return { regexp: new RegExp(`^${pattern}/?$`), keys };
74
- }
75
-
76
- /**
77
- * Builds an {@link HttpMiddleware} that answers requests to one base URI with hand-registered
78
- * route handlers, matched by method and a path template (`:id`-style segments) — a lightweight
79
- * router for tests with more than a couple of routes to fake, without hand-rolling `RegExp`
80
- * matching against `uri` in every middleware.
81
- *
82
- * @remarks
83
- * A request outside `baseUri`, or matching no registered route, falls through to `next`, so
84
- * this composes with other middleware — including the real network call, or another router
85
- * for a different base URI — registered around it. Routes are tried in registration order;
86
- * the first match wins.
87
- *
88
- * Deliberately not an MSW-compatible API — this stays inside `addMiddleware`'s own request
89
- * pipeline rather than intercepting the network boundary, so it has none of MSW's response
90
- * transformers, `onUnhandledRequest` diagnostics, or wildcard patterns.
91
- *
92
- * @param baseUri - The base URI this router answers for, e.g. `https://api.example.com`.
93
- * @param build - Registers routes on the given {@link IMockRouterBuilder}.
94
- * @returns A middleware for {@link IHttpClientConfigurator.addMiddleware}.
95
- *
96
- * @example Fake a handful of routes under one base URI
97
- * ```typescript
98
- * configurator.http.addMiddleware(
99
- * createRouterMiddleware('https://context.example.com', (router) => {
100
- * router.get('/contexts/:id/relations', () => Response.json([{ id: 'ctx-3' }]));
101
- * router.get('/contexts', () => Response.json([{ id: 'ctx-2' }]));
102
- * router.get('/contexts/:id', ({ params }) => Response.json({ id: params.id }));
103
- * }),
104
- * );
105
- * ```
106
- */
107
- export function createRouterMiddleware(
108
- baseUri: string,
109
- build: (router: IMockRouterBuilder) => void,
110
- ): HttpMiddleware {
111
- const routes: RegisteredRoute[] = [];
112
- const register = (
113
- method: string | undefined,
114
- path: string,
115
- handler: MockRouteHandler,
116
- ): IMockRouterBuilder => {
117
- const { regexp, keys } = compilePath(path);
118
- routes.push({ method: method?.toUpperCase(), regexp, keys, handler });
119
- return router;
120
- };
121
- const router: IMockRouterBuilder = {
122
- get: (path, handler) => register('GET', path, handler),
123
- post: (path, handler) => register('POST', path, handler),
124
- put: (path, handler) => register('PUT', path, handler),
125
- patch: (path, handler) => register('PATCH', path, handler),
126
- delete: (path, handler) => register('DELETE', path, handler),
127
- on: register,
128
- };
129
- build(router);
130
-
131
- const base = new URL(baseUri);
132
- const basePath = base.pathname.replace(/\/$/, '');
133
-
134
- return async (uri, init, next) => {
135
- const url = new URL(uri);
136
- // requests to a different origin, or outside this router's base path, are none of its concern
137
- if (url.origin !== base.origin || !url.pathname.startsWith(basePath)) return next(uri, init);
138
-
139
- const pathname = url.pathname.slice(basePath.length) || '/';
140
- const method = (init.method ?? 'GET').toUpperCase();
141
-
142
- // first registered route whose method and pattern both match wins
143
- for (const route of routes) {
144
- // a route registered for a specific method never answers a request for another method
145
- if (route.method && route.method !== method) continue;
146
- const match = route.regexp.exec(pathname);
147
- // pattern didn't match this pathname at all — try the next registered route
148
- if (!match) continue;
149
- // capture groups are positional, in the same order `compilePath` recorded their names
150
- const params = Object.fromEntries(route.keys.map((key, i) => [key, match[i + 1]]));
151
- return route.handler({ params, url, request: new Request(uri, init) });
152
- }
153
-
154
- return next(uri, init);
155
- };
156
- }
157
-
158
- export default createRouterMiddleware;
package/src/mock/index.ts DELETED
@@ -1,26 +0,0 @@
1
- /**
2
- * Testing utilities for the HTTP module.
3
- *
4
- * @remarks
5
- * Imported from `@equinor/fusion-framework-module-http/mock`, so testing
6
- * utilities ship and version with the implementation they stand in for.
7
- *
8
- * There is no separate mock client or configurator here — register a
9
- * short-circuiting `HttpMiddleware` through `configurator.http.addMiddleware(...)`
10
- * on the real `HttpClientConfigurator` instead, so app config never has to
11
- * branch on whether it's under test. See {@link createOpenApiMockMiddleware}
12
- * for faking a whole OpenAPI document's operations that way.
13
- *
14
- * This entry point has no dependency on any test runner.
15
- *
16
- * @packageDocumentation
17
- */
18
-
19
- export { createOpenApiMockMiddleware } from './create-open-api-mock-middleware';
20
- export type { OpenApiMockLike } from './resolve-open-api-mock-response';
21
- export {
22
- createRouterMiddleware,
23
- type MockRouteHandler,
24
- type MockRouteMatch,
25
- type IMockRouterBuilder,
26
- } from './create-router-middleware';
@@ -1,36 +0,0 @@
1
- /**
2
- * The subset of `OpenApiMock` (from `@equinor/fusion-openapi-mock`'s
3
- * `createOpenApiMock`) the adapters in this file need — duck-typed so this
4
- * package has no dependency on that one; anything shaped like this works.
5
- */
6
- export interface OpenApiMockLike {
7
- resolve(request: {
8
- method: string;
9
- path: string;
10
- query?: Record<string, string>;
11
- }): Promise<{ status: number; mock: unknown } | undefined>;
12
- }
13
-
14
- /**
15
- * Resolves a method and URL against an `OpenApiMock`, building a `Response`
16
- * from whatever it matches — shared by every adapter targeting a different
17
- * middleware shape, so the method/path/query mapping and status/body wiring
18
- * lives in one place.
19
- *
20
- * @param openApiMock - The mock to resolve against.
21
- * @param method - The request's HTTP method.
22
- * @param url - The request's fully resolved URL.
23
- * @returns The faked `Response`, or `undefined` when no operation matches.
24
- */
25
- export async function resolveOpenApiMockResponse(
26
- openApiMock: OpenApiMockLike,
27
- method: string,
28
- url: URL,
29
- ): Promise<Response | undefined> {
30
- const result = await openApiMock.resolve({
31
- method,
32
- path: url.pathname,
33
- query: Object.fromEntries(url.searchParams),
34
- });
35
- return result && Response.json(result.mock, { status: result.status });
36
- }
package/src/module.ts DELETED
@@ -1,149 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { HttpClientMsal } from './lib/client';
3
- import {
4
- type IHttpClientConfigurator,
5
- HttpClientConfigurator,
6
- type HttpClientOptions,
7
- } from './configurator';
8
- import { type IHttpClientProvider, HttpClientProvider } from './provider';
9
-
10
- import type {
11
- Module,
12
- ModuleConfigType,
13
- IModuleConfigurator,
14
- } from '@equinor/fusion-framework-module';
15
-
16
- import type { MsalModule } from '@equinor/fusion-framework-module-msal';
17
-
18
- /**
19
- * Defines the type for the HTTP module, which includes:
20
- * - The module name: 'http'
21
- * - The type of the HTTP client provider, which is `IHttpClientProvider`
22
- * - The type of the HTTP client configurator, which is `IHttpClientConfigurator`
23
- */
24
- export type HttpModule = Module<'http', IHttpClientProvider, IHttpClientConfigurator>;
25
-
26
- /**
27
- * Defines the type for the HTTP module with MSAL authentication.
28
- *
29
- * This type represents the module configuration for the HTTP module, which includes:
30
- * - The module name: 'http'
31
- * - The type of the HTTP client provider, which is `IHttpClientProvider<HttpClientMsal>`
32
- * - The type of the HTTP client configurator, which is `IHttpClientConfigurator<HttpClientMsal>`
33
- * - The list of required modules, which includes the `MsalModule`
34
- */
35
- export type HttpMsalModule = Module<
36
- 'http',
37
- IHttpClientProvider<HttpClientMsal>,
38
- IHttpClientConfigurator<HttpClientMsal>,
39
- [MsalModule]
40
- >;
41
-
42
- /**
43
- * Default HTTP module definition for Fusion Framework applications.
44
- *
45
- * The module uses `HttpClientMsal` as the default client implementation and,
46
- * when the auth module is available, installs a request handler that can acquire
47
- * bearer tokens for scoped requests.
48
- */
49
- export const module: HttpMsalModule = {
50
- name: 'http',
51
- /**
52
- * Configures the HTTP module with MSAL authentication.
53
- *
54
- * This function creates a new `HttpClientConfigurator` instance using the `HttpClientMsal` class.
55
- * The `HttpClientConfigurator` is responsible for configuring the HTTP client with the necessary options,
56
- * such as the base URL, request headers, and other settings.
57
- *
58
- * @returns A new `HttpClientConfigurator` instance configured for MSAL authentication.
59
- */
60
- configure: () => new HttpClientConfigurator(HttpClientMsal),
61
-
62
- /**
63
- * Initializes the HTTP client provider with MSAL authentication.
64
- *
65
- * This function is responsible for setting up the default HTTP request handler
66
- * to acquire an access token from MSAL and attach it to the request headers
67
- * when the request includes scopes.
68
- *
69
- * @param config - The module configuration.
70
- * @param hasModule - A function to check if a module is available.
71
- * @param requireInstance - A function to get an instance of a module.
72
- * @returns A promise that resolves to the HTTP client provider.
73
- */
74
- initialize: async ({
75
- config,
76
- hasModule,
77
- requireInstance,
78
- }): Promise<HttpClientProvider<HttpClientMsal>> => {
79
- const httpProvider = new HttpClientProvider(config);
80
- // wire up an MSAL bearer-token handler only when the auth module is registered
81
- if (hasModule('auth')) {
82
- const authProvider = await requireInstance('auth');
83
- httpProvider.defaultHttpRequestHandler.set('MSAL', async (request) => {
84
- const { scopes = [] } = request;
85
- // only attempt to acquire a token when the request actually declares scopes
86
- if (scopes.length) {
87
- /** TODO(#5143): should be try catch, check caller for handling */
88
- const accessToken = await authProvider.acquireAccessToken({
89
- request: { scopes },
90
- });
91
- // without a token there's nothing to attach, fall through to the default request
92
- if (accessToken) {
93
- const headers = new Headers(request.headers);
94
- headers.set('Authorization', `Bearer ${accessToken}`);
95
- return { ...request, headers };
96
- }
97
- }
98
- });
99
- }
100
- return httpProvider;
101
- },
102
- };
103
-
104
- /**
105
- * Creates a module configurator for the HTTP module.
106
- *
107
- * Use this when you need lower-level access to the module configuration callback,
108
- * for example when registering several named clients in one setup step.
109
- *
110
- * @param configure - The callback that receives the HTTP module configuration.
111
- * @returns A module configurator for the HTTP module.
112
- */
113
- export const configureHttp = <TRef = unknown>(
114
- configure: (config: ModuleConfigType<HttpMsalModule>, ref?: TRef) => void,
115
- ): IModuleConfigurator<HttpMsalModule, TRef> => ({
116
- module,
117
- configure,
118
- });
119
-
120
- /**
121
- * Creates a module configurator that registers one named HTTP client.
122
- *
123
- * This is the convenience API for the common case where a setup step only needs to
124
- * register one client with `baseUri`, `defaultScopes`, handlers, or a custom constructor.
125
- *
126
- * @param name - The client key used later with `createClient(name)`.
127
- * @param args - The named client configuration.
128
- * @returns A module configurator that registers the named client.
129
- */
130
- export const configureHttpClient = <TRef = unknown>(
131
- name: string,
132
- args: HttpClientOptions<HttpClientMsal>,
133
- ): IModuleConfigurator<HttpMsalModule, TRef> => ({
134
- module,
135
- configure: (config: ModuleConfigType<HttpMsalModule>) => {
136
- config.configureClient(name, args);
137
- },
138
- });
139
-
140
- /**
141
- * Declares a module named '@equinor/fusion-framework-module' that contains an interface named 'Modules' with a property 'http' of type 'HttpMsalModule'.
142
- */
143
- declare module '@equinor/fusion-framework-module' {
144
- interface Modules {
145
- http: HttpMsalModule;
146
- }
147
- }
148
-
149
- export default module;
package/src/provider.ts DELETED
@@ -1,225 +0,0 @@
1
- import type { HttpClient } from './lib/client';
2
- import type {
3
- HttpClientOptions,
4
- HttpClientRequestInitType,
5
- IHttpClientConfigurator,
6
- } from './configurator';
7
-
8
- import type { IHttpMiddlewareHandler, IHttpRequestHandler } from './lib/operators';
9
- import type { IHttpClient } from './lib/client';
10
- import { BaseModuleProvider } from '@equinor/fusion-framework-module/provider';
11
- import { version } from './version';
12
- import { ClientNotFoundException } from './errors/index.js';
13
-
14
- /**
15
- * Creates fresh HTTP client instances from named or ad-hoc configuration.
16
- *
17
- * A provider can create clients from registered names, inline `HttpClientOptions`,
18
- * or absolute URLs treated as ad-hoc `baseUri` values.
19
- */
20
- export interface IHttpClientProvider<TClient extends IHttpClient = IHttpClient> {
21
- /**
22
- * The default HTTP request handler used by the HttpClientProvider.
23
- * This handler is responsible for executing HTTP requests using the configured HttpClient.
24
- */
25
- readonly defaultHttpRequestHandler: IHttpRequestHandler<HttpClientRequestInitType<TClient>>;
26
-
27
- /**
28
- * The default middleware chain used by the HttpClientProvider, wrapping the network call
29
- * for every client it creates unless a client overrides it with its own `middlewareHandler`.
30
- */
31
- readonly defaultHttpMiddlewareHandler: IHttpMiddlewareHandler;
32
-
33
- /**
34
- * Checks if a client is configured with the given key.
35
- * @param key - The key of the client to check.
36
- * @returns `true` if a client is configured with the given key, `false` otherwise.
37
- */
38
- hasClient(key: string): boolean;
39
-
40
- /**
41
- * Creates a new HTTP client instance with the specified key.
42
- * @param key - The key of the HTTP client to create.
43
- * @returns The created HTTP client instance.
44
- */
45
- createClient(key: string): TClient;
46
- createClient(key: HttpClientOptions<TClient>): TClient;
47
-
48
- /**
49
- * Creates a client instance and casts it to a custom HTTP client type.
50
- *
51
- * This is most useful when the named client configuration uses a custom `ctor`
52
- * that extends `HttpClient` with domain-specific methods.
53
- * @example
54
- * ```ts
55
- * config.http.configureClient('foobar', {
56
- * ctor: MyClient,
57
- * baseUri: 'https://foobar.com',
58
- * });
59
- * ```
60
- */
61
- createCustomClient<T extends HttpClient>(key: string): T;
62
- }
63
-
64
- /** URL protocols accepted as valid ad-hoc base URIs. */
65
- const SUPPORTED_PROTOCOLS = ['http:', 'https:', 'ws:', 'wss:'] as const;
66
-
67
- /**
68
- * Checks if a given string is a valid absolute URL with a supported protocol.
69
- * @param url - The string to check.
70
- * @returns `true` when the string uses one of {@link SUPPORTED_PROTOCOLS}.
71
- */
72
- const isURL = (url: string): boolean => {
73
- try {
74
- const parsed = new URL(url);
75
- return (SUPPORTED_PROTOCOLS as readonly string[]).includes(parsed.protocol);
76
- } catch {
77
- return false;
78
- }
79
- };
80
-
81
- /**
82
- * Heuristic check for strings that look like a bare hostname or URL without a
83
- * protocol prefix (e.g. `api.example.com` or `api.example.com/v1`).
84
- *
85
- * Used to emit a deprecation warning when callers rely on the old (pre-patch)
86
- * behaviour that accepted protocol-less URLs.
87
- */
88
- const looksLikeURL = (value: string): boolean =>
89
- !value.includes(' ') && /^[a-z\d]([a-z\d-]*\.)+[a-z]{2,}/i.test(value);
90
-
91
- /**
92
- * The `HttpClientProvider` class is responsible for managing HTTP client instances and their configuration.
93
- * It provides methods to check if a client is configured, create new client instances, and create custom client instances.
94
- */
95
- export class HttpClientProvider<TClient extends IHttpClient = IHttpClient>
96
- extends BaseModuleProvider<IHttpClientConfigurator<TClient>>
97
- implements IHttpClientProvider<TClient>
98
- {
99
- /**
100
- * Gets the default HTTP request handler for the HTTP client provider.
101
- * @returns The default HTTP request handler.
102
- */
103
- get defaultHttpRequestHandler(): IHttpRequestHandler<HttpClientRequestInitType<TClient>> {
104
- return this.config.defaultHttpRequestHandler;
105
- }
106
-
107
- /**
108
- * Gets the default middleware chain for the HTTP client provider.
109
- * @returns The default middleware chain.
110
- */
111
- get defaultHttpMiddlewareHandler(): IHttpMiddlewareHandler {
112
- return this.config.defaultHttpMiddlewareHandler;
113
- }
114
-
115
- /**
116
- * Creates a new `HttpClientProvider`.
117
- * @param config - The configurator providing client definitions and defaults.
118
- */
119
- constructor(protected config: IHttpClientConfigurator<TClient>) {
120
- super({
121
- version,
122
- config,
123
- });
124
- }
125
-
126
- /**
127
- * Checks if a client with the given key is configured in the `HttpClientProvider`.
128
- * @param key - The key of the HTTP client to check.
129
- * @returns `true` if a client with the given key is configured, `false` otherwise.
130
- */
131
- public hasClient(key: string): boolean {
132
- return Object.keys(this.config.clients).includes(key);
133
- }
134
-
135
- /**
136
- * Creates a fresh HTTP client instance from a named or ad-hoc configuration.
137
- *
138
- * @param keyOrConfig - The key or configuration object for the HTTP client.
139
- * @returns The created HTTP client instance.
140
- *
141
- * @remarks
142
- * This method resolves the configuration for the HTTP client based on the provided `keyOrConfig` parameter.
143
- * If a string is provided, it is treated as the key for a pre-configured client in the `HttpClientProvider`.
144
- * If an `HttpClientOptions` object is provided, it is used as the configuration for the new client instance.
145
- *
146
- * The method applies `baseUri`, `defaultScopes`, `requestHandler`, `responseHandler`,
147
- * a custom `ctor` when configured, and finally runs `onCreate` for the newly created instance.
148
- *
149
- * The created HTTP client instance is returned.
150
- */
151
- public createClient(keyOrConfig: string | HttpClientOptions<TClient>): TClient {
152
- const config = this._resolveConfig(keyOrConfig);
153
- const {
154
- baseUri,
155
- defaultScopes = [],
156
- onCreate,
157
- ctor = this.config.defaultHttpClientCtor,
158
- requestHandler = this.defaultHttpRequestHandler,
159
- responseHandler,
160
- middlewareHandler = this.defaultHttpMiddlewareHandler,
161
- } = config as HttpClientOptions<TClient>;
162
- const options = { requestHandler, responseHandler, middlewareHandler };
163
- const instance = new ctor(baseUri || '', options) as TClient;
164
- // attach the resolved default scopes onto the instance without overwriting other own properties
165
- Object.assign(instance, { defaultScopes });
166
- onCreate?.(instance as TClient);
167
- return instance as TClient;
168
- }
169
-
170
- /**
171
- * Creates a client instance and returns it as the requested custom client type.
172
- *
173
- * @template T - The custom `HttpClient` implementation type to cast the created instance to.
174
- * @param key - The key of the pre-configured HTTP client to create.
175
- * @returns The created HTTP client instance, cast to the specified type `T`.
176
- *
177
- * @remarks
178
- * This method delegates to the `createClient` method, but casts the returned
179
- * instance to the specified type `T`. This can be useful when you need to
180
- * work with a specific HTTP client implementation, but the `HttpClientProvider`
181
- * is configured to use a different implementation.
182
- */
183
- public createCustomClient<T extends HttpClient>(key: string): T {
184
- // `createClient` always returns the provider's configured `HttpClient` implementation —
185
- // cast through `unknown` to hand back the caller-requested implementation type `T`.
186
- return this.createClient(key) as unknown as T;
187
- }
188
-
189
- /**
190
- * Resolves the configuration for an HTTP client based on the provided `keyOrConfig` parameter.
191
- *
192
- * If a string is provided, it is treated as either a pre-configured client key or,
193
- * when it is an absolute `http:` or `https:` URL, as an ad-hoc `baseUri`.
194
- * If an `HttpClientOptions` object is provided, it is used directly as the configuration for the new client instance.
195
- *
196
- * @param keyOrConfig - The key or configuration object for the HTTP client.
197
- * @returns The resolved HTTP client configuration.
198
- * @throws {ClientNotFoundException} When `keyOrConfig` is a string that is neither a registered
199
- * client key nor a URL-like value.
200
- */
201
- protected _resolveConfig(
202
- keyOrConfig: string | HttpClientOptions<TClient>,
203
- ): HttpClientOptions<TClient> {
204
- // a string may reference a registered client key or an ad-hoc URL; anything else is used as-is
205
- if (typeof keyOrConfig === 'string') {
206
- const config = this.config.clients[keyOrConfig];
207
- // an absolute http(s) URL can be used directly as an ad-hoc baseUri
208
- if (!config && isURL(keyOrConfig)) {
209
- return { baseUri: keyOrConfig };
210
- } else if (!config && looksLikeURL(keyOrConfig)) {
211
- // recover from a missing protocol instead of failing outright, but warn so it can be fixed
212
- console.warn(
213
- `[HttpClientProvider] "${keyOrConfig}" looks like a URL but is missing the http:// or https:// protocol. ` +
214
- `Treating it as "https://${keyOrConfig}". ` +
215
- `Pass a fully-qualified URL to silence this warning.`,
216
- );
217
- return { baseUri: `https://${keyOrConfig}` };
218
- } else if (!config) {
219
- throw new ClientNotFoundException(`No registered http client for key [${keyOrConfig}]`);
220
- }
221
- return config;
222
- }
223
- return keyOrConfig as HttpClientOptions<TClient>;
224
- }
225
- }
package/src/version.ts DELETED
@@ -1,2 +0,0 @@
1
- // Generated by genversion.
2
- export const version = '8.1.0';