node-autotask 0.29.0 → 0.30.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 (41) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/MCP_TOOL_CATALOG.json +28 -9
  3. package/MCP_TOOL_MANIFEST.md +12 -11
  4. package/N8N_MCP_MANIFEST.json +3 -3
  5. package/N8N_MCP_MANIFEST.md +4 -4
  6. package/README.md +1 -1
  7. package/capabilities.json +1462 -1303
  8. package/dist/capabilities.cjs +2 -2
  9. package/dist/capabilities.js +1 -1
  10. package/dist/{chunk-X4TUU2Y6.js → chunk-2ETR5GSO.js} +2 -2
  11. package/dist/{chunk-PY45RBQ2.cjs → chunk-EDVSWL32.cjs} +1461 -1302
  12. package/dist/{chunk-APXBBN3D.cjs → chunk-L4TDVUJM.cjs} +143 -143
  13. package/dist/{chunk-IKWHRUQ5.cjs → chunk-LLIB4JGK.cjs} +52 -9
  14. package/dist/{chunk-T4SZGOJB.js → chunk-P4PC32RJ.js} +157 -80
  15. package/dist/{chunk-KVT5V7SA.js → chunk-QQPCJT2L.js} +49 -6
  16. package/dist/{chunk-BNIOQEKP.cjs → chunk-RS7QMPRO.cjs} +589 -512
  17. package/dist/{chunk-WKP442HS.js → chunk-TZC4ZAA6.js} +1461 -1302
  18. package/dist/{index-BZkfUU59.d.cts → index-B9VNv-EP.d.cts} +30 -3
  19. package/dist/{index-BGZ1Mhbh.d.cts → index-CJ36PwRG.d.cts} +6 -1
  20. package/dist/{index-BGZ1Mhbh.d.ts → index-CJ36PwRG.d.ts} +6 -1
  21. package/dist/{index-6_i-__sN.d.ts → index-DkpaFqyu.d.ts} +30 -3
  22. package/dist/index.cjs +22 -22
  23. package/dist/index.d.cts +4 -4
  24. package/dist/index.d.ts +4 -4
  25. package/dist/index.js +4 -4
  26. package/dist/operations/index.cjs +112 -112
  27. package/dist/operations/index.d.cts +4 -4
  28. package/dist/operations/index.d.ts +4 -4
  29. package/dist/operations/index.js +2 -2
  30. package/dist/pool.cjs +9 -9
  31. package/dist/pool.d.cts +2 -2
  32. package/dist/pool.d.ts +2 -2
  33. package/dist/pool.js +4 -4
  34. package/dist/resources/index.cjs +4 -4
  35. package/dist/resources/index.d.cts +2 -2
  36. package/dist/resources/index.d.ts +2 -2
  37. package/dist/resources/index.js +3 -3
  38. package/dist/types/index.d.cts +1 -1
  39. package/dist/types/index.d.ts +1 -1
  40. package/docs/API.md +1 -1
  41. package/package.json +1 -1
@@ -40,10 +40,10 @@ import {
40
40
  unwrapItems,
41
41
  unwrapOperation,
42
42
  vendorId
43
- } from "./chunk-KVT5V7SA.js";
43
+ } from "./chunk-QQPCJT2L.js";
44
44
  import {
45
45
  CAPABILITIES
46
- } from "./chunk-WKP442HS.js";
46
+ } from "./chunk-TZC4ZAA6.js";
47
47
 
48
48
  // src/resources/appointments.ts
49
49
  var AppointmentsResource = class extends BaseResource {
@@ -4832,6 +4832,42 @@ var ContractServiceUnitsResource = class extends BaseResource {
4832
4832
  }
4833
4833
  };
4834
4834
 
4835
+ // src/resources/special/contracts/lineOfBusiness.ts
4836
+ var OP3 = "contracts.lineOfBusiness";
4837
+ function positiveId(value, name) {
4838
+ const n = typeof value === "string" && /^[0-9]+$/.test(value.trim()) ? Number(value) : value;
4839
+ if (typeof n !== "number" || !Number.isSafeInteger(n) || n < 1) {
4840
+ throw new AutotaskConfigError(OP3 + ": " + name + " must be a positive integer id (got " + String(value) + ")", { operation: OP3 });
4841
+ }
4842
+ return n;
4843
+ }
4844
+ async function lineOfBusiness(resource, contractIdIn, http, associationIdIn) {
4845
+ const contractId = positiveId(contractIdIn, "contractId");
4846
+ let associationId;
4847
+ let associationSource;
4848
+ if (associationIdIn !== void 0) {
4849
+ associationId = positiveId(associationIdIn, "associationId");
4850
+ associationSource = "argument";
4851
+ } else {
4852
+ associationSource = "contract";
4853
+ const contract = await resource.get(contractId);
4854
+ associationId = vendorId(contract.organizationalLevelAssociationID);
4855
+ }
4856
+ if (associationId === void 0) {
4857
+ return {
4858
+ contractId,
4859
+ associationSource,
4860
+ association: null,
4861
+ organizationalLevel2: null,
4862
+ organizationalLevel1: null,
4863
+ markers: { association: "missing", organizationalLevel2: "missing", organizationalLevel1: "missing" }
4864
+ };
4865
+ }
4866
+ const chain = await resolveLineOfBusinessChain(http, associationId, { budget: 3, operation: OP3, onError: "propagate" });
4867
+ const { association, organizationalLevel2, organizationalLevel1, markers } = chain.lineOfBusiness;
4868
+ return { contractId, associationSource, association, organizationalLevel2, organizationalLevel1, markers };
4869
+ }
4870
+
4835
4871
  // src/resources/special/contracts/profitability.constants.ts
