node-autotask 0.14.0 → 0.16.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/ARCHITECTURE.md CHANGED
@@ -304,7 +304,7 @@ export interface AutotaskConfig {
304
304
  pageSize?: number;
305
305
  /** HTTP timeout in ms (whole-call budget). Default 30_000. */
306
306
  timeoutMs?: number;
307
- /** The client's retry budget (default 3; 0 disables auto-retry). Two legs (issue #105): the 429 leg retries on the pre-#105 retriable set (GET/PUT/DELETE + idempotent-flagged calls) and the 5xx/network leg retries GET + idempotent-flagged calls only. A per-call override rides `InvokeOptions.maxRetries` / `MutationOpts.maxRetries`. */
307
+ /** The client's retry budget (default 3; 0 disables auto-retry). Three legs, two rules (issues #105/#109): the 429 leg retries on the pre-#105 retriable set (GET/PUT/DELETE + idempotent-flagged calls); the 5xx/network leg and the non-JSON-2xx (#24) leg retry GET + idempotent-flagged calls only. A per-call override rides `InvokeOptions.maxRetries` / `MutationOpts.maxRetries`. */
308
308
  maxRetries?: number;
309
309
  /** Optional request log sink. Default: no-op. */
310
310
  logger?: Logger;
@@ -510,7 +510,7 @@ export interface RequestOptions {
510
510
  - `2xx` → parse JSON (if body present); empty body → resolve `undefined`.
511
511
  - non-2xx → throw via `errorFromStatus(status, body, url, operation)` (§10).
512
512
  - network/AbortError → `AutotaskNetworkError` / `AutotaskTimeoutError`.
513
- 6. **Retries** (issue #105 — two legs, two rules, retry up to `maxRetries` with
513
+ 6. **Retries** (issues #105/#109 — three legs, two rules, retry up to `maxRetries` with
514
514
  exponential backoff + jitter, base 200 ms, cap 30 s, honouring `Retry-After`):
515
515
  - **429 leg — UNCHANGED by #105.** A `429` is a **pre-processing refusal** (the
516
516
  vendor rate limiter rejected the call before executing it); it is retried on the
@@ -527,6 +527,21 @@ export interface RequestOptions {
527
527
  `POST .../Reject` is never retried on either leg — it is an unflagged `POST`, so a
528
528
  `429` surfaces at once as well (`time_off_requests.reject` lists no retryable
529
529
  statuses in the registry).
530
+ - **`#24` leg (non-JSON `2xx`, an edge maintenance page) — follows the write
531
+ rule (issue #109).** A `GET` / explicitly idempotent-flagged call retries; a
532
+ mutation makes ONE send and throws `UNEXPECTED_CONTENT_TYPE` with the residue
533
+ `suggestedAction`. The transport no longer assumes the edge served the page —
534
+ that premise is unprovable from the response, and the #104 classifier pins this
535
+ code as `unknown` for a write (never blindly resend). `idempotent: true` /
536
+ `maxRetries` remain the explicit opt-ins.
537
+ - **Maintenance-window wait (weekly window):** a non-JSON `2xx` that reads as a
538
+ maintenance notice is waited out for up to `maintenanceMaxWaitMs` (default 1 h,
539
+ polled every `maintenancePollMs` = 30 s) from the first such page — for reads
540
+ AND writes, because the edge answered before the vendor application saw the
541
+ request. It does not consume `maxRetries`, each post-wait attempt gets a fresh
542
+ `timeoutMs`, and the timer is re-armed around the wait. On exhaustion the error
543
+ carries `details.maintenance = { waits, waitedMs, maxWaitMs, exhausted }`. A page
544
+ that does not read as maintenance (a wrong `baseUrl`) never enters the loop.
530
545
  - **Per-call budget override:** `InvokeOptions.maxRetries` / `MutationOpts.maxRetries`
531
546
  threads the transport's per-request override through a mutation (and its
532
547
  auxiliary reads, e.g. a partial-update merge read); `0` = exactly one send per
package/README.md CHANGED
@@ -397,9 +397,11 @@ The SDK ships the mechanical substrate, not a server (no MCP imports, no zod):
397
397
  gains two server-category codes: `UNEXPECTED_CONTENT_TYPE` (a non-JSON 2xx
398
398
  whose `Content-Type` is not a JSON media type — the vendor maintenance
399
399
  page; `details` carries the content-type + a 256-byte truncated snippet
400
- that the MCP servers wrap as untrusted host text; idempotent methods retry
401
- per policy, a write makes ONE call and says the write may have taken
402
- effect) and `EMPTY_RESPONSE` (a blank 2xx on a call that expects a result
400
+ that the MCP servers wrap as untrusted host text; a maintenance notice is waited
401
+ out for up to `maintenanceMaxWaitMs` (default 1 h — the weekly window is usually
402
+ under 30 min) for reads and writes, otherwise a `GET` or an explicitly
403
+ `idempotent`-flagged call retries and a write makes ONE call and says the write
404
+ may have taken effect) and `EMPTY_RESPONSE` (a blank 2xx on a call that expects a result
403
405
  — `expectBody`, non-DELETE by default; `DELETE` / 204 keep `undefined` and
404
406
  the delete ops synthesize `{ id }` from the path id on a blank answer). A
405
407
  vendor field-validation 500 matching the documented phrases (`exceeds
@@ -76,11 +76,12 @@ interface CapabilityRecord {
76
76
  maxScanRecords: number;
77
77
  maxScanPages: number;
78
78
  } | null;
79
- /** From the actual transport (src/http.ts; issue #105 — two legs): the
80
- * 429 (a pre-processing refusal) leg auto-retries per Retry-After on the
81
- * pre-#105 retriable set (GET/PUT/DELETE + idempotent-flagged ops; an
82
- * unflagged POST/PATCH surfaces at once); on 5xx/network errors only reads
83
- * and idempotent-flagged ops auto-retry (exponential backoff, equal
79
+ /** From the actual transport (src/http.ts; issues #105/#109 — three legs,
80
+ * two rules): the 429 (a pre-processing refusal) leg auto-retries per
81
+ * Retry-After on the pre-#105 retriable set (GET/PUT/DELETE +
82
+ * idempotent-flagged ops; an unflagged POST/PATCH surfaces at once); on
83
+ * 5xx/network errors AND on a non-JSON 2xx (#24) only reads and
84
+ * idempotent-flagged ops auto-retry (exponential backoff, equal
84
85
  * jitter, base 200ms, cap 30s, max 3 retries, Retry-After honoured) — a
85
86
  * mutation's outcome is unknown once its body was written. The vendor
86
87
  * offers no idempotency pass-through. */
@@ -76,11 +76,12 @@ interface CapabilityRecord {
76
76
  maxScanRecords: number;
77
77
  maxScanPages: number;
78
78
  } | null;
79
- /** From the actual transport (src/http.ts; issue #105 — two legs): the
80
- * 429 (a pre-processing refusal) leg auto-retries per Retry-After on the
81
- * pre-#105 retriable set (GET/PUT/DELETE + idempotent-flagged ops; an
82
- * unflagged POST/PATCH surfaces at once); on 5xx/network errors only reads
83
- * and idempotent-flagged ops auto-retry (exponential backoff, equal
79
+ /** From the actual transport (src/http.ts; issues #105/#109 — three legs,
80
+ * two rules): the 429 (a pre-processing refusal) leg auto-retries per
81
+ * Retry-After on the pre-#105 retriable set (GET/PUT/DELETE +
82
+ * idempotent-flagged ops; an unflagged POST/PATCH surfaces at once); on
83
+ * 5xx/network errors AND on a non-JSON 2xx (#24) only reads and
84
+ * idempotent-flagged ops auto-retry (exponential backoff, equal
84
85
  * jitter, base 200ms, cap 30s, max 3 retries, Retry-After honoured) — a
85
86
  * mutation's outcome is unknown once its body was written. The vendor
86
87
  * offers no idempotency pass-through. */
@@ -127,13 +127,13 @@ import {
127
127
  VersionInformationResource,
128
128
  VersionResource,
129
129
  ZoneInformationResource
130
- } from "./chunk-IYN2BHVW.js";
130
+ } from "./chunk-NB254T3F.js";
131
131
  import {
132
132
  AutotaskConfigError,
133
133
  HttpClient,
134
134
  resolveConfig,
135
135
  runWithSignal
136
- } from "./chunk-KA6UU26H.js";
136
+ } from "./chunk-U6JUHHMB.js";
137
137
 
138
138
  // src/client.ts
139
139
  var AutotaskClient = class {