node-autotask 0.34.0 → 0.37.1

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 (41) hide show
  1. package/CHANGELOG.md +58 -1
  2. package/MCP_TOOL_CATALOG.json +26 -9
  3. package/MCP_TOOL_MANIFEST.md +14 -13
  4. package/N8N_MCP_MANIFEST.json +5 -5
  5. package/N8N_MCP_MANIFEST.md +4 -4
  6. package/README.md +12 -5
  7. package/capabilities.json +3097 -1344
  8. package/capabilities.schema.json +4 -0
  9. package/dist/capabilities.cjs +2 -2
  10. package/dist/capabilities.d.cts +2 -0
  11. package/dist/capabilities.d.ts +2 -0
  12. package/dist/capabilities.js +1 -1
  13. package/dist/{chunk-P6YN2POI.cjs → chunk-25VGFT5M.cjs} +143 -143
  14. package/dist/{chunk-EZKM4HQ6.js → chunk-7IADHNBZ.js} +8486 -3122
  15. package/dist/{chunk-RDFL5QYE.js → chunk-7WI7FBPB.js} +12 -12
  16. package/dist/{chunk-FOOHJBPP.cjs → chunk-HBYKTXN3.cjs} +3096 -1343
  17. package/dist/{chunk-4MUBUSTL.js → chunk-KQ6HMBB4.js} +3096 -1343
  18. package/dist/{chunk-DKJP73FX.cjs → chunk-PFFW4DIK.cjs} +4657 -9597
  19. package/dist/{chunk-6ADFCU3I.js → chunk-PFJAMFUL.js} +4456 -9396
  20. package/dist/{chunk-GDQ4QM7Q.cjs → chunk-TBFXRNNE.cjs} +8452 -3088
  21. package/dist/{index-ByMU8IC2.d.ts → index-BDqw377y.d.ts} +117 -14
  22. package/dist/{index-Dx4-zpDo.d.cts → index-CqepIQfp.d.cts} +117 -14
  23. package/dist/index.cjs +22 -22
  24. package/dist/index.d.cts +2 -2
  25. package/dist/index.d.ts +2 -2
  26. package/dist/index.js +14 -14
  27. package/dist/operations/index.cjs +828 -137
  28. package/dist/operations/index.d.cts +145 -5
  29. package/dist/operations/index.d.ts +145 -5
  30. package/dist/operations/index.js +697 -6
  31. package/dist/pool.cjs +9 -9
  32. package/dist/pool.d.cts +1 -1
  33. package/dist/pool.d.ts +1 -1
  34. package/dist/pool.js +4 -4
  35. package/dist/resources/index.cjs +5 -4
  36. package/dist/resources/index.d.cts +1 -1
  37. package/dist/resources/index.d.ts +1 -1
  38. package/dist/resources/index.js +14 -13
  39. package/docs/API.md +331 -13
  40. package/docs/LIVE-TESTING.md +11 -11
  41. package/package.json +1 -1
@@ -44,29 +44,49 @@
44
44
 
45
45
 
46
46
 
47
- var _chunkGDQ4QM7Qcjs = require('../chunk-GDQ4QM7Q.cjs');
48
47
 
49
48
 
50
- var _chunkFOOHJBPPcjs = require('../chunk-FOOHJBPP.cjs');
49
+
50
+
51
+
52
+
53
+
54
+
55
+
56
+
57
+
58
+
59
+
60
+
61
+
62
+
63
+
64
+
65
+
66
+
67
+ var _chunkTBFXRNNEcjs = require('../chunk-TBFXRNNE.cjs');
68
+
69
+
70
+ var _chunkHBYKTXN3cjs = require('../chunk-HBYKTXN3.cjs');
51
71
 
52
72
  // src/operations/searchAcrossResources.ts
53
73
  var DEFAULT_LIMIT = 25;
54
74
  function resourceFor(client, key) {
55
- return client[_chunkGDQ4QM7Qcjs.camelKey.call(void 0, key)];
75
+ return client[_chunkTBFXRNNEcjs.camelKey.call(void 0, key)];
56
76
  }
57
77
  async function searchAcrossResources(client, query, opts = {}) {
58
78
  const text = query.trim();
59
79
  if (text === "") {
60
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)("searchAcrossResources: query must be a non-empty string");
80
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)("searchAcrossResources: query must be a non-empty string");
61
81
  }
62
- const keys = _nullishCoalesce(opts.resources, () => ( _chunkGDQ4QM7Qcjs.WORKFLOW_RESOURCES));
82
+ const keys = _nullishCoalesce(opts.resources, () => ( _chunkTBFXRNNEcjs.WORKFLOW_RESOURCES));
63
83
  if (keys.length === 0) {
64
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)("searchAcrossResources: no resources requested");
84
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)("searchAcrossResources: no resources requested");
65
85
  }
66
- const limit = _chunkGDQ4QM7Qcjs.clampPageSize.call(void 0, _nullishCoalesce(opts.limit, () => ( DEFAULT_LIMIT)));
86
+ const limit = _chunkTBFXRNNEcjs.clampPageSize.call(void 0, _nullishCoalesce(opts.limit, () => ( DEFAULT_LIMIT)));
67
87
  const totalLimit = opts.totalLimit;
68
88
  if (totalLimit !== void 0 && !(Number.isInteger(totalLimit) && totalLimit >= 1)) {
69
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)("searchAcrossResources: totalLimit must be a positive integer");
89
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)("searchAcrossResources: totalLimit must be a positive integer");
70
90
  }
71
91
  const results = [];
72
92
  const skipped = [];
@@ -97,7 +117,7 @@ async function searchAcrossResources(client, query, opts = {}) {
97
117
 
98
118
  // src/operations/resolveAny.ts
99
119
  function resourceFor2(client, key) {
100
- return client[_chunkGDQ4QM7Qcjs.camelKey.call(void 0, key)];
120
+ return client[_chunkTBFXRNNEcjs.camelKey.call(void 0, key)];
101
121
  }
102
122
  var FAULT_CATEGORIES = /* @__PURE__ */ new Set(["auth", "rate_limit", "server", "network", "timeout", "policy"]);
103
123
  function missCost(identifier) {
@@ -106,13 +126,13 @@ function missCost(identifier) {
106
126
  }
107
127
  async function resolveAny(client, identifier, opts = {}) {
108
128
  if (typeof identifier === "number") {
109
- _chunkGDQ4QM7Qcjs.parseIdentifier.call(void 0, identifier, "identifier");
129
+ _chunkTBFXRNNEcjs.parseIdentifier.call(void 0, identifier, "identifier");
110
130
  } else if (identifier.trim() === "") {
111
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)("resolveAny: identifier must be non-empty");
131
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)("resolveAny: identifier must be non-empty");
112
132
  }
113
- const keys = _nullishCoalesce(opts.resources, () => ( _chunkGDQ4QM7Qcjs.WORKFLOW_RESOURCES));
133
+ const keys = _nullishCoalesce(opts.resources, () => ( _chunkTBFXRNNEcjs.WORKFLOW_RESOURCES));
114
134
  if (keys.length === 0) {
115
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)("resolveAny: no resources requested");
135
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)("resolveAny: no resources requested");
116
136
  }
117
137
  const results = [];
