node-autotask 0.40.0 → 0.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/MCP_TOOL_CATALOG.json +9 -31
  3. package/MCP_TOOL_MANIFEST.md +11 -12
  4. package/N8N_MCP_MANIFEST.json +5 -44
  5. package/N8N_MCP_MANIFEST.md +7 -8
  6. package/README.md +1 -1
  7. package/capabilities.json +1319 -1503
  8. package/dist/capabilities.cjs +2 -2
  9. package/dist/capabilities.js +1 -1
  10. package/dist/{chunk-FEYVLIHD.cjs → chunk-DKAD7MOV.cjs} +40 -142
  11. package/dist/{chunk-EUGSF3U4.cjs → chunk-DXEBPK55.cjs} +285 -285
  12. package/dist/{chunk-VDVBXXJW.js → chunk-LR6FDJI3.js} +36 -138
  13. package/dist/{chunk-EVDVESQM.cjs → chunk-MJ6J74F3.cjs} +1318 -1502
  14. package/dist/{chunk-MTFRSD7P.js → chunk-P5655PGY.js} +2 -2
  15. package/dist/{chunk-O32L6GS5.js → chunk-TCND5PFF.js} +2 -2
  16. package/dist/{chunk-E5W24BZB.cjs → chunk-YAHFPOQF.cjs} +143 -143
  17. package/dist/{chunk-Y6YJYKBZ.js → chunk-ZVSSAULC.js} +1318 -1502
  18. package/dist/{index-BKp8_P2L.d.ts → index-CqO1HNHl.d.cts} +1 -46
  19. package/dist/{index-BKp8_P2L.d.cts → index-CqO1HNHl.d.ts} +1 -46
  20. package/dist/index.cjs +23 -23
  21. package/dist/index.d.cts +2 -2
  22. package/dist/index.d.ts +2 -2
  23. package/dist/index.js +5 -5
  24. package/dist/operations/index.cjs +177 -177
  25. package/dist/operations/index.d.cts +2 -2
  26. package/dist/operations/index.d.ts +2 -2
  27. package/dist/operations/index.js +2 -2
  28. package/dist/pool.cjs +8 -8
  29. package/dist/pool.d.cts +1 -1
  30. package/dist/pool.d.ts +1 -1
  31. package/dist/pool.js +4 -4
  32. package/dist/resources/index.cjs +4 -4
  33. package/dist/resources/index.d.cts +1 -1
  34. package/dist/resources/index.d.ts +1 -1
  35. package/dist/resources/index.js +3 -3
  36. package/dist/types/index.d.cts +1 -1
  37. package/dist/types/index.d.ts +1 -1
  38. package/docs/API.md +9 -22
  39. package/docs/N8N-ADAPTER.md +1 -1
  40. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  CAPABILITIES
3
- } from "./chunk-Y6YJYKBZ.js";
3
+ } from "./chunk-ZVSSAULC.js";
4
4
  import {
5
5
  wrapUntrusted
6
6
  } from "./chunk-5VHSLJMR.js";
@@ -22729,7 +22729,7 @@ function appendWiresNote(wires, note) {
22729
22729
  wires.note = (wires.note ? wires.note + " | " : "") + note;
22730
22730
  }
22731
22731
  function makeFetchCtx(rawHttp, v, contractId, budget) {
22732
- const OP9 = PROFITABILITY_OP;
22732
+ const OP8 = PROFITABILITY_OP;
22733
22733
  const id = parseIdentifier(contractId, "contractId");
22734
22734
  const idNum = typeof id === "number" ? id : Number(id);
22735
22735
  const wires = { issued: 0, requests: 0, budget };
@@ -22741,19 +22741,19 @@ function makeFetchCtx(rawHttp, v, contractId, budget) {
22741
22741
  } };
22742
22742
  const readPart = (path, conditions, fields) => {
22743
22743
  wires.issued += 1;
22744
- return degradable(() => boundedPart(http, path, conditions, v.limit, OP9, fields));
22744
+ return degradable(() => boundedPart(http, path, conditions, v.limit, OP8, fields));
22745
22745
  };
22746
22746
  const truncatedMonths = {};
