node-autotask 0.25.0 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/MCP_TOOL_CATALOG.json +1063 -30
  3. package/MCP_TOOL_MANIFEST.md +82 -24
  4. package/N8N_MCP_MANIFEST.json +39 -8
  5. package/N8N_MCP_MANIFEST.md +9 -8
  6. package/README.md +11 -9
  7. package/capabilities.json +16956 -10596
  8. package/capabilities.schema.json +125 -0
  9. package/dist/capabilities.cjs +2 -2
  10. package/dist/capabilities.js +1 -1
  11. package/dist/{chunk-VUGZKP33.js → chunk-42ZUISDH.js} +997 -136
  12. package/dist/{chunk-WBMRACCV.cjs → chunk-5CC7LGNM.cjs} +16955 -10595
  13. package/dist/{chunk-Z5L7Q33V.cjs → chunk-5GGCSRT4.cjs} +947 -493
  14. package/dist/{chunk-EFR2XWRX.js → chunk-F7FVOXPQ.js} +16955 -10595
  15. package/dist/{chunk-XUB3S6AM.js → chunk-GURC52J7.js} +26 -2
  16. package/dist/{chunk-FKJ77K6Z.cjs → chunk-UHTZLUDE.cjs} +159 -135
  17. package/dist/{chunk-6PIJ6AZG.js → chunk-ZGTFVZL5.js} +478 -24
  18. package/dist/{chunk-2H7YI54B.cjs → chunk-ZJ4ONAQF.cjs} +1084 -223
  19. package/dist/{index-CZ94y401.d.ts → index-BIWy9m-a.d.ts} +414 -49
  20. package/dist/{index-C0OwQhon.d.cts → index-D4XYtn4s.d.cts} +414 -49
  21. package/dist/{index-BVtycq-6.d.cts → index-DQ9NgraW.d.cts} +322 -1
  22. package/dist/{index-BVtycq-6.d.ts → index-DQ9NgraW.d.ts} +322 -1
  23. package/dist/index.cjs +46 -24
  24. package/dist/index.d.cts +11 -5
  25. package/dist/index.d.ts +11 -5
  26. package/dist/index.js +28 -6
  27. package/dist/operations/index.cjs +147 -120
  28. package/dist/operations/index.d.cts +136 -7
  29. package/dist/operations/index.d.ts +136 -7
  30. package/dist/operations/index.js +33 -6
  31. package/dist/pool.cjs +42 -9
  32. package/dist/pool.d.cts +14 -3
  33. package/dist/pool.d.ts +14 -3
  34. package/dist/pool.js +38 -5
  35. package/dist/resources/index.cjs +21 -5
  36. package/dist/resources/index.d.cts +2 -2
  37. package/dist/resources/index.d.ts +2 -2
  38. package/dist/resources/index.js +20 -4
  39. package/dist/types/index.cjs +1 -1
  40. package/dist/types/index.d.cts +1 -1
  41. package/dist/types/index.d.ts +1 -1
  42. package/dist/types/index.js +1 -1
  43. package/docs/API.md +207 -9
  44. package/examples/mcp/schemas.ts +16 -7
  45. package/package.json +3 -3
  46. /package/dist/{chunk-FLB2X6O5.cjs → chunk-IXF7AKOJ.cjs} +0 -0
  47. /package/dist/{chunk-DMMMWO6A.js → chunk-RMG55JTF.js} +0 -0
  48. /package/dist/{chunk-IDPB4N2Q.cjs → chunk-SDYRQFGL.cjs} +0 -0
  49. /package/dist/{chunk-UPQIUWOS.js → chunk-WLTLB2ND.js} +0 -0
@@ -38,10 +38,10 @@ import {
38
38
  unwrapItem,
39
39
  unwrapItems,
40
40
  unwrapOperation
41
- } from "./chunk-VUGZKP33.js";
41
+ } from "./chunk-42ZUISDH.js";
42
42
  import {
43
43
  CAPABILITIES
44
- } from "./chunk-EFR2XWRX.js";
44
+ } from "./chunk-F7FVOXPQ.js";
45
45
 
46
46
  // src/resources/appointments.ts
47
47
  var AppointmentsResource = class extends BaseResource {
@@ -172,6 +172,42 @@ var BillingCodesResource = class extends BaseResource {
172
172
  }
173
173
  };
174
174
 
175
+ // src/resources/billing_item_approval_levels.ts
176
+ var BillingItemApprovalLevelsResource = class extends BaseResource {
177
+ constructor(http, pageSize) {
178
+ super(http, {
179
+ key: "billing_item_approval_levels",
180
+ resourcePath: "/V1.0/BillingItemApprovalLevels",
181
+ deletable: false,
182
+ udfCapable: false
183
+ }, pageSize);
184
+ }
185
+ /** Query BillingItemApprovalLevel records with the G3 filter surface (server-side JSON filter). */
186
+ query(params) {
187
+ return this.queryItems(params);
188
+ }
189
+ /** Get every BillingItemApprovalLevel record (the MCP-preferred read; 1000-page guarded). */
190
+ async queryAll(params) {
191
+ return this.queryAllItems(params);
192
+ }
193
+ /** Count matching records (queryCount envelope unwrapped to a plain number). */
194
+ async count(params) {
195
+ return this.countGlobal(params);
196
+ }
197
+ /** Get one record by id (item envelope; item: null → NotFoundError). */
198
+ async get(id) {
199
+ return this.getGlobal(id);
200
+ }
201
+ /** Create a record (OperationResultModel → { id}). `dryRun: true` returns the
202
+ * pinned envelope (section 19.3) and never issues the create. A 2xx that is not the
203
+ * specced envelope runs the plan-pinned marker recovery (issue #13 — one bounded read;
204
+ * `recoverIdFromMarker: false` restores the pre-recovery behaviour). */
205
+ async create(data, opts = {}) {
206
+ if (opts.dryRun === true) return this.runCreateDryRun(data);
207
+ return this.createGlobal(data, opts);
208
+ }
209
+ };
210
+
175
211
  // src/resources/special/dateWindow.ts
