@composio/client 2.0.0-rc.17 → 2.0.0-rc.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/README.md +107 -33
  2. package/dist/{api-key-revocation-lc3308Ao.mjs → api-key-revocation-JkA4sOGH.mjs} +1 -1
  3. package/dist/{auth-DkGiEaxg.mjs → auth-B_K-wdMm.mjs} +1 -1
  4. package/dist/{auth-configs-DbxqGahP.mjs → auth-configs-RAgN782Z.mjs} +1 -1
  5. package/dist/{clanker-fK9cAkTz.mjs → clanker-Pgyyh95r.mjs} +1 -1
  6. package/dist/{cli-K1MskpaR.mjs → cli-Ca5bRiEN.mjs} +4 -5
  7. package/dist/{connected-accounts-Bfl7_SY_.mjs → connected-accounts-D6NTwvbi.mjs} +1 -1
  8. package/dist/{consumer-5o2zMQwr.mjs → consumer-BP4OyJS0.mjs} +6 -7
  9. package/dist/{custom-wEkSiPHn.mjs → custom-BBr7KbCv.mjs} +1 -1
  10. package/dist/{custom-8rs-sHnb.mjs → custom-DA3ABHnI.mjs} +1 -1
  11. package/dist/effect.d.mts +54 -23
  12. package/dist/effect.mjs +204 -143
  13. package/dist/{error-D9cG225M.mjs → error-Bw7_G2NZ.mjs} +1 -1
  14. package/dist/{files-BPKJXlpc.mjs → files-CeBs4ZE1.mjs} +1 -1
  15. package/dist/{files-BjPFzRnM.mjs → files-DLRmNLRD.mjs} +1 -1
  16. package/dist/{generate-DDHNgbPS.mjs → generate-16uLPwUU.mjs} +1 -1
  17. package/dist/{generated-deprecated-inputs--L5LHDO_.mjs → generated-deprecated-inputs-zx6ml908.mjs} +2 -2
  18. package/dist/{generated-operations-D1e__yar.mjs → generated-operations-DKgGT6Dg.mjs} +426 -198
  19. package/dist/index.d.mts +3 -3
  20. package/dist/index.mjs +131 -101
  21. package/dist/{keyring-Dkm6DQIp.mjs → keyring-Q8GSieAv.mjs} +1 -1
  22. package/dist/{link-BBU-J5L_.mjs → link-D4dY_eaN.mjs} +1 -1
  23. package/dist/{logs-CuuysWk1.mjs → logs-Dc63Ju74.mjs} +3 -3
  24. package/dist/{manage-B1R7I3ZM.mjs → manage-ByF6b3OD.mjs} +1 -1
  25. package/dist/{mcp-C3beSy48.mjs → mcp-Cw7-Mtkm.mjs} +3 -3
  26. package/dist/{org-B13XOuKh.mjs → org-RRUxKfRw.mjs} +6 -6
  27. package/dist/{owner-BAr5uwk3.mjs → owner-GZX-sp-h.mjs} +1 -1
  28. package/dist/{pagination-rules-uMUdPq_7.mjs → pagination-rules-CMnBwktJ.mjs} +1 -1
  29. package/dist/pagination.mjs +1 -1
  30. package/dist/{project-BbCgXD83.mjs → project-BsKmk9T7.mjs} +1 -1
  31. package/dist/{project-C30H_5b6.mjs → project-C1uq7bV_.mjs} +1 -1
  32. package/dist/{project-DF5KclHm.mjs → project-C_YZ-eLI.mjs} +4 -7
  33. package/dist/{project-CDm8tjUw.mjs → project-Cj9ULE0a.mjs} +1 -1
  34. package/dist/{realtime-6LigMh83.mjs → realtime-W-lJ0Vcs.mjs} +1 -1
  35. package/dist/resources/api-key-revocation.d.mts +1 -1
  36. package/dist/resources/api-key-revocation.mjs +1 -1
  37. package/dist/resources/auth/auth.d.mts +1 -1
  38. package/dist/resources/auth/auth.mjs +1 -1
  39. package/dist/resources/auth/index.d.mts +1 -1
  40. package/dist/resources/auth/index.mjs +2 -2
  41. package/dist/resources/auth/session.d.mts +1 -1
  42. package/dist/resources/auth/session.mjs +1 -1
  43. package/dist/resources/auth-configs.d.mts +1 -1
  44. package/dist/resources/auth-configs.mjs +1 -1
  45. package/dist/resources/auth.d.mts +1 -1
  46. package/dist/resources/auth.mjs +2 -2
  47. package/dist/resources/cli/cli.d.mts +1 -1
  48. package/dist/resources/cli/cli.mjs +1 -1
  49. package/dist/resources/cli/index.d.mts +1 -1
  50. package/dist/resources/cli/index.mjs +2 -2
  51. package/dist/resources/cli/realtime.d.mts +1 -1
  52. package/dist/resources/cli/realtime.mjs +1 -1
  53. package/dist/resources/cli.d.mts +1 -1
  54. package/dist/resources/cli.mjs +2 -2
  55. package/dist/resources/connected-accounts.d.mts +1 -1
  56. package/dist/resources/connected-accounts.mjs +1 -1
  57. package/dist/resources/custom.d.mts +1 -1
  58. package/dist/resources/custom.mjs +1 -1
  59. package/dist/resources/files.d.mts +1 -1
  60. package/dist/resources/files.mjs +1 -1
  61. package/dist/resources/index.d.mts +1 -1
  62. package/dist/resources/index.mjs +13 -13
  63. package/dist/resources/keyring.d.mts +1 -1
  64. package/dist/resources/keyring.mjs +1 -1
  65. package/dist/resources/link.d.mts +1 -1
  66. package/dist/resources/link.mjs +1 -1
  67. package/dist/resources/logs/index.d.mts +1 -1
  68. package/dist/resources/logs/index.mjs +3 -3
  69. package/dist/resources/logs/logs.d.mts +1 -1
  70. package/dist/resources/logs/logs.mjs +1 -1
  71. package/dist/resources/logs/tools.d.mts +1 -1
  72. package/dist/resources/logs/tools.mjs +1 -1
  73. package/dist/resources/logs/triggers.d.mts +1 -1
  74. package/dist/resources/logs/triggers.mjs +1 -1
  75. package/dist/resources/logs.d.mts +1 -1
  76. package/dist/resources/logs.mjs +3 -3
  77. package/dist/resources/mcp/custom.d.mts +1 -1
  78. package/dist/resources/mcp/custom.mjs +1 -1
  79. package/dist/resources/mcp/generate.d.mts +1 -1
  80. package/dist/resources/mcp/generate.mjs +1 -1
  81. package/dist/resources/mcp/index.d.mts +1 -1
  82. package/dist/resources/mcp/index.mjs +3 -3
  83. package/dist/resources/mcp/mcp.d.mts +1 -1
  84. package/dist/resources/mcp/mcp.mjs +1 -1
  85. package/dist/resources/mcp.d.mts +1 -1
  86. package/dist/resources/mcp.mjs +3 -3
  87. package/dist/resources/org/clanker.d.mts +1 -1
  88. package/dist/resources/org/clanker.mjs +1 -1
  89. package/dist/resources/org/consumer/consumer.d.mts +1 -1
  90. package/dist/resources/org/consumer/consumer.mjs +1 -1
  91. package/dist/resources/org/consumer/index.d.mts +1 -1
  92. package/dist/resources/org/consumer/index.mjs +2 -2
  93. package/dist/resources/org/consumer/project.d.mts +1 -1
  94. package/dist/resources/org/consumer/project.mjs +1 -1
  95. package/dist/resources/org/consumer.d.mts +1 -1
  96. package/dist/resources/org/consumer.mjs +2 -2
  97. package/dist/resources/org/index.d.mts +1 -1
  98. package/dist/resources/org/index.mjs +6 -6
  99. package/dist/resources/org/org.d.mts +1 -1
  100. package/dist/resources/org/org.mjs +1 -1
  101. package/dist/resources/org/owner/index.d.mts +1 -1
  102. package/dist/resources/org/owner/index.mjs +2 -2
  103. package/dist/resources/org/owner/owner.d.mts +1 -1
  104. package/dist/resources/org/owner/owner.mjs +1 -1
  105. package/dist/resources/org/owner/project.d.mts +1 -1
  106. package/dist/resources/org/owner/project.mjs +1 -1
  107. package/dist/resources/org/owner.d.mts +1 -1
  108. package/dist/resources/org/owner.mjs +2 -2
  109. package/dist/resources/org/project.d.mts +1 -1
  110. package/dist/resources/org/project.mjs +1 -1
  111. package/dist/resources/org/usage.d.mts +1 -1
  112. package/dist/resources/org/usage.mjs +1 -1
  113. package/dist/resources/org.d.mts +1 -1
  114. package/dist/resources/org.mjs +6 -6
  115. package/dist/resources/project/index.d.mts +1 -1
  116. package/dist/resources/project/index.mjs +1 -1
  117. package/dist/resources/project/project.d.mts +1 -1
  118. package/dist/resources/project/project.mjs +1 -1
  119. package/dist/resources/project/usage.d.mts +1 -1
  120. package/dist/resources/project/usage.mjs +1 -1
  121. package/dist/resources/project.d.mts +1 -1
  122. package/dist/resources/project.mjs +1 -1
  123. package/dist/resources/session-configs.d.mts +1 -1
  124. package/dist/resources/session-configs.mjs +1 -1
  125. package/dist/resources/tool-router/index.d.mts +1 -1
  126. package/dist/resources/tool-router/index.mjs +2 -2
  127. package/dist/resources/tool-router/session/files.d.mts +1 -1
  128. package/dist/resources/tool-router/session/files.mjs +1 -1
  129. package/dist/resources/tool-router/session/index.d.mts +1 -1
  130. package/dist/resources/tool-router/session/index.mjs +2 -2
  131. package/dist/resources/tool-router/session/session.d.mts +1 -1
  132. package/dist/resources/tool-router/session/session.mjs +1 -1
  133. package/dist/resources/tool-router/session.d.mts +1 -1
  134. package/dist/resources/tool-router/session.mjs +2 -2
  135. package/dist/resources/tool-router/tool-router.d.mts +1 -1
  136. package/dist/resources/tool-router/tool-router.mjs +1 -1
  137. package/dist/resources/tool-router.d.mts +1 -1
  138. package/dist/resources/tool-router.mjs +2 -2
  139. package/dist/resources/toolkits.d.mts +1 -1
  140. package/dist/resources/toolkits.mjs +1 -1
  141. package/dist/resources/tools.d.mts +1 -1
  142. package/dist/resources/tools.mjs +1 -1
  143. package/dist/resources/trigger-instances/index.d.mts +1 -1
  144. package/dist/resources/trigger-instances/index.mjs +2 -2
  145. package/dist/resources/trigger-instances/manage.d.mts +1 -1
  146. package/dist/resources/trigger-instances/manage.mjs +1 -1
  147. package/dist/resources/trigger-instances/trigger-instances.d.mts +1 -1
  148. package/dist/resources/trigger-instances/trigger-instances.mjs +1 -1
  149. package/dist/resources/trigger-instances.d.mts +1 -1
  150. package/dist/resources/trigger-instances.mjs +2 -2
  151. package/dist/resources/triggers-types.d.mts +1 -1
  152. package/dist/resources/triggers-types.mjs +1 -1
  153. package/dist/resources/webhook-endpoints.d.mts +1 -1
  154. package/dist/resources/webhook-endpoints.mjs +1 -1
  155. package/dist/resources/webhook-subscriptions.d.mts +1 -1
  156. package/dist/resources/webhook-subscriptions.mjs +1 -1
  157. package/dist/{session-Dm8WtF4I.mjs → session-BT5NJfbm.mjs} +1 -1
  158. package/dist/{session-DEfDnHZZ.mjs → session-BmXeclWC.mjs} +2 -2
  159. package/dist/{session-configs-nA6TL_i4.d.mts → session-configs-x3OA4CSe.d.mts} +179 -102
  160. package/dist/{tool-router-6l_dREjC.mjs → tool-router-DYPUf-fN.mjs} +1 -1
  161. package/dist/{toolkits-Mn_uLV98.mjs → toolkits-DZOZDm-4.mjs} +1 -1
  162. package/dist/{tools-btk0mzFP.mjs → tools-BDCRk80t.mjs} +1 -1
  163. package/dist/{tools-z-PjBsf7.mjs → tools-C0GjPEpP.mjs} +1 -1
  164. package/dist/{trigger-instances-PQaObQQy.mjs → trigger-instances-J5frdgzO.mjs} +2 -2
  165. package/dist/{triggers-y0mi0XzT.mjs → triggers-CnvE7y0L.mjs} +1 -1
  166. package/dist/{triggers-types-KoRbT0k5.mjs → triggers-types-DLVCtuwC.mjs} +1 -1
  167. package/dist/{usage-B2Z947BK.mjs → usage-DPxuivP6.mjs} +1 -1
  168. package/dist/{usage-DvjkSmpI.mjs → usage-DjQg9WIV.mjs} +1 -1
  169. package/dist/version-DEAhxVwC.d.mts +4 -0
  170. package/dist/{webhook-endpoints-kf4Jj2Mz.mjs → webhook-endpoints-BrSjXOf0.mjs} +1 -1
  171. package/dist/{webhook-subscriptions-DcYN8qo1.mjs → webhook-subscriptions-HT1acmwH.mjs} +1 -1
  172. package/package.json +2 -2
  173. 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-D9cG225M.mjs";
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 `apiKey` and
98
- * `baseURL` are both public mutable fields on the client.
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,22 +85,10 @@ 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
- /**
163
- * Whether anything beyond the project key is configured — the condition that
164
- * makes per-operation selection able to change an outcome at all.
165
- *
166
- * Load-bearing rather than an optimization. With only `apiKey` set, every
167
- * branch of {@link selectScheme} lands on `ApiKeyAuth`: it wins wherever it is
168
- * an accepted alternative, and where it is not, the alternative is unconfigured
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
88
  /**
176
- * Which credential a request declaring `schemes` should carry.
89
+ * Which credential a request declaring `schemes` should carry, for a client in
90
+ * `auto` mode holding the schemes `held` answers `true` for. A fixed mode never
91
+ * asks: it always sends its own.
177
92
  *
178
93
  * **Exactly one, always** — and the API says so itself. Measured against
179
94
  * production on 2026-08-06, `GET /toolkits` answers 200 for `x-api-key` alone
@@ -191,37 +106,38 @@ const hasAlternateCredential = (credentials) => credentials.userApiKey !== null
191
106
  * model available, and the choice has to be made per request rather than
192
107
  * accumulated.
193
108
  *
194
- * The precedence exists to make the change free where it must be free:
109
+ * The precedence is the one every release before `rc.18` applied:
195
110
  *
196
- * 1. **`ApiKeyAuth` wins wherever the operation accepts it** and an `apiKey` is
197
- * configured — 85 of the 104 operations, every wire byte preserved.
111
+ * 1. **`ApiKeyAuth` wins wherever the operation accepts it** and a project key
112
+ * is held.
198
113
  * 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
114
+ * recognizes *and* holds a credential for. That is what makes the
200
115
  * `UserApiKeyAuth`-only and `OrgApiKeyAuth`-only operations reachable.
201
116
  * 3. Otherwise `ApiKeyAuth`, which is what this client did before any of this
202
117
  * 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`.
118
+ * key still sends `x-api-key` and still fails the same way.
206
119
  *
207
120
  * Rule 3 is also where a scheme name this client does not know lands. Three of
208
121
  * them exist: `security` references `no_auth` (3 operations) and
209
122
  * `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.
123
+ * Those four operations receive `x-api-key`, so resolving an unknown name to
124
+ * "no credential" would be a wire change made on the strength of a spec defect.
125
+ * A later generator pass must not "fix" that.
214
126
  */
