@homeflare/distilled-unifi-network 0.2.0
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/LICENSE +201 -0
- package/README.md +125 -0
- package/dist/credentials.d.ts +24 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +78 -0
- package/dist/credentials.js.map +1 -0
- package/dist/errors.d.ts +74 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +49 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol.d.ts +18 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +59 -0
- package/dist/protocol.js.map +1 -0
- package/dist/retry.d.ts +57 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +50 -0
- package/dist/retry.js.map +1 -0
- package/dist/services/access_control_acl_rules.d.ts +222 -0
- package/dist/services/access_control_acl_rules.d.ts.map +1 -0
- package/dist/services/access_control_acl_rules.js +225 -0
- package/dist/services/access_control_acl_rules.js.map +1 -0
- package/dist/services/application_info.d.ts +15 -0
- package/dist/services/application_info.d.ts.map +1 -0
- package/dist/services/application_info.js +22 -0
- package/dist/services/application_info.js.map +1 -0
- package/dist/services/clients.d.ts +108 -0
- package/dist/services/clients.d.ts.map +1 -0
- package/dist/services/clients.js +122 -0
- package/dist/services/clients.js.map +1 -0
- package/dist/services/dns_policies.d.ts +143 -0
- package/dist/services/dns_policies.d.ts.map +1 -0
- package/dist/services/dns_policies.js +171 -0
- package/dist/services/dns_policies.js.map +1 -0
- package/dist/services/firewall.d.ts +473 -0
- package/dist/services/firewall.d.ts.map +1 -0
- package/dist/services/firewall.js +521 -0
- package/dist/services/firewall.js.map +1 -0
- package/dist/services/hotspot.d.ts +107 -0
- package/dist/services/hotspot.d.ts.map +1 -0
- package/dist/services/hotspot.js +145 -0
- package/dist/services/hotspot.js.map +1 -0
- package/dist/services/index.d.ts +14 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +15 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/networks.d.ts +251 -0
- package/dist/services/networks.d.ts.map +1 -0
- package/dist/services/networks.js +256 -0
- package/dist/services/networks.js.map +1 -0
- package/dist/services/sites.d.ts +31 -0
- package/dist/services/sites.d.ts.map +1 -0
- package/dist/services/sites.js +38 -0
- package/dist/services/sites.js.map +1 -0
- package/dist/services/supporting_resources.d.ts +238 -0
- package/dist/services/supporting_resources.d.ts.map +1 -0
- package/dist/services/supporting_resources.js +298 -0
- package/dist/services/supporting_resources.js.map +1 -0
- package/dist/services/switching.d.ts +168 -0
- package/dist/services/switching.d.ts.map +1 -0
- package/dist/services/switching.js +226 -0
- package/dist/services/switching.js.map +1 -0
- package/dist/services/traffic_matching_lists.d.ts +75 -0
- package/dist/services/traffic_matching_lists.d.ts.map +1 -0
- package/dist/services/traffic_matching_lists.js +126 -0
- package/dist/services/traffic_matching_lists.js.map +1 -0
- package/dist/services/unifi_devices.d.ts +280 -0
- package/dist/services/unifi_devices.d.ts.map +1 -0
- package/dist/services/unifi_devices.js +338 -0
- package/dist/services/unifi_devices.js.map +1 -0
- package/dist/services/wifi_broadcasts.d.ts +378 -0
- package/dist/services/wifi_broadcasts.d.ts.map +1 -0
- package/dist/services/wifi_broadcasts.js +396 -0
- package/dist/services/wifi_broadcasts.js.map +1 -0
- package/dist/traits.d.ts +11 -0
- package/dist/traits.d.ts.map +1 -0
- package/dist/traits.js +12 -0
- package/dist/traits.js.map +1 -0
- package/package.json +75 -0
- package/src/credentials.ts +112 -0
- package/src/errors.ts +103 -0
- package/src/index.ts +36 -0
- package/src/protocol.ts +86 -0
- package/src/retry.ts +83 -0
- package/src/services/access_control_acl_rules.ts +537 -0
- package/src/services/application_info.ts +44 -0
- package/src/services/clients.ts +272 -0
- package/src/services/dns_policies.ts +363 -0
- package/src/services/firewall.ts +1492 -0
- package/src/services/hotspot.ts +305 -0
- package/src/services/index.ts +14 -0
- package/src/services/networks.ts +613 -0
- package/src/services/sites.ts +81 -0
- package/src/services/supporting_resources.ts +650 -0
- package/src/services/switching.ts +496 -0
- package/src/services/traffic_matching_lists.ts +248 -0
- package/src/services/unifi_devices.ts +795 -0
- package/src/services/wifi_broadcasts.ts +992 -0
- package/src/traits.ts +45 -0
package/src/errors.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UniFi Network-specific error types.
|
|
3
|
+
*
|
|
4
|
+
* ⛔ THE SPEC DOCUMENTS ZERO ERROR RESPONSES. Every one of the 73 operations
|
|
5
|
+
* in `network_v10.4.57_openapi.json` declares only its success status (65
|
|
6
|
+
* carry `200`, 8 carry `201`) — there is no per-operation 4xx/5xx, and
|
|
7
|
+
* unlike Hetzner's spec there isn't even a blanket `4xx`/`5xx` wildcard to
|
|
8
|
+
* signal "any of these can happen." So there is nothing for the OpenAPI→
|
|
9
|
+
* Smithy converter to type per operation (see `scripts/convert.ts`'s
|
|
10
|
+
* `statusToErrorClass: {}`), and every generated operation's error channel
|
|
11
|
+
* is the SAME open set below, dispatched purely by HTTP status at runtime
|
|
12
|
+
* (`src/protocol.ts`, `@distilled.cloud/core/errors#HTTP_STATUS_MAP`) —
|
|
13
|
+
* exactly the situation core's shared map exists for, just with less
|
|
14
|
+
* upstream signal than usual to say which statuses are actually reachable.
|
|
15
|
+
*
|
|
16
|
+
* Re-exports the common HTTP errors from core (nothing UniFi-specific to
|
|
17
|
+
* add to the status→class mapping — no documented error envelope shape,
|
|
18
|
+
* either, so `UnknownUnifiNetworkError` below carries the raw body rather
|
|
19
|
+
* than any parsed `code`/`message` pair) plus the unknown-error and
|
|
20
|
+
* parse-error wrappers every package needs.
|
|
21
|
+
*
|
|
22
|
+
* Known unknowns — confirm against a live console before hardening on them:
|
|
23
|
+
* - Exact body shape of a failure (no operation's `responses` gives one).
|
|
24
|
+
* - Whether 429 carries `Retry-After` (assume not; see `src/retry.ts`).
|
|
25
|
+
* - Whether a bad/missing `X-API-KEY` answers 401 or 403 (both are wired
|
|
26
|
+
* through `HTTP_STATUS_MAP`; only one will actually fire).
|
|
27
|
+
*/
|
|
28
|
+
export {
|
|
29
|
+
BadGateway,
|
|
30
|
+
BadRequest,
|
|
31
|
+
Conflict,
|
|
32
|
+
ConfigError,
|
|
33
|
+
Forbidden,
|
|
34
|
+
GatewayTimeout,
|
|
35
|
+
InternalServerError,
|
|
36
|
+
NotFound,
|
|
37
|
+
ServiceUnavailable,
|
|
38
|
+
TooManyRequests,
|
|
39
|
+
Unauthorized,
|
|
40
|
+
UnprocessableEntity,
|
|
41
|
+
HTTP_STATUS_MAP,
|
|
42
|
+
DEFAULT_ERRORS,
|
|
43
|
+
API_ERRORS,
|
|
44
|
+
} from "@distilled.cloud/core/errors";
|
|
45
|
+
import type {
|
|
46
|
+
BadRequest as CoreBadRequest,
|
|
47
|
+
Conflict as CoreConflict,
|
|
48
|
+
DefaultErrors as CoreDefaultErrors,
|
|
49
|
+
Forbidden as CoreForbidden,
|
|
50
|
+
NotFound as CoreNotFound,
|
|
51
|
+
UnprocessableEntity as CoreUnprocessableEntity,
|
|
52
|
+
} from "@distilled.cloud/core/errors";
|
|
53
|
+
|
|
54
|
+
import * as Schema from "effect/Schema";
|
|
55
|
+
import * as Category from "@distilled.cloud/core/category";
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Unknown UniFi Network error — returned when a failed response's HTTP
|
|
59
|
+
* status has no mapped error class, OR (given the spec's total silence on
|
|
60
|
+
* error shapes) as the fallback for any status this SDK has not been told
|
|
61
|
+
* about by a real failure yet. Carries the raw body for later cataloging.
|
|
62
|
+
*/
|
|
63
|
+
export class UnknownUnifiNetworkError extends Schema.TaggedError<UnknownUnifiNetworkError>()(
|
|
64
|
+
"UnknownUnifiNetworkError",
|
|
65
|
+
{
|
|
66
|
+
code: Schema.optional(Schema.String),
|
|
67
|
+
message: Schema.optional(Schema.String),
|
|
68
|
+
body: Schema.Unknown,
|
|
69
|
+
},
|
|
70
|
+
).pipe(Category.withServerError) {}
|
|
71
|
+
|
|
72
|
+
/** Schema parse error wrapper. */
|
|
73
|
+
export class UnifiNetworkParseError extends Schema.TaggedError<UnifiNetworkParseError>()(
|
|
74
|
+
"UnifiNetworkParseError",
|
|
75
|
+
{
|
|
76
|
+
body: Schema.Unknown,
|
|
77
|
+
cause: Schema.Unknown,
|
|
78
|
+
},
|
|
79
|
+
).pipe(Category.withParseError) {}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Errors any UniFi Network operation may surface in addition to the shared
|
|
83
|
+
* HTTP status errors.
|
|
84
|
+
*/
|
|
85
|
+
export type ClientErrors = UnknownUnifiNetworkError | UnifiNetworkParseError;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Default UniFi Network operation errors.
|
|
89
|
+
*
|
|
90
|
+
* EVERY operation carries the whole set — the spec types no failure at all,
|
|
91
|
+
* per-operation or wildcard, so the error channel says a `404` (site or
|
|
92
|
+
* object not found), `400` (a malformed whole-object PUT — see the
|
|
93
|
+
* package README) or `409` is possible on any call rather than pretending
|
|
94
|
+
* only the statuses core marks "default" (401/429/5xx) can happen.
|
|
95
|
+
*/
|
|
96
|
+
export type DefaultErrors =
|
|
97
|
+
| CoreDefaultErrors
|
|
98
|
+
| CoreBadRequest
|
|
99
|
+
| CoreForbidden
|
|
100
|
+
| CoreNotFound
|
|
101
|
+
| CoreConflict
|
|
102
|
+
| CoreUnprocessableEntity
|
|
103
|
+
| ClientErrors;
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @distilled.cloud/unifi-network — UniFi Network Integration API SDK for
|
|
3
|
+
* Effect.
|
|
4
|
+
*
|
|
5
|
+
* `./services` is generated by `scripts/generate.ts` from the Smithy models
|
|
6
|
+
* in `.generated-specs` (written by `scripts/convert.ts` from the OpenAPI
|
|
7
|
+
* document at `specs/spec-mirror-unifi-network/specs/openapi.json`).
|
|
8
|
+
* Everything else in this folder is hand-written.
|
|
9
|
+
*
|
|
10
|
+
* One module per UniFi Network API tag (Sites, UniFi Devices, Clients,
|
|
11
|
+
* Networks, WiFi Broadcasts, Hotspot, Firewall, Access Control, Switching,
|
|
12
|
+
* DNS Policies, Traffic Matching Lists, Supporting Resources, Application
|
|
13
|
+
* Info) — the same split the API reference uses.
|
|
14
|
+
*
|
|
15
|
+
* ⛔ READ THE PACKAGE README before writing a Resource against this SDK: it
|
|
16
|
+
* documents traps this SDK does NOT paper over on purpose (whole-object PUT
|
|
17
|
+
* semantics, ordering endpoints, adopt-only objects, hardware-affecting
|
|
18
|
+
* writes) — this package is the API walk-down, not a provider.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* import * as UnifiNetwork from "@distilled.cloud/unifi-network";
|
|
23
|
+
*
|
|
24
|
+
* const { data: sites } = yield* UnifiNetwork.Services.sites.getSiteOverviewPage({});
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export * from "./credentials.ts";
|
|
28
|
+
export * from "./errors.ts";
|
|
29
|
+
export * as T from "./traits.ts";
|
|
30
|
+
export {
|
|
31
|
+
UnifiNetworkProtocol,
|
|
32
|
+
type UnifiNetworkOpError,
|
|
33
|
+
type UnifiNetworkOpContext,
|
|
34
|
+
} from "./protocol.ts";
|
|
35
|
+
export * as Retry from "./retry.ts";
|
|
36
|
+
export * as Services from "./services/index.ts";
|
package/src/protocol.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UnifiNetworkProtocol — the shared header-auth REST protocol instantiated
|
|
3
|
+
* for the UniFi Network Integration API.
|
|
4
|
+
*
|
|
5
|
+
* The spec's `info.description` is empty and its `components` carries no
|
|
6
|
+
* `securitySchemes` — this package cannot generate its auth from the
|
|
7
|
+
* document, unlike almost every other OpenAPI-sourced package here. The
|
|
8
|
+
* `X-API-KEY` header is sourced from Ubiquiti's own Integration API guide;
|
|
9
|
+
* see the warning in `src/credentials.ts`.
|
|
10
|
+
*
|
|
11
|
+
* Response envelope: list endpoints return `{ count, data, limit, offset,
|
|
12
|
+
* totalCount }` (offset pagination — see `scripts/convert.ts` for why no
|
|
13
|
+
* `smithy.api#paginated` trait is stamped yet); single-resource endpoints
|
|
14
|
+
* return the object directly; mutations return the created/updated object
|
|
15
|
+
* (`200`/`201`), never `204`.
|
|
16
|
+
*
|
|
17
|
+
* FAILURE ENVELOPE IS UNKNOWN: no operation in the spec documents an error
|
|
18
|
+
* response, so there is no field to read a machine-readable code or message
|
|
19
|
+
* from (`errorEnvelope` below always returns undefined, meaning every
|
|
20
|
+
* failure falls through to the protocol's raw-text / `HTTP <status>`
|
|
21
|
+
* default and `unknownError`). Replace this the first time a real console
|
|
22
|
+
* failure is captured and its body shape is known.
|
|
23
|
+
*/
|
|
24
|
+
import * as Effect from "effect/Effect";
|
|
25
|
+
import type * as Layer from "effect/Layer";
|
|
26
|
+
import * as Redacted from "effect/Redacted";
|
|
27
|
+
import type * as HttpClient from "effect/unstable/http/HttpClient";
|
|
28
|
+
import type * as HttpClientError from "effect/unstable/http/HttpClientError";
|
|
29
|
+
import type * as API from "@distilled.cloud/core/api";
|
|
30
|
+
import type { ConfigError } from "@distilled.cloud/core/errors";
|
|
31
|
+
import {
|
|
32
|
+
makeRestProtocol,
|
|
33
|
+
type RestErrorEnvelope,
|
|
34
|
+
} from "@distilled.cloud/core/protocol-rest";
|
|
35
|
+
import { Credentials, type Config } from "./credentials.ts";
|
|
36
|
+
import { UnknownUnifiNetworkError, type DefaultErrors } from "./errors.ts";
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Error channel shared by every generated UniFi Network operation. Generated
|
|
40
|
+
* service files annotate operations with `API.OperationMethod<I, O,
|
|
41
|
+
* UnifiNetworkOpError, UnifiNetworkOpContext>` explicitly so the compiler
|
|
42
|
+
* never infers these back out of the schema generics.
|
|
43
|
+
*/
|
|
44
|
+
export type UnifiNetworkOpError =
|
|
45
|
+
| DefaultErrors
|
|
46
|
+
| ConfigError
|
|
47
|
+
| HttpClientError.HttpClientError;
|
|
48
|
+
|
|
49
|
+
/** Context (requirements) shared by every generated UniFi Network operation. */
|
|
50
|
+
export type UnifiNetworkOpContext = Credentials | HttpClient.HttpClient;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* No documented failure envelope to parse (see module docs) — every failure
|
|
54
|
+
* falls through to the protocol's status-derived default and
|
|
55
|
+
* {@link UnknownUnifiNetworkError}.
|
|
56
|
+
*/
|
|
57
|
+
const errorEnvelope = (_body: unknown): RestErrorEnvelope | undefined =>
|
|
58
|
+
undefined;
|
|
59
|
+
|
|
60
|
+
export const UnifiNetworkProtocol: Layer.Layer<API.Protocol> =
|
|
61
|
+
makeRestProtocol<Config>({
|
|
62
|
+
// Resolved on the CALLING fiber per request (the layer is memoized per
|
|
63
|
+
// process); the Credentials service holds an effect, so a key rotated
|
|
64
|
+
// between calls is picked up without rebuilding the layer.
|
|
65
|
+
credentials: Effect.gen(function* () {
|
|
66
|
+
const resolve = yield* Credentials;
|
|
67
|
+
return yield* resolve;
|
|
68
|
+
}),
|
|
69
|
+
baseUrl: (creds) => creds.apiBaseUrl,
|
|
70
|
+
headers: (creds) => ({
|
|
71
|
+
"X-API-KEY": Redacted.value(creds.apiKey),
|
|
72
|
+
Accept: "application/json",
|
|
73
|
+
}),
|
|
74
|
+
errorEnvelope,
|
|
75
|
+
unknownError: ({ code, message, body }) =>
|
|
76
|
+
new UnknownUnifiNetworkError({
|
|
77
|
+
code:
|
|
78
|
+
typeof code === "string"
|
|
79
|
+
? code
|
|
80
|
+
: code !== undefined
|
|
81
|
+
? String(code)
|
|
82
|
+
: undefined,
|
|
83
|
+
message,
|
|
84
|
+
body,
|
|
85
|
+
}),
|
|
86
|
+
});
|
package/src/retry.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UniFi Network retry surface — a veneer over `@distilled.cloud/core/retry`.
|
|
3
|
+
*
|
|
4
|
+
* The `Retry` service tag is threaded into every generated operation via
|
|
5
|
+
* `API.make({ retry: Retry })`, so a caller-installed policy applies to all
|
|
6
|
+
* UniFi Network calls below it and core's `makeDefault` is the fallback when
|
|
7
|
+
* none is provided.
|
|
8
|
+
*
|
|
9
|
+
* No operation in the spec documents a 429 response (see `src/errors.ts`),
|
|
10
|
+
* so whether a console rate-limits at all — and whether it sends
|
|
11
|
+
* `Retry-After` — is unconfirmed. `TooManyRequests` is wired through core's
|
|
12
|
+
* shared status map regardless (a console-side reverse proxy or the cloud
|
|
13
|
+
* connector could still emit one), and the default policy's capped backoff
|
|
14
|
+
* applies when no server hint is present.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* import * as UnifiNetwork from "@distilled.cloud/unifi-network";
|
|
19
|
+
*
|
|
20
|
+
* myEffect.pipe(UnifiNetwork.Retry.transient);
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
import * as Context from "effect/Context";
|
|
24
|
+
import * as Effect from "effect/Effect";
|
|
25
|
+
import * as Layer from "effect/Layer";
|
|
26
|
+
import * as Retries from "@distilled.cloud/core/retry";
|
|
27
|
+
|
|
28
|
+
export type Options = Retries.Options;
|
|
29
|
+
export type Factory = Retries.Factory;
|
|
30
|
+
export type Policy = Retries.Policy;
|
|
31
|
+
|
|
32
|
+
/** Context tag for configuring retry behavior of UniFi Network API calls. */
|
|
33
|
+
export class Retry extends Context.Service<Retry, Policy>()(
|
|
34
|
+
"UnifiNetworkRetry",
|
|
35
|
+
) {}
|
|
36
|
+
|
|
37
|
+
/** Provides a custom retry policy to every UniFi Network API call below it. */
|
|
38
|
+
export const policy: {
|
|
39
|
+
(
|
|
40
|
+
options: Options,
|
|
41
|
+
): <A, E, R>(
|
|
42
|
+
effect: Effect.Effect<A, E, R>,
|
|
43
|
+
) => Effect.Effect<A, E, Exclude<R, Retry>>;
|
|
44
|
+
(
|
|
45
|
+
factory: Factory,
|
|
46
|
+
): <A, E, R>(
|
|
47
|
+
effect: Effect.Effect<A, E, R>,
|
|
48
|
+
) => Effect.Effect<A, E, Exclude<R, Retry>>;
|
|
49
|
+
} = (optionsOrFactory: Options | Factory) =>
|
|
50
|
+
Effect.provide(Layer.succeed(Retry, optionsOrFactory));
|
|
51
|
+
|
|
52
|
+
/** Disables all automatic retries. */
|
|
53
|
+
export const none: <A, E, R>(
|
|
54
|
+
effect: Effect.Effect<A, E, R>,
|
|
55
|
+
) => Effect.Effect<A, E, Exclude<R, Retry>> = Effect.provide(
|
|
56
|
+
Layer.succeed(Retry, { while: () => false }),
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The default retry policy (core's): transient/throttling/retryable errors,
|
|
61
|
+
* capped exponential backoff with jitter, server `retryAfter` hints honored
|
|
62
|
+
* with precedence.
|
|
63
|
+
*/
|
|
64
|
+
export const makeDefault: Factory = Retries.makeDefault;
|
|
65
|
+
|
|
66
|
+
export const jittered = Retries.jittered;
|
|
67
|
+
export const capped = Retries.capped;
|
|
68
|
+
|
|
69
|
+
/** Retry options that retry all throttling errors indefinitely. */
|
|
70
|
+
export const throttlingOptions: Options = Retries.throttlingOptions;
|
|
71
|
+
|
|
72
|
+
/** Retries all throttling errors indefinitely (honoring server hints). */
|
|
73
|
+
export const throttling: <A, E, R>(
|
|
74
|
+
effect: Effect.Effect<A, E, R>,
|
|
75
|
+
) => Effect.Effect<A, E, Exclude<R, Retry>> = policy(Retries.throttlingFactory);
|
|
76
|
+
|
|
77
|
+
/** Retry options that retry all transient errors indefinitely. */
|
|
78
|
+
export const transientOptions: Options = Retries.transientOptions;
|
|
79
|
+
|
|
80
|
+
/** Retries all transient errors indefinitely (honoring server hints). */
|
|
81
|
+
export const transient: <A, E, R>(
|
|
82
|
+
effect: Effect.Effect<A, E, R>,
|
|
83
|
+
) => Effect.Effect<A, E, Exclude<R, Retry>> = policy(Retries.transientFactory);
|