@tangle-network/agent-integrations 0.50.0 → 0.51.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/dist/catalog.js +5 -4
- package/dist/{chunk-IA5GCKM6.js → chunk-BS6LGM3V.js} +84 -38
- package/dist/chunk-BS6LGM3V.js.map +1 -0
- package/dist/{chunk-AJ67SDTL.js → chunk-DRBW2FXU.js} +11 -3
- package/dist/{chunk-AJ67SDTL.js.map → chunk-DRBW2FXU.js.map} +1 -1
- package/dist/chunk-P4FFI752.js +1 -0
- package/dist/chunk-PUXYDSXI.js +109 -0
- package/dist/chunk-PUXYDSXI.js.map +1 -0
- package/dist/{chunk-RM6JJK4Q.js → chunk-XEJKVCXB.js} +181 -19
- package/dist/{chunk-RM6JJK4Q.js.map → chunk-XEJKVCXB.js.map} +1 -1
- package/dist/connectors/adapters/index.js +1 -1
- package/dist/connectors/index.d.ts +39 -2
- package/dist/connectors/index.js +18 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +20 -4
- package/dist/mcp.js +5 -4
- package/dist/mcp.js.map +1 -1
- package/dist/registry.js +5 -4
- package/dist/runtime.js +5 -4
- package/dist/specs.d.ts +13 -2
- package/dist/specs.js +5 -1
- package/package.json +1 -1
- package/dist/chunk-376UBTNB.js +0 -1
- package/dist/chunk-IA5GCKM6.js.map +0 -1
- /package/dist/{chunk-376UBTNB.js.map → chunk-P4FFI752.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=chunk-P4FFI752.js.map
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CONNECTOR_ADAPTER_FACTORIES,
|
|
3
|
+
adapters_exports
|
|
4
|
+
} from "./chunk-XEJKVCXB.js";
|
|
5
|
+
|
|
6
|
+
// src/connectors/bundled-manifests.ts
|
|
7
|
+
var MANIFEST_PROBE_PREFIX = "tangle-adapter-metadata-";
|
|
8
|
+
function isConnectorAdapter(value) {
|
|
9
|
+
if (!value || typeof value !== "object") return false;
|
|
10
|
+
const manifest = value.manifest;
|
|
11
|
+
if (!manifest || typeof manifest !== "object") return false;
|
|
12
|
+
return typeof manifest.kind === "string";
|
|
13
|
+
}
|
|
14
|
+
function manifestFromFactory(definition) {
|
|
15
|
+
const probeOptions = Object.fromEntries(
|
|
16
|
+
Object.keys(definition.envMap).map((name) => [name, `${MANIFEST_PROBE_PREFIX}${name}`])
|
|
17
|
+
);
|
|
18
|
+
try {
|
|
19
|
+
return definition.factory(probeOptions).manifest;
|
|
20
|
+
} catch {
|
|
21
|
+
return void 0;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
var cachedManifests;
|
|
25
|
+
var cachedByKind;
|
|
26
|
+
function buildRegistry() {
|
|
27
|
+
const byKind = /* @__PURE__ */ new Map();
|
|
28
|
+
for (const value of Object.values(adapters_exports)) {
|
|
29
|
+
if (isConnectorAdapter(value)) byKind.set(value.manifest.kind, value.manifest);
|
|
30
|
+
}
|
|
31
|
+
for (const definition of CONNECTOR_ADAPTER_FACTORIES) {
|
|
32
|
+
if (byKind.has(definition.kind)) continue;
|
|
33
|
+
const manifest = manifestFromFactory(definition);
|
|
34
|
+
if (manifest) byKind.set(manifest.kind, manifest);
|
|
35
|
+
}
|
|
36
|
+
return byKind;
|
|
37
|
+
}
|
|
38
|
+
function registry() {
|
|
39
|
+
if (!cachedByKind) cachedByKind = buildRegistry();
|
|
40
|
+
return cachedByKind;
|
|
41
|
+
}
|
|
42
|
+
function listBundledAdapterManifests() {
|
|
43
|
+
if (!cachedManifests) {
|
|
44
|
+
cachedManifests = [...registry().values()].sort((a, b) => a.kind.localeCompare(b.kind));
|
|
45
|
+
}
|
|
46
|
+
return cachedManifests;
|
|
47
|
+
}
|
|
48
|
+
function getBundledAdapterManifest(kind) {
|
|
49
|
+
return registry().get(kind);
|
|
50
|
+
}
|
|
51
|
+
function hasBundledAdapter(kind) {
|
|
52
|
+
return registry().has(kind);
|
|
53
|
+
}
|
|
54
|
+
function listBundledAdapterKinds() {
|
|
55
|
+
return listBundledAdapterManifests().map((manifest) => manifest.kind);
|
|
56
|
+
}
|
|
57
|
+
function bundledAuthMode(manifest) {
|
|
58
|
+
const auth = manifest.auth;
|
|
59
|
+
const effective = auth.kind === "one_of" ? auth.options.find((option) => option.kind === auth.preferred) ?? auth.options[0] : auth;
|
|
60
|
+
switch (effective.kind) {
|
|
61
|
+
case "oauth2":
|
|
62
|
+
return effective.grantType === "client_credentials" ? "oauth2_client_credentials" : "oauth2";
|
|
63
|
+
case "api-key":
|
|
64
|
+
return "api_key";
|
|
65
|
+
case "hmac":
|
|
66
|
+
return "hmac";
|
|
67
|
+
case "none":
|
|
68
|
+
return "none";
|
|
69
|
+
default:
|
|
70
|
+
return void 0;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function bundledApiKeyHint(manifest) {
|
|
74
|
+
const auth = manifest.auth;
|
|
75
|
+
const candidates = auth.kind === "one_of" ? auth.options : [auth];
|
|
76
|
+
for (const candidate of candidates) {
|
|
77
|
+
if (candidate.kind === "api-key") return candidate.hint;
|
|
78
|
+
}
|
|
79
|
+
return void 0;
|
|
80
|
+
}
|
|
81
|
+
function bundledOAuth2Auth(manifest) {
|
|
82
|
+
const auth = manifest.auth;
|
|
83
|
+
const candidates = auth.kind === "one_of" ? auth.options.filter((option) => option.kind === auth.preferred) : [auth];
|
|
84
|
+
for (const candidate of candidates) {
|
|
85
|
+
if (candidate.kind !== "oauth2") continue;
|
|
86
|
+
if (candidate.grantType === "client_credentials") continue;
|
|
87
|
+
if (!candidate.authorizationUrl) continue;
|
|
88
|
+
return {
|
|
89
|
+
authorizationUrl: candidate.authorizationUrl,
|
|
90
|
+
tokenUrl: candidate.tokenUrl,
|
|
91
|
+
scopes: candidate.scopes,
|
|
92
|
+
clientIdEnv: candidate.clientIdEnv,
|
|
93
|
+
clientSecretEnv: candidate.clientSecretEnv,
|
|
94
|
+
extraAuthParams: candidate.extraAuthParams
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
return void 0;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export {
|
|
101
|
+
listBundledAdapterManifests,
|
|
102
|
+
getBundledAdapterManifest,
|
|
103
|
+
hasBundledAdapter,
|
|
104
|
+
listBundledAdapterKinds,
|
|
105
|
+
bundledAuthMode,
|
|
106
|
+
bundledApiKeyHint,
|
|
107
|
+
bundledOAuth2Auth
|
|
108
|
+
};
|
|
109
|
+
//# sourceMappingURL=chunk-PUXYDSXI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/connectors/bundled-manifests.ts"],"sourcesContent":["import {\n CONNECTOR_ADAPTER_FACTORIES,\n type ConnectorAdapterFactoryDefinition,\n} from './adapters/factories.js'\nimport * as bundledAdapters from './adapters/index.js'\nimport type { ConnectorAdapter, ConnectorManifest } from './types.js'\n\n/**\n * The bundled adapter registry — the single source of truth for \"which\n * connectors does this package actually implement, and how do they really\n * authenticate\".\n *\n * This exists because the answer was previously maintained by hand in two\n * places that drifted apart: `specs/registry.ts` carried an 18-name\n * `EXECUTABLE_KINDS` set while the package shipped 530 adapters, and the\n * platform kept its own private `collectBundledAdapters()` copy. A catalog\n * that describes connectors must derive from the connectors, never restate\n * them — restating is what let QuickBooks and Xero advertise a\n * `https://example.invalid/...` authorization URL behind a live Connect\n * button.\n *\n * Manifests are static data. Factory-style adapters need client credentials\n * to *execute*, but their manifest (auth endpoints, scopes, capability list)\n * is fixed at definition time, so we instantiate them with clearly-marked\n * placeholder options purely to read that static shape. The placeholders are\n * never used to make a request — {@link listBundledAdapterManifests} returns\n * manifests, not adapters.\n */\n\n/** Placeholder marker for factory options resolved only to read a manifest. */\nconst MANIFEST_PROBE_PREFIX = 'tangle-adapter-metadata-'\n\nfunction isConnectorAdapter(value: unknown): value is ConnectorAdapter {\n if (!value || typeof value !== 'object') return false\n const manifest = (value as { manifest?: unknown }).manifest\n if (!manifest || typeof manifest !== 'object') return false\n return typeof (manifest as { kind?: unknown }).kind === 'string'\n}\n\nfunction manifestFromFactory(\n definition: ConnectorAdapterFactoryDefinition,\n): ConnectorManifest | undefined {\n const probeOptions = Object.fromEntries(\n Object.keys(definition.envMap).map((name) => [name, `${MANIFEST_PROBE_PREFIX}${name}`]),\n )\n try {\n return definition.factory(probeOptions).manifest\n } catch {\n // A factory that cannot be constructed from placeholder options cannot\n // contribute a manifest. Skipping is correct: it means the adapter is not\n // describable without real credentials, so the catalog must not claim it.\n return undefined\n }\n}\n\nlet cachedManifests: ConnectorManifest[] | undefined\nlet cachedByKind: Map<string, ConnectorManifest> | undefined\n\nfunction buildRegistry(): Map<string, ConnectorManifest> {\n const byKind = new Map<string, ConnectorManifest>()\n for (const value of Object.values(bundledAdapters)) {\n if (isConnectorAdapter(value)) byKind.set(value.manifest.kind, value.manifest)\n }\n for (const definition of CONNECTOR_ADAPTER_FACTORIES) {\n if (byKind.has(definition.kind)) continue\n const manifest = manifestFromFactory(definition)\n if (manifest) byKind.set(manifest.kind, manifest)\n }\n return byKind\n}\n\nfunction registry(): Map<string, ConnectorManifest> {\n if (!cachedByKind) cachedByKind = buildRegistry()\n return cachedByKind\n}\n\n/** Every connector manifest this package bundles, sorted by kind. */\nexport function listBundledAdapterManifests(): ConnectorManifest[] {\n if (!cachedManifests) {\n cachedManifests = [...registry().values()].sort((a, b) => a.kind.localeCompare(b.kind))\n }\n return cachedManifests\n}\n\n/** The bundled manifest for `kind`, or undefined when nothing implements it. */\nexport function getBundledAdapterManifest(kind: string): ConnectorManifest | undefined {\n return registry().get(kind)\n}\n\n/** Whether this package ships a real, executable adapter for `kind`. */\nexport function hasBundledAdapter(kind: string): boolean {\n return registry().has(kind)\n}\n\n/** Kinds this package implements. */\nexport function listBundledAdapterKinds(): string[] {\n return listBundledAdapterManifests().map((manifest) => manifest.kind)\n}\n\n/**\n * How a bundled connector really authenticates.\n *\n * `oauth2_client_credentials` is called out separately because it IS a\n * connectable mode but has no user-facing authorize step — a caller that\n * treats \"oauth2 without an authorizationUrl\" as broken would wrongly condemn\n * these machine-to-machine providers.\n */\nexport type BundledAuthMode =\n | 'oauth2'\n | 'oauth2_client_credentials'\n | 'api_key'\n | 'hmac'\n | 'none'\n\n/** The auth mode a connect flow would actually drive for this manifest,\n * resolving `one_of` through its declared `preferred` mode. */\nexport function bundledAuthMode(manifest: ConnectorManifest): BundledAuthMode | undefined {\n const auth = manifest.auth\n const effective =\n auth.kind === 'one_of'\n ? (auth.options.find((option) => option.kind === auth.preferred) ?? auth.options[0])\n : auth\n switch (effective.kind) {\n case 'oauth2':\n return effective.grantType === 'client_credentials' ? 'oauth2_client_credentials' : 'oauth2'\n case 'api-key':\n return 'api_key'\n case 'hmac':\n return 'hmac'\n case 'none':\n return 'none'\n default:\n return undefined\n }\n}\n\n/** The setup hint an api-key connector shows when collecting its credential. */\nexport function bundledApiKeyHint(manifest: ConnectorManifest): string | undefined {\n const auth = manifest.auth\n const candidates = auth.kind === 'one_of' ? auth.options : [auth]\n for (const candidate of candidates) {\n if (candidate.kind === 'api-key') return candidate.hint\n }\n return undefined\n}\n\n/** The authorization-code OAuth2 branch of a manifest's auth spec, if it has\n * one. `one_of` manifests are resolved through their `preferred` mode, which\n * is the mode a connect flow would actually drive. Returns undefined for\n * api-key/hmac/none connectors and for `client_credentials` OAuth (which has\n * no user-facing authorize step). */\nexport function bundledOAuth2Auth(manifest: ConnectorManifest):\n | {\n authorizationUrl: string\n tokenUrl: string\n scopes: string[]\n clientIdEnv: string\n clientSecretEnv: string\n extraAuthParams?: Record<string, string>\n }\n | undefined {\n const auth = manifest.auth\n const candidates =\n auth.kind === 'one_of'\n ? auth.options.filter((option) => option.kind === auth.preferred)\n : [auth]\n for (const candidate of candidates) {\n if (candidate.kind !== 'oauth2') continue\n if (candidate.grantType === 'client_credentials') continue\n if (!candidate.authorizationUrl) continue\n return {\n authorizationUrl: candidate.authorizationUrl,\n tokenUrl: candidate.tokenUrl,\n scopes: candidate.scopes,\n clientIdEnv: candidate.clientIdEnv,\n clientSecretEnv: candidate.clientSecretEnv,\n extraAuthParams: candidate.extraAuthParams,\n }\n }\n return undefined\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1008,6 +1008,24 @@ function declarativeRestConnector(spec) {
|
|
|
1008
1008
|
async executeMutation(inv) {
|
|
1009
1009
|
const op = readOperation(spec, inv.capabilityName, "mutation");
|
|
1010
1010
|
const response = await executeRestRequest(spec, op.request, inv, requiredArgsOf(op.parameters));
|
|
1011
|
+
if (response.outcome === "conflict") {
|
|
1012
|
+
return {
|
|
1013
|
+
status: "conflict",
|
|
1014
|
+
alternatives: [],
|
|
1015
|
+
// The upstream's parsed body — the contract calls this "the current
|
|
1016
|
+
// authoritative state", so it must be what the provider returned,
|
|
1017
|
+
// not the transport's own wrapper.
|
|
1018
|
+
currentState: response.data,
|
|
1019
|
+
message: response.message || `${spec.displayName} rejected the write on a state conflict`
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
1022
|
+
if (response.outcome === "rate-limited") {
|
|
1023
|
+
return {
|
|
1024
|
+
status: "rate-limited",
|
|
1025
|
+
retryAfterMs: response.retryAfterMs ?? DEFAULT_RETRY_AFTER_MS,
|
|
1026
|
+
message: response.message || `${spec.displayName} throttled the write`
|
|
1027
|
+
};
|
|
1028
|
+
}
|
|
1011
1029
|
return {
|
|
1012
1030
|
status: "committed",
|
|
1013
1031
|
data: response.data,
|
|
@@ -1087,11 +1105,12 @@ async function executeRestRequest(spec, request, inv, requiredArgs) {
|
|
|
1087
1105
|
const awsRegion = aws ? resolveAwsRegion(aws, inv.source.metadata, placement) : void 0;
|
|
1088
1106
|
let baseUrl = resolveBaseUrl(spec.baseUrl, inv.source.metadata);
|
|
1089
1107
|
if (aws) baseUrl = applyRegionTemplate(baseUrl, awsRegion, aws.endpoint);
|
|
1090
|
-
const
|
|
1108
|
+
const scope = renderScope(inv);
|
|
1109
|
+
const renderedPath = interpolate(request.path, scope).replace(/^\/+/, "");
|
|
1091
1110
|
const baseWithSlash = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
|
|
1092
1111
|
const url = new URL(renderedPath, baseWithSlash);
|
|
1093
1112
|
for (const [key, value] of Object.entries(request.query ?? {})) {
|
|
1094
|
-
const rendered = renderQueryValue(value,
|
|
1113
|
+
const rendered = renderQueryValue(value, scope);
|
|
1095
1114
|
if (rendered !== void 0 && rendered !== "") url.searchParams.set(key, String(rendered));
|
|
1096
1115
|
}
|
|
1097
1116
|
const requestHeaders = request.headers ?? {};
|
|
@@ -1100,7 +1119,7 @@ async function executeRestRequest(spec, request, inv, requiredArgs) {
|
|
|
1100
1119
|
const headers = {
|
|
1101
1120
|
accept: "application/json",
|
|
1102
1121
|
...spec.defaultHeaders,
|
|
1103
|
-
...renderHeaders(renderableHeaders,
|
|
1122
|
+
...renderHeaders(renderableHeaders, scope)
|
|
1104
1123
|
};
|
|
1105
1124
|
if (hostOverride) url.host = hostOverride.replace(/\{region\}/g, awsRegion);
|
|
1106
1125
|
if (inv.expectedEtag) headers["if-match"] = inv.expectedEtag;
|
|
@@ -1108,7 +1127,7 @@ async function executeRestRequest(spec, request, inv, requiredArgs) {
|
|
|
1108
1127
|
if (sendsBody && getHeaderCI(headers, "content-type") === void 0) {
|
|
1109
1128
|
headers["content-type"] = "application/json";
|
|
1110
1129
|
}
|
|
1111
|
-
const bodyString = sendsBody ? JSON.stringify(resolveBody(request.body, inv.args, requiredArgs)) : void 0;
|
|
1130
|
+
const bodyString = sendsBody ? JSON.stringify(resolveBody(request.body, inv.args, scope, requiredArgs)) : void 0;
|
|
1112
1131
|
if (placement.kind === "aws-sigv4") {
|
|
1113
1132
|
signAwsRequest(headers, url, {
|
|
1114
1133
|
method: request.method,
|
|
@@ -1130,21 +1149,21 @@ async function executeRestRequest(spec, request, inv, requiredArgs) {
|
|
|
1130
1149
|
throw new CredentialsExpired(`${spec.displayName} rejected credentials (${res.status})`, inv.source.id);
|
|
1131
1150
|
}
|
|
1132
1151
|
if (res.status === 409 || res.status === 412) {
|
|
1152
|
+
const text2 = await safeErrorText(res);
|
|
1133
1153
|
return {
|
|
1134
|
-
data:
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
},
|
|
1154
|
+
data: parseBodyText(text2),
|
|
1155
|
+
outcome: "conflict",
|
|
1156
|
+
message: text2,
|
|
1138
1157
|
etag: res.headers.get("etag") ?? void 0
|
|
1139
1158
|
};
|
|
1140
1159
|
}
|
|
1141
1160
|
if (res.status === 429) {
|
|
1161
|
+
const text2 = await safeErrorText(res);
|
|
1142
1162
|
return {
|
|
1143
|
-
data:
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
}
|
|
1163
|
+
data: parseBodyText(text2),
|
|
1164
|
+
outcome: "rate-limited",
|
|
1165
|
+
message: text2,
|
|
1166
|
+
retryAfterMs: retryAfterMsFromHeader(res.headers.get("retry-after"))
|
|
1148
1167
|
};
|
|
1149
1168
|
}
|
|
1150
1169
|
if (request.existenceCheck && (res.status === 204 || res.status === 404)) {
|
|
@@ -1218,10 +1237,34 @@ function signAwsRequest(headers, url, opts) {
|
|
|
1218
1237
|
headers["x-amz-date"] = signed.amzDate;
|
|
1219
1238
|
headers.authorization = signed.authorization;
|
|
1220
1239
|
}
|
|
1221
|
-
function resolveBody(body, args, requiredArgs) {
|
|
1240
|
+
function resolveBody(body, args, scope, requiredArgs) {
|
|
1222
1241
|
if (!body || body === "args") return args;
|
|
1223
|
-
if (typeof body === "string") return renderValue(body,
|
|
1224
|
-
return renderObject(body,
|
|
1242
|
+
if (typeof body === "string") return renderValue(body, scope, requiredArgs);
|
|
1243
|
+
return renderObject(body, scope, requiredArgs);
|
|
1244
|
+
}
|
|
1245
|
+
var DEFAULT_RETRY_AFTER_MS = 6e4;
|
|
1246
|
+
var MIN_RETRY_AFTER_MS = 1e3;
|
|
1247
|
+
function parseBodyText(text) {
|
|
1248
|
+
if (!text) return null;
|
|
1249
|
+
try {
|
|
1250
|
+
return JSON.parse(text);
|
|
1251
|
+
} catch {
|
|
1252
|
+
return { raw: text };
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
function retryAfterMsFromHeader(raw) {
|
|
1256
|
+
if (typeof raw === "string" && raw.trim()) {
|
|
1257
|
+
const seconds = Number(raw);
|
|
1258
|
+
if (Number.isFinite(seconds) && seconds >= 0) {
|
|
1259
|
+
return Math.max(MIN_RETRY_AFTER_MS, Math.round(seconds * 1e3));
|
|
1260
|
+
}
|
|
1261
|
+
const at = Date.parse(raw);
|
|
1262
|
+
if (Number.isFinite(at)) return Math.max(MIN_RETRY_AFTER_MS, at - Date.now());
|
|
1263
|
+
}
|
|
1264
|
+
return DEFAULT_RETRY_AFTER_MS;
|
|
1265
|
+
}
|
|
1266
|
+
function renderScope(inv) {
|
|
1267
|
+
return { ...inv.args, connection: inv.source.metadata };
|
|
1225
1268
|
}
|
|
1226
1269
|
function renderHeaders(headers, args) {
|
|
1227
1270
|
return Object.fromEntries(Object.entries(headers).map(([key, value]) => [key, interpolate(value, args)]));
|
|
@@ -18364,8 +18407,71 @@ var quickbooksConnector = declarativeRestConnector({
|
|
|
18364
18407
|
defaultHeaders: {
|
|
18365
18408
|
accept: "application/json"
|
|
18366
18409
|
},
|
|
18367
|
-
|
|
18410
|
+
// `realmId` is pinned at connect time, not passed per call, so the health
|
|
18411
|
+
// check reads it from connection metadata. Written as `{realmId}` it resolved
|
|
18412
|
+
// against the (empty) test argument map and threw before any request was
|
|
18413
|
+
// made — the connection test could never pass, for any connection.
|
|
18414
|
+
test: { method: "GET", path: "companyinfo/{connection.realmId}", query: { minorversion: "70" } },
|
|
18368
18415
|
capabilities: [
|
|
18416
|
+
{
|
|
18417
|
+
// The reports namespace is NOT reachable through `entities.query` — QBO
|
|
18418
|
+
// exposes the accountant-grade statements only under /reports/{name}.
|
|
18419
|
+
// These four are the tax/bookkeeping read surface; without them a tax
|
|
18420
|
+
// agent can enumerate ledger rows but cannot obtain a P&L or a balance
|
|
18421
|
+
// sheet, which is what a return is actually built from.
|
|
18422
|
+
name: "reports.get",
|
|
18423
|
+
class: "read",
|
|
18424
|
+
description: "Run a QuickBooks Online report. `reportName` is the QBO report id (ProfitAndLoss, BalanceSheet, TrialBalance, GeneralLedger, CashFlow, AgedReceivables, AgedPayables).",
|
|
18425
|
+
parameters: {
|
|
18426
|
+
type: "object",
|
|
18427
|
+
properties: {
|
|
18428
|
+
reportName: {
|
|
18429
|
+
type: "string",
|
|
18430
|
+
enum: [
|
|
18431
|
+
"ProfitAndLoss",
|
|
18432
|
+
"BalanceSheet",
|
|
18433
|
+
"TrialBalance",
|
|
18434
|
+
"GeneralLedger",
|
|
18435
|
+
"CashFlow",
|
|
18436
|
+
"AgedReceivables",
|
|
18437
|
+
"AgedPayables"
|
|
18438
|
+
]
|
|
18439
|
+
},
|
|
18440
|
+
start_date: { type: "string", description: "YYYY-MM-DD (inclusive)." },
|
|
18441
|
+
end_date: { type: "string", description: "YYYY-MM-DD (inclusive)." },
|
|
18442
|
+
accounting_method: { type: "string", enum: ["Cash", "Accrual"] },
|
|
18443
|
+
date_macro: { type: "string", description: 'e.g. "Last Fiscal Year" \u2014 alternative to start/end dates.' },
|
|
18444
|
+
summarize_column_by: { type: "string", description: "e.g. Month, Quarter, Year, Total." },
|
|
18445
|
+
minorversion: { type: "string" }
|
|
18446
|
+
},
|
|
18447
|
+
required: ["reportName"]
|
|
18448
|
+
},
|
|
18449
|
+
request: {
|
|
18450
|
+
method: "GET",
|
|
18451
|
+
path: "reports/{reportName}",
|
|
18452
|
+
query: {
|
|
18453
|
+
start_date: "{start_date}",
|
|
18454
|
+
end_date: "{end_date}",
|
|
18455
|
+
accounting_method: "{accounting_method}",
|
|
18456
|
+
date_macro: "{date_macro}",
|
|
18457
|
+
summarize_column_by: "{summarize_column_by}",
|
|
18458
|
+
minorversion: "{minorversion}"
|
|
18459
|
+
}
|
|
18460
|
+
},
|
|
18461
|
+
requiredScopes: ["com.intuit.quickbooks.accounting"]
|
|
18462
|
+
},
|
|
18463
|
+
{
|
|
18464
|
+
name: "companyinfo.get",
|
|
18465
|
+
class: "read",
|
|
18466
|
+
description: "Read the connected QuickBooks company profile (legal name, EIN/company id, fiscal year start, country) for the realm this connection was authorized against.",
|
|
18467
|
+
parameters: { type: "object", properties: { minorversion: { type: "string" } } },
|
|
18468
|
+
request: {
|
|
18469
|
+
method: "GET",
|
|
18470
|
+
path: "companyinfo/{connection.realmId}",
|
|
18471
|
+
query: { minorversion: "{minorversion}" }
|
|
18472
|
+
},
|
|
18473
|
+
requiredScopes: ["com.intuit.quickbooks.accounting"]
|
|
18474
|
+
},
|
|
18369
18475
|
{
|
|
18370
18476
|
name: "entities.query",
|
|
18371
18477
|
class: "read",
|
|
@@ -18722,7 +18828,15 @@ var xeroConnector = declarativeRestConnector({
|
|
|
18722
18828
|
kind: "oauth2",
|
|
18723
18829
|
authorizationUrl: "https://login.xero.com/identity/connect/authorize",
|
|
18724
18830
|
tokenUrl: "https://identity.xero.com/connect/token",
|
|
18725
|
-
|
|
18831
|
+
// `accounting.reports.read` is a distinct Xero scope — the reports
|
|
18832
|
+
// namespace is not covered by settings/transactions and 403s without it.
|
|
18833
|
+
scopes: [
|
|
18834
|
+
"offline_access",
|
|
18835
|
+
"accounting.contacts",
|
|
18836
|
+
"accounting.transactions",
|
|
18837
|
+
"accounting.settings.read",
|
|
18838
|
+
"accounting.reports.read"
|
|
18839
|
+
],
|
|
18726
18840
|
clientIdEnv: "XERO_OAUTH_CLIENT_ID",
|
|
18727
18841
|
clientSecretEnv: "XERO_OAUTH_CLIENT_SECRET"
|
|
18728
18842
|
},
|
|
@@ -18732,6 +18846,54 @@ var xeroConnector = declarativeRestConnector({
|
|
|
18732
18846
|
defaultHeaders: { accept: "application/json" },
|
|
18733
18847
|
test: { method: "GET", path: "/connections" },
|
|
18734
18848
|
capabilities: [
|
|
18849
|
+
{
|
|
18850
|
+
// Every other Xero capability REQUIRES `tenantId`, and a tenant id is an
|
|
18851
|
+
// opaque GUID no caller can know before asking. Without this read the
|
|
18852
|
+
// connector is unusable by an agent: the only place the id appeared was
|
|
18853
|
+
// the health check, which discards its body.
|
|
18854
|
+
name: "tenants.list",
|
|
18855
|
+
class: "read",
|
|
18856
|
+
description: "List the Xero organizations (tenants) this connection is authorized for. Call this FIRST \u2014 every other Xero capability requires the `tenantId` returned here.",
|
|
18857
|
+
parameters: { type: "object", properties: {} },
|
|
18858
|
+
request: { method: "GET", path: "/connections" }
|
|
18859
|
+
},
|
|
18860
|
+
{
|
|
18861
|
+
// Xero's reporting surface, like QBO's, is a separate namespace from the
|
|
18862
|
+
// record endpoints. These are the statements a return or a books review
|
|
18863
|
+
// is actually built from.
|
|
18864
|
+
name: "reports.get",
|
|
18865
|
+
class: "read",
|
|
18866
|
+
description: "Run a Xero accounting report. `reportName` is the Xero report id (ProfitAndLoss, BalanceSheet, TrialBalance, BankSummary, AgedReceivablesByContact, AgedPayablesByContact).",
|
|
18867
|
+
parameters: {
|
|
18868
|
+
type: "object",
|
|
18869
|
+
properties: {
|
|
18870
|
+
tenantId: { type: "string", description: "From tenants.list." },
|
|
18871
|
+
reportName: {
|
|
18872
|
+
type: "string",
|
|
18873
|
+
enum: [
|
|
18874
|
+
"ProfitAndLoss",
|
|
18875
|
+
"BalanceSheet",
|
|
18876
|
+
"TrialBalance",
|
|
18877
|
+
"BankSummary",
|
|
18878
|
+
"AgedReceivablesByContact",
|
|
18879
|
+
"AgedPayablesByContact"
|
|
18880
|
+
]
|
|
18881
|
+
},
|
|
18882
|
+
fromDate: { type: "string", description: "YYYY-MM-DD." },
|
|
18883
|
+
toDate: { type: "string", description: "YYYY-MM-DD." },
|
|
18884
|
+
date: { type: "string", description: "YYYY-MM-DD \u2014 point-in-time reports (BalanceSheet, TrialBalance)." },
|
|
18885
|
+
contactId: { type: "string", description: "Required by the aged receivables/payables reports." }
|
|
18886
|
+
},
|
|
18887
|
+
required: ["tenantId", "reportName"]
|
|
18888
|
+
},
|
|
18889
|
+
request: {
|
|
18890
|
+
method: "GET",
|
|
18891
|
+
path: "/api.xro/2.0/Reports/{reportName}",
|
|
18892
|
+
query: { fromDate: "{fromDate}", toDate: "{toDate}", date: "{date}", contactID: "{contactId}" },
|
|
18893
|
+
headers: { "xero-tenant-id": "{tenantId}" }
|
|
18894
|
+
},
|
|
18895
|
+
requiredScopes: ["accounting.reports.read"]
|
|
18896
|
+
},
|
|
18735
18897
|
{
|
|
18736
18898
|
name: "contacts.search",
|
|
18737
18899
|
class: "read",
|
|
@@ -125794,4 +125956,4 @@ export {
|
|
|
125794
125956
|
demandbaseConnector,
|
|
125795
125957
|
adapters_exports
|
|
125796
125958
|
};
|
|
125797
|
-
//# sourceMappingURL=chunk-
|
|
125959
|
+
//# sourceMappingURL=chunk-XEJKVCXB.js.map
|