176
212
  var DAY_MS = 864e5;
177
213
  var DEFAULT_LIMIT = 500;
@@ -5184,7 +5220,7 @@ function appendWiresNote(wires, note) {
5184
5220
  wires.note = (wires.note ? wires.note + " | " : "") + note;
5185
5221
  }
5186
5222
  function makeFetchCtx(rawHttp, v, contractId, budget) {
5187
- const OP6 = PROFITABILITY_OP;
5223
+ const OP7 = PROFITABILITY_OP;
5188
5224
  const id = parseIdentifier(contractId, "contractId");
5189
5225
  const idNum = typeof id === "number" ? id : Number(id);
5190
5226
  const wires = { issued: 0, requests: 0, budget };
@@ -5196,19 +5232,19 @@ function makeFetchCtx(rawHttp, v, contractId, budget) {
5196
5232
  } };
5197
5233
  const readPart = (path, conditions, fields) => {
5198
5234
  wires.issued += 1;
5199
- return degradable(() => boundedPart(http, path, conditions, v.limit, OP6, fields));
5235
+ return degradable(() => boundedPart(http, path, conditions, v.limit, OP7, fields));
5200
5236
  };
5201
5237
  const truncatedMonths = {};
5202
5238
  const windowedPart = async (name, key, path, cond, fields, dateField) => {
5203
5239
  const first = await readPart(path, cond, fields);
5204
5240
  if (first.absent !== void 0 || !first.hasMore) return { part: stampPart(key, first, cond), rows: first.items };
5205
- const wp = await degradable(() => expandByMonth(http, path, cond, v.limit, OP6, fields, dateField, v.dateFrom, v.dateTo, wires));
5241
+ const wp = await degradable(() => expandByMonth(http, path, cond, v.limit, OP7, fields, dateField, v.dateFrom, v.dateTo, wires));
5206
5242
  if (!("truncatedMonths" in wp)) return { part: stampPart(key, wp, cond), rows: [] };
5207
5243
  const { truncatedMonths: tm, ...part } = wp;
5208
5244
  truncatedMonths[name] = tm;
5209
5245
  return { part, rows: wp.items };
5210
5246
  };
5211
- return { v, OP: OP6, id, idNum, rawHttp, http, wires, windowOn, readPart, windowedPart, truncatedMonths };
5247
+ return { v, OP: OP7, id, idNum, rawHttp, http, wires, windowOn, readPart, windowedPart, truncatedMonths };
5212
5248
  }
5213
5249
 
5214
5250
  // src/resources/special/contracts/profitability.stages.ts
@@ -6334,6 +6370,50 @@ var CountriesResource = class extends BaseResource {
6334
6370
  }
6335
6371
  };
6336
6372
 
6373
+ // src/resources/currencies.ts
6374
+ var CurrenciesResource = class extends BaseResource {
6375
+ constructor(http, pageSize) {
6376
+ super(http, {
6377
+ key: "currencies",
6378
+ resourcePath: "/V1.0/Currencies",
6379
+ deletable: false,
6380
+ udfCapable: false,
6381
+ searchFields: ["name"]
6382
+ }, pageSize);
6383
+ }
6384
+ /** Query Currency records with the G3 filter surface (server-side JSON filter). */
6385
+ query(params) {
6386
+ return this.queryItems(params);
6387
+ }
6388
+ /** Get every Currency record (the MCP-preferred read; 1000-page guarded). */
6389
+ async queryAll(params) {
6390
+ return this.queryAllItems(params);
6391
+ }
6392
+ /** Count matching records (queryCount envelope unwrapped to a plain number). */
6393
+ async count(params) {
6394
+ return this.countGlobal(params);
6395
+ }
6396
+ /** Get one record by id (item envelope; item: null → NotFoundError). */
6397
+ async get(id) {
6398
+ return this.getGlobal(id);
6399
+ }
6400
+ /** Resolve a Currency from a numeric id (or, where the vendor indexes a primary text field,
6401
+ * from an exact match on name). A numeric id miss throws NOT_FOUND; a complete
6402
+ * non-match returns null; ambiguity throws RESOLUTION_AMBIGUOUS (candidate ids) and a
6403
+ * cap-tripped bounded client scan throws RESOLUTION_TRUNCATED (never a silent null).
6404
+ * The compact shape is the structural alias of the full record; `expand: true` is the
6405
+ * type-level escape hatch. */
6406
+ async resolve(identifier, opts = {}) {
6407
+ void opts;
6408
+ return this.resolveBase(identifier);
6409
+ }
6410
+ /** Search Currency records: bounded contains on name (no vendor free-text search exists);
6411
+ * limit defaults to 25, max 500. */
6412
+ async search(query, opts) {
6413
+ return this.searchBase(query, { limit: opts?.limit });
6414
+ }
6415
+ };
6416
+
6337
6417
  // src/resources/departments.ts
