@composio/client 2.0.0-rc.17 → 2.0.0-rc.19
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/README.md +136 -40
- package/dist/{api-key-revocation-lc3308Ao.mjs → api-key-revocation-DMCgun-A.mjs} +1 -1
- package/dist/{auth-DkGiEaxg.mjs → auth-D-U9Aq8C.mjs} +1 -1
- package/dist/{auth-configs-DbxqGahP.mjs → auth-configs-DAG5mMeH.mjs} +1 -1
- package/dist/{clanker-fK9cAkTz.mjs → clanker-Yomp86hJ.mjs} +1 -1
- package/dist/{cli-K1MskpaR.mjs → cli-zihiw3aI.mjs} +4 -5
- package/dist/{connected-accounts-Bfl7_SY_.mjs → connected-accounts-Bd4AbWoH.mjs} +1 -1
- package/dist/{consumer-5o2zMQwr.mjs → consumer-Bk0cyIii.mjs} +6 -7
- package/dist/{custom-8rs-sHnb.mjs → custom-Ce8G2c11.mjs} +1 -1
- package/dist/{custom-wEkSiPHn.mjs → custom-DWT3cCog.mjs} +1 -1
- package/dist/effect.d.mts +29 -42
- package/dist/effect.mjs +217 -192
- package/dist/{error-D9cG225M.mjs → error-Bw7_G2NZ.mjs} +1 -1
- package/dist/{files-BPKJXlpc.mjs → files-DRp_J4zH.mjs} +1 -1
- package/dist/{files-BjPFzRnM.mjs → files-ZxEVlE_y.mjs} +1 -1
- package/dist/{generate-DDHNgbPS.mjs → generate-Du9XUrlx.mjs} +1 -1
- package/dist/{generated-deprecated-inputs--L5LHDO_.mjs → generated-deprecated-inputs-Dy_lBver.mjs} +2 -2
- package/dist/{generated-operations-D1e__yar.mjs → generated-operations-Dv7pAKDT.mjs} +354 -226
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +104 -154
- package/dist/{keyring-Dkm6DQIp.mjs → keyring-CgOIS5x7.mjs} +1 -1
- package/dist/{link-BBU-J5L_.mjs → link-CW1ts4pm.mjs} +1 -1
- package/dist/{logs-CuuysWk1.mjs → logs-DFdH5DoT.mjs} +3 -3
- package/dist/{manage-B1R7I3ZM.mjs → manage-CeB03gO8.mjs} +1 -1
- package/dist/{mcp-C3beSy48.mjs → mcp-DNRMWWum.mjs} +3 -3
- package/dist/{org-B13XOuKh.mjs → org-HuYaKgVf.mjs} +6 -6
- package/dist/{owner-BAr5uwk3.mjs → owner-I9fXmIO_.mjs} +1 -1
- package/dist/{pagination-rules-uMUdPq_7.mjs → pagination-rules-CMnBwktJ.mjs} +1 -1
- package/dist/pagination.mjs +1 -1
- package/dist/{project-CDm8tjUw.mjs → project-CxQ2H8UB.mjs} +1 -1
- package/dist/{project-DF5KclHm.mjs → project-DcV01umC.mjs} +4 -7
- package/dist/{project-BbCgXD83.mjs → project-Dwblmpw8.mjs} +1 -1
- package/dist/{project-C30H_5b6.mjs → project-FuP5k9R1.mjs} +1 -1
- package/dist/{realtime-6LigMh83.mjs → realtime-F_sGuTd8.mjs} +1 -1
- package/dist/resources/api-key-revocation.d.mts +1 -1
- package/dist/resources/api-key-revocation.mjs +1 -1
- package/dist/resources/auth/auth.d.mts +1 -1
- package/dist/resources/auth/auth.mjs +1 -1
- package/dist/resources/auth/index.d.mts +1 -1
- package/dist/resources/auth/index.mjs +2 -2
- package/dist/resources/auth/session.d.mts +1 -1
- package/dist/resources/auth/session.mjs +1 -1
- package/dist/resources/auth-configs.d.mts +1 -1
- package/dist/resources/auth-configs.mjs +1 -1
- package/dist/resources/auth.d.mts +1 -1
- package/dist/resources/auth.mjs +2 -2
- package/dist/resources/cli/cli.d.mts +1 -1
- package/dist/resources/cli/cli.mjs +1 -1
- package/dist/resources/cli/index.d.mts +1 -1
- package/dist/resources/cli/index.mjs +2 -2
- package/dist/resources/cli/realtime.d.mts +1 -1
- package/dist/resources/cli/realtime.mjs +1 -1
- package/dist/resources/cli.d.mts +1 -1
- package/dist/resources/cli.mjs +2 -2
- package/dist/resources/connected-accounts.d.mts +1 -1
- package/dist/resources/connected-accounts.mjs +1 -1
- package/dist/resources/custom.d.mts +1 -1
- package/dist/resources/custom.mjs +1 -1
- package/dist/resources/files.d.mts +1 -1
- package/dist/resources/files.mjs +1 -1
- package/dist/resources/index.d.mts +1 -1
- package/dist/resources/index.mjs +13 -13
- package/dist/resources/keyring.d.mts +1 -1
- package/dist/resources/keyring.mjs +1 -1
- package/dist/resources/link.d.mts +1 -1
- package/dist/resources/link.mjs +1 -1
- package/dist/resources/logs/index.d.mts +1 -1
- package/dist/resources/logs/index.mjs +3 -3
- package/dist/resources/logs/logs.d.mts +1 -1
- package/dist/resources/logs/logs.mjs +1 -1
- package/dist/resources/logs/tools.d.mts +1 -1
- package/dist/resources/logs/tools.mjs +1 -1
- package/dist/resources/logs/triggers.d.mts +1 -1
- package/dist/resources/logs/triggers.mjs +1 -1
- package/dist/resources/logs.d.mts +1 -1
- package/dist/resources/logs.mjs +3 -3
- package/dist/resources/mcp/custom.d.mts +1 -1
- package/dist/resources/mcp/custom.mjs +1 -1
- package/dist/resources/mcp/generate.d.mts +1 -1
- package/dist/resources/mcp/generate.mjs +1 -1
- package/dist/resources/mcp/index.d.mts +1 -1
- package/dist/resources/mcp/index.mjs +3 -3
- package/dist/resources/mcp/mcp.d.mts +1 -1
- package/dist/resources/mcp/mcp.mjs +1 -1
- package/dist/resources/mcp.d.mts +1 -1
- package/dist/resources/mcp.mjs +3 -3
- package/dist/resources/org/clanker.d.mts +1 -1
- package/dist/resources/org/clanker.mjs +1 -1
- package/dist/resources/org/consumer/consumer.d.mts +1 -1
- package/dist/resources/org/consumer/consumer.mjs +1 -1
- package/dist/resources/org/consumer/index.d.mts +1 -1
- package/dist/resources/org/consumer/index.mjs +2 -2
- package/dist/resources/org/consumer/project.d.mts +1 -1
- package/dist/resources/org/consumer/project.mjs +1 -1
- package/dist/resources/org/consumer.d.mts +1 -1
- package/dist/resources/org/consumer.mjs +2 -2
- package/dist/resources/org/index.d.mts +1 -1
- package/dist/resources/org/index.mjs +6 -6
- package/dist/resources/org/org.d.mts +1 -1
- package/dist/resources/org/org.mjs +1 -1
- package/dist/resources/org/owner/index.d.mts +1 -1
- package/dist/resources/org/owner/index.mjs +2 -2
- package/dist/resources/org/owner/owner.d.mts +1 -1
- package/dist/resources/org/owner/owner.mjs +1 -1
- package/dist/resources/org/owner/project.d.mts +1 -1
- package/dist/resources/org/owner/project.mjs +1 -1
- package/dist/resources/org/owner.d.mts +1 -1
- package/dist/resources/org/owner.mjs +2 -2
- package/dist/resources/org/project.d.mts +1 -1
- package/dist/resources/org/project.mjs +1 -1
- package/dist/resources/org/usage.d.mts +1 -1
- package/dist/resources/org/usage.mjs +1 -1
- package/dist/resources/org.d.mts +1 -1
- package/dist/resources/org.mjs +6 -6
- package/dist/resources/project/index.d.mts +1 -1
- package/dist/resources/project/index.mjs +1 -1
- package/dist/resources/project/project.d.mts +1 -1
- package/dist/resources/project/project.mjs +1 -1
- package/dist/resources/project/usage.d.mts +1 -1
- package/dist/resources/project/usage.mjs +1 -1
- package/dist/resources/project.d.mts +1 -1
- package/dist/resources/project.mjs +1 -1
- package/dist/resources/session-configs.d.mts +1 -1
- package/dist/resources/session-configs.mjs +1 -1
- package/dist/resources/tool-router/index.d.mts +1 -1
- package/dist/resources/tool-router/index.mjs +2 -2
- package/dist/resources/tool-router/session/files.d.mts +1 -1
- package/dist/resources/tool-router/session/files.mjs +1 -1
- package/dist/resources/tool-router/session/index.d.mts +1 -1
- package/dist/resources/tool-router/session/index.mjs +2 -2
- package/dist/resources/tool-router/session/session.d.mts +1 -1
- package/dist/resources/tool-router/session/session.mjs +1 -1
- package/dist/resources/tool-router/session.d.mts +1 -1
- package/dist/resources/tool-router/session.mjs +2 -2
- package/dist/resources/tool-router/tool-router.d.mts +1 -1
- package/dist/resources/tool-router/tool-router.mjs +1 -1
- package/dist/resources/tool-router.d.mts +1 -1
- package/dist/resources/tool-router.mjs +2 -2
- package/dist/resources/toolkits.d.mts +1 -1
- package/dist/resources/toolkits.mjs +1 -1
- package/dist/resources/tools.d.mts +1 -1
- package/dist/resources/tools.mjs +1 -1
- package/dist/resources/trigger-instances/index.d.mts +1 -1
- package/dist/resources/trigger-instances/index.mjs +2 -2
- package/dist/resources/trigger-instances/manage.d.mts +1 -1
- package/dist/resources/trigger-instances/manage.mjs +1 -1
- package/dist/resources/trigger-instances/trigger-instances.d.mts +1 -1
- package/dist/resources/trigger-instances/trigger-instances.mjs +1 -1
- package/dist/resources/trigger-instances.d.mts +1 -1
- package/dist/resources/trigger-instances.mjs +2 -2
- package/dist/resources/triggers-types.d.mts +1 -1
- package/dist/resources/triggers-types.mjs +1 -1
- package/dist/resources/webhook-endpoints.d.mts +1 -1
- package/dist/resources/webhook-endpoints.mjs +1 -1
- package/dist/resources/webhook-subscriptions.d.mts +1 -1
- package/dist/resources/webhook-subscriptions.mjs +1 -1
- package/dist/{session-Dm8WtF4I.mjs → session-B-ifOjVv.mjs} +1 -1
- package/dist/{session-DEfDnHZZ.mjs → session-CpwJh7Hn.mjs} +2 -2
- package/dist/{session-configs-nA6TL_i4.d.mts → session-configs-BLy_O6bX.d.mts} +131 -134
- package/dist/{tool-router-6l_dREjC.mjs → tool-router-jNsaldKV.mjs} +1 -1
- package/dist/{toolkits-Mn_uLV98.mjs → toolkits-DK4My9FW.mjs} +1 -1
- package/dist/{tools-z-PjBsf7.mjs → tools-DNkimllW.mjs} +1 -1
- package/dist/{tools-btk0mzFP.mjs → tools-Gun_2We6.mjs} +1 -1
- package/dist/{trigger-instances-PQaObQQy.mjs → trigger-instances-vvKswQSW.mjs} +2 -2
- package/dist/{triggers-y0mi0XzT.mjs → triggers-CfrGxKIo.mjs} +1 -1
- package/dist/{triggers-types-KoRbT0k5.mjs → triggers-types-DYW2Mr8z.mjs} +1 -1
- package/dist/{usage-DvjkSmpI.mjs → usage-YIBYNpVF.mjs} +1 -1
- package/dist/{usage-B2Z947BK.mjs → usage-vt9HmnNf.mjs} +1 -1
- package/dist/version-DB98yI2B.d.mts +4 -0
- package/dist/{webhook-endpoints-kf4Jj2Mz.mjs → webhook-endpoints-HqLteVW6.mjs} +1 -1
- package/dist/{webhook-subscriptions-DcYN8qo1.mjs → webhook-subscriptions-CXhNXIOM.mjs} +1 -1
- package/package.json +2 -2
- package/dist/version-DUxhnnPj.d.mts +0 -4
|
@@ -1,78 +1,5 @@
|
|
|
1
|
-
import { i as APIUserAbortError, n as APIConnectionTimeoutError, s as ComposioError, t as APIConnectionError } from "./error-
|
|
1
|
+
import { i as APIUserAbortError, n as APIConnectionTimeoutError, s as ComposioError, t as APIConnectionError } from "./error-Bw7_G2NZ.mjs";
|
|
2
2
|
|
|
3
|
-
//#region src/compat/headers.ts
|
|
4
|
-
const hasEntries = (value) => typeof value === "object" && value !== null && "append" in value && typeof value.append === "function" && "delete" in value && typeof value.delete === "function" && "entries" in value && typeof value.entries === "function" && "get" in value && typeof value.get === "function";
|
|
5
|
-
const isHeaders = (value) => value instanceof Headers || hasEntries(value);
|
|
6
|
-
const isNullableHeadersLike = (headers) => {
|
|
7
|
-
if (!("values" in headers) || !isHeaders(headers.values) || !("nulls" in headers)) return false;
|
|
8
|
-
const nulls = headers.nulls;
|
|
9
|
-
return typeof nulls === "object" && nulls !== null && Symbol.iterator in nulls;
|
|
10
|
-
};
|
|
11
|
-
/**
|
|
12
|
-
* Iterates every supported input while preserving explicit deletions. Plain
|
|
13
|
-
* objects replace an older value for a key; tuple inputs append duplicate
|
|
14
|
-
* values, matching the published client.
|
|
15
|
-
*/
|
|
16
|
-
function* iterateHeaders(headers) {
|
|
17
|
-
if (!headers) return;
|
|
18
|
-
if (isNullableHeadersLike(headers)) {
|
|
19
|
-
yield* headers.values.entries();
|
|
20
|
-
for (const name of headers.nulls) yield [name, null];
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
const shouldReplace = !isHeaders(headers) && !Array.isArray(headers);
|
|
24
|
-
const entries = isHeaders(headers) ? headers.entries() : Array.isArray(headers) ? headers : Object.entries(headers);
|
|
25
|
-
for (const entry of entries) {
|
|
26
|
-
const name = entry[0];
|
|
27
|
-
if (typeof name !== "string") throw new TypeError("expected header name to be a string");
|
|
28
|
-
const rawValue = entry[1];
|
|
29
|
-
const values = Array.isArray(rawValue) ? rawValue : [rawValue];
|
|
30
|
-
let replaced = false;
|
|
31
|
-
for (const value of values) {
|
|
32
|
-
if (value === void 0) continue;
|
|
33
|
-
if (shouldReplace && !replaced) {
|
|
34
|
-
replaced = true;
|
|
35
|
-
yield [name, null];
|
|
36
|
-
}
|
|
37
|
-
yield [name, value];
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
/** Merge sources while retaining names explicitly deleted by the last source. */
|
|
42
|
-
const mergeHeaders = (sources) => {
|
|
43
|
-
const values = new Headers();
|
|
44
|
-
const nulls = /* @__PURE__ */ new Set();
|
|
45
|
-
for (const source of sources) {
|
|
46
|
-
if (!source) continue;
|
|
47
|
-
const seen = /* @__PURE__ */ new Set();
|
|
48
|
-
for (const [name, value] of iterateHeaders(source)) {
|
|
49
|
-
const lowerName = name.toLowerCase();
|
|
50
|
-
if (!seen.has(lowerName)) {
|
|
51
|
-
values.delete(name);
|
|
52
|
-
seen.add(lowerName);
|
|
53
|
-
}
|
|
54
|
-
if (value === null) {
|
|
55
|
-
values.delete(name);
|
|
56
|
-
nulls.add(lowerName);
|
|
57
|
-
} else {
|
|
58
|
-
values.append(name, value);
|
|
59
|
-
nulls.delete(lowerName);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
return {
|
|
64
|
-
values,
|
|
65
|
-
nulls
|
|
66
|
-
};
|
|
67
|
-
};
|
|
68
|
-
/** Merge sources into the native header collection sent to fetch. */
|
|
69
|
-
const buildHeaders = (sources) => mergeHeaders(sources).values;
|
|
70
|
-
/** Every header name a source mentions, lowercased, a `null` deletion included. */
|
|
71
|
-
function* headerNames(headers) {
|
|
72
|
-
for (const [name] of iterateHeaders(headers)) yield name.toLowerCase();
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
//#endregion
|
|
76
3
|
//#region src/compat/credentials.ts
|
|
77
4
|
/**
|
|
78
5
|
* The credential transport boundary.
|
|
@@ -94,8 +21,8 @@ function* headerNames(headers) {
|
|
|
94
21
|
* caller opts into with `allowInsecureHTTP` or
|
|
95
22
|
* `COMPOSIO_ALLOW_INSECURE_HTTP=1`.
|
|
96
23
|
* Enforced by {@link assertCredentialTransport} at construction and again
|
|
97
|
-
* by {@link credentialForRequest} at dispatch, because `
|
|
98
|
-
*
|
|
24
|
+
* by {@link credentialForRequest} at dispatch, because `baseURL` is a
|
|
25
|
+
* public mutable field on the client.
|
|
99
26
|
* 2. **The credential is attached only to requests whose origin matches the
|
|
100
27
|
* configured API origin.** {@link credentialForRequest} returns `null`
|
|
101
28
|
* off-origin, and the header is simply not sent.
|
|
@@ -158,70 +85,25 @@ const SCHEME_HEADERS = {
|
|
|
158
85
|
};
|
|
159
86
|
/** The scheme a request authenticates with when its operation names none. */
|
|
160
87
|
const DEFAULT_SCHEME = "ApiKeyAuth";
|
|
161
|
-
const valueFor = (scheme, credentials) => scheme === "ApiKeyAuth" ? credentials.apiKey : scheme === "UserApiKeyAuth" ? credentials.userApiKey : credentials.orgApiKey;
|
|
162
88
|
/**
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
* and the fallback is `ApiKeyAuth` again. So the client that every existing
|
|
170
|
-
* caller constructs never consults the operation table, and "an `apiKey`-only
|
|
171
|
-
* client emits byte-identical requests on all 104 operations" is a property of
|
|
172
|
-
* the code shape rather than a claim tests have to keep re-establishing.
|
|
173
|
-
*/
|
|
174
|
-
const hasAlternateCredential = (credentials) => credentials.userApiKey !== null || credentials.orgApiKey !== null;
|
|
175
|
-
/**
|
|
176
|
-
* Which credential a request declaring `schemes` should carry.
|
|
177
|
-
*
|
|
178
|
-
* **Exactly one, always** — and the API says so itself. Measured against
|
|
179
|
-
* production on 2026-08-06, `GET /toolkits` answers 200 for `x-api-key` alone
|
|
180
|
-
* and 200 for `x-user-api-key` alone, and answers both together with
|
|
181
|
-
* `401 HTTP_Unauthorized`:
|
|
182
|
-
*
|
|
183
|
-
* > Multiple authentication modes were provided. Provide exactly one
|
|
184
|
-
* > authentication mode per request. Provided: ApiKeyAuth via x-api-key,
|
|
185
|
-
* > UserApiKeyAuth via x-user-api-key.
|
|
186
|
-
*
|
|
187
|
-
* The platform names the schemes by their OpenAPI names, so this is the same
|
|
188
|
-
* vocabulary `security` is written in rather than a coincidence of headers. It
|
|
189
|
-
* holds for `x-api-key` + `x-org-api-key` too, and on an operation that accepts
|
|
190
|
-
* only one of them. There is therefore no additive "send the user key as well"
|
|
191
|
-
* model available, and the choice has to be made per request rather than
|
|
192
|
-
* accumulated.
|
|
193
|
-
*
|
|
194
|
-
* The precedence exists to make the change free where it must be free:
|
|
195
|
-
*
|
|
196
|
-
* 1. **`ApiKeyAuth` wins wherever the operation accepts it** and an `apiKey` is
|
|
197
|
-
* configured — 85 of the 104 operations, every wire byte preserved.
|
|
198
|
-
* 2. Otherwise the first scheme the operation names that this client both
|
|
199
|
-
* recognizes *and* holds a credential for. That is what makes the 16
|
|
200
|
-
* `UserApiKeyAuth`-only and `OrgApiKeyAuth`-only operations reachable.
|
|
201
|
-
* 3. Otherwise `ApiKeyAuth`, which is what this client did before any of this
|
|
202
|
-
* existed. A `UserApiKeyAuth`-only operation called by a client with no user
|
|
203
|
-
* key still sends `x-api-key` and still fails the same way — which is what
|
|
204
|
-
* keeps `cli.realtime.auth` and `cli.realtime.credentials` pinned against
|
|
205
|
-
* the Stainless oracle in `test/unit/differential-wire.test.ts`.
|
|
206
|
-
*
|
|
207
|
-
* Rule 3 is also where a scheme name this client does not know lands. Three of
|
|
208
|
-
* them exist: `security` references `no_auth` (3 operations) and
|
|
209
|
-
* `workbench_access_key` (1) and `components.securitySchemes` declares neither.
|
|
210
|
-
* Those four operations receive `x-api-key` today and are differentially
|
|
211
|
-
* pinned doing so, so resolving an unknown name to "no credential" would be a
|
|
212
|
-
* wire change made on the strength of a spec defect. A later generator pass
|
|
213
|
-
* must not "fix" that.
|
|
89
|
+
* `Auth.auto`'s choice for an operation declaring `schemes`: `ApiKeyAuth`
|
|
90
|
+
* wherever the operation accepts it and a project key is held, else the first
|
|
91
|
+
* declared scheme that is held, else `ApiKeyAuth`. An undeclared scheme name
|
|
92
|
+
* (`no_auth`, `workbench_access_key`) falls through to `ApiKeyAuth`, as every
|
|
93
|
+
* release before rc.18 sent. A request may carry only one credential: the API
|
|
94
|
+
* answers two with a 401.
|
|
214
95
|
*/
|
|
215
|
-
const selectScheme = (schemes,
|
|
96
|
+
const selectScheme = (schemes, held) => {
|
|
216
97
|
if (schemes === void 0 || schemes.length === 0) return DEFAULT_SCHEME;
|
|
217
|
-
if (schemes.includes(DEFAULT_SCHEME) &&
|
|
98
|
+
if (schemes.includes(DEFAULT_SCHEME) && held(DEFAULT_SCHEME)) return DEFAULT_SCHEME;
|
|
218
99
|
for (const scheme of schemes) {
|
|
219
100
|
if (!Object.hasOwn(SCHEME_HEADERS, scheme)) continue;
|
|
220
101
|
const known = scheme;
|
|
221
|
-
if (
|
|
102
|
+
if (held(known)) return known;
|
|
222
103
|
}
|
|
223
104
|
return DEFAULT_SCHEME;
|
|
224
105
|
};
|
|
106
|
+
const schemeOfHeader = (name) => Object.keys(SCHEME_HEADERS).find((scheme) => SCHEME_HEADERS[scheme] === name);
|
|
225
107
|
/**
|
|
226
108
|
* What counts as loopback, pinned rather than assumed. `localhost` is not the
|
|
227
109
|
* whole set:
|
|
@@ -275,9 +157,7 @@ const resolveHTTPURL = (target, base) => {
|
|
|
275
157
|
/** Whether a credential may be sent to this origin at all. */
|
|
276
158
|
const isCredentialSafeOrigin = (url, allowedHTTPOrigin = null) => url.protocol === "https:" || url.protocol === "http:" && (isLoopbackHostname(url.hostname) || allowedHTTPOrigin !== null && url.origin === allowedHTTPOrigin);
|
|
277
159
|
const LOOPBACK_DESCRIPTION = "localhost, *.localhost, 127.0.0.0/8, [::1]";
|
|
278
|
-
const insecureOriginMessage = (baseURL) => `Refusing to send a Composio API credential to ${baseURL}: a credentialed API origin must use HTTPS. By default, plain http:// is permitted only for loopback development endpoints (${LOOPBACK_DESCRIPTION}). Pass an https://
|
|
279
|
-
/** Whether the client holds anything at all that rule 1 has to protect. */
|
|
280
|
-
const anyCredential = (credentials) => credentials.apiKey !== null || hasAlternateCredential(credentials);
|
|
160
|
+
const insecureOriginMessage = (baseURL) => `Refusing to send a Composio API credential to ${baseURL}: a credentialed API origin must use HTTPS. By default, plain http:// is permitted only for loopback development endpoints (${LOOPBACK_DESCRIPTION}). Pass an https:// or loopback baseURL, set allowInsecureHTTP: true (or COMPOSIO_ALLOW_INSECURE_HTTP=1) for the configured development origin, or construct the client without credentials.`;
|
|
281
161
|
/**
|
|
282
162
|
* Rule 1 at construction time: a client that holds a credential must be
|
|
283
163
|
* pointed at an origin that can carry one. Knowable before any request is
|
|
@@ -286,13 +166,9 @@ const anyCredential = (credentials) => credentials.apiKey !== null || hasAlterna
|
|
|
286
166
|
* A `baseURL` that is not an absolute http(s) URL fails the same way — a
|
|
287
167
|
* credential cannot be sent over a scheme this client does not speak, and the
|
|
288
168
|
* alternative is a `TypeError` from `new URL()` one layer down.
|
|
289
|
-
*
|
|
290
|
-
* Every configured credential counts, not just `apiKey`: which one a given
|
|
291
|
-
* request carries is decided per operation, so a client holding *any* of them
|
|
292
|
-
* is a client that can put one on the wire.
|
|
293
169
|
*/
|
|
294
|
-
const assertCredentialTransport = (baseURL,
|
|
295
|
-
if (!
|
|
170
|
+
const assertCredentialTransport = (baseURL, credentialed, allowedHTTPOrigin = null) => {
|
|
171
|
+
if (!credentialed) return;
|
|
296
172
|
const url = parseHTTPURL(baseURL);
|
|
297
173
|
if (url === null || !isCredentialSafeOrigin(url, allowedHTTPOrigin)) throw new ComposioError(insecureOriginMessage(baseURL));
|
|
298
174
|
};
|
|
@@ -300,7 +176,7 @@ const assertCredentialTransport = (baseURL, credentials, allowedHTTPOrigin = nul
|
|
|
300
176
|
* The credential this request may carry, or `null` for none.
|
|
301
177
|
*
|
|
302
178
|
* Rules 1 and 2 at dispatch time. Both re-checks are load-bearing rather than
|
|
303
|
-
* belt-and-braces: `
|
|
179
|
+
* belt-and-braces: `baseURL` is a public mutable field, so the
|
|
304
180
|
* construction-time check can be invalidated by an assignment, and the request
|
|
305
181
|
* URL is *not* guaranteed to sit on the configured origin. `buildURL`
|
|
306
182
|
* concatenates `baseURL + path` and the escape hatch (`client.get(path)`)
|
|
@@ -314,18 +190,14 @@ const assertCredentialTransport = (baseURL, credentials, allowedHTTPOrigin = nul
|
|
|
314
190
|
* with credentials, so that one dies at the transport instead. httpx has no
|
|
315
191
|
* such objection, which is why the Python port checks the same thing.)
|
|
316
192
|
*/
|
|
317
|
-
const credentialForRequest = (baseURL,
|
|
318
|
-
|
|
319
|
-
if (value === null) return null;
|
|
193
|
+
const credentialForRequest = (baseURL, credential, requestURL, allowedHTTPOrigin = null) => {
|
|
194
|
+
if (credential === null) return null;
|
|
320
195
|
const base = parseHTTPURL(baseURL);
|
|
321
196
|
const target = parseHTTPURL(requestURL);
|
|
322
197
|
if (base === null || target === null) return null;
|
|
323
198
|
if (base.origin !== target.origin) return null;
|
|
324
199
|
if (!isCredentialSafeOrigin(target, allowedHTTPOrigin)) throw new ComposioError(insecureOriginMessage(baseURL));
|
|
325
|
-
return
|
|
326
|
-
name: SCHEME_HEADERS[scheme],
|
|
327
|
-
value
|
|
328
|
-
};
|
|
200
|
+
return credential;
|
|
329
201
|
};
|
|
330
202
|
/**
|
|
331
203
|
* Whether two absolute http(s) URLs share an origin, by the same test
|
|
@@ -337,34 +209,6 @@ const sameOrigin = (a, b) => {
|
|
|
337
209
|
return origin !== void 0 && origin === parseHTTPURL(b)?.origin;
|
|
338
210
|
};
|
|
339
211
|
/**
|
|
340
|
-
* The credential headers a *caller* can place that are not the one this client
|
|
341
|
-
* attaches — `x-api-key` is excluded because a caller setting it is overriding
|
|
342
|
-
* the client's own value in the same slot, which is pinned Stainless behaviour,
|
|
343
|
-
* not a second credential.
|
|
344
|
-
*/
|
|
345
|
-
const FOREIGN_CREDENTIAL_HEADERS = ["x-user-api-key", "x-org-api-key"];
|
|
346
|
-
/**
|
|
347
|
-
* Whether the caller has placed a credential of their own, in which case the
|
|
348
|
-
* client must not add one beside it.
|
|
349
|
-
*
|
|
350
|
-
* Not a courtesy: this API answers a request carrying two credential headers
|
|
351
|
-
* with `401 HTTP_Unauthorized`, so attaching `x-api-key` next to a caller's
|
|
352
|
-
* `x-user-api-key` does not weaken the call, it *breaks* it. Three released
|
|
353
|
-
* methods make that reachable without any `defaultHeaders` at all —
|
|
354
|
-
* `cli.createCodactFailure`, `org.consumer.project.resolve` and
|
|
355
|
-
* `org.consumer.listConnectedToolkits` declare `x-user-api-key` as a `required`
|
|
356
|
-
* header parameter, which the generator folds into their params object. Calling
|
|
357
|
-
* them the way their signature asks for returned 401 until this rule existed.
|
|
358
|
-
*
|
|
359
|
-
* Header merging is replayed rather than approximated, because a later source
|
|
360
|
-
* may carry `null` to delete what an earlier one set (`buildHeaders`).
|
|
361
|
-
*/
|
|
362
|
-
const callerPlacedCredential = (sources) => {
|
|
363
|
-
if (!sources.some(Boolean)) return false;
|
|
364
|
-
const headers = buildHeaders(sources);
|
|
365
|
-
return FOREIGN_CREDENTIAL_HEADERS.some((name) => headers.has(name));
|
|
366
|
-
};
|
|
367
|
-
/**
|
|
368
212
|
* Header names that carry a credential and must not survive an origin change.
|
|
369
213
|
*
|
|
370
214
|
* The first three are what `fetch` itself would have stripped had it been
|
|
@@ -437,6 +281,188 @@ const withdrawCredentials = (headers) => {
|
|
|
437
281
|
*/
|
|
438
282
|
const carriesCredentials = (headers) => CREDENTIAL_HEADERS.some((name) => headers.has(name));
|
|
439
283
|
|
|
284
|
+
//#endregion
|
|
285
|
+
//#region src/compat/auth.ts
|
|
286
|
+
const NONE = Object.freeze({ mode: "none" });
|
|
287
|
+
const authConstructors = () => Object.freeze({
|
|
288
|
+
none: () => NONE,
|
|
289
|
+
project: (credential) => Object.freeze({
|
|
290
|
+
mode: "project",
|
|
291
|
+
credential
|
|
292
|
+
}),
|
|
293
|
+
user: (credential) => Object.freeze({
|
|
294
|
+
mode: "user",
|
|
295
|
+
credential
|
|
296
|
+
}),
|
|
297
|
+
organization: (credential) => Object.freeze({
|
|
298
|
+
mode: "organization",
|
|
299
|
+
credential
|
|
300
|
+
}),
|
|
301
|
+
auto: (credentials) => Object.freeze({
|
|
302
|
+
mode: "auto",
|
|
303
|
+
credentials: Object.freeze({ ...credentials })
|
|
304
|
+
})
|
|
305
|
+
});
|
|
306
|
+
const Auth = authConstructors();
|
|
307
|
+
const FIXED_MODES = [
|
|
308
|
+
"project",
|
|
309
|
+
"user",
|
|
310
|
+
"organization"
|
|
311
|
+
];
|
|
312
|
+
const SCHEME_OF_MODE = {
|
|
313
|
+
project: "ApiKeyAuth",
|
|
314
|
+
user: "UserApiKeyAuth",
|
|
315
|
+
organization: "OrgApiKeyAuth"
|
|
316
|
+
};
|
|
317
|
+
const isFixedMode = (mode) => FIXED_MODES.includes(mode);
|
|
318
|
+
/** One credential is that fixed mode, several is `auto`, none is `none`. Shared by `fromEnv` and `layerConfig`. */
|
|
319
|
+
const authFromCredentials = (credentials) => {
|
|
320
|
+
const auth = authConstructors();
|
|
321
|
+
const [first, ...rest] = FIXED_MODES.filter((mode) => credentials[mode] !== void 0);
|
|
322
|
+
if (first === void 0) return auth.none();
|
|
323
|
+
if (rest.length > 0) return auth.auto(credentials);
|
|
324
|
+
return auth[first](credentials[first]);
|
|
325
|
+
};
|
|
326
|
+
const isSendable = (value, name = "x-api-key") => {
|
|
327
|
+
try {
|
|
328
|
+
new globalThis.Headers().set(name, value);
|
|
329
|
+
return true;
|
|
330
|
+
} catch {
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
const isUsableKey = (key) => typeof key === "string" && /\S/.test(key) && isSendable(key);
|
|
335
|
+
const unusableKeyError = (source) => new ComposioError(`${source} is not a usable key: it must be a string with a non-whitespace character and no line break, NUL or character outside Latin-1.`);
|
|
336
|
+
const holdCredential = (value, option, kind) => {
|
|
337
|
+
if (!kind.is(value)) throw new ComposioError(`\`${option}\` must be a key or a function that returns one.`);
|
|
338
|
+
const key = kind.keyOf(value);
|
|
339
|
+
if (key !== void 0 && !isUsableKey(key)) throw unusableKeyError(`\`${option}\``);
|
|
340
|
+
return value;
|
|
341
|
+
};
|
|
342
|
+
const holdAuto = (given, kind) => {
|
|
343
|
+
const credentials = {};
|
|
344
|
+
for (const mode of FIXED_MODES) {
|
|
345
|
+
const value = given?.[mode];
|
|
346
|
+
if (value !== void 0) credentials[SCHEME_OF_MODE[mode]] = holdCredential(value, `auth.credentials.${mode}`, kind);
|
|
347
|
+
}
|
|
348
|
+
if (Object.keys(credentials).length === 0) throw new ComposioError("`Auth.auto` needs at least one of `project`, `user` and `organization`.");
|
|
349
|
+
return credentials;
|
|
350
|
+
};
|
|
351
|
+
const MIGRATION = "Pass `auth`: `Auth.project(key)`, `Auth.user(key)`, `Auth.organization(key)`, `Auth.auto({ project, user, organization })` or `Auth.none()`.";
|
|
352
|
+
const resolveAuth = (auth, kind) => {
|
|
353
|
+
const value = auth;
|
|
354
|
+
const mode = value?.mode;
|
|
355
|
+
if (mode === void 0) throw new ComposioError(`\`auth\` is required. ${MIGRATION}`);
|
|
356
|
+
if (mode === "none") return {
|
|
357
|
+
mode,
|
|
358
|
+
credentials: {}
|
|
359
|
+
};
|
|
360
|
+
if (mode === "auto") return {
|
|
361
|
+
mode,
|
|
362
|
+
credentials: holdAuto(value?.credentials, kind)
|
|
363
|
+
};
|
|
364
|
+
if (!isFixedMode(mode)) throw new ComposioError(`\`auth.mode\` must be 'none', 'project', 'user', 'organization' or 'auto'. ${MIGRATION}`);
|
|
365
|
+
return {
|
|
366
|
+
mode,
|
|
367
|
+
credentials: { [SCHEME_OF_MODE[mode]]: holdCredential(value?.credential, "auth.credential", kind) }
|
|
368
|
+
};
|
|
369
|
+
};
|
|
370
|
+
const REMOVED_OPTIONS = {
|
|
371
|
+
apiKey: "Auth.project(key)",
|
|
372
|
+
userApiKey: "Auth.user(key)",
|
|
373
|
+
orgApiKey: "Auth.organization(key)"
|
|
374
|
+
};
|
|
375
|
+
const assertNoRemovedCredentialOptions = (options) => {
|
|
376
|
+
for (const [option, replacement] of Object.entries(REMOVED_OPTIONS)) {
|
|
377
|
+
if (!Object.hasOwn(options, option)) continue;
|
|
378
|
+
throw new ComposioError(`The \`${option}\` option was removed in 2.0.0-rc.18. Pass \`auth: ${replacement}\` instead, or \`Auth.auto({ ... })\` for per-operation selection.`);
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
const CREDENTIAL_HEADER_NAMES = Object.values(SCHEME_HEADERS);
|
|
382
|
+
const SCOPE_HEADER_NAMES = ["x-org-id", "x-project-id"];
|
|
383
|
+
const isScopeId = (value) => typeof value === "string" && value !== "" && value === value.trim() && isSendable(value, "x-org-id");
|
|
384
|
+
const scopeId = (field, value) => {
|
|
385
|
+
if (value === void 0) return void 0;
|
|
386
|
+
if (!isScopeId(value)) throw new ComposioError(`\`scope.${field}\` must be a non-empty string with no surrounding whitespace.`);
|
|
387
|
+
return value;
|
|
388
|
+
};
|
|
389
|
+
const resolveScope = (scope) => {
|
|
390
|
+
if (scope === void 0) return void 0;
|
|
391
|
+
if (typeof scope !== "object" || scope === null) throw new ComposioError("`scope` must be an object with an `organizationId`, a `projectId`, or both.");
|
|
392
|
+
const { organizationId, projectId } = scope;
|
|
393
|
+
const headers = {};
|
|
394
|
+
const org = scopeId("organizationId", organizationId);
|
|
395
|
+
const project = scopeId("projectId", projectId);
|
|
396
|
+
if (org !== void 0) headers["x-org-id"] = org;
|
|
397
|
+
if (project !== void 0) headers["x-project-id"] = project;
|
|
398
|
+
if (Object.keys(headers).length === 0) throw new ComposioError("`scope` must name an `organizationId`, a `projectId`, or both.");
|
|
399
|
+
return headers;
|
|
400
|
+
};
|
|
401
|
+
const assertRequiredOperationHeaders = (operation, supplied) => {
|
|
402
|
+
for (const name of operation?.requiredHeaders ?? []) {
|
|
403
|
+
if (supplied?.[name] != null) continue;
|
|
404
|
+
throw new ComposioError(`\`${operation?.chain.join(".")}\` requires the \`${name}\` parameter.`);
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
const scopeForCall = (configured, supplied) => {
|
|
408
|
+
const merged = { ...configured };
|
|
409
|
+
for (const name of SCOPE_HEADER_NAMES) {
|
|
410
|
+
const value = supplied?.[name];
|
|
411
|
+
if (value == null) continue;
|
|
412
|
+
const current = configured?.[name];
|
|
413
|
+
if (current !== void 0 && current !== value) throw new ComposioError(`The \`${name}\` parameter disagrees with the client's \`scope\`. Derive a client with \`withOptions({ scope })\` to address another one.`);
|
|
414
|
+
merged[name] = value;
|
|
415
|
+
}
|
|
416
|
+
return merged;
|
|
417
|
+
};
|
|
418
|
+
const operationCredential = (supplied) => {
|
|
419
|
+
for (const [name, value] of Object.entries(supplied ?? {})) {
|
|
420
|
+
const scheme = schemeOfHeader(name);
|
|
421
|
+
if (scheme !== void 0 && value != null) return {
|
|
422
|
+
scheme,
|
|
423
|
+
credential: value
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
const configuredScheme = (auth, operation) => {
|
|
428
|
+
if (auth.mode === "none") return void 0;
|
|
429
|
+
if (auth.mode === "auto") return selectScheme(operation?.schemes, (scheme) => auth.credentials[scheme] !== void 0);
|
|
430
|
+
return SCHEME_OF_MODE[auth.mode];
|
|
431
|
+
};
|
|
432
|
+
/**
|
|
433
|
+
* The credential one call carries: an operation credential replaces `auth`,
|
|
434
|
+
* and a fixed mode never reads the operation table. `null` off the API origin.
|
|
435
|
+
*/
|
|
436
|
+
const chooseCredential = (auth, baseURL, requestURL, operation, supplied) => {
|
|
437
|
+
if (!sameOrigin(baseURL, requestURL)) return null;
|
|
438
|
+
const own = operationCredential(supplied);
|
|
439
|
+
if (own !== void 0) return own;
|
|
440
|
+
const scheme = configuredScheme(auth, operation);
|
|
441
|
+
if (scheme === void 0) return null;
|
|
442
|
+
const credential = auth.credentials[scheme];
|
|
443
|
+
return credential === void 0 ? null : {
|
|
444
|
+
scheme,
|
|
445
|
+
credential
|
|
446
|
+
};
|
|
447
|
+
};
|
|
448
|
+
const credentialHeader = (scheme, key) => {
|
|
449
|
+
const name = SCHEME_HEADERS[scheme];
|
|
450
|
+
if (!isUsableKey(key)) throw unusableKeyError(`The \`${name}\` credential`);
|
|
451
|
+
return {
|
|
452
|
+
name,
|
|
453
|
+
value: key
|
|
454
|
+
};
|
|
455
|
+
};
|
|
456
|
+
const providerFailed = (cause) => {
|
|
457
|
+
const error = new ComposioError("The `auth` credential provider failed.");
|
|
458
|
+
Object.defineProperty(error, "cause", {
|
|
459
|
+
value: cause,
|
|
460
|
+
configurable: true,
|
|
461
|
+
writable: true
|
|
462
|
+
});
|
|
463
|
+
return error;
|
|
464
|
+
};
|
|
465
|
+
|
|
440
466
|
//#endregion
|
|
441
467
|
//#region src/compat/deprecation.ts
|
|
442
468
|
/**
|
|
@@ -907,9 +933,82 @@ const inspectDeprecatedInputs = ({ operation, query, body, headers, table, seen,
|
|
|
907
933
|
}
|
|
908
934
|
};
|
|
909
935
|
|
|
936
|
+
//#endregion
|
|
937
|
+
//#region src/compat/headers.ts
|
|
938
|
+
const hasEntries = (value) => typeof value === "object" && value !== null && "append" in value && typeof value.append === "function" && "delete" in value && typeof value.delete === "function" && "entries" in value && typeof value.entries === "function" && "get" in value && typeof value.get === "function";
|
|
939
|
+
const isHeaders = (value) => value instanceof Headers || hasEntries(value);
|
|
940
|
+
const isNullableHeadersLike = (headers) => {
|
|
941
|
+
if (!("values" in headers) || !isHeaders(headers.values) || !("nulls" in headers)) return false;
|
|
942
|
+
const nulls = headers.nulls;
|
|
943
|
+
return typeof nulls === "object" && nulls !== null && Symbol.iterator in nulls;
|
|
944
|
+
};
|
|
945
|
+
/**
|
|
946
|
+
* Iterates every supported input while preserving explicit deletions. Plain
|
|
947
|
+
* objects replace an older value for a key; tuple inputs append duplicate
|
|
948
|
+
* values, matching the published client.
|
|
949
|
+
*/
|
|
950
|
+
function* iterateHeaders(headers) {
|
|
951
|
+
if (!headers) return;
|
|
952
|
+
if (isNullableHeadersLike(headers)) {
|
|
953
|
+
yield* headers.values.entries();
|
|
954
|
+
for (const name of headers.nulls) yield [name, null];
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
const shouldReplace = !isHeaders(headers) && !Array.isArray(headers);
|
|
958
|
+
const entries = isHeaders(headers) ? headers.entries() : Array.isArray(headers) ? headers : Object.entries(headers);
|
|
959
|
+
for (const entry of entries) {
|
|
960
|
+
const name = entry[0];
|
|
961
|
+
if (typeof name !== "string") throw new TypeError("expected header name to be a string");
|
|
962
|
+
const rawValue = entry[1];
|
|
963
|
+
const values = Array.isArray(rawValue) ? rawValue : [rawValue];
|
|
964
|
+
let replaced = false;
|
|
965
|
+
for (const value of values) {
|
|
966
|
+
if (value === void 0) continue;
|
|
967
|
+
if (shouldReplace && !replaced) {
|
|
968
|
+
replaced = true;
|
|
969
|
+
yield [name, null];
|
|
970
|
+
}
|
|
971
|
+
yield [name, value];
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
/** Merge sources while retaining names explicitly deleted by the last source. */
|
|
976
|
+
const mergeHeaders = (sources) => {
|
|
977
|
+
const values = new Headers();
|
|
978
|
+
const nulls = /* @__PURE__ */ new Set();
|
|
979
|
+
for (const source of sources) {
|
|
980
|
+
if (!source) continue;
|
|
981
|
+
const seen = /* @__PURE__ */ new Set();
|
|
982
|
+
for (const [name, value] of iterateHeaders(source)) {
|
|
983
|
+
const lowerName = name.toLowerCase();
|
|
984
|
+
if (!seen.has(lowerName)) {
|
|
985
|
+
values.delete(name);
|
|
986
|
+
seen.add(lowerName);
|
|
987
|
+
}
|
|
988
|
+
if (value === null) {
|
|
989
|
+
values.delete(name);
|
|
990
|
+
nulls.add(lowerName);
|
|
991
|
+
} else {
|
|
992
|
+
values.append(name, value);
|
|
993
|
+
nulls.delete(lowerName);
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
return {
|
|
998
|
+
values,
|
|
999
|
+
nulls
|
|
1000
|
+
};
|
|
1001
|
+
};
|
|
1002
|
+
/** Merge sources into the native header collection sent to fetch. */
|
|
1003
|
+
const buildHeaders = (sources) => mergeHeaders(sources).values;
|
|
1004
|
+
/** Every header name a source mentions, lowercased, a `null` deletion included. */
|
|
1005
|
+
function* headerNames(headers) {
|
|
1006
|
+
for (const [name] of iterateHeaders(headers)) yield name.toLowerCase();
|
|
1007
|
+
}
|
|
1008
|
+
|
|
910
1009
|
//#endregion
|
|
911
1010
|
//#region src/version.ts
|
|
912
|
-
const VERSION = "2.0.0-rc.
|
|
1011
|
+
const VERSION = "2.0.0-rc.19";
|
|
913
1012
|
|
|
914
1013
|
//#endregion
|
|
915
1014
|
//#region src/compat/identity.ts
|
|
@@ -1061,18 +1160,32 @@ const resolveIdentity = (identity) => {
|
|
|
1061
1160
|
reserved: IDENTITY_RESERVED
|
|
1062
1161
|
};
|
|
1063
1162
|
};
|
|
1163
|
+
/** Credential names are reserved while `auth` is not `none`, routing ids while `scope` is set. */
|
|
1164
|
+
const reservedHeaders = (identity, configured) => {
|
|
1165
|
+
const reserved = /* @__PURE__ */ new Map();
|
|
1166
|
+
for (const name of identity.reserved) reserved.set(name, PACKAGE_RESERVED.has(name) ? "client" : "identity");
|
|
1167
|
+
if (configured.auth) for (const name of CREDENTIAL_HEADER_NAMES) reserved.set(name, "auth");
|
|
1168
|
+
if (configured.scope) for (const name of SCOPE_HEADER_NAMES) reserved.set(name, "scope");
|
|
1169
|
+
return reserved;
|
|
1170
|
+
};
|
|
1171
|
+
const REMEDY = {
|
|
1172
|
+
client: " Pass `identity` to describe the calling product.",
|
|
1173
|
+
identity: "",
|
|
1174
|
+
auth: " Configure the credential through `auth`; derive a client with `withOptions({ auth })` for another one.",
|
|
1175
|
+
scope: " Configure the organization and project through `scope`; derive a client with `withOptions({ scope })` for another one."
|
|
1176
|
+
};
|
|
1064
1177
|
/**
|
|
1065
|
-
* Refuses a generic header source that names
|
|
1178
|
+
* Refuses a generic header source that names a reserved header, whether it
|
|
1066
1179
|
* sets one or deletes one with `null`. Constructor validation runs it over
|
|
1067
1180
|
* `defaultHeaders`; request validation over a call's `headers`, before any
|
|
1068
1181
|
* network work.
|
|
1069
1182
|
*/
|
|
1070
|
-
const assertNoReservedHeaders = (headers,
|
|
1183
|
+
const assertNoReservedHeaders = (headers, reserved, option) => {
|
|
1071
1184
|
if (!headers) return;
|
|
1072
1185
|
for (const name of headerNames(headers)) {
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
throw new ComposioError(`The \`${name}\` header is set by ${owner
|
|
1186
|
+
const owner = reserved.get(name);
|
|
1187
|
+
if (owner === void 0) continue;
|
|
1188
|
+
throw new ComposioError(`The \`${name}\` header is set by ${owner === "client" ? "the client" : `\`${owner}\``} and cannot be passed in \`${option}\`.${REMEDY[owner]}`);
|
|
1076
1189
|
}
|
|
1077
1190
|
};
|
|
1078
1191
|
|
|
@@ -1142,20 +1255,25 @@ const createFetchTransport = (options = {}) => {
|
|
|
1142
1255
|
* regression that measures fine and reports nothing.
|
|
1143
1256
|
*/
|
|
1144
1257
|
const OPERATION = Symbol("composio.operation");
|
|
1258
|
+
/** The owned header parameters (`x-user-api-key`, `x-org-id`) a generated call supplied. */
|
|
1259
|
+
const OPERATION_HEADERS = Symbol("composio.operationHeaders");
|
|
1145
1260
|
/**
|
|
1146
|
-
* Attach a generated call's operation
|
|
1261
|
+
* Attach a generated call's operation, and its owned header parameters, to
|
|
1262
|
+
* the options bag it dispatches with.
|
|
1147
1263
|
*
|
|
1148
1264
|
* Called with the freshly built literal — never with the caller's own object —
|
|
1149
1265
|
* and *after* the caller's options have been spread into it, so a caller
|
|
1150
1266
|
* cannot pre-empt the descriptor: the write happens last, and the key it
|
|
1151
1267
|
* writes to is not one a caller can name.
|
|
1152
1268
|
*/
|
|
1153
|
-
const withOperation = (operation, options) => {
|
|
1269
|
+
const withOperation = (operation, options, headers) => {
|
|
1154
1270
|
options[OPERATION] = operation;
|
|
1271
|
+
if (headers !== void 0) options[OPERATION_HEADERS] = headers;
|
|
1155
1272
|
return options;
|
|
1156
1273
|
};
|
|
1157
1274
|
/** The operation a generated call recorded, or `undefined` for a raw one. */
|
|
1158
1275
|
const readOperation = (options) => options[OPERATION];
|
|
1276
|
+
const readOperationHeaders = (options) => options[OPERATION_HEADERS];
|
|
1159
1277
|
/** A request label safe to print: dynamic path values and URL secrets are excluded. */
|
|
1160
1278
|
const printableURL = (url, operation) => `${new URL(url).origin}${operation?.path ?? "/<custom>"}`;
|
|
1161
1279
|
const emitLog = (config, level, message, metadata) => {
|
|
@@ -1418,24 +1536,27 @@ const kernelInternals = { sleep };
|
|
|
1418
1536
|
* The headers for one hop, built fresh from the URL that hop is going to.
|
|
1419
1537
|
*
|
|
1420
1538
|
* This is where rule 3 mostly stops needing machinery of its own: the
|
|
1421
|
-
* credential is re-
|
|
1422
|
-
* along from the last one, so a hop that leaves the configured API
|
|
1423
|
-
* simply does not get a key. `withdrawn` covers what that cannot — the
|
|
1539
|
+
* credential is re-checked per hop against the *request* URL rather than
|
|
1540
|
+
* carried along from the last one, so a hop that leaves the configured API
|
|
1541
|
+
* origin simply does not get a key. `withdrawn` covers what that cannot — the
|
|
1424
1542
|
* caller's own credential headers, which are legitimate on the URL the caller
|
|
1425
1543
|
* chose and are dropped once the *server* has chosen one.
|
|
1426
1544
|
*
|
|
1427
|
-
* The client's identity headers follow the same per-hop rule: they
|
|
1428
|
-
* this client to its own API, so a hop off the configured origin (a
|
|
1429
|
-
* storage URL, a redirect target) goes without them.
|
|
1545
|
+
* The client's identity and scope headers follow the same per-hop rule: they
|
|
1546
|
+
* describe this client to its own API, so a hop off the configured origin (a
|
|
1547
|
+
* presigned storage URL, a redirect target) goes without them.
|
|
1430
1548
|
*/
|
|
1431
|
-
const buildRequestHeaders = (config, options, requestURL, bodyHeaders, withdrawn,
|
|
1432
|
-
const credential = withdrawn
|
|
1433
|
-
const
|
|
1549
|
+
const buildRequestHeaders = (config, options, requestURL, bodyHeaders, withdrawn, call) => {
|
|
1550
|
+
const credential = withdrawn ? null : credentialForRequest(config.baseURL, call.credential, requestURL, config.allowedHTTPOrigin);
|
|
1551
|
+
const own = sameOrigin(config.baseURL, requestURL);
|
|
1552
|
+
const identity = own ? config.identity.headers : void 0;
|
|
1553
|
+
const scope = own ? call.scope : void 0;
|
|
1434
1554
|
if (!withdrawn && bodyHeaders === void 0 && !config.defaultHeaders && !options.headers && options.idempotencyKey === void 0) {
|
|
1435
1555
|
const direct = new Headers({
|
|
1436
1556
|
...identity,
|
|
1437
1557
|
accept: "application/json",
|
|
1438
|
-
"user-agent": config.userAgent
|
|
1558
|
+
"user-agent": config.userAgent,
|
|
1559
|
+
...scope
|
|
1439
1560
|
});
|
|
1440
1561
|
if (credential !== null) direct.set(credential.name, credential.value);
|
|
1441
1562
|
return direct;
|
|
@@ -1448,6 +1569,7 @@ const buildRequestHeaders = (config, options, requestURL, bodyHeaders, withdrawn
|
|
|
1448
1569
|
"user-agent": config.userAgent
|
|
1449
1570
|
},
|
|
1450
1571
|
credential === null ? void 0 : { [credential.name]: credential.value },
|
|
1572
|
+
scope,
|
|
1451
1573
|
config.defaultHeaders,
|
|
1452
1574
|
bodyHeaders,
|
|
1453
1575
|
options.headers
|
|
@@ -1455,28 +1577,25 @@ const buildRequestHeaders = (config, options, requestURL, bodyHeaders, withdrawn
|
|
|
1455
1577
|
if (withdrawn) withdrawCredentials(headers);
|
|
1456
1578
|
return headers;
|
|
1457
1579
|
};
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
const schemeForRequest = (config, operation) => {
|
|
1478
|
-
if (!hasAlternateCredential(config.credentials)) return "ApiKeyAuth";
|
|
1479
|
-
return selectScheme(operation?.schemes, config.credentials);
|
|
1580
|
+
const callProvider = (provider, header) => {
|
|
1581
|
+
let key;
|
|
1582
|
+
try {
|
|
1583
|
+
key = provider();
|
|
1584
|
+
} catch (cause) {
|
|
1585
|
+
throw providerFailed(cause);
|
|
1586
|
+
}
|
|
1587
|
+
if (typeof key === "string") return header(key);
|
|
1588
|
+
return Promise.resolve(key).then(header, (cause) => {
|
|
1589
|
+
throw providerFailed(cause);
|
|
1590
|
+
});
|
|
1591
|
+
};
|
|
1592
|
+
/** Synchronous unless a provider has to be awaited, so a string key goes out in the turn the call starts. */
|
|
1593
|
+
const resolveCallCredential = (config, requestURL, operation, supplied) => {
|
|
1594
|
+
const choice = chooseCredential(config.auth, config.baseURL, requestURL, operation, supplied);
|
|
1595
|
+
if (choice === null) return null;
|
|
1596
|
+
const header = (key) => credentialHeader(choice.scheme, key);
|
|
1597
|
+
if (typeof choice.credential === "string") return header(choice.credential);
|
|
1598
|
+
return callProvider(choice.credential, header);
|
|
1480
1599
|
};
|
|
1481
1600
|
/**
|
|
1482
1601
|
* One attempt: the request, plus however many redirects it takes to land on a
|
|
@@ -1494,15 +1613,14 @@ const schemeForRequest = (config, operation) => {
|
|
|
1494
1613
|
* rewrite), and the query, which is left to the `Location` URL because the
|
|
1495
1614
|
* server picked it.
|
|
1496
1615
|
*/
|
|
1497
|
-
const dispatchWithRedirects = async (config, options, initialURL, initialBody, initialBodyHeaders, signal,
|
|
1616
|
+
const dispatchWithRedirects = async (config, options, initialURL, initialBody, initialBodyHeaders, signal, call) => {
|
|
1498
1617
|
let url = initialURL;
|
|
1499
1618
|
let method = options.method.toUpperCase();
|
|
1500
1619
|
let body = initialBody;
|
|
1501
1620
|
let bodyHeaders = initialBodyHeaders;
|
|
1502
1621
|
let withdrawn = false;
|
|
1503
|
-
const callerPlaced = callerPlacedCredential([config.defaultHeaders, options.headers]);
|
|
1504
1622
|
for (let hop = 0;; hop++) {
|
|
1505
|
-
const headers = buildRequestHeaders(config, options, url, bodyHeaders, withdrawn,
|
|
1623
|
+
const headers = buildRequestHeaders(config, options, url, bodyHeaders, withdrawn, call);
|
|
1506
1624
|
const delegated = hop === 0 && !carriesCredentials(headers);
|
|
1507
1625
|
const init = {
|
|
1508
1626
|
method,
|
|
@@ -1547,7 +1665,7 @@ const dispatchWithRedirects = async (config, options, initialURL, initialBody, i
|
|
|
1547
1665
|
* which is what `deprecation.ts` resolves relative `Link` targets against.
|
|
1548
1666
|
*/
|
|
1549
1667
|
async function makeRequest(config, options) {
|
|
1550
|
-
assertNoReservedHeaders(options.headers, config.
|
|
1668
|
+
assertNoReservedHeaders(options.headers, config.reserved, "headers");
|
|
1551
1669
|
if (options.timeout !== void 0) validatePositiveInteger("timeout", options.timeout);
|
|
1552
1670
|
const maxRetries = options.maxRetries ?? config.maxRetries;
|
|
1553
1671
|
validatePositiveInteger("maxRetries", maxRetries);
|
|
@@ -1563,7 +1681,14 @@ async function makeRequest(config, options) {
|
|
|
1563
1681
|
url: printableURL(url, operation),
|
|
1564
1682
|
maxAttempts: maxRetries + 1
|
|
1565
1683
|
};
|
|
1566
|
-
const
|
|
1684
|
+
const supplied = readOperationHeaders(options);
|
|
1685
|
+
assertRequiredOperationHeaders(threaded ?? null, supplied);
|
|
1686
|
+
const scope = scopeForCall(config.scope, supplied);
|
|
1687
|
+
const credential = resolveCallCredential(config, url, operation, supplied);
|
|
1688
|
+
const call = {
|
|
1689
|
+
scope,
|
|
1690
|
+
credential: credential instanceof Promise ? await credential : credential
|
|
1691
|
+
};
|
|
1567
1692
|
if (config.onRequest !== void 0 && (threaded === void 0 || threaded.hasDeprecatedInputs === true)) config.onRequest(operation, query, options.body, buildHeaders([config.defaultHeaders, options.headers]));
|
|
1568
1693
|
for (let numRetries = 0;; numRetries++) {
|
|
1569
1694
|
if (userSignal?.aborted) throw new APIUserAbortError();
|
|
@@ -1581,7 +1706,7 @@ async function makeRequest(config, options) {
|
|
|
1581
1706
|
const timer = setTimeout(abort, timeout);
|
|
1582
1707
|
let result;
|
|
1583
1708
|
try {
|
|
1584
|
-
result = await dispatchWithRedirects(config, options, url, body, bodyHeaders, controller.signal,
|
|
1709
|
+
result = await dispatchWithRedirects(config, options, url, body, bodyHeaders, controller.signal, call);
|
|
1585
1710
|
} catch (cause) {
|
|
1586
1711
|
if (cause instanceof ComposioError) {
|
|
1587
1712
|
if (attemptLog !== void 0) emitLog(config, "info", "Request failed", {
|
|
@@ -1841,7 +1966,8 @@ const GENERATED_OPERATIONS = [
|
|
|
1841
1966
|
"consumer",
|
|
1842
1967
|
"listConnectedToolkits"
|
|
1843
1968
|
],
|
|
1844
|
-
schemes: ["UserApiKeyAuth"]
|
|
1969
|
+
schemes: ["UserApiKeyAuth"],
|
|
1970
|
+
requiredHeaders: ["x-user-api-key", "x-org-id"]
|
|
1845
1971
|
},
|
|
1846
1972
|
{
|
|
1847
1973
|
method: "get",
|
|
@@ -2106,7 +2232,8 @@ const GENERATED_OPERATIONS = [
|
|
|
2106
2232
|
method: "post",
|
|
2107
2233
|
path: "/api/v3.1/cli/codact_failures",
|
|
2108
2234
|
chain: ["cli", "createCodactFailure"],
|
|
2109
|
-
schemes: ["UserApiKeyAuth"]
|
|
2235
|
+
schemes: ["UserApiKeyAuth"],
|
|
2236
|
+
requiredHeaders: ["x-user-api-key"]
|
|
2110
2237
|
},
|
|
2111
2238
|
{
|
|
2112
2239
|
method: "post",
|
|
@@ -2238,7 +2365,8 @@ const GENERATED_OPERATIONS = [
|
|
|
2238
2365
|
"project",
|
|
2239
2366
|
"resolve"
|
|
2240
2367
|
],
|
|
2241
|
-
schemes: ["UserApiKeyAuth"]
|
|
2368
|
+
schemes: ["UserApiKeyAuth"],
|
|
2369
|
+
requiredHeaders: ["x-user-api-key", "x-org-id"]
|
|
2242
2370
|
},
|
|
2243
2371
|
{
|
|
2244
2372
|
method: "post",
|
|
@@ -2478,4 +2606,4 @@ const generatedOperation = (chainKey) => {
|
|
|
2478
2606
|
};
|
|
2479
2607
|
|
|
2480
2608
|
//#endregion
|
|
2481
|
-
export {
|
|
2609
|
+
export { Auth as A, SCHEME_HEADERS as B, resolveIdentity as C, inspectDeprecatedInputs as D, mergeHeaders as E, chooseCredential as F, carriesCredentials as H, credentialHeader as I, resolveAuth as L, assertRequiredOperationHeaders as M, authConstructors as N, inspectDeprecation as O, authFromCredentials as P, resolveScope as R, reservedHeaders as S, buildHeaders as T, parseHTTPURL as U, assertCredentialTransport as V, resolveHTTPURL as W, shouldRetryResponse as _, TOO_MANY_REDIRECTS as a, createFetchTransport as b, buildURL as c, path as d, printableURL as f, safeJSON as g, rewriteForRedirect as h, REDIRECT_STATUSES as i, assertNoRemovedCredentialOptions as j, matchOperation as k, castToError as l, retryDelayMillis as m, generatedOperation as n, buildBody as o, readOperation as p, OPAQUE_REDIRECT as r, buildRequestHeaders as s, GENERATED_OPERATIONS as t, makeRequest as u, validatePositiveInteger as v, VERSION as w, assertNoReservedHeaders as x, withOperation as y, scopeForCall as z };
|