@webpieces/http-client-node 0.4.702 → 0.4.704

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/http-client-node",
3
- "version": "0.4.702",
3
+ "version": "0.4.704",
4
4
  "description": "Server-side HTTP client for webpieces: inversify-wired, reads RequestContext directly, mints OIDC/shared-secret delivery auth, resolves Cloud Run URLs from a service name",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -22,10 +22,10 @@
22
22
  "access": "public"
23
23
  },
24
24
  "dependencies": {
25
- "@webpieces/core-context": "0.4.702",
26
- "@webpieces/core-util": "0.4.702",
27
- "@webpieces/gcp-identity": "0.4.702",
28
- "@webpieces/http-client-core": "0.4.702",
25
+ "@webpieces/core-context": "0.4.704",
26
+ "@webpieces/core-util": "0.4.704",
27
+ "@webpieces/gcp-identity": "0.4.704",
28
+ "@webpieces/http-client-core": "0.4.704",
29
29
  "inversify": "7.10.4",
30
30
  "reflect-metadata": "0.2.2"
31
31
  }
@@ -1,6 +1,5 @@
1
1
  import { Provider } from '@webpieces/core-context';
2
- import type { ApiPrototype } from '@webpieces/http-client-core';
3
- import type { ClientFilters } from '@webpieces/http-client-core';
2
+ import type { ApiPrototype, ClientFilterDefinition } from '@webpieces/http-client-core';
4
3
  import { ClientConfig } from './ClientConfig';
5
4
  import { NodeProxyClient } from './NodeProxyClient';
6
5
  /**
@@ -63,12 +62,14 @@ export declare class ClientHttpFactory {
63
62
  * guard and credential minter are installed on every client regardless, BENEATH anything
64
63
  * passed here, so there is nothing an app can decline by writing nothing.
65
64
  *
66
- * ONE SPELLING PER DECISION. It is a NON-EMPTY tuple, so `createRpcClient(Api, cfg, [])`
67
- * does not compile: "this client has no app filters" is said by omitting the argument, and
68
- * `[]` would be a second way to say the identical thing. That is the same device
69
- * {@link JwtRoles}'s `roles` uses, for the same reason the bad case is deleted by the
70
- * TYPE rather than left available and discouraged in a docstring. Pinned in
65
+ * A PLAIN OPTIONAL ARRAY, deliberately. Omitting it, passing `[]`, and passing a list you
66
+ * built up conditionally all mean the same thing and all compile because the normal way
67
+ * an app arrives at a filter list is to declare a `ClientFilterDefinition[]` and push to
68
+ * it under `if`s, and the declared type of such a local can never be non-empty. A
69
+ * non-empty tuple here would reject that ordinary code and force a cast at the call site.
70
+ * `filters === undefined ? [] : [...filters]` below normalizes the two empty spellings to
71
+ * one value before anything downstream sees them. Pinned in
71
72
  * {@link CreateRpcClientCompileAssertions}.
72
73
  */
73
- createRpcClient<T extends object>(apiPrototype: ApiPrototype<T>, config: ClientConfig, filters?: ClientFilters): T;
74
+ createRpcClient<T extends object>(apiPrototype: ApiPrototype<T>, config: ClientConfig, filters?: readonly ClientFilterDefinition[]): T;
74
75
  }
