node-autotask 0.18.0 → 0.19.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 (38) hide show
  1. package/ARCHITECTURE.md +15 -8
  2. package/CHANGELOG.md +574 -0
  3. package/MCP_TOOL_CATALOG.json +2 -2
  4. package/MCP_TOOL_MANIFEST.md +5 -5
  5. package/N8N_MCP_MANIFEST.json +2 -2
  6. package/N8N_MCP_MANIFEST.md +3 -3
  7. package/README.md +8 -4
  8. package/capabilities.json +1223 -1223
  9. package/dist/capabilities.cjs +2 -2
  10. package/dist/capabilities.js +1 -1
  11. package/dist/{chunk-W2WSZOZA.js → chunk-4YKV7ORF.js} +2 -2
  12. package/dist/{chunk-7I3F3AJJ.cjs → chunk-7RDR5DSI.cjs} +393 -393
  13. package/dist/{chunk-HXOWEYV3.js → chunk-D5RAQ4DE.js} +2 -2
  14. package/dist/{chunk-5O5EPYBO.cjs → chunk-JM52ZU7T.cjs} +1222 -1222
  15. package/dist/{chunk-VYUZZIEE.js → chunk-LB2X4X4B.js} +86 -8
  16. package/dist/{chunk-VV2UUW2J.js → chunk-NDK7WYWA.js} +1222 -1222
  17. package/dist/{chunk-WRWX6WIK.cjs → chunk-QDYSHAU6.cjs} +147 -69
  18. package/dist/{chunk-G564CHXM.cjs → chunk-TIM75K3G.cjs} +135 -135
  19. package/dist/{index-BqPY04ZG.d.ts → index-DLugNSr7.d.ts} +27 -13
  20. package/dist/{index-D7x3MkLK.d.cts → index-aZ3tCh1h.d.cts} +27 -13
  21. package/dist/index.cjs +24 -22
  22. package/dist/index.d.cts +2 -2
  23. package/dist/index.d.ts +2 -2
  24. package/dist/index.js +6 -4
  25. package/dist/operations/index.cjs +109 -109
  26. package/dist/operations/index.d.cts +2 -2
  27. package/dist/operations/index.d.ts +2 -2
  28. package/dist/operations/index.js +2 -2
  29. package/dist/pool.cjs +8 -8
  30. package/dist/pool.d.cts +1 -1
  31. package/dist/pool.d.ts +1 -1
  32. package/dist/pool.js +4 -4
  33. package/dist/resources/index.cjs +4 -4
  34. package/dist/resources/index.d.cts +1 -1
  35. package/dist/resources/index.d.ts +1 -1
  36. package/dist/resources/index.js +3 -3
  37. package/docs/API.md +48 -18
  38. package/package.json +2 -1
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  CAPABILITIES
3
- } from "./chunk-VV2UUW2J.js";
3
+ } from "./chunk-NDK7WYWA.js";
4
4
 
5
5
  // src/auth.ts