6338
6418
  var DepartmentsResource = class extends BaseResource {
6339
6419
  constructor(http, pageSize) {
@@ -7087,6 +7167,34 @@ var InvoicesResource = class extends BaseResource {
7087
7167
  }
7088
7168
  };
7089
7169
 
7170
+ // src/resources/invoice_templates.ts
7171
+ var InvoiceTemplatesResource = class extends BaseResource {
7172
+ constructor(http, pageSize) {
7173
+ super(http, {
7174
+ key: "invoice_templates",
7175
+ resourcePath: "/V1.0/InvoiceTemplates",
7176
+ deletable: false,
7177
+ udfCapable: false
7178
+ }, pageSize);
7179
+ }
7180
+ /** Query InvoiceTemplate records with the G3 filter surface (server-side JSON filter). */
7181
+ query(params) {
7182
+ return this.queryItems(params);
7183
+ }
7184
+ /** Get every InvoiceTemplate record (the MCP-preferred read; 1000-page guarded). */
7185
+ async queryAll(params) {
7186
+ return this.queryAllItems(params);
7187
+ }
7188
+ /** Count matching records (queryCount envelope unwrapped to a plain number). */
7189
+ async count(params) {
7190
+ return this.countGlobal(params);
7191
+ }
7192
+ /** Get one record by id (item envelope; item: null → NotFoundError). */
7193
+ async get(id) {
7194
+ return this.getGlobal(id);
7195
+ }
7196
+ };
7197
+
7090
7198
  // src/resources/modules.ts
7091
7199
  var ModulesResource = class {
7092
7200
  http;
@@ -7325,6 +7433,159 @@ var OpportunityCategoriesResource = class extends BaseResource {
7325
7433
  }
7326
7434
  };
7327
7435
 
7436
+ // src/resources/organizational_level1s.ts
7437
+ var OrganizationalLevel1sResource = class extends BaseResource {
7438
+ constructor(http, pageSize) {
7439
+ super(http, {
7440
+ key: "organizational_level1s",
7441
+ resourcePath: "/V1.0/OrganizationalLevel1s",
7442
+ deletable: false,
7443
+ udfCapable: false,
7444
+ collectionUpdate: true
7445
+ // D1: the spec's item path is GET-only — confirmed updates PUT the collection (id in the body)
7446
+ }, pageSize);
7447
+ }
7448
+ /** Query OrganizationalLevel1 records with the G3 filter surface (server-side JSON filter). */
7449
+ query(params) {
7450
+ return this.queryItems(params);
7451
+ }
7452
+ /** Get every OrganizationalLevel1 record (the MCP-preferred read; 1000-page guarded). */
7453
+ async queryAll(params) {
7454
+ return this.queryAllItems(params);
7455
+ }
7456
+ /** Count matching records (queryCount envelope unwrapped to a plain number). */
7457
+ async count(params) {
7458
+ return this.countGlobal(params);
7459
+ }
7460
+ /** Get one record by id (item envelope; item: null → NotFoundError). */
7461
+ async get(id) {
7462
+ return this.getGlobal(id);
7463
+ }
7464
+ /** Create a record (OperationResultModel → { id}). `dryRun: true` returns the
7465
+ * pinned envelope (section 19.3) and never issues the create. A 2xx that is not the
7466
+ * specced envelope runs the plan-pinned marker recovery (issue #13 — one bounded read;
7467
+ * `recoverIdFromMarker: false` restores the pre-recovery behaviour). */
7468
+ async create(data, opts = {}) {
7469
+ if (opts.dryRun === true) return this.runCreateDryRun(data);
7470
+ return this.createGlobal(data, opts);
7471
+ }
7472
+ /** Update a record (PUT on the COLLECTION — the vendored spec's item path is GET-only; the vendor
7473
+ * keys the record by the id in the body). The vendor validates the FULL model on this route (V2), so a
7474
+ * partial body is merged into the CURRENT record first: one fresh GET (which also serves the
7475
+ * stale-object guard's read) then the collection PUT of the merged model — an explicit null in the
7476
+ * caller body sends null; an omitted field keeps the current value. `raw: true` in the opts bag sends
7477
+ * the body as-is (full model or intentional partial — the compatibility escape hatch; no merge read).
7478
+ * `dryRun: true` returns the pinned envelope whose `data` is the merged body (the exact confirmed
7479
+ * wire) with the best-effort diff, from that same single read; a caller-supplied lastModifiedDate that
7480
+ * mismatches the vendor's current value throws STALE_OBJECT before the mutation. */
7481
+ async update(id, data, opts = {}) {
7482
+ if (opts.dryRun === true) return this.runUpdateDryRun(id, data, opts);
7483
+ return this.updateGlobal(id, data, opts);
7484
+ }
7485
+ };
7486
+
7487
+ // src/resources/organizational_level2s.ts
7488
+ var OrganizationalLevel2sResource = class extends BaseResource {
7489
+ constructor(http, pageSize) {
7490
+ super(http, {
7491
+ key: "organizational_level2s",
7492
+ resourcePath: "/V1.0/OrganizationalLevel2s",
7493
+ deletable: false,
7494
+ udfCapable: false,
7495
+ collectionUpdate: true
7496
+ // D1: the spec's item path is GET-only — confirmed updates PUT the collection (id in the body)
7497
+ }, pageSize);
7498
+ }
7499
+ /** Query OrganizationalLevel2 records with the G3 filter surface (server-side JSON filter). */
7500
+ query(params) {
7501
+ return this.queryItems(params);
7502
+ }
7503
+ /** Get every OrganizationalLevel2 record (the MCP-preferred read; 1000-page guarded). */
7504
+ async queryAll(params) {
7505
+ return this.queryAllItems(params);
7506
+ }
7507
+ /** Count matching records (queryCount envelope unwrapped to a plain number). */
7508
+ async count(params) {
7509
+ return this.countGlobal(params);
7510
+ }
7511
+ /** Get one record by id (item envelope; item: null → NotFoundError). */
7512
+ async get(id) {
7513
+ return this.getGlobal(id);
7514
+ }
7515
+ /** Create a record (OperationResultModel → { id}). `dryRun: true` returns the
7516
+ * pinned envelope (section 19.3) and never issues the create. A 2xx that is not the
7517
+ * specced envelope runs the plan-pinned marker recovery (issue #13 — one bounded read;
7518
+ * `recoverIdFromMarker: false` restores the pre-recovery behaviour). */
7519
+ async create(data, opts = {}) {
7520
+ if (opts.dryRun === true) return this.runCreateDryRun(data);
7521
+ return this.createGlobal(data, opts);
7522
+ }
7523
+ /** Update a record (PUT on the COLLECTION — the vendored spec's item path is GET-only; the vendor
7524
+ * keys the record by the id in the body). The vendor validates the FULL model on this route (V2), so a
7525
+ * partial body is merged into the CURRENT record first: one fresh GET (which also serves the
7526
+ * stale-object guard's read) then the collection PUT of the merged model — an explicit null in the
7527
+ * caller body sends null; an omitted field keeps the current value. `raw: true` in the opts bag sends
7528
+ * the body as-is (full model or intentional partial — the compatibility escape hatch; no merge read).
7529
+ * `dryRun: true` returns the pinned envelope whose `data` is the merged body (the exact confirmed
7530
+ * wire) with the best-effort diff, from that same single read; a caller-supplied lastModifiedDate that
7531
+ * mismatches the vendor's current value throws STALE_OBJECT before the mutation. */
7532
+ async update(id, data, opts = {}) {
7533
+ if (opts.dryRun === true) return this.runUpdateDryRun(id, data, opts);
7534
+ return this.updateGlobal(id, data, opts);
7535
+ }
7536
+ };
7537
+
7538
+ // src/resources/organizational_level_associations.ts
7539
+ var OrganizationalLevelAssociationsResource = class extends BaseResource {
7540
+ constructor(http, pageSize) {
7541
+ super(http, {
7542
+ key: "organizational_level_associations",
7543
+ resourcePath: "/V1.0/OrganizationalLevelAssociations",
7544
+ deletable: false,
7545
+ udfCapable: false,
7546
+ collectionUpdate: true
7547
+ // D1: the spec's item path is GET-only — confirmed updates PUT the collection (id in the body)
7548
+ }, pageSize);
7549
+ }
7550
+ /** Query OrganizationalLevelAssociation records with the G3 filter surface (server-side JSON filter). */
7551
+ query(params) {
7552
+ return this.queryItems(params);
7553
+ }
7554
+ /** Get every OrganizationalLevelAssociation record (the MCP-preferred read; 1000-page guarded). */
7555
+ async queryAll(params) {
7556
+ return this.queryAllItems(params);
7557
+ }
7558
+ /** Count matching records (queryCount envelope unwrapped to a plain number). */
7559
+ async count(params) {
7560
+ return this.countGlobal(params);
7561
+ }
7562
+ /** Get one record by id (item envelope; item: null → NotFoundError). */
7563
+ async get(id) {
7564
+ return this.getGlobal(id);
7565
+ }
7566
+ /** Create a record (OperationResultModel → { id}). `dryRun: true` returns the
7567
+ * pinned envelope (section 19.3) and never issues the create. A 2xx that is not the
7568
+ * specced envelope runs the plan-pinned marker recovery (issue #13 — one bounded read;
7569
+ * `recoverIdFromMarker: false` restores the pre-recovery behaviour). */
7570
+ async create(data, opts = {}) {
7571
+ if (opts.dryRun === true) return this.runCreateDryRun(data);
7572
+ return this.createGlobal(data, opts);
7573
+ }
7574
+ /** Update a record (PUT on the COLLECTION — the vendored spec's item path is GET-only; the vendor
7575
+ * keys the record by the id in the body). The vendor validates the FULL model on this route (V2), so a
7576
+ * partial body is merged into the CURRENT record first: one fresh GET (which also serves the
7577
+ * stale-object guard's read) then the collection PUT of the merged model — an explicit null in the
7578
+ * caller body sends null; an omitted field keeps the current value. `raw: true` in the opts bag sends
7579
+ * the body as-is (full model or intentional partial — the compatibility escape hatch; no merge read).
7580
+ * `dryRun: true` returns the pinned envelope whose `data` is the merged body (the exact confirmed
7581
+ * wire) with the best-effort diff, from that same single read; a caller-supplied lastModifiedDate that
7582
+ * mismatches the vendor's current value throws STALE_OBJECT before the mutation. */
7583
+ async update(id, data, opts = {}) {
7584
+ if (opts.dryRun === true) return this.runUpdateDryRun(id, data, opts);
7585
+ return this.updateGlobal(id, data, opts);
7586
+ }
7587
+ };
7588
+
7328
7589
  // src/resources/phases.ts
7329
7590
  var PhasesResource = class extends BaseResource {
7330
7591
  constructor(http, pageSize) {
@@ -8763,6 +9024,49 @@ var RolesResource = class extends BaseResource {
8763
9024
  }
8764
9025
  };
8765
9026
 
9027
+ // src/resources/sales_orders.ts
9028
+ var SalesOrdersResource = class extends BaseResource {
9029
+ constructor(http, pageSize) {
9030
+ super(http, {
9031
+ key: "sales_orders",
9032
+ resourcePath: "/V1.0/SalesOrders",
9033
+ deletable: false,
9034
+ udfCapable: true,
9035
+ collectionUpdate: true
9036
+ // D1: the spec's item path is GET-only — confirmed updates PUT the collection (id in the body)
9037
+ }, pageSize);
9038
+ }
9039
+ /** Query SalesOrder records with the G3 filter surface (server-side JSON filter). */
9040
+ query(params) {
9041
+ return this.queryItems(params);
9042
+ }
9043
+ /** Get every SalesOrder record (the MCP-preferred read; 1000-page guarded). */
9044
+ async queryAll(params) {
9045
+ return this.queryAllItems(params);
9046
+ }
9047
+ /** Count matching records (queryCount envelope unwrapped to a plain number). */
9048
+ async count(params) {
9049
+ return this.countGlobal(params);
9050
+ }
9051
+ /** Get one record by id (item envelope; item: null → NotFoundError). */
9052
+ async get(id) {
9053
+ return this.getGlobal(id);
9054
+ }
9055
+ /** Update a record (PUT on the COLLECTION — the vendored spec's item path is GET-only; the vendor
9056
+ * keys the record by the id in the body). The vendor validates the FULL model on this route (V2), so a
9057
+ * partial body is merged into the CURRENT record first: one fresh GET (which also serves the
9058
+ * stale-object guard's read) then the collection PUT of the merged model — an explicit null in the
9059
+ * caller body sends null; an omitted field keeps the current value. `raw: true` in the opts bag sends
9060
+ * the body as-is (full model or intentional partial — the compatibility escape hatch; no merge read).
9061
+ * `dryRun: true` returns the pinned envelope whose `data` is the merged body (the exact confirmed
9062
+ * wire) with the best-effort diff, from that same single read; a caller-supplied lastModifiedDate that
9063
+ * mismatches the vendor's current value throws STALE_OBJECT before the mutation. */
9064
+ async update(id, data, opts = {}) {
9065
+ if (opts.dryRun === true) return this.runUpdateDryRun(id, data, opts);
9066
+ return this.updateGlobal(id, data, opts);
9067
+ }
9068
+ };
9069
+
8766
9070
  // src/resources/service_calls.ts
8767
9071
  var ServiceCallsResource = class extends BaseResource {
8768
9072
  constructor(http, pageSize) {
@@ -9718,6 +10022,57 @@ var TasksResource = class extends BaseResource {
9718
10022
  }
9719
10023
  };
9720
10024
 
10025
+ // src/resources/tax_regions.ts
10026
+ var TaxRegionsResource = class extends BaseResource {
10027
+ constructor(http, pageSize) {
10028
+ super(http, {
10029
+ key: "tax_regions",
10030
+ resourcePath: "/V1.0/TaxRegions",
10031
+ deletable: false,
10032
+ udfCapable: false,
10033
+ collectionUpdate: true
10034
+ // D1: the spec's item path is GET-only — confirmed updates PUT the collection (id in the body)
10035
+ }, pageSize);
10036
+ }
10037
+ /** Query TaxRegion records with the G3 filter surface (server-side JSON filter). */
10038
+ query(params) {
10039
+ return this.queryItems(params);
10040
+ }
10041
+ /** Get every TaxRegion record (the MCP-preferred read; 1000-page guarded). */
10042
+ async queryAll(params) {
10043
+ return this.queryAllItems(params);
10044
+ }
10045
+ /** Count matching records (queryCount envelope unwrapped to a plain number). */
10046
+ async count(params) {
10047
+ return this.countGlobal(params);
10048
+ }
10049
+ /** Get one record by id (item envelope; item: null → NotFoundError). */
10050
+ async get(id) {
10051
+ return this.getGlobal(id);
10052
+ }
10053
+ /** Create a record (OperationResultModel → { id}). `dryRun: true` returns the
10054
+ * pinned envelope (section 19.3) and never issues the create. A 2xx that is not the
10055
+ * specced envelope runs the plan-pinned marker recovery (issue #13 — one bounded read;
10056
+ * `recoverIdFromMarker: false` restores the pre-recovery behaviour). */
10057
+ async create(data, opts = {}) {
10058
+ if (opts.dryRun === true) return this.runCreateDryRun(data);
10059
+ return this.createGlobal(data, opts);
10060
+ }
10061
+ /** Update a record (PUT on the COLLECTION — the vendored spec's item path is GET-only; the vendor
10062
+ * keys the record by the id in the body). The vendor validates the FULL model on this route (V2), so a
10063
+ * partial body is merged into the CURRENT record first: one fresh GET (which also serves the
10064
+ * stale-object guard's read) then the collection PUT of the merged model — an explicit null in the
10065
+ * caller body sends null; an omitted field keeps the current value. `raw: true` in the opts bag sends
10066
+ * the body as-is (full model or intentional partial — the compatibility escape hatch; no merge read).
10067
+ * `dryRun: true` returns the pinned envelope whose `data` is the merged body (the exact confirmed
10068
+ * wire) with the best-effort diff, from that same single read; a caller-supplied lastModifiedDate that
10069
+ * mismatches the vendor's current value throws STALE_OBJECT before the mutation. */
10070
+ async update(id, data, opts = {}) {
10071
+ if (opts.dryRun === true) return this.runUpdateDryRun(id, data, opts);
10072
+ return this.updateGlobal(id, data, opts);
10073
+ }
10074
+ };
10075
+
9721
10076
  // src/resources/threshold_information.ts
9722
10077
  var ThresholdInformationResource = class {
9723
10078
  http;
@@ -11939,12 +12294,12 @@ async function postedDateStatusQuery(_resource, mode, http, opts) {
11939
12294
  return items;
11940
12295
  }
11941
12296
  async function postedWithin(_resource, from, to, http, opts, opLabel = "time_entries.postedWithin") {
11942
- const OP6 = opLabel;
11943
- if (opts?.tz !== void 0) validateZone(opts.tz, OP6);
11944
- const fromB = customRangeDay(from, "from", void 0, OP6);
11945
- const toB = customRangeDay(to, "to", void 0, OP6);
12297
+ const OP7 = opLabel;
12298
+ if (opts?.tz !== void 0) validateZone(opts.tz, OP7);
12299
+ const fromB = customRangeDay(from, "from", void 0, OP7);
12300
+ const toB = customRangeDay(to, "to", void 0, OP7);
11946
12301
  if (fromB.ms > toB.ms) {
11947
- throw new AutotaskConfigError(`${OP6}: from (${iso2(fromB.ms)}) must not be after to (${iso2(toB.ms)})`, { operation: OP6 });
12302
+ throw new AutotaskConfigError(`${OP7}: from (${iso2(fromB.ms)}) must not be after to (${iso2(toB.ms)})`, { operation: OP7 });
11948
12303
  }
11949
12304
  const windowToMs = toB.ms + DAY_MS2 - 1;
11950
12305
  const filter = [
@@ -11955,7 +12310,7 @@ async function postedWithin(_resource, from, to, http, opts, opLabel = "time_ent
11955
12310
  else if (opts?.posted === false) filter.push({ field: "postedDate", op: "notExist" });
11956
12311
  if (opts?.ticketID !== void 0) filter.push({ field: "ticketID", op: "eq", value: opts.ticketID });
11957
12312
  if (opts?.resourceID !== void 0) filter.push({ field: "resourceID", op: "eq", value: opts.resourceID });
11958
- const { items, hasMore } = await queryTimeEntries(_resource, filter, clampWindowLimit(opts?.limit), OP6, http);
12313
+ const { items, hasMore } = await queryTimeEntries(_resource, filter, clampWindowLimit(opts?.limit), OP7, http);
11959
12314
  let postedCount = 0;
11960
12315
  for (const item of items) {
11961
12316
  const postedDate = item.postedDate;
@@ -12456,29 +12811,116 @@ function moveToTicket2(_resource, sourceId, toTicketId, opts, http) {
12456
12811
  return runMove(http, SPEC2, sourceId, toTicketId, opts);
12457
12812
  }
12458
12813
 
12814
+ // src/resources/special/time_entries/approve.ts
12815
+ var OP5 = "time_entries.approve";
12816
+ var APPROVAL_LEVELS_PATH = "/V1.0/BillingItemApprovalLevels";
12817
+ function toIso(value) {
12818
+ if (value instanceof Date) {
12819
+ if (Number.isNaN(value.getTime())) throw new AutotaskConfigError("time_entries.approve: approvalDateTime is an invalid Date");
12820
+ return value.toISOString();
12821
+ }
12822
+ const parsed = new Date(value);
12823
+ if (Number.isNaN(parsed.getTime())) throw new AutotaskConfigError(`time_entries.approve: approvalDateTime "${value}" is not a parseable date`);
12824
+ return parsed.toISOString();
12825
+ }
12826
+ function toNumber(value) {
12827
+ return typeof value === "number" ? value : Number(value);
12828
+ }
12829
+ function sameInstant(a, b) {
12830
+ if (typeof a !== "string" || a === "") return false;
12831
+ const left = new Date(a).getTime();
12832
+ const right = new Date(b).getTime();
12833
+ return !Number.isNaN(left) && left === right;
12834
+ }
12835
+ async function approve(resource, id, opts = {}, http) {
12836
+ const numericId = toNumber(parseIdentifier(id, "id"));
12837
+ if (opts.approvalLevel !== void 0 && (!Number.isInteger(opts.approvalLevel) || opts.approvalLevel < 1)) {
12838
+ throw new AutotaskConfigError(`time_entries.approve: approvalLevel must be a positive integer (got ${String(opts.approvalLevel)})`);
12839
+ }
12840
+ const approvalLevel = opts.approvalLevel ?? 1;
12841
+ const approvalDateTime = toIso(opts.approvalDateTime ?? /* @__PURE__ */ new Date());
12842
+ const entry = await resource.get(numericId);
12843
+ const approvalResourceID = opts.approvalResourceID === void 0 ? entry.resourceID : toNumber(parseIdentifier(opts.approvalResourceID, "approvalResourceID"));
12844
+ if (approvalResourceID === void 0) {
12845
+ throw new AutotaskConfigError(
12846
+ `time_entries.approve: time entry ${numericId} carries no resourceID and the caller supplied no approvalResourceID \u2014 the vendor requires an approving resource`
12847
+ );
12848
+ }
12849
+ const body = { timeEntryID: numericId, approvalLevel, approvalResourceID, approvalDateTime };
12850
+ if (opts.dryRun === true) {
12851
+ return buildDryRunResult(
12852
+ {
12853
+ operation: OP5,
12854
+ method: "POST",
12855
+ path: APPROVAL_LEVELS_PATH,
12856
+ ids: [numericId],
12857
+ checks: [
12858
+ { name: "input-validation", ok: true },
12859
+ { name: "time-entry-exists", ok: true }
12860
+ ],
12861
+ impact: { affected: 1, scope: "single-record", reversible: false },
12862
+ warnings: [
12863
+ "two calls: POST the BillingItemApprovalLevels record, then PUT the time entry (billingApprovalDateTime + billingApprovalResourceID) \u2014 the vendor sets BillingApprovalLevelMostRecent from the create but not these two fields",
12864
+ "approval is not posting: the API exposes no post action on BillingItems, so the entry stays unposted until a vendor workflow posts it",
12865
+ `approvalResourceID ${approvalResourceID} is not existence-checked by the dry run`
12866
+ ],
12867
+ data: body
12868
+ },
12869
+ { redactPersonalData: http.redactPersonalData }
12870
+ );
12871
+ }
12872
+ const created = await http.request({
12873
+ method: "POST",
12874
+ path: APPROVAL_LEVELS_PATH,
12875
+ body,
12876
+ operation: OP5,
12877
+ maxRetries: opts.maxRetries
12878
+ });
12879
+ const levelId = toNumber(parseIdentifier(unwrapOperation(created, OP5).id, "billingItemApprovalLevelID"));
12880
+ await resource.update(
12881
+ numericId,
12882
+ { billingApprovalDateTime: approvalDateTime, billingApprovalResourceID: approvalResourceID },
12883
+ { maxRetries: opts.maxRetries, lastModifiedDate: opts.lastModifiedDate ?? entry.lastModifiedDateTime }
12884
+ );
12885
+ const fresh = await resource.get(numericId);
12886
+ const persisted = sameInstant(fresh.billingApprovalDateTime, approvalDateTime) && fresh.billingApprovalResourceID === approvalResourceID;
12887
+ return {
12888
+ timeEntryID: numericId,
12889
+ billingItemApprovalLevelID: levelId,
12890
+ approvalLevel,
12891
+ approvalResourceID,
12892
+ approvalDateTime,
12893
+ billingApprovalLevelMostRecent: fresh.billingApprovalLevelMostRecent ?? null,
12894
+ billingApprovalDateTime: fresh.billingApprovalDateTime ?? null,
12895
+ billingApprovalResourceID: fresh.billingApprovalResourceID ?? null,
12896
+ status: persisted ? "approved" : "approval_fields_not_persisted",
12897
+ persisted
12898
+ };
12899
+ }
12900
+
12459
12901
  // src/resources/special/time_entries/recentTickets.ts
12460
- var OP5 = "time_entries.recentTickets";
12902
+ var OP6 = "time_entries.recentTickets";
12461
12903
  var DAY_MS3 = 864e5;
12462
12904
  var TICKET_CHUNK = 100;
12463
12905
  var TICKET_FIELDS2 = ["id", "ticketNumber", "title", "status", "assignedResourceID", "companyID"];
12464
12906
  function positiveId(value, name) {
12465
12907
  const n = typeof value === "string" && /^\d+$/.test(value.trim()) ? Number(value) : value;
12466
12908
  if (typeof n !== "number" || !Number.isSafeInteger(n) || n < 1) {
12467
- throw new AutotaskConfigError(`${OP5}: ${name} must be a positive integer id (got ${String(value)})`, { operation: OP5 });
12909
+ throw new AutotaskConfigError(`${OP6}: ${name} must be a positive integer id (got ${String(value)})`, { operation: OP6 });
12468
12910
  }
12469
12911
  return n;
12470
12912
  }
12471
12913
  async function recentTickets(_resource, from, to, http, opts) {
12472
12914
  if (opts === void 0 || opts === null || typeof opts !== "object") {
12473
- throw new AutotaskConfigError(`${OP5}: opts { resourceID, companyID?, tz?, limit? } is required`, { operation: OP5 });
12915
+ throw new AutotaskConfigError(`${OP6}: opts { resourceID, companyID?, tz?, limit? } is required`, { operation: OP6 });
12474
12916
  }
12475
12917
  const resourceID = positiveId(opts.resourceID, "resourceID");
12476
12918
  const companyID = opts.companyID === void 0 ? void 0 : positiveId(opts.companyID, "companyID");
12477
- if (opts.tz !== void 0) validateZone(opts.tz, OP5);
12478
- const fromB = customRangeDay(from, "from", void 0, OP5);
12479
- const toB = customRangeDay(to, "to", void 0, OP5);
12919
+ if (opts.tz !== void 0) validateZone(opts.tz, OP6);
12920
+ const fromB = customRangeDay(from, "from", void 0, OP6);
12921
+ const toB = customRangeDay(to, "to", void 0, OP6);
12480
12922
  if (fromB.ms > toB.ms) {
12481
- throw new AutotaskConfigError(`${OP5}: from (${isoUtc(fromB.ms)}) must not be after to (${isoUtc(toB.ms)})`, { operation: OP5 });
12923
+ throw new AutotaskConfigError(`${OP6}: from (${isoUtc(fromB.ms)}) must not be after to (${isoUtc(toB.ms)})`, { operation: OP6 });
12482
12924
  }
12483
12925
  const windowToMs = toB.ms + DAY_MS3 - 1;
12484
12926
  const { items: entries, hasMore } = await queryTimeEntries(
@@ -12489,7 +12931,7 @@ async function recentTickets(_resource, from, to, http, opts) {
12489
12931
  { field: "resourceID", op: "eq", value: resourceID }
12490
12932
  ],
12491
12933
  clampWindowLimit(opts.limit),
12492
- OP5,
12934
+ OP6,
12493
12935
  http
12494
12936
  );
12495
12937
  const groups = /* @__PURE__ */ new Map();
@@ -12515,9 +12957,9 @@ async function recentTickets(_resource, from, to, http, opts) {
12515
12957
  idempotent: true,
12516
12958
  path: "/V1.0/Tickets/query",
12517
12959
  body: { MaxRecords: TICKET_CHUNK, filter, IncludeFields: TICKET_FIELDS2 },
12518
- operation: OP5
12960
+ operation: OP6
12519
12961
  });
12520
- for (const t of unwrapItems(res, OP5).items) if (typeof t.id === "number") tickets.set(t.id, t);
12962
+ for (const t of unwrapItems(res, OP6).items) if (typeof t.id === "number") tickets.set(t.id, t);
12521
12963
  }
12522
12964
  const items = [];
12523
12965
  const unresolvedTicketIDs = [];
@@ -12621,6 +13063,10 @@ var TimeEntriesResource = class extends BaseResource {
12621
13063
  return this.resolveBase(identifier);
12622
13064
  }
12623
13065
  /** Node-parity special op (hand-written in src/resources/special/time_entries.ts). */
13066
+ approve(id, opts = {}) {
13067
+ return approve(this, id, opts, this.http);
13068
+ }
13069
+ /** Node-parity special op (hand-written in src/resources/special/time_entries.ts). */
12624
13070
  createForResource(resourceID, params, opts = {}) {
12625
13071
  return createForResource(this, resourceID, params, opts, this.http);
12626
13072
  }
@@ -12761,7 +13207,7 @@ var TimeEntryAttachmentsResource = class extends BaseResource {
12761
13207
  };
12762
13208
 
12763
13209
  // src/resources/special/time_off_requests.ts
12764
- async function approve(_resource, id, opts = {}, http) {
13210
+ async function approve2(_resource, id, opts = {}, http) {
12765
13211
  const numericId = parseIdentifier(id, "id");
12766
13212
  if (opts.dryRun === true) {
12767
13213
  return buildDryRunResult({
@@ -12849,7 +13295,7 @@ var TimeOffRequestsResource = class extends BaseResource {
12849
13295
  }
12850
13296
  /** Node-parity special op (hand-written in src/resources/special/time_off_requests.ts). */
12851
13297
  approve(id, opts = {}) {
12852
- return approve(this, id, opts, this.http);
13298
+ return approve2(this, id, opts, this.http);
12853
13299
  }
12854
13300
  /** Node-parity special op (hand-written in src/resources/special/time_off_requests.ts). */
12855
13301
  reject(id, reason, opts = {}) {
@@ -12921,6 +13367,7 @@ export {
12921
13367
  AppointmentsResource,
12922
13368
  AuthenticateResource,
12923
13369
  BillingCodesResource,
13370
+ BillingItemApprovalLevelsResource,
12924
13371
  BillingItemsResource,
12925
13372
  ChangeRequestLinksResource,
12926
13373
  ChecklistLibrariesResource,
@@ -12969,6 +13416,7 @@ export {
12969
13416
  ContractsResource,
12970
13417
  ContractTicketPurchasesResource,
12971
13418
  CountriesResource,
13419
+ CurrenciesResource,
12972
13420
  DepartmentsResource,
12973
13421
  DomainRegistrarsResource,
12974
13422
  EntityInformationResource,
@@ -12979,11 +13427,15 @@ export {
12979
13427
  HolidaysResource,
12980
13428
  InventoryProductsResource,
12981
13429
  InvoicesResource,
13430
+ InvoiceTemplatesResource,
12982
13431
  ModulesResource,
12983
13432
  NotificationHistoryResource,
12984
13433
  OpportunitiesResource,
12985
13434
  OpportunityAttachmentsResource,
12986
13435
  OpportunityCategoriesResource,
13436
+ OrganizationalLevel1sResource,
13437
+ OrganizationalLevel2sResource,
13438
+ OrganizationalLevelAssociationsResource,
12987
13439
  PhasesResource,
12988
13440
  ProductsResource,
12989
13441
  ProductVendorsResource,
@@ -13006,6 +13458,7 @@ export {
13006
13458
  ResourceTimeOffApproversResource,
13007
13459
  ResourceTimeOffBalancesResource,
13008
13460
  RolesResource,
13461
+ SalesOrdersResource,
13009
13462
  ServiceCallsResource,
13010
13463
  ServiceCallTaskResourcesResource,
13011
13464
  ServiceCallTasksResource,
@@ -13023,6 +13476,7 @@ export {
13023
13476
  TagsResource,
13024
13477
  TaskSecondaryResourcesResource,
13025
13478
  TasksResource,
13479
+ TaxRegionsResource,
13026
13480
  ThresholdInformationResource,
13027
13481
  TicketAdditionalConfigurationItemsResource,
13028
13482
  TicketAdditionalContactsResource,