215
- const selectScheme = (schemes, credentials) => {
127
+ const selectScheme = (schemes, held) => {
216
128
  if (schemes === void 0 || schemes.length === 0) return DEFAULT_SCHEME;
217
- if (schemes.includes(DEFAULT_SCHEME) && credentials.apiKey !== null) return DEFAULT_SCHEME;
129
+ if (schemes.includes(DEFAULT_SCHEME) && held(DEFAULT_SCHEME)) return DEFAULT_SCHEME;
218
130
  for (const scheme of schemes) {
219
131
  if (!Object.hasOwn(SCHEME_HEADERS, scheme)) continue;
220
132
  const known = scheme;
221
- if (valueFor(known, credentials) !== null) return known;
133
+ if (held(known)) return known;
222
134
  }
223
135
  return DEFAULT_SCHEME;
224
136
  };
137
+ /** The header `scheme` is sent as. */
138
+ const schemeHeader = (scheme) => SCHEME_HEADERS[scheme];
139
+ /** The scheme a credential header name belongs to, or `undefined` for any other name. */
140
+ const schemeOfHeader = (name) => Object.keys(SCHEME_HEADERS).find((scheme) => SCHEME_HEADERS[scheme] === name);
225
141
  /**
226
142
  * What counts as loopback, pinned rather than assumed. `localhost` is not the
227
143
  * whole set:
@@ -276,8 +192,6 @@ const resolveHTTPURL = (target, base) => {
276
192
  const isCredentialSafeOrigin = (url, allowedHTTPOrigin = null) => url.protocol === "https:" || url.protocol === "http:" && (isLoopbackHostname(url.hostname) || allowedHTTPOrigin !== null && url.origin === allowedHTTPOrigin);
277
193
  const LOOPBACK_DESCRIPTION = "localhost, *.localhost, 127.0.0.0/8, [::1]";
278
194
  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:// baseURL, use environment: 'local', set allowInsecureHTTP: true (or COMPOSIO_ALLOW_INSECURE_HTTP=1) for the configured development origin, or construct the client without credentials.`;
279
- /** Whether the client holds anything at all that rule 1 has to protect. */
280
- const anyCredential = (credentials) => credentials.apiKey !== null || hasAlternateCredential(credentials);
281
195
  /**
282
196
  * Rule 1 at construction time: a client that holds a credential must be
283
197
  * pointed at an origin that can carry one. Knowable before any request is
@@ -286,13 +200,9 @@ const anyCredential = (credentials) => credentials.apiKey !== null || hasAlterna
286
200
  * A `baseURL` that is not an absolute http(s) URL fails the same way — a
287
201
  * credential cannot be sent over a scheme this client does not speak, and the
288
202
  * 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
203
  */
294
- const assertCredentialTransport = (baseURL, credentials, allowedHTTPOrigin = null) => {
295
- if (!anyCredential(credentials)) return;
204
+ const assertCredentialTransport = (baseURL, credentialed, allowedHTTPOrigin = null) => {
205
+ if (!credentialed) return;
296
206
  const url = parseHTTPURL(baseURL);
297
207
  if (url === null || !isCredentialSafeOrigin(url, allowedHTTPOrigin)) throw new ComposioError(insecureOriginMessage(baseURL));
298
208
  };
@@ -300,7 +210,7 @@ const assertCredentialTransport = (baseURL, credentials, allowedHTTPOrigin = nul
300
210
  * The credential this request may carry, or `null` for none.
301
211
  *
302
212
  * Rules 1 and 2 at dispatch time. Both re-checks are load-bearing rather than
303
- * belt-and-braces: `apiKey` and `baseURL` are public mutable fields, so the
213
+ * belt-and-braces: `baseURL` is a public mutable field, so the
304
214
  * construction-time check can be invalidated by an assignment, and the request
305
215
  * URL is *not* guaranteed to sit on the configured origin. `buildURL`
306
216
  * concatenates `baseURL + path` and the escape hatch (`client.get(path)`)
@@ -314,18 +224,14 @@ const assertCredentialTransport = (baseURL, credentials, allowedHTTPOrigin = nul
314
224
  * with credentials, so that one dies at the transport instead. httpx has no
315
225
  * such objection, which is why the Python port checks the same thing.)
316
226
  */
317
- const credentialForRequest = (baseURL, scheme, credentials, requestURL, allowedHTTPOrigin = null) => {
318
- const value = valueFor(scheme, credentials);
319
- if (value === null) return null;
227
+ const credentialForRequest = (baseURL, credential, requestURL, allowedHTTPOrigin = null) => {
228
+ if (credential === null) return null;
320
229
  const base = parseHTTPURL(baseURL);
321
230
  const target = parseHTTPURL(requestURL);
322
231
  if (base === null || target === null) return null;
323
232
  if (base.origin !== target.origin) return null;
324
233
  if (!isCredentialSafeOrigin(target, allowedHTTPOrigin)) throw new ComposioError(insecureOriginMessage(baseURL));
325
- return {
326
- name: SCHEME_HEADERS[scheme],
327
- value
328
- };
234
+ return credential;
329
235
  };
330
236
  /**
331
237
  * Whether two absolute http(s) URLs share an origin, by the same test
@@ -337,34 +243,6 @@ const sameOrigin = (a, b) => {
337
243
  return origin !== void 0 && origin === parseHTTPURL(b)?.origin;
338
244
  };
339
245
  /**
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
246
  * Header names that carry a credential and must not survive an origin change.
369
247
  *
370
248
  * The first three are what `fetch` itself would have stripped had it been
@@ -437,6 +315,211 @@ const withdrawCredentials = (headers) => {
437
315
  */
438
316
  const carriesCredentials = (headers) => CREDENTIAL_HEADERS.some((name) => headers.has(name));
439
317
 
318
+ //#endregion
319
+ //#region src/compat/auth.ts
320
+ /**
321
+ * Who a client authenticates as (`Auth`) and which organization or project it
322
+ * addresses (`Scope`).
323
+ *
324
+ * A request carries zero or one Composio credential. A fixed mode sends that
325
+ * credential class on every request to the API origin and never consults the
326
+ * operation table; `auto` picks one configured credential from the operation's
327
+ * declared schemes, which is how `rc.17` and earlier chose. `none` sends no
328
+ * credential, and leaves the credential header names to the caller.
329
+ */
330
+ const NONE = Object.freeze({ mode: "none" });
331
+ /** The constructors, typed for one entry's credential. Every entry's behave the same. */
332
+ const authConstructors = () => Object.freeze({
333
+ none: () => NONE,
334
+ project: (credential) => Object.freeze({
335
+ mode: "project",
336
+ credential
337
+ }),
338
+ user: (credential) => Object.freeze({
339
+ mode: "user",
340
+ credential
341
+ }),
342
+ organization: (credential) => Object.freeze({
343
+ mode: "organization",
344
+ credential
345
+ }),
346
+ auto: (credentials) => Object.freeze({
347
+ mode: "auto",
348
+ credentials: Object.freeze({ ...credentials })
349
+ })
350
+ });
351
+ /** The constructors of {@link Auth}: `Auth.project(key)`, `Auth.user(key)`, `Auth.organization(key)`, `Auth.auto({ ... })`, `Auth.none()`. */
352
+ const Auth = authConstructors();
353
+ /**
354
+ * The rule `fromEnv` and the Effect `layerConfig` share: one credential given
355
+ * is that fixed mode, several is `auto` over them, none is `none`. Generic over
356
+ * what a credential is, so the Effect entry keeps its `Redacted` values.
357
+ */
358
+ const authFromCredentials = (credentials) => {
359
+ const given = [
360
+ "project",
361
+ "user",
362
+ "organization"
363
+ ].filter((key) => credentials[key] !== void 0);
364
+ if (given.length === 0) return NONE;
365
+ if (given.length > 1) return authConstructors().auto(Object.fromEntries(given.map((key) => [key, credentials[key]])));
366
+ const [only] = given;
367
+ return authConstructors()[only](credentials[only]);
368
+ };
369
+ const MODE_SCHEME = {
370
+ project: "ApiKeyAuth",
371
+ user: "UserApiKeyAuth",
372
+ organization: "OrgApiKeyAuth"
373
+ };
374
+ /** The scheme each credential class authenticates with, keyed by mode. */
375
+ const schemeOfMode = (mode) => MODE_SCHEME[mode];
376
+ const MIGRATION = "Pass `auth`: `Auth.project(key)`, `Auth.user(key)`, `Auth.organization(key)`, `Auth.auto({ project, user, organization })` or `Auth.none()`.";
377
+ /** The credential options `rc.18` removed, each with the `auth` that replaces it. */
378
+ const REMOVED_OPTIONS = {
379
+ apiKey: "Auth.project(key)",
380
+ userApiKey: "Auth.user(key)",
381
+ orgApiKey: "Auth.organization(key)"
382
+ };
383
+ /**
384
+ * Refuses a removed credential option, which TypeScript already rejects, for
385
+ * a caller it did not reach.
386
+ */
387
+ const assertNoRemovedCredentialOptions = (options) => {
388
+ for (const [option, replacement] of Object.entries(REMOVED_OPTIONS)) if (Object.hasOwn(options, option)) 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.`);
389
+ };
390
+ /**
391
+ * Validates `auth` and lays it out by scheme. `isCredential` decides what a
392
+ * credential may be on the calling entry; `checkKey` validates a key that is
393
+ * already known, so a bad literal fails here rather than on the first request.
394
+ */
395
+ const resolveAuth = (auth, isCredential, checkKey) => {
396
+ if (typeof auth !== "object" || auth === null || !("mode" in auth)) throw new ComposioError(`\`auth\` is required. ${MIGRATION}`);
397
+ const value = auth;
398
+ const held = (credential, option) => {
399
+ if (!isCredential(credential)) throw new ComposioError(`\`${option}\` must be a key or a function that returns one.`);
400
+ checkKey(credential, option);
401
+ return credential;
402
+ };
403
+ switch (value.mode) {
404
+ case "none": return {
405
+ mode: "none",
406
+ credentials: {}
407
+ };
408
+ case "project":
409
+ case "user":
410
+ case "organization": return {
411
+ mode: value.mode,
412
+ credentials: { [MODE_SCHEME[value.mode]]: held(value.credential, "auth.credential") }
413
+ };
414
+ case "auto": {
415
+ const given = value.credentials;
416
+ if (typeof given !== "object" || given === null) throw new ComposioError("`Auth.auto` needs at least one of `project`, `user` and `organization`.");
417
+ const credentials = {};
418
+ for (const [key, scheme] of Object.entries(MODE_SCHEME)) {
419
+ const credential = given[key];
420
+ if (credential !== void 0) credentials[scheme] = held(credential, `auth.credentials.${key}`);
421
+ }
422
+ if (Object.keys(credentials).length === 0) throw new ComposioError("`Auth.auto` needs at least one of `project`, `user` and `organization`.");
423
+ return {
424
+ mode: "auto",
425
+ credentials
426
+ };
427
+ }
428
+ default: throw new ComposioError(`\`auth.mode\` must be 'none', 'project', 'user', 'organization' or 'auto'. ${MIGRATION}`);
429
+ }
430
+ };
431
+ /** Whether the platform's `Headers` takes `value` under `name`. Its refusal quotes the value, so it stays here. */
432
+ const isSendable = (name, value) => {
433
+ try {
434
+ new globalThis.Headers().set(name, value);
435
+ return true;
436
+ } catch {
437
+ return false;
438
+ }
439
+ };
440
+ /**
441
+ * Whether `key` can be sent as `scheme`'s header: a string with a
442
+ * non-whitespace character that the platform's `Headers` accepts. It is sent
443
+ * as given.
444
+ */
445
+ const isUsableKey = (scheme, key) => typeof key === "string" && /\S/.test(key) && isSendable(SCHEME_HEADERS[scheme], key);
446
+ /** The error for a key that cannot be sent. It names where the key came from and never the key. */
447
+ 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.`);
448
+ const SCOPE_ID = /^\S(?:.*\S)?$/s;
449
+ /** Validates `scope` (an id must be non-empty with no surrounding whitespace) and returns the headers it sends. */
450
+ const resolveScope = (scope) => {
451
+ if (scope === void 0) return void 0;
452
+ if (typeof scope !== "object" || scope === null) throw new ComposioError("`scope` must be an object with an `organizationId`, a `projectId`, or both.");
453
+ const { organizationId, projectId } = scope;
454
+ if (organizationId === void 0 && projectId === void 0) throw new ComposioError("`scope` must name an `organizationId`, a `projectId`, or both.");
455
+ const headers = {};
456
+ for (const [field, header, value] of [[
457
+ "organizationId",
458
+ "x-org-id",
459
+ organizationId
460
+ ], [
461
+ "projectId",
462
+ "x-project-id",
463
+ projectId
464
+ ]]) {
465
+ if (value === void 0) continue;
466
+ if (typeof value !== "string" || !SCOPE_ID.test(value) || !isSendable(header, value)) throw new ComposioError(`\`scope.${field}\` must be a non-empty string with no surrounding whitespace.`);
467
+ headers[header] = value;
468
+ }
469
+ return headers;
470
+ };
471
+ /** The header names `auth` owns while it is not `none`. */
472
+ const CREDENTIAL_HEADER_NAMES = Object.values(SCHEME_HEADERS);
473
+ /** The header names `scope` owns while it is set. */
474
+ const SCOPE_HEADER_NAMES = ["x-org-id", "x-project-id"];
475
+ /**
476
+ * Fails a generated call whose operation requires an owned header parameter it
477
+ * did not supply. It does not fall back to the configured `auth` or `scope`:
478
+ * the operation asked for a value of its own.
479
+ */
480
+ const assertRequiredOperationHeaders = (operation, supplied) => {
481
+ for (const name of operation?.requiredHeaders ?? []) if (supplied?.[name] == null) throw new ComposioError(`\`${operation?.chain.join(".")}\` requires the \`${name}\` parameter.`);
482
+ };
483
+ const chooseCredential = (auth, operation, supplied) => {
484
+ for (const [name, value] of Object.entries(supplied ?? {})) {
485
+ const scheme = schemeOfHeader(name);
486
+ if (scheme === void 0 || value == null) continue;
487
+ if (!isUsableKey(scheme, value)) throw unusableKeyError(`The \`${name}\` parameter`);
488
+ return {
489
+ kind: "operation",
490
+ scheme,
491
+ key: value
492
+ };
493
+ }
494
+ if (auth.mode === "none") return null;
495
+ const scheme = auth.mode === "auto" ? selectScheme(operation?.schemes, (candidate) => auth.credentials[candidate] !== void 0) : schemeOfMode(auth.mode);
496
+ const credential = auth.credentials[scheme];
497
+ return credential === void 0 ? null : {
498
+ kind: "configured",
499
+ scheme,
500
+ credential
501
+ };
502
+ };
503
+ /**
504
+ * The routing headers one call sends: the configured scope, with any operation
505
+ * scope id the call supplied in its place. Where both name the same id they
506
+ * must agree; a call that disagrees with its own client fails before dispatch.
507
+ */
508
+ const scopeForCall = (configured, supplied) => {
509
+ let merged = configured;
510
+ for (const name of SCOPE_HEADER_NAMES) {
511
+ const value = supplied?.[name];
512
+ if (value == null) continue;
513
+ const current = configured?.[name];
514
+ 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.`);
515
+ merged = {
516
+ ...merged,
517
+ [name]: value
518
+ };
519
+ }
520
+ return merged;
521
+ };
522
+
440
523
  //#endregion
441
524
  //#region src/compat/deprecation.ts
442
525
  /**
@@ -907,9 +990,82 @@ const inspectDeprecatedInputs = ({ operation, query, body, headers, table, seen,
907
990
  }
908
991
  };
909
992
 
993
+ //#endregion
994
+ //#region src/compat/headers.ts
995
+ 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";
996
+ const isHeaders = (value) => value instanceof Headers || hasEntries(value);
997
+ const isNullableHeadersLike = (headers) => {
998
+ if (!("values" in headers) || !isHeaders(headers.values) || !("nulls" in headers)) return false;
999
+ const nulls = headers.nulls;
1000
+ return typeof nulls === "object" && nulls !== null && Symbol.iterator in nulls;
1001
+ };
1002
+ /**
1003
+ * Iterates every supported input while preserving explicit deletions. Plain
1004
+ * objects replace an older value for a key; tuple inputs append duplicate
1005
+ * values, matching the published client.
1006
+ */
1007
+ function* iterateHeaders(headers) {
1008
+ if (!headers) return;
1009
+ if (isNullableHeadersLike(headers)) {
1010
+ yield* headers.values.entries();
1011
+ for (const name of headers.nulls) yield [name, null];
1012
+ return;
1013
+ }
1014
+ const shouldReplace = !isHeaders(headers) && !Array.isArray(headers);
1015
+ const entries = isHeaders(headers) ? headers.entries() : Array.isArray(headers) ? headers : Object.entries(headers);
1016
+ for (const entry of entries) {
1017
+ const name = entry[0];
1018
+ if (typeof name !== "string") throw new TypeError("expected header name to be a string");
1019
+ const rawValue = entry[1];
1020
+ const values = Array.isArray(rawValue) ? rawValue : [rawValue];
1021
+ let replaced = false;
1022
+ for (const value of values) {
1023
+ if (value === void 0) continue;
1024
+ if (shouldReplace && !replaced) {
1025
+ replaced = true;
1026
+ yield [name, null];
1027
+ }
1028
+ yield [name, value];
1029
+ }
1030
+ }
1031
+ }
1032
+ /** Merge sources while retaining names explicitly deleted by the last source. */
1033
+ const mergeHeaders = (sources) => {
1034
+ const values = new Headers();
1035
+ const nulls = /* @__PURE__ */ new Set();
1036
+ for (const source of sources) {
1037
+ if (!source) continue;
1038
+ const seen = /* @__PURE__ */ new Set();
1039
+ for (const [name, value] of iterateHeaders(source)) {
1040
+ const lowerName = name.toLowerCase();
1041
+ if (!seen.has(lowerName)) {
1042
+ values.delete(name);
1043
+ seen.add(lowerName);
1044
+ }
1045
+ if (value === null) {
1046
+ values.delete(name);
1047
+ nulls.add(lowerName);
1048
+ } else {
1049
+ values.append(name, value);
1050
+ nulls.delete(lowerName);
1051
+ }
1052
+ }
1053
+ }
1054
+ return {
1055
+ values,
1056
+ nulls
1057
+ };
1058
+ };
1059
+ /** Merge sources into the native header collection sent to fetch. */
1060
+ const buildHeaders = (sources) => mergeHeaders(sources).values;
1061
+ /** Every header name a source mentions, lowercased, a `null` deletion included. */
1062
+ function* headerNames(headers) {
1063
+ for (const [name] of iterateHeaders(headers)) yield name.toLowerCase();
1064
+ }
1065
+
910
1066
  //#endregion
911
1067
  //#region src/version.ts
912
- const VERSION = "2.0.0-rc.17";
1068
+ const VERSION = "2.0.0-rc.18";
913
1069
 
914
1070
  //#endregion
915
1071
  //#region src/compat/identity.ts
@@ -1062,17 +1218,37 @@ const resolveIdentity = (identity) => {
1062
1218
  };
1063
1219
  };
1064
1220
  /**
1065
- * Refuses a generic header source that names an identity header, whether it
1221
+ * The reserved names, as a function of what is configured. The identity names
1222
+ * are rc.17's. The credential names are reserved while `auth` is not `none`,
1223
+ * and the routing ids while a `scope` is set; with neither configured they are
1224
+ * ordinary headers, which is how a client is used as a transport for schemes
1225
+ * it does not model.
1226
+ */
1227
+ const reservedHeaders = (identity, configured) => {
1228
+ const reserved = /* @__PURE__ */ new Map();
1229
+ for (const name of identity.reserved) reserved.set(name, PACKAGE_RESERVED.has(name) ? "client" : "identity");
1230
+ if (configured.auth) for (const name of CREDENTIAL_HEADER_NAMES) reserved.set(name, "auth");
1231
+ if (configured.scope) for (const name of SCOPE_HEADER_NAMES) reserved.set(name, "scope");
1232
+ return reserved;
1233
+ };
1234
+ const REMEDY = {
1235
+ client: " Pass `identity` to describe the calling product.",
1236
+ identity: "",
1237
+ auth: " Configure the credential through `auth`; derive a client with `withOptions({ auth })` for another one.",
1238
+ scope: " Configure the organization and project through `scope`; derive a client with `withOptions({ scope })` for another one."
1239
+ };
1240
+ /**
1241
+ * Refuses a generic header source that names a reserved header, whether it
1066
1242
  * sets one or deletes one with `null`. Constructor validation runs it over
1067
1243
  * `defaultHeaders`; request validation over a call's `headers`, before any
1068
1244
  * network work.
1069
1245
  */
1070
- const assertNoReservedHeaders = (headers, identity, option) => {
1246
+ const assertNoReservedHeaders = (headers, reserved, option) => {
1071
1247
  if (!headers) return;
1072
1248
  for (const name of headerNames(headers)) {
1073
- if (!identity.reserved.has(name)) continue;
1074
- const owner = PACKAGE_RESERVED.has(name) ? "the client" : "`identity`";
1075
- throw new ComposioError(`The \`${name}\` header is set by ${owner} and cannot be passed in \`${option}\`.` + (owner === "`identity`" ? "" : " Pass `identity` to describe the calling product."));
1249
+ const owner = reserved.get(name);
1250
+ if (owner === void 0) continue;
1251
+ throw new ComposioError(`The \`${name}\` header is set by ${owner === "client" ? "the client" : `\`${owner}\``} and cannot be passed in \`${option}\`.${REMEDY[owner]}`);
1076
1252
  }