22747
22747
  const windowedPart = async (name, key, path, cond, fields, dateField) => {
22748
22748
  const first = await readPart(path, cond, fields);
22749
22749
  if (first.absent !== void 0 || !first.hasMore) return { part: stampPart(key, first, cond), rows: first.items };
22750
- const wp = await degradable(() => expandByMonth(http, path, cond, v.limit, OP9, fields, dateField, v.dateFrom, v.dateTo, wires));
22750
+ const wp = await degradable(() => expandByMonth(http, path, cond, v.limit, OP8, fields, dateField, v.dateFrom, v.dateTo, wires));
22751
22751
  if (!("truncatedMonths" in wp)) return { part: stampPart(key, wp, cond), rows: [] };
22752
22752
  const { truncatedMonths: tm, ...part } = wp;
22753
22753
  truncatedMonths[name] = tm;
22754
22754
  return { part, rows: wp.items };
22755
22755
  };
22756
- return { v, OP: OP9, id, idNum, rawHttp, http, wires, windowOn, readPart, windowedPart, truncatedMonths };
22756
+ return { v, OP: OP8, id, idNum, rawHttp, http, wires, windowOn, readPart, windowedPart, truncatedMonths };
22757
22757
  }
22758
22758
 
22759
22759
  // src/resources/special/contracts/profitability.stages.ts
@@ -24385,50 +24385,50 @@ async function queryTimeEntries(_resource, filter, limit, operation, http, curso
24385
24385
  const { items, pageDetails } = unwrapItems(res);
24386
24386
  return { items, hasMore: pageDetails.nextPageUrl != null, nextCursor: pageDetails.nextPageUrl ?? null };
24387
24387
  }