@@ -72,11 +72,13 @@ let ClientHttpFactory = class ClientHttpFactory {
72
72
  * guard and credential minter are installed on every client regardless, BENEATH anything
73
73
  * passed here, so there is nothing an app can decline by writing nothing.
74
74
  *
75
- * ONE SPELLING PER DECISION. It is a NON-EMPTY tuple, so `createRpcClient(Api, cfg, [])`
76
- * does not compile: "this client has no app filters" is said by omitting the argument, and
77
- * `[]` would be a second way to say the identical thing. That is the same device
78
- * {@link JwtRoles}'s `roles` uses, for the same reason the bad case is deleted by the
79
- * TYPE rather than left available and discouraged in a docstring. Pinned in
75
+ * A PLAIN OPTIONAL ARRAY, deliberately. Omitting it, passing `[]`, and passing a list you
76
+ * built up conditionally all mean the same thing and all compile because the normal way
77
+ * an app arrives at a filter list is to declare a `ClientFilterDefinition[]` and push to
78
+ * it under `if`s, and the declared type of such a local can never be non-empty. A
79
+ * non-empty tuple here would reject that ordinary code and force a cast at the call site.
80
+ * `filters === undefined ? [] : [...filters]` below normalizes the two empty spellings to
81
+ * one value before anything downstream sees them. Pinned in
80
82
  * {@link CreateRpcClientCompileAssertions}.
81
83
  */
82
84
  createRpcClient(apiPrototype, config, filters) {
@@ -1 +1 @@
1
- {"version":3,"file":"ClientHttpFactory.js","sourceRoot":"","sources":["../../../../../packages/http/http-client-node/src/ClientHttpFactory.ts"],"names":[],"mappings":";;;;AAAA,yCAAmC;AACnC,oDAAsD;AACtD,0DAAqG;AAErG,kEAA+D;AAG/D,uDAAgF;AAEhF,iGAAiG;AACjG,6EAA6E;AAC7E,IAAA,oCAAqB,EAAC,4CAA0B,EAAE,iCAAe,CAAC,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAGI,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAE+B;IADzD,YACyD,mBAA8C;QAA9C,wBAAmB,GAAnB,mBAAmB,CAA2B;IACpG,CAAC;IAEJ;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,eAAe,CACX,YAA6B,EAC7B,MAAoB,EACpB,OAAuB;QAEvB,sFAAsF;QACtF,wEAAwE;QACxE,MAAM,WAAW,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,EAAE,CAAC;QACnD,WAAW,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;QAClF,OAAO,IAAA,mCAAgB,EAAC,YAAY,EAAE,WAAW,CAAC,CAAC;IACvD,CAAC;CACJ,CAAA;AAtCY,8CAAiB;4BAAjB,iBAAiB;IAF7B,IAAA,0BAAc,GAAE;IAChB,IAAA,wCAAyB,GAAE;IAGnB,mBAAA,IAAA,kBAAM,EAAC,4CAA0B,CAAC,CAAA;6CAAuC,uBAAQ;GAF7E,iBAAiB,CAsC7B","sourcesContent":["import { inject } from 'inversify';\nimport { DocumentDesign } from '@webpieces/core-util';\nimport { Provider, bindFrameworkProvider, provideFrameworkSingleton } from '@webpieces/core-context';\nimport type { ApiPrototype } from '@webpieces/http-client-core';\nimport { buildClientProxy } from '@webpieces/http-client-core';\nimport type { ClientFilters } from '@webpieces/http-client-core';\nimport { ClientConfig } from './ClientConfig';\nimport { NODE_PROXY_CLIENT_PROVIDER, NodeProxyClient } from './NodeProxyClient';\n\n// Teach the container how to hand out fresh NodeProxyClients. NodeProxyClient is bound TRANSIENT\n// (@provideFrameworkTransient), so each provider.get() constructs a new one.\nbindFrameworkProvider(NODE_PROXY_CLIENT_PROVIDER, NodeProxyClient);\n\n/**\n * ClientHttpFactory - builds type-safe HTTP clients from API prototypes carrying\n * @ApiPath/@Endpoint decorators. The SERVER-side factory.\n *\n * This is the client-side equivalent of ApiRoutingFactory:\n * - Server routing: ApiRoutingFactory reads decorators -> routes HTTP requests to controllers\n * - Server client: ClientHttpFactory reads decorators -> generates HTTP requests from method calls\n *\n * Inject it and ask for a typed client per contract:\n * ```typescript\n * // same project + region as this container; the URL is derived, you maintain nothing\n * const server2 = factory.createRpcClient(Server2Api, new ClientConfig('server2'));\n *\n * // to reach somewhere derivation cannot describe (other region/project, non-Cloud-Run, localhost),\n * // register it once at startup — the client still carries only the svcName:\n * // ClientRegistry.addUrlMapping('legacy', 'https://legacy.corp');\n * const legacy = factory.createRpcClient(LegacyApi, new ClientConfig('legacy'));\n *\n * const response = await server2.fetchValue(req); // inside a RequestContext\n * ```\n *\n * A destination that is DATA rather than deployment — a URL a partner registered — is a FILTER, not\n * a different kind of client. Install `ContextBaseUrlFilter` on the one client that may be\n * re-pointed, and set the URL per call:\n * ```typescript\n * const partner = factory.createRpcClient(PartnerWebhookApi, new ClientConfig('partner-webhooks'), [\n * new ClientFilterDefinition(1000, new ContextBaseUrlFilter()),\n * ]);\n * ```\n * The SSRF guard arms itself the moment that filter re-points a request, and the contract's\n * `@AuthWebhook(name)` selects the app's bound `WebhookSignerCallback` to sign the exact bytes —\n * neither is something the app registers, orders, or can displace.\n *\n * Every client it builds shares one {@link NodeProxyClient} *shape* but never one instance: the\n * injected `Provider<NodeProxyClient>` hands out a fresh one per contract, which `createRpcClient`\n * then `init`s. Their collaborators (RequestContextHeaders, Secrets) come from the container, so\n * the whole dependency graph is visible in this package's design.html.\n *\n * Unlike @webpieces/http-client-browser this package is Node-only, so the factory IS the inversify\n * entry point and the magic context is read straight from the RequestContext. A call made outside\n * `RequestContext.run(...)` throws rather than silently dropping the trace.\n */\n@DocumentDesign()\n@provideFrameworkSingleton()\nexport class ClientHttpFactory {\n constructor(\n @inject(NODE_PROXY_CLIENT_PROVIDER) private readonly proxyClientProvider: Provider<NodeProxyClient>,\n ) {}\n\n /**\n * Create a type-safe RPC (HTTP) client for one API contract.\n *\n * @param apiPrototype - The API prototype class with @ApiPath/@Endpoint decorators\n * @param config - This client's state: its svcName, which is what `ClientRegistry` resolves\n * @param filters - This client's own OUTBOUND filters, each with the priority it runs at\n * (highest OUTERMOST). They wrap the send, so a filter may rewrite the URL, add or remove\n * headers, log, or replace `ClientRequest.body` — the exact bytes transmitted. What goes\n * here is APP behaviour: url rewriting, headers, logging, and `ContextBaseUrlFilter` when\n * this client's destination arrives per call.\n *\n * OPTIONAL, and omitting it is not a statement about security: the framework's own SSRF\n * guard and credential minter are installed on every client regardless, BENEATH anything\n * passed here, so there is nothing an app can decline by writing nothing.\n *\n * ONE SPELLING PER DECISION. It is a NON-EMPTY tuple, so `createRpcClient(Api, cfg, [])`\n * does not compile: \"this client has no app filters\" is said by omitting the argument, and\n * `[]` would be a second way to say the identical thing. That is the same device\n * {@link JwtRoles}'s `roles` uses, for the same reason the bad case is deleted by the\n * TYPE rather than left available and discouraged in a docstring. Pinned in\n * {@link CreateRpcClientCompileAssertions}.\n */\n createRpcClient<T extends object>(\n apiPrototype: ApiPrototype<T>,\n config: ClientConfig,\n filters?: ClientFilters,\n ): T {\n // Fresh instance per contract — NodeProxyClient is transient. init() binds it to this\n // contract + target; the collaborators already came from the container.\n const proxyClient = this.proxyClientProvider.get();\n proxyClient.init(apiPrototype, config, filters === undefined ? [] : [...filters]);\n return buildClientProxy(apiPrototype, proxyClient);\n }\n}\n"]}
1
+ {"version":3,"file":"ClientHttpFactory.js","sourceRoot":"","sources":["../../../../../packages/http/http-client-node/src/ClientHttpFactory.ts"],"names":[],"mappings":";;;;AAAA,yCAAmC;AACnC,oDAAsD;AACtD,0DAAqG;AAErG,kEAA+D;AAE/D,uDAAgF;AAEhF,iGAAiG;AACjG,6EAA6E;AAC7E,IAAA,oCAAqB,EAAC,4CAA0B,EAAE,iCAAe,CAAC,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAGI,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAE+B;IADzD,YACyD,mBAA8C;QAA9C,wBAAmB,GAAnB,mBAAmB,CAA2B;IACpG,CAAC;IAEJ;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,eAAe,CACX,YAA6B,EAC7B,MAAoB,EACpB,OAA2C;QAE3C,sFAAsF;QACtF,wEAAwE;QACxE,MAAM,WAAW,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,EAAE,CAAC;QACnD,WAAW,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;QAClF,OAAO,IAAA,mCAAgB,EAAC,YAAY,EAAE,WAAW,CAAC,CAAC;IACvD,CAAC;CACJ,CAAA;AAxCY,8CAAiB;4BAAjB,iBAAiB;IAF7B,IAAA,0BAAc,GAAE;IAChB,IAAA,wCAAyB,GAAE;IAGnB,mBAAA,IAAA,kBAAM,EAAC,4CAA0B,CAAC,CAAA;6CAAuC,uBAAQ;GAF7E,iBAAiB,CAwC7B","sourcesContent":["import { inject } from 'inversify';\nimport { DocumentDesign } from '@webpieces/core-util';\nimport { Provider, bindFrameworkProvider, provideFrameworkSingleton } from '@webpieces/core-context';\nimport type { ApiPrototype, ClientFilterDefinition } from '@webpieces/http-client-core';\nimport { buildClientProxy } from '@webpieces/http-client-core';\nimport { ClientConfig } from './ClientConfig';\nimport { NODE_PROXY_CLIENT_PROVIDER, NodeProxyClient } from './NodeProxyClient';\n\n// Teach the container how to hand out fresh NodeProxyClients. NodeProxyClient is bound TRANSIENT\n// (@provideFrameworkTransient), so each provider.get() constructs a new one.\nbindFrameworkProvider(NODE_PROXY_CLIENT_PROVIDER, NodeProxyClient);\n\n/**\n * ClientHttpFactory - builds type-safe HTTP clients from API prototypes carrying\n * @ApiPath/@Endpoint decorators. The SERVER-side factory.\n *\n * This is the client-side equivalent of ApiRoutingFactory:\n * - Server routing: ApiRoutingFactory reads decorators -> routes HTTP requests to controllers\n * - Server client: ClientHttpFactory reads decorators -> generates HTTP requests from method calls\n *\n * Inject it and ask for a typed client per contract:\n * ```typescript\n * // same project + region as this container; the URL is derived, you maintain nothing\n * const server2 = factory.createRpcClient(Server2Api, new ClientConfig('server2'));\n *\n * // to reach somewhere derivation cannot describe (other region/project, non-Cloud-Run, localhost),\n * // register it once at startup — the client still carries only the svcName:\n * // ClientRegistry.addUrlMapping('legacy', 'https://legacy.corp');\n * const legacy = factory.createRpcClient(LegacyApi, new ClientConfig('legacy'));\n *\n * const response = await server2.fetchValue(req); // inside a RequestContext\n * ```\n *\n * A destination that is DATA rather than deployment — a URL a partner registered — is a FILTER, not\n * a different kind of client. Install `ContextBaseUrlFilter` on the one client that may be\n * re-pointed, and set the URL per call:\n * ```typescript\n * const partner = factory.createRpcClient(PartnerWebhookApi, new ClientConfig('partner-webhooks'), [\n * new ClientFilterDefinition(1000, new ContextBaseUrlFilter()),\n * ]);\n * ```\n * The SSRF guard arms itself the moment that filter re-points a request, and the contract's\n * `@AuthWebhook(name)` selects the app's bound `WebhookSignerCallback` to sign the exact bytes —\n * neither is something the app registers, orders, or can displace.\n *\n * Every client it builds shares one {@link NodeProxyClient} *shape* but never one instance: the\n * injected `Provider<NodeProxyClient>` hands out a fresh one per contract, which `createRpcClient`\n * then `init`s. Their collaborators (RequestContextHeaders, Secrets) come from the container, so\n * the whole dependency graph is visible in this package's design.html.\n *\n * Unlike @webpieces/http-client-browser this package is Node-only, so the factory IS the inversify\n * entry point and the magic context is read straight from the RequestContext. A call made outside\n * `RequestContext.run(...)` throws rather than silently dropping the trace.\n */\n@DocumentDesign()\n@provideFrameworkSingleton()\nexport class ClientHttpFactory {\n constructor(\n @inject(NODE_PROXY_CLIENT_PROVIDER) private readonly proxyClientProvider: Provider<NodeProxyClient>,\n ) {}\n\n /**\n * Create a type-safe RPC (HTTP) client for one API contract.\n *\n * @param apiPrototype - The API prototype class with @ApiPath/@Endpoint decorators\n * @param config - This client's state: its svcName, which is what `ClientRegistry` resolves\n * @param filters - This client's own OUTBOUND filters, each with the priority it runs at\n * (highest OUTERMOST). They wrap the send, so a filter may rewrite the URL, add or remove\n * headers, log, or replace `ClientRequest.body` — the exact bytes transmitted. What goes\n * here is APP behaviour: url rewriting, headers, logging, and `ContextBaseUrlFilter` when\n * this client's destination arrives per call.\n *\n * OPTIONAL, and omitting it is not a statement about security: the framework's own SSRF\n * guard and credential minter are installed on every client regardless, BENEATH anything\n * passed here, so there is nothing an app can decline by writing nothing.\n *\n * A PLAIN OPTIONAL ARRAY, deliberately. Omitting it, passing `[]`, and passing a list you\n * built up conditionally all mean the same thing and all compile because the normal way\n * an app arrives at a filter list is to declare a `ClientFilterDefinition[]` and push to\n * it under `if`s, and the declared type of such a local can never be non-empty. A\n * non-empty tuple here would reject that ordinary code and force a cast at the call site.\n * `filters === undefined ? [] : [...filters]` below normalizes the two empty spellings to\n * one value before anything downstream sees them. Pinned in\n * {@link CreateRpcClientCompileAssertions}.\n */\n createRpcClient<T extends object>(\n apiPrototype: ApiPrototype<T>,\n config: ClientConfig,\n filters?: readonly ClientFilterDefinition[],\n ): T {\n // Fresh instance per contract — NodeProxyClient is transient. init() binds it to this\n // contract + target; the collaborators already came from the container.\n const proxyClient = this.proxyClientProvider.get();\n proxyClient.init(apiPrototype, config, filters === undefined ? [] : [...filters]);\n return buildClientProxy(apiPrototype, proxyClient);\n }\n}\n"]}
@@ -1,16 +1,19 @@
1
1
  /**
2
- * COMPILE-TIME assertions pinning `createRpcClient`'s filters argument to ONE spelling per decision.
2
+ * COMPILE-TIME assertions that `createRpcClient`'s filters argument is GENUINELY optional.
3
3
  *
4
- * A CLASS is one shape and cannot express "absent, or at least one" — so the argument is a NON-EMPTY
5
- * tuple, and the empty array that used to mean the same thing as omitting it is a COMPILE error. See
6
- * `.claude/review/backwards-compatibility.md` shim shape #1: the fix for two spellings is to make the
7
- * type unsatisfiable in the bad case, not to document a preference.
4
+ * The argument is `readonly ClientFilterDefinition[] | undefined`, so all three ways an app says
5
+ * "here are this client's filters" compile: omit it, pass `[]`, or pass a mutable
6
+ * `ClientFilterDefinition[]` that was declared empty and pushed to under `if`s. That last one is the
7
+ * whole reason this file exists it is how a real app builds a filter list once the list is not a
8
+ * hardcoded literal, and a non-empty tuple parameter rejects it, because the declared type of a
9
+ * conditionally-populated local cannot be non-empty. The cure would be a cast at every call site,
10
+ * which is worse than the case the tuple was protecting against.
8
11
  *
9
12
  * WHY THIS FILE AND NOT A SPEC. `tsconfig.lib.json` EXCLUDES `*.spec.ts`, and vitest strips types
10
- * with esbuild rather than checking them — so a `@ts-expect-error` in a spec is inert and the suite
11
- * passes whether or not the bad case still compiles. Here it is compiled by the build: if any line
12
- * below ever starts compiling, tsc fails with TS2578 ("Unused '@ts-expect-error' directive"). That
13
- * failure IS the test. Mirrors `core-util/src/http/AuthJwtCompileAssertions.ts`.
13
+ * with esbuild rather than checking them — so a type-level assertion in a spec is inert and the
14
+ * suite passes whether or not the signature still admits these calls. Here it is compiled by the
15
+ * build: if the signature is ever re-narrowed, tsc fails on the line below that stops compiling.
16
+ * That failure IS the test. Mirrors `core-util/src/http/AuthJwtCompileAssertions.ts`.
14
17
  *
15
18
  * Nothing here runs. The class is never constructed and never exported from the barrel.
16
19
  */
@@ -1,36 +1,50 @@
1
1
  "use strict";
2
2
  /**
3
- * COMPILE-TIME assertions pinning `createRpcClient`'s filters argument to ONE spelling per decision.
3
+ * COMPILE-TIME assertions that `createRpcClient`'s filters argument is GENUINELY optional.
4
4
  *
5
- * A CLASS is one shape and cannot express "absent, or at least one" — so the argument is a NON-EMPTY
6
- * tuple, and the empty array that used to mean the same thing as omitting it is a COMPILE error. See
7
- * `.claude/review/backwards-compatibility.md` shim shape #1: the fix for two spellings is to make the
8
- * type unsatisfiable in the bad case, not to document a preference.
5
+ * The argument is `readonly ClientFilterDefinition[] | undefined`, so all three ways an app says
6
+ * "here are this client's filters" compile: omit it, pass `[]`, or pass a mutable
7
+ * `ClientFilterDefinition[]` that was declared empty and pushed to under `if`s. That last one is the
8
+ * whole reason this file exists it is how a real app builds a filter list once the list is not a
9
+ * hardcoded literal, and a non-empty tuple parameter rejects it, because the declared type of a
10
+ * conditionally-populated local cannot be non-empty. The cure would be a cast at every call site,
11
+ * which is worse than the case the tuple was protecting against.
9
12
  *
10
13
  * WHY THIS FILE AND NOT A SPEC. `tsconfig.lib.json` EXCLUDES `*.spec.ts`, and vitest strips types
11
- * with esbuild rather than checking them — so a `@ts-expect-error` in a spec is inert and the suite
12
- * passes whether or not the bad case still compiles. Here it is compiled by the build: if any line
13
- * below ever starts compiling, tsc fails with TS2578 ("Unused '@ts-expect-error' directive"). That
14
- * failure IS the test. Mirrors `core-util/src/http/AuthJwtCompileAssertions.ts`.
14
+ * with esbuild rather than checking them — so a type-level assertion in a spec is inert and the
15
+ * suite passes whether or not the signature still admits these calls. Here it is compiled by the
16
+ * build: if the signature is ever re-narrowed, tsc fails on the line below that stops compiling.
17
+ * That failure IS the test. Mirrors `core-util/src/http/AuthJwtCompileAssertions.ts`.
15
18
  *
16
19
  * Nothing here runs. The class is never constructed and never exported from the barrel.
17
20
  */
18
21
  Object.defineProperty(exports, "__esModule", { value: true });
22
+ const core_util_1 = require("@webpieces/core-util");
19
23
  const http_client_core_1 = require("@webpieces/http-client-core");
20
24
  const ClientConfig_1 = require("./ClientConfig");
21
25
  const ContextBaseUrlFilter_1 = require("./ContextBaseUrlFilter");
26
+ /** A second app filter, so the conditional-build case below has two branches like a real one. */
27
+ class OutboundLogFilter extends core_util_1.Filter {
28
+ filter(request, next) {
29
+ return next.invoke(request);
30
+ }
31
+ }
22
32
  class CreateRpcClientCompileAssertions {
23
- /** No app filters the ONE spelling for it is omitting the argument. */
33
+ /** No app filters, said by omitting the argument. */
24
34
  noFilters() {
25
35
  factory.createRpcClient(someApi, new ClientConfig_1.ClientConfig('server2'));
26
36
  }
27
- /** One app filter. */
37
+ /** No app filters, said with an empty array — the same thing, normalized to the same value. */
38
+ emptyArray() {
39
+ factory.createRpcClient(someApi, new ClientConfig_1.ClientConfig('server2'), []);
40
+ }
41
+ /** One app filter. */
28
42
  oneFilter() {
29
43
  factory.createRpcClient(someApi, new ClientConfig_1.ClientConfig('partner-webhooks'), [
30
44
  new http_client_core_1.ClientFilterDefinition(1000, new ContextBaseUrlFilter_1.ContextBaseUrlFilter()),
31
45
  ]);
32
46
  }
33
- /** Several app filters. */
47
+ /** Several app filters. */
34
48
  severalFilters() {
35
49
  factory.createRpcClient(someApi, new ClientConfig_1.ClientConfig('partner-webhooks'), [
36
50
  new http_client_core_1.ClientFilterDefinition(1000, new ContextBaseUrlFilter_1.ContextBaseUrlFilter()),
@@ -38,12 +52,17 @@ class CreateRpcClientCompileAssertions {
38
52
  ]);
39
53
  }
40
54
  /**
41
- * `[]` is a SECOND way to say what omitting the argument already says. Deleting it by type is
42
- * what keeps "this client has no app filters" to one spelling.
55
+ * THE CASE THIS CHANGE EXISTS FOR: a MUTABLE `ClientFilterDefinition[]`, declared empty and
56
+ * pushed to conditionally. Its declared type is not, and cannot be, non-empty; a mutable array
57
+ * is assignable to the `readonly` parameter, so this compiles with no cast.
43
58
  */
44
- emptyArrayDoesNotCompile() {
45
- // @ts-expect-error - pass no third argument instead; [] is a second spelling of that
46
- factory.createRpcClient(someApi, new ClientConfig_1.ClientConfig('server2'), []);
59
+ conditionallyBuiltList() {
60
+ const filters = [];
61
+ if (perTenant)
62
+ filters.push(new http_client_core_1.ClientFilterDefinition(1000, new ContextBaseUrlFilter_1.ContextBaseUrlFilter()));
63
+ if (verbose)
64
+ filters.push(new http_client_core_1.ClientFilterDefinition(500, new OutboundLogFilter()));
65
+ factory.createRpcClient(someApi, new ClientConfig_1.ClientConfig('partner-webhooks'), filters);
47
66
  }
48
67
  }
49
68
  void CreateRpcClientCompileAssertions;
@@ -1 +1 @@
1
- {"version":3,"file":"CreateRpcClientCompileAssertions.js","sourceRoot":"","sources":["../../../../../packages/http/http-client-node/src/CreateRpcClientCompileAssertions.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;AAEH,kEAAqE;AACrE,iDAA8C;AAE9C,iEAA8D;AAM9D,MAAM,gCAAgC;IAClC,2EAA2E;IAC3E,SAAS;QACL,OAAO,CAAC,eAAe,CAAC,OAAO,EAAE,IAAI,2BAAY,CAAC,SAAS,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,wBAAwB;IACxB,SAAS;QACL,OAAO,CAAC,eAAe,CAAC,OAAO,EAAE,IAAI,2BAAY,CAAC,kBAAkB,CAAC,EAAE;YACnE,IAAI,yCAAsB,CAAC,IAAI,EAAE,IAAI,2CAAoB,EAAE,CAAC;SAC/D,CAAC,CAAC;IACP,CAAC;IAED,6BAA6B;IAC7B,cAAc;QACV,OAAO,CAAC,eAAe,CAAC,OAAO,EAAE,IAAI,2BAAY,CAAC,kBAAkB,CAAC,EAAE;YACnE,IAAI,yCAAsB,CAAC,IAAI,EAAE,IAAI,2CAAoB,EAAE,CAAC;YAC5D,IAAI,yCAAsB,CAAC,GAAG,EAAE,IAAI,2CAAoB,EAAE,CAAC;SAC9D,CAAC,CAAC;IACP,CAAC;IAED;;;OAGG;IACH,wBAAwB;QACpB,qFAAqF;QACrF,OAAO,CAAC,eAAe,CAAC,OAAO,EAAE,IAAI,2BAAY,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC;IACtE,CAAC;CACJ;AAED,KAAK,gCAAgC,CAAC","sourcesContent":["/**\n * COMPILE-TIME assertions pinning `createRpcClient`'s filters argument to ONE spelling per decision.\n *\n * A CLASS is one shape and cannot express \"absent, or at least one\" so the argument is a NON-EMPTY\n * tuple, and the empty array that used to mean the same thing as omitting it is a COMPILE error. See\n * `.claude/review/backwards-compatibility.md` shim shape #1: the fix for two spellings is to make the\n * type unsatisfiable in the bad case, not to document a preference.\n *\n * WHY THIS FILE AND NOT A SPEC. `tsconfig.lib.json` EXCLUDES `*.spec.ts`, and vitest strips types\n * with esbuild rather than checking them — so a `@ts-expect-error` in a spec is inert and the suite\n * passes whether or not the bad case still compiles. Here it is compiled by the build: if any line\n * below ever starts compiling, tsc fails with TS2578 (\"Unused '@ts-expect-error' directive\"). That\n * failure IS the test. Mirrors `core-util/src/http/AuthJwtCompileAssertions.ts`.\n *\n * Nothing here runs. The class is never constructed and never exported from the barrel.\n */\n\nimport { ClientFilterDefinition } from '@webpieces/http-client-core';\nimport { ClientConfig } from './ClientConfig';\nimport { ClientHttpFactory } from './ClientHttpFactory';\nimport { ContextBaseUrlFilter } from './ContextBaseUrlFilter';\n\n/** Stand-in for a real contract; only its TYPE is used, and only by tsc. */\ndeclare const someApi: Parameters<ClientHttpFactory['createRpcClient']>[0];\ndeclare const factory: ClientHttpFactory;\n\nclass CreateRpcClientCompileAssertions {\n /** No app filters — the ONE spelling for it is omitting the argument. */\n noFilters(): void {\n factory.createRpcClient(someApi, new ClientConfig('server2'));\n }\n\n /** One app filter. */\n oneFilter(): void {\n factory.createRpcClient(someApi, new ClientConfig('partner-webhooks'), [\n new ClientFilterDefinition(1000, new ContextBaseUrlFilter()),\n ]);\n }\n\n /** Several app filters. */\n severalFilters(): void {\n factory.createRpcClient(someApi, new ClientConfig('partner-webhooks'), [\n new ClientFilterDefinition(1000, new ContextBaseUrlFilter()),\n new ClientFilterDefinition(500, new ContextBaseUrlFilter()),\n ]);\n }\n\n /**\n * `[]` is a SECOND way to say what omitting the argument already says. Deleting it by type is\n * what keeps \"this client has no app filters\" to one spelling.\n */\n emptyArrayDoesNotCompile(): void {\n // @ts-expect-error - pass no third argument instead; [] is a second spelling of that\n factory.createRpcClient(someApi, new ClientConfig('server2'), []);\n }\n}\n\nvoid CreateRpcClientCompileAssertions;\n"]}
1
+ {"version":3,"file":"CreateRpcClientCompileAssertions.js","sourceRoot":"","sources":["../../../../../packages/http/http-client-node/src/CreateRpcClientCompileAssertions.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;GAkBG;;AAEH,oDAAuD;AACvD,kEAAoF;AACpF,iDAA8C;AAE9C,iEAA8D;AAQ9D,iGAAiG;AACjG,MAAM,iBAAkB,SAAQ,kBAA+B;IAClD,MAAM,CAAC,OAAsB,EAAE,IAAsC;QAC1E,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;CACJ;AAED,MAAM,gCAAgC;IAClC,qDAAqD;IACrD,SAAS;QACL,OAAO,CAAC,eAAe,CAAC,OAAO,EAAE,IAAI,2BAAY,CAAC,SAAS,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,+FAA+F;IAC/F,UAAU;QACN,OAAO,CAAC,eAAe,CAAC,OAAO,EAAE,IAAI,2BAAY,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC;IACtE,CAAC;IAED,sBAAsB;IACtB,SAAS;QACL,OAAO,CAAC,eAAe,CAAC,OAAO,EAAE,IAAI,2BAAY,CAAC,kBAAkB,CAAC,EAAE;YACnE,IAAI,yCAAsB,CAAC,IAAI,EAAE,IAAI,2CAAoB,EAAE,CAAC;SAC/D,CAAC,CAAC;IACP,CAAC;IAED,2BAA2B;IAC3B,cAAc;QACV,OAAO,CAAC,eAAe,CAAC,OAAO,EAAE,IAAI,2BAAY,CAAC,kBAAkB,CAAC,EAAE;YACnE,IAAI,yCAAsB,CAAC,IAAI,EAAE,IAAI,2CAAoB,EAAE,CAAC;YAC5D,IAAI,yCAAsB,CAAC,GAAG,EAAE,IAAI,2CAAoB,EAAE,CAAC;SAC9D,CAAC,CAAC;IACP,CAAC;IAED;;;;OAIG;IACH,sBAAsB;QAClB,MAAM,OAAO,GAA6B,EAAE,CAAC;QAC7C,IAAI,SAAS;YAAE,OAAO,CAAC,IAAI,CAAC,IAAI,yCAAsB,CAAC,IAAI,EAAE,IAAI,2CAAoB,EAAE,CAAC,CAAC,CAAC;QAC1F,IAAI,OAAO;YAAE,OAAO,CAAC,IAAI,CAAC,IAAI,yCAAsB,CAAC,GAAG,EAAE,IAAI,iBAAiB,EAAE,CAAC,CAAC,CAAC;QACpF,OAAO,CAAC,eAAe,CAAC,OAAO,EAAE,IAAI,2BAAY,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC,CAAC;IACpF,CAAC;CACJ;AAED,KAAK,gCAAgC,CAAC","sourcesContent":["/**\n * COMPILE-TIME assertions that `createRpcClient`'s filters argument is GENUINELY optional.\n *\n * The argument is `readonly ClientFilterDefinition[] | undefined`, so all three ways an app says\n * \"here are this client's filters\" compile: omit it, pass `[]`, or pass a mutable\n * `ClientFilterDefinition[]` that was declared empty and pushed to under `if`s. That last one is the\n * whole reason this file exists — it is how a real app builds a filter list once the list is not a\n * hardcoded literal, and a non-empty tuple parameter rejects it, because the declared type of a\n * conditionally-populated local cannot be non-empty. The cure would be a cast at every call site,\n * which is worse than the case the tuple was protecting against.\n *\n * WHY THIS FILE AND NOT A SPEC. `tsconfig.lib.json` EXCLUDES `*.spec.ts`, and vitest strips types\n * with esbuild rather than checking them — so a type-level assertion in a spec is inert and the\n * suite passes whether or not the signature still admits these calls. Here it is compiled by the\n * build: if the signature is ever re-narrowed, tsc fails on the line below that stops compiling.\n * That failure IS the test. Mirrors `core-util/src/http/AuthJwtCompileAssertions.ts`.\n *\n * Nothing here runs. The class is never constructed and never exported from the barrel.\n */\n\nimport { Filter, Service } from '@webpieces/core-util';\nimport { ClientFilterDefinition, ClientRequest } from '@webpieces/http-client-core';\nimport { ClientConfig } from './ClientConfig';\nimport { ClientHttpFactory } from './ClientHttpFactory';\nimport { ContextBaseUrlFilter } from './ContextBaseUrlFilter';\n\n/** Stand-in for a real contract; only its TYPE is used, and only by tsc. */\ndeclare const someApi: Parameters<ClientHttpFactory['createRpcClient']>[0];\ndeclare const factory: ClientHttpFactory;\ndeclare const perTenant: boolean;\ndeclare const verbose: boolean;\n\n/** A second app filter, so the conditional-build case below has two branches like a real one. */\nclass OutboundLogFilter extends Filter<ClientRequest, Response> {\n override filter(request: ClientRequest, next: Service<ClientRequest, Response>): Promise<Response> {\n return next.invoke(request);\n }\n}\n\nclass CreateRpcClientCompileAssertions {\n /** No app filters, said by omitting the argument. */\n noFilters(): void {\n factory.createRpcClient(someApi, new ClientConfig('server2'));\n }\n\n /** No app filters, said with an empty array — the same thing, normalized to the same value. */\n emptyArray(): void {\n factory.createRpcClient(someApi, new ClientConfig('server2'), []);\n }\n\n /** One app filter. */\n oneFilter(): void {\n factory.createRpcClient(someApi, new ClientConfig('partner-webhooks'), [\n new ClientFilterDefinition(1000, new ContextBaseUrlFilter()),\n ]);\n }\n\n /** Several app filters. */\n severalFilters(): void {\n factory.createRpcClient(someApi, new ClientConfig('partner-webhooks'), [\n new ClientFilterDefinition(1000, new ContextBaseUrlFilter()),\n new ClientFilterDefinition(500, new ContextBaseUrlFilter()),\n ]);\n }\n\n /**\n * THE CASE THIS CHANGE EXISTS FOR: a MUTABLE `ClientFilterDefinition[]`, declared empty and\n * pushed to conditionally. Its declared type is not, and cannot be, non-empty; a mutable array\n * is assignable to the `readonly` parameter, so this compiles with no cast.\n */\n conditionallyBuiltList(): void {\n const filters: ClientFilterDefinition[] = [];\n if (perTenant) filters.push(new ClientFilterDefinition(1000, new ContextBaseUrlFilter()));\n if (verbose) filters.push(new ClientFilterDefinition(500, new OutboundLogFilter()));\n factory.createRpcClient(someApi, new ClientConfig('partner-webhooks'), filters);\n }\n}\n\nvoid CreateRpcClientCompileAssertions;\n"]}
package/src/index.d.ts CHANGED
@@ -38,5 +38,5 @@ export { InternalAddressRules } from './InternalAddressRules';
38
38
  export { AddressResolver, DnsAddressResolver } from './AddressResolver';
39
39
  export { ProxyClient, ClientErrorTranslator, TranslatedFailure } from '@webpieces/http-client-core';
40
40
  export { ClientRequest, ClientFilterDefinition } from '@webpieces/http-client-core';
41
- export type { ClientFilter, ClientFilters } from '@webpieces/http-client-core';
41
+ export type { ClientFilter } from '@webpieces/http-client-core';
42
42
  export type { ApiPrototype } from '@webpieces/http-client-core';
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/http/http-client-node/src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;;;AAEH,yDAAwD;AAA/C,sHAAA,iBAAiB,OAAA;AAC1B,qDAAgF;AAAvE,kHAAA,eAAe,OAAA;AAAE,6HAAA,0BAA0B,OAAA;AACpD,+CAA8C;AAArC,4GAAA,YAAY,OAAA;AAErB,kGAAkG;AAClG,4DAA4D;AAC5D,+DAA8D;AAArD,4HAAA,oBAAoB,OAAA;AAC7B,2EAA0E;AAAjE,wIAAA,0BAA0B,OAAA;AAEnC,mGAAmG;AACnG,kGAAkG;AAClG,6DAA6D;AAC7D,2DAA2F;AAAlF,8HAAA,wBAAwB,OAAA;AAAE,+HAAA,yBAAyB,OAAA;AAE5D,mGAAmG;AACnG,mFAAmF;AACnF,iEAA0G;AAAjG,8HAAA,qBAAqB,OAAA;AAAE,wHAAA,eAAe,OAAA;AAAE,gIAAA,uBAAuB,OAAA;AAExE,qGAAqG;AACrG,+FAA+F;AAC/F,2CAA6D;AAApD,wGAAA,UAAU,OAAA;AAAE,+GAAA,iBAAiB,OAAA;AACtC,qDAAoD;AAA3C,kHAAA,eAAe,OAAA;AACxB,uDAAsD;AAA7C,oHAAA,gBAAgB,OAAA;AACzB,2DAA0D;AAAjD,wHAAA,kBAAkB,OAAA;AAC3B,+DAA8D;AAArD,4HAAA,oBAAoB,OAAA;AAC7B,qDAAwE;AAA/D,kHAAA,eAAe,OAAA;AAAE,qHAAA,kBAAkB,OAAA;AAE5C,uEAAuE;AACvE,gEAAoG;AAA3F,+GAAA,WAAW,OAAA;AAAE,yHAAA,qBAAqB,OAAA;AAAE,qHAAA,iBAAiB,OAAA;AAC9D,gEAAoF;AAA3E,iHAAA,aAAa,OAAA;AAAE,0HAAA,sBAAsB,OAAA","sourcesContent":["/**\n * @webpieces/http-client-node\n *\n * The SERVER-side HTTP client. Reads an API contract's decorators and generates type-safe HTTP\n * clients from it — the same contract the callee's controller implements.\n *\n * Node-only, so unlike @webpieces/http-client-browser it is fully inversify-wired and reads the\n * magic context straight out of the AsyncLocalStorage-backed RequestContext. There is no\n * ContextReader indirection, because a server has exactly one right answer, and a call made\n * OUTSIDE `RequestContext.run(...)` throws instead of silently dropping the trace.\n *\n * Usage:\n * ```typescript\n * import { ClientHttpFactory, ClientConfig } from '@webpieces/http-client-node';\n *\n * // inject the factory, then one client per contract\n * const server2 = factory.createRpcClient(Server2Api, new ClientConfig('server2'));\n * const response = await server2.fetchValue(req);\n *\n * // a client whose destination arrives per call: ONE filter, and nothing else changes\n * const partner = factory.createRpcClient(PartnerWebhookApi, new ClientConfig('partner-webhooks'), [\n * new ClientFilterDefinition(1000, new ContextBaseUrlFilter()),\n * ]);\n * ```\n */\n\nexport { ClientHttpFactory } from './ClientHttpFactory';\nexport { NodeProxyClient, NODE_PROXY_CLIENT_PROVIDER } from './NodeProxyClient';\nexport { ClientConfig } from './ClientConfig';\n\n// Install this on the ONE client whose destination is data. Installing it IS the opt-in; a client\n// without it ignores an ambient OVERRIDE_BASE_URL entirely.\nexport { ContextBaseUrlFilter } from './ContextBaseUrlFilter';\nexport { MissingRuntimeBaseUrlError } from './MissingRuntimeBaseUrlError';\n\n// The two ways outbound auth refuses to send: a binding a contract's auth mode requires is absent.\n// Typed, so a delivery worker tells 'we are misconfigured' from 'the partner registered something\n// hostile' (SsrfRefusedError) without matching message text.\nexport { MissingSharedSecretError, MissingWebhookSignerError } from './OutboundAuthErrors';\n\n// The OUTBOUND half of @AuthWebhook(name) — the mirror of http-routing's WebhookAuthCallback. Bind\n// one, or every outbound @AuthWebhook call throws rather than delivering unsigned.\nexport { WebhookSignerCallback, SignableRequest, WEBHOOK_SIGNER_CALLBACK } from './WebhookSignerCallback';\n\n// The SSRF policy a re-pointed URL is judged under, and the refusal it produces. Automatic, armed by\n// the ACT of re-pointing; the ONLY way to relax it is naming SsrfTestingPolicy at a call site.\nexport { SsrfPolicy, SsrfTestingPolicy } from './SsrfPolicy';\nexport { SsrfGuardFilter } from './SsrfGuardFilter';\nexport { SsrfRefusedError } from './SsrfRefusedError';\nexport { OutboundAuthFilter } from './OutboundAuthFilter';\nexport { InternalAddressRules } from './InternalAddressRules';\nexport { AddressResolver, DnsAddressResolver } from './AddressResolver';\n\n// The isomorphic engine, re-exported so a server app needs one import.\nexport { ProxyClient, ClientErrorTranslator, TranslatedFailure } from '@webpieces/http-client-core';\nexport { ClientRequest, ClientFilterDefinition } from '@webpieces/http-client-core';\nexport type { ClientFilter, ClientFilters } from '@webpieces/http-client-core';\nexport type { ApiPrototype } from '@webpieces/http-client-core';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/http/http-client-node/src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;;;AAEH,yDAAwD;AAA/C,sHAAA,iBAAiB,OAAA;AAC1B,qDAAgF;AAAvE,kHAAA,eAAe,OAAA;AAAE,6HAAA,0BAA0B,OAAA;AACpD,+CAA8C;AAArC,4GAAA,YAAY,OAAA;AAErB,kGAAkG;AAClG,4DAA4D;AAC5D,+DAA8D;AAArD,4HAAA,oBAAoB,OAAA;AAC7B,2EAA0E;AAAjE,wIAAA,0BAA0B,OAAA;AAEnC,mGAAmG;AACnG,kGAAkG;AAClG,6DAA6D;AAC7D,2DAA2F;AAAlF,8HAAA,wBAAwB,OAAA;AAAE,+HAAA,yBAAyB,OAAA;AAE5D,mGAAmG;AACnG,mFAAmF;AACnF,iEAA0G;AAAjG,8HAAA,qBAAqB,OAAA;AAAE,wHAAA,eAAe,OAAA;AAAE,gIAAA,uBAAuB,OAAA;AAExE,qGAAqG;AACrG,+FAA+F;AAC/F,2CAA6D;AAApD,wGAAA,UAAU,OAAA;AAAE,+GAAA,iBAAiB,OAAA;AACtC,qDAAoD;AAA3C,kHAAA,eAAe,OAAA;AACxB,uDAAsD;AAA7C,oHAAA,gBAAgB,OAAA;AACzB,2DAA0D;AAAjD,wHAAA,kBAAkB,OAAA;AAC3B,+DAA8D;AAArD,4HAAA,oBAAoB,OAAA;AAC7B,qDAAwE;AAA/D,kHAAA,eAAe,OAAA;AAAE,qHAAA,kBAAkB,OAAA;AAE5C,uEAAuE;AACvE,gEAAoG;AAA3F,+GAAA,WAAW,OAAA;AAAE,yHAAA,qBAAqB,OAAA;AAAE,qHAAA,iBAAiB,OAAA;AAC9D,gEAAoF;AAA3E,iHAAA,aAAa,OAAA;AAAE,0HAAA,sBAAsB,OAAA","sourcesContent":["/**\n * @webpieces/http-client-node\n *\n * The SERVER-side HTTP client. Reads an API contract's decorators and generates type-safe HTTP\n * clients from it — the same contract the callee's controller implements.\n *\n * Node-only, so unlike @webpieces/http-client-browser it is fully inversify-wired and reads the\n * magic context straight out of the AsyncLocalStorage-backed RequestContext. There is no\n * ContextReader indirection, because a server has exactly one right answer, and a call made\n * OUTSIDE `RequestContext.run(...)` throws instead of silently dropping the trace.\n *\n * Usage:\n * ```typescript\n * import { ClientHttpFactory, ClientConfig } from '@webpieces/http-client-node';\n *\n * // inject the factory, then one client per contract\n * const server2 = factory.createRpcClient(Server2Api, new ClientConfig('server2'));\n * const response = await server2.fetchValue(req);\n *\n * // a client whose destination arrives per call: ONE filter, and nothing else changes\n * const partner = factory.createRpcClient(PartnerWebhookApi, new ClientConfig('partner-webhooks'), [\n * new ClientFilterDefinition(1000, new ContextBaseUrlFilter()),\n * ]);\n * ```\n */\n\nexport { ClientHttpFactory } from './ClientHttpFactory';\nexport { NodeProxyClient, NODE_PROXY_CLIENT_PROVIDER } from './NodeProxyClient';\nexport { ClientConfig } from './ClientConfig';\n\n// Install this on the ONE client whose destination is data. Installing it IS the opt-in; a client\n// without it ignores an ambient OVERRIDE_BASE_URL entirely.\nexport { ContextBaseUrlFilter } from './ContextBaseUrlFilter';\nexport { MissingRuntimeBaseUrlError } from './MissingRuntimeBaseUrlError';\n\n// The two ways outbound auth refuses to send: a binding a contract's auth mode requires is absent.\n// Typed, so a delivery worker tells 'we are misconfigured' from 'the partner registered something\n// hostile' (SsrfRefusedError) without matching message text.\nexport { MissingSharedSecretError, MissingWebhookSignerError } from './OutboundAuthErrors';\n\n// The OUTBOUND half of @AuthWebhook(name) — the mirror of http-routing's WebhookAuthCallback. Bind\n// one, or every outbound @AuthWebhook call throws rather than delivering unsigned.\nexport { WebhookSignerCallback, SignableRequest, WEBHOOK_SIGNER_CALLBACK } from './WebhookSignerCallback';\n\n// The SSRF policy a re-pointed URL is judged under, and the refusal it produces. Automatic, armed by\n// the ACT of re-pointing; the ONLY way to relax it is naming SsrfTestingPolicy at a call site.\nexport { SsrfPolicy, SsrfTestingPolicy } from './SsrfPolicy';\nexport { SsrfGuardFilter } from './SsrfGuardFilter';\nexport { SsrfRefusedError } from './SsrfRefusedError';\nexport { OutboundAuthFilter } from './OutboundAuthFilter';\nexport { InternalAddressRules } from './InternalAddressRules';\nexport { AddressResolver, DnsAddressResolver } from './AddressResolver';\n\n// The isomorphic engine, re-exported so a server app needs one import.\nexport { ProxyClient, ClientErrorTranslator, TranslatedFailure } from '@webpieces/http-client-core';\nexport { ClientRequest, ClientFilterDefinition } from '@webpieces/http-client-core';\nexport type { ClientFilter } from '@webpieces/http-client-core';\nexport type { ApiPrototype } from '@webpieces/http-client-core';\n"]}