node-autotask 0.8.3 → 0.10.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/ARCHITECTURE.md +13 -10
- package/MCP_TOOL_CATALOG.json +733 -251
- package/MCP_TOOL_MANIFEST.md +162 -133
- package/MCP_TOOL_OVERRIDES.json +2 -2
- package/N8N_MCP_MANIFEST.json +88 -25
- package/N8N_MCP_MANIFEST.md +26 -24
- package/README.md +12 -4
- package/capabilities.json +12503 -9316
- package/dist/capabilities.cjs +2 -3
- package/dist/capabilities.js +1 -2
- package/dist/{chunk-4WJCXIY2.js → chunk-3VB6N44U.js} +1141 -2977
- package/dist/{chunk-32AKZMY4.js → chunk-6KFP5HV3.js} +12502 -9316
- package/dist/chunk-DMMMWO6A.js +0 -0
- package/dist/chunk-FLB2X6O5.cjs +1 -0
- package/dist/{chunk-GYI4ZQID.js → chunk-HWC2WPX2.js} +4781 -89
- package/dist/chunk-IDPB4N2Q.cjs +1 -0
- package/dist/{chunk-F6YSQRZV.js → chunk-NVJ2PTN3.js} +7 -7
- package/dist/{chunk-5UGSQLLO.cjs → chunk-QUM74WLQ.cjs} +136 -136
- package/dist/{chunk-LAKEIYET.cjs → chunk-S7VMY5KN.cjs} +1468 -3304
- package/dist/chunk-UPQIUWOS.js +0 -0
- package/dist/{chunk-KNTUX3RR.cjs → chunk-WTVD2JZN.cjs} +12502 -9316
- package/dist/{chunk-V3XPLTIR.cjs → chunk-WTVLHMZA.cjs} +4784 -92
- package/dist/{index-B6JeThrY.d.ts → index-BOyh7S65.d.cts} +870 -79
- package/dist/{index-B0I2bGtx.d.cts → index-DGgMD8aq.d.ts} +870 -79
- package/dist/{index-DOCRp_83.d.cts → index-cQ6CRexR.d.cts} +158 -90
- package/dist/{index-DOCRp_83.d.ts → index-cQ6CRexR.d.ts} +158 -90
- package/dist/index.cjs +37 -22
- package/dist/index.d.cts +46 -5
- package/dist/index.d.ts +46 -5
- package/dist/index.js +48 -33
- package/dist/operations/index.cjs +480 -359
- package/dist/operations/index.d.cts +195 -16
- package/dist/operations/index.d.ts +195 -16
- package/dist/operations/index.js +370 -249
- package/dist/pool.cjs +36 -12
- package/dist/pool.d.cts +2 -3
- package/dist/pool.d.ts +2 -3
- package/dist/pool.js +33 -9
- 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 +693 -48
- package/docs/N8N-ADAPTER.md +4 -4
- package/examples/basic.ts +1 -1
- package/package.json +5 -3
- package/dist/capabilities.cjs.map +0 -1
- package/dist/capabilities.js.map +0 -1
- package/dist/chunk-32AKZMY4.js.map +0 -1
- package/dist/chunk-4WJCXIY2.js.map +0 -1
- package/dist/chunk-5UGSQLLO.cjs.map +0 -1
- package/dist/chunk-CXM35TEC.cjs +0 -1
- package/dist/chunk-CXM35TEC.cjs.map +0 -1
- package/dist/chunk-F6YSQRZV.js.map +0 -1
- package/dist/chunk-GIVD2CQ3.js +0 -1
- package/dist/chunk-GIVD2CQ3.js.map +0 -1
- package/dist/chunk-GYI4ZQID.js.map +0 -1
- package/dist/chunk-KNTUX3RR.cjs.map +0 -1
- package/dist/chunk-LAKEIYET.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-V3XPLTIR.cjs.map +0 -1
- package/dist/client-DHmr0Oyx.d.ts +0 -203
- package/dist/client-Q6NoqinP.d.cts +0 -203
- 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
package/dist/operations/index.js
CHANGED
|
@@ -2,36 +2,38 @@ import {
|
|
|
2
2
|
AutotaskConfigError,
|
|
3
3
|
AutotaskError,
|
|
4
4
|
BLIND_SURFACE_INVENTORY,
|
|
5
|
+
BOUNDED_QUERY_MAX_LIMIT,
|
|
5
6
|
CREATE_GUIDANCE,
|
|
6
7
|
ConfirmationRequiredError,
|
|
7
8
|
DELETE_BOUNDARY_NOTES,
|
|
8
9
|
DeleteBoundaryError,
|
|
10
|
+
EXPAND_RESOURCE_NAMES_MAX_IDS,
|
|
9
11
|
FIELD_CACHE_KINDS,
|
|
12
|
+
FIELD_CATALOG_HONESTY_NOTE,
|
|
10
13
|
MARKER_FIELDS,
|
|
14
|
+
MAX_FIELD_CATALOG_WIRE,
|
|
11
15
|
MarkerUnsafeIdError,
|
|
12
16
|
NotFoundError,
|
|
17
|
+
PICKLIST_VALUE_NOT_SERVED_NOTE,
|
|
13
18
|
REACHABILITY_PROBE_DEFAULTS,
|
|
14
19
|
RELATIONSHIP_MAP,
|
|
15
20
|
RELATIONSHIP_ZONE,
|
|
16
21
|
RecoveryTruncatedError,
|
|
22
|
+
WORKFLOW_RESOURCES,
|
|
23
|
+
buildFilter,
|
|
24
|
+
buildQueryRequest,
|
|
17
25
|
camelKey,
|
|
18
26
|
clampPageSize,
|
|
27
|
+
expandResourceNames,
|
|
28
|
+
fieldCatalog,
|
|
19
29
|
isAutotaskError,
|
|
20
30
|
isRecord,
|
|
21
|
-
parseIdentifier
|
|
22
|
-
|
|
31
|
+
parseIdentifier,
|
|
32
|
+
unwrapItems
|
|
33
|
+
} from "../chunk-HWC2WPX2.js";
|
|
23
34
|
import {
|
|
24
35
|
CAPABILITIES
|
|
25
|
-
} from "../chunk-
|
|
26
|
-
|
|
27
|
-
// src/operations/types.ts
|
|
28
|
-
var WORKFLOW_RESOURCES = [
|
|
29
|
-
"companies",
|
|
30
|
-
"tickets",
|
|
31
|
-
"contacts",
|
|
32
|
-
"configuration_items",
|
|
33
|
-
"projects"
|
|
34
|
-
];
|
|
36
|
+
} from "../chunk-6KFP5HV3.js";
|
|
35
37
|
|
|
36
38
|
// src/operations/searchAcrossResources.ts
|
|
37
39
|
var DEFAULT_LIMIT = 25;
|
|
@@ -259,23 +261,23 @@ var MODEL_FIELD_SETS = {
|
|
|
259
261
|
|
|
260
262
|
// src/operations/fetchMany.ts
|
|
261
263
|
var FETCH_MANY_MAX_ITEMS = 20;
|
|
262
|
-
function validateFetchManyItems(items, cap) {
|
|
264
|
+
function validateFetchManyItems(items, cap, opName = "fetchMany", capRef = `FETCH_MANY_MAX_ITEMS = ${FETCH_MANY_MAX_ITEMS}`, validation) {
|
|
263
265
|
if (!Array.isArray(items)) {
|
|
264
266
|
throw new AutotaskConfigError(
|
|
265
|
-
|
|
267
|
+
`${opName}: items must be the items ARRAY \u2014 one positional arg, [{ resource: string, id: number, fields?: string[] }] (got ${Array.isArray(items) ? "an array" : typeof items})`,
|
|
266
268
|
{
|
|
267
269
|
suggestedAction: 'Pass args = [[{ resource: "tickets", id: 123 }, { resource: "projects", id: 456 }]] \u2014 the items array is the single positional argument.'
|
|
268
270
|
}
|
|
269
271
|
);
|
|
270
272
|
}
|
|
271
273
|
if (items.length === 0) {
|
|
272
|
-
throw new AutotaskConfigError(
|
|
274
|
+
throw new AutotaskConfigError(`${opName}: items must not be empty (a zero-item batch is a shape error, not a no-op)`, {
|
|
273
275
|
suggestedAction: "Pass at least one { resource, id } item \u2014 or use the resource's query op for a filtered read."
|
|
274
276
|
});
|
|
275
277
|
}
|
|
276
278
|
if (items.length > cap) {
|
|
277
279
|
throw new AutotaskConfigError(
|
|
278
|
-
|
|
280
|
+
`${opName}: ${items.length} items over the ${cap}-item cap (${capRef}) \u2014 zero items were fetched (pre-request)`,
|
|
279
281
|
{
|
|
280
282
|
suggestedAction: `Split the batch into groups of <= ${cap} items \u2014 or, for more than ${cap} records / a filtered set, use the resource's bounded query op (<resource>.query).`
|
|
281
283
|
}
|
|
@@ -327,21 +329,24 @@ function validateFetchManyItems(items, cap) {
|
|
|
327
329
|
}
|
|
328
330
|
if (item.fields !== void 0) {
|
|
329
331
|
if (!Array.isArray(item.fields) || item.fields.some((f) => typeof f !== "string")) {
|
|
330
|
-
problems.push(`${at}.fields: must be an array of exact vendor field names (discover them via
|
|
332
|
+
problems.push(`${at}.fields: must be an array of exact vendor field names (discover them via operations.fieldCatalog)`);
|
|
331
333
|
continue;
|
|
332
334
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
335
|
+
if (validation?.fieldCheck !== false) {
|
|
336
|
+
const authoritative = validation?.fieldSetsByResource?.get(resourceKey) ?? fields;
|
|
337
|
+
for (const f of item.fields) {
|
|
338
|
+
if (!authoritative.includes(f)) {
|
|
339
|
+
problems.push(
|
|
340
|
+
`${at}.fields: "${f}" is not a field of ${resourceKey} \u2014 a hallucinated field is a shape error, not a silent projection-miss (exact vendor field names via operations.fieldCatalog)`
|
|
341
|
+
);
|
|
342
|
+
}
|
|
338
343
|
}
|
|
339
344
|
}
|
|
340
345
|
}
|
|
341
346
|
}
|
|
342
347
|
if (problems.length > 0) {
|
|
343
348
|
throw new AutotaskConfigError(
|
|
344
|
-
|
|
349
|
+
`${opName}: ${problems.length} problem(s) found pre-request (zero wire was issued)
|
|
345
350
|
- ` + problems.join("\n- "),
|
|
346
351
|
{ suggestedAction: "Fix every item above and call again \u2014 validation covers the whole batch up-front (one round, zero wire)." }
|
|
347
352
|
);
|
|
@@ -360,8 +365,38 @@ async function fetchMany(client, items, opts = {}) {
|
|
|
360
365
|
throw new AutotaskConfigError(`fetchMany: maxItems must be an integer >= 1 (got ${String(opts.maxItems)})`);
|
|
361
366
|
}
|
|
362
367
|
}
|
|
368
|
+
if (opts.liveFields !== void 0 && typeof opts.liveFields !== "boolean") {
|
|
369
|
+
throw new AutotaskConfigError(`fetchMany: liveFields must be a boolean (got ${typeof opts.liveFields})`);
|
|
370
|
+
}
|
|
363
371
|
const cap = Math.min(FETCH_MANY_MAX_ITEMS, opts.maxItems ?? FETCH_MANY_MAX_ITEMS);
|
|
364
|
-
|
|
372
|
+
if (opts.liveFields === true) {
|
|
373
|
+
validateFetchManyItems(items, cap, void 0, void 0, { fieldCheck: false });
|
|
374
|
+
const liveFieldSets = /* @__PURE__ */ new Map();
|
|
375
|
+
for (const item of items) {
|
|
376
|
+
const key = item.resource;
|
|
377
|
+
if (liveFieldSets.has(key)) continue;
|
|
378
|
+
const holder = client[camelKey(key)];
|
|
379
|
+
if (holder === void 0) {
|
|
380
|
+
throw new AutotaskConfigError(`fetchMany: the client exposes no accessor for resource "${key}"`, {
|
|
381
|
+
suggestedAction: "Rebuild the client from the SDK build that ships this registry (the resource set is pinned by the plan)."
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
try {
|
|
385
|
+
const rows = await holder.getFieldInfo();
|
|
386
|
+
const names = [];
|
|
387
|
+
for (const row of rows) {
|
|
388
|
+
if (typeof row.name === "string") names.push(row.name);
|
|
389
|
+
}
|
|
390
|
+
liveFieldSets.set(key, names.length > 0 ? names : null);
|
|
391
|
+
} catch (err) {
|
|
392
|
+
if (!isAutotaskError(err) || err.code === "ABORTED") throw err;
|
|
393
|
+
liveFieldSets.set(key, null);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
validateFetchManyItems(items, cap, void 0, void 0, { fieldSetsByResource: liveFieldSets });
|
|
397
|
+
} else {
|
|
398
|
+
validateFetchManyItems(items, cap);
|
|
399
|
+
}
|
|
365
400
|
const results = [];
|
|
366
401
|
for (const item of items) {
|
|
367
402
|
const key = item.resource;
|
|
@@ -391,6 +426,286 @@ async function fetchMany(client, items, opts = {}) {
|
|
|
391
426
|
return { results, ok, failed: results.length - ok };
|
|
392
427
|
}
|
|
393
428
|
|
|
429
|
+
// src/operations/aggregate.ts
|
|
430
|
+
var AGGREGATE_TOP_MAX = 100;
|
|
431
|
+
var AGGREGATE_DEFAULT_TOP = 25;
|
|
432
|
+
var AGGREGATE_DEFAULT_LIMIT = BOUNDED_QUERY_MAX_LIMIT;
|
|
433
|
+
var QUERY_RESOURCE_KEYS = (() => {
|
|
434
|
+
const s = /* @__PURE__ */ new Set();
|
|
435
|
+
for (const rec of CAPABILITIES) if (rec.operation === "query") s.add(rec.resource);
|
|
436
|
+
return s;
|
|
437
|
+
})();
|
|
438
|
+
var AGGREGATE_OPT_KEYS = ["groupBy", "sum", "top", "limit"];
|
|
439
|
+
var OP_RE = /^([a-z0-9_]+)\.query$/;
|
|
440
|
+
function num(v) {
|
|
441
|
+
return typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
442
|
+
}
|
|
443
|
+
function validateAggregate(operation, filter, opts) {
|
|
444
|
+
const problems = [];
|
|
445
|
+
let resourceKey;
|
|
446
|
+
if (typeof operation !== "string" || !OP_RE.test(operation)) {
|
|
447
|
+
problems.push(
|
|
448
|
+
`operation must be exactly "<planResourceKey>.query" (the resource's bounded query op \u2014 e.g. "billing_items.query"); a special op, a ".count" row, or any other verb is not an aggregate surface \u2014 see autotask_catalog for the exact plan keys`
|
|
449
|
+
);
|
|
450
|
+
} else {
|
|
451
|
+
const key = OP_RE.exec(operation)[1];
|
|
452
|
+
resourceKey = key;
|
|
453
|
+
if (!QUERY_RESOURCE_KEYS.has(key)) {
|
|
454
|
+
problems.push(
|
|
455
|
+
`operation "${operation}": "${key}" has no query row in the capability registry (116 query surfaces) \u2014 see autotask_catalog for the exact plan keys`
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
let conditions = [];
|
|
460
|
+
if (filter === void 0 || filter === null) {
|
|
461
|
+
conditions = [];
|
|
462
|
+
} else {
|
|
463
|
+
const conds = Array.isArray(filter) ? filter : filter.filter;
|
|
464
|
+
if (!Array.isArray(conds)) {
|
|
465
|
+
problems.push("filter must be the query-bag filter (a conditions array, or { filter: [...] })");
|
|
466
|
+
} else if (conds.length === 0) {
|
|
467
|
+
conditions = [];
|
|
468
|
+
} else {
|
|
469
|
+
try {
|
|
470
|
+
conditions = buildFilter(conds).filter;
|
|
471
|
+
} catch (err) {
|
|
472
|
+
problems.push(err instanceof AutotaskConfigError ? err.message : `filter must be the query-bag filter (13 operators; caps 500 OR-conditions / 1 UDF / 8000 chars); ${String(err)}`);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
if (opts !== void 0 && (typeof opts !== "object" || opts === null || Array.isArray(opts))) {
|
|
477
|
+
throw new AutotaskConfigError(
|
|
478
|
+
`aggregate: opts must be the options object (got ${Array.isArray(opts) ? "an array" : typeof opts})`,
|
|
479
|
+
{ operation: "operations.aggregate" }
|
|
480
|
+
);
|
|
481
|
+
}
|
|
482
|
+
for (const key of Object.keys(opts ?? {})) {
|
|
483
|
+
if (!AGGREGATE_OPT_KEYS.includes(key)) {
|
|
484
|
+
problems.push(`unknown opts key "${key}" \u2014 the bag is closed: ${AGGREGATE_OPT_KEYS.join(", ")}`);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
const fieldSets = resourceKey !== void 0 ? MODEL_FIELD_SETS[resourceKey] : void 0;
|
|
488
|
+
const checkFields = (name, fields) => {
|
|
489
|
+
if (fields === void 0) return [];
|
|
490
|
+
if (!Array.isArray(fields) || fields.length === 0 || fields.some((f) => typeof f !== "string" || f.trim() === "")) {
|
|
491
|
+
problems.push(`${name} must be a non-empty array of exact vendor field names (discover them via operations.fieldCatalog)`);
|
|
492
|
+
return [];
|
|
493
|
+
}
|
|
494
|
+
const out = [];
|
|
495
|
+
for (const f of fields) {
|
|
496
|
+
if (fieldSets === void 0 || !fieldSets.includes(f)) {
|
|
497
|
+
problems.push(`${name}: "${f}" is not a field of ${resourceKey} \u2014 a hallucinated field is a shape error, not a silent fold-miss (exact vendor field names via operations.fieldCatalog)`);
|
|
498
|
+
} else {
|
|
499
|
+
out.push(f);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
return out;
|
|
503
|
+
};
|
|
504
|
+
const groupBy = checkFields("groupBy", opts.groupBy);
|
|
505
|
+
const sum = checkFields("sum", opts.sum);
|
|
506
|
+
let top = AGGREGATE_DEFAULT_TOP;
|
|
507
|
+
if (opts.top !== void 0) {
|
|
508
|
+
if (!Number.isInteger(opts.top)) {
|
|
509
|
+
problems.push(`top must be an integer (got ${String(opts.top)})`);
|
|
510
|
+
} else {
|
|
511
|
+
top = Math.min(Math.max(opts.top, 1), AGGREGATE_TOP_MAX);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
let limit = AGGREGATE_DEFAULT_LIMIT;
|
|
515
|
+
if (opts.limit !== void 0) {
|
|
516
|
+
if (!Number.isInteger(opts.limit)) {
|
|
517
|
+
problems.push(`limit must be an integer (got ${String(opts.limit)})`);
|
|
518
|
+
} else {
|
|
519
|
+
limit = Math.min(Math.max(opts.limit, 1), BOUNDED_QUERY_MAX_LIMIT);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
if (problems.length > 0) {
|
|
523
|
+
throw new AutotaskConfigError(
|
|
524
|
+
`aggregate: ${problems.length} problem(s) found pre-request (zero wire was issued)
|
|
525
|
+
- ` + problems.join("\n- "),
|
|
526
|
+
{ operation: "operations.aggregate" }
|
|
527
|
+
);
|
|
528
|
+
}
|
|
529
|
+
return { resourceKey, conditions, groupBy, sum, top, limit };
|
|
530
|
+
}
|
|
531
|
+
async function aggregate(client, operation, filter, opts = {}) {
|
|
532
|
+
const v = validateAggregate(operation, filter, opts);
|
|
533
|
+
const holder = client[camelKey(v.resourceKey)];
|
|
534
|
+
if (holder === void 0) {
|
|
535
|
+
throw new AutotaskConfigError(`aggregate: the client exposes no accessor for resource "${v.resourceKey}"`, {
|
|
536
|
+
operation: "operations.aggregate",
|
|
537
|
+
suggestedAction: "Rebuild the client from the SDK build that ships this registry (the resource set is pinned by the plan)."
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
const wireFilter = v.conditions.length === 0 ? void 0 : v.conditions;
|
|
541
|
+
if (v.groupBy.length === 0 && v.sum.length === 0) {
|
|
542
|
+
const raw = await holder.count({ filter: wireFilter });
|
|
543
|
+
const sentinel = typeof raw === "object" && raw !== null && "count" in raw ? raw : { count: raw };
|
|
544
|
+
const result2 = { mode: "count", count: sentinel.count, blind: sentinel.blindSurface !== void 0 };
|
|
545
|
+
if (sentinel.blindSurface !== void 0) result2.blindSurface = sentinel.blindSurface;
|
|
546
|
+
if (sentinel.emptyReason !== void 0) result2.emptyReason = sentinel.emptyReason;
|
|
547
|
+
return result2;
|
|
548
|
+
}
|
|
549
|
+
const res = await holder.queryBounded({ filter: wireFilter, limit: v.limit });
|
|
550
|
+
const groups = /* @__PURE__ */ new Map();
|
|
551
|
+
for (const item of res.items) {
|
|
552
|
+
const key = {};
|
|
553
|
+
const values = [];
|
|
554
|
+
for (const f of v.groupBy) {
|
|
555
|
+
const value = item[f] === void 0 ? null : item[f];
|
|
556
|
+
key[f] = value;
|
|
557
|
+
values.push(value);
|
|
558
|
+
}
|
|
559
|
+
const keyOrder = JSON.stringify(values);
|
|
560
|
+
let g = groups.get(keyOrder);
|
|
561
|
+
if (g === void 0) {
|
|
562
|
+
g = { key, keyOrder, count: 0, ...v.sum.length > 0 ? { sums: {} } : {} };
|
|
563
|
+
groups.set(keyOrder, g);
|
|
564
|
+
}
|
|
565
|
+
g.count += 1;
|
|
566
|
+
if (g.sums !== void 0) {
|
|
567
|
+
for (const f of v.sum) g.sums[f] = (g.sums[f] ?? 0) + num(item[f]);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
const sorted = [...groups.values()].sort((a, b) => b.count - a.count || (a.keyOrder < b.keyOrder ? -1 : a.keyOrder > b.keyOrder ? 1 : 0));
|
|
571
|
+
const top = sorted.slice(0, v.top);
|
|
572
|
+
const result = {
|
|
573
|
+
mode: v.groupBy.length > 0 ? "group" : "sum",
|
|
574
|
+
groups: top.map((g) => ({ key: g.key, count: g.count, ...g.sums !== void 0 ? { sums: g.sums } : {} })),
|
|
575
|
+
totalGroups: sorted.length,
|
|
576
|
+
groupsTruncated: sorted.length > top.length,
|
|
577
|
+
totalScanned: res.fetched,
|
|
578
|
+
hasMore: res.hasMore
|
|
579
|
+
};
|
|
580
|
+
if (res.blindSurface !== void 0) result.blindSurface = res.blindSurface;
|
|
581
|
+
if (res.emptyReason !== void 0) result.emptyReason = res.emptyReason;
|
|
582
|
+
return result;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// src/operations/fetchByIds.ts
|
|
586
|
+
var FETCH_BY_IDS_MAX_ITEMS = 500;
|
|
587
|
+
var FETCH_BY_IDS_CHUNK_SIZE = 250;
|
|
588
|
+
function project2(value, fields) {
|
|
589
|
+
const out = {};
|
|
590
|
+
for (const f of fields) {
|
|
591
|
+
if (f in value) out[f] = value[f];
|
|
592
|
+
}
|
|
593
|
+
return out;
|
|
594
|
+
}
|
|
595
|
+
function resourcePathOf(key, holder) {
|
|
596
|
+
const path = holder?.resourcePath;
|
|
597
|
+
if (typeof path !== "string" || path === "") {
|
|
598
|
+
throw new AutotaskConfigError(`fetchByIds: the client exposes no ${key} resource path (registry drift)`, {
|
|
599
|
+
suggestedAction: "Rebuild the client from the SDK build that ships this registry (the resource set is pinned by the plan)."
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
return path;
|
|
603
|
+
}
|
|
604
|
+
async function fetchByIds(client, items, opts = {}) {
|
|
605
|
+
if (opts.maxItems !== void 0) {
|
|
606
|
+
if (!Number.isInteger(opts.maxItems) || opts.maxItems < 1) {
|
|
607
|
+
throw new AutotaskConfigError(`fetchByIds: maxItems must be an integer >= 1 (got ${String(opts.maxItems)})`);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
const cap = Math.min(FETCH_BY_IDS_MAX_ITEMS, opts.maxItems ?? FETCH_BY_IDS_MAX_ITEMS);
|
|
611
|
+
validateFetchManyItems(items, cap, "fetchByIds", `FETCH_BY_IDS_MAX_ITEMS = ${FETCH_BY_IDS_MAX_ITEMS}`);
|
|
612
|
+
const groups = /* @__PURE__ */ new Map();
|
|
613
|
+
const canonical = [];
|
|
614
|
+
for (let i = 0; i < items.length; i += 1) {
|
|
615
|
+
const item = items[i];
|
|
616
|
+
const id = parseIdentifier(item.id, `items[${i}].id`);
|
|
617
|
+
canonical[i] = id;
|
|
618
|
+
const g = groups.get(item.resource) ?? { indices: [], fields: /* @__PURE__ */ new Set(), anyFields: false };
|
|
619
|
+
g.indices.push(i);
|
|
620
|
+
if (item.fields !== void 0) {
|
|
621
|
+
g.anyFields = true;
|
|
622
|
+
for (const f of item.fields) g.fields.add(f);
|
|
623
|
+
}
|
|
624
|
+
groups.set(item.resource, g);
|
|
625
|
+
}
|
|
626
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
627
|
+
for (const [key, group] of groups) {
|
|
628
|
+
const holder = client[camelKey(key)];
|
|
629
|
+
if (holder === void 0) {
|
|
630
|
+
throw new AutotaskConfigError(`fetchByIds: the client exposes no accessor for resource "${key}"`, {
|
|
631
|
+
suggestedAction: "Rebuild the client from the SDK build that ships this registry (the resource set is pinned by the plan)."
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
const resourcePath = resourcePathOf(key, holder);
|
|
635
|
+
const unique = [];
|
|
636
|
+
const seen = /* @__PURE__ */ new Set();
|
|
637
|
+
for (const i of group.indices) {
|
|
638
|
+
const k = String(canonical[i]);
|
|
639
|
+
if (!seen.has(k)) {
|
|
640
|
+
seen.add(k);
|
|
641
|
+
unique.push(canonical[i]);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
const includeFields = group.anyFields && group.indices.every((i) => items[i].fields !== void 0) ? [...group.fields] : void 0;
|
|
645
|
+
const kOf = (id) => `${key}:${String(id)}`;
|
|
646
|
+
for (let c = 0; c < unique.length; c += FETCH_BY_IDS_CHUNK_SIZE) {
|
|
647
|
+
const chunk = unique.slice(c, c + FETCH_BY_IDS_CHUNK_SIZE);
|
|
648
|
+
const chunkKeys = new Set(chunk.map((id) => String(id)));
|
|
649
|
+
try {
|
|
650
|
+
const req = buildQueryRequest(client.http.baseUrl, resourcePath, {
|
|
651
|
+
filter: [{ field: "id", op: "in", value: chunk }],
|
|
652
|
+
maxRecords: FETCH_BY_IDS_CHUNK_SIZE,
|
|
653
|
+
includeFields
|
|
654
|
+
});
|
|
655
|
+
const res = await client.http.request({ ...req, operation: `${key}.fetchByIds` });
|
|
656
|
+
const { items: rows } = unwrapItems(res, `${key}.fetchByIds`);
|
|
657
|
+
for (const row of rows) {
|
|
658
|
+
const k = String(row.id);
|
|
659
|
+
if (!chunkKeys.has(k)) continue;
|
|
660
|
+
const q = kOf(k);
|
|
661
|
+
if (!byKey.has(q)) byKey.set(q, { found: true, value: row });
|
|
662
|
+
}
|
|
663
|
+
} catch (err) {
|
|
664
|
+
if (isAutotaskError(err) && err.code !== "ABORTED") {
|
|
665
|
+
const e = { code: err.code, message: err.message };
|
|
666
|
+
if (err.httpStatus !== void 0) e.httpStatus = err.httpStatus;
|
|
667
|
+
for (const u of chunk) {
|
|
668
|
+
const q = kOf(u);
|
|
669
|
+
if (!byKey.has(q)) byKey.set(q, { found: false, value: null, error: e });
|
|
670
|
+
}
|
|
671
|
+
continue;
|
|
672
|
+
}
|
|
673
|
+
throw err;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
for (const id of unique) {
|
|
677
|
+
const k = kOf(id);
|
|
678
|
+
if (byKey.has(k)) continue;
|
|
679
|
+
try {
|
|
680
|
+
const value = await holder.get(id);
|
|
681
|
+
byKey.set(k, { found: true, value });
|
|
682
|
+
} catch (err) {
|
|
683
|
+
if (err instanceof NotFoundError) {
|
|
684
|
+
byKey.set(k, { found: false, value: null, error: { code: "NOT_FOUND", message: err.message } });
|
|
685
|
+
} else if (isAutotaskError(err) && err.code !== "ABORTED") {
|
|
686
|
+
const e = { code: err.code, message: err.message };
|
|
687
|
+
if (err.httpStatus !== void 0) e.httpStatus = err.httpStatus;
|
|
688
|
+
byKey.set(k, { found: false, value: null, error: e });
|
|
689
|
+
} else {
|
|
690
|
+
throw err;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
const results = [];
|
|
696
|
+
for (let i = 0; i < items.length; i += 1) {
|
|
697
|
+
const item = items[i];
|
|
698
|
+
const id = canonical[i];
|
|
699
|
+
const out = byKey.get(`${item.resource}:${String(id)}`);
|
|
700
|
+
const value = out.found ? item.fields !== void 0 ? project2(out.value, item.fields) : out.value : null;
|
|
701
|
+
results.push(
|
|
702
|
+
out.found ? { resource: item.resource, id, found: true, value } : { resource: item.resource, id, found: false, value: null, error: out.error }
|
|
703
|
+
);
|
|
704
|
+
}
|
|
705
|
+
const ok = results.filter((r) => r.found).length;
|
|
706
|
+
return { results, ok, failed: results.length - ok };
|
|
707
|
+
}
|
|
708
|
+
|
|
394
709
|
// src/operations/relationshipMap.ts
|
|
395
710
|
async function relationshipMap(client, resourceKey) {
|
|
396
711
|
void client;
|
|
@@ -628,229 +943,6 @@ async function createGuidance(client, opts) {
|
|
|
628
943
|
};
|
|
629
944
|
}
|
|
630
945
|
|
|
631
|
-
// src/operations/fieldCatalog.ts
|
|
632
|
-
var MAX_FIELD_CATALOG_WIRE = 60;
|
|
633
|
-
var FIELD_CATALOG_HONESTY_NOTE = "Live field metadata reports the SHAPE of a field (existence, requiredness, type, maxLength, read-only, queryable, picklist-ness) and serves picklist VALUES where the vendor exposes them. It cannot resolve a picklist VALUE the vendor does not expose to this API user (the W-A4 wall \u2014 e.g. the attachments Type picklist): retrying the catalog will not surface a withheld value; that gap is vendor-side, not a client defect.";
|
|
634
|
-
var FIELD_CATALOG_OPT_KEYS = ["resources", "include", "fresh"];
|
|
635
|
-
function projectFieldRow(raw) {
|
|
636
|
-
const r = typeof raw === "object" && raw !== null ? raw : {};
|
|
637
|
-
const name = typeof r.name === "string" ? r.name : "";
|
|
638
|
-
const type = typeof r.dataType === "string" ? r.dataType : typeof r.type === "string" ? r.type : "";
|
|
639
|
-
return {
|
|
640
|
-
name,
|
|
641
|
-
...typeof r.label === "string" && r.label !== "" ? { label: r.label } : {},
|
|
642
|
-
type,
|
|
643
|
-
isRequired: r.isRequired === true,
|
|
644
|
-
isReadOnly: r.isReadOnly === true,
|
|
645
|
-
isQueryable: r.isQueryable === true,
|
|
646
|
-
isPickList: r.isPickList === true,
|
|
647
|
-
maxLength: typeof r.length === "number" ? r.length : null,
|
|
648
|
-
referenceEntityType: typeof r.referenceEntityType === "string" ? r.referenceEntityType : ""
|
|
649
|
-
};
|
|
650
|
-
}
|
|
651
|
-
function exposesPicklistValues(raw) {
|
|
652
|
-
const r = typeof raw === "object" && raw !== null ? raw : {};
|
|
653
|
-
return Array.isArray(r.picklistValues) && r.picklistValues.length > 0;
|
|
654
|
-
}
|
|
655
|
-
function capabilitySets() {
|
|
656
|
-
const fieldOps = /* @__PURE__ */ new Map();
|
|
657
|
-
const udfOps = /* @__PURE__ */ new Map();
|
|
658
|
-
const resources = /* @__PURE__ */ new Set();
|
|
659
|
-
for (const rec of CAPABILITIES) {
|
|
660
|
-
if (rec.resource === "operations") continue;
|
|
661
|
-
resources.add(rec.resource);
|
|
662
|
-
if (rec.operation === "getFieldInfo") fieldOps.set(rec.resource, rec);
|
|
663
|
-
if (rec.operation === "getUdfInfo") udfOps.set(rec.resource, rec);
|
|
664
|
-
}
|
|
665
|
-
return { fieldOps, udfOps, resources };
|
|
666
|
-
}
|
|
667
|
-
function apiEntityFor(rec) {
|
|
668
|
-
const m = /^GET \/V1\.0\/([^/]+)\/entityInformation\/fields$/.exec(rec.endpoint ?? "");
|
|
669
|
-
if (m === null) {
|
|
670
|
-
throw new AutotaskConfigError(
|
|
671
|
-
`fieldCatalog: the plan's getFieldInfo endpoint for "${rec.resource}" has no /V1.0/<Entity>/entityInformation/fields shape (${rec.endpoint}) \u2014 plan defect`,
|
|
672
|
-
{ operation: "operations.fieldCatalog" }
|
|
673
|
-
);
|
|
674
|
-
}
|
|
675
|
-
return m[1];
|
|
676
|
-
}
|
|
677
|
-
async function fieldCatalog(client, opts) {
|
|
678
|
-
if (opts !== void 0 && (typeof opts !== "object" || opts === null || Array.isArray(opts))) {
|
|
679
|
-
throw new AutotaskConfigError(
|
|
680
|
-
"fieldCatalog: opts must be an object { resources?: string[], include?: (info|fields|udf)[], fresh?: boolean }"
|
|
681
|
-
);
|
|
682
|
-
}
|
|
683
|
-
for (const key of Object.keys(opts ?? {})) {
|
|
684
|
-
if (!FIELD_CATALOG_OPT_KEYS.includes(key)) {
|
|
685
|
-
throw new AutotaskConfigError(
|
|
686
|
-
`fieldCatalog: unknown opts key "${key}" \u2014 the bag is closed: ${FIELD_CATALOG_OPT_KEYS.join(", ")}`,
|
|
687
|
-
{ suggestedAction: "Drop the unknown key (autotask_describe(operations.fieldCatalog) shows the exact bag)." }
|
|
688
|
-
);
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
const { fieldOps, udfOps, resources: allResources } = capabilitySets();
|
|
692
|
-
const includeRaw = opts?.include ?? ["fields"];
|
|
693
|
-
if (!Array.isArray(includeRaw) || includeRaw.length === 0) {
|
|
694
|
-
throw new AutotaskConfigError("fieldCatalog: opts.include must be a non-empty array of (info|fields|udf)");
|
|
695
|
-
}
|
|
696
|
-
const include = [];
|
|
697
|
-
for (const kind of includeRaw) {
|
|
698
|
-
if (typeof kind !== "string" || !FIELD_CACHE_KINDS.includes(kind)) {
|
|
699
|
-
throw new AutotaskConfigError(
|
|
700
|
-
`fieldCatalog: unknown include kind "${String(kind)}" \u2014 the valid kinds are: ${FIELD_CACHE_KINDS.join(", ")}`,
|
|
701
|
-
{ suggestedAction: `Filter with one or more of: ${FIELD_CACHE_KINDS.join(", ")} (default ['fields']).` }
|
|
702
|
-
);
|
|
703
|
-
}
|
|
704
|
-
if (!include.includes(kind)) include.push(kind);
|
|
705
|
-
}
|
|
706
|
-
const resourcesRaw = opts?.resources ?? WORKFLOW_RESOURCES;
|
|
707
|
-
if (!Array.isArray(resourcesRaw) || resourcesRaw.length === 0) {
|
|
708
|
-
throw new AutotaskConfigError("fieldCatalog: opts.resources must be a non-empty array of plan resource keys");
|
|
709
|
-
}
|
|
710
|
-
const targets = [];
|
|
711
|
-
for (const r of resourcesRaw) {
|
|
712
|
-
if (typeof r !== "string" || r.trim() === "") {
|
|
713
|
-
throw new AutotaskConfigError(
|
|
714
|
-
`fieldCatalog: opts.resources must contain non-empty plan resource key strings (got ${typeof r === "string" && r.trim() === "" ? "a blank string" : typeof r})`
|
|
715
|
-
);
|
|
716
|
-
}
|
|
717
|
-
const key = r.trim();
|
|
718
|
-
const fieldOp = fieldOps.get(key);
|
|
719
|
-
if (fieldOp === void 0) {
|
|
720
|
-
if (allResources.has(key)) {
|
|
721
|
-
throw new AutotaskConfigError(
|
|
722
|
-
`fieldCatalog: resource "${key}" has no field catalog \u2014 the vendor defines the entityInformation trio for the ${fieldOps.size} plan entity resources only`,
|
|
723
|
-
{ suggestedAction: `Pass one of the ${fieldOps.size} field-capable plan keys (list them with autotask_catalog).` }
|
|
724
|
-
);
|
|
725
|
-
}
|
|
726
|
-
throw new AutotaskError(
|
|
727
|
-
`fieldCatalog: unknown resource "${key}" \u2014 the plan has ${fieldOps.size} field-capable resources`,
|
|
728
|
-
{
|
|
729
|
-
code: "RESOURCE_UNKNOWN",
|
|
730
|
-
category: "validation",
|
|
731
|
-
suggestedAction: "Pass the exact plan resource key (snake_case) from autotask_catalog (e.g. tickets, companies, configuration_items)."
|
|
732
|
-
}
|
|
733
|
-
);
|
|
734
|
-
}
|
|
735
|
-
if (!targets.includes(key)) targets.push(key);
|
|
736
|
-
}
|
|
737
|
-
const cost = targets.length * include.length;
|
|
738
|
-
if (cost > MAX_FIELD_CATALOG_WIRE) {
|
|
739
|
-
throw new AutotaskConfigError(
|
|
740
|
-
`fieldCatalog: ${targets.length} resource(s) \xD7 ${include.length} kind(s) = ${cost} metadata reads exceed the wire cap of ${MAX_FIELD_CATALOG_WIRE} \u2014 the call is refused above its cap (never truncated)`,
|
|
741
|
-
{ suggestedAction: `Pass a smaller resources list or a narrower include set so the product stays \u2264 ${MAX_FIELD_CATALOG_WIRE}.` }
|
|
742
|
-
);
|
|
743
|
-
}
|
|
744
|
-
const cache = client.http.fieldCache;
|
|
745
|
-
const fresh = opts?.fresh === true;
|
|
746
|
-
const zone = client.config.zone ?? "unknown";
|
|
747
|
-
const rows = [];
|
|
748
|
-
let wireUsed = 0;
|
|
749
|
-
let anyPicklistValues = false;
|
|
750
|
-
for (const resource of targets) {
|
|
751
|
-
const fieldOp = fieldOps.get(resource);
|
|
752
|
-
if (fieldOp === void 0) continue;
|
|
753
|
-
const apiEntity = apiEntityFor(fieldOp);
|
|
754
|
-
const holder = client[camelKey(resource)];
|
|
755
|
-
const row = {
|
|
756
|
-
resource,
|
|
757
|
-
apiEntity,
|
|
758
|
-
udfCapable: udfOps.has(resource),
|
|
759
|
-
required: [],
|
|
760
|
-
readOnly: [],
|
|
761
|
-
queryable: [],
|
|
762
|
-
picklistFields: [],
|
|
763
|
-
cache: { hit: false, age: null },
|
|
764
|
-
wire: 0,
|
|
765
|
-
error: null
|
|
766
|
-
};
|
|
767
|
-
const fetches = {
|
|
768
|
-
info: () => holder?.getEntityInfo?.() ?? Promise.reject(new AutotaskError(`fieldCatalog: the client exposes no getEntityInfo read for "${resource}"`, { code: "INVALID_RESPONSE", category: "server" })),
|
|
769
|
-
fields: () => holder?.getFieldInfo?.() ?? Promise.reject(new AutotaskError(`fieldCatalog: the client exposes no getFieldInfo read for "${resource}"`, { code: "INVALID_RESPONSE", category: "server" })),
|
|
770
|
-
udf: () => holder?.getUdfInfo?.() ?? Promise.reject(new AutotaskError(`fieldCatalog: the client exposes no getUdfInfo read for "${resource}"`, { code: "INVALID_RESPONSE", category: "server" }))
|
|
771
|
-
};
|
|
772
|
-
if (fresh) cache?.invalidate(resource);
|
|
773
|
-
let allCached = true;
|
|
774
|
-
const ages = [];
|
|
775
|
-
for (const kind of include) {
|
|
776
|
-
const peek = cache !== void 0 && !fresh ? cache.peek(resource, kind) : { hit: false, age: null };
|
|
777
|
-
if (peek.hit !== true) allCached = false;
|
|
778
|
-
if (peek.hit === true && cache !== void 0) {
|
|
779
|
-
const value2 = cache.get(resource, kind);
|
|
780
|
-
if (kind === "info") row.info = value2 ?? null;
|
|
781
|
-
else {
|
|
782
|
-
const list = Array.isArray(value2) ? value2 : [];
|
|
783
|
-
const projected = list.map((f) => projectFieldRow(f));
|
|
784
|
-
if (kind === "fields") row.fields = projected;
|
|
785
|
-
else row.udf = projected;
|
|
786
|
-
for (const f of list) if (exposesPicklistValues(f)) anyPicklistValues = true;
|
|
787
|
-
if (kind === "fields") {
|
|
788
|
-
row.required = projected.filter((f) => f.isRequired).map((f) => f.name);
|
|
789
|
-
row.readOnly = projected.filter((f) => f.isReadOnly).map((f) => f.name);
|
|
790
|
-
row.queryable = projected.filter((f) => f.isQueryable).map((f) => f.name);
|
|
791
|
-
row.picklistFields = projected.filter((f) => f.isPickList).map((f) => f.name);
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
if (peek.age !== null) ages.push(peek.age);
|
|
795
|
-
continue;
|
|
796
|
-
}
|
|
797
|
-
let value;
|
|
798
|
-
try {
|
|
799
|
-
value = await fetches[kind]();
|
|
800
|
-
} catch (err) {
|
|
801
|
-
wireUsed += 1;
|
|
802
|
-
row.wire += 1;
|
|
803
|
-
if (row.error === null) {
|
|
804
|
-
const code = isAutotaskError(err) ? err.code : "NETWORK_ERROR";
|
|
805
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
806
|
-
row.error = { code, message };
|
|
807
|
-
}
|
|
808
|
-
continue;
|
|
809
|
-
}
|
|
810
|
-
wireUsed += 1;
|
|
811
|
-
row.wire += 1;
|
|
812
|
-
if (kind === "info") {
|
|
813
|
-
row.info = value ?? null;
|
|
814
|
-
} else {
|
|
815
|
-
const list = Array.isArray(value) ? value : [];
|
|
816
|
-
const projected = list.map((f) => projectFieldRow(f));
|
|
817
|
-
if (kind === "fields") row.fields = projected;
|
|
818
|
-
else row.udf = projected;
|
|
819
|
-
for (const f of list) if (exposesPicklistValues(f)) anyPicklistValues = true;
|
|
820
|
-
if (kind === "fields") {
|
|
821
|
-
row.required = projected.filter((f) => f.isRequired).map((f) => f.name);
|
|
822
|
-
row.readOnly = projected.filter((f) => f.isReadOnly).map((f) => f.name);
|
|
823
|
-
row.queryable = projected.filter((f) => f.isQueryable).map((f) => f.name);
|
|
824
|
-
row.picklistFields = projected.filter((f) => f.isPickList).map((f) => f.name);
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
row.cache = allCached ? { hit: true, age: ages.length > 0 ? Math.max(...ages) : 0 } : { hit: false, age: null };
|
|
829
|
-
rows.push(row);
|
|
830
|
-
}
|
|
831
|
-
return {
|
|
832
|
-
zone,
|
|
833
|
-
label: zone,
|
|
834
|
-
cached: cache !== void 0,
|
|
835
|
-
ttlMs: cache?.ttlMs ?? null,
|
|
836
|
-
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
837
|
-
rows,
|
|
838
|
-
wireUsed,
|
|
839
|
-
cap: MAX_FIELD_CATALOG_WIRE,
|
|
840
|
-
truncated: false,
|
|
841
|
-
counts: {
|
|
842
|
-
resources: targets.length,
|
|
843
|
-
fieldCapableResources: fieldOps.size,
|
|
844
|
-
udfCapableResources: udfOps.size,
|
|
845
|
-
cached: rows.filter((r) => r.cache.hit === true).length
|
|
846
|
-
},
|
|
847
|
-
honesty: {
|
|
848
|
-
picklistValues: anyPicklistValues ? "partial" : "unexposed",
|
|
849
|
-
note: FIELD_CATALOG_HONESTY_NOTE
|
|
850
|
-
}
|
|
851
|
-
};
|
|
852
|
-
}
|
|
853
|
-
|
|
854
946
|
// src/operations/recovery.ts
|
|
855
947
|
var RECOVERY_CONFIRM = "operations.recovery";
|
|
856
948
|
var RECOVERY_DEFAULT_LIMIT = 25;
|
|
@@ -1211,12 +1303,14 @@ function validateDispatchArgs(record, argsIn) {
|
|
|
1211
1303
|
}
|
|
1212
1304
|
}
|
|
1213
1305
|
var PARAMS_BAG_KEYS = {
|
|
1214
|
-
query: ["filter", "limit", "includeFields", "via"],
|
|
1306
|
+
query: ["filter", "limit", "includeFields", "via", "latest", "noteChars", "fieldsPreset"],
|
|
1215
1307
|
queryAll: ["filter", "maxRecords", "includeFields", "maxTotalRecords", "via"],
|
|
1216
1308
|
count: ["filter"]
|
|
1217
1309
|
};
|
|
1218
1310
|
var BAG_KEY_SYNONYMS = {
|
|
1219
1311
|
filters: "filter",
|
|
1312
|
+
last: "latest",
|
|
1313
|
+
// issue #59: the expected typo class (honoured only on `query`)
|
|
1220
1314
|
lmit: "limit",
|
|
1221
1315
|
page: "limit",
|
|
1222
1316
|
pageSize: "limit",
|
|
@@ -1330,11 +1424,29 @@ async function invokeMode(client, operation, argsIn = [], opts = {}) {
|
|
|
1330
1424
|
validateParamsBag(record, args);
|
|
1331
1425
|
const boundedQuery = record.kind === "primitive" && record.operation === "query";
|
|
1332
1426
|
let holder = client[camelKey(record.resource)];
|
|
1427
|
+
if (typeof holder === "function") {
|
|
1428
|
+
holder = client[`${camelKey(record.resource)}Resource`] ?? holder;
|
|
1429
|
+
}
|
|
1333
1430
|
if (holder === void 0 && record.resource === "operations") {
|
|
1334
1431
|
holder = {
|
|
1335
1432
|
resolveAny: (identifier, opts2) => resolveAny(client, identifier, opts2),
|
|
1336
1433
|
searchAcrossResources: (query, opts2) => searchAcrossResources(client, query, opts2),
|
|
1337
1434
|
fetchMany: (items, opts2) => fetchMany(client, items, opts2),
|
|
1435
|
+
// Issue #62: the generic aggregate + the cheap count — the
|
|
1436
|
+
// groupBy/sum-absent mode is ONE vendor /query/count (the S12-C blind
|
|
1437
|
+
// sentinel rides through); the group/sum modes walk the named
|
|
1438
|
+
// <resource>.query op via the house bounded walk and fold client-side
|
|
1439
|
+
// (truncation honesty: hasMore/totalScanned — no silent partial sums).
|
|
1440
|
+
aggregate: (operation2, filter, opts2) => aggregate(client, operation2, filter, opts2),
|
|
1441
|
+
// Issue #59 PR-B: the bulk fetch by ids — query-first chunked `id in`
|
|
1442
|
+
// reads + the per-id `get` fallback (blind-surface-safe; per-item
|
|
1443
|
+
// typed outcomes reuse the fetchMany shapes).
|
|
1444
|
+
fetchByIds: (items, opts2) => fetchByIds(client, items, opts2),
|
|
1445
|
+
// Issue #65: opt-in resource name expansion — per-id resources.get
|
|
1446
|
+
// reads ONLY (never an id-in query — the resources table can be blind
|
|
1447
|
+
// to count/query while per-id reads work); blind-marked rows for ids
|
|
1448
|
+
// the API user cannot resolve; the name cache (default-on).
|
|
1449
|
+
expandResourceNames: (ids, opts2) => expandResourceNames(client, ids, opts2),
|
|
1338
1450
|
relationshipMap: (resourceKey) => relationshipMap(client, resourceKey),
|
|
1339
1451
|
// Issue #11: the served blind-surface inventory (zero wire) + the
|
|
1340
1452
|
// bounded caller-opted reachability sweep (read-only, confirmProbe-
|
|
@@ -1425,20 +1537,30 @@ async function invokeDelete(client, operation, args = [], opts = {}) {
|
|
|
1425
1537
|
return invokeMode(client, operation, args, { ...opts, mode: "delete" });
|
|
1426
1538
|
}
|
|
1427
1539
|
export {
|
|
1540
|
+
AGGREGATE_DEFAULT_LIMIT,
|
|
1541
|
+
AGGREGATE_DEFAULT_TOP,
|
|
1542
|
+
AGGREGATE_TOP_MAX,
|
|
1428
1543
|
BLIND_SURFACE_KINDS,
|
|
1429
1544
|
CREATE_BLOCKER_KINDS,
|
|
1545
|
+
EXPAND_RESOURCE_NAMES_MAX_IDS,
|
|
1546
|
+
FETCH_BY_IDS_CHUNK_SIZE,
|
|
1547
|
+
FETCH_BY_IDS_MAX_ITEMS,
|
|
1430
1548
|
FETCH_MANY_MAX_ITEMS,
|
|
1431
1549
|
FIELD_CACHE_KINDS,
|
|
1432
1550
|
FIELD_CATALOG_HONESTY_NOTE,
|
|
1433
1551
|
INVOKE_OPTION_KEYS,
|
|
1434
1552
|
MAX_FIELD_CATALOG_WIRE,
|
|
1435
1553
|
PARAMS_BAG_KEYS,
|
|
1554
|
+
PICKLIST_VALUE_NOT_SERVED_NOTE,
|
|
1436
1555
|
RECOVERY_CONFIRM,
|
|
1437
1556
|
RECOVERY_DEFAULT_LIMIT,
|
|
1438
1557
|
RECOVERY_MAX_LIMIT,
|
|
1439
1558
|
WORKFLOW_RESOURCES,
|
|
1559
|
+
aggregate,
|
|
1440
1560
|
blindSurfaces,
|
|
1441
1561
|
createGuidance,
|
|
1562
|
+
expandResourceNames,
|
|
1563
|
+
fetchByIds,
|
|
1442
1564
|
fetchMany,
|
|
1443
1565
|
fieldCatalog,
|
|
1444
1566
|
invoke,
|
|
@@ -1457,4 +1579,3 @@ export {
|
|
|
1457
1579
|
validateInvokeOptions,
|
|
1458
1580
|
validateParamsBag
|
|
1459
1581
|
};
|
|
1460
|
-
//# sourceMappingURL=index.js.map
|