24388
- function pagingOpts(opts, OP9) {
24388
+ function pagingOpts(opts, OP8) {
24389
24389
  if (opts?.countOnly !== void 0 && typeof opts.countOnly !== "boolean") {
24390
- throw new AutotaskConfigError(`${OP9}: countOnly must be a boolean`, { operation: OP9 });
24390
+ throw new AutotaskConfigError(`${OP8}: countOnly must be a boolean`, { operation: OP8 });
24391
24391
  }
24392
24392
  const countOnly = opts?.countOnly === true;
24393
24393
  const cursor = opts?.cursor;
24394
24394
  if (cursor !== void 0 && (typeof cursor !== "string" || cursor.trim() === "")) {
24395
- throw new AutotaskConfigError(`${OP9}: cursor must be the non-empty nextCursor of a previous call`, { operation: OP9 });
24395
+ throw new AutotaskConfigError(`${OP8}: cursor must be the non-empty nextCursor of a previous call`, { operation: OP8 });
24396
24396
  }
24397
24397
  if (cursor !== void 0 && cursor.length > CURSOR_MAX) {
24398
- throw new ResponseRejectedError(`${OP9}: refused the pagination cursor: ${cursor.length} chars is over the ${CURSOR_MAX}-char cap (a vendor nextPageUrl is far shorter)`);
24398
+ throw new ResponseRejectedError(`${OP8}: refused the pagination cursor: ${cursor.length} chars is over the ${CURSOR_MAX}-char cap (a vendor nextPageUrl is far shorter)`);
24399
24399
  }
24400
24400
  if (cursor !== void 0 && countOnly) {
24401
- throw new AutotaskConfigError(`${OP9}: cursor does not apply with countOnly (countOnly reads every page itself)`, { operation: OP9 });
24401
+ throw new AutotaskConfigError(`${OP8}: cursor does not apply with countOnly (countOnly reads every page itself)`, { operation: OP8 });
24402
24402
  }
24403
24403
  const budget = opts?.maxVendorCalls ?? COUNT_BUDGET_DEFAULT;
24404
24404
  if (!Number.isInteger(budget) || budget < 1 || budget > COUNT_BUDGET_MAX) {
24405
- throw new AutotaskConfigError(`${OP9}: maxVendorCalls must be an integer 1-${COUNT_BUDGET_MAX} (got ${String(opts?.maxVendorCalls)})`, { operation: OP9 });
24405
+ throw new AutotaskConfigError(`${OP8}: maxVendorCalls must be an integer 1-${COUNT_BUDGET_MAX} (got ${String(opts?.maxVendorCalls)})`, { operation: OP8 });
24406
24406
  }
24407
24407
  return { ...cursor === void 0 ? {} : { cursor }, countOnly, budget };
24408
24408
  }
24409
- function budgetExceeded(OP9, details, midWalk) {
24409
+ function budgetExceeded(OP8, details, midWalk) {
24410
24410
  const { estimate, budget, total } = details;
24411
24411
  const raise = midWalk ? budget < COUNT_BUDGET_MAX ? `, or pass a maxVendorCalls above ${budget} for headroom past the estimate` : "" : estimate <= COUNT_BUDGET_MAX ? ` or pass maxVendorCalls >= ${estimate}` : "";
24412
24412
  return new AutotaskError(
24413
- midWalk ? `${OP9}: countOnly stopped at the ${budget}-call budget mid-walk: the walk needed more calls than the ${estimate} estimated from the ${total}-entry count (more entries than counted, or an extra page such as an empty continuation page), so the next call, which may be the closing re-count, did not fit; no partial total is returned` : `${OP9}: countOnly needs an estimated ${estimate} vendor calls for ${total} entries (1 count + 1 per ${PAGE} entries + 1 join per 250 + 1 re-count), over the ${budget}-call budget; nothing was read past the count`,
24414
- { code: "BUDGET_EXCEEDED", category: "policy", operation: OP9, details, suggestedAction: `Narrow the dateWorked window (dateFrom/dateTo)${raise}.` }
24413
+ midWalk ? `${OP8}: countOnly stopped at the ${budget}-call budget mid-walk: the walk needed more calls than the ${estimate} estimated from the ${total}-entry count (more entries than counted, or an extra page such as an empty continuation page), so the next call, which may be the closing re-count, did not fit; no partial total is returned` : `${OP8}: countOnly needs an estimated ${estimate} vendor calls for ${total} entries (1 count + 1 per ${PAGE} entries + 1 join per 250 + 1 re-count), over the ${budget}-call budget; nothing was read past the count`,
24414
+ { code: "BUDGET_EXCEEDED", category: "policy", operation: OP8, details, suggestedAction: `Narrow the dateWorked window (dateFrom/dateTo)${raise}.` }
24415
24415
  );
24416
24416
  }
24417
- async function countPostedState(http, filter, OP9, budget, window) {
24417
+ async function countPostedState(http, filter, OP8, budget, window) {
24418
24418
  let issued = 0;
24419
24419
  let estimate = 0;
24420
24420
  let counted = 0;
24421
24421
  const spend = () => {
24422
- if (issued >= budget) throw budgetExceeded(OP9, { estimate, budget, total: counted, issued }, true);
24422
+ if (issued >= budget) throw budgetExceeded(OP8, { estimate, budget, total: counted, issued }, true);
24423
24423
  issued += 1;
24424
24424
  };
24425
24425
  spend();
24426
24426
  counted = unwrapQueryCount(
24427
- await http.request({ method: "POST", idempotent: true, path: "/V1.0/TimeEntries/query/count", body: { filter }, operation: OP9 }),
24428
- OP9
24427
+ await http.request({ method: "POST", idempotent: true, path: "/V1.0/TimeEntries/query/count", body: { filter }, operation: OP8 }),
24428
+ OP8
24429
24429
  );
24430
24430
  estimate = 1 + Math.max(1, Math.ceil(counted / PAGE)) + Math.ceil(counted / 250) + 1;
24431
- if (estimate > budget) throw budgetExceeded(OP9, { estimate, budget, total: counted, issued }, false);
24431
+ if (estimate > budget) throw budgetExceeded(OP8, { estimate, budget, total: counted, issued }, false);
24432
24432
  const states = /* @__PURE__ */ new Map();
24433
24433
  let cursor = null;
24434
24434
  do {
@@ -24438,15 +24438,15 @@ async function countPostedState(http, filter, OP9, budget, window) {
24438
24438
  idempotent: true,
24439
24439
  path: cursor === null ? "/V1.0/TimeEntries/query" : entryCursorPath(http.baseUrl, cursor),
24440
24440
  body: { MaxRecords: PAGE, IncludeFields: ["id"], filter },
24441
- operation: OP9
24441
+ operation: OP8
24442
24442
  });
24443
24443
  const page = unwrapItems(res);
24444
- const joined = await postedStateOf(http, page.items, OP9, spend);
24444
+ const joined = await postedStateOf(http, page.items, OP8, spend);
24445
24445
  if (joined.incomplete) {
24446
- throw new AutotaskError(`${OP9}: countOnly refused: a billing-item join page was truncated (more than 500 billing items for 250 entries), so the posted split cannot be confirmed`, {
24446
+ throw new AutotaskError(`${OP8}: countOnly refused: a billing-item join page was truncated (more than 500 billing items for 250 entries), so the posted split cannot be confirmed`, {
24447
24447
  code: "RESOLUTION_TRUNCATED",
24448
24448
  category: "resolution",
24449
- operation: OP9,
24449
+ operation: OP8,
24450
24450
  details: { issued, budget },
24451
24451
  suggestedAction: "Narrow the dateWorked window, or page it with cursor (rows mode reports unconfirmed entries via hasMore)."
24452
24452
  });
@@ -24456,14 +24456,14 @@ async function countPostedState(http, filter, OP9, budget, window) {
24456
24456
  } while (cursor !== null);
24457
24457
  spend();
24458
24458
  const recounted = unwrapQueryCount(
24459
- await http.request({ method: "POST", idempotent: true, path: "/V1.0/TimeEntries/query/count", body: { filter }, operation: OP9 }),
24460
- OP9
24459
+ await http.request({ method: "POST", idempotent: true, path: "/V1.0/TimeEntries/query/count", body: { filter }, operation: OP8 }),
24460
+ OP8
24461
24461
  );
24462
24462
  if (states.size !== counted && states.size !== recounted) {
24463
- throw new AutotaskError(`${OP9}: countOnly read ${states.size} distinct entries but the window counted ${counted} before the walk and ${recounted} after it (a page repeated or dropped entries, or the window changed mid-walk); no total is returned. Retry the call`, {
24463
+ throw new AutotaskError(`${OP8}: countOnly read ${states.size} distinct entries but the window counted ${counted} before the walk and ${recounted} after it (a page repeated or dropped entries, or the window changed mid-walk); no total is returned. Retry the call`, {
24464
24464
  code: "INVALID_RESPONSE",
24465
24465
  category: "server",
24466
- operation: OP9,
24466
+ operation: OP8,
24467
24467
  details: { reason: "count_mismatch", streamed: states.size, counted, recounted, issued, budget },
24468
24468
  suggestedAction: "Retry the call; a window that changes during the walk can fail or pass depending on timing."
24469
24469
  });
@@ -24520,13 +24520,13 @@ async function postedStateQuery(_resource, mode, http, opts) {
24520
24520
  return { items, hasMore: read.hasMore || incomplete, window, nextCursor: read.nextCursor, unconfirmed, approvedCount, unapprovedCount: items.length - approvedCount };
24521
24521
  }
24522
24522
  async function postedWithin(_resource, from, to, http, opts, opLabel = "time_entries.postedWithin") {
24523
- const OP9 = opLabel;
24524
- const paging = pagingOpts(opts, OP9);
24525
- if (opts?.tz !== void 0) validateZone(opts.tz, OP9);
24526
- const fromB = customRangeDay(from, "from", void 0, OP9);
24527
- const toB = customRangeDay(to, "to", void 0, OP9);
24523
+ const OP8 = opLabel;
24524
+ const paging = pagingOpts(opts, OP8);
24525
+ if (opts?.tz !== void 0) validateZone(opts.tz, OP8);
24526
+ const fromB = customRangeDay(from, "from", void 0, OP8);
24527
+ const toB = customRangeDay(to, "to", void 0, OP8);
24528
24528
  if (fromB.ms > toB.ms) {
24529
- throw new AutotaskConfigError(`${OP9}: from (${iso2(fromB.ms)}) must not be after to (${iso2(toB.ms)})`, { operation: OP9 });
24529
+ throw new AutotaskConfigError(`${OP8}: from (${iso2(fromB.ms)}) must not be after to (${iso2(toB.ms)})`, { operation: OP8 });
24530
24530
  }
24531
24531
  const windowToMs = toB.ms + DAY_MS2 - 1;
24532
24532
  const filter = [
@@ -24536,9 +24536,9 @@ async function postedWithin(_resource, from, to, http, opts, opLabel = "time_ent
24536
24536
  if (opts?.ticketID !== void 0) filter.push({ field: "ticketID", op: "eq", value: opts.ticketID });
24537
24537
  if (opts?.resourceID !== void 0) filter.push({ field: "resourceID", op: "eq", value: opts.resourceID });
24538
24538
  const window = { from: iso2(fromB.ms), to: iso2(windowToMs) };
24539
- if (paging.countOnly) return countPostedState(http, filter, OP9, paging.budget, window);
24540
- const { items, hasMore, nextCursor } = await queryTimeEntries(_resource, filter, clampWindowLimit(opts?.limit), OP9, http, paging.cursor);
24541
- const { states, incomplete } = await postedStateOf(http, items, OP9);
24539
+ if (paging.countOnly) return countPostedState(http, filter, OP8, paging.budget, window);
24540
+ const { items, hasMore, nextCursor } = await queryTimeEntries(_resource, filter, clampWindowLimit(opts?.limit), OP8, http, paging.cursor);
24541
+ const { states, incomplete } = await postedStateOf(http, items, OP8);
24542
24542
  let postedCount = 0;
24543
24543
  let unpostedCount = 0;
24544
24544
  for (const state of states.values()) {
@@ -25308,103 +25308,6 @@ async function approve(resource, id, opts = {}, http) {
25308
25308
  };
25309
25309
  }
25310
25310
 
25311
- // src/resources/special/time_entries/recentTickets.ts
25312
- var OP8 = "time_entries.recentTickets";
25313
- var DAY_MS3 = 864e5;
25314
- var TICKET_CHUNK = 100;
25315
- var TICKET_FIELDS2 = ["id", "ticketNumber", "title", "status", "assignedResourceID", "companyID"];
25316
- function positiveId2(value, name) {
25317
- const n = typeof value === "string" && /^\d+$/.test(value.trim()) ? Number(value) : value;
25318
- if (typeof n !== "number" || !Number.isSafeInteger(n) || n < 1) {
25319
- throw new AutotaskConfigError(`${OP8}: ${name} must be a positive integer id (got ${String(value)})`, { operation: OP8 });
25320
- }
25321
- return n;
25322
- }
25323
- async function recentTickets(_resource, from, to, http, opts) {
25324
- if (opts === void 0 || opts === null || typeof opts !== "object") {
25325
- throw new AutotaskConfigError(`${OP8}: opts { resourceID, companyID?, tz?, limit? } is required`, { operation: OP8 });
25326
- }
25327
- const resourceID = positiveId2(opts.resourceID, "resourceID");
25328
- const companyID = opts.companyID === void 0 ? void 0 : positiveId2(opts.companyID, "companyID");
25329
- if (opts.tz !== void 0) validateZone(opts.tz, OP8);
25330
- const fromB = customRangeDay(from, "from", void 0, OP8);
25331
- const toB = customRangeDay(to, "to", void 0, OP8);
25332
- if (fromB.ms > toB.ms) {
25333
- throw new AutotaskConfigError(`${OP8}: from (${isoUtc(fromB.ms)}) must not be after to (${isoUtc(toB.ms)})`, { operation: OP8 });
25334
- }
25335
- const windowToMs = toB.ms + DAY_MS3 - 1;
25336
- const { items: entries, hasMore } = await queryTimeEntries(
25337
- _resource,
25338
- [
25339
- { field: "dateWorked", op: "gte", value: isoUtc(fromB.ms) },
25340
- { field: "dateWorked", op: "lte", value: isoUtc(windowToMs) },
25341
- { field: "resourceID", op: "eq", value: resourceID }
25342
- ],
25343
- clampWindowLimit(opts.limit),
25344
- OP8,
25345
- http
25346
- );
25347
- const groups = /* @__PURE__ */ new Map();
25348
- let entriesWithoutTicket = 0;
25349
- for (const e of entries) {
25350
- if (typeof e.ticketID !== "number") {
25351
- entriesWithoutTicket += 1;
25352
- continue;
25353
- }
25354
- const g = groups.get(e.ticketID) ?? { entryCount: 0, totalHours: 0, lastWorked: "" };
25355
- g.entryCount += 1;
25356
- g.totalHours += e.hoursWorked ?? 0;
25357
- if ((e.dateWorked ?? "") > g.lastWorked) g.lastWorked = e.dateWorked ?? "";
25358
- groups.set(e.ticketID, g);
25359
- }
25360
- const ids2 = [...groups.keys()];
25361
- const tickets = /* @__PURE__ */ new Map();
25362
- for (let c = 0; c < ids2.length; c += TICKET_CHUNK) {
25363
- const chunk = ids2.slice(c, c + TICKET_CHUNK);
25364
- const filter = [{ field: "id", op: "in", value: chunk }];
25365
- const res = await http.request({
25366
- method: "POST",
25367
- idempotent: true,
25368
- path: "/V1.0/Tickets/query",
25369
- body: { MaxRecords: TICKET_CHUNK, filter, IncludeFields: TICKET_FIELDS2 },
25370
- operation: OP8
25371
- });
25372
- for (const t of unwrapItems(res, OP8).items) if (typeof t.id === "number") tickets.set(t.id, t);
25373
- }
25374
- const items = [];
25375
- const unresolvedTicketIDs = [];
25376
- let excludedTickets = 0;
25377
- for (const [ticketID, g] of groups) {
25378
- const t = tickets.get(ticketID);
25379
- if (t === void 0) unresolvedTicketIDs.push(ticketID);
25380
- if (companyID !== void 0 && t?.companyID !== companyID) {
25381
- if (t !== void 0) excludedTickets += 1;
25382
- continue;
25383
- }
25384
- items.push({
25385
- ticketID,
25386
- ...t?.ticketNumber !== void 0 ? { ticketNumber: t.ticketNumber } : {},
25387
- ...t?.title !== void 0 ? { title: t.title } : {},
25388
- ...t?.status !== void 0 ? { status: t.status } : {},
25389
- ...t?.assignedResourceID !== void 0 ? { assignedResourceID: t.assignedResourceID } : {},
25390
- ...t?.companyID !== void 0 ? { companyID: t.companyID } : {},
25391
- entryCount: g.entryCount,
25392
- totalHours: Math.round(g.totalHours * 100) / 100,
25393
- lastWorked: g.lastWorked
25394
- });
25395
- }
25396
- items.sort((a, b) => a.lastWorked < b.lastWorked ? 1 : a.lastWorked > b.lastWorked ? -1 : a.ticketID - b.ticketID);
25397
- return {
25398
- items,
25399
- entriesRead: entries.length,
25400
- entriesWithoutTicket,
25401
- unresolvedTicketIDs,
25402
- ...companyID !== void 0 ? { excludedTickets } : {},
25403
- window: { from: isoUtc(fromB.ms), to: isoUtc(windowToMs) },
25404
- truncated: hasMore
25405
- };
25406
- }
25407
-
25408
25311
  // src/resources/time_entries.ts
25409
25312
  var TimeEntriesResource = class extends BaseResource {
25410
25313
  constructor(http, pageSize) {
@@ -25536,11 +25439,6 @@ var TimeEntriesResource = class extends BaseResource {
25536
25439
  postedWithin(from, to, opts) {
25537
25440
  return postedWithin(this, from, to, this.http, opts);
25538
25441
  }
25539
- /** Node-parity special op (hand-written in src/resources/special/time_entries.ts).
25540
- * @deprecated Since 0.38.0, removed in the next minor. Use operations.aggregate(client, 'time_entries.query', [{ field: 'resourceID', op: 'eq', value: R }, { field: 'dateWorked', op: 'gte', value: FROM }, { field: 'dateWorked', op: 'lte', value: TO }], { groupBy: ['ticketID'], sum: ['hoursWorked'] }) — group keys carry ticketIDName; add { field: 'ticket.companyID', op: 'eq', value: C } to scope by company. */
25541
- recentTickets(from, to, opts) {
25542
- return recentTickets(this, from, to, this.http, opts);
25543
- }
25544
25442
  /** Node-parity special op (hand-written in src/resources/special/time_entries.ts). */
25545
25443
  today(opts) {
25546
25444
  return windowQuery3(this, "today", this.http, opts);