node-autotask 0.26.0 → 0.28.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 (49) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/MCP_TOOL_CATALOG.json +941 -14
  3. package/MCP_TOOL_MANIFEST.md +71 -16
  4. package/N8N_MCP_MANIFEST.json +91 -10
  5. package/N8N_MCP_MANIFEST.md +14 -11
  6. package/README.md +11 -9
  7. package/capabilities.json +13623 -7738
  8. package/capabilities.schema.json +125 -0
  9. package/dist/capabilities.cjs +2 -2
  10. package/dist/capabilities.js +1 -1
  11. package/dist/{chunk-QXWIQ67O.js → chunk-6EQSXYRW.js} +13622 -7737
  12. package/dist/{chunk-HQGE4WAV.cjs → chunk-D5IVS6GY.cjs} +1054 -235
  13. package/dist/{chunk-5OGJTS2E.cjs → chunk-GUY2KK7U.cjs} +157 -136
  14. package/dist/{chunk-SSUECUVN.js → chunk-IRVZGW5K.js} +947 -128
  15. package/dist/{chunk-7DOSJS6S.js → chunk-O2D7KDDD.js} +23 -2
  16. package/dist/{chunk-VVQ6NJYZ.js → chunk-SYX6EWMT.js} +694 -76
  17. package/dist/{chunk-SG4LIVMG.cjs → chunk-WYKGD5UD.cjs} +1189 -571
  18. package/dist/{chunk-WM6E5O55.cjs → chunk-ZEGMVEF3.cjs} +13622 -7737
  19. package/dist/{index-CKYr0unq.d.cts → index-CORcZUNm.d.cts} +457 -50
  20. package/dist/{index-1zBdJIEy.d.cts → index-DQ9NgraW.d.cts} +281 -1
  21. package/dist/{index-1zBdJIEy.d.ts → index-DQ9NgraW.d.ts} +281 -1
  22. package/dist/{index-C8QH3BkP.d.ts → index-DXuV04zM.d.ts} +457 -50
  23. package/dist/index.cjs +44 -24
  24. package/dist/index.d.cts +11 -5
  25. package/dist/index.d.ts +11 -5
  26. package/dist/index.js +26 -6
  27. package/dist/operations/index.cjs +147 -120
  28. package/dist/operations/index.d.cts +136 -7
  29. package/dist/operations/index.d.ts +136 -7
  30. package/dist/operations/index.js +33 -6
  31. package/dist/pool.cjs +42 -9
  32. package/dist/pool.d.cts +14 -3
  33. package/dist/pool.d.ts +14 -3
  34. package/dist/pool.js +38 -5
  35. package/dist/resources/index.cjs +19 -5
  36. package/dist/resources/index.d.cts +2 -2
  37. package/dist/resources/index.d.ts +2 -2
  38. package/dist/resources/index.js +18 -4
  39. package/dist/types/index.cjs +1 -1
  40. package/dist/types/index.d.cts +1 -1
  41. package/dist/types/index.d.ts +1 -1
  42. package/dist/types/index.js +1 -1
  43. package/docs/API.md +246 -10
  44. package/examples/mcp/schemas.ts +16 -7
  45. package/package.json +1 -1
  46. /package/dist/{chunk-S643FDOR.cjs → chunk-IXF7AKOJ.cjs} +0 -0
  47. /package/dist/{chunk-2TWKEB2L.js → chunk-RMG55JTF.js} +0 -0
  48. /package/dist/{chunk-W3K5BEVY.cjs → chunk-SDYRQFGL.cjs} +0 -0
  49. /package/dist/{chunk-EBCHCNPK.js → chunk-WLTLB2ND.js} +0 -0
@@ -1,6 +1,6 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5; var _class6; var _class7; var _class8;
2
2
 
3
- var _chunkWM6E5O55cjs = require('./chunk-WM6E5O55.cjs');
3
+ var _chunkZEGMVEF3cjs = require('./chunk-ZEGMVEF3.cjs');
4
4
 
5
5
  // src/auth.ts
6
6
  var AUTH_HEADERS = {
@@ -583,6 +583,111 @@ var MoveRefusedError = class extends AutotaskError {
583
583
  }
584
584
  };
585
585
 
586
+ // src/cache.ts
587
+ var READ_CACHE_MAX_ENTRIES = 4096;
588
+ var ReadCache = (_class = class {
589
+ /** The configured TTL in ms (the fallback for resources without an override). */
590
+
591
+ /** The per-resource TTL overrides (issue #32; absent = every resource uses `ttlMs`). */
592
+
593
+ __init() {this.store = /* @__PURE__ */ new Map()}
594
+ __init2() {this.epochCounter = 0}
595
+ constructor(ttlMs, perResourceTtlMs) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);
596
+ if (!Number.isInteger(ttlMs) || ttlMs <= 0) {
597
+ throw new AutotaskConfigError(`cache.ttlMs must be a positive integer (got ${ttlMs})`);
598
+ }
599
+ if (perResourceTtlMs !== void 0) {
600
+ if (perResourceTtlMs === null || typeof perResourceTtlMs !== "object" || Array.isArray(perResourceTtlMs)) {
601
+ throw new AutotaskConfigError(
602
+ `cache.perResourceTtlMs must be an object of resource key -> ms (got ${String(perResourceTtlMs)})`
603
+ );
604
+ }
605
+ for (const [key, value] of Object.entries(perResourceTtlMs)) {
606
+ if (key === "") {
607
+ throw new AutotaskConfigError("cache.perResourceTtlMs keys must be non-empty resource keys");
608
+ }
609
+ if (!Number.isInteger(value) || value <= 0) {
610
+ throw new AutotaskConfigError(
611
+ `cache.perResourceTtlMs.${key} must be a positive integer (got ${String(value)})`
612
+ );
613
+ }
614
+ }
615
+ }
616
+ this.ttlMs = ttlMs;
617
+ this.perResourceTtlMs = perResourceTtlMs;
618
+ }
619
+ /**
620
+ * The TTL (ms) for a resource plan key: the `perResourceTtlMs` override
621
+ * when the map is present and names the resource, else the base
622
+ * `ttlMs` (absent map, absent key, and `undefined` all fall back).
623
+ */
624
+ ttlFor(resource) {
625
+ if (resource !== void 0 && this.perResourceTtlMs !== void 0) {
626
+ const override = this.perResourceTtlMs[resource];
627
+ if (override !== void 0) return override;
628
+ }
629
+ return this.ttlMs;
630
+ }
631
+ /**
632
+ * Read-through lookup: the live entry's value, or `undefined` (absent OR
633
+ * expired — an expired entry is purged lazily on this read).
634
+ */
635
+ get(key) {
636
+ const entry = this.store.get(key);
637
+ if (entry === void 0) return void 0;
638
+ if (entry.expiresAt <= Date.now()) {
639
+ this.store.delete(key);
640
+ return void 0;
641
+ }
642
+ return structuredClone(entry.value);
643
+ }
644
+ /** Store a successful read payload under `key`, live for `ttlFor(resource)`:
645
+ * the per-resource override (issue #32) when named, else `ttlMs`.
646
+ * `epoch` is the invalidation epoch the caller captured BEFORE its wire
647
+ * read: a read that straddled a `clear()` (a write) is dropped, never
648
+ * re-stored with its pre-write body. */
649
+ set(key, value, resource, epoch = this.epochCounter) {
650
+ if (epoch !== this.epochCounter) return;
651
+ if (this.store.size >= READ_CACHE_MAX_ENTRIES && this.purgeExpired() === 0) {
652
+ const oldest = this.store.keys().next();
653
+ if (!oldest.done) this.store.delete(oldest.value);
654
+ }
655
+ this.store.delete(key);
656
+ this.store.set(key, { value: structuredClone(value), expiresAt: Date.now() + this.ttlFor(resource) });
657
+ }
658
+ /** Drop every expired entry (returns the number removed). */
659
+ purgeExpired() {
660
+ const now = Date.now();
661
+ let removed = 0;
662
+ for (const [key, entry] of this.store) {
663
+ if (entry.expiresAt <= now) {
664
+ this.store.delete(key);
665
+ removed += 1;
666
+ }
667
+ }
668
+ return removed;
669
+ }
670
+ /** Current entry count (live + not-yet-purged expired). */
671
+ get size() {
672
+ return this.store.size;
673
+ }
674
+ /** Drop one key (issue #36: a later positive outcome clears a stale 'absent' marker). */
675
+ delete(key) {
676
+ return this.store.delete(key);
677
+ }
678
+ /** The invalidation epoch: bumped by `clear()`; capture it before a wire
679
+ * read and pass it to `set` so a read in flight across a write cannot
680
+ * re-store its stale answer. */
681
+ get epoch() {
682
+ return this.epochCounter;
683
+ }
684
+ /** Drop everything (e.g. a caller that knows the tenant was reset). */
685
+ clear() {
686
+ this.epochCounter += 1;
687
+ this.store.clear();
688
+ }
689
+ }, _class);
690
+
586
691
  // src/config/zones.ts