6
6
  var AUTH_HEADERS = {
@@ -1536,6 +1536,7 @@ var DEFAULT_TIMEOUT_MS = 3e4;
1536
1536
  var DEFAULT_MAX_RETRIES = 3;
1537
1537
  var DEFAULT_MAINTENANCE_MAX_WAIT_MS = 36e5;
1538
1538
  var DEFAULT_MAINTENANCE_POLL_MS = 3e4;
1539
+ var MAINTENANCE_WINDOW_MAX_MS = 4 * 36e5;
1539
1540
  var DEFAULT_MAX_CONCURRENT = 10;
1540
1541
  var DEFAULT_MAX_RESPONSE_BYTES = 64 * 1024 * 1024;
1541
1542
  var DEFAULT_MAX_SCAN_RECORDS = 500;
@@ -14779,9 +14780,21 @@ function backoffDelay(attempt) {
14779
14780
  const exp = Math.min(BACKOFF_CAP_MS, BACKOFF_BASE_MS * 2 ** attempt);
14780
14781
  return Math.floor(exp / 2 + Math.random() * (exp / 2));
14781
14782
  }
14782
- function isMaintenancePage(err) {
14783
- const snippet = typeof err.details?.bodySnippet === "string" ? err.details.bodySnippet : "";
14784
- return /maintenance|temporarily unavailable|service unavailable|outage|downtime|down for/i.test(snippet);
14783
+ var MAINTENANCE_PROBE_BYTES = 256;
14784
+ function maintenanceProbe(text) {
14785
+ return Buffer.from(text, "utf8").subarray(0, MAINTENANCE_PROBE_BYTES).toString("utf8");
14786
+ }
14787
+ function looksLikeMaintenanceText(text) {
14788
+ return /maintenance|temporarily unavailable|service unavailable|outage|downtime|down for/i.test(
14789
+ maintenanceProbe(text)
14790
+ );
14791
+ }
14792
+ function isHtmlLike(contentType, body) {
14793
+ if (contentType !== null && /text\/html|application\/xhtml/i.test(contentType)) return true;
14794
+ return body.trimStart().startsWith("<");
14795
+ }
14796
+ function maintenanceExhaustedAction(maxWaitMs, waits) {
14797
+ return `The zone stayed in a maintenance window for ${Math.round(maxWaitMs / 6e4)} min \u2014 the SDK waited and retried ${waits} time(s) and gave up. Re-run after the window (the observed median is about 2 h; the ceiling is 4 h \u2014 MAINTENANCE_WINDOW_MAX_MS), or raise maintenanceMaxWaitMs.`;
14785
14798
  }
14786
14799
  function parseRetryAfter(value) {
14787
14800
  if (value === null || value.length === 0) return void 0;
@@ -15217,6 +15230,7 @@ var HttpClient = class {
15217
15230
  const maintenancePollMs = opts.maintenancePollMs ?? this.maintenancePollMs;
15218
15231
  let firstMaintenanceAt;
15219
15232
  let maintenanceWaits = 0;
15233
+ let maintenanceBudgetSpent = false;
15220
15234
  const started = Date.now();
15221
15235
  let deadlineAt = started + timeoutMs;
15222
15236
  const callerSignal = opts.signal ?? ambientSignal.getStore();
@@ -15437,12 +15451,13 @@ var HttpClient = class {
15437
15451
  httpStatus: status,
15438
15452
  suggestedAction: "The zone returned a non-JSON 2xx body; verify baseUrl points at the REST API."
15439
15453
  });
15440
- if (err2.code === "UNEXPECTED_CONTENT_TYPE" && maintenanceMaxWaitMs > 0 && isMaintenancePage(err2)) {
15454
+ if (err2.code === "UNEXPECTED_CONTENT_TYPE" && maintenanceMaxWaitMs > 0 && looksLikeMaintenanceText(text)) {
15441
15455
  const now = Date.now();
15442
15456
  firstMaintenanceAt ??= now;
15443
15457
  const remaining = maintenanceMaxWaitMs - (now - firstMaintenanceAt);
15444
15458
  if (remaining > 0) {
15445
15459
  const wait = Math.min(maintenancePollMs, remaining);
15460
+ if (wait >= remaining) maintenanceBudgetSpent = true;
15446
15461
  maintenanceWaits += 1;
15447
15462
  this.logger.warn?.(
15448
15463
  `[autotask] maintenance window on ${method} ${opts.path}; waiting ${Math.round(wait / 1e3)}s (retry ${maintenanceWaits}, up to ${Math.round(maintenanceMaxWaitMs / 6e4)} min)`,
@@ -15453,6 +15468,7 @@ var HttpClient = class {
15453
15468
  await pause(wait);
15454
15469
  continue;
15455
15470
  }
15471
+ maintenanceBudgetSpent = true;
15456
15472
  }
15457
15473
  if (err2.code === "UNEXPECTED_CONTENT_TYPE" && retriable5xx && attempt < maxRetries) {
15458
15474
  const retryAfter = parseRetryAfter(res.headers.get("Retry-After"));
@@ -15467,17 +15483,27 @@ var HttpClient = class {
15467
15483
  continue;
15468
15484
  }
15469
15485
  }
15470
- if (maintenanceWaits > 0 && err2.code === "UNEXPECTED_CONTENT_TYPE") {
15486
+ const pageSnippet = typeof err2.details?.bodySnippet === "string" ? err2.details.bodySnippet : "";
15487
+ if (maintenanceWaits > 0) {
15471
15488
  err2.details = {
15472
15489
  ...err2.details ?? {},
15473
15490
  maintenance: {
15474
15491
  waits: maintenanceWaits,
15475
15492
  waitedMs: Date.now() - (firstMaintenanceAt ?? Date.now()),
15476
15493
  maxWaitMs: maintenanceMaxWaitMs,
15477
- exhausted: true
15494
+ exhausted: maintenanceBudgetSpent
15478
15495
  }
15479
15496
  };
15480
- err2.suggestedAction = `The zone stayed in a maintenance window for ${Math.round(maintenanceMaxWaitMs / 6e4)} min \u2014 the SDK waited and retried ${maintenanceWaits} time(s) and gave up. Re-run after the window (typically under 30 min), or raise maintenanceMaxWaitMs.`;
15497
+ if (maintenanceBudgetSpent) {
15498
+ err2.suggestedAction = maintenanceExhaustedAction(maintenanceMaxWaitMs, maintenanceWaits);
15499
+ }
15500
+ }
15501
+ if (err2.code === "UNEXPECTED_CONTENT_TYPE" && !looksLikeMaintenanceText(text) && isHtmlLike(res.headers.get("Content-Type"), text)) {
15502
+ err2.details = { ...err2.details ?? {}, maintenancePatternMiss: true };
15503
+ this.logger.debug?.(
15504
+ `[autotask] non-JSON body did not match the maintenance vocabulary on ${method} ${opts.path}: ${pageSnippet}`,
15505
+ correlationId
15506
+ );
15481
15507
  }
15482
15508
  attachEmptyReasonDetails(err2);
15483
15509
  throw err2;
@@ -15489,12 +15515,37 @@ var HttpClient = class {
15489
15515
  break;
15490
15516
  }
15491
15517
  let body;
15518
+ let nonJsonBody;
15492
15519
  if (text.length > 0) {
15493
15520
  try {
15494
15521
  body = JSON.parse(text);
15495
15522
  } catch {
15496
15523
  body = text;
15524
+ nonJsonBody = text;
15525
+ }
15526
+ }
15527
+ const nonJsonSnippet = nonJsonBody === void 0 ? void 0 : bodySnippet(nonJsonBody, this.redactPersonalData);
15528
+ const nonJsonIsMaintenance = nonJsonBody !== void 0 && looksLikeMaintenanceText(nonJsonBody);
15529
+ const nonJsonIsHtmlCandidate = nonJsonBody !== void 0 && isHtmlLike(res.headers.get("Content-Type"), nonJsonBody);
15530
+ const nonJsonMaintenanceMayWait = nonJsonIsMaintenance && retriable5xx;
15531
+ if (nonJsonBody !== void 0 && maintenanceMaxWaitMs > 0 && nonJsonMaintenanceMayWait) {
15532
+ const now = Date.now();
15533
+ firstMaintenanceAt ??= now;
15534
+ const remaining = maintenanceMaxWaitMs - (now - firstMaintenanceAt);
15535
+ if (remaining > 0) {
15536
+ const wait = Math.min(maintenancePollMs, remaining);
15537
+ if (wait >= remaining) maintenanceBudgetSpent = true;
15538
+ maintenanceWaits += 1;
15539
+ this.logger.warn?.(
15540
+ `[autotask] maintenance window on ${method} ${opts.path} (HTTP ${status}); waiting ${Math.round(wait / 1e3)}s (retry ${maintenanceWaits}, up to ${Math.round(maintenanceMaxWaitMs / 6e4)} min)`,
15541
+ correlationId
15542
+ );
15543
+ deadlineAt = Date.now() + wait + timeoutMs;
15544
+ armDeadline(deadlineAt - Date.now());
15545
+ await pause(wait);
15546
+ continue;
15497
15547
  }
15548
+ maintenanceBudgetSpent = true;
15498
15549
  }
15499
15550
  const deterministic500 = status >= 500 && isDeterministicVendor500(parseVendorErrors(body));
15500
15551
  const retryableStatus = status === 429 || status >= 500;
@@ -15537,6 +15588,32 @@ var HttpClient = class {
15537
15588
  credentialShapeExpectation(headers, this.auth)
15538
15589
  );
15539
15590
  err.correlationId = correlationId;
15591
+ if (maintenanceWaits > 0) {
15592
+ err.details = {
15593
+ ...err.details ?? {},
15594
+ maintenance: {
15595
+ waits: maintenanceWaits,
15596
+ waitedMs: Date.now() - (firstMaintenanceAt ?? Date.now()),
15597
+ maxWaitMs: maintenanceMaxWaitMs,
15598
+ exhausted: maintenanceBudgetSpent
15599
+ }
15600
+ };
15601
+ if (maintenanceBudgetSpent) {
15602
+ err.suggestedAction = maintenanceExhaustedAction(maintenanceMaxWaitMs, maintenanceWaits);
15603
+ }
15604
+ }
15605
+ if (nonJsonBody !== void 0) {
15606
+ if (nonJsonIsMaintenance && !retriable5xx) {
15607
+ err.details = { ...err.details ?? {}, maintenanceDetected: true };
15608
+ err.suggestedAction = `A maintenance-shaped page answered ${method} ${opts.path} (HTTP ${status}); it was NOT waited out or re-sent \u2014 a non-2xx edge page can arrive after the request was forwarded, so verify the record before re-issuing (only a GET or an explicitly idempotent-flagged call waits this window out).`;
15609
+ } else if (!nonJsonIsMaintenance && nonJsonIsHtmlCandidate) {
15610
+ err.details = { ...err.details ?? {}, maintenancePatternMiss: true };
15611
+ this.logger.debug?.(
15612
+ `[autotask] non-JSON body did not match the maintenance vocabulary on ${method} ${opts.path}: ${nonJsonSnippet}`,
15613
+ correlationId
15614
+ );
15615
+ }
15616
+ }
15540
15617
  if (status === 401 && zoneRetry !== void 0) {
15541
15618
  err.details = {
15542
15619
  ...err.details ?? {},
@@ -18702,6 +18779,7 @@ export {
18702
18779
  DEFAULT_MAX_RETRIES,
18703
18780
  DEFAULT_MAINTENANCE_MAX_WAIT_MS,
18704
18781
  DEFAULT_MAINTENANCE_POLL_MS,
18782
+ MAINTENANCE_WINDOW_MAX_MS,
18705
18783
  DEFAULT_MAX_CONCURRENT,
18706
18784
  DEFAULT_MAX_RESPONSE_BYTES,
18707
18785
  DEFAULT_MAX_SCAN_RECORDS,