1077
1253
  };
1078
1254
 
@@ -1143,19 +1319,31 @@ const createFetchTransport = (options = {}) => {
1143
1319
  */
1144
1320
  const OPERATION = Symbol("composio.operation");
1145
1321
  /**
1146
- * Attach a generated call's operation to the options bag it dispatches with.
1322
+ * Beside the descriptor, the owned header parameters the call supplied
1323
+ * (`x-user-api-key`, `x-org-id`): the generated method takes them out of the
1324
+ * generic header bag and hands them over here, so the kernel can let an
1325
+ * operation credential replace `auth` and hold an operation scope id to the
1326
+ * configured `scope`. A raw call has no way to set it.
1327
+ */
1328
+ const OPERATION_HEADERS = Symbol("composio.operationHeaders");
1329
+ /**
1330
+ * Attach a generated call's operation, and the owned header parameters it
1331
+ * supplied, to the options bag it dispatches with.
1147
1332
  *
1148
1333
  * Called with the freshly built literal — never with the caller's own object —
1149
1334
  * and *after* the caller's options have been spread into it, so a caller
1150
1335
  * cannot pre-empt the descriptor: the write happens last, and the key it
1151
1336
  * writes to is not one a caller can name.
1152
1337
  */
1153
- const withOperation = (operation, options) => {
1338
+ const withOperation = (operation, options, headers) => {
1154
1339
  options[OPERATION] = operation;
1340
+ if (headers !== void 0) options[OPERATION_HEADERS] = headers;
1155
1341
  return options;
1156
1342
  };
1157
1343
  /** The operation a generated call recorded, or `undefined` for a raw one. */
1158
1344
  const readOperation = (options) => options[OPERATION];
1345
+ /** The owned header parameters a generated call supplied, or `undefined`. */
1346
+ const readOperationHeaders = (options) => options[OPERATION_HEADERS];
1159
1347
  /** A request label safe to print: dynamic path values and URL secrets are excluded. */
1160
1348
  const printableURL = (url, operation) => `${new URL(url).origin}${operation?.path ?? "/<custom>"}`;
1161
1349
  const emitLog = (config, level, message, metadata) => {
@@ -1418,24 +1606,27 @@ const kernelInternals = { sleep };
1418
1606
  * The headers for one hop, built fresh from the URL that hop is going to.
1419
1607
  *
1420
1608
  * This is where rule 3 mostly stops needing machinery of its own: the
1421
- * credential is re-derived per hop from the *request* URL rather than carried
1422
- * along from the last one, so a hop that leaves the configured API origin
1423
- * simply does not get a key. `withdrawn` covers what that cannot — the
1609
+ * credential is re-checked per hop against the *request* URL rather than
1610
+ * carried along from the last one, so a hop that leaves the configured API
1611
+ * origin simply does not get a key. `withdrawn` covers what that cannot — the
1424
1612
  * caller's own credential headers, which are legitimate on the URL the caller
1425
1613
  * chose and are dropped once the *server* has chosen one.
1426
1614
  *
1427
- * The client's identity headers follow the same per-hop rule: they describe
1428
- * this client to its own API, so a hop off the configured origin (a presigned
1429
- * storage URL, a redirect target) goes without them.
1615
+ * The client's identity and scope headers follow the same per-hop rule: they
1616
+ * describe this client to its own API, so a hop off the configured origin (a
1617
+ * presigned storage URL, a redirect target) goes without them.
1430
1618
  */
1431
- const buildRequestHeaders = (config, options, requestURL, bodyHeaders, withdrawn, scheme, callerPlaced) => {
1432
- const credential = withdrawn || callerPlaced ? null : credentialForRequest(config.baseURL, scheme, config.credentials, requestURL, config.allowedHTTPOrigin);
1433
- const identity = sameOrigin(config.baseURL, requestURL) ? config.identity.headers : void 0;
1619
+ const buildRequestHeaders = (config, options, requestURL, bodyHeaders, withdrawn, call) => {
1620
+ const credential = withdrawn ? null : credentialForRequest(config.baseURL, call.credential, requestURL, config.allowedHTTPOrigin);
1621
+ const own = sameOrigin(config.baseURL, requestURL);
1622
+ const identity = own ? config.identity.headers : void 0;
1623
+ const scope = own ? call.scope : void 0;
1434
1624
  if (!withdrawn && bodyHeaders === void 0 && !config.defaultHeaders && !options.headers && options.idempotencyKey === void 0) {
1435
1625
  const direct = new Headers({
1436
1626
  ...identity,
1437
1627
  accept: "application/json",
1438
- "user-agent": config.userAgent
1628
+ "user-agent": config.userAgent,
1629
+ ...scope
1439
1630
  });
1440
1631
  if (credential !== null) direct.set(credential.name, credential.value);
1441
1632
  return direct;
@@ -1448,6 +1639,7 @@ const buildRequestHeaders = (config, options, requestURL, bodyHeaders, withdrawn
1448
1639
  "user-agent": config.userAgent
1449
1640
  },
1450
1641
  credential === null ? void 0 : { [credential.name]: credential.value },
1642
+ scope,
1451
1643
  config.defaultHeaders,
1452
1644
  bodyHeaders,
1453
1645
  options.headers
@@ -1455,28 +1647,55 @@ const buildRequestHeaders = (config, options, requestURL, bodyHeaders, withdrawn
1455
1647
  if (withdrawn) withdrawCredentials(headers);
1456
1648
  return headers;
1457
1649
  };
1650
+ /** The error for a provider that failed; the provider's own error is its `cause`. */
1651
+ const providerFailed = (cause) => {
1652
+ const error = new ComposioError("The `auth` credential provider failed.");
1653
+ Object.defineProperty(error, "cause", {
1654
+ value: cause,
1655
+ configurable: true,
1656
+ writable: true
1657
+ });
1658
+ return error;
1659
+ };
1458
1660
  /**
1459
- * The credential class this logical request authenticates with, decided once
1460
- * from the operation the *caller* invoked.
1461
- *
1462
- * Deliberately not re-derived per redirect hop. A hop's URL was chosen by the
1463
- * server, so matching it back to a template would let the server's choice
1464
- * change which of the caller's credentials goes out; the operation the caller
1465
- * asked for is the honest answer for the whole chain, and rule 3 already
1466
- * withdraws everything once a hop leaves the origin.
1467
- *
1468
- * `operation` is the match `makeRequest` already computed for the static
1469
- * deprecated-input check, threaded in rather than re-derived: the two
1470
- * features need the same fact, so `matchOperation` runs once per logical call
1471
- * regardless of which of them a given client configuration actually uses.
1472
- * With only `apiKey` set the scheme answer is still `ApiKeyAuth` down every
1473
- * branch of {@link selectScheme}, so an existing caller's requests stay
1474
- * byte-identical by construction; what changed is that the match itself is no
1475
- * longer skippable, because the deprecated-input warning needs it too.
1476
- */
1477
- const schemeForRequest = (config, operation) => {
1478
- if (!hasAlternateCredential(config.credentials)) return "ApiKeyAuth";
1479
- return selectScheme(operation?.schemes, config.credentials);
1661
+ * The credential one logical call carries, its provider asked at most once,
1662
+ * and before any network work.
1663
+ *
1664
+ * A configured credential is asked for only when the call starts on the API
1665
+ * origin: a call that starts anywhere else never carries it (rule 2), and a
1666
+ * redirect back onto the origin arrives after the chain has left it, so the
1667
+ * withdrawal holds. An operation credential is the call's own and is returned
1668
+ * as given; the origin rules still decide, per hop, whether it is sent.
1669
+ */
1670
+ const resolveCallCredential = (config, operation, supplied, requestURL) => {
1671
+ const choice = chooseCredential(config.auth, operation, supplied);
1672
+ if (choice === null) return null;
1673
+ const name = schemeHeader(choice.scheme);
1674
+ if (choice.kind === "operation") return {
1675
+ name,
1676
+ value: choice.key
1677
+ };
1678
+ if (!sameOrigin(config.baseURL, requestURL)) return null;
1679
+ if (typeof choice.credential === "string") return {
1680
+ name,
1681
+ value: choice.credential
1682
+ };
1683
+ const usable = (key) => {
1684
+ if (!isUsableKey(choice.scheme, key)) throw unusableKeyError("The key the `auth` credential provider returned");
1685
+ return {
1686
+ name,
1687
+ value: key
1688
+ };
1689
+ };
1690
+ let key;
1691
+ try {
1692
+ key = choice.credential();
1693
+ } catch (cause) {
1694
+ throw providerFailed(cause);
1695
+ }
1696
+ return typeof key === "string" ? usable(key) : Promise.resolve(key).then(usable, (cause) => {
1697
+ throw providerFailed(cause);
1698
+ });
1480
1699
  };
1481
1700
  /**
1482
1701
  * One attempt: the request, plus however many redirects it takes to land on a
@@ -1494,15 +1713,14 @@ const schemeForRequest = (config, operation) => {
1494
1713
  * rewrite), and the query, which is left to the `Location` URL because the
1495
1714
  * server picked it.
1496
1715
  */
1497
- const dispatchWithRedirects = async (config, options, initialURL, initialBody, initialBodyHeaders, signal, scheme) => {
1716
+ const dispatchWithRedirects = async (config, options, initialURL, initialBody, initialBodyHeaders, signal, call) => {
1498
1717
  let url = initialURL;
1499
1718
  let method = options.method.toUpperCase();
1500
1719
  let body = initialBody;
1501
1720
  let bodyHeaders = initialBodyHeaders;
1502
1721
  let withdrawn = false;
1503
- const callerPlaced = callerPlacedCredential([config.defaultHeaders, options.headers]);
1504
1722
  for (let hop = 0;; hop++) {
1505
- const headers = buildRequestHeaders(config, options, url, bodyHeaders, withdrawn, scheme, callerPlaced);
1723
+ const headers = buildRequestHeaders(config, options, url, bodyHeaders, withdrawn, call);
1506
1724
  const delegated = hop === 0 && !carriesCredentials(headers);
1507
1725
  const init = {
1508
1726
  method,
@@ -1547,7 +1765,7 @@ const dispatchWithRedirects = async (config, options, initialURL, initialBody, i
1547
1765
  * which is what `deprecation.ts` resolves relative `Link` targets against.
1548
1766
  */
1549
1767
  async function makeRequest(config, options) {
1550
- assertNoReservedHeaders(options.headers, config.identity, "headers");
1768
+ assertNoReservedHeaders(options.headers, config.reserved, "headers");
1551
1769
  if (options.timeout !== void 0) validatePositiveInteger("timeout", options.timeout);
1552
1770
  const maxRetries = options.maxRetries ?? config.maxRetries;
1553
1771
  validatePositiveInteger("maxRetries", maxRetries);
@@ -1563,7 +1781,14 @@ async function makeRequest(config, options) {
1563
1781
  url: printableURL(url, operation),
1564
1782
  maxAttempts: maxRetries + 1
1565
1783
  };
1566
- const scheme = schemeForRequest(config, operation);
1784
+ const supplied = readOperationHeaders(options);
1785
+ assertRequiredOperationHeaders(threaded ?? null, supplied);
1786
+ const scope = scopeForCall(config.scope, supplied);
1787
+ const resolving = resolveCallCredential(config, operation, supplied, url);
1788
+ const call = {
1789
+ scope,
1790
+ credential: resolving instanceof Promise ? await resolving : resolving
1791
+ };
1567
1792
  if (config.onRequest !== void 0 && (threaded === void 0 || threaded.hasDeprecatedInputs === true)) config.onRequest(operation, query, options.body, buildHeaders([config.defaultHeaders, options.headers]));
1568
1793
  for (let numRetries = 0;; numRetries++) {
1569
1794
  if (userSignal?.aborted) throw new APIUserAbortError();
@@ -1581,7 +1806,7 @@ async function makeRequest(config, options) {
1581
1806
  const timer = setTimeout(abort, timeout);
1582
1807
  let result;
1583
1808
  try {
1584
- result = await dispatchWithRedirects(config, options, url, body, bodyHeaders, controller.signal, scheme);
1809
+ result = await dispatchWithRedirects(config, options, url, body, bodyHeaders, controller.signal, call);
1585
1810
  } catch (cause) {
1586
1811
  if (cause instanceof ComposioError) {
1587
1812
  if (attemptLog !== void 0) emitLog(config, "info", "Request failed", {
@@ -1841,7 +2066,8 @@ const GENERATED_OPERATIONS = [
1841
2066
  "consumer",
1842
2067
  "listConnectedToolkits"
1843
2068
  ],
1844
- schemes: ["UserApiKeyAuth"]
2069
+ schemes: ["UserApiKeyAuth"],
2070
+ requiredHeaders: ["x-user-api-key", "x-org-id"]
1845
2071
  },
1846
2072
  {
1847
2073
  method: "get",
@@ -2106,7 +2332,8 @@ const GENERATED_OPERATIONS = [
2106
2332
  method: "post",
2107
2333
  path: "/api/v3.1/cli/codact_failures",
2108
2334
  chain: ["cli", "createCodactFailure"],
2109
- schemes: ["UserApiKeyAuth"]
2335
+ schemes: ["UserApiKeyAuth"],
2336
+ requiredHeaders: ["x-user-api-key"]
2110
2337
  },
2111
2338
  {
2112
2339
  method: "post",
@@ -2238,7 +2465,8 @@ const GENERATED_OPERATIONS = [
2238
2465
  "project",
2239
2466
  "resolve"
2240
2467
  ],
2241
- schemes: ["UserApiKeyAuth"]
2468
+ schemes: ["UserApiKeyAuth"],
2469
+ requiredHeaders: ["x-user-api-key", "x-org-id"]
2242
2470
  },
2243
2471
  {
2244
2472
  method: "post",
@@ -2478,4 +2706,4 @@ const generatedOperation = (chainKey) => {
2478
2706
  };
2479
2707
 
2480
2708
  //#endregion
2481
- export { callerPlacedCredential as A, resolveIdentity as C, matchOperation as D, inspectDeprecation as E, mergeHeaders as F, parseHTTPURL as M, resolveHTTPURL as N, SCHEME_HEADERS as O, buildHeaders as P, assertNoReservedHeaders as S, inspectDeprecatedInputs as T, schemeForRequest as _, TOO_MANY_REDIRECTS as a, withOperation as b, buildURL as c, path as d, printableURL as f, safeJSON as g, rewriteForRedirect as h, REDIRECT_STATUSES as i, carriesCredentials as j, assertCredentialTransport 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, shouldRetryResponse as v, VERSION as w, createFetchTransport as x, validatePositiveInteger as y };
2709
+ export { Auth as A, unusableKeyError as B, resolveIdentity as C, inspectDeprecatedInputs as D, mergeHeaders as E, chooseCredential as F, resolveHTTPURL as G, assertCredentialTransport as H, isUsableKey as I, sameOrigin as K, resolveAuth as L, assertRequiredOperationHeaders as M, authConstructors as N, inspectDeprecation as O, authFromCredentials as P, resolveScope as R, reservedHeaders as S, buildHeaders as T, carriesCredentials as U, SCHEME_HEADERS as V, parseHTTPURL 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, schemeHeader as q, 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 };