587
692
  var ZONE_CATALOG = {
588
693
  "pre-release": "https://webservices2.autotask.net/atservicesrest",
@@ -689,6 +794,7 @@ var DEFAULT_PER_RESOURCE_TTL_MS = {
689
794
  "appointments": 3e5,
690
795
  "authenticate": 3e5,
691
796
  "billing_codes": 36e5,
797
+ "billing_item_approval_levels": 3e5,
692
798
  "billing_items": 3e5,
693
799
  "change_request_links": 3e5,
694
800
  "checklist_libraries": 3e5,
@@ -747,12 +853,16 @@ var DEFAULT_PER_RESOURCE_TTL_MS = {
747
853
  "holiday_sets": 3e5,
748
854
  "holidays": 3e5,
749
855
  "inventory_products": 3e5,
856
+ "invoice_templates": 3e5,
750
857
  "invoices": 3e5,
751
858
  "modules": 3e5,
752
859
  "notification_history": 3e5,
753
860
  "opportunities": 3e5,
754
861
  "opportunity_attachments": 3e5,
755
862
  "opportunity_categories": 3e5,
863
+ "organizational_level1s": 3e5,
864
+ "organizational_level2s": 3e5,
865
+ "organizational_level_associations": 3e5,
756
866
  "phases": 36e5,
757
867
  "product_vendors": 3e5,
758
868
  "products": 3e5,
@@ -775,6 +885,7 @@ var DEFAULT_PER_RESOURCE_TTL_MS = {
775
885
  "resource_time_off_balances": 3e5,
776
886
  "resources": 3e5,
777
887
  "roles": 36e5,
888
+ "sales_orders": 3e5,
778
889
  "service_call_task_resources": 3e5,
779
890
  "service_call_tasks": 3e5,
780
891
  "service_call_ticket_resources": 3e5,
@@ -792,6 +903,7 @@ var DEFAULT_PER_RESOURCE_TTL_MS = {
792
903
  "tags": 3e5,
793
904
  "task_secondary_resources": 3e5,
794
905
  "tasks": 3e5,
906
+ "tax_regions": 3e5,
795
907
  "threshold_information": 3e5,
796
908
  "ticket_additional_configuration_items": 3e5,
797
909
  "ticket_additional_contacts": 3e5,
@@ -819,6 +931,7 @@ var DEFAULT_PER_RESOURCE_TTL_MS = {
819
931
  var RESOURCE_KEY_BY_PATH = {
820
932
  "/V1.0/Appointments": "appointments",
821
933
  "/V1.0/BillingCodes": "billing_codes",
934
+ "/V1.0/BillingItemApprovalLevels": "billing_item_approval_levels",
822
935
  "/V1.0/BillingItems": "billing_items",
823
936
  "/V1.0/ChangeRequestLinks": "change_request_links",
824
937
  "/V1.0/ChecklistLibraries": "checklist_libraries",
@@ -876,11 +989,15 @@ var RESOURCE_KEY_BY_PATH = {
876
989
  "/V1.0/HolidaySets": "holiday_sets",
877
990
  "/V1.0/Holidays": "holidays",
878
991
  "/V1.0/InventoryProducts": "inventory_products",
992
+ "/V1.0/InvoiceTemplates": "invoice_templates",
879
993
  "/V1.0/Invoices": "invoices",
880
994
  "/V1.0/NotificationHistory": "notification_history",
881
995
  "/V1.0/Opportunities": "opportunities",
882
996
  "/V1.0/OpportunityAttachments": "opportunity_attachments",
883
997
  "/V1.0/OpportunityCategories": "opportunity_categories",
998
+ "/V1.0/OrganizationalLevel1s": "organizational_level1s",
999
+ "/V1.0/OrganizationalLevel2s": "organizational_level2s",
1000
+ "/V1.0/OrganizationalLevelAssociations": "organizational_level_associations",
884
1001
  "/V1.0/Phases": "phases",
885
1002
  "/V1.0/ProductVendors": "product_vendors",
886
1003
  "/V1.0/Products": "products",
@@ -903,6 +1020,7 @@ var RESOURCE_KEY_BY_PATH = {
903
1020
  "/V1.0/ResourceTimeOffBalances": "resource_time_off_balances",
904
1021
  "/V1.0/Resources": "resources",
905
1022
  "/V1.0/Roles": "roles",
1023
+ "/V1.0/SalesOrders": "sales_orders",
906
1024
  "/V1.0/ServiceCallTaskResources": "service_call_task_resources",
907
1025
  "/V1.0/ServiceCallTasks": "service_call_tasks",
908
1026
  "/V1.0/ServiceCallTicketResources": "service_call_ticket_resources",
@@ -920,6 +1038,7 @@ var RESOURCE_KEY_BY_PATH = {
920
1038
  "/V1.0/Tags": "tags",
921
1039
  "/V1.0/TaskSecondaryResources": "task_secondary_resources",
922
1040
  "/V1.0/Tasks": "tasks",
1041
+ "/V1.0/TaxRegions": "tax_regions",
923
1042
  "/V1.0/TicketAdditionalConfigurationItems": "ticket_additional_configuration_items",
924
1043
  "/V1.0/TicketAdditionalContacts": "ticket_additional_contacts",
925
1044
  "/V1.0/TicketAttachments": "ticket_attachments",
@@ -984,14 +1103,14 @@ function credentialValueSummary(value) {
984
1103
  // src/fieldCache.ts
985
1104
  var FIELD_CACHE_MAX_ENTITIES = 256;
986
1105
  var FIELD_CACHE_KINDS = ["info", "fields", "udf"];
987
- var FieldCache = (_class = class _FieldCache {
1106
+ var FieldCache = (_class2 = class _FieldCache {
988
1107
  /** The configured TTL in ms. */
989
1108
 
990
1109
  /** The entity bound (the cap applies to STORED entries; inflight never counts). */
991
1110
 
992
- __init() {this.store = /* @__PURE__ */ new Map()}
993
- __init2() {this.inflightMap = /* @__PURE__ */ new Map()}
994
- constructor(ttlMs, maxEntities = FIELD_CACHE_MAX_ENTITIES) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);
1111
+ __init3() {this.store = /* @__PURE__ */ new Map()}
1112
+ __init4() {this.inflightMap = /* @__PURE__ */ new Map()}
1113
+ constructor(ttlMs, maxEntities = FIELD_CACHE_MAX_ENTITIES) {;_class2.prototype.__init3.call(this);_class2.prototype.__init4.call(this);
995
1114
  if (!Number.isInteger(ttlMs) || ttlMs <= 0) {
996
1115
  throw new AutotaskConfigError(`fieldCache.ttlMs must be a positive integer (got ${ttlMs})`);
997
1116
  }
@@ -1113,7 +1232,7 @@ var FieldCache = (_class = class _FieldCache {
1113
1232
  this.store.clear();
1114
1233
  this.inflightMap.clear();
1115
1234
  }
1116
- }, _class);
1235
+ }, _class2);
1117
1236
 
1118
1237
  // src/circuit-breaker.ts
1119
1238
  var DEFAULT_CIRCUIT_BREAKER_WINDOW_MS = 1e4;
@@ -1121,10 +1240,10 @@ var DEFAULT_CIRCUIT_BREAKER_FAILURE_THRESHOLD = 5;
1121
1240
  var DEFAULT_CIRCUIT_BREAKER_OPEN_TIMEOUT_MS = 3e4;
1122
1241
  var DEFAULT_CIRCUIT_BREAKER_SUCCESSES_TO_CLOSE = 2;
1123
1242
  var DEFAULT_CIRCUIT_BREAKER_MAX_ENTRIES = 1024;
1124
- var InMemoryCircuitBreakerStore = (_class2 = class {
1243
+ var InMemoryCircuitBreakerStore = (_class3 = class {
1125
1244
 
1126
- __init3() {this.states = /* @__PURE__ */ new Map()}
1127
- constructor(maxEntries = DEFAULT_CIRCUIT_BREAKER_MAX_ENTRIES) {;_class2.prototype.__init3.call(this);
1245
+ __init5() {this.states = /* @__PURE__ */ new Map()}
1246
+ constructor(maxEntries = DEFAULT_CIRCUIT_BREAKER_MAX_ENTRIES) {;_class3.prototype.__init5.call(this);
1128
1247
  if (!Number.isInteger(maxEntries) || maxEntries <= 0) {
1129
1248
  throw new TypeError(`InMemoryCircuitBreakerStore maxEntries must be a positive integer (got ${String(maxEntries)})`);
1130
1249
  }
@@ -1159,7 +1278,7 @@ var InMemoryCircuitBreakerStore = (_class2 = class {
1159
1278
  clear() {
1160
1279
  this.states.clear();
1161
1280
  }
1162
- }, _class2);
1281
+ }, _class3);
1163
1282
  var defaultStore;
1164
1283
  function defaultCircuitBreakerStore() {
1165
1284
  if (defaultStore === void 0) defaultStore = new InMemoryCircuitBreakerStore();
@@ -1189,10 +1308,10 @@ var DEFAULT_COOLDOWN_DEFAULT_MS = 6e4;
1189
1308
  var DEFAULT_COOLDOWN_MAX_ENTRIES = 1024;
1190
1309
  var THREAD_THRESHOLD_MAX_MS = 1e4;
1191
1310
  var THREAD_THRESHOLD_DEFAULT_MS = 5e3;
1192
- var InMemoryCooldownStore = (_class3 = class {
1311
+ var InMemoryCooldownStore = (_class4 = class {
1193
1312
 
1194
- __init4() {this.deadlines = /* @__PURE__ */ new Map()}
1195
- constructor(maxEntries = DEFAULT_COOLDOWN_MAX_ENTRIES) {;_class3.prototype.__init4.call(this);
1313
+ __init6() {this.deadlines = /* @__PURE__ */ new Map()}
1314
+ constructor(maxEntries = DEFAULT_COOLDOWN_MAX_ENTRIES) {;_class4.prototype.__init6.call(this);
1196
1315
  if (!Number.isInteger(maxEntries) || maxEntries <= 0) {
1197
1316
  throw new TypeError(`InMemoryCooldownStore maxEntries must be a positive integer (got ${String(maxEntries)})`);
1198
1317
  }
@@ -1226,7 +1345,7 @@ var InMemoryCooldownStore = (_class3 = class {
1226
1345
  clear() {
1227
1346
  this.deadlines.clear();
1228
1347
  }
1229
- }, _class3);
1348
+ }, _class4);
1230
1349
  var defaultStore2;
1231
1350
  function defaultCooldownStore() {
1232
1351
  if (defaultStore2 === void 0) defaultStore2 = new InMemoryCooldownStore();
@@ -1247,111 +1366,6 @@ function cooldownDurationMs(retryAfterSecs, opts) {
1247
1366
  return Math.min(rawMs, opts.maxMs);
1248
1367
  }
1249
1368
 
1250
- // src/cache.ts
1251
- var READ_CACHE_MAX_ENTRIES = 4096;
1252
- var ReadCache = (_class4 = class {
1253
- /** The configured TTL in ms (the fallback for resources without an override). */
1254
-
1255
- /** The per-resource TTL overrides (issue #32; absent = every resource uses `ttlMs`). */
1256
-
1257
- __init5() {this.store = /* @__PURE__ */ new Map()}
1258
- __init6() {this.epochCounter = 0}
1259
- constructor(ttlMs, perResourceTtlMs) {;_class4.prototype.__init5.call(this);_class4.prototype.__init6.call(this);
1260
- if (!Number.isInteger(ttlMs) || ttlMs <= 0) {
1261
- throw new AutotaskConfigError(`cache.ttlMs must be a positive integer (got ${ttlMs})`);
1262
- }
1263
- if (perResourceTtlMs !== void 0) {
1264
- if (perResourceTtlMs === null || typeof perResourceTtlMs !== "object" || Array.isArray(perResourceTtlMs)) {
1265
- throw new AutotaskConfigError(
1266
- `cache.perResourceTtlMs must be an object of resource key -> ms (got ${String(perResourceTtlMs)})`
1267
- );
1268
- }
1269
- for (const [key, value] of Object.entries(perResourceTtlMs)) {
1270
- if (key === "") {
1271
- throw new AutotaskConfigError("cache.perResourceTtlMs keys must be non-empty resource keys");
1272
- }
1273
- if (!Number.isInteger(value) || value <= 0) {
1274
- throw new AutotaskConfigError(
1275
- `cache.perResourceTtlMs.${key} must be a positive integer (got ${String(value)})`
1276
- );
1277
- }
1278
- }
1279
- }
1280
- this.ttlMs = ttlMs;
1281
- this.perResourceTtlMs = perResourceTtlMs;
1282
- }
1283
- /**
1284
- * The TTL (ms) for a resource plan key: the `perResourceTtlMs` override
1285
- * when the map is present and names the resource, else the base
1286
- * `ttlMs` (absent map, absent key, and `undefined` all fall back).
1287
- */
1288
- ttlFor(resource) {
1289
- if (resource !== void 0 && this.perResourceTtlMs !== void 0) {
1290
- const override = this.perResourceTtlMs[resource];
1291
- if (override !== void 0) return override;
1292
- }
1293
- return this.ttlMs;
1294
- }
1295
- /**
1296
- * Read-through lookup: the live entry's value, or `undefined` (absent OR
1297
- * expired — an expired entry is purged lazily on this read).
1298
- */
1299
- get(key) {
1300
- const entry = this.store.get(key);
1301
- if (entry === void 0) return void 0;
1302
- if (entry.expiresAt <= Date.now()) {
1303
- this.store.delete(key);
1304
- return void 0;
1305
- }
1306
- return structuredClone(entry.value);
1307
- }
1308
- /** Store a successful read payload under `key`, live for `ttlFor(resource)`:
1309
- * the per-resource override (issue #32) when named, else `ttlMs`.
1310
- * `epoch` is the invalidation epoch the caller captured BEFORE its wire
1311
- * read: a read that straddled a `clear()` (a write) is dropped, never
1312
- * re-stored with its pre-write body. */
1313
- set(key, value, resource, epoch = this.epochCounter) {
1314
- if (epoch !== this.epochCounter) return;
1315
- if (this.store.size >= READ_CACHE_MAX_ENTRIES && this.purgeExpired() === 0) {
1316
- const oldest = this.store.keys().next();
1317
- if (!oldest.done) this.store.delete(oldest.value);
1318
- }
1319
- this.store.delete(key);
1320
- this.store.set(key, { value: structuredClone(value), expiresAt: Date.now() + this.ttlFor(resource) });
1321
- }
1322
- /** Drop every expired entry (returns the number removed). */
1323
- purgeExpired() {
1324
- const now = Date.now();
1325
- let removed = 0;
1326
- for (const [key, entry] of this.store) {
1327
- if (entry.expiresAt <= now) {
1328
- this.store.delete(key);
1329
- removed += 1;
1330
- }
1331
- }
1332
- return removed;
1333
- }
1334
- /** Current entry count (live + not-yet-purged expired). */
1335
- get size() {
1336
- return this.store.size;
1337
- }
1338
- /** Drop one key (issue #36: a later positive outcome clears a stale 'absent' marker). */
1339
- delete(key) {
1340
- return this.store.delete(key);
1341
- }
1342
- /** The invalidation epoch: bumped by `clear()`; capture it before a wire
1343
- * read and pass it to `set` so a read in flight across a write cannot
1344
- * re-store its stale answer. */
1345
- get epoch() {
1346
- return this.epochCounter;
1347
- }
1348
- /** Drop everything (e.g. a caller that knows the tenant was reset). */
1349
- clear() {
1350
- this.epochCounter += 1;
1351
- this.store.clear();
1352
- }
1353
- }, _class4);
1354
-
1355
1369
  // src/resourceNameCache.ts
1356
1370
  var RESOURCE_NAME_CACHE_MAX_ENTRIES = 1024;
1357
1371
  var RESOURCE_NAME_CACHE_BLIND_TTL_MS = 6e4;
@@ -1835,22 +1849,41 @@ function resolveResolution(config, agent) {
1835
1849
  }
1836
1850
  function resolveCaches(config) {
1837
1851
  const cacheBlock = config.cache === false || config.cache === void 0 ? void 0 : config.cache;
1852
+ resolveReadCacheStore(cacheBlock);
1838
1853
  const fieldCacheBlock = config.fieldCache === false || config.fieldCache === void 0 ? void 0 : config.fieldCache;
1839
1854
  const resourceNameCacheBlock = config.resourceNameCache === false || config.resourceNameCache === void 0 ? void 0 : config.resourceNameCache;
1840
- const readCache = config.cache === false ? void 0 : new ReadCache(
1841
- _nullishCoalesce(_optionalChain([cacheBlock, 'optionalAccess', _41 => _41.ttlMs]), () => ( DEFAULT_READ_CACHE_TTL_MS)),
1842
- { ...DEFAULT_PER_RESOURCE_TTL_MS, ..._optionalChain([cacheBlock, 'optionalAccess', _42 => _42.perResourceTtlMs]) }
1843
- );
1855
+ const readCache = config.cache === false ? void 0 : _nullishCoalesce(_optionalChain([cacheBlock, 'optionalAccess', _41 => _41.store]), () => ( buildReadCache(config)));
1844
1856
  const fieldCache = config.fieldCache === false ? void 0 : new FieldCache(
1845
- _nullishCoalesce(_optionalChain([fieldCacheBlock, 'optionalAccess', _43 => _43.ttlMs]), () => ( DEFAULT_FIELD_CACHE_TTL_MS)),
1846
- _nullishCoalesce(_optionalChain([fieldCacheBlock, 'optionalAccess', _44 => _44.maxEntities]), () => ( FIELD_CACHE_MAX_ENTITIES))
1857
+ _nullishCoalesce(_optionalChain([fieldCacheBlock, 'optionalAccess', _42 => _42.ttlMs]), () => ( DEFAULT_FIELD_CACHE_TTL_MS)),
1858
+ _nullishCoalesce(_optionalChain([fieldCacheBlock, 'optionalAccess', _43 => _43.maxEntities]), () => ( FIELD_CACHE_MAX_ENTITIES))
1847
1859
  );
1848
1860
  const resourceNameCache = config.resourceNameCache === false ? void 0 : new ResourceNameCache(
1849
- _nullishCoalesce(_optionalChain([resourceNameCacheBlock, 'optionalAccess', _45 => _45.ttlMs]), () => ( DEFAULT_RESOURCE_NAME_CACHE_TTL_MS)),
1850
- _nullishCoalesce(_optionalChain([resourceNameCacheBlock, 'optionalAccess', _46 => _46.maxEntries]), () => ( RESOURCE_NAME_CACHE_MAX_ENTRIES))
1861
+ _nullishCoalesce(_optionalChain([resourceNameCacheBlock, 'optionalAccess', _44 => _44.ttlMs]), () => ( DEFAULT_RESOURCE_NAME_CACHE_TTL_MS)),
1862
+ _nullishCoalesce(_optionalChain([resourceNameCacheBlock, 'optionalAccess', _45 => _45.maxEntries]), () => ( RESOURCE_NAME_CACHE_MAX_ENTRIES))
1851
1863
  );
1852
1864
  return { readCache, fieldCache, resourceNameCache };
1853
1865
  }
1866
+ function resolveReadCacheStore(cacheBlock) {
1867
+ if (cacheBlock === void 0 || cacheBlock === false || cacheBlock.store === void 0) return;
1868
+ if (!(cacheBlock.store instanceof ReadCache)) {
1869
+ throw new AutotaskConfigError(
1870
+ "cache.store must be a ReadCache instance (import { ReadCache } from the SDK; the pool supplies its own)"
1871
+ );
1872
+ }
1873
+ if (cacheBlock.ttlMs !== void 0 || cacheBlock.perResourceTtlMs !== void 0) {
1874
+ throw new AutotaskConfigError(
1875
+ "cache.store cannot be combined with cache.ttlMs or cache.perResourceTtlMs \u2014 the supplied ReadCache instance owns its TTLs"
1876
+ );
1877
+ }
1878
+ }
1879
+ function buildReadCache(config) {
1880
+ if (config.cache === false) return void 0;
1881
+ const cacheBlock = config.cache === void 0 ? void 0 : config.cache;
1882
+ return new ReadCache(
1883
+ _nullishCoalesce(_optionalChain([cacheBlock, 'optionalAccess', _46 => _46.ttlMs]), () => ( DEFAULT_READ_CACHE_TTL_MS)),
1884
+ { ...DEFAULT_PER_RESOURCE_TTL_MS, ..._optionalChain([cacheBlock, 'optionalAccess', _47 => _47.perResourceTtlMs]) }
1885
+ );
1886
+ }
1854
1887
  function resolveConfig(config) {
1855
1888
  if (config === null || typeof config !== "object") {
1856
1889
  throw new AutotaskConfigError("AutotaskConfig is required");
@@ -1866,12 +1899,12 @@ function resolveConfig(config) {
1866
1899
  const resolution = resolveResolution(config, agent);
1867
1900
  const redactPersonalData = _nullishCoalesce(config.redactPersonalData, () => ( true));
1868
1901
  const caches = resolveCaches(config);
1869
- const update = { putFallback: _optionalChain([config, 'access', _47 => _47.update, 'optionalAccess', _48 => _48.putFallback]) === true };
1902
+ const update = { putFallback: _optionalChain([config, 'access', _48 => _48.update, 'optionalAccess', _49 => _49.putFallback]) === true };
1870
1903
  const reResolveZoneOn401 = config.reResolveZoneOn401 === true;
1871
1904
  const logger = _nullishCoalesce(config.logger, () => ( NoopLogger));
1872
1905
  if (credentials.baseUrl.startsWith("http:")) {
1873
1906
  const host = new URL(credentials.baseUrl).host;
1874
- _optionalChain([logger, 'access', _49 => _49.warn, 'optionalCall', _50 => _50(
1907
+ _optionalChain([logger, 'access', _50 => _50.warn, 'optionalCall', _51 => _51(
1875
1908
  `[autotask] cleartext credentials to ${host} \u2014 https recommended (baseUrl uses http:; all catalog zones are https)`
1876
1909
  )]);
1877
1910
  }
@@ -1952,7 +1985,7 @@ function parseIdentifier(value, label = "id") {
1952
1985
  return parsed;
1953
1986
  }
1954
1987
  function flattenUdfs(record, options) {
1955
- const prefix = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _51 => _51.prefix]), () => ( "udf_"));
1988
+ const prefix = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _52 => _52.prefix]), () => ( "udf_"));
1956
1989
  const out = { ...record };
1957
1990
  const udfs = record.userDefinedFields;
1958
1991
  if (!Array.isArray(udfs)) return out;
@@ -2355,6 +2388,52 @@ var RELATIONSHIP_MAP = {
2355
2388
  "deleteBoundary": null,
2356
2389
  "markerField": null
2357
2390
  },
2391
+ "billing_item_approval_levels": {
2392
+ "resource": "billing_item_approval_levels",
2393
+ "apiEntity": "BillingItemApprovalLevel",
2394
+ "kind": "entity",
2395
+ "path": "BillingItemApprovalLevels",
2396
+ "parentScoped": false,
2397
+ "tier": "extended",
2398
+ "workflowResource": false,
2399
+ "group": "B",
2400
+ "parent": null,
2401
+ "children": [],
2402
+ "naturalKeys": {
2403
+ "hasSearch": false,
2404
+ "searchCovers": null,
2405
+ "findBy": []
2406
+ },
2407
+ "blindSurfaces": null,
2408
+ "zoneFacts": {
2409
+ "createGuidance": {
2410
+ "createOp": "billing_item_approval_levels.create",
2411
+ "parentScoped": false,
2412
+ "liveProvenPrefix": [],
2413
+ "unproven": true,
2414
+ "blocker": {
2415
+ "kind": "unknown",
2416
+ "message": "never live-probed: this entity reached the plan on 2026-10-26 (feat/time-entry-approve) after the stage-11 apply matrix closed, so no create has been attempted against a tenant. The vendor documents the conditions (timeEntryID and approvalResourceID must reference existing objects) and the side effect (TimeEntry.BillingApprovalLevelMostRecent is updated; approvalDateTime / approvalResourceID are not), but the acceptance of the model body is unverified.",
2417
+ "remedy": "attempt one create against a time entry in a non-production tenant (dry-run first), then promote createGuidance to kind ok with its liveProvenPrefix; a refusal arrives as a vendor 500 whose errors[] text names the failing field."
2418
+ },
2419
+ "vendorEvidence": [
2420
+ 'Vendor help, BillingItemApprovalLevels entity page (fetched 2026-10-26): "describes a multi-level approval record for an Autotask time entry ... This option is only available through the REST API."',
2421
+ 'Vendor help, BillingItemApprovalLevels entity page (fetched 2026-10-26): "When the BillingItemApprovalLevels entity is created, the TimeEntry.BillingApprovalLevelMostRecent field is updated, but approvalDateTime and approvalResourceID are not. Instead, the approvalDateTime and approvalResourceID fields are editable on the TimeEntry entity. Workaround: ... create the BillingItemApprovalLevel and then follow that call up with an update to the TimeEntry to set the BillingApprovalDateTime and BillingApprovalResourceID fields."',
2422
+ "api-docs.json: POST /V1.0/BillingItemApprovalLevels consumes definitions.BillingItemApprovalLevelModel and answers OperationResultModel \u2014 the entity defines no PUT, PATCH or DELETE path."
2423
+ ],
2424
+ "deleteBoundary": {
2425
+ "available": false,
2426
+ "note": "the vendor defines no DELETE for billing_item_approval_levels (spec-derived) \u2014 an approval level cannot be removed or corrected through the API; record cleanup is UI-only."
2427
+ },
2428
+ "zone": "ww29"
2429
+ }
2430
+ },
2431
+ "deleteBoundary": {
2432
+ "note": "the vendor defines no DELETE for billing_item_approval_levels (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 an approval level cannot be removed or corrected through the API; record cleanup is UI-only.",
2433
+ "proof": "spec-derived"
2434
+ },
2435
+ "markerField": null
2436
+ },
2358
2437
  "billing_items": {
2359
2438
  "resource": "billing_items",
2360
2439
  "apiEntity": "BillingItems",
@@ -5078,8 +5157,8 @@ var RELATIONSHIP_MAP = {
5078
5157
  "unproven": false,
5079
5158
  "blocker": {
5080
5159
  "kind": "ok",
5081
- "message": "live-PROVEN 2026-10-06 (confirm-100, marker CONF100-1791187382): the W-A6 'blind parent' was companyID \u2014 an OWNED company satisfies it (seed 30132785). Proven contractType values: 1, 3 (Fixed Price), 4 (Block hours), 6 (Retainer), 7 (Recurring Services), 8 (PerTicket incident); type 5 is an invalid picklist value. Type-specific extra fields: types 1/3/4/6/8 require estimatedRevenue (type 1 additionally estimatedHours + estimatedCost); type 7 additionally contractPeriodType (2 valid) + setupFee. Proven ids 30131842-30131847 (residue \u2014 no vendor DELETE for contracts).",
5082
- "remedy": "live-proven on ww29 2026-10-06 (confirm-100, marker CONF100-1791187382) \u2014 use the proven body / type gates from the message; residue records are ledgered (.run/confirm-100-20261006/CONFIRMATION-LEDGER.md section E; UI cleanup)"
5160
+ "message": "live-PROVEN 2026-10-06 (confirm-100, marker CONF100-1791187382): the W-A6 'blind parent' was companyID \u2014 an OWNED company satisfies it (seed 30132785). Proven contractType values: 1, 3 (Fixed Price), 4 (Block hours), 6 (Retainer), 7 (Recurring Services), 8 (PerTicket incident). The type-conditioned field gates are declared in requiresByValue / rejectedValues on this row (issue #219 N3) \u2014 they are no longer restated in prose here. Proven ids 30131842-30131847 (residue \u2014 no vendor DELETE for contracts).",
5161
+ "remedy": "live-proven on ww29 2026-10-06 (confirm-100, marker CONF100-1791187382) \u2014 send the body with the contractType you need and satisfy that value's requiresByValue gate (plus the contractPeriodType value it names); residue records are ledgered (.run/confirm-100-20261006/CONFIRMATION-LEDGER.md section E; UI cleanup)"
5083
5162
  },
5084
5163
  "vendorEvidence": [
5085
5164
  '{"error":true,"code":"SERVER_ERROR","category":"server","retryable":true,"httpStatus":500,"operation":"contracts.create","suggestedAction":"Retry with backoff; the server error is transient.","correlationId":"25d4a730-6d6c-49ff-a038-96d3fd09165d","message":"Value does not exist for the required fiel',
@@ -5089,7 +5168,75 @@ var RELATIONSHIP_MAP = {
5089
5168
  "available": false,
5090
5169
  "note": "the vendor defines no DELETE for contracts (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only."
5091
5170
  },
5092
- "zone": "ww29"
5171
+ "zone": "ww29",
5172
+ "requiresByValue": [
5173
+ {
5174
+ "field": "contractType",
5175
+ "value": 1,
5176
+ "requires": {
5177
+ "allOf": [
5178
+ "estimatedRevenue",
5179
+ "estimatedHours",
5180
+ "estimatedCost"
5181
+ ]
5182
+ }
5183
+ },
5184
+ {
5185
+ "field": "contractType",
5186
+ "value": 3,
5187
+ "requires": {
5188
+ "allOf": [
5189
+ "estimatedRevenue"
5190
+ ]
5191
+ }
5192
+ },
5193
+ {
5194
+ "field": "contractType",
5195
+ "value": 4,
5196
+ "requires": {
5197
+ "allOf": [
5198
+ "estimatedRevenue"
5199
+ ]
5200
+ }
5201
+ },
5202
+ {
5203
+ "field": "contractType",
5204
+ "value": 6,
5205
+ "requires": {
5206
+ "allOf": [
5207
+ "estimatedRevenue"
5208
+ ]
5209
+ }
5210
+ },
5211
+ {
5212
+ "field": "contractType",
5213
+ "value": 7,
5214
+ "requires": {
5215
+ "allOf": [
5216
+ "contractPeriodType",
5217
+ "setupFee"
5218
+ ]
5219
+ },
5220
+ "values": {
5221
+ "contractPeriodType": 2
5222
+ }
5223
+ },
5224
+ {
5225
+ "field": "contractType",
5226
+ "value": 8,
5227
+ "requires": {
5228
+ "allOf": [
5229
+ "estimatedRevenue"
5230
+ ]
5231
+ }
5232
+ }
5233
+ ],
5234
+ "rejectedValues": [
5235
+ {
5236
+ "field": "contractType",
5237
+ "value": 5
5238
+ }
5239
+ ]
5093
5240
  }
5094
5241
  },
5095
5242
  "deleteBoundary": {
@@ -5527,6 +5674,27 @@ var RELATIONSHIP_MAP = {
5527
5674
  "deleteBoundary": null,
5528
5675
  "markerField": null
5529
5676
  },
5677
+ "invoice_templates": {
5678
+ "resource": "invoice_templates",
5679
+ "apiEntity": "InvoiceTemplate",
5680
+ "kind": "entity",
5681
+ "path": "InvoiceTemplates",
5682
+ "parentScoped": false,
5683
+ "tier": "advanced",
5684
+ "workflowResource": false,
5685
+ "group": "B",
5686
+ "parent": null,
5687
+ "children": [],
5688
+ "naturalKeys": {
5689
+ "hasSearch": false,
5690
+ "searchCovers": null,
5691
+ "findBy": []
5692
+ },
5693
+ "blindSurfaces": null,
5694
+ "zoneFacts": null,
5695
+ "deleteBoundary": null,
5696
+ "markerField": null
5697
+ },
5530
5698
  "invoices": {
5531
5699
  "resource": "invoices",
5532
5700
  "apiEntity": "Invoice",
@@ -5717,6 +5885,138 @@ var RELATIONSHIP_MAP = {
5717
5885
  "deleteBoundary": null,
5718
5886
  "markerField": null
5719
5887
  },
5888
+ "organizational_level1s": {
5889
+ "resource": "organizational_level1s",
5890
+ "apiEntity": "OrganizationalLevel1",
5891
+ "kind": "entity",
5892
+ "path": "OrganizationalLevel1s",
5893
+ "parentScoped": false,
5894
+ "tier": "advanced",
5895
+ "workflowResource": false,
5896
+ "group": "B",
5897
+ "parent": null,
5898
+ "children": [],
5899
+ "naturalKeys": {
5900
+ "hasSearch": false,
5901
+ "searchCovers": null,
5902
+ "findBy": []
5903
+ },
5904
+ "blindSurfaces": null,
5905
+ "zoneFacts": {
5906
+ "createGuidance": {
5907
+ "createOp": "organizational_level1s.create",
5908
+ "parentScoped": false,
5909
+ "liveProvenPrefix": [],
5910
+ "unproven": true,
5911
+ "blocker": {
5912
+ "kind": "unknown",
5913
+ "message": "never live-probed: this entity reached the plan on 2026-10-26 (feat/guidance-contract-027) after the stage-11 apply matrix closed, so no create has been attempted against a tenant. The vendor documents the model body (definitions.OrganizationalLevel1Model) and answers OperationResultModel, but acceptance of the body is unverified; the spec defines no DELETE on the entity's paths.",
5914
+ "remedy": "attempt one create against a non-production tenant (dry-run first), then promote createGuidance to kind ok with its liveProvenPrefix; a refusal arrives as a vendor 500 whose errors[] text names the failing field."
5915
+ },
5916
+ "vendorEvidence": [
5917
+ "api-docs.json: POST /V1.0/OrganizationalLevel1s consumes definitions.OrganizationalLevel1Model and answers OperationResultModel \u2014 the entity defines no DELETE path."
5918
+ ],
5919
+ "deleteBoundary": {
5920
+ "available": false,
5921
+ "note": "the vendor defines no DELETE for organizational_level1s (spec-derived) \u2014 a record cannot be removed or corrected through the API; cleanup is UI-only."
5922
+ },
5923
+ "zone": "ww29"
5924
+ }
5925
+ },
5926
+ "deleteBoundary": {
5927
+ "note": "the vendor defines no DELETE for organizational_level1s (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only.",
5928
+ "proof": "spec-derived"
5929
+ },
5930
+ "markerField": null
5931
+ },
5932
+ "organizational_level2s": {
5933
+ "resource": "organizational_level2s",
5934
+ "apiEntity": "OrganizationalLevel2",
5935
+ "kind": "entity",
5936
+ "path": "OrganizationalLevel2s",
5937
+ "parentScoped": false,
5938
+ "tier": "advanced",
5939
+ "workflowResource": false,
5940
+ "group": "B",
5941
+ "parent": null,
5942
+ "children": [],
5943
+ "naturalKeys": {
5944
+ "hasSearch": false,
5945
+ "searchCovers": null,
5946
+ "findBy": []
5947
+ },
5948
+ "blindSurfaces": null,
5949
+ "zoneFacts": {
5950
+ "createGuidance": {
5951
+ "createOp": "organizational_level2s.create",
5952
+ "parentScoped": false,
5953
+ "liveProvenPrefix": [],
5954
+ "unproven": true,
5955
+ "blocker": {
5956
+ "kind": "unknown",
5957
+ "message": "never live-probed: this entity reached the plan on 2026-10-26 (feat/guidance-contract-027) after the stage-11 apply matrix closed, so no create has been attempted against a tenant. The vendor documents the model body (definitions.OrganizationalLevel2Model) and answers OperationResultModel, but acceptance of the body is unverified; the spec defines no DELETE on the entity's paths.",
5958
+ "remedy": "attempt one create against a non-production tenant (dry-run first), then promote createGuidance to kind ok with its liveProvenPrefix; a refusal arrives as a vendor 500 whose errors[] text names the failing field."
5959
+ },
5960
+ "vendorEvidence": [
5961
+ "api-docs.json: POST /V1.0/OrganizationalLevel2s consumes definitions.OrganizationalLevel2Model and answers OperationResultModel \u2014 the entity defines no DELETE path."
5962
+ ],
5963
+ "deleteBoundary": {
5964
+ "available": false,
5965
+ "note": "the vendor defines no DELETE for organizational_level2s (spec-derived) \u2014 a record cannot be removed or corrected through the API; cleanup is UI-only."
5966
+ },
5967
+ "zone": "ww29"
5968
+ }
5969
+ },
5970
+ "deleteBoundary": {
5971
+ "note": "the vendor defines no DELETE for organizational_level2s (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only.",
5972
+ "proof": "spec-derived"
5973
+ },
5974
+ "markerField": null
5975
+ },
5976
+ "organizational_level_associations": {
5977
+ "resource": "organizational_level_associations",
5978
+ "apiEntity": "OrganizationalLevelAssociation",
5979
+ "kind": "entity",
5980
+ "path": "OrganizationalLevelAssociations",
5981
+ "parentScoped": false,
5982
+ "tier": "advanced",
5983
+ "workflowResource": false,
5984
+ "group": "B",
5985
+ "parent": null,
5986
+ "children": [],
5987
+ "naturalKeys": {
5988
+ "hasSearch": false,
5989
+ "searchCovers": null,
5990
+ "findBy": []
5991
+ },
5992
+ "blindSurfaces": null,
5993
+ "zoneFacts": {
5994
+ "createGuidance": {
5995
+ "createOp": "organizational_level_associations.create",
5996
+ "parentScoped": false,
5997
+ "liveProvenPrefix": [],
5998
+ "unproven": true,
5999
+ "blocker": {
6000
+ "kind": "unknown",
6001
+ "message": "never live-probed: this entity reached the plan on 2026-10-26 (feat/guidance-contract-027) after the stage-11 apply matrix closed, so no create has been attempted against a tenant. The vendor documents the model body (definitions.OrganizationalLevelAssociationModel) and answers OperationResultModel, but acceptance of the body is unverified; the spec defines no DELETE on the entity's paths.",
6002
+ "remedy": "attempt one create against a non-production tenant (dry-run first), then promote createGuidance to kind ok with its liveProvenPrefix; a refusal arrives as a vendor 500 whose errors[] text names the failing field."
6003
+ },
6004
+ "vendorEvidence": [
6005
+ "api-docs.json: POST /V1.0/OrganizationalLevelAssociations consumes definitions.OrganizationalLevelAssociationModel and answers OperationResultModel \u2014 the entity defines no DELETE path."
6006
+ ],
6007
+ "deleteBoundary": {
6008
+ "available": false,
6009
+ "note": "the vendor defines no DELETE for organizational_level_associations (spec-derived) \u2014 a record cannot be removed or corrected through the API; cleanup is UI-only."
6010
+ },
6011
+ "zone": "ww29"
6012
+ }
6013
+ },
6014
+ "deleteBoundary": {
6015
+ "note": "the vendor defines no DELETE for organizational_level_associations (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only.",
6016
+ "proof": "spec-derived"
6017
+ },
6018
+ "markerField": null
6019
+ },
5720
6020
  "product_vendors": {
5721
6021
  "resource": "product_vendors",
5722
6022
  "apiEntity": "ProductVendors",
@@ -5869,7 +6169,13 @@ var RELATIONSHIP_MAP = {
5869
6169
  "blocker": {
5870
6170
  "kind": "blind-parent",
5871
6171
  "message": "vendor 500 (stage-11 apply-matrix, marker FULL100W-1791110339): the create consumed the vendor field ladder and then failed on the parent reference \u2014 the parent table is blind (0 rows) for this API user, so no valid parent id exists to satisfy it (W-A6). The exact final vendor response is preserved verbatim in vendorEvidence (campaign receipt artifact, as recorded on disk).",
5872
- "remedy": "provision a parent record in the Autotask UI first \u2014 the projects table is blind (0 rows) for this API user (W-A6), so no valid parent id can be read back; then retry the create with the real parent id."
6172
+ "remedy": "provision a parent record in the Autotask UI first \u2014 the projects table is blind (0 rows) for this API user (W-A6), so no valid parent id can be read back; then retry the create with the real parent id.",
6173
+ "requires": {
6174
+ "anyOf": [
6175
+ "productID",
6176
+ "billingCodeID"
6177
+ ]
6178
+ }
5873
6179
  },
5874
6180
  "vendorEvidence": [
5875
6181
  '{"error":true,"code":"SERVER_ERROR","category":"server","retryable":true,"httpStatus":500,"operation":"project_charges.create","suggestedAction":"Retry with backoff; the server error is transient.","correlationId":"664ab2ea-408f-4834-a331-eb5dd55ac557","message":"A productID or a billingCodeID must '
@@ -6942,6 +7248,27 @@ var RELATIONSHIP_MAP = {
6942
7248
  },
6943
7249
  "markerField": "name"
6944
7250
  },
7251
+ "sales_orders": {
7252
+ "resource": "sales_orders",
7253
+ "apiEntity": "SalesOrder",
7254
+ "kind": "entity",
7255
+ "path": "SalesOrders",
7256
+ "parentScoped": false,
7257
+ "tier": "extended",
7258
+ "workflowResource": false,
7259
+ "group": "B",
7260
+ "parent": null,
7261
+ "children": [],
7262
+ "naturalKeys": {
7263
+ "hasSearch": false,
7264
+ "searchCovers": null,
7265
+ "findBy": []
7266
+ },
7267
+ "blindSurfaces": null,
7268
+ "zoneFacts": null,
7269
+ "deleteBoundary": null,
7270
+ "markerField": null
7271
+ },
6945
7272
  "service_call_task_resources": {
6946
7273
  "resource": "service_call_task_resources",
6947
7274
  "apiEntity": "ServiceCallTaskResource",
@@ -7577,20 +7904,61 @@ var RELATIONSHIP_MAP = {
7577
7904
  "deleteBoundary": null,
7578
7905
  "markerField": null
7579
7906
  },
7580
- "task_secondary_resources": {
7581
- "resource": "task_secondary_resources",
7582
- "apiEntity": "TaskSecondaryResource",
7907
+ "task_secondary_resources": {
7908
+ "resource": "task_secondary_resources",
7909
+ "apiEntity": "TaskSecondaryResource",
7910
+ "kind": "entity",
7911
+ "path": "TaskSecondaryResources",
7912
+ "parentScoped": true,
7913
+ "tier": "extended",
7914
+ "workflowResource": false,
7915
+ "group": "A",
7916
+ "parent": {
7917
+ "resource": "tasks",
7918
+ "segment": "SecondaryResources",
7919
+ "field": "taskID"
7920
+ },
7921
+ "children": [],
7922
+ "naturalKeys": {
7923
+ "hasSearch": false,
7924
+ "searchCovers": null,
7925
+ "findBy": []
7926
+ },
7927
+ "blindSurfaces": null,
7928
+ "zoneFacts": {
7929
+ "createGuidance": {
7930
+ "createOp": "task_secondary_resources.create",
7931
+ "parentScoped": true,
7932
+ "liveProvenPrefix": [],
7933
+ "unproven": true,
7934
+ "blocker": {
7935
+ "kind": "unknown",
7936
+ "message": "vendor 500: reference rejection on r (exact vendor text preserved verbatim in vendorEvidence \u2014 campaign receipt artifact, as recorded on disk)",
7937
+ "remedy": "the wall is opaque in the campaign record \u2014 inspect vendorEvidence for the exact vendor text, re-run the create with a live probe (dry-run first), and adjudicate against the vendored spec before retrying."
7938
+ },
7939
+ "vendorEvidence": [
7940
+ '{"error":true,"code":"SERVER_ERROR","category":"server","retryable":true,"httpStatus":500,"operation":"task_secondary_resources.create","suggestedAction":"Retry with backoff; the server error is transient.","correlationId":"d2783d1d-b23a-4c7d-9459-0089be7f9b0b","message":"Reference value on field: r'
7941
+ ],
7942
+ "deleteBoundary": {
7943
+ "available": true,
7944
+ "note": null
7945
+ },
7946
+ "zone": "ww29"
7947
+ }
7948
+ },
7949
+ "deleteBoundary": null,
7950
+ "markerField": null
7951
+ },
7952
+ "tax_regions": {
7953
+ "resource": "tax_regions",
7954
+ "apiEntity": "TaxRegion",
7583
7955
  "kind": "entity",
7584
- "path": "TaskSecondaryResources",
7585
- "parentScoped": true,
7586
- "tier": "extended",
7956
+ "path": "TaxRegions",
7957
+ "parentScoped": false,
7958
+ "tier": "advanced",
7587
7959
  "workflowResource": false,
7588
- "group": "A",
7589
- "parent": {
7590
- "resource": "tasks",
7591
- "segment": "SecondaryResources",
7592
- "field": "taskID"
7593
- },
7960
+ "group": "B",
7961
+ "parent": null,
7594
7962
  "children": [],
7595
7963
  "naturalKeys": {
7596
7964
  "hasSearch": false,
@@ -7600,26 +7968,29 @@ var RELATIONSHIP_MAP = {
7600
7968
  "blindSurfaces": null,
7601
7969
  "zoneFacts": {
7602
7970
  "createGuidance": {
7603
- "createOp": "task_secondary_resources.create",
7604
- "parentScoped": true,
7971
+ "createOp": "tax_regions.create",
7972
+ "parentScoped": false,
7605
7973
  "liveProvenPrefix": [],
7606
7974
  "unproven": true,
7607
7975
  "blocker": {
7608
7976
  "kind": "unknown",
7609
- "message": "vendor 500: reference rejection on r (exact vendor text preserved verbatim in vendorEvidence \u2014 campaign receipt artifact, as recorded on disk)",
7610
- "remedy": "the wall is opaque in the campaign record \u2014 inspect vendorEvidence for the exact vendor text, re-run the create with a live probe (dry-run first), and adjudicate against the vendored spec before retrying."
7977
+ "message": "never live-probed: this entity reached the plan on 2026-10-26 (feat/guidance-contract-027) after the stage-11 apply matrix closed, so no create has been attempted against a tenant. The vendor documents the model body (definitions.TaxRegionModel) and answers OperationResultModel, but acceptance of the body is unverified; the spec defines no DELETE on the entity's paths.",
7978
+ "remedy": "attempt one create against a non-production tenant (dry-run first), then promote createGuidance to kind ok with its liveProvenPrefix; a refusal arrives as a vendor 500 whose errors[] text names the failing field."
7611
7979
  },
7612
7980
  "vendorEvidence": [
7613
- '{"error":true,"code":"SERVER_ERROR","category":"server","retryable":true,"httpStatus":500,"operation":"task_secondary_resources.create","suggestedAction":"Retry with backoff; the server error is transient.","correlationId":"d2783d1d-b23a-4c7d-9459-0089be7f9b0b","message":"Reference value on field: r'
7981
+ "api-docs.json: POST /V1.0/TaxRegions consumes definitions.TaxRegionModel and answers OperationResultModel \u2014 the entity defines no DELETE path."
7614
7982
  ],
7615
7983
  "deleteBoundary": {
7616
- "available": true,
7617
- "note": null
7984
+ "available": false,
7985
+ "note": "the vendor defines no DELETE for tax_regions (spec-derived) \u2014 a record cannot be removed or corrected through the API; cleanup is UI-only."
7618
7986
  },
7619
7987
  "zone": "ww29"
7620
7988
  }
7621
7989
  },
7622
- "deleteBoundary": null,
7990
+ "deleteBoundary": {
7991
+ "note": "the vendor defines no DELETE for tax_regions (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only.",
7992
+ "proof": "spec-derived"
7993
+ },
7623
7994
  "markerField": null
7624
7995
  },
7625
7996
  "ticket_additional_configuration_items": {
@@ -7911,7 +8282,13 @@ var RELATIONSHIP_MAP = {
7911
8282
  "blocker": {
7912
8283
  "kind": "blind-parent",
7913
8284
  "message": "vendor 500 (stage-11 apply-matrix, marker FULL100W-1791110339): the create consumed the vendor field ladder and then failed on the parent reference \u2014 the parent table is blind (0 rows) for this API user, so no valid parent id exists to satisfy it (W-A6). The exact final vendor response is preserved verbatim in vendorEvidence (campaign receipt artifact, as recorded on disk).",
7914
- "remedy": "provision a parent record in the Autotask UI first \u2014 the tickets table is blind (0 rows) for this API user (W-A6), so no valid parent id can be read back; then retry the create with the real parent id."
8285
+ "remedy": "provision a parent record in the Autotask UI first \u2014 the tickets table is blind (0 rows) for this API user (W-A6), so no valid parent id can be read back; then retry the create with the real parent id.",
8286
+ "requires": {
8287
+ "anyOf": [
8288
+ "productID",
8289
+ "billingCodeID"
8290
+ ]
8291
+ }
7915
8292
  },
7916
8293
  "vendorEvidence": [
7917
8294
  '{"error":true,"code":"SERVER_ERROR","category":"server","retryable":true,"httpStatus":500,"operation":"ticket_charges.create","suggestedAction":"Retry with backoff; the server error is transient.","correlationId":"b9b6939b-ccc5-4e9d-9ea2-e2f47d064f63","message":"A productID or a billingCodeID must b'
@@ -8977,6 +9354,7 @@ var BLIND_SURFACE_STAMPS = {
8977
9354
  }
8978
9355
  };
8979
9356
  var DELETE_BOUNDARY_NOTES = {
9357
+ "billing_item_approval_levels": "the vendor defines no DELETE for billing_item_approval_levels (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 an approval level cannot be removed or corrected through the API; record cleanup is UI-only.",
8980
9358
  "companies": "the vendor defines no DELETE for companies (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only.",
8981
9359
  "company_notes": "the vendor defines no DELETE for company_notes (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only.",
8982
9360
  "configuration_item_categories": "the vendor defines no DELETE for configuration_item_categories (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only.",
@@ -9000,6 +9378,9 @@ var DELETE_BOUNDARY_NOTES = {
9000
9378
  "expense_items": "the vendor defines no DELETE for expense_items (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only.",
9001
9379
  "expense_reports": "the vendor defines no DELETE for expense_reports (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only.",
9002
9380
  "opportunities": "the vendor defines no DELETE for opportunities (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only.",
9381
+ "organizational_level1s": "the vendor defines no DELETE for organizational_level1s (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only.",
9382
+ "organizational_level2s": "the vendor defines no DELETE for organizational_level2s (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only.",
9383
+ "organizational_level_associations": "the vendor defines no DELETE for organizational_level_associations (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only.",
9003
9384
  "phases": "the vendor defines no DELETE for phases (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only.",
9004
9385
  "product_vendors": "the vendor defines no DELETE for product_vendors (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only.",
9005
9386
  "products": "the vendor defines no DELETE for products (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only.",
@@ -9014,6 +9395,7 @@ var DELETE_BOUNDARY_NOTES = {
9014
9395
  "roles": "the vendor defines no DELETE for roles (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only.",
9015
9396
  "services": "the vendor defines no DELETE for services (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only.",
9016
9397
  "tasks": "the vendor defines no DELETE for tasks (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only.",
9398
+ "tax_regions": "the vendor defines no DELETE for tax_regions (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only.",
9017
9399
  "ticket_checklist_libraries": "the vendor defines no DELETE for ticket_checklist_libraries (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only.",
9018
9400
  "ticket_notes": "the vendor defines no DELETE for ticket_notes (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only.",
9019
9401
  "tickets": "the vendor defines no DELETE for tickets (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only."
@@ -10515,6 +10897,18 @@ var BLIND_SURFACE_INVENTORY = {
10515
10897
  "note": "billing_codes count/query are pinned blind in this zone (plan.blindSurfaces pin, byte-identical sentinel) \u2014 the discovery sweep confirmed 0 rows unfiltered (limit-2 read, marker FULL100-SEED-1791096521); get(id) is the authority.",
10516
10898
  "proof": "live-verified"
10517
10899
  },
10900
+ {
10901
+ "resource": "billing_item_approval_levels",
10902
+ "ops": [
10903
+ "count",
10904
+ "query"
10905
+ ],
10906
+ "kind": "unknown",
10907
+ "unfilteredRows": null,
10908
+ "authority": "billing_item_approval_levels.get",
10909
+ "note": "billing_item_approval_levels was added to the plan on 2026-10-26 (feat/time-entry-approve) and has NEVER been swept \u2014 no discovery read has run against this zone, so the surface is unverified, not blind. get(id) is the authority for a specific record; query by timeEntryID is the intended read.",
10910
+ "proof": "spec-derived"
10911
+ },
10518
10912
  {
10519
10913
  "resource": "billing_items",
10520
10914
  "ops": [
@@ -11175,6 +11569,18 @@ var BLIND_SURFACE_INVENTORY = {
11175
11569
  "note": "ww29 discovery sweep (marker FULL100-SEED-1791096521, 2026-10-04): the unfiltered limit-2 read returned 1 row(s) \u2014 data-full for this API user (unfiltered reads are safe here; no blind class assigned).",
11176
11570
  "proof": "discovery-sweep"
11177
11571
  },
11572
+ {
11573
+ "resource": "invoice_templates",
11574
+ "ops": [
11575
+ "count",
11576
+ "query"
11577
+ ],
11578
+ "kind": "unknown",
11579
+ "unfilteredRows": null,
11580
+ "authority": "invoice_templates.get",
11581
+ "note": "invoice_templates was added to the plan on 2026-10-26 (feat/guidance-contract-027) and has NEVER been swept \u2014 no discovery read has run against this zone, so the surface is unverified, not blind. get(id) is the authority for a specific record.",
11582
+ "proof": "spec-derived"
11583
+ },
11178
11584
  {
11179
11585
  "resource": "invoices",
11180
11586
  "ops": [
@@ -11235,6 +11641,42 @@ var BLIND_SURFACE_INVENTORY = {
11235
11641
  "note": "ww29 discovery sweep (marker FULL100-SEED-1791096521, 2026-10-04): the unfiltered limit-2 read returned 2 row(s) \u2014 data-full for this API user (unfiltered reads are safe here; no blind class assigned).",
11236
11642
  "proof": "discovery-sweep"
11237
11643
  },
11644
+ {
11645
+ "resource": "organizational_level1s",
11646
+ "ops": [
11647
+ "count",
11648
+ "query"
11649
+ ],
11650
+ "kind": "unknown",
11651
+ "unfilteredRows": null,
11652
+ "authority": "organizational_level1s.get",
11653
+ "note": "organizational_level1s was added to the plan on 2026-10-26 (feat/guidance-contract-027) and has NEVER been swept \u2014 no discovery read has run against this zone, so the surface is unverified, not blind. get(id) is the authority for a specific record.",
11654
+ "proof": "spec-derived"
11655
+ },
11656
+ {
11657
+ "resource": "organizational_level2s",
11658
+ "ops": [
11659
+ "count",
11660
+ "query"
11661
+ ],
11662
+ "kind": "unknown",
11663
+ "unfilteredRows": null,
11664
+ "authority": "organizational_level2s.get",
11665
+ "note": "organizational_level2s was added to the plan on 2026-10-26 (feat/guidance-contract-027) and has NEVER been swept \u2014 no discovery read has run against this zone, so the surface is unverified, not blind. get(id) is the authority for a specific record.",
11666
+ "proof": "spec-derived"
11667
+ },
11668
+ {
11669
+ "resource": "organizational_level_associations",
11670
+ "ops": [
11671
+ "count",
11672
+ "query"
11673
+ ],
11674
+ "kind": "unknown",
11675
+ "unfilteredRows": null,
11676
+ "authority": "organizational_level_associations.get",
11677
+ "note": "organizational_level_associations was added to the plan on 2026-10-26 (feat/guidance-contract-027) and has NEVER been swept \u2014 no discovery read has run against this zone, so the surface is unverified, not blind. get(id) is the authority for a specific record.",
11678
+ "proof": "spec-derived"
11679
+ },
11238
11680
  {
11239
11681
  "resource": "phases",
11240
11682
  "ops": [
@@ -11475,6 +11917,18 @@ var BLIND_SURFACE_INVENTORY = {
11475
11917
  "note": "ww29 discovery sweep (marker FULL100-SEED-1791096521, 2026-10-04): the unfiltered limit-2 read returned 2 row(s) \u2014 data-full for this API user (unfiltered reads are safe here; no blind class assigned).",
11476
11918
  "proof": "discovery-sweep"
11477
11919
  },
11920
+ {
11921
+ "resource": "sales_orders",
11922
+ "ops": [
11923
+ "count",
11924
+ "query"
11925
+ ],
11926
+ "kind": "unknown",
11927
+ "unfilteredRows": null,
11928
+ "authority": "sales_orders.get",
11929
+ "note": "sales_orders was added to the plan on 2026-10-26 (feat/guidance-contract-027) and has NEVER been swept \u2014 no discovery read has run against this zone, so the surface is unverified, not blind. get(id) is the authority for a specific record.",
11930
+ "proof": "spec-derived"
11931
+ },
11478
11932
  {
11479
11933
  "resource": "service_call_task_resources",
11480
11934
  "ops": [
@@ -11679,6 +12133,18 @@ var BLIND_SURFACE_INVENTORY = {
11679
12133
  "note": "ww29 discovery sweep (marker FULL100-SEED-1791096521, 2026-10-04): the unfiltered limit-2 read returned 2 row(s) \u2014 data-full for this API user (unfiltered reads are safe here; no blind class assigned).",
11680
12134
  "proof": "discovery-sweep"
11681
12135
  },
12136
+ {
12137
+ "resource": "tax_regions",
12138
+ "ops": [
12139
+ "count",
12140
+ "query"
12141
+ ],
12142
+ "kind": "unknown",
12143
+ "unfilteredRows": null,
12144
+ "authority": "tax_regions.get",
12145
+ "note": "tax_regions was added to the plan on 2026-10-26 (feat/guidance-contract-027) and has NEVER been swept \u2014 no discovery read has run against this zone, so the surface is unverified, not blind. get(id) is the authority for a specific record.",
12146
+ "proof": "spec-derived"
12147
+ },
11682
12148
  {
11683
12149
  "resource": "ticket_additional_configuration_items",
11684
12150
  "ops": [
@@ -11897,7 +12363,7 @@ var BLIND_SURFACE_INVENTORY = {
11897
12363
  }
11898
12364
  ],
11899
12365
  "counts": {
11900
- "total": 117,
12366
+ "total": 124,
11901
12367
  "dataFull": 46,
11902
12368
  "blind": 69,
11903
12369
  "pinned": 6
@@ -11967,6 +12433,7 @@ var REACHABILITY_PROBE_DEFAULTS = {
11967
12433
  "defaultTargets": [
11968
12434
  "appointments",
11969
12435
  "billing_codes",
12436
+ "billing_item_approval_levels",
11970
12437
  "billing_items",
11971
12438
  "change_request_links",
11972
12439
  "classification_icons",
@@ -12002,8 +12469,12 @@ var REACHABILITY_PROBE_DEFAULTS = {
12002
12469
  "currencies",
12003
12470
  "expense_items",
12004
12471
  "expense_reports",
12472
+ "invoice_templates",
12005
12473
  "invoices",
12006
12474
  "notification_history",
12475
+ "organizational_level1s",
12476
+ "organizational_level2s",
12477
+ "organizational_level_associations",
12007
12478
  "product_vendors",
12008
12479
  "products",
12009
12480
  "project_charges",
@@ -12018,6 +12489,7 @@ var REACHABILITY_PROBE_DEFAULTS = {
12018
12489
  "resource_roles",
12019
12490
  "resource_skills",
12020
12491
  "resources",
12492
+ "sales_orders",
12021
12493
  "service_call_task_resources",
12022
12494
  "service_call_tasks",
12023
12495
  "service_call_ticket_resources",
@@ -12027,6 +12499,7 @@ var REACHABILITY_PROBE_DEFAULTS = {
12027
12499
  "skills",
12028
12500
  "subscription_periods",
12029
12501
  "subscriptions",
12502
+ "tax_regions",
12030
12503
  "ticket_change_request_approvals",
12031
12504
  "ticket_charges",
12032
12505
  "ticket_history",
@@ -12067,6 +12540,28 @@ var CREATE_GUIDANCE = {
12067
12540
  },
12068
12541
  "zone": "ww29"
12069
12542
  },
12543
+ {
12544
+ "resource": "billing_item_approval_levels",
12545
+ "createOp": "billing_item_approval_levels.create",
12546
+ "parentScoped": false,
12547
+ "liveProvenPrefix": [],
12548
+ "unproven": true,
12549
+ "blocker": {
12550
+ "kind": "unknown",
12551
+ "message": "never live-probed: this entity reached the plan on 2026-10-26 (feat/time-entry-approve) after the stage-11 apply matrix closed, so no create has been attempted against a tenant. The vendor documents the conditions (timeEntryID and approvalResourceID must reference existing objects) and the side effect (TimeEntry.BillingApprovalLevelMostRecent is updated; approvalDateTime / approvalResourceID are not), but the acceptance of the model body is unverified.",
12552
+ "remedy": "attempt one create against a time entry in a non-production tenant (dry-run first), then promote createGuidance to kind ok with its liveProvenPrefix; a refusal arrives as a vendor 500 whose errors[] text names the failing field."
12553
+ },
12554
+ "vendorEvidence": [
12555
+ 'Vendor help, BillingItemApprovalLevels entity page (fetched 2026-10-26): "describes a multi-level approval record for an Autotask time entry ... This option is only available through the REST API."',
12556
+ 'Vendor help, BillingItemApprovalLevels entity page (fetched 2026-10-26): "When the BillingItemApprovalLevels entity is created, the TimeEntry.BillingApprovalLevelMostRecent field is updated, but approvalDateTime and approvalResourceID are not. Instead, the approvalDateTime and approvalResourceID fields are editable on the TimeEntry entity. Workaround: ... create the BillingItemApprovalLevel and then follow that call up with an update to the TimeEntry to set the BillingApprovalDateTime and BillingApprovalResourceID fields."',
12557
+ "api-docs.json: POST /V1.0/BillingItemApprovalLevels consumes definitions.BillingItemApprovalLevelModel and answers OperationResultModel \u2014 the entity defines no PUT, PATCH or DELETE path."
12558
+ ],
12559
+ "deleteBoundary": {
12560
+ "available": false,
12561
+ "note": "the vendor defines no DELETE for billing_item_approval_levels (spec-derived) \u2014 an approval level cannot be removed or corrected through the API; record cleanup is UI-only."
12562
+ },
12563
+ "zone": "ww29"
12564
+ },
12070
12565
  {
12071
12566
  "resource": "change_request_links",
12072
12567
  "createOp": "change_request_links.create",
@@ -12998,8 +13493,8 @@ var CREATE_GUIDANCE = {
12998
13493
  "unproven": false,
12999
13494
  "blocker": {
13000
13495
  "kind": "ok",
13001
- "message": "live-PROVEN 2026-10-06 (confirm-100, marker CONF100-1791187382): the W-A6 'blind parent' was companyID \u2014 an OWNED company satisfies it (seed 30132785). Proven contractType values: 1, 3 (Fixed Price), 4 (Block hours), 6 (Retainer), 7 (Recurring Services), 8 (PerTicket incident); type 5 is an invalid picklist value. Type-specific extra fields: types 1/3/4/6/8 require estimatedRevenue (type 1 additionally estimatedHours + estimatedCost); type 7 additionally contractPeriodType (2 valid) + setupFee. Proven ids 30131842-30131847 (residue \u2014 no vendor DELETE for contracts).",
13002
- "remedy": "live-proven on ww29 2026-10-06 (confirm-100, marker CONF100-1791187382) \u2014 use the proven body / type gates from the message; residue records are ledgered (.run/confirm-100-20261006/CONFIRMATION-LEDGER.md section E; UI cleanup)"
13496
+ "message": "live-PROVEN 2026-10-06 (confirm-100, marker CONF100-1791187382): the W-A6 'blind parent' was companyID \u2014 an OWNED company satisfies it (seed 30132785). Proven contractType values: 1, 3 (Fixed Price), 4 (Block hours), 6 (Retainer), 7 (Recurring Services), 8 (PerTicket incident). The type-conditioned field gates are declared in requiresByValue / rejectedValues on this row (issue #219 N3) \u2014 they are no longer restated in prose here. Proven ids 30131842-30131847 (residue \u2014 no vendor DELETE for contracts).",
13497
+ "remedy": "live-proven on ww29 2026-10-06 (confirm-100, marker CONF100-1791187382) \u2014 send the body with the contractType you need and satisfy that value's requiresByValue gate (plus the contractPeriodType value it names); residue records are ledgered (.run/confirm-100-20261006/CONFIRMATION-LEDGER.md section E; UI cleanup)"
13003
13498
  },
13004
13499
  "vendorEvidence": [
13005
13500
  '{"error":true,"code":"SERVER_ERROR","category":"server","retryable":true,"httpStatus":500,"operation":"contracts.create","suggestedAction":"Retry with backoff; the server error is transient.","correlationId":"25d4a730-6d6c-49ff-a038-96d3fd09165d","message":"Value does not exist for the required fiel',
@@ -13009,7 +13504,75 @@ var CREATE_GUIDANCE = {
13009
13504
  "available": false,
13010
13505
  "note": "the vendor defines no DELETE for contracts (spec-derived: the vendored api-docs.json defines no DELETE on the entity's paths) \u2014 a create cannot be undone through the API; cleanup is UI-only."
13011
13506
  },
13012
- "zone": "ww29"
13507
+ "zone": "ww29",
13508
+ "requiresByValue": [
13509
+ {
13510
+ "field": "contractType",
13511
+ "value": 1,
13512
+ "requires": {
13513
+ "allOf": [
13514
+ "estimatedRevenue",
13515
+ "estimatedHours",
13516
+ "estimatedCost"
13517
+ ]
13518
+ }
13519
+ },
13520
+ {
13521
+ "field": "contractType",
13522
+ "value": 3,
13523
+ "requires": {
13524
+ "allOf": [
13525
+ "estimatedRevenue"
13526
+ ]
13527
+ }
13528
+ },
13529
+ {
13530
+ "field": "contractType",
13531
+ "value": 4,
13532
+ "requires": {
13533
+ "allOf": [
13534
+ "estimatedRevenue"
13535
+ ]
13536
+ }
13537
+ },
13538
+ {
13539
+ "field": "contractType",
13540
+ "value": 6,
13541
+ "requires": {
13542
+ "allOf": [
13543
+ "estimatedRevenue"
13544
+ ]
13545
+ }
13546
+ },
13547
+ {
13548
+ "field": "contractType",
13549
+ "value": 7,
13550
+ "requires": {
13551
+ "allOf": [
13552
+ "contractPeriodType",
13553
+ "setupFee"
13554
+ ]
13555
+ },
13556
+ "values": {
13557
+ "contractPeriodType": 2
13558
+ }
13559
+ },
13560
+ {
13561
+ "field": "contractType",
13562
+ "value": 8,
13563
+ "requires": {
13564
+ "allOf": [
13565
+ "estimatedRevenue"
13566
+ ]
13567
+ }
13568
+ }
13569
+ ],
13570
+ "rejectedValues": [
13571
+ {
13572
+ "field": "contractType",
13573
+ "value": 5
13574
+ }
13575
+ ]
13013
13576
  },
13014
13577
  {
13015
13578
  "resource": "departments",
@@ -13255,6 +13818,66 @@ var CREATE_GUIDANCE = {
13255
13818
  },
13256
13819
  "zone": "ww29"
13257
13820
  },
13821
+ {
13822
+ "resource": "organizational_level1s",
13823
+ "createOp": "organizational_level1s.create",
13824
+ "parentScoped": false,
13825
+ "liveProvenPrefix": [],
13826
+ "unproven": true,
13827
+ "blocker": {
13828
+ "kind": "unknown",
13829
+ "message": "never live-probed: this entity reached the plan on 2026-10-26 (feat/guidance-contract-027) after the stage-11 apply matrix closed, so no create has been attempted against a tenant. The vendor documents the model body (definitions.OrganizationalLevel1Model) and answers OperationResultModel, but acceptance of the body is unverified; the spec defines no DELETE on the entity's paths.",
13830
+ "remedy": "attempt one create against a non-production tenant (dry-run first), then promote createGuidance to kind ok with its liveProvenPrefix; a refusal arrives as a vendor 500 whose errors[] text names the failing field."
13831
+ },
13832
+ "vendorEvidence": [
13833
+ "api-docs.json: POST /V1.0/OrganizationalLevel1s consumes definitions.OrganizationalLevel1Model and answers OperationResultModel \u2014 the entity defines no DELETE path."
13834
+ ],
13835
+ "deleteBoundary": {
13836
+ "available": false,
13837
+ "note": "the vendor defines no DELETE for organizational_level1s (spec-derived) \u2014 a record cannot be removed or corrected through the API; cleanup is UI-only."
13838
+ },
13839
+ "zone": "ww29"
13840
+ },
13841
+ {
13842
+ "resource": "organizational_level2s",
13843
+ "createOp": "organizational_level2s.create",
13844
+ "parentScoped": false,
13845
+ "liveProvenPrefix": [],
13846
+ "unproven": true,
13847
+ "blocker": {
13848
+ "kind": "unknown",
13849
+ "message": "never live-probed: this entity reached the plan on 2026-10-26 (feat/guidance-contract-027) after the stage-11 apply matrix closed, so no create has been attempted against a tenant. The vendor documents the model body (definitions.OrganizationalLevel2Model) and answers OperationResultModel, but acceptance of the body is unverified; the spec defines no DELETE on the entity's paths.",
13850
+ "remedy": "attempt one create against a non-production tenant (dry-run first), then promote createGuidance to kind ok with its liveProvenPrefix; a refusal arrives as a vendor 500 whose errors[] text names the failing field."
13851
+ },
13852
+ "vendorEvidence": [
13853
+ "api-docs.json: POST /V1.0/OrganizationalLevel2s consumes definitions.OrganizationalLevel2Model and answers OperationResultModel \u2014 the entity defines no DELETE path."
13854
+ ],
13855
+ "deleteBoundary": {
13856
+ "available": false,
13857
+ "note": "the vendor defines no DELETE for organizational_level2s (spec-derived) \u2014 a record cannot be removed or corrected through the API; cleanup is UI-only."
13858
+ },
13859
+ "zone": "ww29"
13860
+ },
13861
+ {
13862
+ "resource": "organizational_level_associations",
13863
+ "createOp": "organizational_level_associations.create",
13864
+ "parentScoped": false,
13865
+ "liveProvenPrefix": [],
13866
+ "unproven": true,
13867
+ "blocker": {
13868
+ "kind": "unknown",
13869
+ "message": "never live-probed: this entity reached the plan on 2026-10-26 (feat/guidance-contract-027) after the stage-11 apply matrix closed, so no create has been attempted against a tenant. The vendor documents the model body (definitions.OrganizationalLevelAssociationModel) and answers OperationResultModel, but acceptance of the body is unverified; the spec defines no DELETE on the entity's paths.",
13870
+ "remedy": "attempt one create against a non-production tenant (dry-run first), then promote createGuidance to kind ok with its liveProvenPrefix; a refusal arrives as a vendor 500 whose errors[] text names the failing field."
13871
+ },
13872
+ "vendorEvidence": [
13873
+ "api-docs.json: POST /V1.0/OrganizationalLevelAssociations consumes definitions.OrganizationalLevelAssociationModel and answers OperationResultModel \u2014 the entity defines no DELETE path."
13874
+ ],
13875
+ "deleteBoundary": {
13876
+ "available": false,
13877
+ "note": "the vendor defines no DELETE for organizational_level_associations (spec-derived) \u2014 a record cannot be removed or corrected through the API; cleanup is UI-only."
13878
+ },
13879
+ "zone": "ww29"
13880
+ },
13258
13881
  {
13259
13882
  "resource": "phases",
13260
13883
  "createOp": "phases.create",
@@ -13336,7 +13959,13 @@ var CREATE_GUIDANCE = {
13336
13959
  "blocker": {
13337
13960
  "kind": "blind-parent",
13338
13961
  "message": "vendor 500 (stage-11 apply-matrix, marker FULL100W-1791110339): the create consumed the vendor field ladder and then failed on the parent reference \u2014 the parent table is blind (0 rows) for this API user, so no valid parent id exists to satisfy it (W-A6). The exact final vendor response is preserved verbatim in vendorEvidence (campaign receipt artifact, as recorded on disk).",
13339
- "remedy": "provision a parent record in the Autotask UI first \u2014 the projects table is blind (0 rows) for this API user (W-A6), so no valid parent id can be read back; then retry the create with the real parent id."
13962
+ "remedy": "provision a parent record in the Autotask UI first \u2014 the projects table is blind (0 rows) for this API user (W-A6), so no valid parent id can be read back; then retry the create with the real parent id.",
13963
+ "requires": {
13964
+ "anyOf": [
13965
+ "productID",
13966
+ "billingCodeID"
13967
+ ]
13968
+ }
13340
13969
  },
13341
13970
  "vendorEvidence": [
13342
13971
  '{"error":true,"code":"SERVER_ERROR","category":"server","retryable":true,"httpStatus":500,"operation":"project_charges.create","suggestedAction":"Retry with backoff; the server error is transient.","correlationId":"664ab2ea-408f-4834-a331-eb5dd55ac557","message":"A productID or a billingCodeID must '
@@ -13840,6 +14469,26 @@ var CREATE_GUIDANCE = {
13840
14469
  },
13841
14470
  "zone": "ww29"
13842
14471
  },
14472
+ {
14473
+ "resource": "tax_regions",
14474
+ "createOp": "tax_regions.create",
14475
+ "parentScoped": false,
14476
+ "liveProvenPrefix": [],
14477
+ "unproven": true,
14478
+ "blocker": {
14479
+ "kind": "unknown",
14480
+ "message": "never live-probed: this entity reached the plan on 2026-10-26 (feat/guidance-contract-027) after the stage-11 apply matrix closed, so no create has been attempted against a tenant. The vendor documents the model body (definitions.TaxRegionModel) and answers OperationResultModel, but acceptance of the body is unverified; the spec defines no DELETE on the entity's paths.",
14481
+ "remedy": "attempt one create against a non-production tenant (dry-run first), then promote createGuidance to kind ok with its liveProvenPrefix; a refusal arrives as a vendor 500 whose errors[] text names the failing field."
14482
+ },
14483
+ "vendorEvidence": [
14484
+ "api-docs.json: POST /V1.0/TaxRegions consumes definitions.TaxRegionModel and answers OperationResultModel \u2014 the entity defines no DELETE path."
14485
+ ],
14486
+ "deleteBoundary": {
14487
+ "available": false,
14488
+ "note": "the vendor defines no DELETE for tax_regions (spec-derived) \u2014 a record cannot be removed or corrected through the API; cleanup is UI-only."
14489
+ },
14490
+ "zone": "ww29"
14491
+ },
13843
14492
  {
13844
14493
  "resource": "ticket_additional_configuration_items",
13845
14494
  "createOp": "ticket_additional_configuration_items.create",
@@ -13945,7 +14594,13 @@ var CREATE_GUIDANCE = {
13945
14594
  "blocker": {
13946
14595
  "kind": "blind-parent",
13947
14596
  "message": "vendor 500 (stage-11 apply-matrix, marker FULL100W-1791110339): the create consumed the vendor field ladder and then failed on the parent reference \u2014 the parent table is blind (0 rows) for this API user, so no valid parent id exists to satisfy it (W-A6). The exact final vendor response is preserved verbatim in vendorEvidence (campaign receipt artifact, as recorded on disk).",
13948
- "remedy": "provision a parent record in the Autotask UI first \u2014 the tickets table is blind (0 rows) for this API user (W-A6), so no valid parent id can be read back; then retry the create with the real parent id."
14597
+ "remedy": "provision a parent record in the Autotask UI first \u2014 the tickets table is blind (0 rows) for this API user (W-A6), so no valid parent id can be read back; then retry the create with the real parent id.",
14598
+ "requires": {
14599
+ "anyOf": [
14600
+ "productID",
14601
+ "billingCodeID"
14602
+ ]
14603
+ }
13949
14604
  },
13950
14605
  "vendorEvidence": [
13951
14606
  '{"error":true,"code":"SERVER_ERROR","category":"server","retryable":true,"httpStatus":500,"operation":"ticket_charges.create","suggestedAction":"Retry with backoff; the server error is transient.","correlationId":"b9b6939b-ccc5-4e9d-9ea2-e2f47d064f63","message":"A productID or a billingCodeID must b'
@@ -14168,7 +14823,30 @@ var CREATE_GUIDANCE = {
14168
14823
  "available": true,
14169
14824
  "note": null
14170
14825
  },
14171
- "zone": "ww29"
14826
+ "zone": "ww29",
14827
+ "derived": [
14828
+ {
14829
+ "field": "hoursWorked",
14830
+ "rule": "elapsed(startDateTime,endDateTime)"
14831
+ },
14832
+ {
14833
+ "field": "timeEntryType",
14834
+ "rule": "parent"
14835
+ },
14836
+ {
14837
+ "field": "contractID",
14838
+ "rule": "parent"
14839
+ },
14840
+ {
14841
+ "field": "internalBillingCodeID",
14842
+ "rule": "mirror(billingCodeID)"
14843
+ },
14844
+ {
14845
+ "field": "billingApprovalLevelMostRecent",
14846
+ "rule": "external",
14847
+ "writableRoute": "billing_item_approval_levels.create"
14848
+ }
14849
+ ]
14172
14850
  },
14173
14851
  {
14174
14852
  "resource": "time_entry_attachments",
@@ -14197,7 +14875,7 @@ var CREATE_GUIDANCE = {
14197
14875
  }
14198
14876
  ],
14199
14877
  "counts": {
14200
- "total": 92,
14878
+ "total": 97,
14201
14879
  "byKind": {
14202
14880
  "ok": 31,
14203
14881
  "blind-reference": 16,
@@ -14207,7 +14885,7 @@ var CREATE_GUIDANCE = {
14207
14885
  "resource-role-pair": 2,
14208
14886
  "delete-absent": 8,
14209
14887
  "non-mutable": 0,
14210
- "unknown": 12
14888
+ "unknown": 17
14211
14889
  }
14212
14890
  }
14213
14891
  };
@@ -14507,6 +15185,13 @@ var UNTRUSTED_FIELDS_BY_RESOURCE = {
14507
15185
  "holidays": [
14508
15186
  "holidayName"
14509
15187
  ],
15188
+ "invoice_templates": [
15189
+ "coveredByBlockRetainerContractLabel",
15190
+ "coveredByRecurringServiceFixedPricePerTicketContractLabel",
15191
+ "name",
15192
+ "nonBillableLaborLabel",
15193
+ "rateCostExpression"
15194
+ ],
14510
15195
  "invoices": [
14511
15196
  "comments",
14512
15197
  "taxRegionName"
@@ -14555,6 +15240,14 @@ var UNTRUSTED_FIELDS_BY_RESOURCE = {
14555
15240
  "name",
14556
15241
  "nickname"
14557
15242
  ],
15243
+ "organizational_level1s": [
15244
+ "description",
15245
+ "name"
15246
+ ],
15247
+ "organizational_level2s": [
15248
+ "description",
15249
+ "name"
15250
+ ],
14558
15251
  "products": [
14559
15252
  "UDF1",
14560
15253
  "UDF10",
@@ -14692,6 +15385,34 @@ var UNTRUSTED_FIELDS_BY_RESOURCE = {
14692
15385
  "description",
14693
15386
  "name"
14694
15387
  ],
15388
+ "sales_orders": [
15389
+ "UDF1",
15390
+ "UDF10",
15391
+ "UDF11",
15392
+ "UDF12",
15393
+ "UDF13",
15394
+ "UDF14",
15395
+ "UDF15",
15396
+ "UDF16",
15397
+ "UDF17",
15398
+ "UDF18",
15399
+ "UDF19",
15400
+ "UDF2",
15401
+ "UDF20",
15402
+ "UDF3",
15403
+ "UDF4",
15404
+ "UDF5",
15405
+ "UDF6",
15406
+ "UDF7",
15407
+ "UDF8",
15408
+ "UDF9",
15409
+ "additionalBillToAddressInformation",
15410
+ "additionalShipToAddressInformation",
15411
+ "billToPostalCode",
15412
+ "shipToCity",
15413
+ "shipToState",
15414
+ "title"
15415
+ ],
14695
15416
  "service_calls": [
14696
15417
  "description"
14697
15418
  ],
@@ -14766,6 +15487,9 @@ var UNTRUSTED_FIELDS_BY_RESOURCE = {
14766
15487
  "tags": [
14767
15488
  "label"
14768
15489
  ],
15490
+ "tax_regions": [
15491
+ "name"
15492
+ ],
14769
15493
  "ticket_attachments": [
14770
15494
  "title"
14771
15495
  ],
@@ -14881,7 +15605,7 @@ function attachEmptyReasonDetails(err) {
14881
15605
  const resource = err.operation.slice(0, dot);
14882
15606
  const op = err.operation.slice(dot + 1);
14883
15607
  const surface = err.operation;
14884
- const stamp = _optionalChain([EMPTY_REASON_STAMPS, 'access', _52 => _52[resource], 'optionalAccess', _53 => _53[op]]);
15608
+ const stamp = _optionalChain([EMPTY_REASON_STAMPS, 'access', _53 => _53[resource], 'optionalAccess', _54 => _54[op]]);
14885
15609
  const pointer = POINTER_NOTES[surface];
14886
15610
  const isGetMiss = err instanceof NotFoundError && op === "get";
14887
15611
  if (stamp === void 0 && pointer === void 0 && !isGetMiss) return;
@@ -15076,7 +15800,7 @@ async function readBodyText(res, max, what, ctx) {
15076
15800
  });
15077
15801
  const declared = Number(res.headers.get("Content-Length"));
15078
15802
  if (Number.isFinite(declared) && declared > max) {
15079
- await _optionalChain([res, 'access', _54 => _54.body, 'optionalAccess', _55 => _55.cancel, 'call', _56 => _56(), 'access', _57 => _57.catch, 'call', _58 => _58(() => void 0)]);
15803
+ await _optionalChain([res, 'access', _55 => _55.body, 'optionalAccess', _56 => _56.cancel, 'call', _57 => _57(), 'access', _58 => _58.catch, 'call', _59 => _59(() => void 0)]);
15080
15804
  throw tooLarge();
15081
15805
  }
15082
15806
  if (res.body === null) return "";
@@ -15097,7 +15821,7 @@ async function readBodyText(res, max, what, ctx) {
15097
15821
  return text + decoder.decode();
15098
15822
  }
15099
15823
  function isJsonMediaType(header) {
15100
- const mediaType = _nullishCoalesce(_optionalChain([header, 'access', _59 => _59.split, 'call', _60 => _60(";"), 'access', _61 => _61[0], 'optionalAccess', _62 => _62.trim, 'call', _63 => _63(), 'access', _64 => _64.toLowerCase, 'call', _65 => _65()]), () => ( ""));
15824
+ const mediaType = _nullishCoalesce(_optionalChain([header, 'access', _60 => _60.split, 'call', _61 => _61(";"), 'access', _62 => _62[0], 'optionalAccess', _63 => _63.trim, 'call', _64 => _64(), 'access', _65 => _65.toLowerCase, 'call', _66 => _66()]), () => ( ""));
15101
15825
  return mediaType.startsWith("application/json") || mediaType.endsWith("+json");
15102
15826
  }
15103
15827
  function bodySnippet(text, redactPersonalData) {
@@ -15177,7 +15901,7 @@ function recordSuccess(breaker, key, probe, logger) {
15177
15901
  };
15178
15902
  if (next.successes >= breaker.successesToClose) {
15179
15903
  breaker.store.delete(key);
15180
- _optionalChain([logger, 'access', _66 => _66.warn, 'optionalCall', _67 => _67(
15904
+ _optionalChain([logger, 'access', _67 => _67.warn, 'optionalCall', _68 => _68(
15181
15905
  `[autotask] circuit breaker CLOSED for ${key} (${next.successes} probe successes)`,
15182
15906
  void 0
15183
15907
  )]);
@@ -15192,7 +15916,7 @@ function recordFailure(breaker, key, probe, logger, correlationId) {
15192
15916
  const failures = [...st.failures.filter((t) => t > now - breaker.failureWindowMs), now];
15193
15917
  if (failures.length >= breaker.failureThreshold) {
15194
15918
  breaker.store.set(key, { failures, openedAt: now, successes: 0, probes: 0 });
15195
- _optionalChain([logger, 'access', _68 => _68.warn, 'optionalCall', _69 => _69(
15919
+ _optionalChain([logger, 'access', _69 => _69.warn, 'optionalCall', _70 => _70(
15196
15920
  `[autotask] circuit breaker OPEN for ${key} (${failures.length} counted failures in ${Math.round(breaker.failureWindowMs / 1e3)}s) \u2014 refusing locally for ${Math.round(breaker.openTimeoutMs / 1e3)}s`,
15197
15921
  correlationId
15198
15922
  )]);
@@ -15347,7 +16071,7 @@ async function discoverZoneBase(userName, maxResponseBytes, signal, ctx) {
15347
16071
  return void 0;
15348
16072
  }
15349
16073
  if (res.status < 200 || res.status >= 300) {
15350
- await _optionalChain([res, 'access', _70 => _70.body, 'optionalAccess', _71 => _71.cancel, 'call', _72 => _72(), 'access', _73 => _73.catch, 'call', _74 => _74(() => void 0)]);
16074
+ await _optionalChain([res, 'access', _71 => _71.body, 'optionalAccess', _72 => _72.cancel, 'call', _73 => _73(), 'access', _74 => _74.catch, 'call', _75 => _75(() => void 0)]);
15351
16075
  return void 0;
15352
16076
  }
15353
16077
  let text;
@@ -15482,7 +16206,7 @@ var HttpClient = class {
15482
16206
  this.maintenanceMaxWaitMs = config.maintenanceMaxWaitMs;
15483
16207
  this.maintenancePollMs = config.maintenancePollMs;
15484
16208
  this.maxResponseBytes = config.maxResponseBytes;
15485
- this.hourly = _optionalChain([config, 'access', _75 => _75.rateLimit, 'optionalAccess', _76 => _76.perHour]) === void 0 ? void 0 : new HourlyBudget(config.rateLimit.perHour, config.profile);
16209
+ this.hourly = _optionalChain([config, 'access', _76 => _76.rateLimit, 'optionalAccess', _77 => _77.perHour]) === void 0 ? void 0 : new HourlyBudget(config.rateLimit.perHour, config.profile);
15486
16210
  this.tenantKey = buildTenantKey(config.userName, config.baseUrl);
15487
16211
  this.cooldownStore = config.cooldown.enabled ? _nullishCoalesce(config.cooldown.store, () => ( defaultCooldownStore())) : void 0;
15488
16212
  this.cooldownMaxMs = config.cooldown.maxMs;
@@ -15512,7 +16236,7 @@ var HttpClient = class {
15512
16236
  * `thresholdInformation.get()`.
15513
16237
  */
15514
16238
  hourlyBudget() {
15515
- return _optionalChain([this, 'access', _77 => _77.hourly, 'optionalAccess', _78 => _78.snapshot, 'call', _79 => _79()]);
16239
+ return _optionalChain([this, 'access', _78 => _78.hourly, 'optionalAccess', _79 => _79.snapshot, 'call', _80 => _80()]);
15516
16240
  }
15517
16241
  /**
15518
16242
  * One audit event per settled request (section 19.3): the correlation id,
@@ -15542,7 +16266,7 @@ var HttpClient = class {
15542
16266
  this.liveBaseUrl = to;
15543
16267
  this.tenantKey = buildTenantKey(this.auth.userName, to);
15544
16268
  this.breakerKey = buildBreakerKey(to);
15545
- _optionalChain([this, 'access', _80 => _80.logger, 'access', _81 => _81.warn, 'optionalCall', _82 => _82(
16269
+ _optionalChain([this, 'access', _81 => _81.logger, 'access', _82 => _82.warn, 'optionalCall', _83 => _83(
15546
16270
  `[autotask] zone re-point ${from} -> ${to} (a 401 on the stale zone base; the vendor's unauthenticated zone discovery named the tenant's current zone) \u2014 retrying the request once against the new base`,
15547
16271
  void 0
15548
16272
  )]);
@@ -15571,7 +16295,7 @@ var HttpClient = class {
15571
16295
  /** The caller's signal wins over the deadline when both fired. */
15572
16296
  interrupted(s) {
15573
16297
  const { method, opts, ctx } = s;
15574
- return _optionalChain([s, 'access', _83 => _83.callerSignal, 'optionalAccess', _84 => _84.aborted]) ? new AutotaskAbortError(`Request aborted: ${method} ${opts.path}`, { ...ctx, suggestedAction: "The caller aborted; re-issue the call if still needed." }) : new AutotaskTimeoutError(`Request timed out after ${s.timeoutMs}ms: ${method} ${opts.path}`, ctx);
16298
+ return _optionalChain([s, 'access', _84 => _84.callerSignal, 'optionalAccess', _85 => _85.aborted]) ? new AutotaskAbortError(`Request aborted: ${method} ${opts.path}`, { ...ctx, suggestedAction: "The caller aborted; re-issue the call if still needed." }) : new AutotaskTimeoutError(`Request timed out after ${s.timeoutMs}ms: ${method} ${opts.path}`, ctx);
15575
16299
  }
15576
16300
  /** A retry only runs when its wait fits inside what is left of the call budget. */
15577
16301
  canWait(s, delay) {
@@ -15592,7 +16316,7 @@ var HttpClient = class {
15592
16316
  /** If the retry's wait fits the budget: log, count the attempt, pause, and report true (loop again). */
15593
16317
  async retryAfterDelay(s, delay, what) {
15594
16318
  if (!this.canWait(s, delay)) return false;
15595
- _optionalChain([this, 'access', _85 => _85.logger, 'access', _86 => _86.warn, 'optionalCall', _87 => _87(
16319
+ _optionalChain([this, 'access', _86 => _86.logger, 'access', _87 => _87.warn, 'optionalCall', _88 => _88(
15596
16320
  `[autotask] ${what}; retrying in ${delay}ms (attempt ${s.attempt + 1}/${s.maxRetries})`,
15597
16321
  s.correlationId
15598
16322
  )]);
@@ -15616,7 +16340,7 @@ var HttpClient = class {
15616
16340
  const wait = Math.min(s.maintenancePollMs, remaining);
15617
16341
  if (wait >= remaining) s.maintenanceBudgetSpent = true;
15618
16342
  s.maintenanceWaits += 1;
15619
- _optionalChain([this, 'access', _88 => _88.logger, 'access', _89 => _89.warn, 'optionalCall', _90 => _90(
16343
+ _optionalChain([this, 'access', _89 => _89.logger, 'access', _90 => _90.warn, 'optionalCall', _91 => _91(
15620
16344
  `[autotask] maintenance window on ${s.method} ${s.opts.path}${statusLabel}; waiting ${Math.round(wait / 1e3)}s (retry ${s.maintenanceWaits}, up to ${Math.round(s.maintenanceMaxWaitMs / 6e4)} min)`,
15621
16345
  s.correlationId
15622
16346
  )]);
@@ -15666,7 +16390,7 @@ var HttpClient = class {
15666
16390
  if (this.cooldownStore === void 0 || s.opts.bypassCooldown) return;
15667
16391
  const err = cooldownRefusal(this.cooldownStore, this.tenantKey, s.ctx);
15668
16392
  if (err === void 0) return;
15669
- if (_optionalChain([s, 'access', _91 => _91.callerSignal, 'optionalAccess', _92 => _92.aborted])) throw this.interrupted(s);
16393
+ if (_optionalChain([s, 'access', _92 => _92.callerSignal, 'optionalAccess', _93 => _93.aborted])) throw this.interrupted(s);
15670
16394
  this.auditNotSent(s, "RATE_LIMITED_COOLDOWN");
15671
16395
  throw err;
15672
16396
  }
@@ -15680,7 +16404,7 @@ var HttpClient = class {
15680
16404
  */
15681
16405
  gateBreaker(s) {
15682
16406
  if (this.breaker === void 0 || s.opts.bypassCircuitBreaker) return;
15683
- if (_optionalChain([s, 'access', _93 => _93.callerSignal, 'optionalAccess', _94 => _94.aborted])) throw this.interrupted(s);
16407
+ if (_optionalChain([s, 'access', _94 => _94.callerSignal, 'optionalAccess', _95 => _95.aborted])) throw this.interrupted(s);
15684
16408
  const verdict = evaluateBreakerGate(this.breaker, this.breakerKey, s.ctx);
15685
16409
  if (verdict.refusal !== void 0) {
15686
16410
  this.auditNotSent(s, "CIRCUIT_BREAKER_OPEN");
@@ -15700,7 +16424,7 @@ var HttpClient = class {
15700
16424
  async sendOnce(s) {
15701
16425
  const { method, opts, ctx } = s;
15702
16426
  try {
15703
- await _optionalChain([this, 'access', _95 => _95.hourly, 'optionalAccess', _96 => _96.take, 'call', _97 => _97(s.deadlineAt, s.signal, ctx)]);
16427
+ await _optionalChain([this, 'access', _96 => _96.hourly, 'optionalAccess', _97 => _97.take, 'call', _98 => _98(s.deadlineAt, s.signal, ctx)]);
15704
16428
  } catch (err) {
15705
16429
  if (s.signal.aborted) throw this.interrupted(s);
15706
16430
  throw err;
@@ -15726,7 +16450,7 @@ var HttpClient = class {
15726
16450
  try {
15727
16451
  status = res.status;
15728
16452
  if (status >= 300 && status < 400) {
15729
- await _optionalChain([res, 'access', _98 => _98.body, 'optionalAccess', _99 => _99.cancel, 'call', _100 => _100(), 'access', _101 => _101.catch, 'call', _102 => _102(() => void 0)]);
16453
+ await _optionalChain([res, 'access', _99 => _99.body, 'optionalAccess', _100 => _100.cancel, 'call', _101 => _101(), 'access', _102 => _102.catch, 'call', _103 => _103(() => void 0)]);
15730
16454
  throw new ResponseRejectedError(
15731
16455
  `Refused to follow a ${status} redirect for ${method} ${opts.path}`,
15732
16456
  { ...ctx, code: "REDIRECT_BLOCKED", httpStatus: status, suggestedAction: "Check the configured zone/baseUrl; the API does not redirect." }
@@ -15808,11 +16532,11 @@ var HttpClient = class {
15808
16532
  const delay = retryAfter !== void 0 ? retryAfter * 1e3 : backoffDelay(s.attempt);
15809
16533
  if (await this.retryAfterDelay(s, delay, `non-JSON 2xx on ${method} ${opts.path}`)) return RETRY;
15810
16534
  }
15811
- const pageSnippet = typeof _optionalChain([err, 'access', _103 => _103.details, 'optionalAccess', _104 => _104.bodySnippet]) === "string" ? err.details.bodySnippet : "";
16535
+ const pageSnippet = typeof _optionalChain([err, 'access', _104 => _104.details, 'optionalAccess', _105 => _105.bodySnippet]) === "string" ? err.details.bodySnippet : "";
15812
16536
  this.stampMaintenance(s, err);
15813
16537
  if (err.code === "UNEXPECTED_CONTENT_TYPE" && !looksLikeMaintenanceText(text) && isHtmlLike(res.headers.get("Content-Type"), text)) {
15814
16538
  err.details = { ..._nullishCoalesce(err.details, () => ( {})), maintenancePatternMiss: true };
15815
- _optionalChain([this, 'access', _105 => _105.logger, 'access', _106 => _106.debug, 'optionalCall', _107 => _107(
16539
+ _optionalChain([this, 'access', _106 => _106.logger, 'access', _107 => _107.debug, 'optionalCall', _108 => _108(
15816
16540
  `[autotask] non-JSON body did not match the maintenance vocabulary on ${method} ${opts.path}: ${pageSnippet}`,
15817
16541
  s.correlationId
15818
16542
  )]);
@@ -15855,7 +16579,7 @@ var HttpClient = class {
15855
16579
  const target = await discoverZoneBase(this.userName, this.maxResponseBytes, s.signal, s.ctx);
15856
16580
  const targetViolation = target === void 0 || this.hostPolicy === void 0 ? null : decideHostPolicy(target, this.hostPolicy);
15857
16581
  if (targetViolation !== null) {
15858
- _optionalChain([this, 'access', _108 => _108.logger, 'access', _109 => _109.warn, 'optionalCall', _110 => _110(
16582
+ _optionalChain([this, 'access', _109 => _109.logger, 'access', _110 => _110.warn, 'optionalCall', _111 => _111(
15859
16583
  `[autotask] zone re-point refused by hostPolicy (${targetViolation.bound}): ${targetViolation.origin} \u2014 the original 401 propagates, zero wire to the refused host`,
15860
16584
  void 0
15861
16585
  )]);
@@ -15884,7 +16608,7 @@ var HttpClient = class {
15884
16608
  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).`;
15885
16609
  } else if (!nonJsonIsMaintenance && nonJsonIsHtmlCandidate) {
15886
16610
  err.details = { ..._nullishCoalesce(err.details, () => ( {})), maintenancePatternMiss: true };
15887
- _optionalChain([this, 'access', _111 => _111.logger, 'access', _112 => _112.debug, 'optionalCall', _113 => _113(
16611
+ _optionalChain([this, 'access', _112 => _112.logger, 'access', _113 => _113.debug, 'optionalCall', _114 => _114(
15888
16612
  `[autotask] non-JSON body did not match the maintenance vocabulary on ${method} ${opts.path}: ${nonJsonSnippet}`,
15889
16613
  s.correlationId
15890
16614
  )]);
@@ -15906,7 +16630,7 @@ var HttpClient = class {
15906
16630
  threadThreshold
15907
16631
  });
15908
16632
  this.cooldownStore.set(this.tenantKey, Date.now() + durationMs);
15909
- _optionalChain([this, 'access', _114 => _114.logger, 'access', _115 => _115.warn, 'optionalCall', _116 => _116(
16633
+ _optionalChain([this, 'access', _115 => _115.logger, 'access', _116 => _116.warn, 'optionalCall', _117 => _117(
15910
16634
  `[autotask] 429 on ${method} ${opts.path} surfaces after ${s.attempt + 1} attempt(s); tenant cooldown armed for ${Math.round(durationMs / 1e3)}s`,
15911
16635
  s.correlationId
15912
16636
  )]);
@@ -15952,7 +16676,7 @@ var HttpClient = class {
15952
16676
  if (this.fieldCache !== void 0 && err instanceof AutotaskError) {
15953
16677
  const op = typeof opts.operation === "string" ? opts.operation : void 0;
15954
16678
  const verb = op !== void 0 ? op.slice(op.lastIndexOf(".") + 1) : "";
15955
- const drift = _optionalChain([err, 'access', _117 => _117.details, 'optionalAccess', _118 => _118.deterministic]) === true || err.code === "INVALID_RESPONSE" && META_TRIO_VERBS.has(verb);
16679
+ const drift = _optionalChain([err, 'access', _118 => _118.details, 'optionalAccess', _119 => _119.deterministic]) === true || err.code === "INVALID_RESPONSE" && META_TRIO_VERBS.has(verb);
15956
16680
  if (drift && op !== void 0) {
15957
16681
  const dot = op.indexOf(".");
15958
16682
  if (dot > 0) this.fieldCache.invalidate(op.slice(0, dot));
@@ -15962,7 +16686,7 @@ var HttpClient = class {
15962
16686
  /** A real write (even a failed one — it may have partly applied) voids cached reads. */
15963
16687
  invalidateAfterWrite(opts) {
15964
16688
  if (opts.method === "GET" || opts.idempotent === true) return;
15965
- _optionalChain([this, 'access', _119 => _119.readCache, 'optionalAccess', _120 => _120.clear, 'call', _121 => _121()]);
16689
+ _optionalChain([this, 'access', _120 => _120.readCache, 'optionalAccess', _121 => _121.clear, 'call', _122 => _122()]);
15966
16690
  this.latestCountCache.clear();
15967
16691
  const nameOp = typeof opts.operation === "string" ? opts.operation : void 0;
15968
16692
  const nameDot = nameOp !== void 0 ? nameOp.indexOf(".") : -1;
@@ -16043,7 +16767,7 @@ var HttpClient = class {
16043
16767
  try {
16044
16768
  this.gateCooldown(s);
16045
16769
  this.gateBreaker(s);
16046
- _optionalChain([this, 'access', _122 => _122.logger, 'access', _123 => _123.debug, 'optionalCall', _124 => _124(`[autotask] ${method} ${opts.path}`, correlationId)]);
16770
+ _optionalChain([this, 'access', _123 => _123.logger, 'access', _124 => _124.debug, 'optionalCall', _125 => _125(`[autotask] ${method} ${opts.path}`, correlationId)]);
16047
16771
  try {
16048
16772
  for (; ; ) {
16049
16773
  const sent = await this.sendOnce(s);
@@ -16253,7 +16977,7 @@ async function expandResourceNames(client, ids, opts = {}) {
16253
16977
  continue;
16254
16978
  }
16255
16979
  }
16256
- const epoch = _nullishCoalesce(_optionalChain([cache, 'optionalAccess', _125 => _125.epoch]), () => ( 0));
16980
+ const epoch = _nullishCoalesce(_optionalChain([cache, 'optionalAccess', _126 => _126.epoch]), () => ( 0));
16257
16981
  const work = (async () => {
16258
16982
  try {
16259
16983
  const record = await holder.get(id, { fresh });
@@ -16288,6 +17012,38 @@ async function expandResourceNames(client, ids, opts = {}) {
16288
17012
  return { results, resolved, blind, failed };
16289
17013
  }
16290
17014
 
17015
+ // src/operations/entityType.ts
17016
+ function buildEntityTypeMap() {
17017
+ const exact = {};
17018
+ for (const [resource, entry] of Object.entries(RELATIONSHIP_MAP)) {
17019
+ const apiEntity = entry.apiEntity;
17020
+ if (typeof apiEntity !== "string" || apiEntity === "") continue;
17021
+ if (exact[apiEntity] === void 0) exact[apiEntity] = resource;
17022
+ }
17023
+ const aliases = {};
17024
+ for (const [apiEntity, resource] of Object.entries(exact)) {
17025
+ if (!apiEntity.endsWith("s") || apiEntity.endsWith("ss")) continue;
17026
+ const singular = apiEntity.slice(0, -1);
17027
+ if (exact[singular] !== void 0 || aliases[singular] !== void 0) continue;
17028
+ aliases[singular] = resource;
17029
+ }
17030
+ return { ...exact, ...aliases };
17031
+ }
17032
+ var ENTITY_TYPE_TO_RESOURCE = buildEntityTypeMap();
17033
+ var ENUMERABLE_RESOURCES = new Set(
17034
+ _chunkZEGMVEF3cjs.CAPABILITIES.filter((rec) => rec.resource !== "operations" && (rec.operation === "query" || rec.operation === "get")).map(
17035
+ (rec) => rec.resource
17036
+ )
17037
+ );
17038
+ function resourceForEntityType(entityType) {
17039
+ if (typeof entityType !== "string" || entityType === "") return null;
17040
+ return _nullishCoalesce(ENTITY_TYPE_TO_RESOURCE[entityType], () => ( null));
17041
+ }
17042
+ function isEnumerableResource(resource) {
17043
+ if (typeof resource !== "string" || resource === "") return false;
17044
+ return ENUMERABLE_RESOURCES.has(resource);
17045
+ }
17046
+
16291
17047
  // src/operations/types.ts
16292
17048
  var WORKFLOW_RESOURCES = [
16293
17049
  "companies",
@@ -16301,24 +17057,36 @@ var WORKFLOW_RESOURCES = [
16301
17057
  var MAX_FIELD_CATALOG_WIRE = 60;
16302
17058
  var FIELD_CATALOG_HONESTY_NOTE = "Live field metadata reports the SHAPE of a field (existence, requiredness, type, maxLength, read-only, queryable, picklist-ness) as FLAGS and NAMES: picklist-ness as a flag (isPickList) and picklist field names (picklistFields). With the opt-in `labels: true`, picklist rows carry the vendor's exposed picklist VALUES (labels next to each value); without it the op serves no VALUES. It cannot resolve a picklist VALUE the vendor does not expose to this API user (the W-A4 wall \u2014 e.g. the attachments Type picklist): retrying the catalog will not surface a withheld value; that gap is vendor-side, not a client defect.";
16303
17059
  var FIELD_CATALOG_OPT_KEYS = ["resources", "include", "fresh", "fields", "labels"];
16304
- function projectFieldRow(raw, labels = false) {
17060
+ function projectFieldRow(raw, labels = false, udf = false) {
16305
17061
  const r = typeof raw === "object" && raw !== null ? raw : {};
16306
17062
  const name = typeof r.name === "string" ? r.name : "";
16307
17063
  const type = typeof r.dataType === "string" ? r.dataType : typeof r.type === "string" ? r.type : "";
16308
17064
  const values = labels && r.isPickList === true && Array.isArray(r.picklistValues) && r.picklistValues.length > 0 ? r.picklistValues : void 0;
17065
+ const referenceEntityType = typeof r.referenceEntityType === "string" ? r.referenceEntityType : "";
17066
+ const targetResource = resourceForEntityType(referenceEntityType);
16309
17067
  return {
16310
17068
  name,
16311
17069
  ...typeof r.label === "string" && r.label !== "" ? { label: r.label } : {},
16312
17070
  type,
16313
17071
  isRequired: r.isRequired === true,
16314
17072
  isReadOnly: r.isReadOnly === true,
16315
- isQueryable: r.isQueryable === true,
17073
+ // Issue #219 N7: a UDF row never serves the vendor's isQueryable (it is
17074
+ // true for UDFs while a plain filter on a UDF name is refused); it serves
17075
+ // the marker the filter actually needs.
17076
+ ...udf ? { filterable: "udf-marker" } : { isQueryable: r.isQueryable === true },
16316
17077
  isPickList: r.isPickList === true,
17078
+ ...isObjectOrArrayType(type) ? { writeShape: "replace-all" } : {},
16317
17079
  maxLength: typeof r.length === "number" ? r.length : null,
16318
- referenceEntityType: typeof r.referenceEntityType === "string" ? r.referenceEntityType : "",
17080
+ referenceEntityType,
17081
+ targetResource,
17082
+ targetEnumerable: isEnumerableResource(targetResource),
16319
17083
  ...values !== void 0 ? { picklistValues: values } : {}
16320
17084
  };
16321
17085
  }
17086
+ function isObjectOrArrayType(type) {
17087
+ const t = type.trim().toLowerCase();
17088
+ return t === "object" || t === "array" || t === "collection" || t.endsWith("[]");
17089
+ }
16322
17090
  function exposesPicklistValues(raw) {
16323
17091
  const r = typeof raw === "object" && raw !== null ? raw : {};
16324
17092
  return Array.isArray(r.picklistValues) && r.picklistValues.length > 0;
@@ -16340,7 +17108,7 @@ function capabilitySets() {
16340
17108
  const fieldOps = /* @__PURE__ */ new Map();
16341
17109
  const udfOps = /* @__PURE__ */ new Map();
16342
17110
  const resources = /* @__PURE__ */ new Set();
16343
- for (const rec of _chunkWM6E5O55cjs.CAPABILITIES) {
17111
+ for (const rec of _chunkZEGMVEF3cjs.CAPABILITIES) {
16344
17112
  if (rec.resource === "operations") continue;
16345
17113
  resources.add(rec.resource);
16346
17114
  if (rec.operation === "getFieldInfo") fieldOps.set(rec.resource, rec);
@@ -16348,6 +17116,27 @@ function capabilitySets() {
16348
17116
  }
16349
17117
  return { fieldOps, udfOps, resources };
16350
17118
  }
17119
+ var derivedIndex = null;
17120
+ function derivedFieldsFor(resource) {
17121
+ if (derivedIndex === null) {
17122
+ derivedIndex = /* @__PURE__ */ new Map();
17123
+ for (const rec of _chunkZEGMVEF3cjs.CAPABILITIES) {
17124
+ const declared = _optionalChain([rec, 'access', _127 => _127.metadata, 'optionalAccess', _128 => _128.derivedFields]);
17125
+ if (!Array.isArray(declared) || derivedIndex.has(rec.resource)) continue;
17126
+ const rows = [];
17127
+ for (const row of declared) {
17128
+ if (typeof _optionalChain([row, 'optionalAccess', _129 => _129.field]) !== "string" || typeof row.rule !== "string") continue;
17129
+ rows.push({
17130
+ field: row.field,
17131
+ rule: row.rule,
17132
+ ...typeof row.writableRoute === "string" ? { writableRoute: row.writableRoute } : {}
17133
+ });
17134
+ }
17135
+ derivedIndex.set(rec.resource, rows);
17136
+ }
17137
+ }
17138
+ return _nullishCoalesce(derivedIndex.get(resource), () => ( []));
17139
+ }
16351
17140
  function apiEntityFor(rec) {
16352
17141
  const m = /^GET \/V1\.0\/([^/]+)\/entityInformation\/fields$/.exec(_nullishCoalesce(rec.endpoint, () => ( "")));
16353
17142
  if (m === null) {
@@ -16374,7 +17163,7 @@ function validateCatalogOptsShape(opts) {
16374
17163
  }
16375
17164
  }
16376
17165
  function resolveInclude(opts) {
16377
- const includeRaw = _nullishCoalesce(_optionalChain([opts, 'optionalAccess', _126 => _126.include]), () => ( ["fields"]));
17166
+ const includeRaw = _nullishCoalesce(_optionalChain([opts, 'optionalAccess', _130 => _130.include]), () => ( ["fields"]));
16378
17167
  if (!Array.isArray(includeRaw) || includeRaw.length === 0) {
16379
17168
  throw new AutotaskConfigError("fieldCatalog: opts.include must be a non-empty array of (info|fields|udf)");
16380
17169
  }
@@ -16391,7 +17180,7 @@ function resolveInclude(opts) {
16391
17180
  return include;
16392
17181
  }
16393
17182
  function resolveTargets(opts, fieldOps, allResources) {
16394
- const resourcesRaw = _nullishCoalesce(_optionalChain([opts, 'optionalAccess', _127 => _127.resources]), () => ( WORKFLOW_RESOURCES));
17183
+ const resourcesRaw = _nullishCoalesce(_optionalChain([opts, 'optionalAccess', _131 => _131.resources]), () => ( WORKFLOW_RESOURCES));
16395
17184
  if (!Array.isArray(resourcesRaw) || resourcesRaw.length === 0) {
16396
17185
  throw new AutotaskConfigError("fieldCatalog: opts.resources must be a non-empty array of plan resource keys");
16397
17186
  }
@@ -16425,7 +17214,7 @@ function resolveTargets(opts, fieldOps, allResources) {
16425
17214
  return targets;
16426
17215
  }
16427
17216
  function resolveFieldsFilter(opts) {
16428
- const fieldsRaw = _optionalChain([opts, 'optionalAccess', _128 => _128.fields]);
17217
+ const fieldsRaw = _optionalChain([opts, 'optionalAccess', _132 => _132.fields]);
16429
17218
  if (fieldsRaw === void 0) return void 0;
16430
17219
  if (!Array.isArray(fieldsRaw) || fieldsRaw.length === 0) {
16431
17220
  throw new AutotaskConfigError("fieldCatalog: opts.fields must be a non-empty array of vendor field name strings");
@@ -16448,7 +17237,7 @@ function resolveLabels(opts) {
16448
17237
  `fieldCatalog: opts.labels must be a boolean (got ${typeof opts.labels})`
16449
17238
  );
16450
17239
  }
16451
- return _optionalChain([opts, 'optionalAccess', _129 => _129.labels]) === true;
17240
+ return _optionalChain([opts, 'optionalAccess', _133 => _133.labels]) === true;
16452
17241
  }
16453
17242
  function assertWithinWireCap(targetCount, kindCount) {
16454
17243
  const cost = targetCount * kindCount;
@@ -16461,9 +17250,9 @@ function assertWithinWireCap(targetCount, kindCount) {
16461
17250
  }
16462
17251
  function kindFetches(holder, resource) {
16463
17252
  return {
16464
- info: () => _nullishCoalesce(_optionalChain([holder, 'optionalAccess', _130 => _130.getEntityInfo, 'optionalCall', _131 => _131()]), () => ( Promise.reject(new AutotaskError(`fieldCatalog: the client exposes no getEntityInfo read for "${resource}"`, { code: "INVALID_RESPONSE", category: "server" })))),
16465
- fields: () => _nullishCoalesce(_optionalChain([holder, 'optionalAccess', _132 => _132.getFieldInfo, 'optionalCall', _133 => _133()]), () => ( Promise.reject(new AutotaskError(`fieldCatalog: the client exposes no getFieldInfo read for "${resource}"`, { code: "INVALID_RESPONSE", category: "server" })))),
16466
- udf: () => _nullishCoalesce(_optionalChain([holder, 'optionalAccess', _134 => _134.getUdfInfo, 'optionalCall', _135 => _135()]), () => ( Promise.reject(new AutotaskError(`fieldCatalog: the client exposes no getUdfInfo read for "${resource}"`, { code: "INVALID_RESPONSE", category: "server" }))))
17253
+ info: () => _nullishCoalesce(_optionalChain([holder, 'optionalAccess', _134 => _134.getEntityInfo, 'optionalCall', _135 => _135()]), () => ( Promise.reject(new AutotaskError(`fieldCatalog: the client exposes no getEntityInfo read for "${resource}"`, { code: "INVALID_RESPONSE", category: "server" })))),
17254
+ fields: () => _nullishCoalesce(_optionalChain([holder, 'optionalAccess', _136 => _136.getFieldInfo, 'optionalCall', _137 => _137()]), () => ( Promise.reject(new AutotaskError(`fieldCatalog: the client exposes no getFieldInfo read for "${resource}"`, { code: "INVALID_RESPONSE", category: "server" })))),
17255
+ udf: () => _nullishCoalesce(_optionalChain([holder, 'optionalAccess', _138 => _138.getUdfInfo, 'optionalCall', _139 => _139()]), () => ( Promise.reject(new AutotaskError(`fieldCatalog: the client exposes no getUdfInfo read for "${resource}"`, { code: "INVALID_RESPONSE", category: "server" }))))
16467
17256
  };
16468
17257
  }
16469
17258
  async function sweepResource(ctx, resource, tally) {
@@ -16477,6 +17266,8 @@ async function sweepResource(ctx, resource, tally) {
16477
17266
  resource,
16478
17267
  apiEntity,
16479
17268
  udfCapable: ctx.udfOps.has(resource),
17269
+ // Issue #219 N7: the UDF surface is declared with the mechanism, not a boolean.
17270
+ ...ctx.udfOps.has(resource) ? { udfFilter: "udf-marker", udfWriteShape: "merge" } : {},
16480
17271
  unmatchedFields: [],
16481
17272
  required: [],
16482
17273
  readOnly: [],
@@ -16487,9 +17278,9 @@ async function sweepResource(ctx, resource, tally) {
16487
17278
  error: null
16488
17279
  };
16489
17280
  const fetches = kindFetches(holder, resource);
16490
- if (fresh) _optionalChain([cache, 'optionalAccess', _136 => _136.invalidate, 'call', _137 => _137(resource)]);
17281
+ if (fresh) _optionalChain([cache, 'optionalAccess', _140 => _140.invalidate, 'call', _141 => _141(resource)]);
16491
17282
  const projectList = (kind, list) => {
16492
- const projected = list.map((f) => projectFieldRow(f, labels));
17283
+ const projected = list.map((f) => projectFieldRow(f, labels, kind === "udf"));
16493
17284
  if (kind === "fields") applyFieldsFilter(projected, fieldsFilter, row);
16494
17285
  else row.udf = projected;
16495
17286
  for (const f of list) if (exposesPicklistValues(f)) tally.anyPicklistValues = true;
@@ -16529,6 +17320,19 @@ async function sweepResource(ctx, resource, tally) {
16529
17320
  }
16530
17321
  }
16531
17322
  row.cache = allCached ? { hit: true, age: ages.length > 0 ? Math.max(...ages) : 0 } : { hit: false, age: null };
17323
+ const declared = derivedFieldsFor(resource);
17324
+ if (declared.length > 0) {
17325
+ const byField = new Map(declared.map((d) => [d.field, d]));
17326
+ row.derivedFields = declared;
17327
+ for (const field of _nullishCoalesce(row.fields, () => ( []))) {
17328
+ const derivation = byField.get(field.name);
17329
+ if (derivation === void 0) continue;
17330
+ field.derived = {
17331
+ rule: derivation.rule,
17332
+ ...derivation.writableRoute !== void 0 ? { writableRoute: derivation.writableRoute } : {}
17333
+ };
17334
+ }
17335
+ }
16532
17336
  return row;
16533
17337
  }
16534
17338
  async function fieldCatalog(client, opts) {
@@ -16543,7 +17347,7 @@ async function fieldCatalog(client, opts) {
16543
17347
  const zone = _nullishCoalesce(client.config.zone, () => ( "unknown"));
16544
17348
  const rows = [];
16545
17349
  const tally = { wireUsed: 0, anyPicklistValues: false };
16546
- const ctx = { client, include, fieldsFilter, labels, fresh: _optionalChain([opts, 'optionalAccess', _138 => _138.fresh]) === true, fieldOps, udfOps };
17350
+ const ctx = { client, include, fieldsFilter, labels, fresh: _optionalChain([opts, 'optionalAccess', _142 => _142.fresh]) === true, fieldOps, udfOps };
16547
17351
  for (const resource of targets) {
16548
17352
  const row = await sweepResource(ctx, resource, tally);
16549
17353
  if (row !== void 0) rows.push(row);
@@ -16553,7 +17357,7 @@ async function fieldCatalog(client, opts) {
16553
17357
  label: zone,
16554
17358
  cached: cache !== void 0,
16555
17359
  labels,
16556
- ttlMs: _nullishCoalesce(_optionalChain([cache, 'optionalAccess', _139 => _139.ttlMs]), () => ( null)),
17360
+ ttlMs: _nullishCoalesce(_optionalChain([cache, 'optionalAccess', _143 => _143.ttlMs]), () => ( null)),
16557
17361
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
16558
17362
  rows,
16559
17363
  wireUsed: tally.wireUsed,
@@ -16718,7 +17522,7 @@ async function resolveCompositeNames(http, plan, opts = {}) {
16718
17522
  } else {
16719
17523
  for (const f of plan.labelFields) {
16720
17524
  const frow = row.fields.find((x) => x.name === f);
16721
- picklists[f] = _optionalChain([frow, 'optionalAccess', _140 => _140.picklistValues]);
17525
+ picklists[f] = _optionalChain([frow, 'optionalAccess', _144 => _144.picklistValues]);
16722
17526
  }
16723
17527
  }
16724
17528
  } catch (err) {
@@ -16729,8 +17533,8 @@ async function resolveCompositeNames(http, plan, opts = {}) {
16729
17533
  }
16730
17534
  return {
16731
17535
  section,
16732
- resourceName: (id) => _nullishCoalesce(_optionalChain([section, 'access', _141 => _141.rows, 'access', _142 => _142[`resource:${id}`], 'optionalAccess', _143 => _143.name]), () => ( null)),
16733
- recordName: (table, id) => _nullishCoalesce(_optionalChain([section, 'access', _144 => _144.rows, 'access', _145 => _145[`${table}:${id}`], 'optionalAccess', _146 => _146.name]), () => ( null)),
17536
+ resourceName: (id) => _nullishCoalesce(_optionalChain([section, 'access', _145 => _145.rows, 'access', _146 => _146[`resource:${id}`], 'optionalAccess', _147 => _147.name]), () => ( null)),
17537
+ recordName: (table, id) => _nullishCoalesce(_optionalChain([section, 'access', _148 => _148.rows, 'access', _149 => _149[`${table}:${id}`], 'optionalAccess', _150 => _150.name]), () => ( null)),
16734
17538
  labelFor: (field, value) => {
16735
17539
  if (value === null || value === void 0) return null;
16736
17540
  const values = picklists[field];
@@ -16752,6 +17556,7 @@ async function resolveCompositeNames(http, plan, opts = {}) {
16752
17556
  var MODEL_FIELD_SETS = {
16753
17557
  "appointments": ["id", "createDateTime", "creatorResourceID", "description", "endDateTime", "resourceID", "startDateTime", "title", "updateDateTime"],
16754
17558
  "billing_codes": ["id", "afterHoursWorkType", "billingCodeType", "department", "description", "externalNumber", "generalLedgerAccount", "isActive", "isExcludedFromNewContracts", "markupRate", "name", "taxCategoryID", "unitCost", "unitPrice", "useType"],
17559
+ "billing_item_approval_levels": ["id", "approvalDateTime", "approvalLevel", "approvalResourceID", "timeEntryID"],
16755
17560
  "billing_items": ["id", "accountManagerWhenApprovedID", "billingCodeID", "billingItemType", "companyID", "configurationItemID", "contractBlockID", "contractChargeID", "contractID", "contractServiceAdjustmentID", "contractServiceBundleAdjustmentID", "contractServiceBundleID", "contractServiceBundlePeriodID", "contractServiceID", "contractServicePeriodID", "description", "expenseItemID", "extendedPrice", "internalCurrencyExtendedPrice", "internalCurrencyRate", "internalCurrencyTaxDollars", "internalCurrencyTotalAmount", "invoiceID", "itemApproverID", "itemDate", "itemName", "lineItemFullDescription", "lineItemGroupDescription", "milestoneID", "nonBillable", "organizationalLevelAssociationID", "ourCost", "postedDate", "postedOnTime", "projectChargeID", "projectID", "purchaseOrderNumber", "quantity", "rate", "roleID", "serviceBundleID", "serviceID", "sortOrderID", "subType", "taskID", "taxDollars", "ticketChargeID", "ticketID", "timeEntryID", "totalAmount", "vendorID", "webServiceDate"],
16756
17561
  "change_request_links": ["id", "changeRequestTicketID", "problemOrIncidentTicketID"],
16757
17562
  "checklist_libraries": ["id", "description", "entityType", "isActive", "name"],
@@ -16807,11 +17612,15 @@ var MODEL_FIELD_SETS = {
16807
17612
  "holiday_sets": ["id", "holidaySetDescription", "holidaySetName"],
16808
17613
  "holidays": ["id", "holidayDate", "holidayName", "holidaySetID", "soapParentPropertyId"],
16809
17614
  "inventory_products": ["id", "availableUnits", "backOrderQuantity", "bin", "createDateTime", "createdByResourceID", "inventoryLocationID", "onHandUnits", "pickedUnits", "productID", "quantityMaximum", "quantityMinimum", "referenceNumber", "reservedUnits", "unitsOnOrder"],
17615
+ "invoice_templates": ["id", "coveredByBlockRetainerContractLabel", "coveredByRecurringServiceFixedPricePerTicketContractLabel", "currencyNegativeFormat", "currencyPositiveFormat", "dateFormat", "displayFixedPriceContractLabor", "displayRecurringServiceContractLabor", "displaySeparateLineItemForEachTax", "displayTaxCategory", "displayTaxCategorySuperscripts", "displayZeroAmountRecurringServicesAndBundles", "groupBy", "itemizeItemsInEachGroup", "itemizeServicesAndBundles", "name", "nonBillableLaborLabel", "numberFormat", "pageLayout", "pageNumberFormat", "paymentTerms", "rateCostExpression", "showGridHeader", "showVerticalGridLines", "sortBy", "timeFormat"],
16810
17616
  "invoices": ["id", "batchID", "comments", "companyID", "createDateTime", "creatorResourceID", "dueDate", "fromDate", "invoiceDateTime", "invoiceEditorTemplateID", "invoiceNumber", "invoiceTotal", "isVoided", "orderNumber", "paidDate", "paymentTerm", "taxGroup", "taxRegionName", "toDate", "totalTaxValue", "voidedByResourceID", "voidedDate", "webServiceDate"],
16811
17617
  "notification_history": ["id", "companyID", "entityNumber", "entityTitle", "initiatingContactID", "initiatingResourceID", "isActive", "isDeleted", "isTemplateJob", "notificationHistoryTypeID", "notificationSentTime", "opportunityID", "projectID", "quoteID", "recipientDisplayName", "recipientEmailAddress", "taskID", "templateName", "ticketID", "timeEntryID"],
16812
17618
  "opportunities": ["id", "advancedField1", "advancedField2", "advancedField3", "advancedField4", "advancedField5", "amount", "assessmentScore", "barriers", "closedDate", "companyID", "contactID", "cost", "createDate", "creatorResourceID", "description", "helpNeeded", "impersonatorCreatorResourceID", "lastActivity", "leadSource", "lossReason", "lossReasonDetail", "lostDate", "market", "monthlyCost", "monthlyRevenue", "nextStep", "onetimeCost", "onetimeRevenue", "opportunityCategoryID", "organizationalLevelAssociationID", "ownerResourceID", "primaryCompetitor", "probability", "productID", "projectedCloseDate", "promisedFulfillmentDate", "promotionName", "quarterlyCost", "quarterlyRevenue", "rating", "relationshipAssessmentScore", "revenueSpread", "revenueSpreadUnit", "salesOrderID", "salesProcessPercentComplete", "semiannualCost", "semiannualRevenue", "stage", "startDate", "status", "technicalAssessmentScore", "throughDate", "title", "totalAmountMonths", "useQuoteTotals", "winReason", "winReasonDetail", "yearlyCost", "yearlyRevenue", "userDefinedFields"],
16813
17619
  "opportunity_attachments": ["id", "attachDate", "attachedByContactID", "attachedByResourceID", "attachmentType", "contentType", "creatorType", "fileSize", "fullPath", "impersonatorCreatorResourceID", "opportunityID", "parentAttachmentID", "parentID", "publish", "title", "data", "parentType", "soapParentPropertyId", "isTaskAttachment"],
16814
17620
  "opportunity_categories": ["id", "displayColorRGB", "isActive", "isGlobalDefault", "name", "nickname"],
17621
+ "organizational_level1s": ["id", "description", "isActive", "name"],
17622
+ "organizational_level2s": ["id", "description", "isActive", "name"],
17623
+ "organizational_level_associations": ["id", "isActive", "organizationalLevel1ID", "organizationalLevel2ID"],
16815
17624
  "phases": ["id", "createDate", "creatorResourceID", "description", "dueDate", "estimatedHours", "externalID", "isScheduled", "lastActivityDateTime", "parentPhaseID", "phaseNumber", "projectID", "startDate", "title", "soapParentPropertyId"],
16816
17625
  "product_vendors": ["id", "isActive", "isDefault", "productID", "vendorCost", "vendorID", "vendorPartNumber", "soapParentPropertyId"],
16817
17626
  "products": ["id", "billingType", "chargeBillingCodeID", "createdByResourceID", "createdTime", "defaultVendorID", "description", "doesNotRequireProcurement", "externalProductID", "impersonatorCreatorResourceID", "internalProductID", "isActive", "isEligibleForRma", "isSerialized", "link", "manufacturerName", "manufacturerProductName", "markupRate", "msrp", "name", "periodType", "priceCostMethod", "productBillingCodeID", "productCategory", "sku", "unitCost", "unitPrice", "vendorProductNumber", "defaultInstalledProductCategoryID", "userDefinedFields"],
@@ -16833,6 +17642,7 @@ var MODEL_FIELD_SETS = {
16833
17642
  "resource_time_off_balances": ["id", "resourceID", "floatingHolidayAnnualAllowance", "floatingHolidayBalance", "floatingHolidayPlanned", "floatingHolidayUsed", "floatingHolidayWaitingApproval", "personalTimeAnnualAllowance", "personalTimeBalance", "personalTimePlanned", "personalTimeUsed", "personalTimeWaitingApproval", "sickTimeAnnualAllowance", "sickTimeBalance", "sickTimePlanned", "sickTimeUsed", "sickTimeWaitingApproval", "vacationTimeAnnualAllowance", "vacationTimeBalance", "vacationTimePlanned", "vacationTimeUsed", "vacationTimeWaitingApproval", "year", "soapParentPropertyId"],
16834
17643
  "resources": ["id", "accountingReferenceID", "dateFormat", "defaultServiceDeskRoleID", "email", "email2", "email3", "emailTypeCode", "emailTypeCode2", "emailTypeCode3", "firstName", "gender", "greeting", "hireDate", "homePhone", "initials", "internalCost", "isActive", "lastName", "licenseType", "locationID", "middleName", "mobilePhone", "numberFormat", "officeExtension", "officePhone", "payrollIdentifier", "payrollType", "resourceType", "suffix", "surveyResourceRating", "timeFormat", "title", "travelAvailabilityPct", "userName", "userType"],
16835
17644
  "roles": ["id", "description", "hourlyFactor", "hourlyRate", "isActive", "isExcludedFromNewContracts", "isSystemRole", "name", "quoteItemDefaultTaxCategoryId", "roleType"],
17645
+ "sales_orders": ["id", "additionalBillToAddressInformation", "additionalShipToAddressInformation", "billingAddress1", "billingAddress2", "billToCity", "billToCountryID", "billToPostalCode", "billToState", "companyID", "contactID", "impersonatorCreatorResourceID", "opportunityID", "organizationalLevelAssociationID", "ownerResourceID", "promisedFulfillmentDate", "salesOrderDate", "shipToAddress1", "shipToAddress2", "shipToCity", "shipToCountryID", "shipToPostalCode", "shipToState", "status", "title", "soapParentPropertyId", "userDefinedFields"],
16836
17646
  "service_call_task_resources": ["id", "resourceID", "serviceCallTaskID", "soapParentPropertyId"],
16837
17647
  "service_call_tasks": ["id", "serviceCallID", "taskID", "soapParentPropertyId"],
16838
17648
  "service_call_ticket_resources": ["id", "resourceID", "serviceCallTicketID", "soapParentPropertyId"],
@@ -16850,6 +17660,7 @@ var MODEL_FIELD_SETS = {
16850
17660
  "tags": ["id", "createDateTime", "isActive", "isExcludedFromAutomaticTagging", "isSystem", "label", "lastModifiedDateTime", "tagGroupID"],
16851
17661
  "task_secondary_resources": ["id", "resourceID", "roleID", "taskID", "soapParentPropertyId"],
16852
17662
  "tasks": ["id", "assignedResourceID", "assignedResourceRoleID", "billingCodeID", "canClientPortalUserCompleteTask", "companyLocationID", "completedByResourceID", "completedByType", "completedDateTime", "createDateTime", "creatorResourceID", "creatorType", "departmentID", "description", "endDateTime", "estimatedHours", "externalID", "hoursToBeScheduled", "isTaskBillable", "isVisibleInClientPortal", "lastActivityDateTime", "lastActivityPersonType", "lastActivityResourceID", "phaseID", "priority", "priorityLabel", "projectID", "purchaseOrderNumber", "remainingHours", "startDateTime", "status", "taskCategoryID", "taskNumber", "taskType", "title", "soapParentPropertyId", "userDefinedFields"],
17663
+ "tax_regions": ["id", "isActive", "name"],
16853
17664
  "ticket_additional_configuration_items": ["id", "configurationItemID", "ticketID", "soapParentPropertyId"],
16854
17665
  "ticket_additional_contacts": ["id", "contactID", "ticketID", "soapParentPropertyId"],
16855
17666
  "ticket_attachments": ["id", "attachDate", "attachedByContactID", "attachedByResourceID", "attachmentType", "contentType", "creatorType", "fileSize", "fullPath", "impersonatorCreatorResourceID", "opportunityID", "parentAttachmentID", "parentID", "publish", "ticketID", "ticketNoteID", "timeEntryID", "title", "data", "parentType", "soapParentPropertyId", "isTaskAttachment"],
@@ -16871,6 +17682,7 @@ var MODEL_FIELD_SETS = {
16871
17682
  };
16872
17683
  var MODEL_DATE_FIELDS = {
16873
17684
  "appointments": ["createDateTime", "endDateTime", "startDateTime", "updateDateTime"],
17685
+ "billing_item_approval_levels": ["approvalDateTime"],
16874
17686
  "billing_items": ["itemDate", "postedDate", "postedOnTime", "webServiceDate"],
16875
17687
  "companies": ["createDate", "lastActivityDate", "lastTrackedModifiedDateTime"],
16876
17688
  "company_notes": ["completedDateTime", "createDateTime", "endDateTime", "lastModifiedDate", "startDateTime"],
@@ -16910,6 +17722,7 @@ var MODEL_DATE_FIELDS = {
16910
17722
  "quote_templates": ["createDate", "lastActivityDate"],
16911
17723
  "quotes": ["approvalStatusChangedDate", "createDate", "effectiveDate", "expirationDate", "extApprovalResponseDate", "lastActivityDate", "lastPublishedDateTime"],
16912
17724
  "resources": ["hireDate"],
17725
+ "sales_orders": ["promisedFulfillmentDate", "salesOrderDate"],
16913
17726
  "service_calls": ["canceledDateTime", "createDateTime", "endDateTime", "lastModifiedDateTime", "startDateTime"],
16914
17727
  "services": ["createDate", "lastModifiedDate"],
16915
17728
  "subscription_periods": ["periodDate", "postedDate"],
@@ -17003,8 +17816,8 @@ function validateFetchManyItems(items, cap, opName = "fetchMany", capRef = `FETC
17003
17816
  problems.push(`${at}.fields: must be an array of exact vendor field names (discover them via operations.fieldCatalog)`);
17004
17817
  continue;
17005
17818
  }
17006
- if (_optionalChain([validation, 'optionalAccess', _147 => _147.fieldCheck]) !== false) {
17007
- const authoritative = _nullishCoalesce(_optionalChain([validation, 'optionalAccess', _148 => _148.fieldSetsByResource, 'optionalAccess', _149 => _149.get, 'call', _150 => _150(resourceKey)]), () => ( fields));
17819
+ if (_optionalChain([validation, 'optionalAccess', _151 => _151.fieldCheck]) !== false) {
17820
+ const authoritative = _nullishCoalesce(_optionalChain([validation, 'optionalAccess', _152 => _152.fieldSetsByResource, 'optionalAccess', _153 => _153.get, 'call', _154 => _154(resourceKey)]), () => ( fields));
17008
17821
  for (const f of item.fields) {
17009
17822
  if (!authoritative.includes(f)) {
17010
17823
  problems.push(
@@ -17108,7 +17921,7 @@ function project2(value, fields) {
17108
17921
  return out;
17109
17922
  }
17110
17923
  function resourcePathOf(key, holder) {
17111
- const path = _optionalChain([holder, 'optionalAccess', _151 => _151.resourcePath]);
17924
+ const path = _optionalChain([holder, 'optionalAccess', _155 => _155.resourcePath]);
17112
17925
  if (typeof path !== "string" || path === "") {
17113
17926
  throw new AutotaskConfigError(`fetchByIds: the client exposes no ${key} resource path (registry drift)`, {
17114
17927
  suggestedAction: "Rebuild the client from the SDK build that ships this registry (the resource set is pinned by the plan)."
@@ -17244,7 +18057,7 @@ function uiHostFromBase(baseUrl) {
17244
18057
  } catch (e18) {
17245
18058
  return void 0;
17246
18059
  }
17247
- const n = _optionalChain([REST_HOST, 'access', _152 => _152.exec, 'call', _153 => _153(hostname), 'optionalAccess', _154 => _154[1]]);
18060
+ const n = _optionalChain([REST_HOST, 'access', _156 => _156.exec, 'call', _157 => _157(hostname), 'optionalAccess', _158 => _158[1]]);
17248
18061
  return n === void 0 ? void 0 : `ww${n}.autotask.net`;
17249
18062
  }
17250
18063
  function buildUiLink(input) {
@@ -17350,7 +18163,7 @@ function blindEmptyReason(stamp) {
17350
18163
  };
17351
18164
  }
17352
18165
  function attachUpdateTargetMissReason(err, key) {
17353
- const pinned = _optionalChain([EMPTY_REASON_STAMPS, 'access', _155 => _155[key], 'optionalAccess', _156 => _156.update]);
18166
+ const pinned = _optionalChain([EMPTY_REASON_STAMPS, 'access', _159 => _159[key], 'optionalAccess', _160 => _160.update]);
17354
18167
  if (pinned === void 0) return;
17355
18168
  err.details = { ..._nullishCoalesce(err.details, () => ( {})), emptyReason: pinned };
17356
18169
  }
@@ -17535,7 +18348,7 @@ var QueryBase = class {
17535
18348
  }
17536
18349
  /** @internal */
17537
18350
  walkPageSize(params) {
17538
- return clampPageSize(_nullishCoalesce(_optionalChain([params, 'optionalAccess', _157 => _157.maxRecords]), () => ( this.defaultPageSize)));
18351
+ return clampPageSize(_nullishCoalesce(_optionalChain([params, 'optionalAccess', _161 => _161.maxRecords]), () => ( this.defaultPageSize)));
17539
18352
  }
17540
18353
  /** Stream items across pages (the resource `query` surface). */
17541
18354
  queryItems(params) {
@@ -17547,7 +18360,7 @@ var QueryBase = class {
17547
18360
  }
17548
18361
  /** Collect every item across all pages (the resource `queryAll` surface; 1000-page guarded). */
17549
18362
  async queryAllItems(params) {
17550
- return collectAll(this.pageFetcher(params), { pageSize: this.walkPageSize(params), maxRecords: _optionalChain([params, 'optionalAccess', _158 => _158.maxTotalRecords]) });
18363
+ return collectAll(this.pageFetcher(params), { pageSize: this.walkPageSize(params), maxRecords: _optionalChain([params, 'optionalAccess', _162 => _162.maxTotalRecords]) });
17551
18364
  }
17552
18365
  /**
17553
18366
  * `queryBounded` — server-side pagination (the MCP query surface): ONE call
@@ -17584,19 +18397,19 @@ var QueryBase = class {
17584
18397
  "queryBounded: params must be an object { filter?, limit?, latest?, includeFields? } \u2014 a bare conditions array is not accepted (wrap it: { filter: [...] })"
17585
18398
  );
17586
18399
  }
17587
- const limit = _nullishCoalesce(_optionalChain([params, 'optionalAccess', _159 => _159.limit]), () => ( BOUNDED_QUERY_DEFAULT_LIMIT));
18400
+ const limit = _nullishCoalesce(_optionalChain([params, 'optionalAccess', _163 => _163.limit]), () => ( BOUNDED_QUERY_DEFAULT_LIMIT));
17588
18401
  if (!Number.isInteger(limit) || limit < 1 || limit > BOUNDED_QUERY_MAX_LIMIT) {
17589
18402
  throw new AutotaskConfigError(
17590
18403
  `queryBounded: limit must be an integer 1..${BOUNDED_QUERY_MAX_LIMIT} (got ${String(limit)}) \u2014 it is the TOTAL record cap, not a page size`
17591
18404
  );
17592
18405
  }
17593
- const noteChars = _optionalChain([params, 'optionalAccess', _160 => _160.noteChars]);
18406
+ const noteChars = _optionalChain([params, 'optionalAccess', _164 => _164.noteChars]);
17594
18407
  if (noteChars !== void 0 && (!Number.isInteger(noteChars) || noteChars < 1)) {
17595
18408
  throw new AutotaskConfigError(
17596
18409
  `queryBounded: noteChars must be an integer >= 1 (got ${String(noteChars)}) \u2014 it is the per-field char cap on the untrusted-class free-text fields (absent = the raw, untruncated result)`
17597
18410
  );
17598
18411
  }
17599
- const walkParams = _optionalChain([params, 'optionalAccess', _161 => _161.fieldsPreset]) !== void 0 ? { ...params, includeFields: resolveFieldsPreset(params.fieldsPreset, this.config.key, params.includeFields) } : _nullishCoalesce(params, () => ( {}));
18412
+ const walkParams = _optionalChain([params, 'optionalAccess', _165 => _165.fieldsPreset]) !== void 0 ? { ...params, includeFields: resolveFieldsPreset(params.fieldsPreset, this.config.key, params.includeFields) } : _nullishCoalesce(params, () => ( {}));
17600
18413
  const latest = walkParams.latest;
17601
18414
  if (latest !== void 0) {
17602
18415
  if (!Number.isInteger(latest) || latest < 1 || latest > BOUNDED_QUERY_MAX_LIMIT) {
@@ -17604,7 +18417,7 @@ var QueryBase = class {
17604
18417
  `queryBounded: latest must be an integer 1..${BOUNDED_QUERY_MAX_LIMIT} (got ${String(latest)}) \u2014 it is the count of the highest-id rows to return`
17605
18418
  );
17606
18419
  }
17607
- if (_optionalChain([params, 'optionalAccess', _162 => _162.limit]) !== void 0 && limit < latest) {
18420
+ if (_optionalChain([params, 'optionalAccess', _166 => _166.limit]) !== void 0 && limit < latest) {
17608
18421
  throw new AutotaskConfigError(
17609
18422
  `queryBounded: limit (${String(limit)}) must be >= latest (${String(latest)}) \u2014 latest governs the returned count and limit is the walk window`
17610
18423
  );
@@ -17690,8 +18503,8 @@ var QueryBase = class {
17690
18503
  * @internal */
17691
18504
  stampEmptyQueryResult(result, params) {
17692
18505
  if (result.items.length !== 0) return;
17693
- result.blindSurface = blindStampFor(_optionalChain([BLIND_SURFACE_STAMPS, 'access', _163 => _163[this.config.key], 'optionalAccess', _164 => _164.query]), _optionalChain([params, 'optionalAccess', _165 => _165.filter]));
17694
- const pinnedReason = normalizedConditions(_optionalChain([params, 'optionalAccess', _166 => _166.filter])) === void 0 ? _optionalChain([EMPTY_REASON_STAMPS, 'access', _167 => _167[this.config.key], 'optionalAccess', _168 => _168.query]) : void 0;
18506
+ result.blindSurface = blindStampFor(_optionalChain([BLIND_SURFACE_STAMPS, 'access', _167 => _167[this.config.key], 'optionalAccess', _168 => _168.query]), _optionalChain([params, 'optionalAccess', _169 => _169.filter]));
18507
+ const pinnedReason = normalizedConditions(_optionalChain([params, 'optionalAccess', _170 => _170.filter])) === void 0 ? _optionalChain([EMPTY_REASON_STAMPS, 'access', _171 => _171[this.config.key], 'optionalAccess', _172 => _172.query]) : void 0;
17695
18508
  if (result.blindSurface !== void 0 || pinnedReason !== void 0) {
17696
18509
  result.emptyReason = result.blindSurface !== void 0 ? blindEmptyReason(result.blindSurface) : pinnedReason;
17697
18510
  }
@@ -17920,7 +18733,7 @@ var QueryBase = class {
17920
18733
  if (result.items.length === 0) {
17921
18734
  this.stampEmptyQueryResult(result, params);
17922
18735
  } else {
17923
- result.blindSurface = blindStampFor(_optionalChain([BLIND_SURFACE_STAMPS, 'access', _169 => _169[this.config.key], 'optionalAccess', _170 => _170.query]), params.filter);
18736
+ result.blindSurface = blindStampFor(_optionalChain([BLIND_SURFACE_STAMPS, 'access', _173 => _173[this.config.key], 'optionalAccess', _174 => _174.query]), params.filter);
17924
18737
  }
17925
18738
  return result;
17926
18739
  }
@@ -17961,7 +18774,7 @@ var QueryBase = class {
17961
18774
  * or, on a plan-pinned blind surface, the `{ count: 0, blindSurface }`
17962
18775
  * typed sentinel (S12-C T10; see `BlindCountResult`). */
17963
18776
  async countGlobal(params) {
17964
- const conditions = normalizedConditions(_optionalChain([params, 'optionalAccess', _171 => _171.filter]));
18777
+ const conditions = normalizedConditions(_optionalChain([params, 'optionalAccess', _175 => _175.filter]));
17965
18778
  const body = {};
17966
18779
  body.filter = conditions === void 0 ? [] : buildFilter(conditions).filter;
17967
18780
  const res = await this.http.request({
@@ -17972,9 +18785,9 @@ var QueryBase = class {
17972
18785
  idempotent: true
17973
18786
  });
17974
18787
  const count = unwrapQueryCount(res, `${this.config.key}.count`);
17975
- const stamp = blindStampFor(_optionalChain([BLIND_SURFACE_STAMPS, 'access', _172 => _172[this.config.key], 'optionalAccess', _173 => _173.count]), _optionalChain([params, 'optionalAccess', _174 => _174.filter]));
18788
+ const stamp = blindStampFor(_optionalChain([BLIND_SURFACE_STAMPS, 'access', _176 => _176[this.config.key], 'optionalAccess', _177 => _177.count]), _optionalChain([params, 'optionalAccess', _178 => _178.filter]));
17976
18789
  if (count === 0) {
17977
- const pinnedReason = conditions === void 0 ? _optionalChain([EMPTY_REASON_STAMPS, 'access', _175 => _175[this.config.key], 'optionalAccess', _176 => _176.count]) : void 0;
18790
+ const pinnedReason = conditions === void 0 ? _optionalChain([EMPTY_REASON_STAMPS, 'access', _179 => _179[this.config.key], 'optionalAccess', _180 => _180.count]) : void 0;
17978
18791
  if (stamp !== void 0 || pinnedReason !== void 0) {
17979
18792
  return {
17980
18793
  count,
@@ -18010,9 +18823,9 @@ var MetaBase = class extends QueryBase {
18010
18823
  const hit = cache.get(path);
18011
18824
  if (hit !== void 0) return hit;
18012
18825
  }
18013
- const epoch = _optionalChain([cache, 'optionalAccess', _177 => _177.epoch]);
18826
+ const epoch = _optionalChain([cache, 'optionalAccess', _181 => _181.epoch]);
18014
18827
  const res = await this.http.request({ method: "GET", path, operation });
18015
- _optionalChain([cache, 'optionalAccess', _178 => _178.set, 'call', _179 => _179(path, res, resource, epoch)]);
18828
+ _optionalChain([cache, 'optionalAccess', _182 => _182.set, 'call', _183 => _183(path, res, resource, epoch)]);
18016
18829
  return res;
18017
18830
  }
18018
18831
  /**
@@ -18052,7 +18865,7 @@ var MetaBase = class extends QueryBase {
18052
18865
  return value;
18053
18866
  });
18054
18867
  work.catch((err) => {
18055
- if (err instanceof AutotaskError && (err.code === "INVALID_RESPONSE" || _optionalChain([err, 'access', _180 => _180.details, 'optionalAccess', _181 => _181.deterministic]) === true)) {
18868
+ if (err instanceof AutotaskError && (err.code === "INVALID_RESPONSE" || _optionalChain([err, 'access', _184 => _184.details, 'optionalAccess', _185 => _185.deterministic]) === true)) {
18056
18869
  cache.invalidate(key);
18057
18870
  }
18058
18871
  });
@@ -18082,7 +18895,7 @@ var MetaBase = class extends QueryBase {
18082
18895
  path: `${this.resourcePath}/${numeric}`,
18083
18896
  operation: `${this.config.key}.get`,
18084
18897
  skipResponseRedaction: true,
18085
- maxRetries: _optionalChain([readOpts, 'optionalAccess', _182 => _182.maxRetries])
18898
+ maxRetries: _optionalChain([readOpts, 'optionalAccess', _186 => _186.maxRetries])
18086
18899
  });
18087
18900
  return unwrapItem(res, numeric, `${this.config.key}.get`, this.entityName);
18088
18901
  }
@@ -18101,7 +18914,7 @@ var MetaBase = class extends QueryBase {
18101
18914
  path: this.scopedItemPath(parentId, numeric),
18102
18915
  operation: `${this.config.key}.get`,
18103
18916
  skipResponseRedaction: true,
18104
- maxRetries: _optionalChain([readOpts, 'optionalAccess', _183 => _183.maxRetries])
18917
+ maxRetries: _optionalChain([readOpts, 'optionalAccess', _187 => _187.maxRetries])
18105
18918
  });
18106
18919
  return unwrapItem(res, numeric, `${this.config.key}.get`, this.entityName);
18107
18920
  }
@@ -18310,12 +19123,12 @@ var MetaBase = class extends QueryBase {
18310
19123
  return null;
18311
19124
  }
18312
19125
  }
18313
- const epoch = _optionalChain([cache, 'optionalAccess', _184 => _184.epoch]);
19126
+ const epoch = _optionalChain([cache, 'optionalAccess', _188 => _188.epoch]);
18314
19127
  try {
18315
19128
  return await this.fetchRecordRaw(entityPath, referenceId);
18316
19129
  } catch (err) {
18317
19130
  if (err instanceof NotFoundError) {
18318
- _optionalChain([cache, 'optionalAccess', _185 => _185.set, 'call', _186 => _186(absentKey, CONTEXT_ABSENT_MARKER, RESOURCE_KEY_BY_PATH[entityPath], epoch)]);
19131
+ _optionalChain([cache, 'optionalAccess', _189 => _189.set, 'call', _190 => _190(absentKey, CONTEXT_ABSENT_MARKER, RESOURCE_KEY_BY_PATH[entityPath], epoch)]);
18319
19132
  return null;
18320
19133
  }
18321
19134
  throw err;
@@ -18432,7 +19245,7 @@ var MetaBase = class extends QueryBase {
18432
19245
  missDetail(operator, fields) {
18433
19246
  const key = this.config.key;
18434
19247
  const probe = fields.map((field) => ({ field, op: operator, value: "" }));
18435
- const blind = blindStampFor(_optionalChain([BLIND_SURFACE_STAMPS, 'access', _187 => _187[key], 'optionalAccess', _188 => _188.query]), probe);
19248
+ const blind = blindStampFor(_optionalChain([BLIND_SURFACE_STAMPS, 'access', _191 => _191[key], 'optionalAccess', _192 => _192.query]), probe);
18436
19249
  const next = [];
18437
19250
  if (blind !== void 0) {
18438
19251
  next.push(`This surface is blind to records the API user does not own, so a miss is not proof of absence: ${blind.authority} returns the record when the id is known.`);
@@ -19091,7 +19904,7 @@ var MutationBase = class extends MetaBase {
19091
19904
  current = parentId === void 0 ? await this.getGlobal(id, true) : this.config.attachmentGet ? await this.getScopedModel(parentId, id, true) : await this.getScopedRaw(parentId, id, true);
19092
19905
  } catch (err) {
19093
19906
  if (err instanceof NotFoundError) {
19094
- const updateReason = _optionalChain([EMPTY_REASON_STAMPS, 'access', _189 => _189[this.config.key], 'optionalAccess', _190 => _190.update]);
19907
+ const updateReason = _optionalChain([EMPTY_REASON_STAMPS, 'access', _193 => _193[this.config.key], 'optionalAccess', _194 => _194.update]);
19095
19908
  checks.push({
19096
19909
  name: "current-record-exists",
19097
19910
  ok: false,
@@ -19262,7 +20075,7 @@ function readIncludeNames(record, includeFields) {
19262
20075
  function resolveAuthority(record, live) {
19263
20076
  if (live !== null) return { known: live, authority: "the tenant's live entity field metadata" };
19264
20077
  const vendored = MODEL_FIELD_SETS[record.resource];
19265
- const liveOnlyExempt = Array.isArray(_optionalChain([record, 'access', _191 => _191.metadata, 'optionalAccess', _192 => _192.liveOnlyFields])) ? record.metadata.liveOnlyFields : [];
20078
+ const liveOnlyExempt = Array.isArray(_optionalChain([record, 'access', _195 => _195.metadata, 'optionalAccess', _196 => _196.liveOnlyFields])) ? record.metadata.liveOnlyFields : [];
19266
20079
  if (vendored === void 0) return void 0;
19267
20080
  return {
19268
20081
  known: [...vendored, ...liveOnlyExempt],
@@ -19488,4 +20301,10 @@ async function validateQueryFieldNames(record, holder, args) {
19488
20301
 
19489
20302
 
19490
20303
 
19491
- exports.AUTH_HEADERS = AUTH_HEADERS; exports.buildAuthHeaders = buildAuthHeaders; exports.withAuthHeaders = withAuthHeaders; exports.AutotaskError = AutotaskError; exports.AutotaskConfigError = AutotaskConfigError; exports.isAutotaskError = isAutotaskError; exports.AutotaskNetworkError = AutotaskNetworkError; exports.AutotaskTimeoutError = AutotaskTimeoutError; exports.AutotaskAbortError = AutotaskAbortError; exports.ResponseRejectedError = ResponseRejectedError; exports.BadRequestError = BadRequestError; exports.UnauthorizedError = UnauthorizedError; exports.ForbiddenError = ForbiddenError; exports.NotFoundError = NotFoundError; exports.ConflictError = ConflictError; exports.UnprocessableEntityError = UnprocessableEntityError; exports.RateLimitError = RateLimitError; exports.ServerError = ServerError; exports.UnexpectedContentTypeError = UnexpectedContentTypeError; exports.EmptyResponseError = EmptyResponseError; exports.CircuitBreakerError = CircuitBreakerError; exports.HostPolicyDeniedError = HostPolicyDeniedError; exports.ResolutionError = ResolutionError; exports.PaginationLimitError = PaginationLimitError; exports.QueryTooLongError = QueryTooLongError; exports.parseVendorErrors = parseVendorErrors; exports.isDeterministicVendor500 = isDeterministicVendor500; exports.formatVendorDetail = formatVendorDetail; exports.NoopLogger = NoopLogger; exports.REDACTED = REDACTED; exports.CREDENTIAL_HEADER_NAMES = CREDENTIAL_HEADER_NAMES; exports.isCredentialHeaderName = isCredentialHeaderName; exports.redactRecord = redactRecord; exports.SECRET_RESPONSE_FIELDS = SECRET_RESPONSE_FIELDS; exports.PERSONAL_RESPONSE_FIELDS = PERSONAL_RESPONSE_FIELDS; exports.CONFIDENTIAL_RESPONSE_FIELDS = CONFIDENTIAL_RESPONSE_FIELDS; exports.isRedactedFieldName = isRedactedFieldName; exports.redactResponseBody = redactResponseBody; exports.CREDENTIAL_SHAPE_POINTER = CREDENTIAL_SHAPE_POINTER; exports.mergeDetails = mergeDetails; exports.errorFromStatus = errorFromStatus; exports.StaleObjectError = StaleObjectError; exports.ConfirmationRequiredError = ConfirmationRequiredError; exports.DeleteBoundaryError = DeleteBoundaryError; exports.MarkerUnsafeIdError = MarkerUnsafeIdError; exports.RecoveryTruncatedError = RecoveryTruncatedError; exports.MoveRefusedError = MoveRefusedError; exports.ZONE_CATALOG = ZONE_CATALOG; exports.ZONES = ZONES; exports.DEFAULT_ZONE = DEFAULT_ZONE; exports.zoneUrl = zoneUrl; exports.resolveBaseUrl = resolveBaseUrl; exports.AGENT_PROFILE = AGENT_PROFILE; exports.DEFAULT_PAGE_SIZE = DEFAULT_PAGE_SIZE; exports.MAX_PAGE_SIZE = MAX_PAGE_SIZE; exports.DEFAULT_TIMEOUT_MS = DEFAULT_TIMEOUT_MS; exports.DEFAULT_MAX_RETRIES = DEFAULT_MAX_RETRIES; exports.DEFAULT_MAINTENANCE_MAX_WAIT_MS = DEFAULT_MAINTENANCE_MAX_WAIT_MS; exports.DEFAULT_MAINTENANCE_POLL_MS = DEFAULT_MAINTENANCE_POLL_MS; exports.MAINTENANCE_WINDOW_MAX_MS = MAINTENANCE_WINDOW_MAX_MS; exports.DEFAULT_MAX_CONCURRENT = DEFAULT_MAX_CONCURRENT; exports.DEFAULT_MAX_RESPONSE_BYTES = DEFAULT_MAX_RESPONSE_BYTES; exports.DEFAULT_MAX_SCAN_RECORDS = DEFAULT_MAX_SCAN_RECORDS; exports.DEFAULT_MAX_SCAN_PAGES = DEFAULT_MAX_SCAN_PAGES; exports.DEFAULT_READ_CACHE_TTL_MS = DEFAULT_READ_CACHE_TTL_MS; exports.DEFAULT_FIELD_CACHE_TTL_MS = DEFAULT_FIELD_CACHE_TTL_MS; exports.DEFAULT_RESOURCE_NAME_CACHE_TTL_MS = DEFAULT_RESOURCE_NAME_CACHE_TTL_MS; exports.hasSurroundingQuotes = hasSurroundingQuotes; exports.credentialShapeProblem = credentialShapeProblem; exports.CREDENTIAL_ENV_LOAD_ACTION = CREDENTIAL_ENV_LOAD_ACTION; exports.MIN_PREFIX_SUMMARY_LENGTH = MIN_PREFIX_SUMMARY_LENGTH; exports.credentialValueSummary = credentialValueSummary; exports.FIELD_CACHE_KINDS = FIELD_CACHE_KINDS; exports.DEFAULT_CIRCUIT_BREAKER_WINDOW_MS = DEFAULT_CIRCUIT_BREAKER_WINDOW_MS; exports.DEFAULT_CIRCUIT_BREAKER_FAILURE_THRESHOLD = DEFAULT_CIRCUIT_BREAKER_FAILURE_THRESHOLD; exports.DEFAULT_CIRCUIT_BREAKER_OPEN_TIMEOUT_MS = DEFAULT_CIRCUIT_BREAKER_OPEN_TIMEOUT_MS; exports.DEFAULT_CIRCUIT_BREAKER_SUCCESSES_TO_CLOSE = DEFAULT_CIRCUIT_BREAKER_SUCCESSES_TO_CLOSE; exports.DEFAULT_CIRCUIT_BREAKER_MAX_ENTRIES = DEFAULT_CIRCUIT_BREAKER_MAX_ENTRIES; exports.InMemoryCircuitBreakerStore = InMemoryCircuitBreakerStore; exports.defaultCircuitBreakerStore = defaultCircuitBreakerStore; exports.resetDefaultCircuitBreakerStore = resetDefaultCircuitBreakerStore; exports.buildBreakerKey = buildBreakerKey; exports.isBreakerFailure = isBreakerFailure; exports.DEFAULT_COOLDOWN_MAX_MS = DEFAULT_COOLDOWN_MAX_MS; exports.DEFAULT_COOLDOWN_DEFAULT_MS = DEFAULT_COOLDOWN_DEFAULT_MS; exports.DEFAULT_COOLDOWN_MAX_ENTRIES = DEFAULT_COOLDOWN_MAX_ENTRIES; exports.InMemoryCooldownStore = InMemoryCooldownStore; exports.defaultCooldownStore = defaultCooldownStore; exports.resetDefaultCooldownStore = resetDefaultCooldownStore; exports.buildTenantKey = buildTenantKey; exports.cooldownDurationMs = cooldownDurationMs; exports.resolveCredentials = resolveCredentials; exports.resolveConfig = resolveConfig; exports.IDEMPOTENT_METHODS = IDEMPOTENT_METHODS; exports.isRecord = isRecord2; exports.assertRecord = assertRecord; exports.deepMergeParams = deepMergeParams; exports.isIdentifierCandidate = isIdentifierCandidate; exports.parseIdentifier = parseIdentifier; exports.flattenUdfs = flattenUdfs; exports.newCorrelationId = newCorrelationId; exports.redactAuditBody = redactAuditBody; exports.camelKey = camelKey; exports.FILTER_OPERATORS = FILTER_OPERATORS; exports.GROUPING_OPERATORS = GROUPING_OPERATORS; exports.MAX_OR_CONDITIONS = MAX_OR_CONDITIONS; exports.MAX_UDF_PER_QUERY = MAX_UDF_PER_QUERY; exports.MAX_QUERY_LENGTH = MAX_QUERY_LENGTH; exports.MAX_GET_LENGTH = MAX_GET_LENGTH; exports.MAX_FIELD_LENGTH = MAX_FIELD_LENGTH; exports.isFilterOperator = isFilterOperator; exports.serializeFilter = serializeFilter; exports.validateFilter = validateFilter; exports.buildFilter = buildFilter; exports.normalizedConditions = normalizedConditions; exports.buildUrl = buildUrl; exports.cursorToPath = cursorToPath; exports.buildQueryBody = buildQueryBody; exports.buildQueryRequest = buildQueryRequest; exports.runWithSignal = runWithSignal; exports.RELATIONSHIP_ZONE = RELATIONSHIP_ZONE; exports.RELATIONSHIP_MAP = RELATIONSHIP_MAP; exports.BLIND_SURFACE_STAMPS = BLIND_SURFACE_STAMPS; exports.DELETE_BOUNDARY_NOTES = DELETE_BOUNDARY_NOTES; exports.MARKER_FIELDS = MARKER_FIELDS; exports.EMPTY_REASON_STAMPS = EMPTY_REASON_STAMPS; exports.BLIND_SURFACE_INVENTORY = BLIND_SURFACE_INVENTORY; exports.REACHABILITY_PROBE_DEFAULTS = REACHABILITY_PROBE_DEFAULTS; exports.CREATE_GUIDANCE = CREATE_GUIDANCE; exports.UNTRUSTED_FIELDS_BY_RESOURCE = UNTRUSTED_FIELDS_BY_RESOURCE; exports.unwrapItems = unwrapItems; exports.unwrapItem = unwrapItem; exports.unwrapQueryCount = unwrapQueryCount; exports.unwrapOperation = unwrapOperation; exports.passthrough = passthrough; exports.HttpClient = HttpClient; exports.BOUNDED_QUERY_MAX_LIMIT = BOUNDED_QUERY_MAX_LIMIT; exports.truncateNoteChars = truncateNoteChars; exports.buildDryRunResult = buildDryRunResult; exports.mergePartialBody = mergePartialBody; exports.blindStampFor = blindStampFor; exports.decodeFileData = decodeFileData; exports.MAX_PAGES = MAX_PAGES; exports.clampPageSize = clampPageSize; exports.totalPagesFor = totalPagesFor; exports.paginate = paginate; exports.paginateItems = paginateItems; exports.collectAll = collectAll; exports.toArray = toArray; exports.FIELD_PRESETS = FIELD_PRESETS; exports.FIELD_PRESET_NAMES = FIELD_PRESET_NAMES; exports.resolveFieldsPreset = resolveFieldsPreset; exports.BaseResource = BaseResource; exports.MODEL_FIELD_SETS = MODEL_FIELD_SETS; exports.MODEL_DATE_FIELDS = MODEL_DATE_FIELDS; exports.formatUnknownNameList = formatUnknownNameList; exports.validateQueryFieldNames = validateQueryFieldNames; exports.EXPAND_RESOURCE_NAMES_MAX_IDS = EXPAND_RESOURCE_NAMES_MAX_IDS; exports.expandResourceNames = expandResourceNames; exports.WORKFLOW_RESOURCES = WORKFLOW_RESOURCES; exports.MAX_FIELD_CATALOG_WIRE = MAX_FIELD_CATALOG_WIRE; exports.FIELD_CATALOG_HONESTY_NOTE = FIELD_CATALOG_HONESTY_NOTE; exports.fieldCatalog = fieldCatalog; exports.PICKLIST_VALUE_NOT_SERVED_NOTE = PICKLIST_VALUE_NOT_SERVED_NOTE; exports.TICKET_LABEL_FIELDS = TICKET_LABEL_FIELDS; exports.createNamePlan = createNamePlan; exports.addNameSibling = addNameSibling; exports.addLabelSibling = addLabelSibling; exports.resolveCompositeNames = resolveCompositeNames; exports.FETCH_MANY_MAX_ITEMS = FETCH_MANY_MAX_ITEMS; exports.validateFetchManyItems = validateFetchManyItems; exports.fetchMany = fetchMany; exports.FETCH_BY_IDS_MAX_ITEMS = FETCH_BY_IDS_MAX_ITEMS; exports.FETCH_BY_IDS_CHUNK_SIZE = FETCH_BY_IDS_CHUNK_SIZE; exports.fetchByIds = fetchByIds; exports.UI_LINK_ENTITIES = UI_LINK_ENTITIES; exports.buildUiLink = buildUiLink; exports.uiLink = uiLink;
20304
+
20305
+
20306
+
20307
+
20308
+
20309
+
20310
+ exports.AUTH_HEADERS = AUTH_HEADERS; exports.buildAuthHeaders = buildAuthHeaders; exports.withAuthHeaders = withAuthHeaders; exports.AutotaskError = AutotaskError; exports.AutotaskConfigError = AutotaskConfigError; exports.isAutotaskError = isAutotaskError; exports.AutotaskNetworkError = AutotaskNetworkError; exports.AutotaskTimeoutError = AutotaskTimeoutError; exports.AutotaskAbortError = AutotaskAbortError; exports.ResponseRejectedError = ResponseRejectedError; exports.BadRequestError = BadRequestError; exports.UnauthorizedError = UnauthorizedError; exports.ForbiddenError = ForbiddenError; exports.NotFoundError = NotFoundError; exports.ConflictError = ConflictError; exports.UnprocessableEntityError = UnprocessableEntityError; exports.RateLimitError = RateLimitError; exports.ServerError = ServerError; exports.UnexpectedContentTypeError = UnexpectedContentTypeError; exports.EmptyResponseError = EmptyResponseError; exports.CircuitBreakerError = CircuitBreakerError; exports.HostPolicyDeniedError = HostPolicyDeniedError; exports.ResolutionError = ResolutionError; exports.PaginationLimitError = PaginationLimitError; exports.QueryTooLongError = QueryTooLongError; exports.parseVendorErrors = parseVendorErrors; exports.isDeterministicVendor500 = isDeterministicVendor500; exports.formatVendorDetail = formatVendorDetail; exports.NoopLogger = NoopLogger; exports.REDACTED = REDACTED; exports.CREDENTIAL_HEADER_NAMES = CREDENTIAL_HEADER_NAMES; exports.isCredentialHeaderName = isCredentialHeaderName; exports.redactRecord = redactRecord; exports.SECRET_RESPONSE_FIELDS = SECRET_RESPONSE_FIELDS; exports.PERSONAL_RESPONSE_FIELDS = PERSONAL_RESPONSE_FIELDS; exports.CONFIDENTIAL_RESPONSE_FIELDS = CONFIDENTIAL_RESPONSE_FIELDS; exports.isRedactedFieldName = isRedactedFieldName; exports.redactResponseBody = redactResponseBody; exports.CREDENTIAL_SHAPE_POINTER = CREDENTIAL_SHAPE_POINTER; exports.mergeDetails = mergeDetails; exports.errorFromStatus = errorFromStatus; exports.StaleObjectError = StaleObjectError; exports.ConfirmationRequiredError = ConfirmationRequiredError; exports.DeleteBoundaryError = DeleteBoundaryError; exports.MarkerUnsafeIdError = MarkerUnsafeIdError; exports.RecoveryTruncatedError = RecoveryTruncatedError; exports.MoveRefusedError = MoveRefusedError; exports.READ_CACHE_MAX_ENTRIES = READ_CACHE_MAX_ENTRIES; exports.ReadCache = ReadCache; exports.ZONE_CATALOG = ZONE_CATALOG; exports.ZONES = ZONES; exports.DEFAULT_ZONE = DEFAULT_ZONE; exports.zoneUrl = zoneUrl; exports.resolveBaseUrl = resolveBaseUrl; exports.AGENT_PROFILE = AGENT_PROFILE; exports.DEFAULT_PAGE_SIZE = DEFAULT_PAGE_SIZE; exports.MAX_PAGE_SIZE = MAX_PAGE_SIZE; exports.DEFAULT_TIMEOUT_MS = DEFAULT_TIMEOUT_MS; exports.DEFAULT_MAX_RETRIES = DEFAULT_MAX_RETRIES; exports.DEFAULT_MAINTENANCE_MAX_WAIT_MS = DEFAULT_MAINTENANCE_MAX_WAIT_MS; exports.DEFAULT_MAINTENANCE_POLL_MS = DEFAULT_MAINTENANCE_POLL_MS; exports.MAINTENANCE_WINDOW_MAX_MS = MAINTENANCE_WINDOW_MAX_MS; exports.DEFAULT_MAX_CONCURRENT = DEFAULT_MAX_CONCURRENT; exports.DEFAULT_MAX_RESPONSE_BYTES = DEFAULT_MAX_RESPONSE_BYTES; exports.DEFAULT_MAX_SCAN_RECORDS = DEFAULT_MAX_SCAN_RECORDS; exports.DEFAULT_MAX_SCAN_PAGES = DEFAULT_MAX_SCAN_PAGES; exports.DEFAULT_READ_CACHE_TTL_MS = DEFAULT_READ_CACHE_TTL_MS; exports.DEFAULT_FIELD_CACHE_TTL_MS = DEFAULT_FIELD_CACHE_TTL_MS; exports.DEFAULT_RESOURCE_NAME_CACHE_TTL_MS = DEFAULT_RESOURCE_NAME_CACHE_TTL_MS; exports.hasSurroundingQuotes = hasSurroundingQuotes; exports.credentialShapeProblem = credentialShapeProblem; exports.CREDENTIAL_ENV_LOAD_ACTION = CREDENTIAL_ENV_LOAD_ACTION; exports.MIN_PREFIX_SUMMARY_LENGTH = MIN_PREFIX_SUMMARY_LENGTH; exports.credentialValueSummary = credentialValueSummary; exports.FIELD_CACHE_KINDS = FIELD_CACHE_KINDS; exports.DEFAULT_CIRCUIT_BREAKER_WINDOW_MS = DEFAULT_CIRCUIT_BREAKER_WINDOW_MS; exports.DEFAULT_CIRCUIT_BREAKER_FAILURE_THRESHOLD = DEFAULT_CIRCUIT_BREAKER_FAILURE_THRESHOLD; exports.DEFAULT_CIRCUIT_BREAKER_OPEN_TIMEOUT_MS = DEFAULT_CIRCUIT_BREAKER_OPEN_TIMEOUT_MS; exports.DEFAULT_CIRCUIT_BREAKER_SUCCESSES_TO_CLOSE = DEFAULT_CIRCUIT_BREAKER_SUCCESSES_TO_CLOSE; exports.DEFAULT_CIRCUIT_BREAKER_MAX_ENTRIES = DEFAULT_CIRCUIT_BREAKER_MAX_ENTRIES; exports.InMemoryCircuitBreakerStore = InMemoryCircuitBreakerStore; exports.defaultCircuitBreakerStore = defaultCircuitBreakerStore; exports.resetDefaultCircuitBreakerStore = resetDefaultCircuitBreakerStore; exports.buildBreakerKey = buildBreakerKey; exports.isBreakerFailure = isBreakerFailure; exports.DEFAULT_COOLDOWN_MAX_MS = DEFAULT_COOLDOWN_MAX_MS; exports.DEFAULT_COOLDOWN_DEFAULT_MS = DEFAULT_COOLDOWN_DEFAULT_MS; exports.DEFAULT_COOLDOWN_MAX_ENTRIES = DEFAULT_COOLDOWN_MAX_ENTRIES; exports.InMemoryCooldownStore = InMemoryCooldownStore; exports.defaultCooldownStore = defaultCooldownStore; exports.resetDefaultCooldownStore = resetDefaultCooldownStore; exports.buildTenantKey = buildTenantKey; exports.cooldownDurationMs = cooldownDurationMs; exports.resolveCredentials = resolveCredentials; exports.buildReadCache = buildReadCache; exports.resolveConfig = resolveConfig; exports.IDEMPOTENT_METHODS = IDEMPOTENT_METHODS; exports.isRecord = isRecord2; exports.assertRecord = assertRecord; exports.deepMergeParams = deepMergeParams; exports.isIdentifierCandidate = isIdentifierCandidate; exports.parseIdentifier = parseIdentifier; exports.flattenUdfs = flattenUdfs; exports.newCorrelationId = newCorrelationId; exports.redactAuditBody = redactAuditBody; exports.camelKey = camelKey; exports.FILTER_OPERATORS = FILTER_OPERATORS; exports.GROUPING_OPERATORS = GROUPING_OPERATORS; exports.MAX_OR_CONDITIONS = MAX_OR_CONDITIONS; exports.MAX_UDF_PER_QUERY = MAX_UDF_PER_QUERY; exports.MAX_QUERY_LENGTH = MAX_QUERY_LENGTH; exports.MAX_GET_LENGTH = MAX_GET_LENGTH; exports.MAX_FIELD_LENGTH = MAX_FIELD_LENGTH; exports.isFilterOperator = isFilterOperator; exports.serializeFilter = serializeFilter; exports.validateFilter = validateFilter; exports.buildFilter = buildFilter; exports.normalizedConditions = normalizedConditions; exports.buildUrl = buildUrl; exports.cursorToPath = cursorToPath; exports.buildQueryBody = buildQueryBody; exports.buildQueryRequest = buildQueryRequest; exports.runWithSignal = runWithSignal; exports.RELATIONSHIP_ZONE = RELATIONSHIP_ZONE; exports.RELATIONSHIP_MAP = RELATIONSHIP_MAP; exports.BLIND_SURFACE_STAMPS = BLIND_SURFACE_STAMPS; exports.DELETE_BOUNDARY_NOTES = DELETE_BOUNDARY_NOTES; exports.MARKER_FIELDS = MARKER_FIELDS; exports.EMPTY_REASON_STAMPS = EMPTY_REASON_STAMPS; exports.BLIND_SURFACE_INVENTORY = BLIND_SURFACE_INVENTORY; exports.REACHABILITY_PROBE_DEFAULTS = REACHABILITY_PROBE_DEFAULTS; exports.CREATE_GUIDANCE = CREATE_GUIDANCE; exports.UNTRUSTED_FIELDS_BY_RESOURCE = UNTRUSTED_FIELDS_BY_RESOURCE; exports.unwrapItems = unwrapItems; exports.unwrapItem = unwrapItem; exports.unwrapQueryCount = unwrapQueryCount; exports.unwrapOperation = unwrapOperation; exports.passthrough = passthrough; exports.HttpClient = HttpClient; exports.BOUNDED_QUERY_MAX_LIMIT = BOUNDED_QUERY_MAX_LIMIT; exports.truncateNoteChars = truncateNoteChars; exports.buildDryRunResult = buildDryRunResult; exports.mergePartialBody = mergePartialBody; exports.blindStampFor = blindStampFor; exports.decodeFileData = decodeFileData; exports.MAX_PAGES = MAX_PAGES; exports.clampPageSize = clampPageSize; exports.totalPagesFor = totalPagesFor; exports.paginate = paginate; exports.paginateItems = paginateItems; exports.collectAll = collectAll; exports.toArray = toArray; exports.FIELD_PRESETS = FIELD_PRESETS; exports.FIELD_PRESET_NAMES = FIELD_PRESET_NAMES; exports.resolveFieldsPreset = resolveFieldsPreset; exports.BaseResource = BaseResource; exports.MODEL_FIELD_SETS = MODEL_FIELD_SETS; exports.MODEL_DATE_FIELDS = MODEL_DATE_FIELDS; exports.formatUnknownNameList = formatUnknownNameList; exports.validateQueryFieldNames = validateQueryFieldNames; exports.EXPAND_RESOURCE_NAMES_MAX_IDS = EXPAND_RESOURCE_NAMES_MAX_IDS; exports.expandResourceNames = expandResourceNames; exports.ENTITY_TYPE_TO_RESOURCE = ENTITY_TYPE_TO_RESOURCE; exports.resourceForEntityType = resourceForEntityType; exports.isEnumerableResource = isEnumerableResource; exports.WORKFLOW_RESOURCES = WORKFLOW_RESOURCES; exports.MAX_FIELD_CATALOG_WIRE = MAX_FIELD_CATALOG_WIRE; exports.FIELD_CATALOG_HONESTY_NOTE = FIELD_CATALOG_HONESTY_NOTE; exports.fieldCatalog = fieldCatalog; exports.PICKLIST_VALUE_NOT_SERVED_NOTE = PICKLIST_VALUE_NOT_SERVED_NOTE; exports.TICKET_LABEL_FIELDS = TICKET_LABEL_FIELDS; exports.createNamePlan = createNamePlan; exports.addNameSibling = addNameSibling; exports.addLabelSibling = addLabelSibling; exports.resolveCompositeNames = resolveCompositeNames; exports.FETCH_MANY_MAX_ITEMS = FETCH_MANY_MAX_ITEMS; exports.validateFetchManyItems = validateFetchManyItems; exports.fetchMany = fetchMany; exports.FETCH_BY_IDS_MAX_ITEMS = FETCH_BY_IDS_MAX_ITEMS; exports.FETCH_BY_IDS_CHUNK_SIZE = FETCH_BY_IDS_CHUNK_SIZE; exports.fetchByIds = fetchByIds; exports.UI_LINK_ENTITIES = UI_LINK_ENTITIES; exports.buildUiLink = buildUiLink; exports.uiLink = uiLink;