4836
4872
  var PROFITABILITY_OPT_KEYS = [
4837
4873
  "dateFrom",
@@ -5301,7 +5337,7 @@ function appendWiresNote(wires, note) {
5301
5337
  wires.note = (wires.note ? wires.note + " | " : "") + note;
5302
5338
  }
5303
5339
  function makeFetchCtx(rawHttp, v, contractId, budget) {
5304
- const OP10 = PROFITABILITY_OP;
5340
+ const OP11 = PROFITABILITY_OP;
5305
5341
  const id = parseIdentifier(contractId, "contractId");
5306
5342
  const idNum = typeof id === "number" ? id : Number(id);
5307
5343
  const wires = { issued: 0, requests: 0, budget };
@@ -5313,19 +5349,19 @@ function makeFetchCtx(rawHttp, v, contractId, budget) {
5313
5349
  } };
5314
5350
  const readPart = (path, conditions, fields) => {
5315
5351
  wires.issued += 1;
5316
- return degradable(() => boundedPart(http, path, conditions, v.limit, OP10, fields));
5352
+ return degradable(() => boundedPart(http, path, conditions, v.limit, OP11, fields));
5317
5353
  };
5318
5354
  const truncatedMonths = {};
5319
5355
  const windowedPart = async (name, key, path, cond, fields, dateField) => {
5320
5356
  const first = await readPart(path, cond, fields);
5321
5357
  if (first.absent !== void 0 || !first.hasMore) return { part: stampPart(key, first, cond), rows: first.items };
5322
- const wp = await degradable(() => expandByMonth(http, path, cond, v.limit, OP10, fields, dateField, v.dateFrom, v.dateTo, wires));
5358
+ const wp = await degradable(() => expandByMonth(http, path, cond, v.limit, OP11, fields, dateField, v.dateFrom, v.dateTo, wires));
5323
5359
  if (!("truncatedMonths" in wp)) return { part: stampPart(key, wp, cond), rows: [] };
5324
5360
  const { truncatedMonths: tm, ...part } = wp;
5325
5361
  truncatedMonths[name] = tm;
5326
5362
  return { part, rows: wp.items };
5327
5363
  };
5328
- return { v, OP: OP10, id, idNum, rawHttp, http, wires, windowOn, readPart, windowedPart, truncatedMonths };
5364
+ return { v, OP: OP11, id, idNum, rawHttp, http, wires, windowOn, readPart, windowedPart, truncatedMonths };
5329
5365
  }
5330
5366
 
5331
5367
  // src/resources/special/contracts/profitability.stages.ts
@@ -6331,6 +6367,10 @@ var ContractsResource = class extends BaseResource {
6331
6367
  profitability(id, opts) {
6332
6368
  return profitability(this, id, opts, this.http);
6333
6369
  }
6370
+ /** Node-parity special op (hand-written in src/resources/special/contracts.ts). */
6371
+ lineOfBusiness(contractId, associationId) {
6372
+ return lineOfBusiness(this, contractId, this.http, associationId);
6373
+ }
6334
6374
  };
6335
6375
 
6336
6376
  // src/resources/contract_ticket_purchases.ts
@@ -10693,22 +10733,22 @@ function uiLinkFor(http, entity, id) {
10693
10733
  }
10694
10734
 
10695
10735
  // src/resources/special/ticket_charges.ts
10696
- var OP3 = "ticket_charges.moveToTicket";
10736
+ var OP4 = "ticket_charges.moveToTicket";
10697
10737
  var COPY = ["name", "description", "chargeType", "billingCodeID", "productID", "unitQuantity", "unitCost", "unitPrice", "datePurchased", "isBillableToCompany", "notes", "purchaseOrderNumber", "internalPurchaseOrderNumber"];
10698
10738
  var CONTRACT_SCOPED = ["contractServiceID", "contractServiceBundleID"];
10699
10739
  async function readCharge(http, id, retries) {
10700
- const rows = await queryRows(http, "TicketCharges", [{ field: "id", op: "eq", value: id }], OP3, retries);
10740
+ const rows = await queryRows(http, "TicketCharges", [{ field: "id", op: "eq", value: id }], OP4, retries);
10701
10741
  return rows[0] ?? null;
10702
10742
  }
