@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.
Files changed (103) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +125 -0
  3. package/dist/credentials.d.ts +24 -0
  4. package/dist/credentials.d.ts.map +1 -0
  5. package/dist/credentials.js +78 -0
  6. package/dist/credentials.js.map +1 -0
  7. package/dist/errors.d.ts +74 -0
  8. package/dist/errors.d.ts.map +1 -0
  9. package/dist/errors.js +49 -0
  10. package/dist/errors.js.map +1 -0
  11. package/dist/index.d.ts +33 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +33 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/protocol.d.ts +18 -0
  16. package/dist/protocol.d.ts.map +1 -0
  17. package/dist/protocol.js +59 -0
  18. package/dist/protocol.js.map +1 -0
  19. package/dist/retry.d.ts +57 -0
  20. package/dist/retry.d.ts.map +1 -0
  21. package/dist/retry.js +50 -0
  22. package/dist/retry.js.map +1 -0
  23. package/dist/services/access_control_acl_rules.d.ts +222 -0
  24. package/dist/services/access_control_acl_rules.d.ts.map +1 -0
  25. package/dist/services/access_control_acl_rules.js +225 -0
  26. package/dist/services/access_control_acl_rules.js.map +1 -0
  27. package/dist/services/application_info.d.ts +15 -0
  28. package/dist/services/application_info.d.ts.map +1 -0
  29. package/dist/services/application_info.js +22 -0
  30. package/dist/services/application_info.js.map +1 -0
  31. package/dist/services/clients.d.ts +108 -0
  32. package/dist/services/clients.d.ts.map +1 -0
  33. package/dist/services/clients.js +122 -0
  34. package/dist/services/clients.js.map +1 -0
  35. package/dist/services/dns_policies.d.ts +143 -0
  36. package/dist/services/dns_policies.d.ts.map +1 -0
  37. package/dist/services/dns_policies.js +171 -0
  38. package/dist/services/dns_policies.js.map +1 -0
  39. package/dist/services/firewall.d.ts +473 -0
  40. package/dist/services/firewall.d.ts.map +1 -0
  41. package/dist/services/firewall.js +521 -0
  42. package/dist/services/firewall.js.map +1 -0
  43. package/dist/services/hotspot.d.ts +107 -0
  44. package/dist/services/hotspot.d.ts.map +1 -0
  45. package/dist/services/hotspot.js +145 -0
  46. package/dist/services/hotspot.js.map +1 -0
  47. package/dist/services/index.d.ts +14 -0
  48. package/dist/services/index.d.ts.map +1 -0
  49. package/dist/services/index.js +15 -0
  50. package/dist/services/index.js.map +1 -0
  51. package/dist/services/networks.d.ts +251 -0
  52. package/dist/services/networks.d.ts.map +1 -0
  53. package/dist/services/networks.js +256 -0
  54. package/dist/services/networks.js.map +1 -0
  55. package/dist/services/sites.d.ts +31 -0
  56. package/dist/services/sites.d.ts.map +1 -0
  57. package/dist/services/sites.js +38 -0
  58. package/dist/services/sites.js.map +1 -0
  59. package/dist/services/supporting_resources.d.ts +238 -0
  60. package/dist/services/supporting_resources.d.ts.map +1 -0
  61. package/dist/services/supporting_resources.js +298 -0
  62. package/dist/services/supporting_resources.js.map +1 -0
  63. package/dist/services/switching.d.ts +168 -0
  64. package/dist/services/switching.d.ts.map +1 -0
  65. package/dist/services/switching.js +226 -0
  66. package/dist/services/switching.js.map +1 -0
  67. package/dist/services/traffic_matching_lists.d.ts +75 -0
  68. package/dist/services/traffic_matching_lists.d.ts.map +1 -0
  69. package/dist/services/traffic_matching_lists.js +126 -0
  70. package/dist/services/traffic_matching_lists.js.map +1 -0
  71. package/dist/services/unifi_devices.d.ts +280 -0
  72. package/dist/services/unifi_devices.d.ts.map +1 -0
  73. package/dist/services/unifi_devices.js +338 -0
  74. package/dist/services/unifi_devices.js.map +1 -0
  75. package/dist/services/wifi_broadcasts.d.ts +378 -0
  76. package/dist/services/wifi_broadcasts.d.ts.map +1 -0
  77. package/dist/services/wifi_broadcasts.js +396 -0
  78. package/dist/services/wifi_broadcasts.js.map +1 -0
  79. package/dist/traits.d.ts +11 -0
  80. package/dist/traits.d.ts.map +1 -0
  81. package/dist/traits.js +12 -0
  82. package/dist/traits.js.map +1 -0
  83. package/package.json +75 -0
  84. package/src/credentials.ts +112 -0
  85. package/src/errors.ts +103 -0
  86. package/src/index.ts +36 -0
  87. package/src/protocol.ts +86 -0
  88. package/src/retry.ts +83 -0
  89. package/src/services/access_control_acl_rules.ts +537 -0
  90. package/src/services/application_info.ts +44 -0
  91. package/src/services/clients.ts +272 -0
  92. package/src/services/dns_policies.ts +363 -0
  93. package/src/services/firewall.ts +1492 -0
  94. package/src/services/hotspot.ts +305 -0
  95. package/src/services/index.ts +14 -0
  96. package/src/services/networks.ts +613 -0
  97. package/src/services/sites.ts +81 -0
  98. package/src/services/supporting_resources.ts +650 -0
  99. package/src/services/switching.ts +496 -0
  100. package/src/services/traffic_matching_lists.ts +248 -0
  101. package/src/services/unifi_devices.ts +795 -0
  102. package/src/services/wifi_broadcasts.ts +992 -0
  103. 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";
@@ -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);