node-autotask 0.9.0 → 0.11.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.
- package/MCP_TOOL_CATALOG.json +3 -3
- package/MCP_TOOL_MANIFEST.md +5 -5
- package/N8N_MCP_MANIFEST.json +2 -2
- package/N8N_MCP_MANIFEST.md +3 -3
- package/capabilities.json +1354 -1263
- package/dist/capabilities.cjs +2 -3
- package/dist/capabilities.js +1 -2
- package/dist/{chunk-53MC2QRQ.cjs → chunk-25ZUKHS4.cjs} +135 -136
- package/dist/{chunk-BZPFDRAE.js → chunk-7L23FDQW.js} +1353 -1263
- package/dist/{chunk-UYJ5V262.js → chunk-CJONZQ7E.js} +32 -182
- package/dist/chunk-DMMMWO6A.js +0 -0
- package/dist/chunk-FLB2X6O5.cjs +1 -0
- package/dist/chunk-IDPB4N2Q.cjs +1 -0
- package/dist/{chunk-UDWV4VVD.js → chunk-LNRN45XS.js} +214 -20
- package/dist/{chunk-OYHKIYVR.cjs → chunk-QAX222R6.cjs} +422 -572
- package/dist/{chunk-QJU2N32V.js → chunk-SXHPUQMB.js} +2 -3
- package/dist/{chunk-LTKMTXUR.cjs → chunk-T5FLSJOD.cjs} +1353 -1263
- package/dist/chunk-UPQIUWOS.js +0 -0
- package/dist/{chunk-RWLPTU67.cjs → chunk-YKEX4SK7.cjs} +235 -41
- package/dist/{index-ZknpNhtc.d.ts → index-B_xToSpq.d.ts} +8 -8
- package/dist/{index-CfU1JDgS.d.cts → index-Dv_GSZaN.d.cts} +8 -8
- package/dist/{index-O2zzIMcQ.d.cts → index-cQ6CRexR.d.cts} +3 -1
- package/dist/{index-O2zzIMcQ.d.ts → index-cQ6CRexR.d.ts} +3 -1
- package/dist/index.cjs +21 -22
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +6 -7
- package/dist/operations/index.cjs +284 -131
- package/dist/operations/index.d.cts +28 -5
- package/dist/operations/index.d.ts +28 -5
- package/dist/operations/index.js +160 -7
- package/dist/pool.cjs +36 -12
- package/dist/pool.d.cts +2 -2
- package/dist/pool.d.ts +2 -2
- package/dist/pool.js +31 -7
- package/dist/resources/index.cjs +5 -6
- package/dist/resources/index.d.cts +2 -2
- package/dist/resources/index.d.ts +2 -2
- package/dist/resources/index.js +4 -5
- package/dist/types/index.cjs +1 -2
- package/dist/types/index.d.cts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.js +1 -2
- package/dist/untrusted.cjs +0 -1
- package/dist/untrusted.js +0 -1
- package/docs/API.md +12 -6
- package/package.json +1 -1
- package/dist/capabilities.cjs.map +0 -1
- package/dist/capabilities.js.map +0 -1
- package/dist/chunk-53MC2QRQ.cjs.map +0 -1
- package/dist/chunk-BZPFDRAE.js.map +0 -1
- package/dist/chunk-CXM35TEC.cjs +0 -1
- package/dist/chunk-CXM35TEC.cjs.map +0 -1
- package/dist/chunk-GIVD2CQ3.js +0 -1
- package/dist/chunk-GIVD2CQ3.js.map +0 -1
- package/dist/chunk-LTKMTXUR.cjs.map +0 -1
- package/dist/chunk-MHBMSBTA.js +0 -1
- package/dist/chunk-MHBMSBTA.js.map +0 -1
- package/dist/chunk-NZUFSSIZ.cjs +0 -1
- package/dist/chunk-NZUFSSIZ.cjs.map +0 -1
- package/dist/chunk-OYHKIYVR.cjs.map +0 -1
- package/dist/chunk-QJU2N32V.js.map +0 -1
- package/dist/chunk-RWLPTU67.cjs.map +0 -1
- package/dist/chunk-UDWV4VVD.js.map +0 -1
- package/dist/chunk-UYJ5V262.js.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/operations/index.cjs.map +0 -1
- package/dist/operations/index.js.map +0 -1
- package/dist/pool.cjs.map +0 -1
- package/dist/pool.js.map +0 -1
- package/dist/resources/index.cjs.map +0 -1
- package/dist/resources/index.js.map +0 -1
- package/dist/types/index.cjs.map +0 -1
- package/dist/types/index.js.map +0 -1
- package/dist/untrusted.cjs.map +0 -1
- package/dist/untrusted.js.map +0 -1
|
@@ -4,34 +4,36 @@ import {
|
|
|
4
4
|
BLIND_SURFACE_STAMPS,
|
|
5
5
|
BaseResource,
|
|
6
6
|
ConflictError,
|
|
7
|
-
FIELD_CATALOG_HONESTY_NOTE,
|
|
8
7
|
NotFoundError,
|
|
9
8
|
RELATIONSHIP_MAP,
|
|
10
9
|
ResolutionError,
|
|
11
10
|
StaleObjectError,
|
|
11
|
+
TICKET_LABEL_FIELDS,
|
|
12
12
|
UNTRUSTED_FIELDS_BY_RESOURCE,
|
|
13
|
+
addLabelSibling,
|
|
14
|
+
addNameSibling,
|
|
13
15
|
blindStampFor,
|
|
14
16
|
buildDryRunResult,
|
|
15
17
|
buildFilter,
|
|
16
18
|
clampPageSize,
|
|
19
|
+
createNamePlan,
|
|
17
20
|
cursorToPath,
|
|
18
21
|
decodeFileData,
|
|
19
|
-
expandResourceNames,
|
|
20
|
-
fieldCatalog,
|
|
21
22
|
formatVendorDetail,
|
|
22
23
|
isAutotaskError,
|
|
23
24
|
mergePartialBody,
|
|
24
25
|
parseIdentifier,
|
|
25
26
|
parseVendorErrors,
|
|
27
|
+
resolveCompositeNames,
|
|
26
28
|
resolveFieldsPreset,
|
|
27
29
|
truncateNoteChars,
|
|
28
30
|
unwrapItem,
|
|
29
31
|
unwrapItems,
|
|
30
32
|
unwrapOperation
|
|
31
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-LNRN45XS.js";
|
|
32
34
|
import {
|
|
33
35
|
CAPABILITIES
|
|
34
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-7L23FDQW.js";
|
|
35
37
|
|
|
36
38
|
// src/resources/appointments.ts
|
|
37
39
|
var AppointmentsResource = class extends BaseResource {
|
|
@@ -820,181 +822,6 @@ var ClassificationIconsResource = class extends BaseResource {
|
|
|
820
822
|
}
|
|
821
823
|
};
|
|
822
824
|
|
|
823
|
-
// src/operations/compositeNames.ts
|
|
824
|
-
var DEFAULT_MAX_NAME_READS = 20;
|
|
825
|
-
var TICKET_LABEL_FIELDS = ["status", "priority", "ticketType", "issueType", "subIssueType", "source", "queueID"];
|
|
826
|
-
function isVendorId(value) {
|
|
827
|
-
if (typeof value === "number") return Number.isSafeInteger(value) && value >= 0;
|
|
828
|
-
if (typeof value === "string") return /^\d+$/.test(value);
|
|
829
|
-
return false;
|
|
830
|
-
}
|
|
831
|
-
function createNamePlan(labelFields = []) {
|
|
832
|
-
const resourceIds = [];
|
|
833
|
-
const resSeen = /* @__PURE__ */ new Set();
|
|
834
|
-
const recordFks = [];
|
|
835
|
-
const fkSeen = /* @__PURE__ */ new Set();
|
|
836
|
-
return {
|
|
837
|
-
plan: () => ({ resourceIds, recordFks, labelFields }),
|
|
838
|
-
addResource: (value) => {
|
|
839
|
-
if (!isVendorId(value)) return;
|
|
840
|
-
const k = String(value);
|
|
841
|
-
if (!resSeen.has(k)) {
|
|
842
|
-
resSeen.add(k);
|
|
843
|
-
resourceIds.push(value);
|
|
844
|
-
}
|
|
845
|
-
},
|
|
846
|
-
addFk: (table, value) => {
|
|
847
|
-
if (!isVendorId(value)) return;
|
|
848
|
-
const k = `${table}:${String(value)}`;
|
|
849
|
-
if (!fkSeen.has(k)) {
|
|
850
|
-
fkSeen.add(k);
|
|
851
|
-
recordFks.push({ table, id: value });
|
|
852
|
-
}
|
|
853
|
-
}
|
|
854
|
-
};
|
|
855
|
-
}
|
|
856
|
-
function addNameSibling(row, field, resolve) {
|
|
857
|
-
const value = row[field];
|
|
858
|
-
if (value === void 0) return;
|
|
859
|
-
row[`${field}Name`] = isVendorId(value) ? resolve(value) : null;
|
|
860
|
-
}
|
|
861
|
-
function addLabelSibling(row, field, names) {
|
|
862
|
-
const value = row[field];
|
|
863
|
-
if (value === void 0) return;
|
|
864
|
-
row[`${field}Label`] = names.labelFor(field, value);
|
|
865
|
-
}
|
|
866
|
-
var FK_TABLE_PATH = {
|
|
867
|
-
role: "/V1.0/Roles",
|
|
868
|
-
billingCode: "/V1.0/BillingCodes",
|
|
869
|
-
contract: "/V1.0/Contracts"
|
|
870
|
-
};
|
|
871
|
-
var FK_NAME_FIELD = {
|
|
872
|
-
role: "name",
|
|
873
|
-
billingCode: "name",
|
|
874
|
-
contract: "contractName"
|
|
875
|
-
};
|
|
876
|
-
function fkName(record, table) {
|
|
877
|
-
const value = record[FK_NAME_FIELD[table]];
|
|
878
|
-
return typeof value === "string" && value.trim() !== "" ? value : null;
|
|
879
|
-
}
|
|
880
|
-
function faultRow(err) {
|
|
881
|
-
const e = err;
|
|
882
|
-
return e.httpStatus !== void 0 ? { code: e.code, message: e.message, httpStatus: e.httpStatus } : { code: e.code, message: e.message };
|
|
883
|
-
}
|
|
884
|
-
async function resolveCompositeNames(http, plan, opts = {}) {
|
|
885
|
-
if (opts.maxNameReads !== void 0 && (!Number.isInteger(opts.maxNameReads) || opts.maxNameReads < 1)) {
|
|
886
|
-
throw new AutotaskConfigError(`composite names: maxNameReads must be an integer >= 1 (got ${String(opts.maxNameReads)})`);
|
|
887
|
-
}
|
|
888
|
-
const budget = Math.min(DEFAULT_MAX_NAME_READS, opts.maxNameReads ?? DEFAULT_MAX_NAME_READS);
|
|
889
|
-
const client = http.client;
|
|
890
|
-
if (client === void 0) {
|
|
891
|
-
throw new AutotaskConfigError("composite names: the transport is not wired to an AutotaskClient (the composite must run through the client)");
|
|
892
|
-
}
|
|
893
|
-
const readCache = http.readCache;
|
|
894
|
-
const nameCache = http.resourceNameCache;
|
|
895
|
-
const section = { truncated: false, rows: {}, reasons: {} };
|
|
896
|
-
let remaining = budget;
|
|
897
|
-
const coldResource = [];
|
|
898
|
-
for (const id of plan.resourceIds) {
|
|
899
|
-
if (nameCache !== void 0 && nameCache.get(id) !== void 0) continue;
|
|
900
|
-
if (readCache !== void 0 && readCache.get(`/V1.0/Resources/${id}`) !== void 0) continue;
|
|
901
|
-
coldResource.push(id);
|
|
902
|
-
}
|
|
903
|
-
const withinBudget = coldResource.slice(0, remaining);
|
|
904
|
-
const overBudgetResource = coldResource.slice(remaining);
|
|
905
|
-
remaining -= withinBudget.length;
|
|
906
|
-
for (const id of overBudgetResource) {
|
|
907
|
-
section.rows[`resource:${id}`] = { name: null, blind: false, capped: true };
|
|
908
|
-
section.truncated = true;
|
|
909
|
-
}
|
|
910
|
-
const overSet = new Set(overBudgetResource.map((id) => String(id)));
|
|
911
|
-
const opIds = plan.resourceIds.filter((id) => !overSet.has(String(id)));
|
|
912
|
-
if (opIds.length > 0) {
|
|
913
|
-
let pass = opIds;
|
|
914
|
-
if (pass.length > 500) {
|
|
915
|
-
for (const id of pass.slice(500)) {
|
|
916
|
-
section.rows[`resource:${id}`] = { name: null, blind: false, capped: true };
|
|
917
|
-
section.truncated = true;
|
|
918
|
-
}
|
|
919
|
-
pass = pass.slice(0, 500);
|
|
920
|
-
}
|
|
921
|
-
const res = await expandResourceNames(client, pass);
|
|
922
|
-
for (const r of res.results) {
|
|
923
|
-
const row = { name: r.name, blind: r.blind, capped: false };
|
|
924
|
-
if (r.error !== void 0) row.error = faultRow(r.error);
|
|
925
|
-
section.rows[`resource:${r.id}`] = row;
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
const holders = {
|
|
929
|
-
role: client.roles,
|
|
930
|
-
billingCode: client.billingCodes,
|
|
931
|
-
contract: client.contracts
|
|
932
|
-
};
|
|
933
|
-
for (const fk of plan.recordFks) {
|
|
934
|
-
const key = `${fk.table}:${fk.id}`;
|
|
935
|
-
const cold = readCache === void 0 || readCache.get(`${FK_TABLE_PATH[fk.table]}/${fk.id}`) === void 0;
|
|
936
|
-
if (cold) {
|
|
937
|
-
if (remaining < 1) {
|
|
938
|
-
section.rows[key] = { name: null, blind: false, capped: true };
|
|
939
|
-
section.truncated = true;
|
|
940
|
-
continue;
|
|
941
|
-
}
|
|
942
|
-
remaining -= 1;
|
|
943
|
-
}
|
|
944
|
-
try {
|
|
945
|
-
const record = await holders[fk.table].get(fk.id);
|
|
946
|
-
section.rows[key] = { name: fkName(record, fk.table), blind: false, capped: false };
|
|
947
|
-
} catch (err) {
|
|
948
|
-
if (err instanceof NotFoundError) {
|
|
949
|
-
section.rows[key] = { name: null, blind: true, capped: false };
|
|
950
|
-
} else if (isAutotaskError(err) && err.code !== "ABORTED") {
|
|
951
|
-
section.rows[key] = { name: null, blind: false, capped: false, error: faultRow(err) };
|
|
952
|
-
} else {
|
|
953
|
-
throw err;
|
|
954
|
-
}
|
|
955
|
-
}
|
|
956
|
-
}
|
|
957
|
-
const picklists = {};
|
|
958
|
-
if (plan.labelFields.length > 0) {
|
|
959
|
-
let usable = true;
|
|
960
|
-
try {
|
|
961
|
-
const catalog = await fieldCatalog(client, { resources: ["tickets"], labels: true, fields: [...plan.labelFields] });
|
|
962
|
-
const row = catalog.rows.find((r) => r.resource === "tickets");
|
|
963
|
-
if (row === void 0 || row.error !== null || row.fields === void 0) {
|
|
964
|
-
usable = false;
|
|
965
|
-
} else {
|
|
966
|
-
for (const f of plan.labelFields) {
|
|
967
|
-
const frow = row.fields.find((x) => x.name === f);
|
|
968
|
-
picklists[f] = frow?.picklistValues;
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
|
-
} catch (err) {
|
|
972
|
-
if (isAutotaskError(err) && err.code !== "ABORTED") usable = false;
|
|
973
|
-
else throw err;
|
|
974
|
-
}
|
|
975
|
-
if (!usable) for (const f of plan.labelFields) section.reasons[f] = FIELD_CATALOG_HONESTY_NOTE;
|
|
976
|
-
}
|
|
977
|
-
return {
|
|
978
|
-
section,
|
|
979
|
-
resourceName: (id) => section.rows[`resource:${id}`]?.name ?? null,
|
|
980
|
-
recordName: (table, id) => section.rows[`${table}:${id}`]?.name ?? null,
|
|
981
|
-
labelFor: (field, value) => {
|
|
982
|
-
if (value === null || value === void 0) return null;
|
|
983
|
-
const values = picklists[field];
|
|
984
|
-
if (values === void 0) {
|
|
985
|
-
section.reasons[field] = FIELD_CATALOG_HONESTY_NOTE;
|
|
986
|
-
return null;
|
|
987
|
-
}
|
|
988
|
-
const hit = values.find((v) => String(v.value) === String(value));
|
|
989
|
-
if (hit === void 0) {
|
|
990
|
-
section.reasons[field] = FIELD_CATALOG_HONESTY_NOTE;
|
|
991
|
-
return null;
|
|
992
|
-
}
|
|
993
|
-
return typeof hit.label === "string" ? hit.label : null;
|
|
994
|
-
}
|
|
995
|
-
};
|
|
996
|
-
}
|
|
997
|
-
|
|
998
825
|
// src/resources/special/companies.ts
|
|
999
826
|
var DEFAULT_LIMIT2 = 25;
|
|
1000
827
|
var MAX_LIMIT2 = 500;
|
|
@@ -1092,6 +919,22 @@ async function familyChildPage(http, parentID) {
|
|
|
1092
919
|
const { items, pageDetails } = unwrapItems(res, "companies.search");
|
|
1093
920
|
return { rows: items, hasNext: pageDetails.nextPageUrl !== null };
|
|
1094
921
|
}
|
|
922
|
+
function assertSearchWithDetailOpts(opts) {
|
|
923
|
+
if (opts === void 0) return;
|
|
924
|
+
if (typeof opts !== "object" || opts === null || Array.isArray(opts)) {
|
|
925
|
+
throw new AutotaskConfigError("companies.searchWithDetail: opts must be an object { limit?: number }", {
|
|
926
|
+
operation: "companies.searchWithDetail"
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
for (const key of Object.keys(opts)) {
|
|
930
|
+
if (key !== "limit") {
|
|
931
|
+
throw new AutotaskConfigError(
|
|
932
|
+
`companies.searchWithDetail: unknown opts key "${key}" \u2014 the bag is closed: limit (includeFamily is a companies.search option)`,
|
|
933
|
+
{ operation: "companies.searchWithDetail" }
|
|
934
|
+
);
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
}
|
|
1095
938
|
async function searchWithFamily(_resource, query, opts = {}, http) {
|
|
1096
939
|
if (opts !== void 0 && (typeof opts !== "object" || opts === null || Array.isArray(opts))) {
|
|
1097
940
|
throw new AutotaskConfigError("companies.search: opts must be an object { limit?: number, includeFamily?: boolean }");
|
|
@@ -1640,7 +1483,8 @@ async function unbilledWork(resource, companyId, opts = {}, http) {
|
|
|
1640
1483
|
capped: false,
|
|
1641
1484
|
hasMore: false,
|
|
1642
1485
|
status: "skipped",
|
|
1643
|
-
|
|
1486
|
+
// joinNotes ride the skipped part too: an empty join set from a PARTIAL read (e.g. a full projects page) is not a true zero
|
|
1487
|
+
note: ["skipped: the company (set) has no tickets or tasks in the returned join set \u2014 no tasks/tickets to join against is NOT evidence of no time entries (zero wire)", ...joinNotes].join(" | ")
|
|
1644
1488
|
};
|
|
1645
1489
|
} else {
|
|
1646
1490
|
const timeConditions = taskCap.ids.length > 0 && ticketCap.ids.length > 0 ? [{ op: "or", items: [{ field: "taskID", op: "in", value: taskCap.ids }, { field: "ticketID", op: "in", value: ticketCap.ids }] }] : taskCap.ids.length > 0 ? [{ field: "taskID", op: "in", value: taskCap.ids }] : [{ field: "ticketID", op: "in", value: ticketCap.ids }];
|
|
@@ -1833,6 +1677,13 @@ var CompaniesResource = class extends BaseResource {
|
|
|
1833
1677
|
async search(query, opts) {
|
|
1834
1678
|
return searchWithFamily(this, query, opts, this.http);
|
|
1835
1679
|
}
|
|
1680
|
+
/** `search` with an empty result explained. Same closed opts discipline as `search`: only `limit` is
|
|
1681
|
+
* accepted here (an unknown key is refused pre-request, zero wire — never silently dropped); the
|
|
1682
|
+
* family block is a `search`-only option. */
|
|
1683
|
+
async searchWithDetail(query, opts = {}) {
|
|
1684
|
+
assertSearchWithDetailOpts(opts);
|
|
1685
|
+
return super.searchWithDetail(query, opts);
|
|
1686
|
+
}
|
|
1836
1687
|
/** Get the Company with its primary context records in one call (each part a single-record
|
|
1837
1688
|
* fetch; no sub-lists; absent/dangling references come back null). */
|
|
1838
1689
|
async getContext(id) {
|
|
@@ -11082,4 +10933,3 @@ export {
|
|
|
11082
10933
|
VersionResource,
|
|
11083
10934
|
ZoneInformationResource
|
|
11084
10935
|
};
|
|
11085
|
-
//# sourceMappingURL=chunk-UYJ5V262.js.map
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CAPABILITIES
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-7L23FDQW.js";
|
|
4
4
|
|
|
5
5
|
// src/auth.ts
|
|
6
6
|
var AUTH_HEADERS = {
|
|
@@ -349,14 +349,15 @@ var QueryTooLongError = class extends AutotaskError {
|
|
|
349
349
|
this.name = "QueryTooLongError";
|
|
350
350
|
}
|
|
351
351
|
};
|
|
352
|
-
var MISSING_REQUIRED_FIELD =
|
|
352
|
+
var MISSING_REQUIRED_FIELD = /Missing Required Field:\s*([A-Za-z_][A-Za-z0-9_]*)/;
|
|
353
|
+
var VALUE_DOES_NOT_EXIST_FOR_FIELD = /Value does not exist for the required field\s+([A-Za-z_][A-Za-z0-9_]*)/;
|
|
353
354
|
function parseVendorErrors(body) {
|
|
354
355
|
if (!isRecord(body) || !Array.isArray(body.errors)) return void 0;
|
|
355
356
|
const out = [];
|
|
356
357
|
for (const entry of body.errors) {
|
|
357
358
|
if (typeof entry === "string") {
|
|
358
359
|
const item2 = { message: entry };
|
|
359
|
-
const m = MISSING_REQUIRED_FIELD.exec(entry);
|
|
360
|
+
const m = MISSING_REQUIRED_FIELD.exec(entry) ?? VALUE_DOES_NOT_EXIST_FOR_FIELD.exec(entry);
|
|
360
361
|
if (m) item2.field = m[1];
|
|
361
362
|
out.push(item2);
|
|
362
363
|
continue;
|
|
@@ -372,7 +373,11 @@ function parseVendorErrors(body) {
|
|
|
372
373
|
}
|
|
373
374
|
return out;
|
|
374
375
|
}
|
|
375
|
-
var DETERMINISTIC_VENDOR_500_PHRASES = [
|
|
376
|
+
var DETERMINISTIC_VENDOR_500_PHRASES = [
|
|
377
|
+
/exceeds maximum length/i,
|
|
378
|
+
/Missing Required Field/i,
|
|
379
|
+
/Value does not exist for the required field/i
|
|
380
|
+
];
|
|
376
381
|
function isDeterministicVendor500(entries) {
|
|
377
382
|
if (entries === void 0) return false;
|
|
378
383
|
return entries.some(
|
|
@@ -2621,16 +2626,20 @@ var RELATIONSHIP_MAP = {
|
|
|
2621
2626
|
"liveProvenPrefix": [
|
|
2622
2627
|
"endDateTime",
|
|
2623
2628
|
"actionType",
|
|
2624
|
-
"startDateTime"
|
|
2629
|
+
"startDateTime",
|
|
2630
|
+
"assignedResourceID"
|
|
2625
2631
|
],
|
|
2626
|
-
"unproven":
|
|
2632
|
+
"unproven": false,
|
|
2627
2633
|
"blocker": {
|
|
2628
|
-
"kind": "
|
|
2629
|
-
"message":
|
|
2630
|
-
"remedy": "the
|
|
2634
|
+
"kind": "delete-absent",
|
|
2635
|
+
"message": 'create succeeded live (DG-1 verification, 2026-10-11, ww29, parent company 29683380, record id 30230658, marker name "node-autotask DG-1 create probe") once the four vendor-required body fields were present \u2014 actionType, assignedResourceID, startDateTime, endDateTime \u2014 plus the parent companyID in the path. The vendor reports a missing required field as HTTP 500 SERVER_ERROR naming the field; it is a deterministic rejection, not a transient fault (the SDK now answers retryable: false \u2014 add the field, do not retry). The vendor defines no DELETE endpoint for this resource (W-A1) \u2014 the record is residue; cleanup is UI-only.',
|
|
2636
|
+
"remedy": "provision via the API as proven: send actionType (picklist, e.g. 3 = Note: General), assignedResourceID (a resource id), startDateTime and endDateTime (UTC ISO) in the body and the company id as the parent; name and note are optional content fields. Clean up the residue record in the Autotask UI (the marker name is the lookup handle) \u2014 there is no API delete path."
|
|
2631
2637
|
},
|
|
2632
2638
|
"vendorEvidence": [
|
|
2633
|
-
|
|
2639
|
+
`{"error":true,"code":"SERVER_ERROR","category":"server","retryable":false,"httpStatus":500,"operation":"company_notes.create","message":"Field 'assignedResourceID': Value does not exist for the required field assignedResourceID. ; on record number [1].","suggestedAction":"Deterministic field rejection \u2014 fix the value, do not retry. Consult operations.fieldCatalog for the field catalog (types, required, maxLength)."}`,
|
|
2640
|
+
`{"error":true,"code":"SERVER_ERROR","category":"server","retryable":false,"httpStatus":500,"operation":"company_notes.create","message":"Field 'actionType': Missing Required Field: actionType. ; on record number [1].","suggestedAction":"Deterministic field rejection \u2014 fix the value, do not retry. Consult operations.fieldCatalog for the field catalog (types, required, maxLength)."}`,
|
|
2641
|
+
`{"error":true,"code":"SERVER_ERROR","category":"server","retryable":false,"httpStatus":500,"operation":"company_notes.create","message":"Field 'endDateTime': Missing Required Field: endDateTime. ; on record number [1].","suggestedAction":"Deterministic field rejection \u2014 fix the value, do not retry. Consult operations.fieldCatalog for the field catalog (types, required, maxLength)."}`,
|
|
2642
|
+
`{"error":true,"code":"SERVER_ERROR","category":"server","retryable":false,"httpStatus":500,"operation":"company_notes.create","message":"Field 'startDateTime': Missing Required Field: startDateTime. ; on record number [1].","suggestedAction":"Deterministic field rejection \u2014 fix the value, do not retry. Consult operations.fieldCatalog for the field catalog (types, required, maxLength)."}`
|
|
2634
2643
|
],
|
|
2635
2644
|
"deleteBoundary": {
|
|
2636
2645
|
"available": false,
|
|
@@ -11940,16 +11949,20 @@ var CREATE_GUIDANCE = {
|
|
|
11940
11949
|
"liveProvenPrefix": [
|
|
11941
11950
|
"endDateTime",
|
|
11942
11951
|
"actionType",
|
|
11943
|
-
"startDateTime"
|
|
11952
|
+
"startDateTime",
|
|
11953
|
+
"assignedResourceID"
|
|
11944
11954
|
],
|
|
11945
|
-
"unproven":
|
|
11955
|
+
"unproven": false,
|
|
11946
11956
|
"blocker": {
|
|
11947
|
-
"kind": "
|
|
11948
|
-
"message":
|
|
11949
|
-
"remedy": "the
|
|
11957
|
+
"kind": "delete-absent",
|
|
11958
|
+
"message": 'create succeeded live (DG-1 verification, 2026-10-11, ww29, parent company 29683380, record id 30230658, marker name "node-autotask DG-1 create probe") once the four vendor-required body fields were present \u2014 actionType, assignedResourceID, startDateTime, endDateTime \u2014 plus the parent companyID in the path. The vendor reports a missing required field as HTTP 500 SERVER_ERROR naming the field; it is a deterministic rejection, not a transient fault (the SDK now answers retryable: false \u2014 add the field, do not retry). The vendor defines no DELETE endpoint for this resource (W-A1) \u2014 the record is residue; cleanup is UI-only.',
|
|
11959
|
+
"remedy": "provision via the API as proven: send actionType (picklist, e.g. 3 = Note: General), assignedResourceID (a resource id), startDateTime and endDateTime (UTC ISO) in the body and the company id as the parent; name and note are optional content fields. Clean up the residue record in the Autotask UI (the marker name is the lookup handle) \u2014 there is no API delete path."
|
|
11950
11960
|
},
|
|
11951
11961
|
"vendorEvidence": [
|
|
11952
|
-
|
|
11962
|
+
`{"error":true,"code":"SERVER_ERROR","category":"server","retryable":false,"httpStatus":500,"operation":"company_notes.create","message":"Field 'assignedResourceID': Value does not exist for the required field assignedResourceID. ; on record number [1].","suggestedAction":"Deterministic field rejection \u2014 fix the value, do not retry. Consult operations.fieldCatalog for the field catalog (types, required, maxLength)."}`,
|
|
11963
|
+
`{"error":true,"code":"SERVER_ERROR","category":"server","retryable":false,"httpStatus":500,"operation":"company_notes.create","message":"Field 'actionType': Missing Required Field: actionType. ; on record number [1].","suggestedAction":"Deterministic field rejection \u2014 fix the value, do not retry. Consult operations.fieldCatalog for the field catalog (types, required, maxLength)."}`,
|
|
11964
|
+
`{"error":true,"code":"SERVER_ERROR","category":"server","retryable":false,"httpStatus":500,"operation":"company_notes.create","message":"Field 'endDateTime': Missing Required Field: endDateTime. ; on record number [1].","suggestedAction":"Deterministic field rejection \u2014 fix the value, do not retry. Consult operations.fieldCatalog for the field catalog (types, required, maxLength)."}`,
|
|
11965
|
+
`{"error":true,"code":"SERVER_ERROR","category":"server","retryable":false,"httpStatus":500,"operation":"company_notes.create","message":"Field 'startDateTime': Missing Required Field: startDateTime. ; on record number [1].","suggestedAction":"Deterministic field rejection \u2014 fix the value, do not retry. Consult operations.fieldCatalog for the field catalog (types, required, maxLength)."}`
|
|
11953
11966
|
],
|
|
11954
11967
|
"deleteBoundary": {
|
|
11955
11968
|
"available": false,
|
|
@@ -13936,9 +13949,9 @@ var CREATE_GUIDANCE = {
|
|
|
13936
13949
|
"picklist-unexposed": 5,
|
|
13937
13950
|
"undocumented-ladder": 1,
|
|
13938
13951
|
"resource-role-pair": 2,
|
|
13939
|
-
"delete-absent":
|
|
13952
|
+
"delete-absent": 8,
|
|
13940
13953
|
"non-mutable": 0,
|
|
13941
|
-
"unknown":
|
|
13954
|
+
"unknown": 12
|
|
13942
13955
|
}
|
|
13943
13956
|
}
|
|
13944
13957
|
};
|
|
@@ -16126,6 +16139,182 @@ async function fieldCatalog(client, opts) {
|
|
|
16126
16139
|
};
|
|
16127
16140
|
}
|
|
16128
16141
|
|
|
16142
|
+
// src/operations/compositeNames.ts
|
|
16143
|
+
var PICKLIST_VALUE_NOT_SERVED_NOTE = "The picklist is served to this API user, but this record's value is not in it (an inactive or unexposed value) \u2014 the label cannot be resolved and is null; refreshing the field catalog will not surface it. (A picklist the vendor does not expose at all is reported with the field-catalog honesty note instead.)";
|
|
16144
|
+
var DEFAULT_MAX_NAME_READS = 20;
|
|
16145
|
+
var TICKET_LABEL_FIELDS = ["status", "priority", "ticketType", "issueType", "subIssueType", "source", "queueID"];
|
|
16146
|
+
function isVendorId(value) {
|
|
16147
|
+
if (typeof value === "number") return Number.isSafeInteger(value) && value >= 0;
|
|
16148
|
+
if (typeof value === "string") return /^\d+$/.test(value);
|
|
16149
|
+
return false;
|
|
16150
|
+
}
|
|
16151
|
+
function createNamePlan(labelFields = []) {
|
|
16152
|
+
const resourceIds = [];
|
|
16153
|
+
const resSeen = /* @__PURE__ */ new Set();
|
|
16154
|
+
const recordFks = [];
|
|
16155
|
+
const fkSeen = /* @__PURE__ */ new Set();
|
|
16156
|
+
return {
|
|
16157
|
+
plan: () => ({ resourceIds, recordFks, labelFields }),
|
|
16158
|
+
addResource: (value) => {
|
|
16159
|
+
if (!isVendorId(value)) return;
|
|
16160
|
+
const k = String(value);
|
|
16161
|
+
if (!resSeen.has(k)) {
|
|
16162
|
+
resSeen.add(k);
|
|
16163
|
+
resourceIds.push(value);
|
|
16164
|
+
}
|
|
16165
|
+
},
|
|
16166
|
+
addFk: (table, value) => {
|
|
16167
|
+
if (!isVendorId(value)) return;
|
|
16168
|
+
const k = `${table}:${String(value)}`;
|
|
16169
|
+
if (!fkSeen.has(k)) {
|
|
16170
|
+
fkSeen.add(k);
|
|
16171
|
+
recordFks.push({ table, id: value });
|
|
16172
|
+
}
|
|
16173
|
+
}
|
|
16174
|
+
};
|
|
16175
|
+
}
|
|
16176
|
+
function addNameSibling(row, field, resolve) {
|
|
16177
|
+
const value = row[field];
|
|
16178
|
+
if (value === void 0) return;
|
|
16179
|
+
row[`${field}Name`] = isVendorId(value) ? resolve(value) : null;
|
|
16180
|
+
}
|
|
16181
|
+
function addLabelSibling(row, field, names) {
|
|
16182
|
+
const value = row[field];
|
|
16183
|
+
if (value === void 0) return;
|
|
16184
|
+
row[`${field}Label`] = names.labelFor(field, value);
|
|
16185
|
+
}
|
|
16186
|
+
var FK_TABLE_PATH = {
|
|
16187
|
+
role: "/V1.0/Roles",
|
|
16188
|
+
billingCode: "/V1.0/BillingCodes",
|
|
16189
|
+
contract: "/V1.0/Contracts"
|
|
16190
|
+
};
|
|
16191
|
+
var FK_NAME_FIELD = {
|
|
16192
|
+
role: "name",
|
|
16193
|
+
billingCode: "name",
|
|
16194
|
+
contract: "contractName"
|
|
16195
|
+
};
|
|
16196
|
+
function fkName(record, table) {
|
|
16197
|
+
const value = record[FK_NAME_FIELD[table]];
|
|
16198
|
+
return typeof value === "string" && value.trim() !== "" ? value : null;
|
|
16199
|
+
}
|
|
16200
|
+
function faultRow(err) {
|
|
16201
|
+
const e = err;
|
|
16202
|
+
return e.httpStatus !== void 0 ? { code: e.code, message: e.message, httpStatus: e.httpStatus } : { code: e.code, message: e.message };
|
|
16203
|
+
}
|
|
16204
|
+
async function resolveCompositeNames(http, plan, opts = {}) {
|
|
16205
|
+
if (opts.maxNameReads !== void 0 && (!Number.isInteger(opts.maxNameReads) || opts.maxNameReads < 1)) {
|
|
16206
|
+
throw new AutotaskConfigError(`composite names: maxNameReads must be an integer >= 1 (got ${String(opts.maxNameReads)})`);
|
|
16207
|
+
}
|
|
16208
|
+
const budget = Math.min(DEFAULT_MAX_NAME_READS, opts.maxNameReads ?? DEFAULT_MAX_NAME_READS);
|
|
16209
|
+
const client = http.client;
|
|
16210
|
+
if (client === void 0) {
|
|
16211
|
+
throw new AutotaskConfigError("composite names: the transport is not wired to an AutotaskClient (the composite must run through the client)");
|
|
16212
|
+
}
|
|
16213
|
+
const readCache = http.readCache;
|
|
16214
|
+
const nameCache = http.resourceNameCache;
|
|
16215
|
+
const section = { truncated: false, rows: {}, reasons: {} };
|
|
16216
|
+
let remaining = budget;
|
|
16217
|
+
const coldResource = [];
|
|
16218
|
+
for (const id of plan.resourceIds) {
|
|
16219
|
+
if (nameCache !== void 0 && nameCache.get(id) !== void 0) continue;
|
|
16220
|
+
if (readCache !== void 0 && readCache.get(`/V1.0/Resources/${id}`) !== void 0) continue;
|
|
16221
|
+
coldResource.push(id);
|
|
16222
|
+
}
|
|
16223
|
+
const withinBudget = coldResource.slice(0, remaining);
|
|
16224
|
+
const overBudgetResource = coldResource.slice(remaining);
|
|
16225
|
+
remaining -= withinBudget.length;
|
|
16226
|
+
for (const id of overBudgetResource) {
|
|
16227
|
+
section.rows[`resource:${id}`] = { name: null, blind: false, capped: true };
|
|
16228
|
+
section.truncated = true;
|
|
16229
|
+
}
|
|
16230
|
+
const overSet = new Set(overBudgetResource.map((id) => String(id)));
|
|
16231
|
+
const opIds = plan.resourceIds.filter((id) => !overSet.has(String(id)));
|
|
16232
|
+
if (opIds.length > 0) {
|
|
16233
|
+
let pass = opIds;
|
|
16234
|
+
if (pass.length > 500) {
|
|
16235
|
+
for (const id of pass.slice(500)) {
|
|
16236
|
+
section.rows[`resource:${id}`] = { name: null, blind: false, capped: true };
|
|
16237
|
+
section.truncated = true;
|
|
16238
|
+
}
|
|
16239
|
+
pass = pass.slice(0, 500);
|
|
16240
|
+
}
|
|
16241
|
+
const res = await expandResourceNames(client, pass);
|
|
16242
|
+
for (const r of res.results) {
|
|
16243
|
+
const row = { name: r.name, blind: r.blind, capped: false };
|
|
16244
|
+
if (r.error !== void 0) row.error = faultRow(r.error);
|
|
16245
|
+
section.rows[`resource:${r.id}`] = row;
|
|
16246
|
+
}
|
|
16247
|
+
}
|
|
16248
|
+
const holders = {
|
|
16249
|
+
role: client.roles,
|
|
16250
|
+
billingCode: client.billingCodes,
|
|
16251
|
+
contract: client.contracts
|
|
16252
|
+
};
|
|
16253
|
+
for (const fk of plan.recordFks) {
|
|
16254
|
+
const key = `${fk.table}:${fk.id}`;
|
|
16255
|
+
const cold = readCache === void 0 || readCache.get(`${FK_TABLE_PATH[fk.table]}/${fk.id}`) === void 0;
|
|
16256
|
+
if (cold) {
|
|
16257
|
+
if (remaining < 1) {
|
|
16258
|
+
section.rows[key] = { name: null, blind: false, capped: true };
|
|
16259
|
+
section.truncated = true;
|
|
16260
|
+
continue;
|
|
16261
|
+
}
|
|
16262
|
+
remaining -= 1;
|
|
16263
|
+
}
|
|
16264
|
+
try {
|
|
16265
|
+
const record = await holders[fk.table].get(fk.id);
|
|
16266
|
+
section.rows[key] = { name: fkName(record, fk.table), blind: false, capped: false };
|
|
16267
|
+
} catch (err) {
|
|
16268
|
+
if (err instanceof NotFoundError) {
|
|
16269
|
+
section.rows[key] = { name: null, blind: true, capped: false };
|
|
16270
|
+
} else if (isAutotaskError(err) && err.code !== "ABORTED") {
|
|
16271
|
+
section.rows[key] = { name: null, blind: false, capped: false, error: faultRow(err) };
|
|
16272
|
+
} else {
|
|
16273
|
+
throw err;
|
|
16274
|
+
}
|
|
16275
|
+
}
|
|
16276
|
+
}
|
|
16277
|
+
const picklists = {};
|
|
16278
|
+
if (plan.labelFields.length > 0) {
|
|
16279
|
+
let usable = true;
|
|
16280
|
+
try {
|
|
16281
|
+
const catalog = await fieldCatalog(client, { resources: ["tickets"], labels: true, fields: [...plan.labelFields] });
|
|
16282
|
+
const row = catalog.rows.find((r) => r.resource === "tickets");
|
|
16283
|
+
if (row === void 0 || row.error !== null || row.fields === void 0) {
|
|
16284
|
+
usable = false;
|
|
16285
|
+
} else {
|
|
16286
|
+
for (const f of plan.labelFields) {
|
|
16287
|
+
const frow = row.fields.find((x) => x.name === f);
|
|
16288
|
+
picklists[f] = frow?.picklistValues;
|
|
16289
|
+
}
|
|
16290
|
+
}
|
|
16291
|
+
} catch (err) {
|
|
16292
|
+
if (isAutotaskError(err) && err.code !== "ABORTED") usable = false;
|
|
16293
|
+
else throw err;
|
|
16294
|
+
}
|
|
16295
|
+
if (!usable) for (const f of plan.labelFields) section.reasons[f] = FIELD_CATALOG_HONESTY_NOTE;
|
|
16296
|
+
}
|
|
16297
|
+
return {
|
|
16298
|
+
section,
|
|
16299
|
+
resourceName: (id) => section.rows[`resource:${id}`]?.name ?? null,
|
|
16300
|
+
recordName: (table, id) => section.rows[`${table}:${id}`]?.name ?? null,
|
|
16301
|
+
labelFor: (field, value) => {
|
|
16302
|
+
if (value === null || value === void 0) return null;
|
|
16303
|
+
const values = picklists[field];
|
|
16304
|
+
if (values === void 0) {
|
|
16305
|
+
section.reasons[field] = FIELD_CATALOG_HONESTY_NOTE;
|
|
16306
|
+
return null;
|
|
16307
|
+
}
|
|
16308
|
+
const hit = values.find((v) => String(v.value) === String(value));
|
|
16309
|
+
if (hit === void 0) {
|
|
16310
|
+
section.reasons[field] = PICKLIST_VALUE_NOT_SERVED_NOTE;
|
|
16311
|
+
return null;
|
|
16312
|
+
}
|
|
16313
|
+
return typeof hit.label === "string" ? hit.label : null;
|
|
16314
|
+
}
|
|
16315
|
+
};
|
|
16316
|
+
}
|
|
16317
|
+
|
|
16129
16318
|
// src/resources/base.ts
|
|
16130
16319
|
var BOUNDED_QUERY_DEFAULT_LIMIT = 500;
|
|
16131
16320
|
var BOUNDED_QUERY_MAX_LIMIT = 2500;
|
|
@@ -18008,6 +18197,11 @@ export {
|
|
|
18008
18197
|
WORKFLOW_RESOURCES,
|
|
18009
18198
|
MAX_FIELD_CATALOG_WIRE,
|
|
18010
18199
|
FIELD_CATALOG_HONESTY_NOTE,
|
|
18011
|
-
fieldCatalog
|
|
18200
|
+
fieldCatalog,
|
|
18201
|
+
PICKLIST_VALUE_NOT_SERVED_NOTE,
|
|
18202
|
+
TICKET_LABEL_FIELDS,
|
|
18203
|
+
createNamePlan,
|
|
18204
|
+
addNameSibling,
|
|
18205
|
+
addLabelSibling,
|
|
18206
|
+
resolveCompositeNames
|
|
18012
18207
|
};
|
|
18013
|
-
//# sourceMappingURL=chunk-UDWV4VVD.js.map
|