10703
10743
  async function checkSource({ http, source, sourceId, sourceTicketId, toTicketId }) {
10704
10744
  if (source.isBilled === true) {
10705
- throw refuse("MOVE_BLOCKED_BILLED", `${OP3}: ticket charge ${sourceId} is billed \u2014 move it in the Autotask UI`, { sourceId, toTicketId }, OP3, {
10745
+ throw refuse("MOVE_BLOCKED_BILLED", `${OP4}: ticket charge ${sourceId} is billed \u2014 move it in the Autotask UI`, { sourceId, toTicketId }, OP4, {
10706
10746
  manualAction: { action: "delete_source", uiLink: uiLinkFor(http, "tickets", sourceTicketId), reason: "billed charges are not moved by the API (the ticket link opens its charges)" }
10707
10747
  });
10708
10748
  }
10709
10749
  }
10710
10750
  var SPEC = {
10711
- operation: OP3,
10751
+ operation: OP4,
10712
10752
  entity: "ticket_charge",
10713
10753
  readSource: readCharge,
10714
10754
  sourceTicketId: (s) => typeof s.ticketID === "number" ? s.ticketID : null,
@@ -12063,7 +12103,12 @@ async function addCompositeNames(http, ctx, entriesPart, result, opts) {
12063
12103
  builder.addFk("contract", t["contractID"]);
12064
12104
  builder.addFk("billingCode", t["billingCodeID"]);
12065
12105
  builder.addFk("role", t["assignedResourceRoleID"]);
12066
- builder.addLineOfBusiness(t["organizationalLevelAssociationID"]);
12106
+ const ticketLobPointer = vendorId(t["organizationalLevelAssociationID"]);
12107
+ if (ticketLobPointer !== void 0) {
12108
+ builder.addLineOfBusiness(ticketLobPointer, { source: "ticket" });
12109
+ } else {
12110
+ builder.addLineOfBusinessFromContract(t["contractID"]);
12111
+ }
12067
12112
  for (const e of entriesPart.items) {
12068
12113
  builder.addResource(e["resourceID"]);
12069
12114
  builder.addFk("role", e["roleID"]);
@@ -12157,16 +12202,16 @@ async function fullContext(resource, id, opts = {}, http) {
12157
12202
  }
12158
12203
 
12159
12204
  // src/resources/special/tickets/forResource.ts
12160
- var OP4 = "tickets.forResource";
12205
+ var OP5 = "tickets.forResource";
12161
12206
  var TICKET_CHUNK = 100;
12162
12207
  var LIMIT_DEFAULT = 100;
12163
12208
  var LIMIT_MAX = 500;
12164
12209
  var LINK_READ_CAP = 500;
12165
12210
  var TICKET_FIELDS2 = ["id", "ticketNumber", "title", "status", "assignedResourceID", "companyID"];
12166
- function positiveId(value, name) {
12211
+ function positiveId2(value, name) {
12167
12212
  const n = typeof value === "string" && /^\d+$/.test(value.trim()) ? Number(value) : value;
12168
12213
  if (typeof n !== "number" || !Number.isSafeInteger(n) || n < 1) {
12169
- throw new AutotaskConfigError(`${OP4}: ${name} must be a positive integer id (got ${String(value)})`, { operation: OP4 });
12214
+ throw new AutotaskConfigError(`${OP5}: ${name} must be a positive integer id (got ${String(value)})`, { operation: OP5 });
12170
12215
  }
12171
12216
  return n;
12172
12217
  }
@@ -12176,28 +12221,28 @@ async function ticketPage(http, filter, maxRecords, fields) {
12176
12221
  idempotent: true,
12177
12222
  path: "/V1.0/Tickets/query",
12178
12223
  body: { MaxRecords: maxRecords, filter, IncludeFields: fields },
12179
- operation: OP4
12224
+ operation: OP5
12180
12225
  });
12181
- const page = unwrapItems(res, OP4);
12226
+ const page = unwrapItems(res, OP5);
12182
12227
  return { rows: page.items, more: page.pageDetails.nextPageUrl !== null };
12183
12228
  }
12184
12229
  async function forResource(_resource, resourceIDIn, http, opts = {}) {
12185
- if (opts === null || typeof opts !== "object") throw new AutotaskConfigError(`${OP4}: opts must be an object`, { operation: OP4 });
12186
- const resourceID = positiveId(resourceIDIn, "resourceID");
12230
+ if (opts === null || typeof opts !== "object") throw new AutotaskConfigError(`${OP5}: opts must be an object`, { operation: OP5 });
12231
+ const resourceID = positiveId2(resourceIDIn, "resourceID");
12187
12232
  const scope = opts.scope ?? "both";
12188
12233
  if (scope !== "primary" && scope !== "secondary" && scope !== "both") {
12189
- throw new AutotaskConfigError(`${OP4}: scope must be 'primary', 'secondary' or 'both' (got ${JSON.stringify(opts.scope)})`, { operation: OP4 });
12234
+ throw new AutotaskConfigError(`${OP5}: scope must be 'primary', 'secondary' or 'both' (got ${JSON.stringify(opts.scope)})`, { operation: OP5 });
12190
12235
  }
12191
12236
  if (opts.openOnly !== void 0 && typeof opts.openOnly !== "boolean") {
12192
- throw new AutotaskConfigError(`${OP4}: openOnly must be a boolean`, { operation: OP4 });
12237
+ throw new AutotaskConfigError(`${OP5}: openOnly must be a boolean`, { operation: OP5 });
12193
12238
  }
12194
12239
  const limit = opts.limit === void 0 ? LIMIT_DEFAULT : opts.limit;
12195
12240
  if (!Number.isInteger(limit) || limit < 1 || limit > LIMIT_MAX) {
12196
- throw new AutotaskConfigError(`${OP4}: limit must be an integer 1-${LIMIT_MAX} (got ${String(opts.limit)})`, { operation: OP4 });
12241
+ throw new AutotaskConfigError(`${OP5}: limit must be an integer 1-${LIMIT_MAX} (got ${String(opts.limit)})`, { operation: OP5 });
12197
12242
  }
12198
12243
  const includeFields = opts.includeFields ?? [];
12199
12244
  if (!Array.isArray(includeFields) || includeFields.some((f) => typeof f !== "string" || f.length === 0)) {
12200
- throw new AutotaskConfigError(`${OP4}: includeFields must be a list of field names`, { operation: OP4 });
12245
+ throw new AutotaskConfigError(`${OP5}: includeFields must be a list of field names`, { operation: OP5 });
12201
12246
  }
12202
12247
  const openOnly = opts.openOnly === true;
12203
12248
  const fields = [.../* @__PURE__ */ new Set([...TICKET_FIELDS2, ...includeFields])];
@@ -12212,9 +12257,9 @@ async function forResource(_resource, resourceIDIn, http, opts = {}) {
12212
12257
  idempotent: true,
12213
12258
  path: "/V1.0/TicketSecondaryResources/query",
12214
12259
  body: { MaxRecords: LINK_READ_CAP, filter: [{ field: "resourceID", op: "eq", value: resourceID }], IncludeFields: ["ticketID"] },
12215
- operation: OP4
12260
+ operation: OP5
12216
12261
  });
12217
- const page = unwrapItems(res, OP4);
12262
+ const page = unwrapItems(res, OP5);
12218
12263
  for (const row of page.items) if (typeof row.ticketID === "number" && !linkIds.includes(row.ticketID)) linkIds.push(row.ticketID);
12219
12264
  if (page.items.length >= LINK_READ_CAP || page.pageDetails.nextPageUrl !== null) capped = true;
12220
12265
  }
@@ -12267,35 +12312,67 @@ async function forResource(_resource, resourceIDIn, http, opts = {}) {
12267
12312
  }
12268
12313
 
12269
12314
  // src/resources/special/tickets/lineOfBusiness.ts
12270
- var OP5 = "tickets.lineOfBusiness";
12271
- function positiveId2(value, name) {
12315
+ var OP6 = "tickets.lineOfBusiness";
12316
+ function positiveId3(value, name) {
12272
12317
  const n = typeof value === "string" && /^[0-9]+$/.test(value.trim()) ? Number(value) : value;
12273
12318
  if (typeof n !== "number" || !Number.isSafeInteger(n) || n < 1) {
12274
- throw new AutotaskConfigError(OP5 + ": " + name + " must be a positive integer id (got " + String(value) + ")", { operation: OP5 });
12319
+ throw new AutotaskConfigError(OP6 + ": " + name + " must be a positive integer id (got " + String(value) + ")", { operation: OP6 });
12275
12320
  }
12276
12321
  return n;
12277
12322
  }
12278
- async function lineOfBusiness(resource, ticketIdIn, http, associationIdIn) {
12279
- const ticketId = positiveId2(ticketIdIn, "ticketId");
12323
+ async function lineOfBusiness2(resource, ticketIdIn, http, associationIdIn) {
12324
+ const ticketId = positiveId3(ticketIdIn, "ticketId");
12280
12325
  let associationId;
12326
+ let associationSource = null;
12327
+ let contractId = null;
12328
+ let contractUnread = false;
12281
12329
  if (associationIdIn !== void 0) {
12282
- associationId = positiveId2(associationIdIn, "associationId");
12330
+ associationId = positiveId3(associationIdIn, "associationId");
12331
+ associationSource = "argument";
12283
12332
  } else {
12284
12333
  const ticket = await resource.get(ticketId);
12285
12334
  associationId = vendorId(ticket.organizationalLevelAssociationID);
12335
+ if (associationId !== void 0) {
12336
+ associationSource = "ticket";
12337
+ } else {
12338
+ const contractRef = vendorId(ticket.contractID);
12339
+ if (contractRef !== void 0) {
12340
+ const client = http.client;
12341
+ if (client === void 0) {
12342
+ throw new AutotaskConfigError(OP6 + ": the transport is not wired to an AutotaskClient (the composite must run through the client)", { operation: OP6 });
12343
+ }
12344
+ try {
12345
+ const contract = await client.contracts.get(contractRef);
12346
+ contractId = contractRef;
12347
+ associationId = vendorId(contract.organizationalLevelAssociationID);
12348
+ if (associationId !== void 0) associationSource = "contract";
12349
+ } catch (e) {
12350
+ if (e instanceof NotFoundError) {
12351
+ contractId = contractRef;
12352
+ } else if (isAutotaskError(e) && e.code !== "ABORTED") {
12353
+ contractId = contractRef;
12354
+ contractUnread = true;
12355
+ } else {
12356
+ throw e;
12357
+ }
12358
+ }
12359
+ }
12360
+ }
12286
12361
  }
12287
12362
  if (associationId === void 0) {
12288
12363
  return {
12289
12364
  ticketId,
12365
+ associationSource,
12366
+ contractId,
12290
12367
  association: null,
12291
12368
  organizationalLevel2: null,
12292
12369
  organizationalLevel1: null,
12293
- markers: { association: "missing", organizationalLevel2: "missing", organizationalLevel1: "missing" }
12370
+ markers: { association: contractUnread ? "unresolved" : "missing", organizationalLevel2: "missing", organizationalLevel1: "missing" }
12294
12371
  };
12295
12372
  }
12296
- const chain = await resolveLineOfBusinessChain(http, associationId, { budget: 3, operation: OP5, onError: "propagate" });
12373
+ const chain = await resolveLineOfBusinessChain(http, associationId, { budget: 3, operation: OP6, onError: "propagate" });
12297
12374
  const { association, organizationalLevel2, organizationalLevel1, markers } = chain.lineOfBusiness;
12298
- return { ticketId, association, organizationalLevel2, organizationalLevel1, markers };
12375
+ return { ticketId, associationSource, contractId, association, organizationalLevel2, organizationalLevel1, markers };
12299
12376
  }
12300
12377
 
12301
12378
  // src/resources/special/tickets/statusSemantics.ts
@@ -12418,7 +12495,7 @@ var TicketsResource = class extends BaseResource {
12418
12495
  }
12419
12496
  /** Node-parity special op (hand-written in src/resources/special/tickets.ts). */
12420
12497
  lineOfBusiness(ticketId, associationId) {
12421
- return lineOfBusiness(this, ticketId, this.http, associationId);
12498
+ return lineOfBusiness2(this, ticketId, this.http, associationId);
12422
12499
  }
12423
12500
  };
12424
12501
 
@@ -12548,12 +12625,12 @@ async function postedDateStatusQuery(_resource, mode, http, opts) {
12548
12625
  return items;
12549
12626
  }
12550
12627
  async function postedWithin(_resource, from, to, http, opts, opLabel = "time_entries.postedWithin") {
12551
- const OP10 = opLabel;
12552
- if (opts?.tz !== void 0) validateZone(opts.tz, OP10);
12553
- const fromB = customRangeDay(from, "from", void 0, OP10);
12554
- const toB = customRangeDay(to, "to", void 0, OP10);
12628
+ const OP11 = opLabel;
12629
+ if (opts?.tz !== void 0) validateZone(opts.tz, OP11);
12630
+ const fromB = customRangeDay(from, "from", void 0, OP11);
12631
+ const toB = customRangeDay(to, "to", void 0, OP11);
12555
12632
  if (fromB.ms > toB.ms) {
12556
- throw new AutotaskConfigError(`${OP10}: from (${iso2(fromB.ms)}) must not be after to (${iso2(toB.ms)})`, { operation: OP10 });
12633
+ throw new AutotaskConfigError(`${OP11}: from (${iso2(fromB.ms)}) must not be after to (${iso2(toB.ms)})`, { operation: OP11 });
12557
12634
  }
12558
12635
  const windowToMs = toB.ms + DAY_MS2 - 1;
12559
12636
  const filter = [
@@ -12564,7 +12641,7 @@ async function postedWithin(_resource, from, to, http, opts, opLabel = "time_ent
12564
12641
  else if (opts?.posted === false) filter.push({ field: "postedDate", op: "notExist" });
12565
12642
  if (opts?.ticketID !== void 0) filter.push({ field: "ticketID", op: "eq", value: opts.ticketID });
12566
12643
  if (opts?.resourceID !== void 0) filter.push({ field: "resourceID", op: "eq", value: opts.resourceID });
12567
- const { items, hasMore } = await queryTimeEntries(_resource, filter, clampWindowLimit(opts?.limit), OP10, http);
12644
+ const { items, hasMore } = await queryTimeEntries(_resource, filter, clampWindowLimit(opts?.limit), OP11, http);
12568
12645
  let postedCount = 0;
12569
12646
  for (const item of items) {
12570
12647
  const postedDate = item.postedDate;
@@ -12774,7 +12851,7 @@ async function resolveCode(http, family, familyLabel2, pinnedId, departments, op
12774
12851
  }
12775
12852
 
12776
12853
  // src/resources/special/time_entries/createForResource.ts
12777
- var OP6 = "time_entries.createForResource";
12854
+ var OP7 = "time_entries.createForResource";
12778
12855
  var PARAM_KEYS = /* @__PURE__ */ new Set([
12779
12856
  "internallAllocationCodeID",
12780
12857
  "ticketID",
@@ -12810,30 +12887,30 @@ function validateCreateParams(params) {
12810
12887
  if (pinCount > 1) {
12811
12888
  throw new AutotaskConfigError(
12812
12889
  "createForResource: exactly one linkage pin is honoured (internallAllocationCodeID | ticketID | taskID) \u2014 the vendor gate requires exactly one; pass one pin (or none for the default internal linkage)",
12813
- { operation: OP6 }
12890
+ { operation: OP7 }
12814
12891
  );
12815
12892
  }
12816
12893
  if (pins.role !== void 0 && pins.code !== void 0) {
12817
12894
  throw new AutotaskConfigError(
12818
12895
  "createForResource: a pinned roleID is only meaningful with the task/ticket linkage (internallAllocationCodeID pins the internal linkage and owns the code) \u2014 drop one",
12819
- { operation: OP6 }
12896
+ { operation: OP7 }
12820
12897
  );
12821
12898
  }
12822
12899
  if (params.hoursWorked !== void 0 && (typeof params.hoursWorked !== "number" || !Number.isFinite(params.hoursWorked) || params.hoursWorked <= 0)) {
12823
12900
  throw new AutotaskConfigError(
12824
12901
  `createForResource: hoursWorked must be a positive finite number (got ${String(params.hoursWorked)})`,
12825
- { operation: OP6 }
12902
+ { operation: OP7 }
12826
12903
  );
12827
12904
  }
12828
12905
  return pins;
12829
12906
  }
12830
12907
  async function assertResourceActive(http, rid) {
12831
- const rec = await fetchItem2(http, `/V1.0/Resources/${rid}`, OP6);
12908
+ const rec = await fetchItem2(http, `/V1.0/Resources/${rid}`, OP7);
12832
12909
  if (rec === null) {
12833
12910
  throw new ResourceInvalidError(`Resource ${rid} was not found \u2014 a time entry cannot attach to a missing resource`, {
12834
12911
  resourceIds: [rid],
12835
12912
  details: { idRefs: [{ entity: "resource", id: rid }] },
12836
- operation: OP6,
12913
+ operation: OP7,
12837
12914
  category: "not_found",
12838
12915
  suggestedAction: "Resolve the resource id (resources.get / resources.search) and retry."
12839
12916
  });
@@ -12842,7 +12919,7 @@ async function assertResourceActive(http, rid) {
12842
12919
  throw new ResourceInvalidError(`Resource ${rid} is not active (isActive !== true) \u2014 the vendor would reject a time entry for an inactive resource`, {
12843
12920
  resourceIds: [rid],
12844
12921
  details: { idRefs: [{ entity: "resource", id: rid }] },
12845
- operation: OP6,
12922
+ operation: OP7,
12846
12923
  suggestedAction: "Activate the resource or pick an active one."
12847
12924
  });
12848
12925
  }
@@ -12852,11 +12929,11 @@ async function resolveAllocationCode(http, rid, linkage, pins, departments) {
12852
12929
  const pinnedForCode = pins.code !== void 0 ? pins.code : pins.role;
12853
12930
  let code = null;
12854
12931
  const familiesTried = [];
12855
- code = await resolveCode(http, familyOf(linkage), familyLabel(familyOf(linkage)), pinnedForCode, departments, OP6);
12932
+ code = await resolveCode(http, familyOf(linkage), familyLabel(familyOf(linkage)), pinnedForCode, departments, OP7);
12856
12933
  familiesTried.push({ family: familyOf(linkage), label: familyLabel(familyOf(linkage)), filters: [{ field: "useType", op: "eq", value: familyOf(linkage) }, { field: "isActive", op: "eq", value: true }] });
12857
12934
  if (code === null && linkage === "task" && pins.role === void 0) {
12858
12935
  usedLinkage = "internal";
12859
- code = await resolveCode(http, USE_TYPE_INTERNAL, familyLabel(USE_TYPE_INTERNAL), void 0, departments, OP6);
12936
+ code = await resolveCode(http, USE_TYPE_INTERNAL, familyLabel(USE_TYPE_INTERNAL), void 0, departments, OP7);
12860
12937
  familiesTried.push({ family: USE_TYPE_INTERNAL, label: familyLabel(USE_TYPE_INTERNAL), filters: [{ field: "useType", op: "eq", value: USE_TYPE_INTERNAL }, { field: "isActive", op: "eq", value: true }] });
12861
12938
  }
12862
12939
  if (code === null) {
@@ -12866,7 +12943,7 @@ async function resolveAllocationCode(http, rid, linkage, pins, departments) {
12866
12943
  families: familiesTried,
12867
12944
  resourceDepartments: [...departments].sort((a, b) => a - b)
12868
12945
  },
12869
- { operation: OP6 }
12946
+ { operation: OP7 }
12870
12947
  );
12871
12948
  }
12872
12949
  const resolvedCode = codeInfo(code);
@@ -12905,7 +12982,7 @@ function createDryRun2(http, rid, body, linkage, usedLinkage, resolvedCode) {
12905
12982
  }
12906
12983
  return buildDryRunResult(
12907
12984
  {
12908
- operation: OP6,
12985
+ operation: OP7,
12909
12986
  method: "POST",
12910
12987
  path: "/V1.0/TimeEntries",
12911
12988
  ids: [rid],
@@ -12947,7 +13024,7 @@ async function createWithAttempts(resource, http, opts, body, defaults, pins, us
12947
13024
  const gate3 = ROLE_REJECTION_PATTERN.test(text);
12948
13025
  if (usedLinkage !== "internal" && gate3) {
12949
13026
  if (!taskRoleFetched && usedLinkage === "task" && pins.task !== void 0) {
12950
- const task = await fetchItem2(http, `/V1.0/Tasks/${pins.task}`, OP6);
13027
+ const task = await fetchItem2(http, `/V1.0/Tasks/${pins.task}`, OP7);
12951
13028
  taskRoleFetched = true;
12952
13029
  if (task !== null) pushLadder(task.assignedResourceRoleID);
12953
13030
  }
@@ -12973,7 +13050,7 @@ async function createForResource(resource, resourceID, params, opts = {}, http)
12973
13050
  const pins = validateCreateParams(params);
12974
13051
  await assertResourceActive(http, rid);
12975
13052
  const linkage = pins.code !== void 0 ? "internal" : pins.ticket !== void 0 ? "ticket" : pins.task !== void 0 ? "task" : "internal";
12976
- const roleRows = await resourceRoleRows(http, rid, OP6);
13053
+ const roleRows = await resourceRoleRows(http, rid, OP7);
12977
13054
  const departments = roleRows.departments;
12978
13055
  const { usedLinkage, resolvedCode } = await resolveAllocationCode(http, rid, linkage, pins, departments);
12979
13056
  const defaults = windowDefaults(params);
@@ -12996,12 +13073,12 @@ function discoveryField(err, body, defaults) {
12996
13073
  }
12997
13074
 
12998
13075
  // src/resources/special/time_entries/move.ts
12999
- var OP7 = "time_entries.moveToTicket";
13076
+ var OP8 = "time_entries.moveToTicket";
13000
13077
  var COPY2 = ["resourceID", "roleID", "billingCodeID", "dateWorked", "startDateTime", "endDateTime", "hoursWorked", "offsetHours", "summaryNotes", "internalNotes", "isNonBillable", "showOnInvoice"];
13001
13078
  var CONTRACT_SCOPED2 = ["contractID", "contractServiceID", "contractServiceBundleID"];
13002
13079
  async function readTimeEntry(http, id, retries) {
13003
13080
  try {
13004
- const res = await http.request({ method: "GET", path: `/V1.0/TimeEntries/${id}`, operation: OP7, maxRetries: retries });
13081
+ const res = await http.request({ method: "GET", path: `/V1.0/TimeEntries/${id}`, operation: OP8, maxRetries: retries });
13005
13082
  return res?.item ?? null;
13006
13083
  } catch (e) {
13007
13084
  if (isAutotaskError(e) && (e.httpStatus === 404 || e.code === "NOT_FOUND")) return null;
@@ -13011,27 +13088,27 @@ async function readTimeEntry(http, id, retries) {
13011
13088
  async function checkSource2({ http, source, sourceId, toTicketId, retries }) {
13012
13089
  const ids2 = { sourceId, toTicketId };
13013
13090
  if (source.taskID !== null && source.taskID !== void 0) {
13014
- throw refuse("MOVE_SOURCE_UNSUPPORTED", `${OP7}: time entry ${sourceId} is on a task \u2014 only ticket time entries are moved`, ids2, OP7);
13091
+ throw refuse("MOVE_SOURCE_UNSUPPORTED", `${OP8}: time entry ${sourceId} is on a task \u2014 only ticket time entries are moved`, ids2, OP8);
13015
13092
  }
13016
13093
  if (source.billingApprovalDateTime || source.billingApprovalResourceID || source.billingApprovalLevelMostRecent) {
13017
- throw refuse("MOVE_BLOCKED_APPROVED", `${OP7}: time entry ${sourceId} has billing approval set \u2014 move it in the Autotask UI`, ids2, OP7, { manualAction: { action: "delete_source", uiLink: uiLinkFor(http, "time_entries", sourceId), reason: "approved entries are not moved by the API" } });
13094
+ throw refuse("MOVE_BLOCKED_APPROVED", `${OP8}: time entry ${sourceId} has billing approval set \u2014 move it in the Autotask UI`, ids2, OP8, { manualAction: { action: "delete_source", uiLink: uiLinkFor(http, "time_entries", sourceId), reason: "approved entries are not moved by the API" } });
13018
13095
  }
13019
13096
  let billing;
13020
13097
  try {
13021
- billing = await queryRows(http, "BillingItems", [{ field: "timeEntryID", op: "eq", value: sourceId }], OP7, retries);
13098
+ billing = await queryRows(http, "BillingItems", [{ field: "timeEntryID", op: "eq", value: sourceId }], OP8, retries);
13022
13099
  } catch {
13023
- throw refuse("MOVE_BLOCKED_BILLED", `${OP7}: the billing items of time entry ${sourceId} could not be read \u2014 refused (fails closed)`, ids2, OP7, { manualAction: { action: "delete_source", uiLink: uiLinkFor(http, "time_entries", sourceId), reason: "billing state unreadable" } });
13100
+ throw refuse("MOVE_BLOCKED_BILLED", `${OP8}: the billing items of time entry ${sourceId} could not be read \u2014 refused (fails closed)`, ids2, OP8, { manualAction: { action: "delete_source", uiLink: uiLinkFor(http, "time_entries", sourceId), reason: "billing state unreadable" } });
13024
13101
  }
13025
13102
  if (billing.some((b) => b.invoiceID || b.postedDate)) {
13026
- throw refuse("MOVE_BLOCKED_BILLED", `${OP7}: time entry ${sourceId} is billed or posted \u2014 move it in the Autotask UI`, ids2, OP7, { manualAction: { action: "delete_source", uiLink: uiLinkFor(http, "time_entries", sourceId), reason: "billed entries are not moved by the API" } });
13103
+ throw refuse("MOVE_BLOCKED_BILLED", `${OP8}: time entry ${sourceId} is billed or posted \u2014 move it in the Autotask UI`, ids2, OP8, { manualAction: { action: "delete_source", uiLink: uiLinkFor(http, "time_entries", sourceId), reason: "billed entries are not moved by the API" } });
13027
13104
  }
13028
- const attachments = await queryRows(http, "TimeEntryAttachments", [{ field: "timeEntryID", op: "eq", value: sourceId }], OP7, retries);
13105
+ const attachments = await queryRows(http, "TimeEntryAttachments", [{ field: "timeEntryID", op: "eq", value: sourceId }], OP8, retries);
13029
13106
  if (attachments.length > 0) {
13030
- throw refuse("MOVE_BLOCKED_ATTACHMENTS", `${OP7}: time entry ${sourceId} has attachments, which a delete would destroy \u2014 move it in the Autotask UI`, ids2, OP7, { manualAction: { action: "delete_source", uiLink: uiLinkFor(http, "time_entries", sourceId), reason: "entries with attachments are not moved by the API" } });
13107
+ throw refuse("MOVE_BLOCKED_ATTACHMENTS", `${OP8}: time entry ${sourceId} has attachments, which a delete would destroy \u2014 move it in the Autotask UI`, ids2, OP8, { manualAction: { action: "delete_source", uiLink: uiLinkFor(http, "time_entries", sourceId), reason: "entries with attachments are not moved by the API" } });
13031
13108
  }
13032
13109
  }
13033
13110
  var SPEC2 = {
13034
- operation: OP7,
13111
+ operation: OP8,
13035
13112
  entity: "time_entry",
13036
13113
  readSource: readTimeEntry,
13037
13114
  sourceTicketId: (s) => typeof s.ticketID === "number" ? s.ticketID : null,
@@ -13066,7 +13143,7 @@ function moveToTicket2(_resource, sourceId, toTicketId, opts, http) {
13066
13143
  }
13067
13144
 
13068
13145
  // src/resources/special/time_entries/approve.ts
13069
- var OP8 = "time_entries.approve";
13146
+ var OP9 = "time_entries.approve";
13070
13147
  var APPROVAL_LEVELS_PATH = "/V1.0/BillingItemApprovalLevels";
13071
13148
  function toIso(value) {
13072
13149
  if (value instanceof Date) {
@@ -13104,7 +13181,7 @@ async function approve(resource, id, opts = {}, http) {
13104
13181
  if (opts.dryRun === true) {
13105
13182
  return buildDryRunResult(
13106
13183
  {
13107
- operation: OP8,
13184
+ operation: OP9,
13108
13185
  method: "POST",
13109
13186
  path: APPROVAL_LEVELS_PATH,
13110
13187
  ids: [numericId],
@@ -13127,10 +13204,10 @@ async function approve(resource, id, opts = {}, http) {
13127
13204
  method: "POST",
13128
13205
  path: APPROVAL_LEVELS_PATH,
13129
13206
  body,
13130
- operation: OP8,
13207
+ operation: OP9,
13131
13208
  maxRetries: opts.maxRetries
13132
13209
  });
13133
- const levelId = toNumber(parseIdentifier(unwrapOperation(created, OP8).id, "billingItemApprovalLevelID"));
13210
+ const levelId = toNumber(parseIdentifier(unwrapOperation(created, OP9).id, "billingItemApprovalLevelID"));
13134
13211
  await resource.update(
13135
13212
  numericId,
13136
13213
  { billingApprovalDateTime: approvalDateTime, billingApprovalResourceID: approvalResourceID },
@@ -13153,28 +13230,28 @@ async function approve(resource, id, opts = {}, http) {
13153
13230
  }
13154
13231
 
13155
13232
  // src/resources/special/time_entries/recentTickets.ts
13156
- var OP9 = "time_entries.recentTickets";
13233
+ var OP10 = "time_entries.recentTickets";
13157
13234
  var DAY_MS3 = 864e5;
13158
13235
  var TICKET_CHUNK2 = 100;
13159
13236
  var TICKET_FIELDS3 = ["id", "ticketNumber", "title", "status", "assignedResourceID", "companyID"];
13160
- function positiveId3(value, name) {
13237
+ function positiveId4(value, name) {
13161
13238
  const n = typeof value === "string" && /^\d+$/.test(value.trim()) ? Number(value) : value;
13162
13239
  if (typeof n !== "number" || !Number.isSafeInteger(n) || n < 1) {
13163
- throw new AutotaskConfigError(`${OP9}: ${name} must be a positive integer id (got ${String(value)})`, { operation: OP9 });
13240
+ throw new AutotaskConfigError(`${OP10}: ${name} must be a positive integer id (got ${String(value)})`, { operation: OP10 });
13164
13241
  }
13165
13242
  return n;
13166
13243
  }
13167
13244
  async function recentTickets(_resource, from, to, http, opts) {
13168
13245
  if (opts === void 0 || opts === null || typeof opts !== "object") {
13169
- throw new AutotaskConfigError(`${OP9}: opts { resourceID, companyID?, tz?, limit? } is required`, { operation: OP9 });
13246
+ throw new AutotaskConfigError(`${OP10}: opts { resourceID, companyID?, tz?, limit? } is required`, { operation: OP10 });
13170
13247
  }
13171
- const resourceID = positiveId3(opts.resourceID, "resourceID");
13172
- const companyID = opts.companyID === void 0 ? void 0 : positiveId3(opts.companyID, "companyID");
13173
- if (opts.tz !== void 0) validateZone(opts.tz, OP9);
13174
- const fromB = customRangeDay(from, "from", void 0, OP9);
13175
- const toB = customRangeDay(to, "to", void 0, OP9);
13248
+ const resourceID = positiveId4(opts.resourceID, "resourceID");
13249
+ const companyID = opts.companyID === void 0 ? void 0 : positiveId4(opts.companyID, "companyID");
13250
+ if (opts.tz !== void 0) validateZone(opts.tz, OP10);
13251
+ const fromB = customRangeDay(from, "from", void 0, OP10);
13252
+ const toB = customRangeDay(to, "to", void 0, OP10);
13176
13253
  if (fromB.ms > toB.ms) {
13177
- throw new AutotaskConfigError(`${OP9}: from (${isoUtc(fromB.ms)}) must not be after to (${isoUtc(toB.ms)})`, { operation: OP9 });
13254
+ throw new AutotaskConfigError(`${OP10}: from (${isoUtc(fromB.ms)}) must not be after to (${isoUtc(toB.ms)})`, { operation: OP10 });
13178
13255
  }
13179
13256
  const windowToMs = toB.ms + DAY_MS3 - 1;
13180
13257
  const { items: entries, hasMore } = await queryTimeEntries(
@@ -13185,7 +13262,7 @@ async function recentTickets(_resource, from, to, http, opts) {
13185
13262
  { field: "resourceID", op: "eq", value: resourceID }
13186
13263
  ],
13187
13264
  clampWindowLimit(opts.limit),
13188
- OP9,
13265
+ OP10,
13189
13266
  http
13190
13267
  );
13191
13268
  const groups = /* @__PURE__ */ new Map();
@@ -13211,9 +13288,9 @@ async function recentTickets(_resource, from, to, http, opts) {
13211
13288
  idempotent: true,
13212
13289
  path: "/V1.0/Tickets/query",
13213
13290
  body: { MaxRecords: TICKET_CHUNK2, filter, IncludeFields: TICKET_FIELDS3 },
13214
- operation: OP9
13291
+ operation: OP10
13215
13292
  });
13216
- for (const t of unwrapItems(res, OP9).items) if (typeof t.id === "number") tickets.set(t.id, t);
13293
+ for (const t of unwrapItems(res, OP10).items) if (typeof t.id === "number") tickets.set(t.id, t);
13217
13294
  }
13218
13295
  const items = [];
13219
13296
  const unresolvedTicketIDs = [];