118
138
  for (const key of keys) {
@@ -142,9 +162,9 @@ async function resolveAny(client, identifier, opts = {}) {
142
162
  } catch (err) {
143
163
  let code;
144
164
  let candidates = [];
145
- if (err instanceof _chunkGDQ4QM7Qcjs.AutotaskConfigError) {
165
+ if (err instanceof _chunkTBFXRNNEcjs.AutotaskConfigError) {
146
166
  code = "CONFIG_ERROR";
147
- } else if (_chunkGDQ4QM7Qcjs.isAutotaskError.call(void 0, err)) {
167
+ } else if (_chunkTBFXRNNEcjs.isAutotaskError.call(void 0, err)) {
148
168
  if (FAULT_CATEGORIES.has(err.category)) throw err;
149
169
  code = err.code;
150
170
  if (code === "RESOLUTION_AMBIGUOUS" && err.resourceIds !== void 0) {
@@ -171,7 +191,7 @@ async function resolveAny(client, identifier, opts = {}) {
171
191
  // src/operations/aggregate.ts
172
192
  var AGGREGATE_TOP_MAX = 100;
173
193
  var AGGREGATE_DEFAULT_TOP = 25;
174
- var AGGREGATE_DEFAULT_LIMIT = _chunkGDQ4QM7Qcjs.BOUNDED_QUERY_MAX_LIMIT;
194
+ var AGGREGATE_DEFAULT_LIMIT = _chunkTBFXRNNEcjs.BOUNDED_QUERY_MAX_LIMIT;
175
195
  var AGGREGATE_DATE_BUCKETS = ["month", "week", "year"];
176
196
  var DATE_ONLY_RE = /^(\d{4})-(\d{2})-(\d{2})$/;
177
197
  var DATETIME_RE = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(\.\d{1,9})?(Z|[+-]\d{2}:?\d{2})?$/;
@@ -228,12 +248,12 @@ function dateBucketLabel(value, bucket) {
228
248
  }
229
249
  var QUERY_RESOURCE_KEYS = (() => {
230
250
  const s = /* @__PURE__ */ new Set();
231
- for (const rec of _chunkFOOHJBPPcjs.CAPABILITIES) if (rec.operation === "query") s.add(rec.resource);
251
+ for (const rec of _chunkHBYKTXN3cjs.CAPABILITIES) if (rec.operation === "query") s.add(rec.resource);
232
252
  return s;
233
253
  })();
234
254
  var AGGREGATE_OPT_KEYS = ["groupBy", "sum", "top", "limit"];
235
255
  var OP_RE = /^([a-z0-9_]+)\.query$/;
236
- function num(v) {
256
+ function num2(v) {
237
257
  return typeof v === "number" && Number.isFinite(v) ? v : 0;
238
258
  }
239
259
  function parseOperationKey(operation, problems) {
@@ -264,15 +284,15 @@ function parseFilterConditions(filter, problems) {
264
284
  return [];
265
285
  }
266
286
  try {
267
- return _chunkGDQ4QM7Qcjs.buildFilter.call(void 0, conds).filter;
287
+ return _chunkTBFXRNNEcjs.buildFilter.call(void 0, conds).filter;
268
288
  } catch (err) {
269
- problems.push(err instanceof _chunkGDQ4QM7Qcjs.AutotaskConfigError ? err.message : `filter must be the query-bag filter (13 operators; caps 500 OR-conditions / 1 UDF / 8000 chars); ${String(err)}`);
289
+ problems.push(err instanceof _chunkTBFXRNNEcjs.AutotaskConfigError ? err.message : `filter must be the query-bag filter (13 operators; caps 500 OR-conditions / 1 UDF / 8000 chars); ${String(err)}`);
270
290
  return [];
271
291
  }
272
292
  }
273
293
  function checkOptsBag(opts, problems) {
274
294
  if (opts !== void 0 && (typeof opts !== "object" || opts === null || Array.isArray(opts))) {
275
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
295
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
276
296
  `aggregate: opts must be the options object (got ${Array.isArray(opts) ? "an array" : typeof opts})`,
277
297
  { operation: "operations.aggregate" }
278
298
  );
@@ -352,7 +372,7 @@ function parseTopAndLimit(opts, problems) {
352
372
  if (!Number.isInteger(opts.limit)) {
353
373
  problems.push(`limit must be an integer (got ${String(opts.limit)})`);
354
374
  } else {
355
- limit = Math.min(Math.max(opts.limit, 1), _chunkGDQ4QM7Qcjs.BOUNDED_QUERY_MAX_LIMIT);
375
+ limit = Math.min(Math.max(opts.limit, 1), _chunkTBFXRNNEcjs.BOUNDED_QUERY_MAX_LIMIT);
356
376
  }
357
377
  }
358
378
  return { top, limit };
@@ -364,14 +384,14 @@ function validateAggregate(operation, filter, opts) {
364
384
  checkOptsBag(opts, problems);
365
385
  const oracles = {
366
386
  resourceKey,
367
- fieldSets: resourceKey !== void 0 ? _chunkGDQ4QM7Qcjs.MODEL_FIELD_SETS[resourceKey] : void 0,
368
- dateSets: resourceKey !== void 0 ? _chunkGDQ4QM7Qcjs.MODEL_DATE_FIELDS[resourceKey] : void 0
387
+ fieldSets: resourceKey !== void 0 ? _chunkTBFXRNNEcjs.MODEL_FIELD_SETS[resourceKey] : void 0,
388
+ dateSets: resourceKey !== void 0 ? _chunkTBFXRNNEcjs.MODEL_DATE_FIELDS[resourceKey] : void 0
369
389
  };
370
390
  const groupBy = parseGroupBy(opts, oracles, problems);
371
391
  const sum = checkSumFields("sum", opts.sum, oracles, problems);
372
392
  const { top, limit } = parseTopAndLimit(opts, problems);
373
393
  if (problems.length > 0) {
374
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
394
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
375
395
  `aggregate: ${problems.length} problem(s) found pre-request (zero wire was issued)
376
396
  - ` + problems.join("\n- "),
377
397
  { operation: "operations.aggregate" }
@@ -398,16 +418,16 @@ function foldGroups(items, v) {
398
418
  }
399
419
  g.count += 1;
400
420
  if (g.sums !== void 0) {
401
- for (const f of v.sum) g.sums[f] = (_nullishCoalesce(g.sums[f], () => ( 0))) + num(item[f]);
421
+ for (const f of v.sum) g.sums[f] = (_nullishCoalesce(g.sums[f], () => ( 0))) + num2(item[f]);
402
422
  }
403
423
  }
404
424
  return [...groups.values()].sort((a, b) => b.count - a.count || (a.keyOrder < b.keyOrder ? -1 : a.keyOrder > b.keyOrder ? 1 : 0));
405
425
  }
406
426
  async function aggregate(client, operation, filter, opts = {}) {
407
427
  const v = validateAggregate(operation, filter, opts);
408
- const holder = client[_chunkGDQ4QM7Qcjs.camelKey.call(void 0, v.resourceKey)];
428
+ const holder = client[_chunkTBFXRNNEcjs.camelKey.call(void 0, v.resourceKey)];
409
429
  if (holder === void 0) {
410
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(`aggregate: the client exposes no accessor for resource "${v.resourceKey}"`, {
430
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(`aggregate: the client exposes no accessor for resource "${v.resourceKey}"`, {
411
431
  operation: "operations.aggregate",
412
432
  suggestedAction: "Rebuild the client from the SDK build that ships this registry (the resource set is pinned by the plan)."
413
433
  });
@@ -437,24 +457,692 @@ async function aggregate(client, operation, filter, opts = {}) {
437
457
  return result;
438
458
  }
439
459
 
460
+ // src/operations/revenueRollup.ts
461
+ var OP = "operations.revenueRollup";
462
+ var PAGE = 500;
463
+ var CONCURRENCY = 3;
464
+ var DEFAULT_BUDGET = 90;
465
+ var DEFAULT_BUDGET_NON_CHARGEABLE = 150;
466
+ var BUDGET_CAP = 200;
467
+ var TOP_MAX = 100;
468
+ var SCOPE_IDS_MAX = 100;
469
+ var TENANT_HOURLY_LIMIT = 1e4;
470
+ var DEFAULT_GROUP_BY = ["vertical", "contractType"];
471
+ var DEFAULT_CONTRACT_TYPE_RE = /^\s*(recurring|fixed)\b/i;
472
+ var CONTRACTS_PATH = "/V1.0/Contracts";
473
+ var COMPANIES_PATH = "/V1.0/Companies";
474
+ var BILLING_ITEMS_PATH = "/V1.0/BillingItems";
475
+ var LINE_TYPE_FIELDS = ["billingItemType", "timeEntryID", "expenseItemID", ..._chunkTBFXRNNEcjs.CHARGE_LINE_FKS, ..._chunkTBFXRNNEcjs.SERVICE_LINE_FKS];
476
+ var isLabour = (line) => _chunkTBFXRNNEcjs.billingLineType.call(void 0, line) === "labour";
477
+ function picklistKey(c, dim, path, field, raw, missing) {
478
+ const id = _chunkTBFXRNNEcjs.num.call(void 0, raw);
479
+ if (id === 0) return { id: null, label: missing };
480
+ const label = _optionalChain([c, 'access', _2 => _2.labels, 'access', _3 => _3[path], 'optionalAccess', _4 => _4.get, 'call', _5 => _5(field), 'optionalAccess', _6 => _6.get, 'call', _7 => _7(id)]);
481
+ if (label === void 0) {
482
+ c.unlabelled.add(`${dim}: ${field} value ${id} has no label on the live ${path} picklist (id-only)`);
483
+ return { id };
484
+ }
485
+ return { id, label };
486
+ }
487
+ var DIMENSIONS = {
488
+ vertical: {
489
+ joins: { companies: ["marketSegmentID"] },
490
+ picklist: COMPANIES_PATH,
491
+ key: (c) => picklistKey(c, "vertical", COMPANIES_PATH, "marketSegmentID", _optionalChain([c, 'access', _8 => _8.company, 'optionalAccess', _9 => _9["marketSegmentID"]]), "unassigned")
492
+ },
493
+ contractType: {
494
+ key: (c) => picklistKey(c, "contractType", CONTRACTS_PATH, "contractType", c.contract["contractType"], "none")
495
+ },
496
+ contractCategory: {
497
+ key: (c) => picklistKey(c, "contractCategory", CONTRACTS_PATH, "contractCategory", c.contract["contractCategory"], "uncategorised")
498
+ },
499
+ company: {
500
+ joins: { companies: ["companyName"] },
501
+ key: (c) => ({ id: _chunkTBFXRNNEcjs.num.call(void 0, c.line["companyID"]), name: String(_nullishCoalesce(_optionalChain([c, 'access', _10 => _10.company, 'optionalAccess', _11 => _11["companyName"]]), () => ( ""))) })
502
+ },
503
+ month: {
504
+ key: (c) => ({ id: c.invoice.month })
505
+ },
506
+ billingItemKind: {
507
+ lineFields: LINE_TYPE_FIELDS,
508
+ picklist: BILLING_ITEMS_PATH,
509
+ key: (c) => _chunkTBFXRNNEcjs.num.call(void 0, c.line["billingItemType"]) === 0 ? { id: _chunkTBFXRNNEcjs.billingLineType.call(void 0, c.line), label: _chunkTBFXRNNEcjs.billingLineType.call(void 0, c.line) } : picklistKey(c, "billingItemKind", BILLING_ITEMS_PATH, "billingItemType", c.line["billingItemType"], "other")
510
+ },
511
+ contract: {
512
+ joins: { contracts: ["contractName"] },
513
+ key: (c) => ({ id: _chunkTBFXRNNEcjs.num.call(void 0, c.line["contractID"]), name: String(_nullishCoalesce(c.contract["contractName"], () => ( ""))) })
514
+ },
515
+ // Per line (no contract-pointer fallback): association → level2 (the Line of Business, `name`) + level1 (the division).
516
+ lineOfBusiness: {
517
+ lineFields: ["organizationalLevelAssociationID"],
518
+ joins: { organizationalLevelAssociations: [], organizationalLevel1s: [], organizationalLevel2s: [] },
519
+ unresolved: "unresolvedAssociations",
520
+ key: (c) => {
521
+ const id = _chunkTBFXRNNEcjs.num.call(void 0, c.line["organizationalLevelAssociationID"]);
522
+ if (id === 0) return { id: null, label: "no LOB assigned" };
523
+ const a = c.joined.organizationalLevelAssociations.get(id);
524
+ const l1 = c.joined.organizationalLevel1s.get(_chunkTBFXRNNEcjs.num.call(void 0, _optionalChain([a, 'optionalAccess', _12 => _12["organizationalLevel1ID"]])));
525
+ const l2 = c.joined.organizationalLevel2s.get(_chunkTBFXRNNEcjs.num.call(void 0, _optionalChain([a, 'optionalAccess', _13 => _13["organizationalLevel2ID"]])));
526
+ if (l1 === void 0 || l2 === void 0) return "unresolvedAssociations";
527
+ return { id, name: String(_nullishCoalesce(l2["name"], () => ( ""))), division: String(_nullishCoalesce(l1["name"], () => ( ""))) };
528
+ }
529
+ },
530
+ // Labour lines only; a non-labour line (or a labour line with no time entry, e.g. an adjustment) is "n/a".
531
+ resource: {
532
+ lineFields: LINE_TYPE_FIELDS,
533
+ joins: { timeEntries: [], resources: [] },
534
+ unresolved: "unresolvedTimeEntries",
535
+ key: (c) => {
536
+ const te = _chunkTBFXRNNEcjs.num.call(void 0, c.line["timeEntryID"]);
537
+ if (!isLabour(c.line) || te === 0) return { id: null, label: "n/a" };
538
+ const id = _chunkTBFXRNNEcjs.num.call(void 0, _optionalChain([c, 'access', _14 => _14.joined, 'access', _15 => _15.timeEntries, 'access', _16 => _16.get, 'call', _17 => _17(te), 'optionalAccess', _18 => _18["resourceID"]]));
539
+ const r = c.joined.resources.get(id);
540
+ if (r === void 0) return "unresolvedTimeEntries";
541
+ return { id, name: `${String(_nullishCoalesce(r["firstName"], () => ( "")))} ${String(_nullishCoalesce(r["lastName"], () => ( "")))}`.trim() };
542
+ }
543
+ },
544
+ billingCode: {
545
+ lineFields: ["billingCodeID"],
546
+ joins: { billingCodes: [] },
547
+ unresolved: "unresolvedBillingCodes",
548
+ key: (c) => {
549
+ const id = _chunkTBFXRNNEcjs.num.call(void 0, c.line["billingCodeID"]);
550
+ if (id === 0) return { id: null, label: "none" };
551
+ const b = c.joined.billingCodes.get(id);
552
+ return b === void 0 ? "unresolvedBillingCodes" : { id, name: String(_nullishCoalesce(b["name"], () => ( ""))) };
553
+ }
554
+ }
555
+ };
556
+ var fk = (rows, field) => [...rows].map((r) => _chunkTBFXRNNEcjs.num.call(void 0, r[field]));
557
+ var ONE_CHUNK = (idChunks) => Math.min(1, idChunks);
558
+ var JOINS = {
559
+ contracts: {
560
+ make: (http) => new (0, _chunkTBFXRNNEcjs.ContractsResource)(http, PAGE),
561
+ fields: ["id", "contractType", "contractCategory"],
562
+ ids: (lines) => fk(lines, "contractID")
563
+ },
564
+ companies: {
565
+ make: (http) => new (0, _chunkTBFXRNNEcjs.CompaniesResource)(http, PAGE),
566
+ fields: ["id"],
567
+ ids: (lines) => fk(lines, "companyID")
568
+ },
569
+ organizationalLevelAssociations: {
570
+ make: (http) => new (0, _chunkTBFXRNNEcjs.OrganizationalLevelAssociationsResource)(http, PAGE),
571
+ fields: ["id", "organizationalLevel1ID", "organizationalLevel2ID"],
572
+ ids: (lines) => fk(lines, "organizationalLevelAssociationID")
573
+ },
574
+ organizationalLevel1s: {
575
+ make: (http) => new (0, _chunkTBFXRNNEcjs.OrganizationalLevel1sResource)(http, PAGE),
576
+ fields: ["id", "name"],
577
+ ids: (_, j) => fk(j["organizationalLevelAssociations"].values(), "organizationalLevel1ID"),
578
+ chunks: ONE_CHUNK
579
+ },
580
+ organizationalLevel2s: {
581
+ make: (http) => new (0, _chunkTBFXRNNEcjs.OrganizationalLevel2sResource)(http, PAGE),
582
+ fields: ["id", "name"],
583
+ ids: (_, j) => fk(j["organizationalLevelAssociations"].values(), "organizationalLevel2ID"),
584
+ chunks: ONE_CHUNK
585
+ },
586
+ timeEntries: {
587
+ make: (http) => new (0, _chunkTBFXRNNEcjs.TimeEntriesResource)(http, PAGE),
588
+ fields: ["id", "resourceID"],
589
+ ids: (lines) => fk(lines.filter(isLabour), "timeEntryID"),
590
+ // One time entry per labour line: the line count is the upper bound (labour share unknown pre-walk).
591
+ chunks: (_, lines) => pages(lines)
592
+ },
593
+ resources: {
594
+ make: (http, client) => new (0, _chunkTBFXRNNEcjs.ResourcesResource)(http, client.config, PAGE),
595
+ fields: ["id", "firstName", "lastName"],
596
+ ids: (_, j) => fk(j["timeEntries"].values(), "resourceID"),
597
+ chunks: ONE_CHUNK
598
+ },
599
+ billingCodes: {
600
+ make: (http) => new (0, _chunkTBFXRNNEcjs.BillingCodesResource)(http, PAGE),
601
+ fields: ["id", "name"],
602
+ ids: (lines) => fk(lines, "billingCodeID")
603
+ }
604
+ };
605
+ var LINE_FIELDS = ["id", "invoiceID", "companyID", "contractID", "totalAmount", "internalCurrencyTotalAmount", "extendedPrice", "internalCurrencyExtendedPrice"];
606
+ var OPT_KEYS = ["companyIDs", "ownerResourceID", "contractIDs", "tenantWide", "dateFrom", "dateTo", "contractTypes", "contractCategories", "groupBy", "top", "maxVendorCalls", "includeNonChargeable"];
607
+ var NC_LINE_FIELDS = ["nonBillable", "quantity", ...LINE_TYPE_FIELDS];
608
+ var SCOPE_KEYS = ["companyIDs", "ownerResourceID", "contractIDs", "tenantWide"];
609
+ var isPosInt = (v) => Number.isSafeInteger(v) && v > 0;
610
+ function checkIdList(name, v, problems) {
611
+ if (!Array.isArray(v) || v.length === 0 || v.length > SCOPE_IDS_MAX || !v.every(isPosInt)) {
612
+ problems.push(`${name} must be a non-empty array of at most ${SCOPE_IDS_MAX} positive integer ids`);
613
+ return void 0;
614
+ }
615
+ return [...new Set(v)].sort((a, b) => a - b);
616
+ }
617
+ function checkSelector(name, v, problems) {
618
+ if (v === void 0) return void 0;
619
+ if (!Array.isArray(v) || v.length === 0 || !v.every((x) => isPosInt(x) || typeof x === "string" && x.trim() !== "")) {
620
+ problems.push(`${name} must be a non-empty array of picklist ids or labels`);
621
+ return void 0;
622
+ }
623
+ return v;
624
+ }
625
+ function checkInt(name, v, def, max, problems) {
626
+ if (v === void 0) return def;
627
+ if (!Number.isInteger(v) || v < 1 || v > max) {
628
+ problems.push(`${name} must be an integer 1..${max} (got ${String(v)})`);
629
+ return def;
630
+ }
631
+ return v;
632
+ }
633
+ function validate(opts) {
634
+ if (typeof opts !== "object" || opts === null || Array.isArray(opts)) {
635
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)("revenueRollup: opts must be the options object { <scope>, dateFrom, dateTo, ... } (zero wire was issued)", { operation: OP });
636
+ }
637
+ const o = opts;
638
+ const problems = [];
639
+ for (const k of Object.keys(o)) if (!OPT_KEYS.includes(k)) problems.push(`unknown opts key "${k}" \u2014 the bag is closed: ${OPT_KEYS.join(", ")}`);
640
+ const given = SCOPE_KEYS.filter((k) => o[k] !== void 0);
641
+ if (given.length !== 1) {
642
+ problems.push(given.length === 0 ? "a scope is required: exactly one of companyIDs, ownerResourceID, contractIDs, or tenantWide: true" : `exactly one scope key is allowed (got ${given.join(", ")})`);
643
+ }
644
+ const scopeKind = _nullishCoalesce(given[0], () => ( "tenantWide"));
645
+ let scopeIds;
646
+ if (given.length === 1) {
647
+ if (scopeKind === "companyIDs" || scopeKind === "contractIDs") scopeIds = checkIdList(scopeKind, o[scopeKind], problems);
648
+ if (scopeKind === "ownerResourceID" && !isPosInt(o.ownerResourceID)) problems.push("ownerResourceID must be a positive integer resource id");
649
+ if (scopeKind === "tenantWide" && o.tenantWide !== true) problems.push("tenantWide must be exactly true");
650
+ }
651
+ const { dateFrom, dateTo } = o;
652
+ if (!_chunkTBFXRNNEcjs.isDateYMD.call(void 0, dateFrom) || !_chunkTBFXRNNEcjs.isDateYMD.call(void 0, dateTo)) {
653
+ problems.push("dateFrom and dateTo are both required as YYYY-MM-DD (the window is inclusive, whole UTC days)");
654
+ } else if (dateFrom > dateTo) {
655
+ problems.push(`dateFrom ${dateFrom} is after dateTo ${dateTo}`);
656
+ } else if (_chunkTBFXRNNEcjs.monthsInWindow.call(void 0, dateFrom, dateTo) > _chunkTBFXRNNEcjs.PROFITABILITY_MAX_WINDOW_MONTHS) {
657
+ problems.push(`the window spans ${_chunkTBFXRNNEcjs.monthsInWindow.call(void 0, dateFrom, dateTo)} months; the cap is ${_chunkTBFXRNNEcjs.PROFITABILITY_MAX_WINDOW_MONTHS}`);
658
+ }
659
+ let groupBy = [...DEFAULT_GROUP_BY];
660
+ if (o.groupBy !== void 0) {
661
+ const g = o.groupBy;
662
+ if (!Array.isArray(g) || g.length === 0 || new Set(g).size !== g.length) {
663
+ problems.push(`groupBy must be a non-empty array of distinct dimensions: ${Object.keys(DIMENSIONS).join(", ")}`);
664
+ } else {
665
+ for (const d of g) if (!Object.hasOwn(DIMENSIONS, d)) problems.push(`unknown groupBy dimension "${String(d)}" \u2014 the dimensions are: ${Object.keys(DIMENSIONS).join(", ")}`);
666
+ groupBy = g;
667
+ }
668
+ }
669
+ const v = {
670
+ dateFrom,
671
+ dateTo,
672
+ scopeKind,
673
+ scopeIds,
674
+ ownerResourceID: scopeKind === "ownerResourceID" ? o.ownerResourceID : void 0,
675
+ contractTypes: checkSelector("contractTypes", o.contractTypes, problems),
676
+ contractCategories: checkSelector("contractCategories", o.contractCategories, problems),
677
+ groupBy,
678
+ top: checkInt("top", o.top, TOP_MAX, TOP_MAX, problems),
679
+ budget: checkInt("maxVendorCalls", o.maxVendorCalls, o.includeNonChargeable === true ? DEFAULT_BUDGET_NON_CHARGEABLE : DEFAULT_BUDGET, BUDGET_CAP, problems),
680
+ nonChargeable: o.includeNonChargeable === true
681
+ };
682
+ if (o.includeNonChargeable !== void 0 && typeof o.includeNonChargeable !== "boolean") problems.push("includeNonChargeable must be a boolean");
683
+ if (problems.length > 0) {
684
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(`revenueRollup: ${problems.length} problem(s) found pre-request (zero wire was issued)
685
+ - ${problems.join("\n- ")}`, { operation: OP });
686
+ }
687
+ return v;
688
+ }
689
+ function resolveSelector(name, sel, values) {
690
+ const out = /* @__PURE__ */ new Map();
691
+ const misses = [];
692
+ for (const s of sel) {
693
+ const hits = typeof s === "number" ? values.has(s) ? [s] : [] : [...values].filter(([, l]) => l.trim().toLowerCase() === s.trim().toLowerCase()).map(([id]) => id);
694
+ if (hits.length === 0) misses.push(JSON.stringify(s));
695
+ for (const h of hits) out.set(h, values.get(h));
696
+ }
697
+ if (misses.length > 0) throw unmatched(name, `${misses.join(", ")} matched no live value`, values);
698
+ return out;
699
+ }
700
+ function unmatched(name, what, values) {
701
+ const live = [...values].map(([id, l]) => `${id} ${l}`).join("; ") || "(the picklist serves no values)";
702
+ return new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(`revenueRollup: ${name}: ${what}. Live values (id label): ${live}`, {
703
+ operation: OP,
704
+ suggestedAction: `Pass ${name} as ids or exact labels from the live list.`
705
+ });
706
+ }
707
+ var sortedRecord = (m) => Object.fromEntries([...m].sort((a, b) => a[0] - b[0]).map(([id, l]) => [String(id), l]));
708
+ var chunk = (a) => {
709
+ const out = [];
710
+ for (let i = 0; i < a.length; i += PAGE) out.push(a.slice(i, i + PAGE));
711
+ return out;
712
+ };
713
+ var byId = (rows) => [...new Map(rows.map((r) => [_chunkTBFXRNNEcjs.num.call(void 0, r["id"]), r])).values()];
714
+ var cents = (v) => Math.round(_chunkTBFXRNNEcjs.num.call(void 0, v) * 100);
715
+ var revC = (line) => cents(_chunkTBFXRNNEcjs.internalAmount.call(void 0, line, "internalCurrencyTotalAmount", "totalAmount"));
716
+ var extC = (line) => cents(_chunkTBFXRNNEcjs.internalAmount.call(void 0, line, "internalCurrencyExtendedPrice", "extendedPrice"));
717
+ var INTERNAL_FIELDS = ["internalCurrencyTotalAmount", "internalCurrencyExtendedPrice"];
718
+ var lacksInternal = (line) => INTERNAL_FIELDS.some((k) => !Number.isFinite(line[k]));
719
+ var money = (c) => c / 100;
720
+ var pages = (n) => Math.ceil(n / PAGE);
721
+ async function collect(res, filter, includeFields) {
722
+ const out = [];
723
+ for await (const r of res.query({ filter, includeFields, maxRecords: PAGE })) out.push(r);
724
+ return out;
725
+ }
726
+ function blindCount() {
727
+ return new (0, _chunkTBFXRNNEcjs.AutotaskError)("revenueRollup: a gate count came back blind (unknown, not zero); the roll-up cannot be sized", {
728
+ code: "INVALID_RESPONSE",
729
+ category: "server",
730
+ operation: OP,
731
+ details: { reason: "blind_count" },
732
+ suggestedAction: "Check the API user can see invoices and billing items (operations.blindSurfaces), then retry."
733
+ });
734
+ }
735
+ function countMismatch(what, streamed, counted, rows) {
736
+ const rowNote = rows !== void 0 && rows !== streamed ? ` (${rows} rows)` : "";
737
+ return new (0, _chunkTBFXRNNEcjs.AutotaskError)(`revenueRollup: the ${what} stream returned ${streamed} distinct ids${rowNote} but the gate count was ${counted} (the data changed mid-walk or a page dropped rows); the fold was discarded`, {
738
+ code: "INVALID_RESPONSE",
739
+ category: "server",
740
+ operation: OP,
741
+ details: { reason: "count_mismatch", stream: what, streamed, counted },
742
+ suggestedAction: "Retry the call."
743
+ });
744
+ }
745
+ function budgetError(message, details, suggestedAction) {
746
+ return new (0, _chunkTBFXRNNEcjs.AutotaskError)(message, { code: "BUDGET_EXCEEDED", category: "policy", operation: OP, details, suggestedAction });
747
+ }
748
+ function lastMonthsFrom(dateTo, months) {
749
+ return new Date(Date.UTC(Number(dateTo.slice(0, 4)), Number(dateTo.slice(5, 7)) - months, 1)).toISOString().slice(0, 10);
750
+ }
751
+ async function revenueRollup(client, opts) {
752
+ const v = validate(opts);
753
+ const raw = client.http;
754
+ let calls = 0;
755
+ let estimate = 0;
756
+ const sizingMin = [.../* @__PURE__ */ new Set([CONTRACTS_PATH, ...v.groupBy.flatMap((d) => DIMENSIONS[d].picklist ? [DIMENSIONS[d].picklist] : [])])].length + (v.scopeKind === "ownerResourceID" ? 1 : 0) + 2 + (v.nonChargeable ? 1 : 0);
757
+ const http = Object.create(raw);
758
+ http.request = (o) => {
759
+ if (calls >= v.budget && estimate === 0) {
760
+ throw budgetError(
761
+ `revenueRollup: the vendor-call budget of ${v.budget} is below the sizing overhead (labels, scope and count calls: at least ${sizingMin} for this call); the roll-up could not be sized and no stream was read. Retry with a higher maxVendorCalls (cap ${BUDGET_CAP}); the refusal then names the full estimate.`,
762
+ { phase: "estimate", estimate: sizingMin, budget: v.budget, vendorCalls: calls, suggestions: [{ maxVendorCalls: sizingMin }] },
763
+ `Pass maxVendorCalls >= ${sizingMin} (cap ${BUDGET_CAP}).`
764
+ );
765
+ }
766
+ if (calls >= v.budget) {
767
+ throw budgetError(
768
+ `revenueRollup: the vendor-call budget of ${v.budget} was exhausted mid-walk (pre-walk estimate ${estimate}); the partial fold was discarded. Retry with a higher maxVendorCalls (cap ${BUDGET_CAP}) or a shorter window / a scope.`,
769
+ { phase: "walk", budget: v.budget, vendorCalls: calls, estimate },
770
+ `Pass maxVendorCalls > ${v.budget} (cap ${BUDGET_CAP}), a later dateFrom, or a scope.`
771
+ );
772
+ }
773
+ calls += 1;
774
+ return raw.request(o);
775
+ };
776
+ const groupDims = v.groupBy.map((d) => DIMENSIONS[d]);
777
+ const paths = [.../* @__PURE__ */ new Set([CONTRACTS_PATH, ...groupDims.flatMap((d) => d.picklist ? [d.picklist] : [])])];
778
+ const labels = {};
779
+ for (const p of paths) labels[p] = await _chunkTBFXRNNEcjs.readPicklists.call(void 0, http, p, OP);
780
+ const contractLabels = labels[CONTRACTS_PATH];
781
+ const typeValues = _nullishCoalesce(contractLabels.get("contractType"), () => ( /* @__PURE__ */ new Map()));
782
+ const inTypes = v.contractTypes ? resolveSelector("contractTypes", v.contractTypes, typeValues) : new Map([...typeValues].filter(([, l]) => DEFAULT_CONTRACT_TYPE_RE.test(l)));
783
+ if (inTypes.size === 0) throw unmatched("contractTypes", "no live contract type label starts with 'Recurring' or 'Fixed' (the default)", typeValues);
784
+ const inCategories = v.contractCategories ? resolveSelector("contractCategories", v.contractCategories, _nullishCoalesce(contractLabels.get("contractCategory"), () => ( /* @__PURE__ */ new Map()))) : void 0;
785
+ let scopeIds = v.scopeIds;
786
+ if (v.scopeKind === "ownerResourceID") {
787
+ const owned = /* @__PURE__ */ new Set();
788
+ for await (const c of new (0, _chunkTBFXRNNEcjs.CompaniesResource)(http, PAGE).query({ filter: [{ field: "ownerResourceID", op: "eq", value: v.ownerResourceID }], includeFields: ["id"], maxRecords: PAGE })) {
789
+ const id = _chunkTBFXRNNEcjs.num.call(void 0, c.id);
790
+ if (id > 0) owned.add(id);
791
+ if (owned.size > SCOPE_IDS_MAX) break;
792
+ }
793
+ scopeIds = [...owned].sort((a, b) => a - b);
794
+ if (scopeIds.length === 0 || scopeIds.length > SCOPE_IDS_MAX) {
795
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
796
+ `revenueRollup: ownerResourceID ${v.ownerResourceID} resolves to ${scopeIds.length > SCOPE_IDS_MAX ? `more than ${SCOPE_IDS_MAX}` : 0} companies (companies.query; 1..${SCOPE_IDS_MAX} supported)`,
797
+ { operation: OP, suggestedAction: "Pass companyIDs explicitly, or tenantWide: true." }
798
+ );
799
+ }
800
+ }
801
+ const scopeCond = scopeIds === void 0 ? [] : [{ field: v.scopeKind === "contractIDs" ? "contractID" : "companyID", op: "in", value: scopeIds }];
802
+ const invoices = new (0, _chunkTBFXRNNEcjs.InvoicesResource)(http, PAGE);
803
+ const billingItems = new (0, _chunkTBFXRNNEcjs.BillingItemsResource)(http, PAGE);
804
+ const windowOn = (field) => [{ field, op: "gte", value: v.dateFrom }, { field, op: "lt", value: _chunkTBFXRNNEcjs.dayAfter.call(void 0, v.dateTo) }];
805
+ const invoiceFilter = (voided2) => [...windowOn("invoiceDateTime"), { field: "isVoided", op: "eq", value: voided2 }];
806
+ const withVoided = v.scopeKind !== "contractIDs";
807
+ const voidedFilter = [...invoiceFilter(true), ...scopeIds !== void 0 && withVoided ? [{ field: "companyID", op: "in", value: scopeIds }] : []];
808
+ const nInvoices = await invoices.count({ filter: invoiceFilter(false) });
809
+ const nLines = await billingItems.count({ filter: [...windowOn("itemDate"), { field: "invoiceID", op: "exist" }, ...scopeCond] });
810
+ const uninvoicedFilter = [{ field: "invoiceID", op: "notExist" }, ...windowOn("itemDate"), ...scopeCond];
811
+ const nUninvoiced = v.nonChargeable ? await billingItems.count({ filter: uninvoicedFilter }) : 0;
812
+ if (typeof nInvoices !== "number" || typeof nLines !== "number" || typeof nUninvoiced !== "number") throw blindCount();
813
+ const joinsNeeded = Object.keys(JOINS).filter((j) => j === "contracts" || groupDims.some((d) => _optionalChain([d, 'access', _19 => _19.joins, 'optionalAccess', _20 => _20[j]])));
814
+ const chunks = pages(nInvoices);
815
+ const linePages = chunks + Math.max(0, pages(nLines) - 1) + chunks;
816
+ const uninvoicedPages = v.nonChargeable ? Math.max(1, pages(nUninvoiced)) : 0;
817
+ const idChunks = pages(Math.min(nLines + nUninvoiced, nInvoices));
818
+ const joinChunks = joinsNeeded.reduce((s, j) => {
819
+ const spec = JOINS[j];
820
+ return s + ("chunks" in spec ? spec.chunks(idChunks, nLines + nUninvoiced) : idChunks);
821
+ }, 0);
822
+ const fixed = calls + (withVoided ? 1 : 0);
823
+ estimate = fixed + Math.max(1, chunks) + linePages + uninvoicedPages + joinChunks;
824
+ if (estimate > v.budget) throw refusal(v, estimate, fixed, scopeIds, joinsNeeded.length);
825
+ const invoiceRows = await collect(invoices, invoiceFilter(false), ["id", "invoiceTotal", "invoiceDateTime", "companyID"]);
826
+ const invoiceById = /* @__PURE__ */ new Map();
827
+ for (const r of invoiceRows) {
828
+ invoiceById.set(_chunkTBFXRNNEcjs.num.call(void 0, r["id"]), { total: cents(r["invoiceTotal"]), month: String(_nullishCoalesce(r["invoiceDateTime"], () => ( ""))).slice(0, 7), companyID: _chunkTBFXRNNEcjs.num.call(void 0, r["companyID"]) });
829
+ }
830
+ if (invoiceById.size !== nInvoices) throw countMismatch("invoice", invoiceById.size, nInvoices, invoiceRows.length);
831
+ const voided = withVoided ? byId(await collect(invoices, voidedFilter, ["id", "invoiceTotal"])) : void 0;
832
+ const lineFields = [.../* @__PURE__ */ new Set([...LINE_FIELDS, ...groupDims.flatMap((d) => _nullishCoalesce(d.lineFields, () => ( []))), ...v.nonChargeable ? NC_LINE_FIELDS : []])];
833
+ const ids = [...invoiceById.keys()].sort((a, b) => a - b);
834
+ const lines = (await client.batch(async (c) => {
835
+ const filter = [{ field: "invoiceID", op: "in", value: c }, ...scopeCond];
836
+ const n = await billingItems.count({ filter });
837
+ if (typeof n !== "number") throw blindCount();
838
+ const rows = byId(await collect(billingItems, filter, lineFields));
839
+ if (rows.length !== n) throw countMismatch("line", rows.length, n);
840
+ return rows;
841
+ }, chunk(ids), { concurrency: CONCURRENCY })).flat();
842
+ const orphan = lines.find((l) => !invoiceById.has(_chunkTBFXRNNEcjs.num.call(void 0, l["invoiceID"])));
843
+ if (orphan !== void 0) {
844
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskError)(`revenueRollup: billing line ${_chunkTBFXRNNEcjs.num.call(void 0, orphan["id"])} belongs to invoice ${_chunkTBFXRNNEcjs.num.call(void 0, orphan["invoiceID"])}, which is not among the ${invoiceById.size} streamed invoices; the fold was discarded`, {
845
+ code: "INVALID_RESPONSE",
846
+ category: "server",
847
+ operation: OP,
848
+ details: { reason: "orphan_line", lineID: _chunkTBFXRNNEcjs.num.call(void 0, orphan["id"]), invoiceID: _chunkTBFXRNNEcjs.num.call(void 0, orphan["invoiceID"]) },
849
+ suggestedAction: "Retry the call."
850
+ });
851
+ }
852
+ const uninvoiced = v.nonChargeable ? byId(await collect(billingItems, uninvoicedFilter, [...lineFields, "itemDate"])) : [];
853
+ if (v.nonChargeable && uninvoiced.length !== nUninvoiced) throw countMismatch("uninvoiced line", uninvoiced.length, nUninvoiced);
854
+ const all = uninvoiced.length > 0 ? [...lines, ...uninvoiced] : lines;
855
+ const joined = Object.fromEntries(Object.keys(JOINS).map((j) => [j, /* @__PURE__ */ new Map()]));
856
+ for (const j of joinsNeeded) {
857
+ const spec = JOINS[j];
858
+ const res = spec.make(http, client);
859
+ const fields = [.../* @__PURE__ */ new Set([...spec.fields, ...groupDims.flatMap((d) => _nullishCoalesce(_optionalChain([d, 'access', _21 => _21.joins, 'optionalAccess', _22 => _22[j]]), () => ( [])))])];
860
+ const want = [...new Set(spec.ids(all, joined))].filter((id) => id > 0).sort((a, b) => a - b);
861
+ const rows = await client.batch((c) => collect(res, [{ field: "id", op: "in", value: c }], fields), chunk(want), { concurrency: CONCURRENCY });
862
+ for (const r of rows.flat()) joined[j].set(_chunkTBFXRNNEcjs.num.call(void 0, r["id"]), r);
863
+ }
864
+ return fold(v, { invoiceById, voided, lines, uninvoiced, joined, labels, inTypes, inCategories, scopeIds, calls, estimate });
865
+ }
866
+ function refusal(v, estimate, fixed, scopeIds, joinCount) {
867
+ const months = _chunkTBFXRNNEcjs.monthsInWindow.call(void 0, v.dateFrom, v.dateTo);
868
+ const variable = estimate - fixed;
869
+ const fitMonths = Math.floor((v.budget - fixed) * months / variable);
870
+ const suggestions = [];
871
+ const text = [];
872
+ let unestimated = false;
873
+ const suggest = (s, t, estimated = false) => {
874
+ suggestions.push(s);
875
+ text.push(t);
876
+ if (!estimated) unestimated = true;
877
+ };
878
+ if (estimate <= BUDGET_CAP) suggest({ maxVendorCalls: estimate }, `maxVendorCalls: ${estimate} (cap ${BUDGET_CAP})`, true);
879
+ if (fitMonths >= 1 && fitMonths < months) {
880
+ const dateFrom = lastMonthsFrom(v.dateTo, fitMonths);
881
+ const est = fixed + Math.ceil(variable * fitMonths / months);
882
+ suggest({ dateFrom, estimate: est }, `dateFrom: '${dateFrom}' (est. ${est})`, true);
883
+ }
884
+ if (v.scopeKind === "tenantWide") suggest({ companyIDs: "[...]" }, "companyIDs: [...] (or ownerResourceID)");
885
+ if (estimate > BUDGET_CAP) {
886
+ if (v.nonChargeable) suggest({ includeNonChargeable: false }, "includeNonChargeable: false");
887
+ if (joinCount > 1) suggest({ groupBy: ["contractType"] }, "groupBy: ['contractType'] (fewer dimensions, fewer id-fetch calls)");
888
+ if (v.scopeKind === "companyIDs" || v.scopeKind === "ownerResourceID") suggest({ contractIDs: "[...]" }, "contractIDs: [...] (one call per group of contracts)");
889
+ const n = (_nullishCoalesce(scopeIds, () => ( []))).length;
890
+ if (v.scopeKind === "companyIDs" && n > 1) suggest({ companyIDs: "[...]" }, "a shorter companyIDs list (one call per part)");
891
+ if (v.scopeKind === "ownerResourceID" && n > 1) suggest({ companyIDs: "[...]" }, "companyIDs: a subset of the owner's companies (one call per part)");
892
+ if (v.scopeKind === "contractIDs" && n > 1) suggest({ contractIDs: "[...]" }, "a shorter contractIDs list (one call per part)");
893
+ }
894
+ if (suggestions.length === 0) suggest({ maxVendorCalls: BUDGET_CAP }, `maxVendorCalls: ${BUDGET_CAP} (the cap; the estimate ${estimate} is above it, so this call will be refused at this estimate even at the cap; no narrower shape exists for this scope and window)`, true);
895
+ const caveat = unestimated ? ". Narrowings without an estimate may still be refused: the invoice stream is tenant-wide in every scope, and the line stream costs at least one page and one count per chunk of 500 of those invoices, so a narrower scope or shape does not reduce that part" : "";
896
+ const scope = v.scopeKind === "tenantWide" ? "tenantWide" : `${v.scopeKind} ${(_nullishCoalesce(scopeIds, () => ( []))).length} id(s)`;
897
+ return budgetError(
898
+ `revenueRollup: estimated ${estimate} vendor calls exceeds maxVendorCalls ${v.budget} (window ${v.dateFrom}..${v.dateTo}, ${scope}). Narrow with one of: ${text.join("; ")}${caveat}`,
899
+ { phase: "estimate", estimate, budget: v.budget, suggestions },
900
+ `Narrow with one of: ${text.join("; ")}${caveat}`
901
+ );
902
+ }
903
+ var amt = () => ({ amount: 0, lines: 0 });
904
+ var nc = () => ({ contractCovered: { value: 0, hours: 0, lines: 0 }, nonBillable: { value: 0, hours: 0, lines: 0 } });
905
+ var add = (a, c) => {
906
+ a.amount += c;
907
+ a.lines += 1;
908
+ };
909
+ var outAmt = (a) => ({ amount: money(a.amount), lines: a.lines });
910
+ var outNc = (n) => {
911
+ const o = (k) => ({ value: money(n[k].value), hours: n[k].hours / 100, lines: n[k].lines });
912
+ return { contractCovered: o("contractCovered"), nonBillable: o("nonBillable") };
913
+ };
914
+ var outRecord = (r) => Object.fromEntries([...r].sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0).map(([k, a]) => [k, outAmt(a)]));
915
+ function ncClass(line) {
916
+ if (line["nonBillable"] === true || line["nonBillable"] === 1) return "nonBillable";
917
+ return extC(line) > 0 && revC(line) === 0 ? "contractCovered" : void 0;
918
+ }
919
+ function ncAdd(n, k, line) {
920
+ n[k].value += extC(line);
921
+ if (isLabour(line)) n[k].hours += cents(line["quantity"]);
922
+ n[k].lines += 1;
923
+ }
924
+ function compareIds(a, b) {
925
+ for (let i = 0; i < a.length; i++) {
926
+ const x = _nullishCoalesce(a[i], () => ( null));
927
+ const y = _nullishCoalesce(b[i], () => ( null));
928
+ if (x === y) continue;
929
+ if (x === null) return -1;
930
+ if (y === null) return 1;
931
+ if (typeof x === "number" && typeof y === "number") return x - y;
932
+ return String(x) < String(y) ? -1 : 1;
933
+ }
934
+ return 0;
935
+ }
936
+ function fold(v, f) {
937
+ const contractLabels = f.labels[CONTRACTS_PATH];
938
+ const bucketLabel = (field, fallback) => (t) => {
939
+ const values = contractLabels.get(field);
940
+ const l = _optionalChain([values, 'optionalAccess', _23 => _23.get, 'call', _24 => _24(t)]);
941
+ if (l === void 0) return `${fallback} ${t}`;
942
+ return [...values.values()].filter((x) => x === l).length > 1 ? `${l} (${t})` : l;
943
+ };
944
+ const typeLabel = bucketLabel("contractType", "type");
945
+ const catLabel = bucketLabel("contractCategory", "category");
946
+ const needCompany = v.groupBy.some((d) => _optionalChain([DIMENSIONS, 'access', _25 => _25[d], 'access', _26 => _26.joins, 'optionalAccess', _27 => _27.companies]));
947
+ const byLob = v.groupBy.includes("lineOfBusiness");
948
+ const unlabelled = /* @__PURE__ */ new Set();
949
+ const uncontracted = amt();
950
+ const unresolvedContracts = amt();
951
+ const unresolvedCompanies = amt();
952
+ const unresolvedJoins = new Map(v.groupBy.flatMap((d) => DIMENSIONS[d].unresolved ? [[DIMENSIONS[d].unresolved, amt()]] : []));
953
+ const unresolvedNc = amt();
954
+ const noPointer = amt();
955
+ const otherTypes = /* @__PURE__ */ new Map();
956
+ const otherCats = /* @__PURE__ */ new Map();
957
+ const cells = /* @__PURE__ */ new Map();
958
+ const allContracts = /* @__PURE__ */ new Set();
959
+ const lineTotals = /* @__PURE__ */ new Map();
960
+ const zeroTotal = amt();
961
+ const zeroIds = /* @__PURE__ */ new Set();
962
+ const locate = (line, invoice) => {
963
+ const contractID = _chunkTBFXRNNEcjs.num.call(void 0, line["contractID"]);
964
+ if (contractID === 0) return { bucket: uncontracted, unresolved: false };
965
+ const contract = f.joined.contracts.get(contractID);
966
+ if (contract === void 0) return { bucket: unresolvedContracts, unresolved: true };
967
+ const type = _chunkTBFXRNNEcjs.num.call(void 0, contract["contractType"]);
968
+ if (!f.inTypes.has(type)) return { bucket: slot(otherTypes, typeLabel(type)), unresolved: false };
969
+ const cat = _chunkTBFXRNNEcjs.num.call(void 0, contract["contractCategory"]);
970
+ if (f.inCategories !== void 0 && !f.inCategories.has(cat)) return { bucket: slot(otherCats, cat === 0 ? "uncategorised" : catLabel(cat)), unresolved: false };
971
+ const company = f.joined.companies.get(_chunkTBFXRNNEcjs.num.call(void 0, line["companyID"]));
972
+ if (needCompany && company === void 0) return { bucket: unresolvedCompanies, unresolved: true };
973
+ const ctx = { line, invoice, contract, company, joined: f.joined, labels: f.labels, unlabelled };
974
+ const keys = {};
975
+ const ids = [];
976
+ for (const d of v.groupBy) {
977
+ const k = DIMENSIONS[d].key(ctx);
978
+ if (typeof k === "string") return { bucket: unresolvedJoins.get(k), unresolved: true };
979
+ keys[d] = k;
980
+ ids.push(k.id);
981
+ }
982
+ const id = JSON.stringify(ids);
983
+ let cell = cells.get(id);
984
+ if (cell === void 0) {
985
+ cell = { keys, ids, revenue: 0, credits: 0, creditLines: 0, included: 0, contracts: /* @__PURE__ */ new Set(), items: 0, nc: nc() };
986
+ cells.set(id, cell);
987
+ }
988
+ return { cell };
989
+ };
990
+ for (const line of f.lines) {
991
+ const invoiceID = _chunkTBFXRNNEcjs.num.call(void 0, line["invoiceID"]);
992
+ const invoice = f.invoiceById.get(invoiceID);
993
+ lineTotals.set(invoiceID, (_nullishCoalesce(lineTotals.get(invoiceID), () => ( 0))) + cents(line["totalAmount"]));
994
+ const c = revC(line);
995
+ if (invoice.total === 0) {
996
+ add(zeroTotal, c);
997
+ zeroIds.add(invoiceID);
998
+ }
999
+ const at = locate(line, invoice);
1000
+ if (!("cell" in at)) {
1001
+ add(at.bucket, c);
1002
+ if (at.unresolved && v.nonChargeable && ncClass(line)) add(unresolvedNc, extC(line));
1003
+ continue;
1004
+ }
1005
+ const cell = at.cell;
1006
+ cell.revenue += c;
1007
+ if (c < 0) {
1008
+ cell.credits += c;
1009
+ cell.creditLines += 1;
1010
+ }
1011
+ cell.included += extC(line) - c;
1012
+ cell.contracts.add(_chunkTBFXRNNEcjs.num.call(void 0, line["contractID"]));
1013
+ cell.items += 1;
1014
+ allContracts.add(_chunkTBFXRNNEcjs.num.call(void 0, line["contractID"]));
1015
+ if (byLob && cell.keys.lineOfBusiness.id === null) add(noPointer, c);
1016
+ const k = v.nonChargeable ? ncClass(line) : void 0;
1017
+ if (k) ncAdd(cell.nc, k, line);
1018
+ }
1019
+ for (const line of f.uninvoiced) {
1020
+ const k = ncClass(line);
1021
+ if (!k) continue;
1022
+ const at = locate(line, { total: 0, month: String(_nullishCoalesce(line["itemDate"], () => ( ""))).slice(0, 7), companyID: _chunkTBFXRNNEcjs.num.call(void 0, line["companyID"]) });
1023
+ if ("cell" in at) ncAdd(at.cell.nc, k, line);
1024
+ else if (at.unresolved) add(unresolvedNc, extC(line));
1025
+ }
1026
+ const sorted = [...cells.values()].sort((a, b) => b.revenue - a.revenue || compareIds(a.ids, b.ids));
1027
+ const kept = sorted.slice(0, v.top);
1028
+ const cut = sorted.slice(v.top);
1029
+ const sum = (k) => sorted.reduce((s, x) => s + x[k], 0);
1030
+ const ncTotal = nc();
1031
+ for (const x of sorted) for (const k of ["contractCovered", "nonBillable"]) for (const m of ["value", "hours", "lines"]) ncTotal[k][m] += x.nc[k][m];
1032
+ const reconciled = v.scopeKind === "contractIDs" ? [] : [...f.invoiceById].filter(([, inv]) => v.scopeKind === "tenantWide" || f.scopeIds.includes(inv.companyID));
1033
+ let headerTotal = 0;
1034
+ let lineTotal = 0;
1035
+ let mismatched = 0;
1036
+ for (const [id, inv] of reconciled) {
1037
+ const lt = _nullishCoalesce(lineTotals.get(id), () => ( 0));
1038
+ headerTotal += inv.total;
1039
+ lineTotal += lt;
1040
+ if (lt !== inv.total) mismatched += 1;
1041
+ }
1042
+ const blindSurfaces2 = [...unlabelled].sort();
1043
+ const noInternal = [...f.lines, ...f.uninvoiced].filter(lacksInternal).length;
1044
+ if (noInternal > 0) blindSurfaces2.push(`billing_items: ${noInternal} line(s) without internalCurrencyTotalAmount / internalCurrencyExtendedPrice; their local-currency totalAmount / extendedPrice was used instead`);
1045
+ if (unresolvedCompanies.lines > 0) blindSurfaces2.push("companies.query: some line companies were not returned by the id-in fetch (the companies list surface can be blind to companies the API user does not own); their lines are in coverage.excluded.unresolvedCompanies");
1046
+ if (v.scopeKind === "ownerResourceID") blindSurfaces2.push("companies.query: ownerResourceID was resolved through the companies list surface, which can be blind to companies the API user does not own; a company it hides is missing from the scope and its revenue is not counted (scope.ids lists the companies that were resolved)");
1047
+ const notes = [
1048
+ "basis: invoice date (invoiceDateTime) as whole UTC days; voided invoices excluded; revenue = internalCurrencyTotalAmount (ex-tax, internal currency); includedValue is informational and never in revenue",
1049
+ "prepaid block-hour / retainer contracts: revenue is the billed purchase"
1050
+ ];
1051
+ notes.push("coverage.zeroTotalInvoices is informational: its lines are also folded into rows / the excluded buckets, so it is not part of coverage.excluded (revenue + the excluded line buckets reconcile to the whole)");
1052
+ if (v.scopeKind === "contractIDs") {
1053
+ notes.push("reconciliation is not run for a contractIDs scope (only the scoped contracts' lines are fetched)");
1054
+ notes.push("coverage.excluded.voidedInvoices is omitted for a contractIDs scope: an invoice header cannot be attributed to a contract (zeroTotalInvoices counts the zero-total invoices carrying a scoped line)");
1055
+ } else if (v.scopeKind !== "tenantWide") {
1056
+ notes.push("scope applies to the line's companyID; reconciliation, voidedInvoices and the zero-total count cover the invoices whose header company is in scope (zero-total also counts an invoice carrying an in-scope line; a mismatch can mean a line billed to another company)");
1057
+ }
1058
+ if (v.nonChargeable) {
1059
+ notes.push("nonChargeable is never added to revenue: contractCovered = billable lines with internalCurrencyExtendedPrice > 0 and internalCurrencyTotalAmount = 0, nonBillable = nonBillable lines; value = \u03A3 internalCurrencyExtendedPrice, hours = \u03A3 quantity on labour lines (Labor and Labor Adjustment). Invoiced lines are keyed on the invoice date; uninvoiced lines (invoiceID notExist) have no invoice date, so they are windowed and month-keyed on itemDate (whole UTC days). Uninvoiced lines outside the contract-type/category scope or uncontracted are not counted.");
1060
+ }
1061
+ for (const [id, inv] of f.invoiceById) {
1062
+ if (inv.total === 0 && (v.scopeKind === "tenantWide" || v.scopeKind !== "contractIDs" && f.scopeIds.includes(inv.companyID))) zeroIds.add(id);
1063
+ }
1064
+ const result = {
1065
+ window: { dateFrom: v.dateFrom, dateTo: v.dateTo, basis: "invoiceDate" },
1066
+ scope: {
1067
+ kind: v.scopeKind,
1068
+ ...v.ownerResourceID !== void 0 ? { ownerResourceID: v.ownerResourceID } : {},
1069
+ ...f.scopeIds !== void 0 ? { ids: f.scopeIds } : {}
1070
+ },
1071
+ groupBy: v.groupBy,
1072
+ top: v.top,
1073
+ rows: kept.map((x) => ({
1074
+ keys: x.keys,
1075
+ revenue: money(x.revenue),
1076
+ credits: { amount: money(x.credits), lines: x.creditLines },
1077
+ includedValue: money(x.included),
1078
+ contracts: x.contracts.size,
1079
+ items: x.items,
1080
+ ...v.nonChargeable ? { nonChargeable: outNc(x.nc) } : {}
1081
+ })),
1082
+ ...cut.length > 0 ? { rowsTruncated: { rows: cut.length, revenue: money(cut.reduce((s, x) => s + x.revenue, 0)) } } : {},
1083
+ totals: {
1084
+ revenue: money(sum("revenue")),
1085
+ credits: money(sum("credits")),
1086
+ includedValue: money(sum("included")),
1087
+ contracts: allContracts.size,
1088
+ items: sum("items"),
1089
+ ...v.nonChargeable ? { nonChargeable: outNc(ncTotal) } : {}
1090
+ },
1091
+ coverage: {
1092
+ vendorCalls: f.calls,
1093
+ budget: v.budget,
1094
+ estimate: f.estimate,
1095
+ tenantHourlyShare: `${(f.calls / TENANT_HOURLY_LIMIT * 100).toFixed(2)}% of ${TENANT_HOURLY_LIMIT.toLocaleString("en-US")}/h`,
1096
+ contractTypeMap: sortedRecord(f.inTypes),
1097
+ ...f.inCategories !== void 0 ? { contractCategoryMap: sortedRecord(f.inCategories) } : {},
1098
+ reconciliation: { headerTotal: money(headerTotal), lineTotal: money(lineTotal), delta: money(lineTotal - headerTotal), invoicesChecked: reconciled.length, invoicesMismatched: mismatched },
1099
+ zeroTotalInvoices: { count: zeroIds.size, ...outAmt(zeroTotal) },
1100
+ excluded: {
1101
+ ...f.voided !== void 0 ? { voidedInvoices: { count: f.voided.length, headerAmount: money(f.voided.reduce((s, r) => s + cents(r["invoiceTotal"]), 0)) } } : {},
1102
+ uncontracted: outAmt(uncontracted),
1103
+ otherContractTypes: outRecord(otherTypes),
1104
+ otherContractCategories: outRecord(otherCats),
1105
+ unresolvedContracts: outAmt(unresolvedContracts),
1106
+ unresolvedCompanies: outAmt(unresolvedCompanies),
1107
+ ...Object.fromEntries([...unresolvedJoins].map(([k, a]) => [k, outAmt(a)])),
1108
+ ...v.nonChargeable ? { unresolvedNonChargeable: outAmt(unresolvedNc) } : {}
1109
+ },
1110
+ ...byLob ? {
1111
+ lineOfBusiness: {
1112
+ noPointer: outAmt(noPointer),
1113
+ note: `LOB figures are floors: lines without a pointer are shown separately (the "no LOB assigned" row, id null). LOB is per billing line (no contract fallback), so a row's contracts = contracts with at least one line in that LOB, and per-LOB contract counts can sum to more than totals.contracts.`
1114
+ }
1115
+ } : {},
1116
+ blindSurfaces: blindSurfaces2,
1117
+ notes
1118
+ }
1119
+ };
1120
+ return result;
1121
+ }
1122
+ function slot(m, k) {
1123
+ const a = _nullishCoalesce(m.get(k), () => ( amt()));
1124
+ m.set(k, a);
1125
+ return a;
1126
+ }
1127
+
440
1128
  // src/operations/relationshipMap.ts
441
1129
  async function relationshipMap(client, resourceKey) {
442
1130
  void client;
443
1131
  if (typeof resourceKey !== "string" || resourceKey.trim() === "") {
444
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
1132
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
445
1133
  `relationshipMap: resourceKey must be a non-empty plan resource key string (e.g. 'tickets'; got ${typeof resourceKey === "string" ? "a blank string" : typeof resourceKey})`,
446
1134
  { suggestedAction: "Pass the exact plan resource key (snake_case) from autotask_catalog \u2014 e.g. tickets, companies, configuration_items, ticket_notes." }
447
1135
  );
448
1136
  }
449
1137
  const key = resourceKey.trim();
450
- const entry = _chunkGDQ4QM7Qcjs.RELATIONSHIP_MAP[key];
1138
+ const entry = _chunkTBFXRNNEcjs.RELATIONSHIP_MAP[key];
451
1139
  if (entry === void 0) {
452
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskError)(
453
- `relationshipMap: unknown resource "${key}" \u2014 the plan has ${Object.keys(_chunkGDQ4QM7Qcjs.RELATIONSHIP_MAP).length} resources`,
1140
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskError)(
1141
+ `relationshipMap: unknown resource "${key}" \u2014 the plan has ${Object.keys(_chunkTBFXRNNEcjs.RELATIONSHIP_MAP).length} resources`,
454
1142
  {
455
1143
  code: "RESOURCE_UNKNOWN",
456
1144
  category: "validation",
457
- suggestedAction: `Pass the exact plan resource key (snake_case) from autotask_catalog (e.g. tickets, companies, configuration_items). Zone facts served are ${_chunkGDQ4QM7Qcjs.RELATIONSHIP_ZONE.label} (${_chunkGDQ4QM7Qcjs.RELATIONSHIP_ZONE.zone})-verified.`
1145
+ suggestedAction: `Pass the exact plan resource key (snake_case) from autotask_catalog (e.g. tickets, companies, configuration_items). Zone facts served are ${_chunkTBFXRNNEcjs.RELATIONSHIP_ZONE.label} (${_chunkTBFXRNNEcjs.RELATIONSHIP_ZONE.zone})-verified.`
458
1146
  }
459
1147
  );
460
1148
  }
@@ -471,24 +1159,24 @@ var BLIND_SURFACE_KINDS = [
471
1159
  async function blindSurfaces(client, opts) {
472
1160
  void client;
473
1161
  if (opts !== void 0 && (typeof opts !== "object" || opts === null || Array.isArray(opts))) {
474
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)("blindSurfaces: opts must be an object { resource?: string, kind?: BlindSurfaceKind }");
1162
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)("blindSurfaces: opts must be an object { resource?: string, kind?: BlindSurfaceKind }");
475
1163
  }
476
- const inv = _chunkGDQ4QM7Qcjs.BLIND_SURFACE_INVENTORY;
1164
+ const inv = _chunkTBFXRNNEcjs.BLIND_SURFACE_INVENTORY;
477
1165
  if (inv === null) {
478
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)("blindSurfaces: the reachability inventory is absent from the generated artifact \u2014 re-run the build");
1166
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)("blindSurfaces: the reachability inventory is absent from the generated artifact \u2014 re-run the build");
479
1167
  }
480
1168
  let surfaces = inv.surfaces;
481
- if (_optionalChain([opts, 'optionalAccess', _ => _.resource]) !== void 0) {
1169
+ if (_optionalChain([opts, 'optionalAccess', _28 => _28.resource]) !== void 0) {
482
1170
  const key = typeof opts.resource === "string" ? opts.resource.trim() : "";
483
1171
  if (key === "") {
484
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
1172
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
485
1173
  "blindSurfaces: opts.resource must be a non-empty plan resource key string (e.g. 'tickets')",
486
1174
  { suggestedAction: "Pass the exact plan resource key (snake_case) from autotask_catalog \u2014 e.g. tickets, companies, configuration_items." }
487
1175
  );
488
1176
  }
489
1177
  if (!inv.surfaces.some((row) => row.resource === key)) {
490
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskError)(
491
- `blindSurfaces: unknown resource "${key}" \u2014 the plan has ${Object.keys(_chunkGDQ4QM7Qcjs.RELATIONSHIP_MAP).length} resources`,
1178
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskError)(
1179
+ `blindSurfaces: unknown resource "${key}" \u2014 the plan has ${Object.keys(_chunkTBFXRNNEcjs.RELATIONSHIP_MAP).length} resources`,
492
1180
  {
493
1181
  code: "RESOURCE_UNKNOWN",
494
1182
  category: "validation",
@@ -498,9 +1186,9 @@ async function blindSurfaces(client, opts) {
498
1186
  }
499
1187
  surfaces = surfaces.filter((row) => row.resource === key);
500
1188
  }
501
- if (_optionalChain([opts, 'optionalAccess', _2 => _2.kind]) !== void 0) {
1189
+ if (_optionalChain([opts, 'optionalAccess', _29 => _29.kind]) !== void 0) {
502
1190
  if (!BLIND_SURFACE_KINDS.includes(opts.kind)) {
503
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
1191
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
504
1192
  `blindSurfaces: unknown kind "${String(opts.kind)}" \u2014 the valid classes are: ${BLIND_SURFACE_KINDS.join(", ")}`,
505
1193
  { suggestedAction: `Filter with one of: ${BLIND_SURFACE_KINDS.join(", ")} (or omit kind for the full 116-surface inventory).` }
506
1194
  );
@@ -513,51 +1201,51 @@ async function blindSurfaces(client, opts) {
513
1201
  // src/operations/probeReachability.ts
514
1202
  async function probeReachability(client, opts) {
515
1203
  if (opts !== void 0 && (typeof opts !== "object" || opts === null || Array.isArray(opts))) {
516
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)("probeReachability: opts must be an object { resources?: string[], limit?: 1|2, maxWireCalls?: number, confirmProbe?: true }");
1204
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)("probeReachability: opts must be an object { resources?: string[], limit?: 1|2, maxWireCalls?: number, confirmProbe?: true }");
517
1205
  }
518
- const defs = _chunkGDQ4QM7Qcjs.REACHABILITY_PROBE_DEFAULTS;
519
- if (_optionalChain([opts, 'optionalAccess', _3 => _3.confirmProbe]) !== true) {
520
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
1206
+ const defs = _chunkTBFXRNNEcjs.REACHABILITY_PROBE_DEFAULTS;
1207
+ if (_optionalChain([opts, 'optionalAccess', _30 => _30.confirmProbe]) !== true) {
1208
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
521
1209
  "probeReachability: confirmProbe: true is required \u2014 the op deliberately fans out read wire across the tenant (one bounded query per surface); pass confirmProbe: true to run it",
522
1210
  { suggestedAction: `Re-call with { confirmProbe: true } (plus resources/limit/maxWireCalls as needed). For the ZERO-wire pinned inventory use operations.blindSurfaces.` }
523
1211
  );
524
1212
  }
525
- const limit = _nullishCoalesce(_optionalChain([opts, 'optionalAccess', _4 => _4.limit]), () => ( defs.limitDefault));
1213
+ const limit = _nullishCoalesce(_optionalChain([opts, 'optionalAccess', _31 => _31.limit]), () => ( defs.limitDefault));
526
1214
  if (!Number.isInteger(limit) || limit < 1 || limit > defs.limitMax) {
527
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
1215
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
528
1216
  `probeReachability: limit must be an integer 1..${defs.limitMax} (got ${String(limit)}) \u2014 the rows-per-surface bound for the discovery read`
529
1217
  );
530
1218
  }
531
- const cap = _nullishCoalesce(_optionalChain([opts, 'optionalAccess', _5 => _5.maxWireCalls]), () => ( defs.defaultCap));
1219
+ const cap = _nullishCoalesce(_optionalChain([opts, 'optionalAccess', _32 => _32.maxWireCalls]), () => ( defs.defaultCap));
532
1220
  if (!Number.isInteger(cap) || cap < 1) {
533
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(`probeReachability: maxWireCalls must be a positive integer (got ${String(cap)})`);
1221
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(`probeReachability: maxWireCalls must be a positive integer (got ${String(cap)})`);
534
1222
  }
535
1223
  if (cap > defs.hardCap) {
536
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
1224
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
537
1225
  `probeReachability: maxWireCalls ${cap} exceeds the hard wire cap of ${defs.hardCap} \u2014 the sweep is refused above it (never capped silently)`,
538
1226
  { suggestedAction: `Pass maxWireCalls \u2264 ${defs.hardCap} and a resources set no larger than the cap (the refused set is never truncated).` }
539
1227
  );
540
1228
  }
541
- const inv = _chunkGDQ4QM7Qcjs.BLIND_SURFACE_INVENTORY;
1229
+ const inv = _chunkTBFXRNNEcjs.BLIND_SURFACE_INVENTORY;
542
1230
  if (inv === null) {
543
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)("probeReachability: the reachability inventory is absent from the generated artifact \u2014 re-run the build");
1231
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)("probeReachability: the reachability inventory is absent from the generated artifact \u2014 re-run the build");
544
1232
  }
545
1233
  let targets;
546
- if (_optionalChain([opts, 'optionalAccess', _6 => _6.resources]) === void 0) {
1234
+ if (_optionalChain([opts, 'optionalAccess', _33 => _33.resources]) === void 0) {
547
1235
  targets = [...defs.defaultTargets];
548
1236
  } else {
549
1237
  if (!Array.isArray(opts.resources) || opts.resources.length === 0) {
550
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)("probeReachability: opts.resources must be a non-empty string[] of plan resource keys (or omit it for the default non-data-full set)");
1238
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)("probeReachability: opts.resources must be a non-empty string[] of plan resource keys (or omit it for the default non-data-full set)");
551
1239
  }
552
1240
  const seen = /* @__PURE__ */ new Set();
553
1241
  for (const r of opts.resources) {
554
1242
  if (typeof r !== "string" || r.trim() === "") {
555
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(`probeReachability: opts.resources must contain non-empty plan resource key strings (got ${typeof r === "string" && r.trim() === "" ? "a blank string" : typeof r})`);
1243
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(`probeReachability: opts.resources must contain non-empty plan resource key strings (got ${typeof r === "string" && r.trim() === "" ? "a blank string" : typeof r})`);
556
1244
  }
557
1245
  const key = r.trim();
558
1246
  if (!inv.surfaces.some((row) => row.resource === key)) {
559
1247
  const surfaceCount = new Set(inv.surfaces.map((s) => s.resource)).size;
560
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskError)(
1248
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskError)(
561
1249
  `probeReachability: unknown resource "${key}" \u2014 the inventory has ${surfaceCount} surfaces`,
562
1250
  {
563
1251
  code: "RESOURCE_UNKNOWN",
@@ -571,7 +1259,7 @@ async function probeReachability(client, opts) {
571
1259
  targets = [...seen];
572
1260
  }
573
1261
  if (targets.length > cap) {
574
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
1262
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
575
1263
  `probeReachability: ${targets.length} requested surface(s) exceed the wire cap of ${cap} \u2014 the sweep is refused above its cap (never truncated)`,
576
1264
  { suggestedAction: `Raise maxWireCalls (\u2264 ${defs.hardCap}) to cover the set, or pass a smaller resources list.` }
577
1265
  );
@@ -581,8 +1269,8 @@ async function probeReachability(client, opts) {
581
1269
  for (const resource of targets.sort()) {
582
1270
  const row = byResource.get(resource);
583
1271
  if (row === void 0) continue;
584
- const holder = client[_chunkGDQ4QM7Qcjs.camelKey.call(void 0, resource)];
585
- const probeFn = _optionalChain([holder, 'optionalAccess', _7 => _7.queryBounded]);
1272
+ const holder = client[_chunkTBFXRNNEcjs.camelKey.call(void 0, resource)];
1273
+ const probeFn = _optionalChain([holder, 'optionalAccess', _34 => _34.queryBounded]);
586
1274
  if (typeof probeFn !== "function") {
587
1275
  results.push({
588
1276
  ...row,
@@ -593,14 +1281,14 @@ async function probeReachability(client, opts) {
593
1281
  }
594
1282
  try {
595
1283
  const res = await probeFn.call(holder, { limit });
596
- const items = Array.isArray(_optionalChain([res, 'optionalAccess', _8 => _8.items])) ? res.items : [];
1284
+ const items = Array.isArray(_optionalChain([res, 'optionalAccess', _35 => _35.items])) ? res.items : [];
597
1285
  results.push({
598
1286
  ...row,
599
1287
  unfilteredRows: items.length,
600
1288
  probe: { ok: true, wire: 1, error: null }
601
1289
  });
602
1290
  } catch (err) {
603
- const code = _chunkGDQ4QM7Qcjs.isAutotaskError.call(void 0, err) ? err.code : "NETWORK_ERROR";
1291
+ const code = _chunkTBFXRNNEcjs.isAutotaskError.call(void 0, err) ? err.code : "NETWORK_ERROR";
604
1292
  const message = err instanceof Error ? err.message : String(err);
605
1293
  results.push({
606
1294
  ...row,
@@ -628,30 +1316,30 @@ var CREATE_BLOCKER_KINDS = [
628
1316
  async function createGuidance(client, opts) {
629
1317
  void client;
630
1318
  if (opts !== void 0 && (typeof opts !== "object" || opts === null || Array.isArray(opts))) {
631
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
1319
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
632
1320
  "createGuidance: opts must be an object { resources?: string[], kind?: CreateBlockerKind }"
633
1321
  );
634
1322
  }
635
- let servedRows = _chunkGDQ4QM7Qcjs.CREATE_GUIDANCE.rows.map((row) => ({
1323
+ let servedRows = _chunkTBFXRNNEcjs.CREATE_GUIDANCE.rows.map((row) => ({
636
1324
  ...row,
637
1325
  // Issue #219 N4: one precedence rule, stated on every row (live-proven >
638
1326
  // zone > spec). The spec set is not available here (it is a LIVE read) —
639
1327
  // the helper is handed the plan's two shapes and names the source.
640
- requiredFields: _chunkGDQ4QM7Qcjs.effectiveRequiredFields.call(void 0, void 0, _nullishCoalesce(_optionalChain([_chunkGDQ4QM7Qcjs.RELATIONSHIP_MAP, 'access', _9 => _9[row.resource], 'optionalAccess', _10 => _10.zoneFacts]), () => ( null)))
1328
+ requiredFields: _chunkTBFXRNNEcjs.effectiveRequiredFields.call(void 0, void 0, _nullishCoalesce(_optionalChain([_chunkTBFXRNNEcjs.RELATIONSHIP_MAP, 'access', _36 => _36[row.resource], 'optionalAccess', _37 => _37.zoneFacts]), () => ( null)))
641
1329
  }));
642
- if (_optionalChain([opts, 'optionalAccess', _11 => _11.resources]) !== void 0) {
1330
+ if (_optionalChain([opts, 'optionalAccess', _38 => _38.resources]) !== void 0) {
643
1331
  if (!Array.isArray(opts.resources) || opts.resources.length === 0) {
644
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)("createGuidance: opts.resources must be a non-empty string[] of plan resource keys");
1332
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)("createGuidance: opts.resources must be a non-empty string[] of plan resource keys");
645
1333
  }
646
1334
  const wanted = /* @__PURE__ */ new Set();
647
1335
  for (const r of opts.resources) {
648
1336
  if (typeof r !== "string" || r.trim() === "") {
649
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)("createGuidance: opts.resources must contain non-empty plan resource key strings");
1337
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)("createGuidance: opts.resources must contain non-empty plan resource key strings");
650
1338
  }
651
1339
  const key = r.trim();
652
- if (!_chunkGDQ4QM7Qcjs.CREATE_GUIDANCE.rows.some((row) => row.resource === key)) {
653
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskError)(
654
- `createGuidance: unknown resource "${key}" \u2014 the catalog has ${_chunkGDQ4QM7Qcjs.CREATE_GUIDANCE.rows.length} create entities`,
1340
+ if (!_chunkTBFXRNNEcjs.CREATE_GUIDANCE.rows.some((row) => row.resource === key)) {
1341
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskError)(
1342
+ `createGuidance: unknown resource "${key}" \u2014 the catalog has ${_chunkTBFXRNNEcjs.CREATE_GUIDANCE.rows.length} create entities`,
655
1343
  {
656
1344
  code: "RESOURCE_UNKNOWN",
657
1345
  category: "validation",
@@ -663,20 +1351,20 @@ async function createGuidance(client, opts) {
663
1351
  }
664
1352
  servedRows = servedRows.filter((row) => wanted.has(row.resource));
665
1353
  }
666
- if (_optionalChain([opts, 'optionalAccess', _12 => _12.kind]) !== void 0) {
1354
+ if (_optionalChain([opts, 'optionalAccess', _39 => _39.kind]) !== void 0) {
667
1355
  if (!CREATE_BLOCKER_KINDS.includes(opts.kind)) {
668
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
1356
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
669
1357
  `createGuidance: unknown kind "${String(opts.kind)}" \u2014 the valid kinds are: ${CREATE_BLOCKER_KINDS.join(", ")}`
670
1358
  );
671
1359
  }
672
- servedRows = servedRows.filter((row) => _optionalChain([row, 'access', _13 => _13.blocker, 'optionalAccess', _14 => _14.kind]) === opts.kind);
1360
+ servedRows = servedRows.filter((row) => _optionalChain([row, 'access', _40 => _40.blocker, 'optionalAccess', _41 => _41.kind]) === opts.kind);
673
1361
  }
674
1362
  return {
675
- zone: _chunkGDQ4QM7Qcjs.CREATE_GUIDANCE.zone,
676
- label: _chunkGDQ4QM7Qcjs.CREATE_GUIDANCE.label,
677
- verifiedAt: _chunkGDQ4QM7Qcjs.CREATE_GUIDANCE.verifiedAt,
1363
+ zone: _chunkTBFXRNNEcjs.CREATE_GUIDANCE.zone,
1364
+ label: _chunkTBFXRNNEcjs.CREATE_GUIDANCE.label,
1365
+ verifiedAt: _chunkTBFXRNNEcjs.CREATE_GUIDANCE.verifiedAt,
678
1366
  rows: servedRows,
679
- counts: _chunkGDQ4QM7Qcjs.CREATE_GUIDANCE.counts
1367
+ counts: _chunkTBFXRNNEcjs.CREATE_GUIDANCE.counts
680
1368
  };
681
1369
  }
682
1370
 
@@ -685,7 +1373,7 @@ var RECOVERY_CONFIRM = "operations.recovery";
685
1373
  var RECOVERY_DEFAULT_LIMIT = 25;
686
1374
  var RECOVERY_MAX_LIMIT = 100;
687
1375
  function configError(message, operation, suggestedAction) {
688
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(message, { operation, suggestedAction });
1376
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(message, { operation, suggestedAction });
689
1377
  }
690
1378
  function parseMatchId(record) {
691
1379
  const raw = record.id;
@@ -701,7 +1389,7 @@ function parseMatchId(record) {
701
1389
  return { id: null, unsafe: true };
702
1390
  }
703
1391
  function validateRecoveryInput(input, operation) {
704
- if (!_chunkGDQ4QM7Qcjs.isRecord.call(void 0, input)) {
1392
+ if (!_chunkTBFXRNNEcjs.isRecord.call(void 0, input)) {
705
1393
  configError(
706
1394
  `recovery: input must be an object { resource, marker, ... } (got ${typeof input})`,
707
1395
  operation,
@@ -735,10 +1423,10 @@ function validateRecoveryInput(input, operation) {
735
1423
  return { resource, marker, action };
736
1424
  }
737
1425
  function resolveRecoveryTarget(client, resource, operation) {
738
- const entry = _chunkGDQ4QM7Qcjs.RELATIONSHIP_MAP[resource];
1426
+ const entry = _chunkTBFXRNNEcjs.RELATIONSHIP_MAP[resource];
739
1427
  if (entry === void 0) {
740
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskError)(
741
- `recovery: unknown resource "${resource}" \u2014 the plan has ${Object.keys(_chunkGDQ4QM7Qcjs.RELATIONSHIP_MAP).length} resources`,
1428
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskError)(
1429
+ `recovery: unknown resource "${resource}" \u2014 the plan has ${Object.keys(_chunkTBFXRNNEcjs.RELATIONSHIP_MAP).length} resources`,
742
1430
  {
743
1431
  code: "RESOURCE_UNKNOWN",
744
1432
  category: "validation",
@@ -747,7 +1435,7 @@ function resolveRecoveryTarget(client, resource, operation) {
747
1435
  }
748
1436
  );
749
1437
  }
750
- const holder = client[_chunkGDQ4QM7Qcjs.camelKey.call(void 0, resource)];
1438
+ const holder = client[_chunkTBFXRNNEcjs.camelKey.call(void 0, resource)];
751
1439
  if (!holder || typeof holder.queryBounded !== "function") {
752
1440
  configError(
753
1441
  `recovery: ${resource} exposes no bounded query surface \u2014 the marker search cannot run`,
@@ -758,7 +1446,7 @@ function resolveRecoveryTarget(client, resource, operation) {
758
1446
  return { entry, holder };
759
1447
  }
760
1448
  function resolveMarkerField(input, resource, operation) {
761
- const field = input.field !== void 0 ? String(input.field) : _chunkGDQ4QM7Qcjs.MARKER_FIELDS[resource];
1449
+ const field = input.field !== void 0 ? String(input.field) : _chunkTBFXRNNEcjs.MARKER_FIELDS[resource];
762
1450
  if (typeof field !== "string" || field.trim() === "") {
763
1451
  configError(
764
1452
  `recovery: ${resource} has no plan markerField and no input.field was passed \u2014 the marker search needs a name-like field to filter on`,
@@ -797,7 +1485,7 @@ function resolveExtraFilter(input, operation) {
797
1485
  );
798
1486
  }
799
1487
  for (const c of input.filter) {
800
- if (!_chunkGDQ4QM7Qcjs.isRecord.call(void 0, c) || typeof c.op !== "string" || c.op === "and" || c.op === "or") {
1488
+ if (!_chunkTBFXRNNEcjs.isRecord.call(void 0, c) || typeof c.op !== "string" || c.op === "and" || c.op === "or") {
801
1489
  configError(
802
1490
  "recovery: input.filter accepts only plain leaf conditions ({ field, op, value }) \u2014 no grouping",
803
1491
  operation,
@@ -822,7 +1510,7 @@ function resolveLimit(input, operation) {
822
1510
  async function applyRecoveryDeletes(holder, matches, parentId, resource, operation) {
823
1511
  const deleteMethod = holder.delete;
824
1512
  if (deleteMethod === void 0) {
825
- throw new (0, _chunkGDQ4QM7Qcjs.DeleteBoundaryError)(
1513
+ throw new (0, _chunkTBFXRNNEcjs.DeleteBoundaryError)(
826
1514
  `recovery: ${resource} has no delete method on the client \u2014 the boundary is marked available in the plan but the typed delete surface is missing`,
827
1515
  {
828
1516
  operation,
@@ -851,14 +1539,14 @@ async function applyRecoveryDeletes(holder, matches, parentId, resource, operati
851
1539
  verify = "still-present";
852
1540
  }
853
1541
  } catch (err) {
854
- if (err instanceof _chunkGDQ4QM7Qcjs.NotFoundError) verify = "not-found";
1542
+ if (err instanceof _chunkTBFXRNNEcjs.NotFoundError) verify = "not-found";
855
1543
  else {
856
1544
  verify = "error";
857
- code = _chunkGDQ4QM7Qcjs.isAutotaskError.call(void 0, err) ? err.code : "SERVER_ERROR";
1545
+ code = _chunkTBFXRNNEcjs.isAutotaskError.call(void 0, err) ? err.code : "SERVER_ERROR";
858
1546
  }
859
1547
  }
860
1548
  } catch (err) {
861
- code = _chunkGDQ4QM7Qcjs.isAutotaskError.call(void 0, err) ? err.code : "SERVER_ERROR";
1549
+ code = _chunkTBFXRNNEcjs.isAutotaskError.call(void 0, err) ? err.code : "SERVER_ERROR";
862
1550
  }
863
1551
  deleted.push({ id, verified: verify === "not-found", code });
864
1552
  }
@@ -886,7 +1574,7 @@ async function recovery(client, input, opts = {}) {
886
1574
  const parentId = resolveParentId(input, entry, resource, operation);
887
1575
  const extra = resolveExtraFilter(input, operation);
888
1576
  const limit = resolveLimit(input, operation);
889
- const boundaryNote = _chunkGDQ4QM7Qcjs.DELETE_BOUNDARY_NOTES[resource];
1577
+ const boundaryNote = _chunkTBFXRNNEcjs.DELETE_BOUNDARY_NOTES[resource];
890
1578
  const boundary = {
891
1579
  available: boundaryNote === void 0,
892
1580
  reason: _nullishCoalesce(boundaryNote, () => ( null)),
@@ -898,7 +1586,7 @@ async function recovery(client, input, opts = {}) {
898
1586
  };
899
1587
  const isDelete = action === "delete";
900
1588
  if (isDelete && boundaryNote !== void 0) {
901
- throw new (0, _chunkGDQ4QM7Qcjs.DeleteBoundaryError)(
1589
+ throw new (0, _chunkTBFXRNNEcjs.DeleteBoundaryError)(
902
1590
  `recovery: the vendor defines no DELETE for ${resource} \u2014 the delete cannot be issued through the API (zero wire was issued)`,
903
1591
  {
904
1592
  operation,
@@ -907,10 +1595,10 @@ async function recovery(client, input, opts = {}) {
907
1595
  }
908
1596
  );
909
1597
  }
910
- const dryRun = _optionalChain([opts, 'optionalAccess', _15 => _15.dryRun]) !== false;
911
- const confirm = _nullishCoalesce(_optionalChain([opts, 'optionalAccess', _16 => _16.confirm]), () => ( input.confirm));
1598
+ const dryRun = _optionalChain([opts, 'optionalAccess', _42 => _42.dryRun]) !== false;
1599
+ const confirm = _nullishCoalesce(_optionalChain([opts, 'optionalAccess', _43 => _43.confirm]), () => ( input.confirm));
912
1600
  if (isDelete && !dryRun && confirm !== RECOVERY_CONFIRM) {
913
- throw new (0, _chunkGDQ4QM7Qcjs.ConfirmationRequiredError)(
1601
+ throw new (0, _chunkTBFXRNNEcjs.ConfirmationRequiredError)(
914
1602
  `recovery: action 'delete' apply is destructive and requires its confirmation flag: pass confirm: "${RECOVERY_CONFIRM}"`,
915
1603
  {
916
1604
  operation: RECOVERY_CONFIRM,
@@ -926,7 +1614,7 @@ async function recovery(client, input, opts = {}) {
926
1614
  const query = await holder.queryBounded({ filter: conditions, limit });
927
1615
  if (query.hasMore) {
928
1616
  const wire = isDelete ? "DELETE wire" : "mutating wire";
929
- throw new (0, _chunkGDQ4QM7Qcjs.RecoveryTruncatedError)(
1617
+ throw new (0, _chunkTBFXRNNEcjs.RecoveryTruncatedError)(
930
1618
  `recovery: the marker search on ${resource} TRIPPED its match cap (${limit}) \u2014 more matches exist than were returned (zero ${wire} was issued)`,
931
1619
  {
932
1620
  operation,
@@ -955,7 +1643,7 @@ async function recovery(client, input, opts = {}) {
955
1643
  return { ...base, simulated: true, dryRun: true };
956
1644
  }
957
1645
  if (unsafeId) {
958
- throw new (0, _chunkGDQ4QM7Qcjs.MarkerUnsafeIdError)(
1646
+ throw new (0, _chunkTBFXRNNEcjs.MarkerUnsafeIdError)(
959
1647
  `recovery: ${unsafeIds.length} of ${matches.length} match(es) on ${resource} have ids beyond Number.MAX_SAFE_INTEGER \u2014 they CANNOT be addressed through the SDK's typed delete surface (zero DELETE wire was issued)`,
960
1648
  {
961
1649
  operation,
@@ -973,7 +1661,7 @@ function needsConfirmation(record) {
973
1661
  return record.effect === "destructive" || (_nullishCoalesce(record.flags, () => ( []))).includes("requiresApproval");
974
1662
  }
975
1663
  function refuse(message, operation, suggestedAction) {
976
- throw new (0, _chunkGDQ4QM7Qcjs.ConfirmationRequiredError)(message, { operation, suggestedAction });
1664
+ throw new (0, _chunkTBFXRNNEcjs.ConfirmationRequiredError)(message, { operation, suggestedAction });
977
1665
  }
978
1666
  var MODE_BY_EFFECT = {
979
1667
  read: "read",
@@ -1019,7 +1707,7 @@ function looseTypeOk(type, value) {
1019
1707
  case "string[]":
1020
1708
  return Array.isArray(value) && value.every((v) => typeof v === "string");
1021
1709
  case "object":
1022
- return _chunkGDQ4QM7Qcjs.isRecord.call(void 0, value);
1710
+ return _chunkTBFXRNNEcjs.isRecord.call(void 0, value);
1023
1711
  default:
1024
1712
  return true;
1025
1713
  }
@@ -1033,12 +1721,12 @@ function declaredArgList(record) {
1033
1721
  function resolveDispatchArgs(record, argsIn) {
1034
1722
  const operation = record.id;
1035
1723
  const bad = (message) => {
1036
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(`invoke: "${operation}" ${message}`, { operation });
1724
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(`invoke: "${operation}" ${message}`, { operation });
1037
1725
  };
1038
1726
  if (argsIn === void 0 || argsIn === null) return [];
1039
1727
  if (Array.isArray(argsIn)) return argsIn;
1040
1728
  const byName = argsIn;
1041
- if (!_chunkGDQ4QM7Qcjs.isRecord.call(void 0, byName) || ![Object.prototype, null].includes(Object.getPrototypeOf(byName))) {
1729
+ if (!_chunkTBFXRNNEcjs.isRecord.call(void 0, byName) || ![Object.prototype, null].includes(Object.getPrototypeOf(byName))) {
1042
1730
  return bad(`args must be a positional array or a plain object of named inputs (declared: ${declaredArgList(record)})`);
1043
1731
  }
1044
1732
  const schema = _nullishCoalesce(record.inputSchema, () => ( {}));
@@ -1059,7 +1747,7 @@ function validateDispatchArgs(record, argsIn) {
1059
1747
  const bagName = names.find((n) => schema[n].properties);
1060
1748
  const surplus = args[names.length];
1061
1749
  const bagHint = bagName && surplus !== null && typeof surplus === "object" && !Array.isArray(surplus) ? ` \u2014 options go inside the single ${bagName} object` : "";
1062
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
1750
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
1063
1751
  `invoke: "${operation}" declares ${names.length} positional arg(s) (${declaredArgList(record)}) but ${args.length} were passed \u2014 extra args are refused${bagHint}`,
1064
1752
  {
1065
1753
  operation,
@@ -1069,7 +1757,7 @@ function validateDispatchArgs(record, argsIn) {
1069
1757
  }
1070
1758
  const required = names.filter((n) => schema[n].required);
1071
1759
  if (args.length < required.length) {
1072
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
1760
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
1073
1761
  `invoke: "${operation}" requires ${required.length} positional arg(s) (${required.map((n) => `${n}: ${schema[n].type}`).join(", ")}) but only ${args.length} were passed \u2014 declared args: ${declaredArgList(record)}`,
1074
1762
  { operation }
1075
1763
  );
@@ -1080,7 +1768,7 @@ function validateDispatchArgs(record, argsIn) {
1080
1768
  const name = names[i];
1081
1769
  const spec = schema[name];
1082
1770
  if (!looseTypeOk(spec.type, value)) {
1083
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
1771
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
1084
1772
  `invoke: "${operation}" arg ${i + 1} is declared ${name}: ${spec.type} \u2014 the value has the wrong type (pass a ${spec.type} value)`,
1085
1773
  { operation }
1086
1774
  );
@@ -1088,17 +1776,17 @@ function validateDispatchArgs(record, argsIn) {
1088
1776
  }
1089
1777
  }
1090
1778
  function foldFlattenedOpts(record, toolArgs) {
1091
- if (!_chunkGDQ4QM7Qcjs.isRecord.call(void 0, toolArgs)) {
1092
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(`invoke: "${record.id}" tool args must be a plain object of named inputs`, { operation: record.id });
1779
+ if (!_chunkTBFXRNNEcjs.isRecord.call(void 0, toolArgs)) {
1780
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(`invoke: "${record.id}" tool args must be a plain object of named inputs`, { operation: record.id });
1093
1781
  }
1094
- const bagKeys = (_nullishCoalesce(_optionalChain([record, 'access', _17 => _17.inputSchema, 'optionalAccess', _18 => _18.opts, 'optionalAccess', _19 => _19.properties]), () => ( []))).map((p) => p.name);
1782
+ const bagKeys = (_nullishCoalesce(_optionalChain([record, 'access', _44 => _44.inputSchema, 'optionalAccess', _45 => _45.opts, 'optionalAccess', _46 => _46.properties]), () => ( []))).map((p) => p.name);
1095
1783
  const flat = Object.keys(toolArgs).filter((k) => bagKeys.includes(k) && toolArgs[k] !== void 0 && toolArgs[k] !== null);
1096
1784
  const folded = { ...toolArgs };
1097
1785
  for (const k of bagKeys) delete folded[k];
1098
1786
  if (folded.opts === null) delete folded.opts;
1099
1787
  if (flat.length === 0) return folded;
1100
1788
  if (folded.opts !== void 0) {
1101
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
1789
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
1102
1790
  `invoke: "${record.id}" was given both opts and flattened option(s) ${flat.map((k) => `"${k}"`).join(", ")} \u2014 pass one form`,
1103
1791
  { operation: record.id }
1104
1792
  );
@@ -1159,12 +1847,12 @@ function validateParamsBag(record, args) {
1159
1847
  if (record.inputSchemaStrict !== true) return;
1160
1848
  const valid = PARAMS_BAG_KEYS[record.operation];
1161
1849
  if (valid === void 0) return;
1162
- const bag = _optionalChain([args, 'optionalAccess', _20 => _20[0]]);
1163
- if (bag === void 0 || bag === null || !_chunkGDQ4QM7Qcjs.isRecord.call(void 0, bag)) return;
1850
+ const bag = _optionalChain([args, 'optionalAccess', _47 => _47[0]]);
1851
+ if (bag === void 0 || bag === null || !_chunkTBFXRNNEcjs.isRecord.call(void 0, bag)) return;
1164
1852
  const unknown = Object.keys(bag).filter((k) => !valid.includes(k));
1165
1853
  if (unknown.length === 0) return;
1166
1854
  const suggestions = unknown.map((k) => [k, suggestForKey(k, valid)]).filter((pair) => pair[1] !== null).map(([k, s]) => `"${k}" \u2192 "${s}"`);
1167
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
1855
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
1168
1856
  `invoke: "${record.id}" params bag has unknown key(s) ${unknown.map((k) => `"${k}"`).join(", ")} \u2014 the bag is closed (valid keys: ${valid.join(", ")})`,
1169
1857
  {
1170
1858
  operation: record.id,
@@ -1175,17 +1863,17 @@ function validateParamsBag(record, args) {
1175
1863
  function validateGetBag(record, args) {
1176
1864
  if (record.kind !== "primitive" || record.operation !== "get") return;
1177
1865
  const at = Object.keys(_nullishCoalesce(record.inputSchema, () => ( {}))).indexOf("opts");
1178
- const bag = at < 0 ? void 0 : _optionalChain([args, 'optionalAccess', _21 => _21[at]]);
1179
- if (bag === void 0 || bag === null || !_chunkGDQ4QM7Qcjs.isRecord.call(void 0, bag)) return;
1866
+ const bag = at < 0 ? void 0 : _optionalChain([args, 'optionalAccess', _48 => _48[at]]);
1867
+ if (bag === void 0 || bag === null || !_chunkTBFXRNNEcjs.isRecord.call(void 0, bag)) return;
1180
1868
  const unknown = Object.keys(bag).filter((k) => k !== "fresh");
1181
1869
  if (unknown.length > 0) {
1182
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
1870
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
1183
1871
  `invoke: "${record.id}" opts bag has unknown key(s) ${unknown.map((k) => `"${k}"`).join(", ")} \u2014 the bag is closed (valid keys: fresh)`,
1184
1872
  { operation: record.id, suggestedAction: "Pass only { fresh?: boolean }." }
1185
1873
  );
1186
1874
  }
1187
1875
  if (bag.fresh !== void 0 && typeof bag.fresh !== "boolean") {
1188
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
1876
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
1189
1877
  `invoke: fresh must be a boolean (got ${typeof bag.fresh}) \u2014 "${record.id}" was not issued`,
1190
1878
  { operation: record.id, suggestedAction: "Pass fresh: true (bypass the read cache) or omit it." }
1191
1879
  );
@@ -1197,7 +1885,7 @@ function validateInvokeOptions(opts, operation) {
1197
1885
  const unknown = Object.keys(opts).filter((k) => !INVOKE_OPTION_KEYS.includes(k));
1198
1886
  if (unknown.length === 0) return;
1199
1887
  const suggestions = unknown.map((k) => [k, suggestForKey(k, ["dryRun", "confirm", "lastModifiedDate", "maxRetries", "fresh"])]).filter((pair) => pair[1] !== null).map(([k, s]) => `"${k}" \u2192 "${s}"`);
1200
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
1888
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
1201
1889
  `invoke: "${operation}" has unknown option key(s) ${unknown.map((k) => `"${k}"`).join(", ")} \u2014 the options set is closed (valid: dryRun, confirm, lastModifiedDate, maxRetries, fresh; "mode" is internal to the mode wrappers)`,
1202
1890
  {
1203
1891
  operation,
@@ -1210,7 +1898,7 @@ function unknownKeysRefusal(raw, validKeys, subject, operation) {
1210
1898
  const unknown = Object.keys(raw).filter((k) => !validKeys.includes(k));
1211
1899
  if (unknown.length === 0) return null;
1212
1900
  const suggestions = unknown.map((k) => [k, suggestForKey(k, [...validKeys])]).filter((pair) => pair[1] !== null).map(([k, s]) => `"${k}" \u2192 "${s}"`);
1213
- return new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
1901
+ return new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
1214
1902
  `unknown ${subject} ${unknown.map((k) => `"${k}"`).join(", ")} \u2014 the ${subject} set is closed (valid keys: ${validKeys.join(", ")})`,
1215
1903
  {
1216
1904
  ...operation !== void 0 ? { operation } : {},
@@ -1220,8 +1908,8 @@ function unknownKeysRefusal(raw, validKeys, subject, operation) {
1220
1908
  }
1221
1909
 
1222
1910
  // src/operations/invoke/registry.ts
1223
- var RECORDS = _chunkFOOHJBPPcjs.CAPABILITIES;
1224
- var byId = new Map(RECORDS.map((r) => [r.id, r]));
1911
+ var RECORDS = _chunkHBYKTXN3cjs.CAPABILITIES;
1912
+ var byId2 = new Map(RECORDS.map((r) => [r.id, r]));
1225
1913
 
1226
1914
  // src/operations/invoke/dispatch.ts
1227
1915
  var INVOKE_MAX_INLINE_BYTES = 1024 * 1024;
@@ -1237,9 +1925,9 @@ function bufferResult(buf) {
1237
1925
  };
1238
1926
  }
1239
1927
  function resolveRecord(operation) {
1240
- const record = byId.get(operation);
1928
+ const record = byId2.get(operation);
1241
1929
  if (record === void 0) {
1242
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
1930
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
1243
1931
  `invoke: unknown operation "${operation}" \u2014 it is not in the capability registry`,
1244
1932
  { operation, suggestedAction: "List the registry (the ./capabilities subpath) for the exact operation key." }
1245
1933
  );
@@ -1250,30 +1938,30 @@ function governPreRequest(record, operation, opts) {
1250
1938
  validateInvokeOptions(opts, operation);
1251
1939
  const mode = opts.mode;
1252
1940
  if (mode !== void 0 && MODE_BY_EFFECT[record.effect] !== mode) {
1253
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(crossModeRefusal(operation, record.effect, mode), { operation });
1941
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(crossModeRefusal(operation, record.effect, mode), { operation });
1254
1942
  }
1255
1943
  if (opts.dryRun !== void 0 && typeof opts.dryRun !== "boolean") {
1256
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
1944
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
1257
1945
  `invoke: dryRun must be a boolean (got ${typeof opts.dryRun}) \u2014 "${operation}" was not issued`,
1258
1946
  { operation, suggestedAction: "Pass dryRun: true (simulate) or dryRun: false (apply) as a real boolean." }
1259
1947
  );
1260
1948
  }
1261
1949
  if (opts.fresh !== void 0) {
1262
1950
  if (typeof opts.fresh !== "boolean") {
1263
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
1951
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
1264
1952
  `invoke: fresh must be a boolean (got ${typeof opts.fresh}) \u2014 "${operation}" was not issued`,
1265
1953
  { operation, suggestedAction: "Pass fresh: true (bypass the read cache) or omit it." }
1266
1954
  );
1267
1955
  }
1268
1956
  if (record.effect !== "read" || record.kind !== "primitive" || record.operation !== "get" || !("opts" in (_nullishCoalesce(record.inputSchema, () => ( {}))))) {
1269
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
1957
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
1270
1958
  `invoke: fresh applies only to a single-record "<resource>.get" read \u2014 "${operation}" was not issued`,
1271
1959
  { operation, suggestedAction: "Drop the fresh option (only <resource>.get consults the read cache per call)." }
1272
1960
  );
1273
1961
  }
1274
1962
  }
1275
1963
  if (record.effect === "read" && opts.dryRun === true) {
1276
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
1964
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
1277
1965
  `invoke: "${operation}" is a read \u2014 dryRun is not applicable (reads issue their request as-is)`,
1278
1966
  { operation }
1279
1967
  );
@@ -1290,22 +1978,24 @@ function operationsHolder(client) {
1290
1978
  return {
1291
1979
  resolveAny: (identifier, opts) => resolveAny(client, identifier, opts),
1292
1980
  searchAcrossResources: (query, opts) => searchAcrossResources(client, query, opts),
1293
- fetchMany: (items, opts) => _chunkGDQ4QM7Qcjs.fetchMany.call(void 0, client, items, opts),
1981
+ fetchMany: (items, opts) => _chunkTBFXRNNEcjs.fetchMany.call(void 0, client, items, opts),
1294
1982
  // Issue #62: the generic aggregate + the cheap count — the
1295
1983
  // groupBy/sum-absent mode is ONE vendor /query/count (the S12-C blind
1296
1984
  // sentinel rides through); the group/sum modes walk the named
1297
1985
  // <resource>.query op via the house bounded walk and fold client-side
1298
1986
  // (truncation honesty: hasMore/totalScanned — no silent partial sums).
1299
1987
  aggregate: (operation, filter, opts) => aggregate(client, operation, filter, opts),
1988
+ // Issue #234: revenue by dimension in one budgeted call (refuses over budget, never partial).
1989
+ revenueRollup: (opts) => revenueRollup(client, opts),
1300
1990
  // Issue #59 PR-B: the bulk fetch by ids — query-first chunked `id in`
1301
1991
  // reads + the per-id `get` fallback (blind-surface-safe; per-item
1302
1992
  // typed outcomes reuse the fetchMany shapes).
1303
- fetchByIds: (items, opts) => _chunkGDQ4QM7Qcjs.fetchByIds.call(void 0, client, items, opts),
1993
+ fetchByIds: (items, opts) => _chunkTBFXRNNEcjs.fetchByIds.call(void 0, client, items, opts),
1304
1994
  // Issue #65: opt-in resource name expansion — per-id resources.get
1305
1995
  // reads ONLY (never an id-in query — the resources table can be blind
1306
1996
  // to count/query while per-id reads work); blind-marked rows for ids
1307
1997
  // the API user cannot resolve; the name cache (default-on).
1308
- expandResourceNames: (ids, opts) => _chunkGDQ4QM7Qcjs.expandResourceNames.call(void 0, client, ids, opts),
1998
+ expandResourceNames: (ids, opts) => _chunkTBFXRNNEcjs.expandResourceNames.call(void 0, client, ids, opts),
1309
1999
  relationshipMap: (resourceKey) => relationshipMap(client, resourceKey),
1310
2000
  // Issue #11: the served blind-surface inventory (zero wire) + the
1311
2001
  // bounded caller-opted reachability sweep (read-only, confirmProbe-
@@ -1315,12 +2005,12 @@ function operationsHolder(client) {
1315
2005
  // Issue #12: the served zone-fact create-guidance catalog (zero wire).
1316
2006
  createGuidance: (opts) => createGuidance(client, opts),
1317
2007
  // Issue #202: ExecuteCommand deep links — pure, zero wire.
1318
- uiLink: (input) => _chunkGDQ4QM7Qcjs.uiLink.call(void 0, client, input),
2008
+ uiLink: (input) => _chunkTBFXRNNEcjs.uiLink.call(void 0, client, input),
1319
2009
  // Issue #31: the opt-in live field-metadata channel — N bounded
1320
2010
  // entityInformation GETs (the op's own cap refuses over-cap fan-outs
1321
2011
  // pre-request; per-resource failures are recorded on the row and
1322
2012
  // never abort the call).
1323
- fieldCatalog: (opts) => _chunkGDQ4QM7Qcjs.fieldCatalog.call(void 0, client, opts),
2013
+ fieldCatalog: (opts) => _chunkTBFXRNNEcjs.fieldCatalog.call(void 0, client, opts),
1324
2014
  // Issue #9: the one-call recovery/cleanup op — effect write in the
1325
2015
  // registry (the governor's dry-run-first applies to it); the op's own
1326
2016
  // confirm gate makes the destructive action deliberate (the governor
@@ -1330,15 +2020,15 @@ function operationsHolder(client) {
1330
2020
  }
1331
2021
  function resolveHolder(client, record, operation) {
1332
2022
  const clientBag = client;
1333
- let holder = clientBag[_chunkGDQ4QM7Qcjs.camelKey.call(void 0, record.resource)];
2023
+ let holder = clientBag[_chunkTBFXRNNEcjs.camelKey.call(void 0, record.resource)];
1334
2024
  if (typeof holder === "function") {
1335
- holder = _nullishCoalesce(clientBag[`${_chunkGDQ4QM7Qcjs.camelKey.call(void 0, record.resource)}Resource`], () => ( holder));
2025
+ holder = _nullishCoalesce(clientBag[`${_chunkTBFXRNNEcjs.camelKey.call(void 0, record.resource)}Resource`], () => ( holder));
1336
2026
  }
1337
2027
  if (holder === void 0 && record.resource === "operations") {
1338
2028
  holder = operationsHolder(client);
1339
2029
  }
1340
2030
  if (holder === void 0) {
1341
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
2031
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
1342
2032
  `invoke: the client exposes no accessor for resource "${record.resource}"`,
1343
2033
  { operation }
1344
2034
  );
@@ -1398,11 +2088,11 @@ async function invokeMode(client, operation, argsIn = [], opts = {}) {
1398
2088
  const boundedQuery = record.kind === "primitive" && record.operation === "query";
1399
2089
  const countedQuery = record.kind === "primitive" && record.operation === "count";
1400
2090
  const holder = resolveHolder(client, record, operation);
1401
- if (boundedQuery || countedQuery) await _chunkGDQ4QM7Qcjs.validateQueryFieldNames.call(void 0, record, holder, args);
2091
+ if (boundedQuery || countedQuery) await _chunkTBFXRNNEcjs.validateQueryFieldNames.call(void 0, record, holder, args);
1402
2092
  const methodName = boundedQuery ? "queryBounded" : record.operation;
1403
2093
  const method = holder[methodName];
1404
2094
  if (typeof method !== "function") {
1405
- throw new (0, _chunkGDQ4QM7Qcjs.AutotaskConfigError)(
2095
+ throw new (0, _chunkTBFXRNNEcjs.AutotaskConfigError)(
1406
2096
  `invoke: "${record.resource}.${methodName}" is not a callable method on the client`,
1407
2097
  { operation }
1408
2098
  );
@@ -1480,4 +2170,5 @@ async function invokeDelete(client, operation, args = [], opts = {}) {
1480
2170
 
1481
2171
 
1482
2172
 
1483
- exports.AGGREGATE_DATE_BUCKETS = AGGREGATE_DATE_BUCKETS; exports.AGGREGATE_DEFAULT_LIMIT = AGGREGATE_DEFAULT_LIMIT; exports.AGGREGATE_DEFAULT_TOP = AGGREGATE_DEFAULT_TOP; exports.AGGREGATE_TOP_MAX = AGGREGATE_TOP_MAX; exports.BLIND_SURFACE_KINDS = BLIND_SURFACE_KINDS; exports.CREATE_BLOCKER_KINDS = CREATE_BLOCKER_KINDS; exports.ENTITY_TYPE_TO_RESOURCE = _chunkGDQ4QM7Qcjs.ENTITY_TYPE_TO_RESOURCE; exports.EXPAND_RESOURCE_NAMES_MAX_IDS = _chunkGDQ4QM7Qcjs.EXPAND_RESOURCE_NAMES_MAX_IDS; exports.FETCH_BY_IDS_CHUNK_SIZE = _chunkGDQ4QM7Qcjs.FETCH_BY_IDS_CHUNK_SIZE; exports.FETCH_BY_IDS_MAX_ITEMS = _chunkGDQ4QM7Qcjs.FETCH_BY_IDS_MAX_ITEMS; exports.FETCH_MANY_MAX_ITEMS = _chunkGDQ4QM7Qcjs.FETCH_MANY_MAX_ITEMS; exports.FIELD_CACHE_KINDS = _chunkGDQ4QM7Qcjs.FIELD_CACHE_KINDS; exports.FIELD_CATALOG_HONESTY_NOTE = _chunkGDQ4QM7Qcjs.FIELD_CATALOG_HONESTY_NOTE; exports.INVOKE_OPTION_KEYS = INVOKE_OPTION_KEYS; exports.MAX_FIELD_CATALOG_WIRE = _chunkGDQ4QM7Qcjs.MAX_FIELD_CATALOG_WIRE; exports.PARAMS_BAG_KEYS = PARAMS_BAG_KEYS; exports.PICKLIST_VALUE_NOT_SERVED_NOTE = _chunkGDQ4QM7Qcjs.PICKLIST_VALUE_NOT_SERVED_NOTE; exports.RECOVERY_CONFIRM = RECOVERY_CONFIRM; exports.RECOVERY_DEFAULT_LIMIT = RECOVERY_DEFAULT_LIMIT; exports.RECOVERY_MAX_LIMIT = RECOVERY_MAX_LIMIT; exports.UI_LINK_ENTITIES = _chunkGDQ4QM7Qcjs.UI_LINK_ENTITIES; exports.WORKFLOW_RESOURCES = _chunkGDQ4QM7Qcjs.WORKFLOW_RESOURCES; exports.aggregate = aggregate; exports.blindSurfaces = blindSurfaces; exports.buildUiLink = _chunkGDQ4QM7Qcjs.buildUiLink; exports.createGuidance = createGuidance; exports.dateBucketLabel = dateBucketLabel; exports.effectiveRequiredFields = _chunkGDQ4QM7Qcjs.effectiveRequiredFields; exports.expandResourceNames = _chunkGDQ4QM7Qcjs.expandResourceNames; exports.fetchByIds = _chunkGDQ4QM7Qcjs.fetchByIds; exports.fetchMany = _chunkGDQ4QM7Qcjs.fetchMany; exports.fieldCatalog = _chunkGDQ4QM7Qcjs.fieldCatalog; exports.foldFlattenedOpts = foldFlattenedOpts; exports.invoke = invoke; exports.invokeDelete = invokeDelete; exports.invokeRead = invokeRead; exports.invokeWrite = invokeWrite; exports.isEnumerableResource = _chunkGDQ4QM7Qcjs.isEnumerableResource; exports.needsConfirmation = needsConfirmation; exports.probeReachability = probeReachability; exports.recovery = recovery; exports.relationshipMap = relationshipMap; exports.resolveAny = resolveAny; exports.resourceForEntityType = _chunkGDQ4QM7Qcjs.resourceForEntityType; exports.searchAcrossResources = searchAcrossResources; exports.uiLink = _chunkGDQ4QM7Qcjs.uiLink; exports.unknownKeysRefusal = unknownKeysRefusal; exports.validateDispatchArgs = validateDispatchArgs; exports.validateFetchManyItems = _chunkGDQ4QM7Qcjs.validateFetchManyItems; exports.validateInvokeOptions = validateInvokeOptions; exports.validateParamsBag = validateParamsBag;
2173
+
2174
+ exports.AGGREGATE_DATE_BUCKETS = AGGREGATE_DATE_BUCKETS; exports.AGGREGATE_DEFAULT_LIMIT = AGGREGATE_DEFAULT_LIMIT; exports.AGGREGATE_DEFAULT_TOP = AGGREGATE_DEFAULT_TOP; exports.AGGREGATE_TOP_MAX = AGGREGATE_TOP_MAX; exports.BLIND_SURFACE_KINDS = BLIND_SURFACE_KINDS; exports.CREATE_BLOCKER_KINDS = CREATE_BLOCKER_KINDS; exports.ENTITY_TYPE_TO_RESOURCE = _chunkTBFXRNNEcjs.ENTITY_TYPE_TO_RESOURCE; exports.EXPAND_RESOURCE_NAMES_MAX_IDS = _chunkTBFXRNNEcjs.EXPAND_RESOURCE_NAMES_MAX_IDS; exports.FETCH_BY_IDS_CHUNK_SIZE = _chunkTBFXRNNEcjs.FETCH_BY_IDS_CHUNK_SIZE; exports.FETCH_BY_IDS_MAX_ITEMS = _chunkTBFXRNNEcjs.FETCH_BY_IDS_MAX_ITEMS; exports.FETCH_MANY_MAX_ITEMS = _chunkTBFXRNNEcjs.FETCH_MANY_MAX_ITEMS; exports.FIELD_CACHE_KINDS = _chunkTBFXRNNEcjs.FIELD_CACHE_KINDS; exports.FIELD_CATALOG_HONESTY_NOTE = _chunkTBFXRNNEcjs.FIELD_CATALOG_HONESTY_NOTE; exports.INVOKE_OPTION_KEYS = INVOKE_OPTION_KEYS; exports.MAX_FIELD_CATALOG_WIRE = _chunkTBFXRNNEcjs.MAX_FIELD_CATALOG_WIRE; exports.PARAMS_BAG_KEYS = PARAMS_BAG_KEYS; exports.PICKLIST_VALUE_NOT_SERVED_NOTE = _chunkTBFXRNNEcjs.PICKLIST_VALUE_NOT_SERVED_NOTE; exports.RECOVERY_CONFIRM = RECOVERY_CONFIRM; exports.RECOVERY_DEFAULT_LIMIT = RECOVERY_DEFAULT_LIMIT; exports.RECOVERY_MAX_LIMIT = RECOVERY_MAX_LIMIT; exports.UI_LINK_ENTITIES = _chunkTBFXRNNEcjs.UI_LINK_ENTITIES; exports.WORKFLOW_RESOURCES = _chunkTBFXRNNEcjs.WORKFLOW_RESOURCES; exports.aggregate = aggregate; exports.blindSurfaces = blindSurfaces; exports.buildUiLink = _chunkTBFXRNNEcjs.buildUiLink; exports.createGuidance = createGuidance; exports.dateBucketLabel = dateBucketLabel; exports.effectiveRequiredFields = _chunkTBFXRNNEcjs.effectiveRequiredFields; exports.expandResourceNames = _chunkTBFXRNNEcjs.expandResourceNames; exports.fetchByIds = _chunkTBFXRNNEcjs.fetchByIds; exports.fetchMany = _chunkTBFXRNNEcjs.fetchMany; exports.fieldCatalog = _chunkTBFXRNNEcjs.fieldCatalog; exports.foldFlattenedOpts = foldFlattenedOpts; exports.invoke = invoke; exports.invokeDelete = invokeDelete; exports.invokeRead = invokeRead; exports.invokeWrite = invokeWrite; exports.isEnumerableResource = _chunkTBFXRNNEcjs.isEnumerableResource; exports.needsConfirmation = needsConfirmation; exports.probeReachability = probeReachability; exports.recovery = recovery; exports.relationshipMap = relationshipMap; exports.resolveAny = resolveAny; exports.resourceForEntityType = _chunkTBFXRNNEcjs.resourceForEntityType; exports.revenueRollup = revenueRollup; exports.searchAcrossResources = searchAcrossResources; exports.uiLink = _chunkTBFXRNNEcjs.uiLink; exports.unknownKeysRefusal = unknownKeysRefusal; exports.validateDispatchArgs = validateDispatchArgs; exports.validateFetchManyItems = _chunkTBFXRNNEcjs.validateFetchManyItems; exports.validateInvokeOptions = validateInvokeOptions; exports.validateParamsBag = validateParamsBag;